diff options
Diffstat (limited to 'drivers/media')
615 files changed, 33315 insertions, 12704 deletions
diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index e10bd588a586..dd6e24a0899b 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -421,6 +421,7 @@ static int __init cec_devnode_init(void) ret = bus_register(&cec_bus_type); if (ret < 0) { + debugfs_remove_recursive(top_cec_dir); unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); pr_warn("cec: bus_register failed\n"); return -EIO; @@ -439,6 +440,6 @@ static void __exit cec_devnode_exit(void) subsys_initcall(cec_devnode_init); module_exit(cec_devnode_exit) -MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_DESCRIPTION("Device node registration for cec drivers"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/cec/platform/cec-gpio/cec-gpio.c b/drivers/media/cec/platform/cec-gpio/cec-gpio.c index 3c27789d8657..842555ed42c7 100644 --- a/drivers/media/cec/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/cec/platform/cec-gpio/cec-gpio.c @@ -291,6 +291,6 @@ static struct platform_driver cec_gpio_pdrv = { module_platform_driver(cec_gpio_pdrv); -MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("CEC GPIO driver"); diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c index fea2d65acffc..1ec0cece0a5b 100644 --- a/drivers/media/cec/platform/stm32/stm32-cec.c +++ b/drivers/media/cec/platform/stm32/stm32-cec.c @@ -248,7 +248,6 @@ static const struct regmap_config stm32_cec_regmap_cfg = { .val_bits = 32, .reg_stride = sizeof(u32), .max_register = 0x14, - .fast_io = true, }; static int stm32_cec_probe(struct platform_device *pdev) diff --git a/drivers/media/cec/usb/extron-da-hd-4k-plus/Makefile b/drivers/media/cec/usb/extron-da-hd-4k-plus/Makefile index 2e8f7f60263f..08d58524419f 100644 --- a/drivers/media/cec/usb/extron-da-hd-4k-plus/Makefile +++ b/drivers/media/cec/usb/extron-da-hd-4k-plus/Makefile @@ -1,8 +1,2 @@ extron-da-hd-4k-plus-cec-objs := extron-da-hd-4k-plus.o cec-splitter.o obj-$(CONFIG_USB_EXTRON_DA_HD_4K_PLUS_CEC) := extron-da-hd-4k-plus-cec.o - -all: - $(MAKE) -C $(KDIR) M=$(shell pwd) modules - -install: - $(MAKE) -C $(KDIR) M=$(shell pwd) modules_install 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 41d019b01ec0..e2eff17952ab 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 @@ -28,7 +28,7 @@ #include "extron-da-hd-4k-plus.h" -MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_DESCRIPTION("Extron DA HD 4K PLUS HDMI CEC driver"); MODULE_LICENSE("GPL"); @@ -1252,7 +1252,7 @@ static int extron_s_output(struct file *file, void *priv, unsigned int o) return o ? -EINVAL : 0; } -static int extron_g_edid(struct file *file, void *_fh, +static int extron_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct extron_port *port = video_drvdata(file); @@ -1280,7 +1280,7 @@ static int extron_g_edid(struct file *file, void *_fh, return 0; } -static int extron_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid) +static int extron_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct extron_port *port = video_drvdata(file); diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c index 171366fe3544..60569f1670fe 100644 --- a/drivers/media/cec/usb/pulse8/pulse8-cec.c +++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c @@ -2,7 +2,7 @@ /* * Pulse Eight HDMI CEC driver * - * Copyright 2016 Hans Verkuil <hverkuil@xs4all.nl + * Copyright 2016 Hans Verkuil <hverkuil@kernel.org> */ /* @@ -41,7 +41,7 @@ #include <media/cec.h> -MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_DESCRIPTION("Pulse Eight HDMI CEC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/cec/usb/rainshadow/rainshadow-cec.c b/drivers/media/cec/usb/rainshadow/rainshadow-cec.c index 6f8d6797c614..08f58456d682 100644 --- a/drivers/media/cec/usb/rainshadow/rainshadow-cec.c +++ b/drivers/media/cec/usb/rainshadow/rainshadow-cec.c @@ -2,7 +2,7 @@ /* * RainShadow Tech HDMI CEC driver * - * Copyright 2016 Hans Verkuil <hverkuil@xs4all.nl + * Copyright 2016 Hans Verkuil <hverkuil@kernel.org> */ /* @@ -31,7 +31,7 @@ #include <media/cec.h> -MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_DESCRIPTION("RainShadow Tech HDMI CEC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/b2c2/flexcop-sram.c b/drivers/media/common/b2c2/flexcop-sram.c index d97962eb0112..dba03769f263 100644 --- a/drivers/media/common/b2c2/flexcop-sram.c +++ b/drivers/media/common/b2c2/flexcop-sram.c @@ -352,7 +352,7 @@ static int flexcop_sram_detect(struct flexcop_device *fc) sram_set_size(adapter, 0x10000); sram_init(adapter); write_reg_dw(adapter, 0x208, tmp); - dprintk("%s: SRAM detection failed. Set to 32K \n", __func__); + dprintk("%s: SRAM detection failed. Set to 32K\n", __func__); return 0; } diff --git a/drivers/media/common/b2c2/flexcop.c b/drivers/media/common/b2c2/flexcop.c index e7a88a2d248c..8506de48ba45 100644 --- a/drivers/media/common/b2c2/flexcop.c +++ b/drivers/media/common/b2c2/flexcop.c @@ -170,7 +170,7 @@ static void flexcop_reset(struct flexcop_device *fc) flexcop_ibi_value v210, v204; /* reset the flexcop itself */ - fc->write_ibi_reg(fc,ctrl_208,ibi_zero); + fc->write_ibi_reg(fc, ctrl_208, ibi_zero); v210.raw = 0; v210.sw_reset_210.reset_block_000 = 1; @@ -183,17 +183,17 @@ static void flexcop_reset(struct flexcop_device *fc) v210.sw_reset_210.reset_block_700 = 1; v210.sw_reset_210.Block_reset_enable = 0xb2; v210.sw_reset_210.Special_controls = 0xc259; - fc->write_ibi_reg(fc,sw_reset_210,v210); + fc->write_ibi_reg(fc, sw_reset_210, v210); msleep(1); /* reset the periphical devices */ - v204 = fc->read_ibi_reg(fc,misc_204); + v204 = fc->read_ibi_reg(fc, misc_204); v204.misc_204.Per_reset_sig = 0; - fc->write_ibi_reg(fc,misc_204,v204); + fc->write_ibi_reg(fc, misc_204, v204); msleep(1); v204.misc_204.Per_reset_sig = 1; - fc->write_ibi_reg(fc,misc_204,v204); + fc->write_ibi_reg(fc, misc_204, v204); } void flexcop_reset_block_300(struct flexcop_device *fc) @@ -202,13 +202,13 @@ void flexcop_reset_block_300(struct flexcop_device *fc) v210 = fc->read_ibi_reg(fc, sw_reset_210); deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw); - fc->write_ibi_reg(fc,ctrl_208,ibi_zero); + fc->write_ibi_reg(fc, ctrl_208, ibi_zero); v210.sw_reset_210.reset_block_300 = 1; v210.sw_reset_210.Block_reset_enable = 0xb2; - fc->write_ibi_reg(fc,sw_reset_210,v210); - fc->write_ibi_reg(fc,ctrl_208,v208_save); + fc->write_ibi_reg(fc, sw_reset_210, v210); + fc->write_ibi_reg(fc, ctrl_208, v208_save); } struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len) @@ -266,8 +266,8 @@ int flexcop_device_initialize(struct flexcop_device *fc) if (fc->get_mac_addr(fc, 0) == 0) { u8 *b = fc->dvb_adapter.proposed_mac; info("MAC address = %pM", b); - flexcop_set_mac_filter(fc,b); - flexcop_mac_filter_ctrl(fc,1); + flexcop_set_mac_filter(fc, b); + flexcop_mac_filter_ctrl(fc, 1); } else warn("reading of MAC address failed.\n"); @@ -275,7 +275,7 @@ int flexcop_device_initialize(struct flexcop_device *fc) if (ret) goto error; - flexcop_device_name(fc,"initialization of","complete"); + flexcop_device_name(fc, "initialization of", "complete"); return 0; error: diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c index 1392bd6b0026..1ee159ef7f38 100644 --- a/drivers/media/common/cx2341x.c +++ b/drivers/media/common/cx2341x.c @@ -2,7 +2,7 @@ /* * cx2341x - generic code for cx23415/6/8 based devices * - * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2006 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index 9d0362a75ecd..a9e3bad76d54 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -186,11 +186,11 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou struct saa7146_dev *dev = video_drvdata(file); int ret; - if (vdev->vfl_type != VFL_TYPE_VBI || !dev->ext_vv_data->vbi_fops.write) + if (vdev->vfl_type != VFL_TYPE_VBI || !dev->ext_vv_data->vbi_write) return -EINVAL; if (mutex_lock_interruptible(vdev->lock)) return -ERESTARTSYS; - ret = dev->ext_vv_data->vbi_fops.write(file, data, count, ppos); + ret = dev->ext_vv_data->vbi_write(file, data, count, ppos); mutex_unlock(vdev->lock); return ret; } diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c index d85c78c104b9..af07fed21ae1 100644 --- a/drivers/media/common/siano/smsir.c +++ b/drivers/media/common/siano/smsir.c @@ -28,7 +28,7 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len) for (i = 0; i < len >> 2; i++) { struct ir_raw_event ev = { .duration = abs(samples[i]), - .pulse = (samples[i] > 0) ? false : true + .pulse = samples[i] <= 0 }; ir_raw_event_store(coredev->ir.dev, &ev); diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index a13ec569c82f..7123c5fae92c 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -258,6 +258,7 @@ static void *vb2_dc_alloc(struct vb2_buffer *vb, if (ret) { dev_err(dev, "dma alloc of size %lu failed\n", size); + put_device(buf->dev); kfree(buf); return ERR_PTR(-ENOMEM); } diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 1cd26faee503..83862d57b126 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -973,18 +973,14 @@ EXPORT_SYMBOL_GPL(vb2_queue_change_type); __poll_t vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait) { - struct video_device *vfd = video_devdata(file); + struct v4l2_fh *fh = file_to_v4l2_fh(file); __poll_t res; res = vb2_core_poll(q, file, wait); - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { - struct v4l2_fh *fh = file->private_data; - - poll_wait(file, &fh->wait, wait); - if (v4l2_event_pending(fh)) - res |= EPOLLPRI; - } + poll_wait(file, &fh->wait, wait); + if (v4l2_event_pending(fh)) + res |= EPOLLPRI; return res; } @@ -1014,6 +1010,11 @@ int vb2_ioctl_remove_bufs(struct file *file, void *priv, if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY; + if (vb2_fileio_is_active(vdev->queue)) { + dprintk(vdev->queue, 1, "file io in progress\n"); + return -EBUSY; + } + return vb2_core_remove_bufs(vdev->queue, d->index, d->count); } EXPORT_SYMBOL_GPL(vb2_ioctl_remove_bufs); diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 151177e5a06d..8c6f5aafda1d 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1414,8 +1414,8 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) if (dmxdev->demux->open(dmxdev->demux) < 0) return -EUSERS; - dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter), - dmxdev->filternum)); + dmxdev->filter = vmalloc_array(dmxdev->filternum, + sizeof(struct dmxdev_filter)); if (!dmxdev->filter) return -ENOMEM; diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index baf64540dc00..7b591aa1179f 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -785,7 +785,7 @@ exit: * be written. * @bytes_write: Size of ebuf. * @size_write_flag: A flag on Command Register which says whether the link size - * information will be writen or not. + * information will be written or not. * * return: Number of bytes written, or < 0 on error. */ diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 7c4d86bfdd6c..290fc7961647 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -744,7 +744,8 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) return -ENODEV; } - if ((ret = demux->start_feed(feed)) < 0) { + ret = demux->start_feed(feed); + if (ret < 0) { mutex_unlock(&demux->mutex); return ret; } @@ -797,7 +798,8 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, if (mutex_lock_interruptible(&demux->mutex)) return -ERESTARTSYS; - if (!(feed = dvb_dmx_feed_alloc(demux))) { + feed = dvb_dmx_feed_alloc(demux); + if (!feed) { mutex_unlock(&demux->mutex); return -EBUSY; } @@ -817,7 +819,8 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; (*ts_feed)->set = dmx_ts_feed_set; - if (!(feed->filter = dvb_dmx_filter_alloc(demux))) { + feed->filter = dvb_dmx_filter_alloc(demux); + if (!feed->filter) { feed->state = DMX_STATE_FREE; mutex_unlock(&demux->mutex); return -EBUSY; @@ -923,7 +926,8 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) struct dmx_section_filter *sf; u8 mask, mode, doneq; - if (!(f = dvbdmxfeed->filter)) + f = dvbdmxfeed->filter; + if (!f) return; do { sf = &f->filter; @@ -970,7 +974,8 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) prepare_secfilters(dvbdmxfeed); - if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) { + ret = dvbdmx->start_feed(dvbdmxfeed); + if (ret < 0) { mutex_unlock(&dvbdmx->mutex); return ret; } @@ -1057,7 +1062,8 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, if (mutex_lock_interruptible(&dvbdmx->mutex)) return -ERESTARTSYS; - if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) { + dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx); + if (!dvbdmxfeed) { mutex_unlock(&dvbdmx->mutex); return -EBUSY; } @@ -1223,7 +1229,7 @@ static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) return 0; } -static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids) +static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids) { struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; @@ -1238,14 +1244,14 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->cnt_storage = NULL; dvbdemux->users = 0; - dvbdemux->filter = vmalloc(array_size(sizeof(struct dvb_demux_filter), - dvbdemux->filternum)); + dvbdemux->filter = vmalloc_array(dvbdemux->filternum, + sizeof(struct dvb_demux_filter)); if (!dvbdemux->filter) return -ENOMEM; - dvbdemux->feed = vmalloc(array_size(sizeof(struct dvb_demux_feed), - dvbdemux->feednum)); + dvbdemux->feed = vmalloc_array(dvbdemux->feednum, + sizeof(struct dvb_demux_feed)); if (!dvbdemux->feed) { vfree(dvbdemux->filter); dvbdemux->filter = NULL; diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c index 7d4558de8e83..de6226556826 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb-core/dvb_ringbuffer.c @@ -37,10 +37,11 @@ void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) { - rbuf->pread=rbuf->pwrite=0; - rbuf->data=data; - rbuf->size=len; - rbuf->error=0; + rbuf->pread = 0; + rbuf->pwrite = 0; + rbuf->data = data; + rbuf->size = len; + rbuf->error = 0; init_waitqueue_head(&rbuf->queue); @@ -235,7 +236,7 @@ ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, return len; } -ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len) +ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len) { int status; ssize_t oldpwrite = rbuf->pwrite; @@ -245,7 +246,8 @@ ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t le DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY); status = dvb_ringbuffer_write(rbuf, buf, len); - if (status < 0) rbuf->pwrite = oldpwrite; + if (status < 0) + rbuf->pwrite = oldpwrite; return status; } @@ -258,8 +260,10 @@ ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, pktlen = rbuf->data[idx] << 8; pktlen |= rbuf->data[(idx + 1) % rbuf->size]; - if (offset > pktlen) return -EINVAL; - if ((offset + len) > pktlen) len = pktlen - offset; + if (offset > pktlen) + return -EINVAL; + if ((offset + len) > pktlen) + len = pktlen - offset; idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; todo = len; @@ -278,7 +282,7 @@ ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, } ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len) + int offset, u8 *buf, size_t len) { size_t todo; size_t split; @@ -286,8 +290,10 @@ ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, pktlen = rbuf->data[idx] << 8; pktlen |= rbuf->data[(idx + 1) % rbuf->size]; - if (offset > pktlen) return -EINVAL; - if ((offset + len) > pktlen) len = pktlen - offset; + if (offset > pktlen) + return -EINVAL; + if ((offset + len) > pktlen) + len = pktlen - offset; idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; todo = len; @@ -309,7 +315,7 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED; // clean up disposed packets - while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) { + while (dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) { if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) { pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8; pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1); @@ -321,14 +327,14 @@ void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) } } -ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen) +ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t *pktlen) { int consumed; int curpktlen; int curpktstatus; if (idx == -1) { - idx = rbuf->pread; + idx = rbuf->pread; } else { curpktlen = rbuf->data[idx] << 8; curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; @@ -339,7 +345,7 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* if (consumed < 0) consumed += rbuf->size; - while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) { + while ((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) { curpktlen = rbuf->data[idx] << 8; curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 9df7c213716a..8b980d371a45 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -571,8 +571,8 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, MKDEV(DVB_MAJOR, minor), dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); if (IS_ERR(clsdev)) { - pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n", - __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); + pr_err("%s: failed to create device dvb%d.%s%d (%pe)\n", + __func__, adap->num, dnames[type], id, clsdev); if (new_node) { list_del(&new_node->list_head); kfree(dvbdevfops); diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 2ef2ff2a38ff..bcc97ca86ed5 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -163,7 +163,7 @@ config DVB_CX24123 A DVB-S tuner module. Say Y when you want to support this frontend. config DVB_DS3000 - tristate "Montage Tehnology DS3000 based" + tristate "Montage Technology DS3000 based" depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT help @@ -270,7 +270,7 @@ config DVB_TDA826X A DVB-S silicon tuner module. Say Y when you want to support this tuner. config DVB_TS2020 - tristate "Montage Tehnology TS2020 based tuners" + tristate "Montage Technology TS2020 based tuners" depends on DVB_CORE && I2C select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 415f1f91cc30..8fcb4417ba22 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c @@ -1936,7 +1936,8 @@ static void cxd2841er_read_ber(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct cxd2841er_priv *priv = fe->demodulator_priv; - u32 ret, bit_error = 0, bit_count = 0; + u32 bit_error = 0, bit_count = 0; + int ret; dev_dbg(&priv->i2c->dev, "%s()\n", __func__); switch (p->delivery_system) { diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 779cce93e94a..428b31e60874 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -1270,7 +1270,7 @@ static const u16 nicam_presc_table_val[43] = { TODO: check ignoring single/multimaster is ok for AUD access ? */ -#define DRXJ_ISAUDWRITE(addr) (((((addr)>>16)&1) == 1) ? true : false) +#define DRXJ_ISAUDWRITE(addr) ((((addr) >> 16) & 1) == 1) #define DRXJ_DAP_AUDTRIF_TIMEOUT 80 /* millisec */ /*============================================================================*/ diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index 87f3d4f0eb8c..9ef367918824 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -6324,8 +6324,7 @@ static int drxk_set_parameters(struct dvb_frontend *fe) case SYS_DVBC_ANNEX_C: if (!state->m_has_dvbc) return -EINVAL; - state->m_itut_annex_c = (delsys == SYS_DVBC_ANNEX_C) ? - true : false; + state->m_itut_annex_c = delsys == SYS_DVBC_ANNEX_C; if (state->m_itut_annex_c) setoperation_mode(state, OM_QAM_ITU_C); else diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index cab442a350a5..8c34a5b850bc 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -124,7 +124,6 @@ static int i2c_read_demod_bytes(struct lgdt330x_state *state, /* Software reset */ static int lgdt3302_sw_reset(struct lgdt330x_state *state) { - u8 ret; u8 reset[] = { IRQ_MASK, /* @@ -133,6 +132,7 @@ static int lgdt3302_sw_reset(struct lgdt330x_state *state) */ 0x00 }; + int ret; ret = i2c_write_demod_bytes(state, reset, sizeof(reset)); @@ -147,11 +147,11 @@ static int lgdt3302_sw_reset(struct lgdt330x_state *state) static int lgdt3303_sw_reset(struct lgdt330x_state *state) { - u8 ret; u8 reset[] = { 0x02, 0x00 /* bit 0 is active low software reset */ }; + int ret; ret = i2c_write_demod_bytes(state, reset, sizeof(reset)); diff --git a/drivers/media/dvb-frontends/mn88443x.c b/drivers/media/dvb-frontends/mn88443x.c index 7a58f53ab999..818c4e67364c 100644 --- a/drivers/media/dvb-frontends/mn88443x.c +++ b/drivers/media/dvb-frontends/mn88443x.c @@ -694,8 +694,7 @@ static int mn88443x_probe(struct i2c_client *client) chip->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(chip->mclk) && !conf) { - dev_err(dev, "Failed to request mclk: %ld\n", - PTR_ERR(chip->mclk)); + dev_err(dev, "Failed to request mclk: %pe\n", chip->mclk); return PTR_ERR(chip->mclk); } @@ -709,8 +708,8 @@ static int mn88443x_probe(struct i2c_client *client) chip->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(chip->reset_gpio)) { - dev_err(dev, "Failed to request reset_gpio: %ld\n", - PTR_ERR(chip->reset_gpio)); + dev_err(dev, "Failed to request reset_gpio: %pe\n", + chip->reset_gpio); return PTR_ERR(chip->reset_gpio); } diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 6237fe804a5c..4b4db8c4f496 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -27,7 +27,7 @@ config VIDEO_IR_I2C menuconfig VIDEO_CAMERA_SENSOR bool "Camera sensor devices" - depends on MEDIA_CAMERA_SUPPORT && I2C + depends on MEDIA_CAMERA_SUPPORT && I2C && HAVE_CLK select MEDIA_CONTROLLER select V4L2_FWNODE select VIDEO_V4L2_SUBDEV_API @@ -70,6 +70,16 @@ config VIDEO_GC0308 To compile this driver as a module, choose M here: the module will be called gc0308. +config VIDEO_GC0310 + tristate "GalaxyCore GC0310 sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor-level driver for the Galaxycore + GC0310 0.3MP sensor. + + To compile this driver as a module, choose M here: the + module will be called gc0310. + config VIDEO_GC05A2 tristate "GalaxyCore gc05a2 sensor support" select V4L2_CCI_I2C @@ -127,6 +137,16 @@ config VIDEO_HI847 To compile this driver as a module, choose M here: the module will be called hi847. +config VIDEO_IMX111 + tristate "Sony IMX111 sensor support" + select V4L2_CCI_I2C + help + This is a V4L2 sensor driver for the Sony IMX111 camera + sensors. + + To compile this driver as a module, choose M here: the + module will be called imx111. + config VIDEO_IMX208 tristate "Sony IMX208 sensor support" help @@ -317,6 +337,7 @@ config VIDEO_MT9V011 config VIDEO_MT9V032 tristate "Micron MT9V032 sensor support" + depends on OF select REGMAP_I2C help This is a Video4Linux2 sensor driver for the Micron @@ -340,6 +361,16 @@ config VIDEO_OG01A1B To compile this driver as a module, choose M here: the module will be called og01a1b. +config VIDEO_OG0VE1B + tristate "OmniVision OG0VE1B sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor driver for the OmniVision + OG0VE1B camera. + + To compile this driver as a module, choose M here: the + module will be called og0ve1b. + config VIDEO_OV01A10 tristate "OmniVision OV01A10 sensor support" help @@ -446,6 +477,16 @@ config VIDEO_OV2685 To compile this driver as a module, choose M here: the module will be called ov2685. +config VIDEO_OV2735 + tristate "OmniVision OV2735 sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor driver for the OmniVision + OV2735 camera. + + To compile this driver as a module, choose M here: the + module will be called ov2735. + config VIDEO_OV2740 tristate "OmniVision OV2740 sensor support" depends on ACPI || COMPILE_TEST @@ -542,24 +583,25 @@ config VIDEO_OV5695 To compile this driver as a module, choose M here: the module will be called ov5695. -config VIDEO_OV64A40 - tristate "OmniVision OV64A40 sensor support" +config VIDEO_OV6211 + tristate "OmniVision OV6211 sensor support" select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the OmniVision - OV64A40 camera. + OV6211 camera. To compile this driver as a module, choose M here: the - module will be called ov64a40. + module will be called ov6211. -config VIDEO_OV6650 - tristate "OmniVision OV6650 sensor support" +config VIDEO_OV64A40 + tristate "OmniVision OV64A40 sensor support" + select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the OmniVision - OV6650 camera. + OV64A40 camera. To compile this driver as a module, choose M here: the - module will be called ov6650. + module will be called ov64a40. config VIDEO_OV7251 tristate "OmniVision OV7251 sensor support" diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 5873d29433ee..c5f17602454f 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_DW9768) += dw9768.o obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/ obj-$(CONFIG_VIDEO_GC0308) += gc0308.o +obj-$(CONFIG_VIDEO_GC0310) += gc0310.o obj-$(CONFIG_VIDEO_GC05A2) += gc05a2.o obj-$(CONFIG_VIDEO_GC08A3) += gc08a3.o obj-$(CONFIG_VIDEO_GC2145) += gc2145.o @@ -45,6 +46,7 @@ obj-$(CONFIG_VIDEO_HI556) += hi556.o obj-$(CONFIG_VIDEO_HI846) += hi846.o obj-$(CONFIG_VIDEO_HI847) += hi847.o obj-$(CONFIG_VIDEO_I2C) += video-i2c.o +obj-$(CONFIG_VIDEO_IMX111) += imx111.o obj-$(CONFIG_VIDEO_IMX208) += imx208.o obj-$(CONFIG_VIDEO_IMX214) += imx214.o obj-$(CONFIG_VIDEO_IMX219) += imx219.o @@ -81,6 +83,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o +obj-$(CONFIG_VIDEO_OG0VE1B) += og0ve1b.o obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o obj-$(CONFIG_VIDEO_OV02A10) += ov02a10.o obj-$(CONFIG_VIDEO_OV02C10) += ov02c10.o @@ -93,6 +96,7 @@ obj-$(CONFIG_VIDEO_OV2640) += ov2640.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_OV2680) += ov2680.o obj-$(CONFIG_VIDEO_OV2685) += ov2685.o +obj-$(CONFIG_VIDEO_OV2735) += ov2735.o obj-$(CONFIG_VIDEO_OV2740) += ov2740.o obj-$(CONFIG_VIDEO_OV4689) += ov4689.o obj-$(CONFIG_VIDEO_OV5640) += ov5640.o @@ -103,8 +107,8 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o obj-$(CONFIG_VIDEO_OV5675) += ov5675.o obj-$(CONFIG_VIDEO_OV5693) += ov5693.o obj-$(CONFIG_VIDEO_OV5695) += ov5695.o +obj-$(CONFIG_VIDEO_OV6211) += ov6211.o obj-$(CONFIG_VIDEO_OV64A40) += ov64a40.o -obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7251) += ov7251.o obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 5d90b8ab9b6d..378f4e6af12c 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -214,7 +214,6 @@ struct adv7180_state { struct gpio_desc *pwdn_gpio; struct gpio_desc *rst_gpio; v4l2_std_id curr_norm; - bool powered; bool streaming; u8 input; @@ -274,6 +273,38 @@ static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg, return i2c_smbus_write_byte_data(state->vpp_client, reg, value); } +static int adv7180_set_power(struct adv7180_state *state, bool on) +{ + u8 val; + int ret; + + if (on) + val = ADV7180_PWR_MAN_ON; + else + val = ADV7180_PWR_MAN_OFF; + + ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val); + if (ret) + return ret; + + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { + if (on) { + adv7180_csi_write(state, 0xDE, 0x02); + adv7180_csi_write(state, 0xD2, 0xF7); + adv7180_csi_write(state, 0xD8, 0x65); + adv7180_csi_write(state, 0xE0, 0x09); + adv7180_csi_write(state, 0x2C, 0x00); + if (state->field == V4L2_FIELD_NONE) + adv7180_csi_write(state, 0x1D, 0x80); + adv7180_csi_write(state, 0x00, 0x00); + } else { + adv7180_csi_write(state, 0x00, 0x80); + } + } + + return 0; +} + static v4l2_std_id adv7180_std_to_v4l2(u8 status1) { /* in case V4L2_IN_ST_NO_SIGNAL */ @@ -357,32 +388,27 @@ static inline struct adv7180_state *to_state(struct v4l2_subdev *sd) static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) { struct adv7180_state *state = to_state(sd); - int err = mutex_lock_interruptible(&state->mutex); - if (err) - return err; - - if (state->streaming) { - err = -EBUSY; - goto unlock; - } + int ret; - err = adv7180_set_video_standard(state, - ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); - if (err) - goto unlock; + guard(mutex)(&state->mutex); - msleep(100); - __adv7180_status(state, NULL, std); + /* + * We can't sample the standard if the device is streaming as that would + * interfere with the capture session as the VID_SEL reg is touched. + */ + if (state->streaming) + return -EBUSY; - err = v4l2_std_to_adv7180(state->curr_norm); - if (err < 0) - goto unlock; + /* Set the standard to autodetect PAL B/G/H/I/D, NTSC J or SECAM */ + ret = adv7180_set_video_standard(state, + ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM); + if (ret) + return ret; - err = adv7180_set_video_standard(state, err); + /* Allow some time for the autodetection to run. */ + msleep(100); -unlock: - mutex_unlock(&state->mutex); - return err; + return __adv7180_status(state, NULL, std); } static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input, @@ -437,22 +463,18 @@ static int adv7180_program_std(struct adv7180_state *state) static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct adv7180_state *state = to_state(sd); - int ret = mutex_lock_interruptible(&state->mutex); + int ret; - if (ret) - return ret; + guard(mutex)(&state->mutex); /* Make sure we can support this std */ ret = v4l2_std_to_adv7180(std); if (ret < 0) - goto out; + return ret; state->curr_norm = std; - ret = adv7180_program_std(state); -out: - mutex_unlock(&state->mutex); - return ret; + return 0; } static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm) @@ -514,55 +536,6 @@ static void adv7180_set_reset_pin(struct adv7180_state *state, bool on) } } -static int adv7180_set_power(struct adv7180_state *state, bool on) -{ - u8 val; - int ret; - - if (on) - val = ADV7180_PWR_MAN_ON; - else - val = ADV7180_PWR_MAN_OFF; - - ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val); - if (ret) - return ret; - - if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { - if (on) { - adv7180_csi_write(state, 0xDE, 0x02); - adv7180_csi_write(state, 0xD2, 0xF7); - adv7180_csi_write(state, 0xD8, 0x65); - adv7180_csi_write(state, 0xE0, 0x09); - adv7180_csi_write(state, 0x2C, 0x00); - if (state->field == V4L2_FIELD_NONE) - adv7180_csi_write(state, 0x1D, 0x80); - adv7180_csi_write(state, 0x00, 0x00); - } else { - adv7180_csi_write(state, 0x00, 0x80); - } - } - - return 0; -} - -static int adv7180_s_power(struct v4l2_subdev *sd, int on) -{ - struct adv7180_state *state = to_state(sd); - int ret; - - ret = mutex_lock_interruptible(&state->mutex); - if (ret) - return ret; - - ret = adv7180_set_power(state, on); - if (ret == 0) - state->powered = on; - - mutex_unlock(&state->mutex); - return ret; -} - static const char * const test_pattern_menu[] = { "Single color", "Color bars", @@ -601,11 +574,11 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_adv7180_sd(ctrl); struct adv7180_state *state = to_state(sd); - int ret = mutex_lock_interruptible(&state->mutex); + int ret = 0; int val; - if (ret) - return ret; + lockdep_assert_held(&state->mutex); + val = ctrl->val; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: @@ -647,7 +620,6 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) ret = -EINVAL; } - mutex_unlock(&state->mutex); return ret; } @@ -668,6 +640,7 @@ static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = { static int adv7180_init_controls(struct adv7180_state *state) { v4l2_ctrl_handler_init(&state->ctrl_hdl, 4); + state->ctrl_hdl.lock = &state->mutex; v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops, V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN, @@ -700,7 +673,6 @@ static int adv7180_init_controls(struct adv7180_state *state) v4l2_ctrl_handler_free(&state->ctrl_hdl); return err; } - v4l2_ctrl_handler_setup(&state->ctrl_hdl); return 0; } @@ -812,12 +784,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd, ret = adv7180_mbus_fmt(sd, &format->format); if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - if (state->field != format->format.field) { - state->field = format->format.field; - adv7180_set_power(state, false); - adv7180_set_field_mode(state); - adv7180_set_power(state, true); - } + state->field = format->format.field; } else { framefmt = v4l2_subdev_state_get_format(sd_state, 0); *framefmt = format->format; @@ -874,23 +841,117 @@ static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) return 0; } -static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) +static int init_device(struct adv7180_state *state) { - struct adv7180_state *state = to_state(sd); int ret; - /* It's always safe to stop streaming, no need to take the lock */ - if (!enable) { - state->streaming = enable; - return 0; + lockdep_assert_held(&state->mutex); + + ret = adv7180_program_std(state); + if (ret) + return ret; + + adv7180_set_field_mode(state); + + __v4l2_ctrl_handler_setup(&state->ctrl_hdl); + + return ret; +} + +static int adv7180_reset_device(struct adv7180_state *state) +{ + int ret; + + lockdep_assert_held(&state->mutex); + + adv7180_set_power_pin(state, true); + adv7180_set_reset_pin(state, false); + + adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); + usleep_range(5000, 10000); + + /* + * If the devices decoder is power on after reset, power off so the + * device can be configured. + */ + if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) + adv7180_set_power(state, false); + + ret = state->chip_info->init(state); + if (ret) + return ret; + + ret = init_device(state); + if (ret) + return ret; + + /* register for interrupts */ + if (state->irq > 0) { + /* config the Interrupt pin to be active low */ + ret = adv7180_write(state, ADV7180_REG_ICONF1, + ADV7180_ICONF1_ACTIVE_LOW | + ADV7180_ICONF1_PSYNC_ONLY); + if (ret < 0) + return ret; + + ret = adv7180_write(state, ADV7180_REG_IMR1, 0); + if (ret < 0) + return ret; + + ret = adv7180_write(state, ADV7180_REG_IMR2, 0); + if (ret < 0) + return ret; + + /* enable AD change interrupts */ + ret = adv7180_write(state, ADV7180_REG_IMR3, + ADV7180_IRQ3_AD_CHANGE); + if (ret < 0) + return ret; + + ret = adv7180_write(state, ADV7180_REG_IMR4, 0); + if (ret < 0) + return ret; } + /* + * If the devices decoder is power on after reset, restore the power + * after configuration. This is to preserve the behavior of the driver, + * not doing this result in the first 35+ frames captured being garbage. + */ + if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) + adv7180_set_power(state, true); + + return 0; +} + +static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct adv7180_state *state = to_state(sd); + int ret; + /* Must wait until querystd released the lock */ - ret = mutex_lock_interruptible(&state->mutex); + guard(mutex)(&state->mutex); + + /* + * Always power off the decoder even if streaming is to be enabled, the + * decoder needs to be off for the device to be configured. + */ + ret = adv7180_set_power(state, false); if (ret) return ret; + + if (enable) { + ret = init_device(state); + if (ret) + return ret; + + ret = adv7180_set_power(state, true); + if (ret) + return ret; + } + state->streaming = enable; - mutex_unlock(&state->mutex); + return 0; } @@ -919,7 +980,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { }; static const struct v4l2_subdev_core_ops adv7180_core_ops = { - .s_power = adv7180_s_power, .subscribe_event = adv7180_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; @@ -1343,62 +1403,6 @@ static const struct adv7180_chip_info adv7282_m_info = { .select_input = adv7182_select_input, }; -static int init_device(struct adv7180_state *state) -{ - int ret; - - mutex_lock(&state->mutex); - - adv7180_set_power_pin(state, true); - adv7180_set_reset_pin(state, false); - - adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); - usleep_range(5000, 10000); - - ret = state->chip_info->init(state); - if (ret) - goto out_unlock; - - ret = adv7180_program_std(state); - if (ret) - goto out_unlock; - - adv7180_set_field_mode(state); - - /* register for interrupts */ - if (state->irq > 0) { - /* config the Interrupt pin to be active low */ - ret = adv7180_write(state, ADV7180_REG_ICONF1, - ADV7180_ICONF1_ACTIVE_LOW | - ADV7180_ICONF1_PSYNC_ONLY); - if (ret < 0) - goto out_unlock; - - ret = adv7180_write(state, ADV7180_REG_IMR1, 0); - if (ret < 0) - goto out_unlock; - - ret = adv7180_write(state, ADV7180_REG_IMR2, 0); - if (ret < 0) - goto out_unlock; - - /* enable AD change interrupts interrupts */ - ret = adv7180_write(state, ADV7180_REG_IMR3, - ADV7180_IRQ3_AD_CHANGE); - if (ret < 0) - goto out_unlock; - - ret = adv7180_write(state, ADV7180_REG_IMR4, 0); - if (ret < 0) - goto out_unlock; - } - -out_unlock: - mutex_unlock(&state->mutex); - - return ret; -} - static int adv7180_probe(struct i2c_client *client) { struct device_node *np = client->dev.of_node; @@ -1457,10 +1461,7 @@ static int adv7180_probe(struct i2c_client *client) state->irq = client->irq; mutex_init(&state->mutex); state->curr_norm = V4L2_STD_NTSC; - if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED) - state->powered = true; - else - state->powered = false; + state->input = 0; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7180_ops); @@ -1477,7 +1478,9 @@ static int adv7180_probe(struct i2c_client *client) if (ret) goto err_free_ctrl; - ret = init_device(state); + mutex_lock(&state->mutex); + ret = adv7180_reset_device(state); + mutex_unlock(&state->mutex); if (ret) goto err_media_entity_cleanup; @@ -1549,6 +1552,8 @@ static int adv7180_suspend(struct device *dev) struct v4l2_subdev *sd = dev_get_drvdata(dev); struct adv7180_state *state = to_state(sd); + guard(mutex)(&state->mutex); + return adv7180_set_power(state, false); } @@ -1558,13 +1563,18 @@ static int adv7180_resume(struct device *dev) struct adv7180_state *state = to_state(sd); int ret; - ret = init_device(state); + guard(mutex)(&state->mutex); + + ret = adv7180_reset_device(state); if (ret < 0) return ret; - ret = adv7180_set_power(state, state->powered); - if (ret) - return ret; + /* If we were streaming when suspending, start decoder. */ + if (state->streaming) { + ret = adv7180_set_power(state, true); + if (ret) + return ret; + } return 0; } diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index afed38596362..516553fb17e9 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 <hansverk@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>"); MODULE_LICENSE("GPL"); @@ -3670,7 +3670,7 @@ static int adv76xx_probe(struct i2c_client *client) err = media_entity_pads_init(&sd->entity, state->source_pad + 1, state->pads); if (err) - goto err_work_queues; + goto err_i2c; /* Configure regmaps */ err = configure_regmaps(state); @@ -3711,8 +3711,6 @@ static int adv76xx_probe(struct i2c_client *client) err_entity: media_entity_cleanup(&sd->entity); -err_work_queues: - cancel_delayed_work(&state->delayed_work_enable_hotplug); err_i2c: adv76xx_unregister_clients(state); err_hdl: diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 5545cd23e113..ea6966c0605e 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 <hansverk@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_AUTHOR("Martin Bugge <marbugge@cisco.com>"); MODULE_LICENSE("GPL"); @@ -2699,6 +2699,7 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) /* CP block */ struct adv7842_state *state = to_state(sd); struct v4l2_dv_timings timings; + int temp; u8 reg_io_0x02 = io_read(sd, 0x02); u8 reg_io_0x21 = io_read(sd, 0x21); u8 reg_rep_0x77 = rep_read(sd, 0x77); @@ -2821,8 +2822,9 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? "(16-235)" : "(0-255)", (reg_io_0x02 & 0x08) ? "enabled" : "disabled"); + temp = cp_read(sd, 0xf4) >> 4; v4l2_info(sd, "Color space conversion: %s\n", - csc_coeff_sel_rb[cp_read(sd, 0xf4) >> 4]); + temp < 0 ? "" : csc_coeff_sel_rb[temp]); if (!is_digital_input(sd)) return 0; @@ -2852,8 +2854,9 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd) hdmi_read(sd, 0x5f)); v4l2_info(sd, "AV Mute: %s\n", (hdmi_read(sd, 0x04) & 0x40) ? "on" : "off"); + temp = hdmi_read(sd, 0x0b) >> 6; v4l2_info(sd, "Deep color mode: %s\n", - deep_color_mode_txt[hdmi_read(sd, 0x0b) >> 6]); + temp < 0 ? "" : deep_color_mode_txt[temp]); adv7842_log_infoframes(sd); @@ -3466,8 +3469,8 @@ static struct i2c_client *adv7842_dummy_client(struct v4l2_subdev *sd, const cha cp = i2c_new_dummy_device(client->adapter, io_read(sd, io_reg) >> 1); if (IS_ERR(cp)) { - v4l2_err(sd, "register %s on i2c addr 0x%x failed with %ld\n", - desc, addr, PTR_ERR(cp)); + v4l2_err(sd, "register %s on i2c addr 0x%x failed with %pe\n", + desc, addr, cp); cp = NULL; } @@ -3626,7 +3629,7 @@ static int adv7842_probe(struct i2c_client *client) err = media_entity_pads_init(&sd->entity, ADV7842_PAD_SOURCE + 1, state->pads); if (err) - goto err_work_queues; + goto err_i2c; err = adv7842_core_init(sd); if (err) @@ -3647,8 +3650,6 @@ static int adv7842_probe(struct i2c_client *client) err_entity: media_entity_cleanup(&sd->entity); -err_work_queues: - cancel_delayed_work(&state->delayed_work_enable_hotplug); err_i2c: adv7842_unregister_clients(sd); err_hdl: diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c index 05b708bd0a64..1f088acecf36 100644 --- a/drivers/media/i2c/alvium-csi2.c +++ b/drivers/media/i2c/alvium-csi2.c @@ -1841,7 +1841,6 @@ static int alvium_s_stream(struct v4l2_subdev *sd, int enable) } else { alvium_set_stream_mipi(alvium, enable); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index 24873149096c..f156058500e3 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -1077,11 +1077,10 @@ static int ar0521_probe(struct i2c_client *client) } /* Get master clock (extclk) */ - sensor->extclk = devm_clk_get(dev, "extclk"); - if (IS_ERR(sensor->extclk)) { - dev_err(dev, "failed to get extclk\n"); - return PTR_ERR(sensor->extclk); - } + sensor->extclk = devm_v4l2_sensor_clk_get(dev, "extclk"); + if (IS_ERR(sensor->extclk)) + return dev_err_probe(dev, PTR_ERR(sensor->extclk), + "failed to get extclk\n"); sensor->extclk_freq = clk_get_rate(sensor->extclk); @@ -1110,8 +1109,8 @@ static int ar0521_probe(struct i2c_client *client) ar0521_supply_names[cnt]); if (IS_ERR(supply)) { - dev_info(dev, "no %s regulator found: %li\n", - ar0521_supply_names[cnt], PTR_ERR(supply)); + dev_info(dev, "no %s regulator found: %pe\n", + ar0521_supply_names[cnt], supply); return PTR_ERR(supply); } sensor->supplies[cnt] = supply; diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 487bcabb4a19..f8523140784c 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -787,10 +787,8 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) rval = -EINVAL; } - if (pm_status > 0) { - pm_runtime_mark_last_busy(&client->dev); + if (pm_status > 0) pm_runtime_put_autosuspend(&client->dev); - } return rval; } @@ -1914,7 +1912,6 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) if (!enable) { ccs_stop_streaming(sensor); sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; @@ -1929,7 +1926,6 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) rval = ccs_start_streaming(sensor); if (rval < 0) { sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } @@ -2677,7 +2673,6 @@ nvm_show(struct device *dev, struct device_attribute *attr, char *buf) return -ENODEV; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); /* @@ -3242,8 +3237,8 @@ static int ccs_probe(struct i2c_client *client) dev_info(&client->dev, "no clock defined, continuing...\n"); sensor->ext_clk = NULL; } else if (IS_ERR(sensor->ext_clk)) { - dev_err(&client->dev, "could not get clock (%ld)\n", - PTR_ERR(sensor->ext_clk)); + dev_err(&client->dev, "could not get clock (%pe)\n", + sensor->ext_clk); return -EPROBE_DEFER; } @@ -3299,8 +3294,8 @@ static int ccs_probe(struct i2c_client *client) sensor->regmap = devm_cci_regmap_init_i2c(client, 16); if (IS_ERR(sensor->regmap)) { - dev_err(&client->dev, "can't initialise CCI (%ld)\n", - PTR_ERR(sensor->regmap)); + dev_err(&client->dev, "can't initialise CCI (%pe)\n", + sensor->regmap); return PTR_ERR(sensor->regmap); } diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index a90a9e5705a0..a86306304330 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -9,10 +9,10 @@ * Changes by Tyler Trafford <tatrafford@comcast.net> * - cleanup/rewrite for V4L2 API (2005) * - * VBI support by Hans Verkuil <hverkuil@xs4all.nl>. + * VBI support by Hans Verkuil <hverkuil@kernel.org>. * * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> - * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. + * with additional fixes by Hans Verkuil <hverkuil@kernel.org>. * * CX23885 support by Steven Toth <stoth@linuxtv.org>. * diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index a80da2b4a8fa..e97e499b04e6 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -333,8 +333,7 @@ static int _ub913_set_routing(struct v4l2_subdev *sd, .quantization = V4L2_QUANTIZATION_LIM_RANGE, .xfer_func = V4L2_XFER_FUNC_SRGB, }; - struct v4l2_subdev_stream_configs *stream_configs; - unsigned int i; + struct v4l2_subdev_route *route; int ret; ret = v4l2_subdev_routing_validate(sd, routing, @@ -346,13 +345,15 @@ static int _ub913_set_routing(struct v4l2_subdev *sd, if (ret) return ret; - stream_configs = &state->stream_configs; + for_each_active_route(&state->routing, route) { + struct v4l2_mbus_framefmt *fmt; - for (i = 0; i < stream_configs->num_configs; i++) { - if (stream_configs->configs[i].pad == UB913_PAD_SINK) - stream_configs->configs[i].fmt = in_format; - else - stream_configs->configs[i].fmt = out_format; + fmt = v4l2_subdev_state_get_format(state, route->sink_pad, + route->sink_stream); + *fmt = in_format; + fmt = v4l2_subdev_state_get_format(state, route->source_pad, + route->source_stream); + *fmt = out_format; } return 0; @@ -621,7 +622,7 @@ static int ub913_v4l2_notifier_register(struct ub913_data *priv) fwnode_handle_put(ep_fwnode); if (IS_ERR(asd)) { - dev_err(dev, "Failed to add subdev: %ld", PTR_ERR(asd)); + dev_err(dev, "Failed to add subdev: %pe", asd); v4l2_async_nf_cleanup(&priv->notifier); return PTR_ERR(asd); } diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c index e3fc9d66970a..daefdb108fbf 100644 --- a/drivers/media/i2c/ds90ub953.c +++ b/drivers/media/i2c/ds90ub953.c @@ -776,7 +776,7 @@ static int ub953_v4l2_notifier_register(struct ub953_data *priv) fwnode_handle_put(ep_fwnode); if (IS_ERR(asd)) { - dev_err(dev, "Failed to add subdev: %ld", PTR_ERR(asd)); + dev_err(dev, "Failed to add subdev: %pe", asd); v4l2_async_nf_cleanup(&priv->notifier); return PTR_ERR(asd); } @@ -1023,15 +1023,17 @@ static unsigned long ub953_clkout_recalc_rate(struct clk_hw *hw, return rate; } -static long ub953_clkout_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int ub953_clkout_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct ub953_data *priv = container_of(hw, struct ub953_data, clkout_clk_hw); struct ub953_clkout_data clkout_data; - ub953_calc_clkout_params(priv, rate, &clkout_data); + ub953_calc_clkout_params(priv, req->rate, &clkout_data); + + req->rate = clkout_data.rate; - return clkout_data.rate; + return 0; } static int ub953_clkout_set_rate(struct clk_hw *hw, unsigned long rate, @@ -1050,7 +1052,7 @@ static int ub953_clkout_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops ub953_clkout_ops = { .recalc_rate = ub953_clkout_recalc_rate, - .round_rate = ub953_clkout_round_rate, + .determine_rate = ub953_clkout_determine_rate, .set_rate = ub953_clkout_set_rate, }; diff --git a/drivers/media/i2c/dw9719.c b/drivers/media/i2c/dw9719.c index 032fbcb981f2..59558335989e 100644 --- a/drivers/media/i2c/dw9719.c +++ b/drivers/media/i2c/dw9719.c @@ -23,6 +23,25 @@ #define DW9719_CTRL_STEPS 16 #define DW9719_CTRL_DELAY_US 1000 +#define DW9718S_PD CCI_REG8(0) + +#define DW9718S_CONTROL CCI_REG8(1) +#define DW9718S_CONTROL_SW_LINEAR BIT(0) +#define DW9718S_CONTROL_SAC_SHIFT 1 +#define DW9718S_CONTROL_SAC_MASK 0x7 +#define DW9718S_CONTROL_OCP_DISABLE BIT(4) +#define DW9718S_CONTROL_UVLO_DISABLE BIT(5) +#define DW9718S_DEFAULT_SAC 4 + +#define DW9718S_VCM_CURRENT CCI_REG16(2) + +#define DW9718S_SW CCI_REG8(4) +#define DW9718S_SW_VCM_FREQ_MASK 0xF +#define DW9718S_DEFAULT_VCM_FREQ 0 + +#define DW9718S_SACT CCI_REG8(5) +#define DW9718S_SACT_PERIOD_8_8MS 0x19 + #define DW9719_INFO CCI_REG8(0) #define DW9719_ID 0xF1 #define DW9761_ID 0xF4 @@ -49,12 +68,17 @@ #define DW9761_VCM_PRELOAD CCI_REG8(8) #define DW9761_DEFAULT_VCM_PRELOAD 0x73 +#define DW9800K_DEFAULT_SAC 1 +#define DW9800K_MODE_SAC_SHIFT 6 +#define DW9800K_DEFAULT_VCM_FREQ 0x10 #define to_dw9719_device(x) container_of(x, struct dw9719_device, sd) enum dw9719_model { + DW9718S, DW9719, DW9761, + DW9800K, }; struct dw9719_device { @@ -75,26 +99,55 @@ struct dw9719_device { static int dw9719_power_down(struct dw9719_device *dw9719) { + u32 reg_pwr = dw9719->model == DW9718S ? DW9718S_PD : DW9719_CONTROL; + + /* + * Worth engaging the internal SHUTDOWN mode especially due to the + * regulator being potentially shared with other devices. + */ + if (cci_write(dw9719->regmap, reg_pwr, DW9719_SHUTDOWN, NULL)) + dev_err(dw9719->dev, "Error writing to power register\n"); return regulator_disable(dw9719->regulator); } static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) { + u32 reg_pwr = dw9719->model == DW9718S ? DW9718S_PD : DW9719_CONTROL; u64 val; int ret; + int err; ret = regulator_enable(dw9719->regulator); if (ret) return ret; - /* Jiggle SCL pin to wake up device */ - cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret); - fsleep(100); - cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_STANDBY, &ret); - /* Need 100us to transit from SHUTDOWN to STANDBY */ - fsleep(100); + /* + * Need 100us to transition from SHUTDOWN to STANDBY. + * Jiggle the SCL pin to wake up the device (even when the regulator is + * shared) and wait double the time to be sure, as 100us is not enough + * at least on the DW9718S as found on the motorola-nora smartphone, + * then retry the write. + */ + cci_write(dw9719->regmap, reg_pwr, DW9719_STANDBY, NULL); + /* the jiggle is expected to fail, don't even log that as error */ + fsleep(200); + cci_write(dw9719->regmap, reg_pwr, DW9719_STANDBY, &ret); if (detect) { + /* These models do not have an INFO register */ + switch (dw9719->model) { + case DW9718S: + dw9719->sac_mode = DW9718S_DEFAULT_SAC; + dw9719->vcm_freq = DW9718S_DEFAULT_VCM_FREQ; + goto props; + case DW9800K: + dw9719->sac_mode = DW9800K_DEFAULT_SAC; + dw9719->vcm_freq = DW9800K_DEFAULT_VCM_FREQ; + goto props; + default: + break; + } + ret = cci_read(dw9719->regmap, DW9719_INFO, &val, NULL); if (ret < 0) return ret; @@ -118,23 +171,52 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) return -ENXIO; } +props: /* Optional indication of SAC mode select */ device_property_read_u32(dw9719->dev, "dongwoon,sac-mode", &dw9719->sac_mode); /* Optional indication of VCM frequency */ - device_property_read_u32(dw9719->dev, "dongwoon,vcm-freq", + err = device_property_read_u32(dw9719->dev, "dongwoon,vcm-freq", + &dw9719->vcm_freq); + if (err == 0) + dev_warn(dw9719->dev, "dongwoon,vcm-freq property is deprecated, please use dongwoon,vcm-prescale\n"); + + /* Optional indication of VCM prescale */ + device_property_read_u32(dw9719->dev, "dongwoon,vcm-prescale", &dw9719->vcm_freq); } - cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_ENABLE_RINGING, &ret); - cci_write(dw9719->regmap, DW9719_MODE, dw9719->mode_low_bits | - (dw9719->sac_mode << DW9719_MODE_SAC_SHIFT), &ret); - cci_write(dw9719->regmap, DW9719_VCM_FREQ, dw9719->vcm_freq, &ret); - - if (dw9719->model == DW9761) + switch (dw9719->model) { + case DW9800K: + cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_ENABLE_RINGING, &ret); + cci_write(dw9719->regmap, DW9719_MODE, + dw9719->sac_mode << DW9800K_MODE_SAC_SHIFT, &ret); + cci_write(dw9719->regmap, DW9719_VCM_FREQ, dw9719->vcm_freq, &ret); + break; + case DW9718S: + /* Datasheet says [OCP/UVLO] should be disabled below 2.5V */ + dw9719->sac_mode &= DW9718S_CONTROL_SAC_MASK; + cci_write(dw9719->regmap, DW9718S_CONTROL, + DW9718S_CONTROL_SW_LINEAR | + (dw9719->sac_mode << DW9718S_CONTROL_SAC_SHIFT) | + DW9718S_CONTROL_OCP_DISABLE | + DW9718S_CONTROL_UVLO_DISABLE, &ret); + cci_write(dw9719->regmap, DW9718S_SACT, + DW9718S_SACT_PERIOD_8_8MS, &ret); + cci_write(dw9719->regmap, DW9718S_SW, + dw9719->vcm_freq & DW9718S_SW_VCM_FREQ_MASK, &ret); + break; + case DW9761: cci_write(dw9719->regmap, DW9761_VCM_PRELOAD, DW9761_DEFAULT_VCM_PRELOAD, &ret); + fallthrough; + case DW9719: + cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_ENABLE_RINGING, &ret); + cci_write(dw9719->regmap, DW9719_MODE, dw9719->mode_low_bits | + (dw9719->sac_mode << DW9719_MODE_SAC_SHIFT), &ret); + cci_write(dw9719->regmap, DW9719_VCM_FREQ, dw9719->vcm_freq, &ret); + } if (ret) dw9719_power_down(dw9719); @@ -144,7 +226,9 @@ static int dw9719_power_up(struct dw9719_device *dw9719, bool detect) static int dw9719_t_focus_abs(struct dw9719_device *dw9719, s32 value) { - return cci_write(dw9719->regmap, DW9719_VCM_CURRENT, value, NULL); + u32 reg = dw9719->model == DW9718S ? DW9718S_VCM_CURRENT + : DW9719_VCM_CURRENT; + return cci_write(dw9719->regmap, reg, value, NULL); } static int dw9719_set_ctrl(struct v4l2_ctrl *ctrl) @@ -229,7 +313,7 @@ static int dw9719_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int dw9719_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - pm_runtime_put(sd->dev); + pm_runtime_put_autosuspend(sd->dev); return 0; } @@ -275,6 +359,8 @@ static int dw9719_probe(struct i2c_client *client) if (!dw9719) return -ENOMEM; + dw9719->model = (enum dw9719_model)(uintptr_t)i2c_get_match_data(client); + dw9719->regmap = devm_cci_regmap_init_i2c(client, 8); if (IS_ERR(dw9719->regmap)) return PTR_ERR(dw9719->regmap); @@ -353,12 +439,14 @@ static void dw9719_remove(struct i2c_client *client) pm_runtime_set_suspended(&client->dev); } -static const struct i2c_device_id dw9719_id_table[] = { - { "dw9719" }, - { "dw9761" }, +static const struct of_device_id dw9719_of_table[] = { + { .compatible = "dongwoon,dw9718s", .data = (const void *)DW9718S }, + { .compatible = "dongwoon,dw9719", .data = (const void *)DW9719 }, + { .compatible = "dongwoon,dw9761", .data = (const void *)DW9761 }, + { .compatible = "dongwoon,dw9800k", .data = (const void *)DW9800K }, { } }; -MODULE_DEVICE_TABLE(i2c, dw9719_id_table); +MODULE_DEVICE_TABLE(of, dw9719_of_table); static DEFINE_RUNTIME_DEV_PM_OPS(dw9719_pm_ops, dw9719_suspend, dw9719_resume, NULL); @@ -367,10 +455,10 @@ static struct i2c_driver dw9719_i2c_driver = { .driver = { .name = "dw9719", .pm = pm_sleep_ptr(&dw9719_pm_ops), + .of_match_table = dw9719_of_table, }, .probe = dw9719_probe, .remove = dw9719_remove, - .id_table = dw9719_id_table, }; module_i2c_driver(dw9719_i2c_driver); diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c index 3a4d100b9199..d434721ba8ed 100644 --- a/drivers/media/i2c/dw9768.c +++ b/drivers/media/i2c/dw9768.c @@ -374,7 +374,6 @@ 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_mark_last_busy(sd->dev); pm_runtime_put_autosuspend(sd->dev); return 0; diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index 7519863d77b1..2cb7b718782b 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -816,7 +816,6 @@ static int et8ek8_power_on(struct et8ek8_sensor *sensor) { struct v4l2_subdev *subdev = &sensor->subdev; struct i2c_client *client = v4l2_get_subdevdata(subdev); - unsigned int xclk_freq; int val, rval; rval = regulator_enable(sensor->vana); @@ -825,17 +824,6 @@ static int et8ek8_power_on(struct et8ek8_sensor *sensor) return rval; } - if (sensor->current_reglist) - xclk_freq = sensor->current_reglist->mode.ext_clock; - else - xclk_freq = sensor->xclk_freq; - - rval = clk_set_rate(sensor->ext_clk, xclk_freq); - if (rval < 0) { - dev_err(&client->dev, "unable to set extclk clock freq to %u\n", - xclk_freq); - goto out; - } rval = clk_prepare_enable(sensor->ext_clk); if (rval < 0) { dev_err(&client->dev, "failed to enable extclk\n"); @@ -849,7 +837,7 @@ static int et8ek8_power_on(struct et8ek8_sensor *sensor) gpiod_set_value(sensor->reset, 1); - msleep(5000 * 1000 / xclk_freq + 1); /* Wait 5000 cycles */ + msleep(5000 * 1000 / sensor->xclk_freq + 1); /* Wait 5000 cycles */ rval = et8ek8_i2c_reglist_find_write(client, &meta_reglist, ET8EK8_REGLIST_POWERON); @@ -1085,9 +1073,6 @@ static int et8ek8_set_frame_interval(struct v4l2_subdev *subdev, if (!reglist) return -EINVAL; - if (sensor->current_reglist->mode.ext_clock != reglist->mode.ext_clock) - return -EINVAL; - sensor->current_reglist = reglist; et8ek8_update_controls(sensor); @@ -1433,18 +1418,13 @@ static int et8ek8_probe(struct i2c_client *client) return PTR_ERR(sensor->vana); } - sensor->ext_clk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->ext_clk)) { - dev_err(&client->dev, "could not get clock\n"); - return PTR_ERR(sensor->ext_clk); - } + sensor->ext_clk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, true, + 9600000); + if (IS_ERR(sensor->ext_clk)) + return dev_err_probe(&client->dev, PTR_ERR(sensor->ext_clk), + "could not get clock\n"); - ret = of_property_read_u32(dev->of_node, "clock-frequency", - &sensor->xclk_freq); - if (ret) { - dev_warn(dev, "can't get clock-frequency\n"); - return ret; - } + sensor->xclk_freq = clk_get_rate(sensor->ext_clk); mutex_init(&sensor->power_lock); diff --git a/drivers/media/i2c/et8ek8/et8ek8_mode.c b/drivers/media/i2c/et8ek8/et8ek8_mode.c index c9088eb0a812..914be1007099 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_mode.c +++ b/drivers/media/i2c/et8ek8/et8ek8_mode.c @@ -44,7 +44,6 @@ static struct et8ek8_reglist mode1_poweron_mode2_16vga_2592x1968_12_07fps = { .window_width = 2592, .window_height = 1968, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 1207 @@ -145,7 +144,6 @@ static struct et8ek8_reglist mode1_16vga_2592x1968_13_12fps_dpcm10_8 = { .window_width = 2592, .window_height = 1968, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 1292 @@ -201,7 +199,6 @@ static struct et8ek8_reglist mode3_4vga_1296x984_29_99fps_dpcm10_8 = { .window_width = 1296, .window_height = 984, .pixel_clock = 96533333, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 3000 @@ -257,7 +254,6 @@ static struct et8ek8_reglist mode4_svga_864x656_29_88fps = { .window_width = 864, .window_height = 656, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 2988 @@ -313,7 +309,6 @@ static struct et8ek8_reglist mode5_vga_648x492_29_93fps = { .window_width = 648, .window_height = 492, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 2993 @@ -369,7 +364,6 @@ static struct et8ek8_reglist mode2_16vga_2592x1968_3_99fps = { .window_width = 2592, .window_height = 1968, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 399 @@ -424,7 +418,6 @@ static struct et8ek8_reglist mode_648x492_5fps = { .window_width = 648, .window_height = 492, .pixel_clock = 13333333, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 499 @@ -480,7 +473,6 @@ static struct et8ek8_reglist mode3_4vga_1296x984_5fps = { .window_width = 1296, .window_height = 984, .pixel_clock = 49400000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 501 @@ -536,7 +528,6 @@ static struct et8ek8_reglist mode_4vga_1296x984_25fps_dpcm10_8 = { .window_width = 1296, .window_height = 984, .pixel_clock = 84266667, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 2500 diff --git a/drivers/media/i2c/et8ek8/et8ek8_reg.h b/drivers/media/i2c/et8ek8/et8ek8_reg.h index c90e74935f12..3305986c7c9c 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_reg.h +++ b/drivers/media/i2c/et8ek8/et8ek8_reg.h @@ -37,7 +37,6 @@ struct et8ek8_mode { u16 window_height; u32 pixel_clock; /* in Hz */ - u32 ext_clock; /* in Hz */ struct v4l2_fract timeperframe; u32 max_exp; /* Maximum exposure value */ u32 bus_format; /* MEDIA_BUS_FMT_ */ diff --git a/drivers/media/i2c/gc0308.c b/drivers/media/i2c/gc0308.c index 069f42785b3c..cbcda0e18ff1 100644 --- a/drivers/media/i2c/gc0308.c +++ b/drivers/media/i2c/gc0308.c @@ -974,7 +974,6 @@ static int gc0308_s_ctrl(struct v4l2_ctrl *ctrl) if (ret) dev_err(gc0308->dev, "failed to set control: %d\n", ret); - pm_runtime_mark_last_busy(gc0308->dev); pm_runtime_put_autosuspend(gc0308->dev); return ret; @@ -1157,14 +1156,12 @@ static int gc0308_start_stream(struct gc0308 *gc0308) return 0; disable_pm: - pm_runtime_mark_last_busy(gc0308->dev); pm_runtime_put_autosuspend(gc0308->dev); return ret; } static int gc0308_stop_stream(struct gc0308 *gc0308) { - pm_runtime_mark_last_busy(gc0308->dev); pm_runtime_put_autosuspend(gc0308->dev); return 0; } diff --git a/drivers/media/i2c/gc0310.c b/drivers/media/i2c/gc0310.c new file mode 100644 index 000000000000..7af4d66f42a0 --- /dev/null +++ b/drivers/media/i2c/gc0310.c @@ -0,0 +1,783 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for GalaxyCore GC0310 VGA camera sensor. + * + * Copyright (c) 2013 Intel Corporation. All Rights Reserved. + * Copyright (c) 2023-2025 Hans de Goede <hansg@kernel.org> + */ + +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define GC0310_NATIVE_WIDTH 656 +#define GC0310_NATIVE_HEIGHT 496 + +/* + * The actual PLL output rate is unknown, the datasheet + * says that the formula for the frame-time in pixels is: + * rowtime = win-width + hblank + sh-delay + 4 + * frametime = rowtime * (win-height + vblank) + * Filling this in and multiplying by 30 fps gives: + * pixelrate = (660 + 178 + 42 + 4) * (498 + 27) * 30 = 13923000 + */ +#define GC0310_PIXELRATE 13923000 +/* single lane, bus-format is 8 bpp, CSI-2 is double data rate */ +#define GC0310_LINK_FREQ (GC0310_PIXELRATE * 8 / 2) +#define GC0310_MCLK_FREQ 19200000 +#define GC0310_FPS 30 +#define GC0310_SKIP_FRAMES 3 + +#define GC0310_ID 0xa310 + +#define GC0310_RESET_RELATED_REG CCI_REG8(0xfe) +#define GC0310_REGISTER_PAGE_0 0x0 +#define GC0310_REGISTER_PAGE_3 0x3 + +/* + * GC0310 System control registers + */ +#define GC0310_SW_STREAM_REG CCI_REG8(0x10) + +#define GC0310_START_STREAMING 0x94 /* 8-bit enable */ +#define GC0310_STOP_STREAMING 0x0 /* 8-bit disable */ + +#define GC0310_SC_CMMN_CHIP_ID_REG CCI_REG16(0xf0) + +#define GC0310_AEC_PK_EXPO_REG CCI_REG16(0x03) +#define GC0310_AGC_ADJ_REG CCI_REG8(0x48) +#define GC0310_DGC_ADJ_REG CCI_REG8(0x71) + +#define GC0310_H_CROP_START_REG CCI_REG16(0x09) +#define GC0310_V_CROP_START_REG CCI_REG16(0x0b) +#define GC0310_H_OUTSIZE_REG CCI_REG16(0x0f) +#define GC0310_V_OUTSIZE_REG CCI_REG16(0x0d) + +#define GC0310_H_BLANKING_REG CCI_REG16(0x05) +/* Hblank-register + sh-delay + H-crop + 4 (from hw) */ +#define GC0310_H_BLANK_DEFAULT (178 + 42 + 4 + 4) + +#define GC0310_V_BLANKING_REG CCI_REG16(0x07) +/* Vblank needs an offset compensate for the small V-crop done */ +#define GC0310_V_BLANK_OFFSET 2 +/* Vsync start time + 1 row vsync + vsync end time + offset */ +#define GC0310_V_BLANK_MIN (9 + 1 + 4 + GC0310_V_BLANK_OFFSET) +#define GC0310_V_BLANK_DEFAULT (27 + GC0310_V_BLANK_OFFSET) +#define GC0310_V_BLANK_MAX (4095 - GC0310_NATIVE_HEIGHT) + +#define GC0310_SH_DELAY_REG CCI_REG8(0x11) +#define GC0310_VS_START_TIME_REG CCI_REG8(0x12) +#define GC0310_VS_END_TIME_REG CCI_REG8(0x13) + +#define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd) + +struct gc0310_device { + struct v4l2_subdev sd; + struct media_pad pad; + + struct regmap *regmap; + struct gpio_desc *reset; + struct gpio_desc *powerdown; + + struct gc0310_ctrls { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + } ctrls; +}; + +struct gc0310_reg { + u8 reg; + u8 val; +}; + +static const struct reg_sequence gc0310_reset_register[] = { + /* System registers */ + { 0xfe, 0xf0 }, + { 0xfe, 0xf0 }, + { 0xfe, 0x00 }, + + { 0xfc, 0x0e }, /* 4e */ + { 0xfc, 0x0e }, /* 16//4e // [0]apwd [6]regf_clk_gate */ + { 0xf2, 0x80 }, /* sync output */ + { 0xf3, 0x00 }, /* 1f//01 data output */ + { 0xf7, 0x33 }, /* f9 */ + { 0xf8, 0x05 }, /* 00 */ + { 0xf9, 0x0e }, /* 0x8e //0f */ + { 0xfa, 0x11 }, + + /* MIPI */ + { 0xfe, 0x03 }, + { 0x01, 0x03 }, /* mipi 1lane */ + { 0x02, 0x22 }, /* 0x33 */ + { 0x03, 0x94 }, + { 0x04, 0x01 }, /* fifo_prog */ + { 0x05, 0x00 }, /* fifo_prog */ + { 0x06, 0x80 }, /* b0 //YUV ISP data */ + { 0x11, 0x2a }, /* 1e //LDI set YUV422 */ + { 0x12, 0x90 }, /* 00 //04 //00 //04//00 //LWC[7:0] */ + { 0x13, 0x02 }, /* 05 //05 //LWC[15:8] */ + { 0x15, 0x12 }, /* 0x10 //DPHYY_MODE read_ready */ + { 0x17, 0x01 }, + { 0x40, 0x08 }, + { 0x41, 0x00 }, + { 0x42, 0x00 }, + { 0x43, 0x00 }, + { 0x21, 0x02 }, /* 0x01 */ + { 0x22, 0x02 }, /* 0x01 */ + { 0x23, 0x01 }, /* 0x05 //Nor:0x05 DOU:0x06 */ + { 0x29, 0x00 }, + { 0x2A, 0x25 }, /* 0x05 //data zero 0x7a de */ + { 0x2B, 0x02 }, + + { 0xfe, 0x00 }, + + /* CISCTL */ + { 0x00, 0x2f }, /* 2f//0f//02//01 */ + { 0x01, 0x0f }, /* 06 */ + { 0x02, 0x04 }, + { 0x4f, 0x00 }, /* AEC 0FF */ + { 0x03, 0x01 }, /* 0x03 //04 */ + { 0x04, 0xc0 }, /* 0xe8 //58 */ + { 0x05, 0x00 }, + { 0x06, 0xb2 }, /* 0x0a //HB */ + /* Vblank (reg 0x07 + 0x08) gets set by the vblank ctrl */ + { 0x09, 0x00 }, /* row start */ + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, /* col start */ + { 0x0c, 0x00 }, + { 0x0d, 0x01 }, /* height */ + { 0x0e, 0xf2 }, /* 0xf7 //height */ + { 0x0f, 0x02 }, /* width */ + { 0x10, 0x94 }, /* 0xa0 //height */ + { 0x17, 0x14 }, + { 0x18, 0x1a }, /* 0a//[4]double reset */ + { 0x19, 0x14 }, /* AD pipeline */ + { 0x1b, 0x48 }, + { 0x1e, 0x6b }, /* 3b//col bias */ + { 0x1f, 0x28 }, /* 20//00//08//txlow */ + { 0x20, 0x89 }, /* 88//0c//[3:2]DA15 */ + { 0x21, 0x49 }, /* 48//[3] txhigh */ + { 0x22, 0xb0 }, + { 0x23, 0x04 }, /* [1:0]vcm_r */ + { 0x24, 0x16 }, /* 15 */ + { 0x34, 0x20 }, /* [6:4] rsg high//range */ + + /* BLK */ + { 0x26, 0x23 }, /* [1]dark_current_en [0]offset_en */ + { 0x28, 0xff }, /* BLK_limie_value */ + { 0x29, 0x00 }, /* global offset */ + { 0x33, 0x18 }, /* offset_ratio */ + { 0x37, 0x20 }, /* dark_current_ratio */ + { 0x2a, 0x00 }, + { 0x2b, 0x00 }, + { 0x2c, 0x00 }, + { 0x2d, 0x00 }, + { 0x2e, 0x00 }, + { 0x2f, 0x00 }, + { 0x30, 0x00 }, + { 0x31, 0x00 }, + { 0x47, 0x80 }, /* a7 */ + { 0x4e, 0x66 }, /* select_row */ + { 0xa8, 0x02 }, /* win_width_dark, same with crop_win_width */ + { 0xa9, 0x80 }, + + /* ISP */ + { 0x40, 0x06 }, /* 0xff //ff //48 */ + { 0x41, 0x00 }, /* 0x21 //00//[0]curve_en */ + { 0x42, 0x04 }, /* 0xcf //0a//[1]awn_en */ + { 0x44, 0x18 }, /* 0x18 //02 */ + { 0x46, 0x02 }, /* 0x03 //sync */ + { 0x49, 0x03 }, + { 0x4c, 0x20 }, /* 00[5]pretect exp */ + { 0x50, 0x01 }, /* crop enable */ + { 0x51, 0x00 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x01 }, + { 0x55, 0x01 }, /* crop window height */ + { 0x56, 0xf0 }, + { 0x57, 0x02 }, /* crop window width */ + { 0x58, 0x90 }, + + /* Gain */ + { 0x70, 0x70 }, /* 70 //80//global gain */ + { 0x71, 0x20 }, /* pregain gain */ + { 0x72, 0x40 }, /* post gain */ + { 0x5a, 0x84 }, /* 84//analog gain 0 */ + { 0x5b, 0xc9 }, /* c9 */ + { 0x5c, 0xed }, /* ed//not use pga gain highest level */ + { 0x77, 0x40 }, /* R gain 0x74 //awb gain */ + { 0x78, 0x40 }, /* G gain */ + { 0x79, 0x40 }, /* B gain 0x5f */ + + { 0x48, 0x00 }, + { 0xfe, 0x01 }, + { 0x0a, 0x45 }, /* [7]col gain mode */ + + { 0x3e, 0x40 }, + { 0x3f, 0x5c }, + { 0x40, 0x7b }, + { 0x41, 0xbd }, + { 0x42, 0xf6 }, + { 0x43, 0x63 }, + { 0x03, 0x60 }, + { 0x44, 0x03 }, + + /* Dark / Sun mode related */ + { 0xfe, 0x01 }, + { 0x45, 0xa4 }, /* 0xf7 */ + { 0x46, 0xf0 }, /* 0xff //f0//sun value th */ + { 0x48, 0x03 }, /* sun mode */ + { 0x4f, 0x60 }, /* sun_clamp */ + { 0xfe, 0x00 }, +}; + +static const struct reg_sequence gc0310_VGA_30fps[] = { + { 0xfe, 0x00 }, + { 0x0d, 0x01 }, /* height */ + { 0x0e, 0xf2 }, /* 0xf7 //height */ + { 0x0f, 0x02 }, /* width */ + { 0x10, 0x94 }, /* 0xa0 //height */ + + { 0x50, 0x01 }, /* crop enable */ + { 0x51, 0x00 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x01 }, + { 0x55, 0x01 }, /* crop window height */ + { 0x56, 0xf0 }, + { 0x57, 0x02 }, /* crop window width */ + { 0x58, 0x90 }, + + { 0xfe, 0x03 }, + { 0x12, 0x90 }, /* 00 //04 //00 //04//00 //LWC[7:0] */ + { 0x13, 0x02 }, /* 05 //05 //LWC[15:8] */ + + { 0xfe, 0x00 }, +}; + +static const s64 link_freq_menu_items[] = { + GC0310_LINK_FREQ, +}; + +static int gc0310_gain_set(struct gc0310_device *sensor, u32 gain) +{ + u8 again, dgain; + int ret = 0; + + /* Taken from original driver, this never sets dgain lower then 32? */ + + /* Change 0 - 95 to 32 - 127 */ + gain += 32; + + if (gain < 64) { + again = 0x0; /* sqrt(2) */ + dgain = gain; + } else { + again = 0x2; /* 2 * sqrt(2) */ + dgain = gain / 2; + } + + cci_write(sensor->regmap, GC0310_AGC_ADJ_REG, again, &ret); + cci_write(sensor->regmap, GC0310_DGC_ADJ_REG, dgain, &ret); + return ret; +} + +static int gc0310_exposure_update_range(struct gc0310_device *sensor) +{ + int exp_max = GC0310_NATIVE_HEIGHT + sensor->ctrls.vblank->val; + + return __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 0, exp_max, + 1, exp_max); +} + +static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gc0310_device *sensor = + container_of(ctrl->handler, struct gc0310_device, ctrls.handler); + int ret; + + /* Update exposure range on vblank changes */ + if (ctrl->id == V4L2_CID_VBLANK) { + ret = gc0310_exposure_update_range(sensor); + if (ret) + return ret; + } + + /* Only apply changes to the controls if the device is powered up */ + if (!pm_runtime_get_if_in_use(sensor->sd.dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ret = cci_write(sensor->regmap, GC0310_AEC_PK_EXPO_REG, + ctrl->val, NULL); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = gc0310_gain_set(sensor, ctrl->val); + break; + case V4L2_CID_VBLANK: + ret = cci_write(sensor->regmap, GC0310_V_BLANKING_REG, + ctrl->val - GC0310_V_BLANK_OFFSET, + NULL); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(sensor->sd.dev); + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = gc0310_s_ctrl, +}; + +/* The GC0310 currently only supports 1 fixed fmt */ +static void gc0310_fill_format(struct v4l2_mbus_framefmt *fmt) +{ + memset(fmt, 0, sizeof(*fmt)); + fmt->width = GC0310_NATIVE_WIDTH; + fmt->height = GC0310_NATIVE_HEIGHT; + fmt->field = V4L2_FIELD_NONE; + fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; +} + +static int gc0310_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + /* Only the single fixed 656x496 mode is supported, without croping */ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = GC0310_NATIVE_WIDTH; + sel->r.height = GC0310_NATIVE_HEIGHT; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int gc0310_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct gc0310_device *sensor = to_gc0310_sensor(sd); + + gpiod_set_value_cansleep(sensor->powerdown, 1); + gpiod_set_value_cansleep(sensor->reset, 1); + return 0; +} + +static int gc0310_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct gc0310_device *sensor = to_gc0310_sensor(sd); + + fsleep(10 * USEC_PER_MSEC); + gpiod_set_value_cansleep(sensor->reset, 0); + fsleep(10 * USEC_PER_MSEC); + gpiod_set_value_cansleep(sensor->powerdown, 0); + fsleep(10 * USEC_PER_MSEC); + + return 0; +} + +static int gc0310_detect(struct gc0310_device *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); + u64 val; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = cci_read(sensor->regmap, GC0310_SC_CMMN_CHIP_ID_REG, &val, NULL); + if (ret < 0) { + dev_err(&client->dev, "read sensor_id failed: %d\n", ret); + return -ENODEV; + } + + dev_dbg(&client->dev, "sensor ID = 0x%llx\n", val); + + if (val != GC0310_ID) { + dev_err(&client->dev, "sensor ID error, read id = 0x%llx, target id = 0x%x\n", + val, GC0310_ID); + return -ENODEV; + } + + dev_dbg(&client->dev, "detect gc0310 success\n"); + + return 0; +} + +static int gc0310_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct gc0310_device *sensor = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) + return ret; + + ret = regmap_multi_reg_write(sensor->regmap, + gc0310_reset_register, + ARRAY_SIZE(gc0310_reset_register)); + if (ret) + goto error_power_down; + + ret = regmap_multi_reg_write(sensor->regmap, + gc0310_VGA_30fps, + ARRAY_SIZE(gc0310_VGA_30fps)); + if (ret) + goto error_power_down; + + /* restore value of all ctrls */ + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + + /* enable per frame MIPI and sensor ctrl reset */ + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, 0x30, &ret); + + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_3, &ret); + cci_write(sensor->regmap, GC0310_SW_STREAM_REG, + GC0310_START_STREAMING, &ret); + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_0, &ret); + +error_power_down: + if (ret) + pm_runtime_put(&client->dev); + + return ret; +} + +static int gc0310_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct gc0310_device *sensor = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_3, &ret); + cci_write(sensor->regmap, GC0310_SW_STREAM_REG, + GC0310_STOP_STREAMING, &ret); + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_0, &ret); + + pm_runtime_put(&client->dev); + return ret; +} + +static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + /* We support only a single format */ + if (code->index) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG8_1X8; + return 0; +} + +static int gc0310_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + /* We support only a single resolution */ + if (fse->index) + return -EINVAL; + + fse->min_width = GC0310_NATIVE_WIDTH; + fse->max_width = GC0310_NATIVE_WIDTH; + fse->min_height = GC0310_NATIVE_HEIGHT; + fse->max_height = GC0310_NATIVE_HEIGHT; + + return 0; +} + +static const struct v4l2_subdev_video_ops gc0310_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { + .enum_mbus_code = gc0310_enum_mbus_code, + .enum_frame_size = gc0310_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = v4l2_subdev_get_fmt, /* Only 1 fixed mode supported */ + .get_selection = gc0310_get_selection, + .set_selection = gc0310_get_selection, + .enable_streams = gc0310_enable_streams, + .disable_streams = gc0310_disable_streams, +}; + +static const struct v4l2_subdev_ops gc0310_ops = { + .video = &gc0310_video_ops, + .pad = &gc0310_pad_ops, +}; + +static int gc0310_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + gc0310_fill_format(v4l2_subdev_state_get_format(sd_state, 0)); + return 0; +} + +static const struct v4l2_subdev_internal_ops gc0310_internal_ops = { + .init_state = gc0310_init_state, +}; + +static int gc0310_init_controls(struct gc0310_device *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); + struct v4l2_ctrl_handler *hdl = &sensor->ctrls.handler; + struct v4l2_fwnode_device_properties props; + int exp_max, ret; + + v4l2_ctrl_handler_init(hdl, 8); + + /* Use the same lock for controls as for everything else */ + sensor->sd.ctrl_handler = hdl; + + exp_max = GC0310_NATIVE_HEIGHT + GC0310_V_BLANK_DEFAULT; + sensor->ctrls.exposure = + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_EXPOSURE, 0, + exp_max, 1, exp_max); + + /* 32 steps at base gain 1 + 64 half steps at base gain 2 */ + sensor->ctrls.gain = + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 0, 95, 1, 31); + + sensor->ctrls.link_freq = + v4l2_ctrl_new_int_menu(hdl, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + sensor->ctrls.pixel_rate = + v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_PIXEL_RATE, 0, + GC0310_PIXELRATE, 1, GC0310_PIXELRATE); + + sensor->ctrls.vblank = + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_VBLANK, + GC0310_V_BLANK_MIN, + GC0310_V_BLANK_MAX, 1, + GC0310_V_BLANK_DEFAULT); + + sensor->ctrls.hblank = + v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_HBLANK, + GC0310_H_BLANK_DEFAULT, + GC0310_H_BLANK_DEFAULT, 1, + GC0310_H_BLANK_DEFAULT); + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + return ret; + + v4l2_ctrl_new_fwnode_properties(hdl, &ctrl_ops, &props); + + if (hdl->error) + return hdl->error; + + sensor->ctrls.pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->ctrls.link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->ctrls.hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + return 0; +} + +static void gc0310_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc0310_device *sensor = to_gc0310_sensor(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sensor->sd.entity); + v4l2_ctrl_handler_free(&sensor->ctrls.handler); + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) { + gc0310_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + } +} + +static int gc0310_check_hwcfg(struct device *dev) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct fwnode_handle *ep_fwnode; + unsigned long link_freq_bitmap; + u32 mclk; + int ret; + + /* + * Sometimes the fwnode graph is initialized by the bridge driver. + * Bridge drivers doing this may also add GPIO mappings, wait for this. + */ + ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); + if (!ep_fwnode) + return dev_err_probe(dev, -EPROBE_DEFER, + "waiting for fwnode graph endpoint\n"); + + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &mclk); + if (ret) { + fwnode_handle_put(ep_fwnode); + return dev_err_probe(dev, ret, + "reading clock-frequency property\n"); + } + + if (mclk != GC0310_MCLK_FREQ) { + fwnode_handle_put(ep_fwnode); + return dev_err_probe(dev, -EINVAL, + "external clock %u is not supported\n", + mclk); + } + + ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &bus_cfg); + fwnode_handle_put(ep_fwnode); + if (ret) + return dev_err_probe(dev, ret, "parsing endpoint failed\n"); + + ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq_menu_items, + ARRAY_SIZE(link_freq_menu_items), + &link_freq_bitmap); + + if (ret == 0 && bus_cfg.bus.mipi_csi2.num_data_lanes != 1) + ret = dev_err_probe(dev, -EINVAL, + "number of CSI2 data lanes %u is not supported\n", + bus_cfg.bus.mipi_csi2.num_data_lanes); + + v4l2_fwnode_endpoint_free(&bus_cfg); + return ret; +} + +static int gc0310_probe(struct i2c_client *client) +{ + struct gc0310_device *sensor; + int ret; + + ret = gc0310_check_hwcfg(&client->dev); + if (ret) + return ret; + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset)) { + return dev_err_probe(&client->dev, PTR_ERR(sensor->reset), + "getting reset GPIO\n"); + } + + sensor->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->powerdown)) { + return dev_err_probe(&client->dev, PTR_ERR(sensor->powerdown), + "getting powerdown GPIO\n"); + } + + v4l2_i2c_subdev_init(&sensor->sd, client, &gc0310_ops); + + sensor->regmap = devm_cci_regmap_init_i2c(client, 8); + if (IS_ERR(sensor->regmap)) + return PTR_ERR(sensor->regmap); + + gc0310_power_on(&client->dev); + + pm_runtime_set_active(&client->dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(&client->dev); + + ret = gc0310_detect(sensor); + if (ret) + goto err_power_down; + + sensor->sd.internal_ops = &gc0310_internal_ops; + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = gc0310_init_controls(sensor); + if (ret) + goto err_power_down; + + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); + if (ret) + goto err_power_down; + + sensor->sd.state_lock = sensor->ctrls.handler.lock; + ret = v4l2_subdev_init_finalize(&sensor->sd); + if (ret) + goto err_power_down; + + ret = v4l2_async_register_subdev_sensor(&sensor->sd); + if (ret) + goto err_power_down; + + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + return 0; + +err_power_down: + pm_runtime_put_noidle(&client->dev); + gc0310_remove(client); + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, + gc0310_power_off, gc0310_power_on, NULL); + +static const struct acpi_device_id gc0310_acpi_match[] = { + {"INT0310"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match); + +static struct i2c_driver gc0310_driver = { + .driver = { + .name = "gc0310", + .pm = pm_sleep_ptr(&gc0310_pm_ops), + .acpi_match_table = gc0310_acpi_match, + }, + .probe = gc0310_probe, + .remove = gc0310_remove, +}; +module_i2c_driver(gc0310_driver); + +MODULE_AUTHOR("Lai, Angie <angie.lai@intel.com>"); +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); +MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/gc05a2.c b/drivers/media/i2c/gc05a2.c index 3f7f3d5abeeb..8ba17f80fffe 100644 --- a/drivers/media/i2c/gc05a2.c +++ b/drivers/media/i2c/gc05a2.c @@ -1235,16 +1235,12 @@ static int gc05a2_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(gc05a2->regmap), "failed to init CCI\n"); - gc05a2->xclk = devm_clk_get(dev, NULL); + gc05a2->xclk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, true, + GC05A2_DEFAULT_CLK_FREQ); if (IS_ERR(gc05a2->xclk)) return dev_err_probe(dev, PTR_ERR(gc05a2->xclk), "failed to get xclk\n"); - ret = clk_set_rate(gc05a2->xclk, GC05A2_DEFAULT_CLK_FREQ); - if (ret) - return dev_err_probe(dev, ret, - "failed to set xclk frequency\n"); - ret = gc05a2_get_regulators(dev, gc05a2); if (ret < 0) return dev_err_probe(dev, ret, diff --git a/drivers/media/i2c/gc08a3.c b/drivers/media/i2c/gc08a3.c index 938709a677b6..11fd936db9c3 100644 --- a/drivers/media/i2c/gc08a3.c +++ b/drivers/media/i2c/gc08a3.c @@ -1199,16 +1199,12 @@ static int gc08a3_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(gc08a3->regmap), "failed to init CCI\n"); - gc08a3->xclk = devm_clk_get(dev, NULL); + gc08a3->xclk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, true, + GC08A3_DEFAULT_CLK_FREQ); if (IS_ERR(gc08a3->xclk)) return dev_err_probe(dev, PTR_ERR(gc08a3->xclk), "failed to get xclk\n"); - ret = clk_set_rate(gc08a3->xclk, GC08A3_DEFAULT_CLK_FREQ); - if (ret) - return dev_err_probe(dev, ret, - "failed to set xclk frequency\n"); - ret = gc08a3_get_regulators(dev, gc08a3); if (ret < 0) return dev_err_probe(dev, ret, diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c index ba02161d46e7..b215963a2648 100644 --- a/drivers/media/i2c/gc2145.c +++ b/drivers/media/i2c/gc2145.c @@ -963,7 +963,6 @@ static int gc2145_enable_streams(struct v4l2_subdev *sd, return 0; err_rpm_put: - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; } @@ -985,7 +984,6 @@ static int gc2145_disable_streams(struct v4l2_subdev *sd, if (ret) dev_err(&client->dev, "%s failed to write regs\n", __func__); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; @@ -1193,7 +1191,6 @@ static int gc2145_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; @@ -1334,7 +1331,7 @@ static int gc2145_probe(struct i2c_client *client) return -EINVAL; /* Get system clock (xclk) */ - gc2145->xclk = devm_clk_get(dev, NULL); + gc2145->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(gc2145->xclk)) return dev_err_probe(dev, PTR_ERR(gc2145->xclk), "failed to get xclk\n"); diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index 076c19fcf99c..de573cee4451 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -10,6 +9,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -631,6 +632,8 @@ static const char * const hi556_supply_names[] = { }; struct hi556 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -715,7 +718,6 @@ static int hi556_write_reg(struct hi556 *hi556, u16 reg, u16 len, u32 val) static int hi556_write_reg_list(struct hi556 *hi556, const struct hi556_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); unsigned int i; int ret; @@ -724,7 +726,7 @@ static int hi556_write_reg_list(struct hi556 *hi556, HI556_REG_VALUE_16BIT, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(hi556->dev, "failed to write reg 0x%4.4x. error = %d\n", r_list->regs[i].address, ret); return ret; @@ -785,7 +787,6 @@ static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) { struct hi556 *hi556 = container_of(ctrl->handler, struct hi556, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); s64 exposure_max; int ret = 0; @@ -801,7 +802,7 @@ static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(hi556->dev)) return 0; switch (ctrl->id) { @@ -835,7 +836,7 @@ static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(hi556->dev); return ret; } @@ -921,7 +922,6 @@ static void hi556_assign_pad_format(const struct hi556_mode *mode, static int hi556_identify_module(struct hi556 *hi556) { - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); int ret; u32 val; @@ -934,7 +934,7 @@ static int hi556_identify_module(struct hi556 *hi556) return ret; if (val != HI556_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(hi556->dev, "chip id mismatch: %x!=%x\n", HI556_CHIP_ID, val); return -ENXIO; } @@ -998,7 +998,6 @@ static int hi556_get_selection(struct v4l2_subdev *sd, static int hi556_start_streaming(struct hi556 *hi556) { - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); const struct hi556_reg_list *reg_list; int link_freq_index, ret; @@ -1010,14 +1009,14 @@ static int hi556_start_streaming(struct hi556 *hi556) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = hi556_write_reg_list(hi556, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls\n"); + dev_err(hi556->dev, "failed to set plls\n"); return ret; } reg_list = &hi556->cur_mode->reg_list; ret = hi556_write_reg_list(hi556, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode\n"); + dev_err(hi556->dev, "failed to set mode\n"); return ret; } @@ -1029,7 +1028,7 @@ static int hi556_start_streaming(struct hi556 *hi556) HI556_REG_VALUE_16BIT, HI556_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream\n"); + dev_err(hi556->dev, "failed to set stream\n"); return ret; } @@ -1038,22 +1037,19 @@ static int hi556_start_streaming(struct hi556 *hi556) static void hi556_stop_streaming(struct hi556 *hi556) { - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); - if (hi556_write_reg(hi556, HI556_REG_MODE_SELECT, HI556_REG_VALUE_16BIT, HI556_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream\n"); + dev_err(hi556->dev, "failed to set stream\n"); } static int hi556_set_stream(struct v4l2_subdev *sd, int enable) { struct hi556 *hi556 = to_hi556(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&hi556->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(hi556->dev); if (ret < 0) { mutex_unlock(&hi556->mutex); return ret; @@ -1062,11 +1058,11 @@ static int hi556_set_stream(struct v4l2_subdev *sd, int enable) ret = hi556_start_streaming(hi556); if (ret) { hi556_stop_streaming(hi556); - pm_runtime_put(&client->dev); + pm_runtime_put(hi556->dev); } } else { hi556_stop_streaming(hi556); - pm_runtime_put(&client->dev); + pm_runtime_put(hi556->dev); } mutex_unlock(&hi556->mutex); @@ -1217,7 +1213,6 @@ static int hi556_check_hwcfg(struct device *dev) struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret = 0; unsigned int i, j; @@ -1235,18 +1230,6 @@ static int hi556_check_hwcfg(struct device *dev) if (ret) return dev_err_probe(dev, ret, "parsing endpoint failed\n"); - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - dev_err(dev, "can't get clock frequency\n"); - goto check_hwcfg_error; - } - - if (mclk != HI556_MCLK) { - dev_err(dev, "external clock %d is not supported\n", mclk); - ret = -EINVAL; - goto check_hwcfg_error; - } - if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { dev_err(dev, "number of CSI2 data lanes %d is not supported\n", bus_cfg.bus.mipi_csi2.num_data_lanes); @@ -1289,7 +1272,7 @@ static void hi556_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(hi556->dev); mutex_destroy(&hi556->mutex); } @@ -1336,6 +1319,7 @@ static int hi556_resume(struct device *dev) static int hi556_probe(struct i2c_client *client) { struct hi556 *hi556; + unsigned long freq; bool full_power; int i, ret; @@ -1347,40 +1331,48 @@ static int hi556_probe(struct i2c_client *client) if (!hi556) return -ENOMEM; + hi556->dev = &client->dev; + v4l2_i2c_subdev_init(&hi556->sd, client, &hi556_subdev_ops); - hi556->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + hi556->reset_gpio = devm_gpiod_get_optional(hi556->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(hi556->reset_gpio)) - return dev_err_probe(&client->dev, PTR_ERR(hi556->reset_gpio), + return dev_err_probe(hi556->dev, PTR_ERR(hi556->reset_gpio), "failed to get reset GPIO\n"); - hi556->clk = devm_clk_get_optional(&client->dev, "clk"); + hi556->clk = devm_v4l2_sensor_clk_get(hi556->dev, "clk"); if (IS_ERR(hi556->clk)) - return dev_err_probe(&client->dev, PTR_ERR(hi556->clk), + return dev_err_probe(hi556->dev, PTR_ERR(hi556->clk), "failed to get clock\n"); + freq = clk_get_rate(hi556->clk); + if (freq != HI556_MCLK) + return dev_err_probe(hi556->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + for (i = 0; i < ARRAY_SIZE(hi556_supply_names); i++) hi556->supplies[i].supply = hi556_supply_names[i]; - ret = devm_regulator_bulk_get(&client->dev, + ret = devm_regulator_bulk_get(hi556->dev, ARRAY_SIZE(hi556_supply_names), hi556->supplies); if (ret) - return dev_err_probe(&client->dev, ret, + return dev_err_probe(hi556->dev, ret, "failed to get regulators\n"); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(hi556->dev); if (full_power) { /* Ensure non ACPI managed resources are enabled */ - ret = hi556_resume(&client->dev); + ret = hi556_resume(hi556->dev); if (ret) - return dev_err_probe(&client->dev, ret, + return dev_err_probe(hi556->dev, ret, "failed to power on sensor\n"); ret = hi556_identify_module(hi556); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); + dev_err(hi556->dev, "failed to find sensor: %d\n", ret); goto probe_error_power_off; } } @@ -1389,7 +1381,7 @@ static int hi556_probe(struct i2c_client *client) hi556->cur_mode = &supported_modes[0]; ret = hi556_init_controls(hi556); if (ret) { - dev_err(&client->dev, "failed to init controls: %d\n", ret); + dev_err(hi556->dev, "failed to init controls: %d\n", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -1400,22 +1392,22 @@ static int hi556_probe(struct i2c_client *client) hi556->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&hi556->sd.entity, 1, &hi556->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d\n", ret); + dev_err(hi556->dev, "failed to init entity pads: %d\n", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&hi556->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d\n", + dev_err(hi556->dev, "failed to register V4L2 subdev: %d\n", ret); goto probe_error_media_entity_cleanup; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(hi556->dev); + pm_runtime_enable(hi556->dev); + pm_runtime_idle(hi556->dev); return 0; @@ -1428,7 +1420,7 @@ probe_error_v4l2_ctrl_handler_free: probe_error_power_off: if (full_power) - hi556_suspend(&client->dev); + hi556_suspend(hi556->dev); return ret; } diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index 172772decd3d..a3f77b8434ca 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -2052,12 +2052,11 @@ static int hi846_probe(struct i2c_client *client) return ret; } - hi846->clock = devm_clk_get(&client->dev, NULL); - if (IS_ERR(hi846->clock)) { - dev_err(&client->dev, "failed to get clock: %pe\n", - hi846->clock); - return PTR_ERR(hi846->clock); - } + hi846->clock = devm_v4l2_sensor_clk_get(&client->dev, NULL); + if (IS_ERR(hi846->clock)) + return dev_err_probe(&client->dev, PTR_ERR(hi846->clock), + "failed to get clock: %pe\n", + hi846->clock); mclk_freq = clk_get_rate(hi846->clock); if (mclk_freq != 25000000) diff --git a/drivers/media/i2c/hi847.c b/drivers/media/i2c/hi847.c index 546833f5b5f5..def01aa07b2f 100644 --- a/drivers/media/i2c/hi847.c +++ b/drivers/media/i2c/hi847.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -2166,6 +2168,9 @@ static const struct hi847_mode supported_modes[] = { }; struct hi847 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -2244,7 +2249,6 @@ static int hi847_write_reg(struct hi847 *hi847, u16 reg, u16 len, u32 val) static int hi847_write_reg_list(struct hi847 *hi847, const struct hi847_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); unsigned int i; int ret; @@ -2253,7 +2257,7 @@ static int hi847_write_reg_list(struct hi847 *hi847, HI847_REG_VALUE_16BIT, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(hi847->dev, "failed to write reg 0x%4.4x. error = %d", r_list->regs[i].address, ret); return ret; @@ -2408,7 +2412,6 @@ static int hi847_set_ctrl(struct v4l2_ctrl *ctrl) { struct hi847 *hi847 = container_of(ctrl->handler, struct hi847, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); s64 exposure_max; int ret = 0; @@ -2424,7 +2427,7 @@ static int hi847_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(hi847->dev)) return 0; switch (ctrl->id) { @@ -2466,7 +2469,7 @@ static int hi847_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(hi847->dev); return ret; } @@ -2557,7 +2560,6 @@ static void hi847_assign_pad_format(const struct hi847_mode *mode, static int hi847_start_streaming(struct hi847 *hi847) { - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); const struct hi847_reg_list *reg_list; int link_freq_index, ret; @@ -2565,14 +2567,14 @@ static int hi847_start_streaming(struct hi847 *hi847) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = hi847_write_reg_list(hi847, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(hi847->dev, "failed to set plls"); return ret; } reg_list = &hi847->cur_mode->reg_list; ret = hi847_write_reg_list(hi847, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(hi847->dev, "failed to set mode"); return ret; } @@ -2587,7 +2589,7 @@ static int hi847_start_streaming(struct hi847 *hi847) HI847_REG_VALUE_16BIT, HI847_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream"); + dev_err(hi847->dev, "failed to set stream"); return ret; } @@ -2596,28 +2598,25 @@ static int hi847_start_streaming(struct hi847 *hi847) static void hi847_stop_streaming(struct hi847 *hi847) { - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); - if (hi847_write_reg(hi847, HI847_REG_MODE_TG, HI847_REG_VALUE_16BIT, HI847_REG_MODE_TG_DISABLE)) - dev_err(&client->dev, "failed to set stream 0x%x", + dev_err(hi847->dev, "failed to set stream 0x%x", HI847_REG_MODE_TG); if (hi847_write_reg(hi847, HI847_REG_MODE_SELECT, HI847_REG_VALUE_16BIT, HI847_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream 0x%x", + dev_err(hi847->dev, "failed to set stream 0x%x", HI847_REG_MODE_SELECT); } static int hi847_set_stream(struct v4l2_subdev *sd, int enable) { struct hi847 *hi847 = to_hi847(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&hi847->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(hi847->dev); if (ret) { mutex_unlock(&hi847->mutex); return ret; @@ -2627,11 +2626,11 @@ static int hi847_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; hi847_stop_streaming(hi847); - pm_runtime_put(&client->dev); + pm_runtime_put(hi847->dev); } } else { hi847_stop_streaming(hi847); - pm_runtime_put(&client->dev); + pm_runtime_put(hi847->dev); } mutex_unlock(&hi847->mutex); @@ -2768,7 +2767,6 @@ static const struct v4l2_subdev_internal_ops hi847_internal_ops = { static int hi847_identify_module(struct hi847 *hi847) { - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); int ret; u32 val; @@ -2778,7 +2776,7 @@ static int hi847_identify_module(struct hi847 *hi847) return ret; if (val != HI847_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(hi847->dev, "chip id mismatch: %x!=%x", HI847_CHIP_ID, val); return -ENXIO; } @@ -2793,24 +2791,12 @@ static int hi847_check_hwcfg(struct device *dev) struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret; unsigned int i, j; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - dev_err(dev, "can't get clock frequency"); - return ret; - } - - if (mclk != HI847_MCLK) { - dev_err(dev, "external clock %d is not supported", mclk); - return -EINVAL; - } - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -2862,22 +2848,36 @@ static void hi847_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(hi847->dev); mutex_destroy(&hi847->mutex); } static int hi847_probe(struct i2c_client *client) { struct hi847 *hi847; + unsigned long freq; int ret; hi847 = devm_kzalloc(&client->dev, sizeof(*hi847), GFP_KERNEL); if (!hi847) return -ENOMEM; - ret = hi847_check_hwcfg(&client->dev); + hi847->dev = &client->dev; + + hi847->clk = devm_v4l2_sensor_clk_get(hi847->dev, NULL); + if (IS_ERR(hi847->clk)) + return dev_err_probe(hi847->dev, PTR_ERR(hi847->clk), + "failed to get clock\n"); + + freq = clk_get_rate(hi847->clk); + if (freq != HI847_MCLK) + return dev_err_probe(hi847->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + + ret = hi847_check_hwcfg(hi847->dev); if (ret) { - dev_err(&client->dev, "failed to get HW configuration: %d", + dev_err(hi847->dev, "failed to get HW configuration: %d", ret); return ret; } @@ -2885,7 +2885,7 @@ static int hi847_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&hi847->sd, client, &hi847_subdev_ops); ret = hi847_identify_module(hi847); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(hi847->dev, "failed to find sensor: %d", ret); return ret; } @@ -2893,7 +2893,7 @@ static int hi847_probe(struct i2c_client *client) hi847->cur_mode = &supported_modes[0]; ret = hi847_init_controls(hi847); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(hi847->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -2904,20 +2904,20 @@ static int hi847_probe(struct i2c_client *client) hi847->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&hi847->sd.entity, 1, &hi847->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(hi847->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&hi847->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(hi847->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(hi847->dev); + pm_runtime_enable(hi847->dev); + pm_runtime_idle(hi847->dev); return 0; diff --git a/drivers/media/i2c/imx111.c b/drivers/media/i2c/imx111.c new file mode 100644 index 000000000000..8eb919788ef7 --- /dev/null +++ b/drivers/media/i2c/imx111.c @@ -0,0 +1,1610 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/media.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> +#include <linux/videodev2.h> +#include <linux/units.h> + +#include <media/media-entity.h> +#include <media/v4l2-async.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-mediabus.h> + +/* product information registers */ +#define IMX111_PRODUCT_ID CCI_REG16(0x0000) +#define IMX111_CHIP_ID 0x111 +#define IMX111_REVISION CCI_REG8(0x0002) +#define IMX111_MANUFACTURER_ID CCI_REG8(0x0003) +#define IMX111_FRAME_COUNTER CCI_REG8(0x0005) +#define IMX111_PIXEL_ORDER CCI_REG8(0x0006) + +/* general configuration registers */ +#define IMX111_STREAMING_MODE CCI_REG8(0x0100) +#define IMX111_MODE_STANDBY 0 +#define IMX111_MODE_STREAMING 1 +#define IMX111_IMAGE_ORIENTATION CCI_REG8(0x0101) +#define IMX111_IMAGE_HFLIP BIT(0) +#define IMX111_IMAGE_VFLIP BIT(1) +#define IMX111_SOFTWARE_RESET CCI_REG8(0x0103) +#define IMX111_RESET_ON 1 +#define IMX111_GROUP_WRITE CCI_REG8(0x0104) +#define IMX111_GROUP_WRITE_ON 1 +#define IMX111_FRAME_DROP CCI_REG8(0x0105) +#define IMX111_FRAME_DROP_ON 1 +#define IMX111_CHANNEL_ID CCI_REG8(0x0110) +#define IMX111_SIGNALLING_MODE CCI_REG8(0x0111) +#define IMX111_DATA_DEPTH CCI_REG16(0x0112) +#define IMX111_DATA_DEPTH_RAW8 0x08 +#define IMX111_DATA_DEPTH_RAW10 0x0a + +/* integration time registers */ +#define IMX111_INTEGRATION_TIME CCI_REG16(0x0202) +#define IMX111_INTEGRATION_TIME_MIN 0x1 +#define IMX111_INTEGRATION_TIME_MAX 0xffff +#define IMX111_INTEGRATION_TIME_STEP 1 +#define IMX111_INTEGRATION_TIME_OFFSET 5 + +/* analog gain control */ +#define IMX111_REG_ANALOG_GAIN CCI_REG8(0x0205) +#define IMX111_ANA_GAIN_MIN 0 +#define IMX111_ANA_GAIN_MAX 240 +#define IMX111_ANA_GAIN_STEP 1 +#define IMX111_ANA_GAIN_DEFAULT 0 + +/* digital gain control */ +#define IMX111_REG_DIG_GAIN_GREENR CCI_REG16(0x020e) +#define IMX111_REG_DIG_GAIN_RED CCI_REG16(0x0210) +#define IMX111_REG_DIG_GAIN_BLUE CCI_REG16(0x0212) +#define IMX111_REG_DIG_GAIN_GREENB CCI_REG16(0x0214) +#define IMX111_DGTL_GAIN_MIN 0x0100 +#define IMX111_DGTL_GAIN_MAX 0x0fff +#define IMX111_DGTL_GAIN_DEFAULT 0x0100 +#define IMX111_DGTL_GAIN_STEP 1 + +/* clock configuration registers */ +#define IMX111_PIXEL_CLK_DIVIDER_PLL1 CCI_REG8(0x0301) +#define IMX111_SYSTEM_CLK_DIVIDER_PLL1 CCI_REG8(0x0303) +#define IMX111_PRE_PLL_CLK_DIVIDER_PLL1 CCI_REG8(0x0305) +#define IMX111_PLL_MULTIPLIER_PLL1 CCI_REG8(0x0307) +#define IMX111_PLL_SETTLING_TIME CCI_REG8(0x303c) +#define IMX111_PLL_SETTLING_TIME_DEFAULT 200 +#define IMX111_POST_DIVIDER CCI_REG8(0x30a4) +#define IMX111_POST_DIVIDER_DIV1 2 +#define IMX111_POST_DIVIDER_DIV2 0 +#define IMX111_POST_DIVIDER_DIV4 1 + +/* frame timing registers */ +#define IMX111_VERTICAL_TOTAL_LENGTH CCI_REG16(0x0340) +#define IMX111_VTL_MAX 0x09d8 +#define IMX111_VBLANK_MIN 16 +#define IMX111_HORIZONTAL_TOTAL_LENGTH CCI_REG16(0x0342) +#define IMX111_HTL_MAX 0x0dd0 +#define IMX111_HBLANK_MIN 16 + +/* image size registers */ +#define IMX111_HORIZONTAL_START CCI_REG16(0x0344) +#define IMX111_VERTICAL_START CCI_REG16(0x0346) +#define IMX111_HORIZONTAL_END CCI_REG16(0x0348) +#define IMX111_VERTICAL_END CCI_REG16(0x034a) +#define IMX111_IMAGE_WIDTH CCI_REG16(0x034c) +#define IMX111_IMAGE_HEIGHT CCI_REG16(0x034e) +#define IMX111_H_EVEN_INC CCI_REG8(0x0381) +#define IMX111_H_ODD_INC CCI_REG8(0x0383) +#define IMX111_W_EVEN_INC CCI_REG8(0x0385) +#define IMX111_W_ODD_INC CCI_REG8(0x0387) + +/* test pattern registers */ +#define IMX111_TEST_PATTERN CCI_REG8(0x0601) +#define IMX111_TEST_PATTERN_NONE 0 +#define IMX111_TEST_PATTERN_SOLID 1 +#define IMX111_TEST_PATTERN_BARS 2 +#define IMX111_TEST_PATTERN_FADE 3 +#define IMX111_TEST_PATTERN_PN9 4 +#define IMX111_SOLID_COLOR_RED CCI_REG16(0x0602) +#define IMX111_SOLID_COLOR_GR CCI_REG16(0x0604) +#define IMX111_SOLID_COLOR_BLUE CCI_REG16(0x0606) +#define IMX111_SOLID_COLOR_GB CCI_REG16(0x0608) +#define IMX111_TESTP_COLOUR_MIN 0 +#define IMX111_TESTP_COLOUR_MAX 0x03ff +#define IMX111_TESTP_COLOUR_STEP 1 + +#define IMX111_FRAME_RATE_STEP 5 + +#define IMX111_PIXEL_ARRAY_WIDTH 3280U +#define IMX111_PIXEL_ARRAY_HEIGHT 2464U + +enum { + IMX111_MODE_3280x2464, + IMX111_MODE_3280x1848, + IMX111_MODE_3280x1098, + IMX111_MODE_2100x1200, + IMX111_MODE_1952x1098, + IMX111_MODE_1920x1080, + IMX111_MODE_1640x1232, + IMX111_MODE_1440x1080, + IMX111_MODE_1640x924, + IMX111_MODE_1308x736, + IMX111_MODE_1280x720, + IMX111_MODE_820x614, + IMX111_MODE_640x480, +}; + +static const struct regulator_bulk_data imx111_supplies[] = { + { .supply = "iovdd" }, + { .supply = "dvdd" }, + { .supply = "avdd" }, +}; + +struct imx111_mode { + u32 width; + u32 height; + + /* Default vertical and horizontal total length */ + u32 vtl_def; + u32 htl_def; + + struct { + const struct cci_reg_sequence *regs; + u32 num_of_regs; + } reg_list; +}; + +struct imx111_pll { + u64 extclk_rate; + u8 pre_div; + u8 mult; +}; + +struct imx111 { + struct regmap *regmap; + + struct clk *extclk; + struct gpio_desc *reset; + struct regulator_bulk_data *supplies; + + struct v4l2_fwnode_endpoint bus_cfg; + struct v4l2_subdev sd; + struct media_pad pad; + + /* V4L2 Controls */ + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + + /* Current mode */ + const struct imx111_mode *cur_mode; + const struct imx111_pll *pll; + u32 data_depth; + + u64 pixel_clk_raw; + s64 default_link_freq; +}; + +static const struct imx111_pll imx111_pll[] = { + { .extclk_rate = 6000000, .pre_div = 1, .mult = 113, }, + { .extclk_rate = 12000000, .pre_div = 2, .mult = 113, }, + { .extclk_rate = 13500000, .pre_div = 1, .mult = 50, }, + { .extclk_rate = 18000000, .pre_div = 2, .mult = 75, }, + { .extclk_rate = 24000000, .pre_div = 4, .mult = 113, }, + { .extclk_rate = 27000000, .pre_div = 2, .mult = 50, }, + { .extclk_rate = 36000000, .pre_div = 4, .mult = 75, }, + { .extclk_rate = 54000000, .pre_div = 4, .mult = 50, }, +}; + +/* + * This table MUST contain 4 entries per format, to cover the various flip + * combinations in the order + * - no flip + * - h flip + * - v flip + * - h&v flips + */ +static const u32 imx111_mbus_formats[] = { + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, +}; + +static const struct cci_reg_sequence imx111_global_init[] = { + { CCI_REG8(0x3080), 0x50 }, + { CCI_REG8(0x3087), 0x53 }, + { CCI_REG8(0x309d), 0x94 }, + { CCI_REG8(0x30b1), 0x03 }, + { CCI_REG8(0x30c6), 0x00 }, + { CCI_REG8(0x30c7), 0x00 }, + { CCI_REG8(0x3115), 0x0b }, + { CCI_REG8(0x3118), 0x30 }, + { CCI_REG8(0x311d), 0x25 }, + { CCI_REG8(0x3121), 0x0a }, + { CCI_REG8(0x3212), 0xf2 }, + { CCI_REG8(0x3213), 0x0f }, + { CCI_REG8(0x3215), 0x0f }, + { CCI_REG8(0x3217), 0x0b }, + { CCI_REG8(0x3219), 0x0b }, + { CCI_REG8(0x321b), 0x0d }, + { CCI_REG8(0x321d), 0x0d }, + { CCI_REG8(0x32aa), 0x11 }, + { CCI_REG8(0x3032), 0x40 }, +}; + +static const struct cci_reg_sequence mode_820x614[] = { + { IMX111_GROUP_WRITE, 1 }, + { IMX111_HORIZONTAL_START, 0x0008 }, { IMX111_VERTICAL_START, 0x0034 }, + { IMX111_HORIZONTAL_END, 0x0cd7 }, { IMX111_VERTICAL_END, 0x09cb }, + { IMX111_IMAGE_WIDTH, 0x0334 }, { IMX111_IMAGE_HEIGHT, 0x0266 }, + { IMX111_GROUP_WRITE, 0 }, + { IMX111_H_EVEN_INC, 0x05 }, { IMX111_H_ODD_INC, 0x03 }, + { IMX111_W_EVEN_INC, 0x05 }, { IMX111_W_ODD_INC, 0x03 }, + { CCI_REG8(0x3033), 0x00 }, { CCI_REG8(0x303d), 0x10 }, + { CCI_REG8(0x303e), 0x40 }, { CCI_REG8(0x3040), 0x08 }, + { CCI_REG8(0x3041), 0x97 }, { CCI_REG8(0x3048), 0x01 }, + { CCI_REG8(0x304c), 0x6f }, { CCI_REG8(0x304d), 0x03 }, + { CCI_REG8(0x3064), 0x12 }, { CCI_REG8(0x3073), 0x00 }, + { CCI_REG8(0x3074), 0x11 }, { CCI_REG8(0x3075), 0x11 }, + { CCI_REG8(0x3076), 0x11 }, { CCI_REG8(0x3077), 0x11 }, + { CCI_REG8(0x3079), 0x00 }, { CCI_REG8(0x307a), 0x00 }, + { CCI_REG8(0x309b), 0x28 }, { CCI_REG8(0x309c), 0x13 }, + { CCI_REG8(0x309e), 0x00 }, { CCI_REG8(0x30a0), 0x14 }, + { CCI_REG8(0x30a1), 0x09 }, { CCI_REG8(0x30aa), 0x03 }, + { CCI_REG8(0x30b2), 0x03 }, { CCI_REG8(0x30d5), 0x09 }, + { CCI_REG8(0x30d6), 0x00 }, { CCI_REG8(0x30d7), 0x00 }, + { CCI_REG8(0x30d8), 0x00 }, { CCI_REG8(0x30d9), 0x00 }, + { CCI_REG8(0x30de), 0x04 }, { CCI_REG8(0x30df), 0x20 }, + { CCI_REG8(0x3102), 0x08 }, { CCI_REG8(0x3103), 0x22 }, + { CCI_REG8(0x3104), 0x20 }, { CCI_REG8(0x3105), 0x00 }, + { CCI_REG8(0x3106), 0x87 }, { CCI_REG8(0x3107), 0x00 }, + { CCI_REG8(0x3108), 0x03 }, { CCI_REG8(0x3109), 0x02 }, + { CCI_REG8(0x310a), 0x03 }, { CCI_REG8(0x315c), 0x9c }, + { CCI_REG8(0x315d), 0x9b }, { CCI_REG8(0x316e), 0x9d }, + { CCI_REG8(0x316f), 0x9c }, { CCI_REG8(0x3318), 0x7a }, + { CCI_REG8(0x3348), 0xe0 }, +}; + +static const struct cci_reg_sequence mode_1308x736[] = { + { IMX111_GROUP_WRITE, 1 }, + { IMX111_HORIZONTAL_START, 0x0154 }, { IMX111_VERTICAL_START, 0x0220 }, + { IMX111_HORIZONTAL_END, 0x0b8b }, { IMX111_VERTICAL_END, 0x07df }, + { IMX111_IMAGE_WIDTH, 0x051c }, { IMX111_IMAGE_HEIGHT, 0x02e0 }, + { IMX111_GROUP_WRITE, 0 }, + { IMX111_H_EVEN_INC, 0x01 }, { IMX111_H_ODD_INC, 0x01 }, + { IMX111_W_EVEN_INC, 0x01 }, { IMX111_W_ODD_INC, 0x03 }, + { CCI_REG8(0x3033), 0x84 }, { CCI_REG8(0x303d), 0x10 }, + { CCI_REG8(0x303e), 0x40 }, { CCI_REG8(0x3040), 0x08 }, + { CCI_REG8(0x3041), 0x97 }, { CCI_REG8(0x3048), 0x01 }, + { CCI_REG8(0x304c), 0xd7 }, { CCI_REG8(0x304d), 0x01 }, + { CCI_REG8(0x3064), 0x12 }, { CCI_REG8(0x3073), 0x00 }, + { CCI_REG8(0x3074), 0x11 }, { CCI_REG8(0x3075), 0x11 }, + { CCI_REG8(0x3076), 0x11 }, { CCI_REG8(0x3077), 0x11 }, + { CCI_REG8(0x3079), 0x00 }, { CCI_REG8(0x307a), 0x00 }, + { CCI_REG8(0x309b), 0x48 }, { CCI_REG8(0x309c), 0x12 }, + { CCI_REG8(0x309e), 0x04 }, { CCI_REG8(0x30a0), 0x14 }, + { CCI_REG8(0x30a1), 0x0a }, { CCI_REG8(0x30aa), 0x01 }, + { CCI_REG8(0x30b2), 0x05 }, { CCI_REG8(0x30d5), 0x04 }, + { CCI_REG8(0x30d6), 0x85 }, { CCI_REG8(0x30d7), 0x2a }, + { CCI_REG8(0x30d8), 0x64 }, { CCI_REG8(0x30d9), 0x89 }, + { CCI_REG8(0x30de), 0x00 }, { CCI_REG8(0x30df), 0x20 }, + { CCI_REG8(0x3102), 0x08 }, { CCI_REG8(0x3103), 0x22 }, + { CCI_REG8(0x3104), 0x20 }, { CCI_REG8(0x3105), 0x00 }, + { CCI_REG8(0x3106), 0x87 }, { CCI_REG8(0x3107), 0x00 }, + { CCI_REG8(0x3108), 0x03 }, { CCI_REG8(0x3109), 0x02 }, + { CCI_REG8(0x310a), 0x03 }, { CCI_REG8(0x315c), 0x42 }, + { CCI_REG8(0x315d), 0x41 }, { CCI_REG8(0x316e), 0x43 }, + { CCI_REG8(0x316f), 0x42 }, { CCI_REG8(0x3318), 0x62 }, + { CCI_REG8(0x3348), 0xe0 }, +}; + +static const struct cci_reg_sequence mode_1640x924[] = { + { IMX111_GROUP_WRITE, 1 }, + { IMX111_HORIZONTAL_START, 0x0008 }, { IMX111_VERTICAL_START, 0x0164 }, + { IMX111_HORIZONTAL_END, 0x0cd7 }, { IMX111_VERTICAL_END, 0x089b }, + { IMX111_IMAGE_WIDTH, 0x0668 }, { IMX111_IMAGE_HEIGHT, 0x039c }, + { IMX111_GROUP_WRITE, 0 }, + { IMX111_H_EVEN_INC, 0x01 }, { IMX111_H_ODD_INC, 0x03 }, + { IMX111_W_EVEN_INC, 0x01 }, { IMX111_W_ODD_INC, 0x03 }, + { CCI_REG8(0x3033), 0x00 }, { CCI_REG8(0x303d), 0x10 }, + { CCI_REG8(0x303e), 0x40 }, { CCI_REG8(0x3040), 0x08 }, + { CCI_REG8(0x3041), 0x97 }, { CCI_REG8(0x3048), 0x01 }, + { CCI_REG8(0x304c), 0x6f }, { CCI_REG8(0x304d), 0x03 }, + { CCI_REG8(0x3064), 0x12 }, { CCI_REG8(0x3073), 0x00 }, + { CCI_REG8(0x3074), 0x11 }, { CCI_REG8(0x3075), 0x11 }, + { CCI_REG8(0x3076), 0x11 }, { CCI_REG8(0x3077), 0x11 }, + { CCI_REG8(0x3079), 0x00 }, { CCI_REG8(0x307a), 0x00 }, + { CCI_REG8(0x309b), 0x28 }, { CCI_REG8(0x309c), 0x13 }, + { CCI_REG8(0x309e), 0x00 }, { CCI_REG8(0x30a0), 0x14 }, + { CCI_REG8(0x30a1), 0x09 }, { CCI_REG8(0x30aa), 0x03 }, + { CCI_REG8(0x30b2), 0x05 }, { CCI_REG8(0x30d5), 0x09 }, + { CCI_REG8(0x30d6), 0x01 }, { CCI_REG8(0x30d7), 0x01 }, + { CCI_REG8(0x30d8), 0x64 }, { CCI_REG8(0x30d9), 0x89 }, + { CCI_REG8(0x30de), 0x02 }, { CCI_REG8(0x30df), 0x20 }, + { CCI_REG8(0x3102), 0x08 }, { CCI_REG8(0x3103), 0x22 }, + { CCI_REG8(0x3104), 0x20 }, { CCI_REG8(0x3105), 0x00 }, + { CCI_REG8(0x3106), 0x87 }, { CCI_REG8(0x3107), 0x00 }, + { CCI_REG8(0x3108), 0x03 }, { CCI_REG8(0x3109), 0x02 }, + { CCI_REG8(0x310a), 0x03 }, { CCI_REG8(0x315c), 0x9c }, + { CCI_REG8(0x315d), 0x9b }, { CCI_REG8(0x316e), 0x9d }, + { CCI_REG8(0x316f), 0x9c }, { CCI_REG8(0x3318), 0x72 }, + { CCI_REG8(0x3348), 0xe0 }, +}; + +static const struct cci_reg_sequence mode_1640x1232[] = { + { IMX111_GROUP_WRITE, 1 }, + { IMX111_HORIZONTAL_START, 0x0008 }, { IMX111_VERTICAL_START, 0x0030 }, + { IMX111_HORIZONTAL_END, 0x0cd7 }, { IMX111_VERTICAL_END, 0x09cf }, + { IMX111_IMAGE_WIDTH, 0x0668 }, { IMX111_IMAGE_HEIGHT, 0x04d0 }, + { IMX111_GROUP_WRITE, 0 }, + { IMX111_H_EVEN_INC, 0x01 }, { IMX111_H_ODD_INC, 0x03 }, + { IMX111_W_EVEN_INC, 0x01 }, { IMX111_W_ODD_INC, 0x03 }, + { CCI_REG8(0x3033), 0x00 }, { CCI_REG8(0x303d), 0x10 }, + { CCI_REG8(0x303e), 0x40 }, { CCI_REG8(0x3040), 0x08 }, + { CCI_REG8(0x3041), 0x97 }, { CCI_REG8(0x3048), 0x01 }, + { CCI_REG8(0x304c), 0x6f }, { CCI_REG8(0x304d), 0x03 }, + { CCI_REG8(0x3064), 0x12 }, { CCI_REG8(0x3073), 0x00 }, + { CCI_REG8(0x3074), 0x11 }, { CCI_REG8(0x3075), 0x11 }, + { CCI_REG8(0x3076), 0x11 }, { CCI_REG8(0x3077), 0x11 }, + { CCI_REG8(0x3079), 0x00 }, { CCI_REG8(0x307a), 0x00 }, + { CCI_REG8(0x309b), 0x28 }, { CCI_REG8(0x309c), 0x13 }, + { CCI_REG8(0x309e), 0x00 }, { CCI_REG8(0x30a0), 0x14 }, + { CCI_REG8(0x30a1), 0x09 }, { CCI_REG8(0x30aa), 0x03 }, + { CCI_REG8(0x30b2), 0x05 }, { CCI_REG8(0x30d5), 0x09 }, + { CCI_REG8(0x30d6), 0x01 }, { CCI_REG8(0x30d7), 0x01 }, + { CCI_REG8(0x30d8), 0x64 }, { CCI_REG8(0x30d9), 0x89 }, + { CCI_REG8(0x30de), 0x02 }, { CCI_REG8(0x30df), 0x20 }, + { CCI_REG8(0x3102), 0x08 }, { CCI_REG8(0x3103), 0x22 }, + { CCI_REG8(0x3104), 0x20 }, { CCI_REG8(0x3105), 0x00 }, + { CCI_REG8(0x3106), 0x87 }, { CCI_REG8(0x3107), 0x00 }, + { CCI_REG8(0x3108), 0x03 }, { CCI_REG8(0x3109), 0x02 }, + { CCI_REG8(0x310a), 0x03 }, { CCI_REG8(0x315c), 0x9c }, + { CCI_REG8(0x315d), 0x9b }, { CCI_REG8(0x316e), 0x9d }, + { CCI_REG8(0x316f), 0x9c }, { CCI_REG8(0x3318), 0x72 }, + { CCI_REG8(0x3348), 0xe0 }, +}; + +static const struct cci_reg_sequence mode_1952x1098[] = { + { IMX111_GROUP_WRITE, 1 }, + { IMX111_HORIZONTAL_START, 0x0016 }, { IMX111_VERTICAL_START, 0x016e }, + { IMX111_HORIZONTAL_END, 0x0ccb }, { IMX111_VERTICAL_END, 0x0893 }, + { IMX111_IMAGE_WIDTH, 0x07a0 }, { IMX111_IMAGE_HEIGHT, 0x044a }, + { IMX111_GROUP_WRITE, 0 }, + { IMX111_H_EVEN_INC, 0x01 }, { IMX111_H_ODD_INC, 0x01 }, + { IMX111_W_EVEN_INC, 0x01 }, { IMX111_W_ODD_INC, 0x01 }, + { CCI_REG8(0x3033), 0x00 }, { CCI_REG8(0x303d), 0x10 }, + { CCI_REG8(0x303e), 0x00 }, { CCI_REG8(0x3040), 0x08 }, + { CCI_REG8(0x3041), 0x91 }, { CCI_REG8(0x3048), 0x00 }, + { CCI_REG8(0x304c), 0x67 }, { CCI_REG8(0x304d), 0x03 }, + { CCI_REG8(0x3064), 0x10 }, { CCI_REG8(0x3073), 0xa0 }, + { CCI_REG8(0x3074), 0x12 }, { CCI_REG8(0x3075), 0x12 }, + { CCI_REG8(0x3076), 0x12 }, { CCI_REG8(0x3077), 0x11 }, + { CCI_REG8(0x3079), 0x0a }, { CCI_REG8(0x307a), 0x0a }, + { CCI_REG8(0x309b), 0x60 }, { CCI_REG8(0x309e), 0x04 }, + { CCI_REG8(0x30a0), 0x15 }, { CCI_REG8(0x30a1), 0x08 }, + { CCI_REG8(0x30aa), 0x03 }, { CCI_REG8(0x30b2), 0x05 }, + { CCI_REG8(0x30d5), 0x20 }, { CCI_REG8(0x30d6), 0x85 }, + { CCI_REG8(0x30d7), 0x2a }, { CCI_REG8(0x30d8), 0x64 }, + { CCI_REG8(0x30d9), 0x89 }, { CCI_REG8(0x30de), 0x00 }, + { CCI_REG8(0x30df), 0x21 }, { CCI_REG8(0x3102), 0x08 }, + { CCI_REG8(0x3103), 0x1d }, { CCI_REG8(0x3104), 0x1e }, + { CCI_REG8(0x3105), 0x00 }, { CCI_REG8(0x3106), 0x74 }, + { CCI_REG8(0x3107), 0x00 }, { CCI_REG8(0x3108), 0x03 }, + { CCI_REG8(0x3109), 0x02 }, { CCI_REG8(0x310a), 0x03 }, + { CCI_REG8(0x315c), 0x37 }, { CCI_REG8(0x315d), 0x36 }, + { CCI_REG8(0x316e), 0x38 }, { CCI_REG8(0x316f), 0x37 }, + { CCI_REG8(0x3318), 0x63 }, { CCI_REG8(0x3348), 0xA0 }, +}; + +static const struct cci_reg_sequence mode_2100x1200[] = { + { IMX111_GROUP_WRITE, 1 }, + { IMX111_HORIZONTAL_START, 0x0256 }, { IMX111_VERTICAL_START, 0x02a8 }, + { IMX111_HORIZONTAL_END, 0x0a89 }, { IMX111_VERTICAL_END, 0x0757 }, + { IMX111_IMAGE_WIDTH, 0x0834 }, { IMX111_IMAGE_HEIGHT, 0x04b0 }, + { IMX111_GROUP_WRITE, 0 }, + { IMX111_H_EVEN_INC, 0x01 }, { IMX111_H_ODD_INC, 0x01 }, + { IMX111_W_EVEN_INC, 0x01 }, { IMX111_W_ODD_INC, 0x01 }, + { CCI_REG8(0x3033), 0x00 }, { CCI_REG8(0x303d), 0x10 }, + { CCI_REG8(0x303e), 0x40 }, { CCI_REG8(0x3040), 0x08 }, + { CCI_REG8(0x3041), 0x97 }, { CCI_REG8(0x3048), 0x00 }, + { CCI_REG8(0x304c), 0x6f }, { CCI_REG8(0x304d), 0x03 }, + { CCI_REG8(0x3064), 0x12 }, { CCI_REG8(0x3073), 0x00 }, + { CCI_REG8(0x3074), 0x11 }, { CCI_REG8(0x3075), 0x11 }, + { CCI_REG8(0x3076), 0x11 }, { CCI_REG8(0x3077), 0x11 }, + { CCI_REG8(0x3079), 0x00 }, { CCI_REG8(0x307a), 0x00 }, + { CCI_REG8(0x309b), 0x20 }, { CCI_REG8(0x309c), 0x13 }, + { CCI_REG8(0x309e), 0x00 }, { CCI_REG8(0x30a0), 0x14 }, + { CCI_REG8(0x30a1), 0x08 }, { CCI_REG8(0x30aa), 0x03 }, + { CCI_REG8(0x30b2), 0x07 }, { CCI_REG8(0x30d5), 0x00 }, + { CCI_REG8(0x30d6), 0x85 }, { CCI_REG8(0x30d7), 0x2a }, + { CCI_REG8(0x30d8), 0x64 }, { CCI_REG8(0x30d9), 0x89 }, + { CCI_REG8(0x30de), 0x00 }, { CCI_REG8(0x30df), 0x20 }, + { CCI_REG8(0x3102), 0x08 }, { CCI_REG8(0x3103), 0x22 }, + { CCI_REG8(0x3104), 0x20 }, { CCI_REG8(0x3105), 0x00 }, + { CCI_REG8(0x3106), 0x87 }, { CCI_REG8(0x3107), 0x00 }, + { CCI_REG8(0x3108), 0x03 }, { CCI_REG8(0x3109), 0x02 }, + { CCI_REG8(0x310a), 0x03 }, { CCI_REG8(0x315c), 0x9c }, + { CCI_REG8(0x315d), 0x9b }, { CCI_REG8(0x316e), 0x9d }, + { CCI_REG8(0x316f), 0x9c }, { CCI_REG8(0x3318), 0x62 }, + { CCI_REG8(0x3348), 0xe0 }, +}; + +static const struct cci_reg_sequence mode_3280x1098[] = { + { IMX111_GROUP_WRITE, 1 }, + { IMX111_HORIZONTAL_START, 0x0008 }, { IMX111_VERTICAL_START, 0x01f6 }, + { IMX111_HORIZONTAL_END, 0x0cd7 }, { IMX111_VERTICAL_END, 0x080b }, + { IMX111_IMAGE_WIDTH, 0x0cd0 }, { IMX111_IMAGE_HEIGHT, 0x044a }, + { IMX111_GROUP_WRITE, 0 }, + { IMX111_H_EVEN_INC, 0x01 }, { IMX111_H_ODD_INC, 0x01 }, + { IMX111_W_EVEN_INC, 0x01 }, { IMX111_W_ODD_INC, 0x01 }, + { CCI_REG8(0x3033), 0x00 }, { CCI_REG8(0x303d), 0x10 }, + { CCI_REG8(0x303e), 0x40 }, { CCI_REG8(0x3040), 0x08 }, + { CCI_REG8(0x3041), 0x93 }, { CCI_REG8(0x3048), 0x00 }, + { CCI_REG8(0x304c), 0x67 }, { CCI_REG8(0x304d), 0x03 }, + { CCI_REG8(0x3064), 0x12 }, { CCI_REG8(0x3073), 0xe0 }, + { CCI_REG8(0x3074), 0x12 }, { CCI_REG8(0x3075), 0x12 }, + { CCI_REG8(0x3076), 0x12 }, { CCI_REG8(0x3077), 0x12 }, + { CCI_REG8(0x3079), 0x2a }, { CCI_REG8(0x307a), 0x0a }, + { CCI_REG8(0x309b), 0x60 }, { CCI_REG8(0x309e), 0x04 }, + { CCI_REG8(0x30a0), 0x15 }, { CCI_REG8(0x30a1), 0x08 }, + { CCI_REG8(0x30aa), 0x03 }, { CCI_REG8(0x30b2), 0x05 }, + { CCI_REG8(0x30d5), 0x00 }, { CCI_REG8(0x30d6), 0x85 }, + { CCI_REG8(0x30d7), 0x2a }, { CCI_REG8(0x30d8), 0x64 }, + { CCI_REG8(0x30d9), 0x89 }, { CCI_REG8(0x30de), 0x00 }, + { CCI_REG8(0x30df), 0x20 }, { CCI_REG8(0x3102), 0x08 }, + { CCI_REG8(0x3103), 0x1d }, { CCI_REG8(0x3104), 0x1e }, + { CCI_REG8(0x3105), 0x00 }, { CCI_REG8(0x3106), 0x74 }, + { CCI_REG8(0x3107), 0x00 }, { CCI_REG8(0x3108), 0x03 }, + { CCI_REG8(0x3109), 0x02 }, { CCI_REG8(0x310a), 0x03 }, + { CCI_REG8(0x315c), 0x37 }, { CCI_REG8(0x315d), 0x36 }, + { CCI_REG8(0x316e), 0x38 }, { CCI_REG8(0x316f), 0x37 }, + { CCI_REG8(0x3318), 0x63 }, { CCI_REG8(0x3348), 0xe0 }, +}; + +static const struct cci_reg_sequence mode_3280x1848[] = { + { IMX111_GROUP_WRITE, 1 }, + { IMX111_HORIZONTAL_START, 0x0008 }, { IMX111_VERTICAL_START, 0x0164 }, + { IMX111_HORIZONTAL_END, 0x0cd7 }, { IMX111_VERTICAL_END, 0x089b }, + { IMX111_IMAGE_WIDTH, 0x0cd0 }, { IMX111_IMAGE_HEIGHT, 0x0738 }, + { IMX111_GROUP_WRITE, 0 }, + { IMX111_H_EVEN_INC, 0x01 }, { IMX111_H_ODD_INC, 0x01 }, + { IMX111_W_EVEN_INC, 0x01 }, { IMX111_W_ODD_INC, 0x01 }, + { CCI_REG8(0x3033), 0x00 }, { CCI_REG8(0x303d), 0x00 }, + { CCI_REG8(0x303e), 0x41 }, { CCI_REG8(0x3040), 0x08 }, + { CCI_REG8(0x3041), 0x97 }, { CCI_REG8(0x3048), 0x00 }, + { CCI_REG8(0x304c), 0x6f }, { CCI_REG8(0x304d), 0x03 }, + { CCI_REG8(0x3064), 0x12 }, { CCI_REG8(0x3073), 0x00 }, + { CCI_REG8(0x3074), 0x11 }, { CCI_REG8(0x3075), 0x11 }, + { CCI_REG8(0x3076), 0x11 }, { CCI_REG8(0x3077), 0x11 }, + { CCI_REG8(0x3079), 0x00 }, { CCI_REG8(0x307a), 0x00 }, + { CCI_REG8(0x309b), 0x20 }, { CCI_REG8(0x309c), 0x13 }, + { CCI_REG8(0x309e), 0x00 }, { CCI_REG8(0x30a0), 0x14 }, + { CCI_REG8(0x30a1), 0x08 }, { CCI_REG8(0x30aa), 0x03 }, + { CCI_REG8(0x30b2), 0x07 }, { CCI_REG8(0x30d5), 0x00 }, + { CCI_REG8(0x30d6), 0x85 }, { CCI_REG8(0x30d7), 0x2a }, + { CCI_REG8(0x30d8), 0x64 }, { CCI_REG8(0x30d9), 0x89 }, + { CCI_REG8(0x30de), 0x00 }, { CCI_REG8(0x30df), 0x20 }, + { CCI_REG8(0x3102), 0x10 }, { CCI_REG8(0x3103), 0x44 }, + { CCI_REG8(0x3104), 0x40 }, { CCI_REG8(0x3105), 0x00 }, + { CCI_REG8(0x3106), 0x0d }, { CCI_REG8(0x3107), 0x01 }, + { CCI_REG8(0x3108), 0x09 }, { CCI_REG8(0x3109), 0x08 }, + { CCI_REG8(0x310a), 0x0f }, { CCI_REG8(0x315c), 0x5d }, + { CCI_REG8(0x315d), 0x5c }, { CCI_REG8(0x316e), 0x5e }, + { CCI_REG8(0x316f), 0x5d }, { CCI_REG8(0x3318), 0x60 }, + { CCI_REG8(0x3348), 0xe0 }, +}; + +static const struct cci_reg_sequence mode_3280x2464[] = { + { IMX111_GROUP_WRITE, 1 }, + { IMX111_HORIZONTAL_START, 0x0008 }, { IMX111_VERTICAL_START, 0x0030 }, + { IMX111_HORIZONTAL_END, 0x0cd7 }, { IMX111_VERTICAL_END, 0x09cf }, + { IMX111_IMAGE_WIDTH, 0x0cd0 }, { IMX111_IMAGE_HEIGHT, 0x09a0 }, + { IMX111_GROUP_WRITE, 0 }, + { IMX111_H_EVEN_INC, 0x01 }, { IMX111_H_ODD_INC, 0x01 }, + { IMX111_W_EVEN_INC, 0x01 }, { IMX111_W_ODD_INC, 0x01 }, + { CCI_REG8(0x3033), 0x00 }, { CCI_REG8(0x303d), 0x00 }, + { CCI_REG8(0x303e), 0x41 }, { CCI_REG8(0x3040), 0x08 }, + { CCI_REG8(0x3041), 0x97 }, { CCI_REG8(0x3048), 0x00 }, + { CCI_REG8(0x304c), 0x6f }, { CCI_REG8(0x304d), 0x03 }, + { CCI_REG8(0x3064), 0x12 }, { CCI_REG8(0x3073), 0x00 }, + { CCI_REG8(0x3074), 0x11 }, { CCI_REG8(0x3075), 0x11 }, + { CCI_REG8(0x3076), 0x11 }, { CCI_REG8(0x3077), 0x11 }, + { CCI_REG8(0x3079), 0x00 }, { CCI_REG8(0x307a), 0x00 }, + { CCI_REG8(0x309b), 0x20 }, { CCI_REG8(0x309c), 0x13 }, + { CCI_REG8(0x309e), 0x00 }, { CCI_REG8(0x30a0), 0x14 }, + { CCI_REG8(0x30a1), 0x08 }, { CCI_REG8(0x30aa), 0x03 }, + { CCI_REG8(0x30b2), 0x07 }, { CCI_REG8(0x30d5), 0x00 }, + { CCI_REG8(0x30d6), 0x85 }, { CCI_REG8(0x30d7), 0x2a }, + { CCI_REG8(0x30d8), 0x64 }, { CCI_REG8(0x30d9), 0x89 }, + { CCI_REG8(0x30de), 0x00 }, { CCI_REG8(0x30df), 0x20 }, + { CCI_REG8(0x3102), 0x10 }, { CCI_REG8(0x3103), 0x44 }, + { CCI_REG8(0x3104), 0x40 }, { CCI_REG8(0x3105), 0x00 }, + { CCI_REG8(0x3106), 0x0d }, { CCI_REG8(0x3107), 0x01 }, + { CCI_REG8(0x3108), 0x09 }, { CCI_REG8(0x3109), 0x08 }, + { CCI_REG8(0x310a), 0x0f }, { CCI_REG8(0x315c), 0x5d }, + { CCI_REG8(0x315d), 0x5c }, { CCI_REG8(0x316e), 0x5e }, + { CCI_REG8(0x316f), 0x5d }, { CCI_REG8(0x3318), 0x60 }, + { CCI_REG8(0x3348), 0xe0 }, +}; + +static const struct imx111_mode imx111_modes[] = { + [IMX111_MODE_3280x2464] = { + .width = 3280, + .height = 2464, + .vtl_def = 2490, + .htl_def = 3536, + .reg_list = { + .regs = mode_3280x2464, + .num_of_regs = ARRAY_SIZE(mode_3280x2464), + }, + }, + [IMX111_MODE_3280x1848] = { + .width = 3280, + .height = 1848, + .vtl_def = 1874, + .htl_def = 3536, + .reg_list = { + .regs = mode_3280x1848, + .num_of_regs = ARRAY_SIZE(mode_3280x1848), + }, + }, + [IMX111_MODE_3280x1098] = { + .width = 3280, + .height = 1098, + .vtl_def = 1130, + .htl_def = 3500, + .reg_list = { + .regs = mode_3280x1098, + .num_of_regs = ARRAY_SIZE(mode_3280x1098), + }, + }, + [IMX111_MODE_2100x1200] = { + .width = 2100, + .height = 1200, + .vtl_def = 1260, + .htl_def = 3536, + .reg_list = { + .regs = mode_2100x1200, + .num_of_regs = ARRAY_SIZE(mode_2100x1200), + }, + }, + [IMX111_MODE_1952x1098] = { + .width = 1952, + .height = 1098, + .vtl_def = 1884, + .htl_def = 3500, + .reg_list = { + .regs = mode_1952x1098, + .num_of_regs = ARRAY_SIZE(mode_1952x1098), + }, + }, + [IMX111_MODE_1920x1080] = { + .width = 1920, + .height = 1080, + .vtl_def = 1884, + .htl_def = 3500, + .reg_list = { + .regs = mode_1952x1098, + .num_of_regs = ARRAY_SIZE(mode_1952x1098), + }, + }, + [IMX111_MODE_1640x1232] = { + .width = 1640, + .height = 1232, + .vtl_def = 1254, + .htl_def = 3536, + .reg_list = { + .regs = mode_1640x1232, + .num_of_regs = ARRAY_SIZE(mode_1640x1232), + }, + }, + [IMX111_MODE_1440x1080] = { + .width = 1440, + .height = 1080, + .vtl_def = 1254, + .htl_def = 3536, + .reg_list = { + .regs = mode_1640x1232, + .num_of_regs = ARRAY_SIZE(mode_1640x1232), + }, + }, + [IMX111_MODE_1640x924] = { + .width = 1640, + .height = 924, + .vtl_def = 946, + .htl_def = 3536, + .reg_list = { + .regs = mode_1640x924, + .num_of_regs = ARRAY_SIZE(mode_1640x924), + }, + }, + [IMX111_MODE_1308x736] = { + .width = 1308, + .height = 736, + .vtl_def = 2369, + .htl_def = 1896, + .reg_list = { + .regs = mode_1308x736, + .num_of_regs = ARRAY_SIZE(mode_1308x736), + }, + }, + [IMX111_MODE_1280x720] = { + .width = 1280, + .height = 720, + .vtl_def = 2369, + .htl_def = 1896, + .reg_list = { + .regs = mode_1308x736, + .num_of_regs = ARRAY_SIZE(mode_1308x736), + }, + }, + [IMX111_MODE_820x614] = { + .width = 820, + .height = 614, + .vtl_def = 1260, + .htl_def = 3536, + .reg_list = { + .regs = mode_820x614, + .num_of_regs = ARRAY_SIZE(mode_820x614), + }, + }, + [IMX111_MODE_640x480] = { + .width = 640, + .height = 480, + .vtl_def = 1260, + .htl_def = 3536, + .reg_list = { + .regs = mode_820x614, + .num_of_regs = ARRAY_SIZE(mode_820x614), + }, + }, +}; + +static inline struct imx111 *sd_to_imx111(struct v4l2_subdev *sd) +{ + return container_of_const(sd, struct imx111, sd); +} + +static inline struct imx111 *ctrl_to_imx111(struct v4l2_ctrl *ctrl) +{ + return container_of_const(ctrl->handler, struct imx111, hdl); +} + +static u8 to_settle_delay(u64 extclk_rate) +{ + u64 extclk_mhz = div_u64(extclk_rate, MEGA); + + return DIV_ROUND_UP(IMX111_PLL_SETTLING_TIME_DEFAULT * extclk_mhz - 63, + 64); +} + +static u32 imx111_get_format_code(struct imx111 *sensor, u32 code, bool test) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(imx111_mbus_formats); i++) + if (imx111_mbus_formats[i] == code) + break; + + if (i >= ARRAY_SIZE(imx111_mbus_formats)) + i = 0; + + if (test) + return imx111_mbus_formats[i]; + + i = (i & ~3) | (sensor->vflip->val ? 2 : 0) | + (sensor->hflip->val ? 1 : 0); + + return imx111_mbus_formats[i]; +} + +static u32 imx111_get_format_bpp(const struct v4l2_mbus_framefmt *format) +{ + switch (format->code) { + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SBGGR8_1X8: + return 8; + + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: + default: + return 10; + } +} + +static int imx111_update_digital_gain(struct imx111 *sensor, u32 val) +{ + int ret = 0; + + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, + IMX111_GROUP_WRITE_ON, &ret); + + cci_write(sensor->regmap, IMX111_REG_DIG_GAIN_GREENR, val, &ret); + cci_write(sensor->regmap, IMX111_REG_DIG_GAIN_RED, val, &ret); + cci_write(sensor->regmap, IMX111_REG_DIG_GAIN_BLUE, val, &ret); + cci_write(sensor->regmap, IMX111_REG_DIG_GAIN_GREENB, val, &ret); + + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, 0, &ret); + + return ret; +} + +static int imx111_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx111 *sensor = ctrl_to_imx111(ctrl); + struct device *dev = regmap_get_device(sensor->regmap); + int ret = 0; + + if (ctrl->id == V4L2_CID_VBLANK) { + s64 max = sensor->cur_mode->height + ctrl->val - + IMX111_INTEGRATION_TIME_OFFSET; + + ret = __v4l2_ctrl_modify_range(sensor->exposure, + sensor->exposure->minimum, + max, sensor->exposure->step, + max); + if (ret) + return ret; + } + + /* + * Applying V4L2 control value only happens + * when power is up for streaming + */ + if (!pm_runtime_get_if_in_use(dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + cci_write(sensor->regmap, IMX111_REG_ANALOG_GAIN, ctrl->val, + &ret); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = imx111_update_digital_gain(sensor, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, + IMX111_GROUP_WRITE_ON, &ret); + cci_write(sensor->regmap, IMX111_INTEGRATION_TIME, ctrl->val, + &ret); + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, 0, &ret); + break; + case V4L2_CID_HBLANK: + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, + IMX111_GROUP_WRITE_ON, &ret); + cci_write(sensor->regmap, IMX111_HORIZONTAL_TOTAL_LENGTH, + sensor->cur_mode->width + ctrl->val, &ret); + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, 0, &ret); + break; + case V4L2_CID_VBLANK: + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, + IMX111_GROUP_WRITE_ON, &ret); + cci_write(sensor->regmap, IMX111_VERTICAL_TOTAL_LENGTH, + sensor->cur_mode->height + ctrl->val, &ret); + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, 0, &ret); + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + cci_write(sensor->regmap, IMX111_IMAGE_ORIENTATION, + sensor->hflip->val | sensor->vflip->val << 1, &ret); + break; + case V4L2_CID_TEST_PATTERN: + cci_write(sensor->regmap, IMX111_TEST_PATTERN, ctrl->val, + &ret); + break; + case V4L2_CID_TEST_PATTERN_RED: + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, + IMX111_GROUP_WRITE_ON, &ret); + cci_write(sensor->regmap, IMX111_SOLID_COLOR_RED, ctrl->val, + &ret); + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, 0, &ret); + break; + case V4L2_CID_TEST_PATTERN_GREENR: + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, + IMX111_GROUP_WRITE_ON, &ret); + cci_write(sensor->regmap, IMX111_SOLID_COLOR_GR, ctrl->val, + &ret); + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, 0, &ret); + break; + case V4L2_CID_TEST_PATTERN_BLUE: + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, + IMX111_GROUP_WRITE_ON, &ret); + cci_write(sensor->regmap, IMX111_SOLID_COLOR_BLUE, ctrl->val, + &ret); + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, 0, &ret); + break; + case V4L2_CID_TEST_PATTERN_GREENB: + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, + IMX111_GROUP_WRITE_ON, &ret); + cci_write(sensor->regmap, IMX111_SOLID_COLOR_GB, ctrl->val, + &ret); + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, 0, &ret); + break; + default: + ret = -EINVAL; + } + + pm_runtime_put(dev); + + return ret; +} + +static const struct v4l2_ctrl_ops imx111_ctrl_ops = { + .s_ctrl = imx111_set_ctrl, +}; + +static const char * const test_pattern_menu[] = { + "Disabled", + "Solid Color Fill", + "Standard Color Bars", + "Fade To Grey Color Bars", + "Pseudorandom data", +}; + +static int imx111_init_controls(struct imx111 *sensor) +{ + const struct v4l2_ctrl_ops *ops = &imx111_ctrl_ops; + struct device *dev = regmap_get_device(sensor->regmap); + const struct imx111_mode *mode = sensor->cur_mode; + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl_handler *hdl = &sensor->hdl; + s64 pixel_rate_min, pixel_rate_max; + int i, ret; + + ret = v4l2_fwnode_device_parse(dev, &props); + if (ret < 0) + return ret; + + v4l2_ctrl_handler_init(hdl, 15); + + pixel_rate_min = div_u64(sensor->pixel_clk_raw, + 2 * IMX111_DATA_DEPTH_RAW10); + pixel_rate_max = div_u64(sensor->pixel_clk_raw, + 2 * IMX111_DATA_DEPTH_RAW8); + sensor->pixel_rate = v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_PIXEL_RATE, + pixel_rate_min, pixel_rate_max, + 1, + div_u64(sensor->pixel_clk_raw, + 2 * + sensor->data_depth)); + + sensor->link_freq = v4l2_ctrl_new_int_menu(hdl, NULL, + V4L2_CID_LINK_FREQ, 0, 0, + &sensor->default_link_freq); + if (sensor->link_freq) + sensor->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_ANALOGUE_GAIN, + IMX111_ANA_GAIN_MIN, IMX111_ANA_GAIN_MAX, + IMX111_ANA_GAIN_STEP, IMX111_ANA_GAIN_DEFAULT); + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DIGITAL_GAIN, + IMX111_DGTL_GAIN_MIN, IMX111_DGTL_GAIN_MAX, + IMX111_DGTL_GAIN_STEP, IMX111_DGTL_GAIN_DEFAULT); + + sensor->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, + 0); + if (sensor->hflip) + sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + sensor->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, + 0); + if (sensor->vflip) + sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + sensor->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK, + IMX111_VBLANK_MIN, + IMX111_VTL_MAX - mode->height, 1, + mode->vtl_def - mode->height); + sensor->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, + IMX111_HBLANK_MIN, + IMX111_HTL_MAX - mode->width, 1, + mode->htl_def - mode->width); + + /* + * The maximum coarse integration time is the frame length in lines + * minus five. + */ + sensor->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, + IMX111_INTEGRATION_TIME_MIN, + IMX111_PIXEL_ARRAY_HEIGHT - + IMX111_INTEGRATION_TIME_OFFSET, + IMX111_INTEGRATION_TIME_STEP, + IMX111_PIXEL_ARRAY_HEIGHT - + IMX111_INTEGRATION_TIME_OFFSET); + + v4l2_ctrl_new_fwnode_properties(hdl, ops, &props); + + v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(test_pattern_menu) - 1, 0, 0, + test_pattern_menu); + for (i = 0; i < 4; i++) { + /* + * The assumption is that + * TEST_PATTERN_GREENR == TEST_PATTERN_RED + 1 + * TEST_PATTERN_BLUE == TEST_PATTERN_RED + 2 + * TEST_PATTERN_GREENB == TEST_PATTERN_RED + 3 + */ + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_TEST_PATTERN_RED + i, + IMX111_TESTP_COLOUR_MIN, + IMX111_TESTP_COLOUR_MAX, + IMX111_TESTP_COLOUR_STEP, + IMX111_TESTP_COLOUR_MAX); + /* The "Solid color" pattern is white by default */ + } + + if (hdl->error) + return hdl->error; + + sensor->sd.ctrl_handler = hdl; + + return 0; +}; + +static int imx111_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct imx111 *sensor = sd_to_imx111(sd); + struct device *dev = regmap_get_device(sensor->regmap); + const struct imx111_mode *mode = sensor->cur_mode; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + /* Apply default values of current mode */ + ret = cci_multi_reg_write(sensor->regmap, mode->reg_list.regs, + mode->reg_list.num_of_regs, NULL); + if (ret < 0) { + dev_err(dev, "Failed to initialize the sensor\n"); + goto err_rpm_put; + } + + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, + IMX111_GROUP_WRITE_ON, &ret); + cci_write(sensor->regmap, IMX111_DATA_DEPTH, + sensor->data_depth | sensor->data_depth << 8, &ret); + cci_update_bits(sensor->regmap, IMX111_GROUP_WRITE, + IMX111_GROUP_WRITE_ON, 0, &ret); + + if (ret) + goto err_rpm_put; + + ret = __v4l2_ctrl_handler_setup(&sensor->hdl); + if (ret) + goto err_rpm_put; + + ret = cci_write(sensor->regmap, IMX111_STREAMING_MODE, + IMX111_MODE_STREAMING, NULL); + if (ret) + dev_err(dev, "failed to start stream"); + + /* vflip and hflip cannot change during streaming */ + __v4l2_ctrl_grab(sensor->vflip, true); + __v4l2_ctrl_grab(sensor->hflip, true); + + msleep(30); + + return 0; + +err_rpm_put: + pm_runtime_put_autosuspend(dev); + return ret; +} + +static int imx111_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct imx111 *sensor = sd_to_imx111(sd); + struct device *dev = regmap_get_device(sensor->regmap); + int ret; + + ret = cci_write(sensor->regmap, IMX111_STREAMING_MODE, + IMX111_MODE_STANDBY, NULL); + if (ret) + dev_err(dev, "failed to stop stream\n"); + + __v4l2_ctrl_grab(sensor->vflip, false); + __v4l2_ctrl_grab(sensor->hflip, false); + + pm_runtime_put_autosuspend(dev); + + return ret; +} + +static int imx111_initialize(struct imx111 *sensor) +{ + struct device *dev = regmap_get_device(sensor->regmap); + int ret = 0; + + /* Configure the PLL. */ + cci_write(sensor->regmap, IMX111_PRE_PLL_CLK_DIVIDER_PLL1, + sensor->pll->pre_div, &ret); + cci_write(sensor->regmap, IMX111_PLL_MULTIPLIER_PLL1, + sensor->pll->mult, &ret); + cci_write(sensor->regmap, IMX111_POST_DIVIDER, + IMX111_POST_DIVIDER_DIV1, &ret); + cci_write(sensor->regmap, IMX111_PLL_SETTLING_TIME, + to_settle_delay(sensor->pll->extclk_rate), &ret); + + cci_multi_reg_write(sensor->regmap, imx111_global_init, + ARRAY_SIZE(imx111_global_init), &ret); + if (ret < 0) { + dev_err(dev, "Failed to initialize the sensor\n"); + return ret; + } + + return 0; +} + +/* ---------------------------------------------------------------------------- + * IMX111 Pad Subdev Init and Operations + */ +static int imx111_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx111 *sensor = sd_to_imx111(sd); + + if (code->index >= ARRAY_SIZE(imx111_mbus_formats) / 4) + return -EINVAL; + + code->code = imx111_get_format_code(sensor, + imx111_mbus_formats[code->index * + 4], false); + + return 0; +} + +static int imx111_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct imx111 *sensor = sd_to_imx111(sd); + u32 code; + + if (fse->index >= ARRAY_SIZE(imx111_modes)) + return -EINVAL; + + code = imx111_get_format_code(sensor, fse->code, true); + if (fse->code != code) + return -EINVAL; + + fse->min_width = imx111_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = imx111_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int imx111_set_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct imx111 *sensor = sd_to_imx111(sd); + struct v4l2_mbus_framefmt *mbus_fmt = &format->format; + struct v4l2_mbus_framefmt *fmt; + const struct imx111_mode *mode; + + mode = v4l2_find_nearest_size(imx111_modes, ARRAY_SIZE(imx111_modes), + width, height, + mbus_fmt->width, mbus_fmt->height); + + fmt = v4l2_subdev_state_get_format(state, format->pad); + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + int ret; + + sensor->cur_mode = mode; + sensor->data_depth = imx111_get_format_bpp(fmt); + + ret = __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate, + div_u64(sensor->pixel_clk_raw, + 2 * + sensor->data_depth)); + if (ret) + return ret; + + ret = __v4l2_ctrl_modify_range(sensor->vblank, + IMX111_VBLANK_MIN, + IMX111_VTL_MAX - mode->height, + 1, + mode->vtl_def - mode->height); + if (ret) + return ret; + + ret = __v4l2_ctrl_s_ctrl(sensor->vblank, mode->vtl_def - + mode->height); + if (ret) + return ret; + + ret = __v4l2_ctrl_modify_range(sensor->hblank, + IMX111_HBLANK_MIN, + IMX111_HTL_MAX - mode->width, + 1, + mode->htl_def - mode->width); + if (ret) + return ret; + + ret = __v4l2_ctrl_s_ctrl(sensor->hblank, mode->htl_def - + mode->width); + if (ret) + return ret; + } + + fmt->code = imx111_get_format_code(sensor, mbus_fmt->code, false); + fmt->width = mode->width; + fmt->height = mode->height; + fmt->colorspace = V4L2_COLORSPACE_RAW; + + *mbus_fmt = *fmt; + + return 0; +} + +static int imx111_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct imx111 *sensor = sd_to_imx111(sd); + const struct imx111_mode *mode = sensor->cur_mode; + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_state_get_format(sd_state, 0); + + fmt->code = MEDIA_BUS_FMT_SGBRG10_1X10; + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_RAW; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_XFER_FUNC_NONE; + + return 0; +} + +static const struct v4l2_subdev_video_ops imx111_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops imx111_pad_ops = { + .enum_mbus_code = imx111_enum_mbus_code, + .enum_frame_size = imx111_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = imx111_set_format, + .enable_streams = imx111_enable_streams, + .disable_streams = imx111_disable_streams, +}; + +static const struct v4l2_subdev_ops imx111_subdev_ops = { + .video = &imx111_video_ops, + .pad = &imx111_pad_ops, +}; + +static const struct media_entity_operations imx111_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_subdev_internal_ops imx111_internal_ops = { + .init_state = imx111_init_state, +}; + +static int imx111_init_subdev(struct imx111 *sensor, struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct v4l2_subdev *sd = &sensor->sd; + struct media_pad *pad = &sensor->pad; + struct v4l2_ctrl_handler *hdl = &sensor->hdl; + int ret; + + /* Initialize the subdev. */ + v4l2_i2c_subdev_init(sd, client, &imx111_subdev_ops); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->internal_ops = &imx111_internal_ops; + + /* Initialize the media entity. */ + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + sd->entity.ops = &imx111_subdev_entity_ops; + pad->flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&sd->entity, 1, pad); + if (ret < 0) { + dev_err(dev, "failed to init entity pads: %d", ret); + return ret; + } + + /* Initialize the control handler. */ + ret = imx111_init_controls(sensor); + if (ret) + goto error; + + return 0; +error: + v4l2_ctrl_handler_free(hdl); + media_entity_cleanup(&sd->entity); + return ret; +}; + +/* ---------------------------------------------------------------------------- + * Power Management + */ + +static int imx111_power_on(struct imx111 *sensor) +{ + int ret; + + if (sensor->reset) + gpiod_set_value(sensor->reset, 1); + + ret = regulator_bulk_enable(ARRAY_SIZE(imx111_supplies), + sensor->supplies); + if (ret < 0) + return ret; + + usleep_range(500, 600); + + if (sensor->reset) + gpiod_set_value(sensor->reset, 0); + + usleep_range(200, 250); + + ret = clk_prepare_enable(sensor->extclk); + if (ret < 0) + goto error_regulator; + + usleep_range(200, 250); + + return 0; + +error_regulator: + regulator_bulk_disable(ARRAY_SIZE(imx111_supplies), sensor->supplies); + return ret; +} + +static void imx111_power_off(struct imx111 *sensor) +{ + if (sensor->reset) + gpiod_set_value(sensor->reset, 1); + usleep_range(1000, 2000); + + clk_disable_unprepare(sensor->extclk); + regulator_bulk_disable(ARRAY_SIZE(imx111_supplies), sensor->supplies); +} + +static int __maybe_unused imx111_pm_runtime_resume(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx111 *sensor = sd_to_imx111(sd); + int ret; + + ret = imx111_power_on(sensor); + if (ret) + return ret; + + ret = imx111_initialize(sensor); + if (ret) { + imx111_power_off(sensor); + return ret; + } + + return 0; +} + +static int __maybe_unused imx111_pm_runtime_suspend(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx111 *sensor = sd_to_imx111(sd); + + imx111_power_off(sensor); + + return 0; +} + +static const struct dev_pm_ops imx111_pm_ops = { + SET_RUNTIME_PM_OPS(imx111_pm_runtime_suspend, + imx111_pm_runtime_resume, NULL) +}; + +/* ---------------------------------------------------------------------------- + * Probe & Remove + */ + +static int imx111_identify_module(struct imx111 *sensor) +{ + struct device *dev = regmap_get_device(sensor->regmap); + u64 value, revision, manufacturer; + int ret = 0; + + ret = cci_read(sensor->regmap, IMX111_PRODUCT_ID, &value, NULL); + if (ret) + return ret; + + if (value != IMX111_CHIP_ID) { + dev_err(dev, "chip id mismatch: %x!=%04llx", IMX111_CHIP_ID, + value); + return -ENXIO; + } + + cci_read(sensor->regmap, IMX111_REVISION, &revision, &ret); + cci_read(sensor->regmap, IMX111_MANUFACTURER_ID, &manufacturer, &ret); + + dev_dbg(dev, "module IMX%03llx rev. %llu manufacturer %llu\n", + value, revision, manufacturer); + + return ret; +} + +static int imx111_clk_init(struct imx111 *sensor) +{ + struct device *dev = regmap_get_device(sensor->regmap); + u32 ndata_lanes = sensor->bus_cfg.bus.mipi_csi2.num_data_lanes; + u64 extclk_rate, system_clk; + unsigned int i; + + extclk_rate = clk_get_rate(sensor->extclk); + if (!extclk_rate) + return dev_err_probe(dev, -EINVAL, "EXTCLK rate unknown\n"); + + for (i = 0; i < ARRAY_SIZE(imx111_pll); i++) { + if (clk_get_rate(sensor->extclk) == + imx111_pll[i].extclk_rate) { + sensor->pll = &imx111_pll[i]; + break; + } + } + if (!sensor->pll) + return dev_err_probe(dev, -EINVAL, + "Unsupported EXTCLK rate %llu\n", + extclk_rate); + + system_clk = div_u64(extclk_rate, sensor->pll->pre_div) * + sensor->pll->mult; + + /* + * Pixel clock or Logic clock is used for internal image processing is + * generated by dividing into 1/10 or 1/8 frequency according to the + * word length of the CSI2 interface. This clock is designating the + * pixel rate and used as the base of integration time, frame rate etc. + */ + sensor->pixel_clk_raw = system_clk * ndata_lanes; + + /* + * The CSI-2 bus is clocked for 16-bit per pixel, transmitted in DDR + * over n lanes for RAW10 default format. + */ + sensor->default_link_freq = div_u64(sensor->pixel_clk_raw * 8, + 2 * IMX111_DATA_DEPTH_RAW10); + + if (sensor->bus_cfg.nr_of_link_frequencies != 1 || + sensor->bus_cfg.link_frequencies[0] != sensor->default_link_freq) + return dev_err_probe(dev, -EINVAL, + "Invalid link-frequency, expected %llu\n", + sensor->default_link_freq); + + return 0; +} + +static int imx111_parse_dt(struct imx111 *sensor) +{ + struct device *dev = regmap_get_device(sensor->regmap); + struct fwnode_handle *fwnode = dev_fwnode(dev); + struct fwnode_handle *ep; + int ret; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) { + dev_err(dev, "No endpoint found\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &sensor->bus_cfg); + fwnode_handle_put(ep); + if (ret < 0) { + dev_err(dev, "Failed to parse endpoint\n"); + goto error; + } + + sensor->bus_cfg.bus_type = V4L2_MBUS_CSI2_DPHY; + + /* Check the number of MIPI CSI2 data lanes */ + if (sensor->bus_cfg.bus.mipi_csi2.num_data_lanes > 2) { + dev_err(dev, "number of lanes is more than 2\n"); + ret = -EINVAL; + goto error; + } + + return 0; + +error: + v4l2_fwnode_endpoint_free(&sensor->bus_cfg); + return ret; +} + +static int imx111_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct imx111 *sensor; + int ret; + + sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(sensor->regmap)) + return dev_err_probe(dev, PTR_ERR(sensor->regmap), + "Failed to allocate register map\n"); + + sensor->extclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->extclk)) + return dev_err_probe(dev, PTR_ERR(sensor->extclk), + "Failed to get clock\n"); + + sensor->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(sensor->reset)) + return dev_err_probe(dev, PTR_ERR(sensor->reset), + "Failed to get reset GPIO\n"); + + ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(imx111_supplies), + imx111_supplies, + &sensor->supplies); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to get regulators\n"); + + ret = imx111_parse_dt(sensor); + if (ret < 0) + return ret; + + ret = imx111_clk_init(sensor); + if (ret < 0) + goto error_ep_free; + + ret = imx111_power_on(sensor); + if (ret < 0) { + dev_err_probe(dev, ret, "Could not power on the device\n"); + goto error_ep_free; + } + + ret = imx111_identify_module(sensor); + if (ret < 0) { + dev_err_probe(dev, ret, "Could not identify module\n"); + goto error_power_off; + } + + sensor->cur_mode = &imx111_modes[IMX111_MODE_3280x2464]; + sensor->data_depth = IMX111_DATA_DEPTH_RAW10; + + ret = imx111_initialize(sensor); + if (ret < 0) + goto error_power_off; + + ret = imx111_init_subdev(sensor, client); + if (ret < 0) { + dev_err(dev, "failed to init controls: %d", ret); + goto error_v4l2_ctrl_handler_free; + } + + ret = v4l2_subdev_init_finalize(&sensor->sd); + if (ret) + goto error_v4l2_ctrl_handler_free; + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + ret = v4l2_async_register_subdev_sensor(&sensor->sd); + if (ret < 0) { + dev_err(dev, "failed to register V4L2 subdev: %d", ret); + goto error_pm; + } + + pm_runtime_set_autosuspend_delay(dev, 1000); + pm_runtime_use_autosuspend(dev); + pm_runtime_idle(dev); + + return 0; + +error_pm: + v4l2_subdev_cleanup(&sensor->sd); + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + +error_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(&sensor->hdl); + media_entity_cleanup(&sensor->sd.entity); + +error_power_off: + imx111_power_off(sensor); + +error_ep_free: + v4l2_fwnode_endpoint_free(&sensor->bus_cfg); + + return ret; +} + +static void imx111_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx111 *sensor = sd_to_imx111(sd); + + v4l2_async_unregister_subdev(&sensor->sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sensor->sd.entity); + v4l2_ctrl_handler_free(&sensor->hdl); + v4l2_fwnode_endpoint_free(&sensor->bus_cfg); + + /* + * Disable runtime PM. In case runtime PM is disabled in the kernel, + * make sure to turn power off manually. + */ + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) { + imx111_power_off(sensor); + pm_runtime_set_suspended(&client->dev); + } +} + +static const struct of_device_id imx111_of_match[] = { + { .compatible = "sony,imx111" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx111_of_match); + +static struct i2c_driver imx111_i2c_driver = { + .driver = { + .name = "imx111", + .of_match_table = imx111_of_match, + .pm = &imx111_pm_ops, + }, + .probe = imx111_probe, + .remove = imx111_remove, +}; +module_i2c_driver(imx111_i2c_driver); + +MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>"); +MODULE_DESCRIPTION("Sony IMX111 CMOS Image Sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c index 2b5a6ce7b1ae..d5350bb46f14 100644 --- a/drivers/media/i2c/imx208.c +++ b/drivers/media/i2c/imx208.c @@ -2,13 +2,15 @@ // Copyright (C) 2021 Intel Corporation #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <linux/unaligned.h> #define IMX208_REG_MODE_SELECT 0x0100 #define IMX208_MODE_STANDBY 0x00 @@ -268,6 +270,9 @@ static const struct imx208_mode supported_modes[] = { }; struct imx208 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; @@ -372,7 +377,6 @@ static int imx208_write_reg(struct imx208 *imx208, u16 reg, u32 len, u32 val) static int imx208_write_regs(struct imx208 *imx208, const struct imx208_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); unsigned int i; int ret; @@ -380,7 +384,7 @@ static int imx208_write_regs(struct imx208 *imx208, ret = imx208_write_reg(imx208, regs[i].address, 1, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(imx208->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -431,14 +435,13 @@ static int imx208_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx208 *imx208 = container_of(ctrl->handler, struct imx208, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); int ret; /* * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(imx208->dev)) return 0; switch (ctrl->id) { @@ -471,13 +474,13 @@ static int imx208_set_ctrl(struct v4l2_ctrl *ctrl) break; default: ret = -EINVAL; - dev_err(&client->dev, + dev_err(imx208->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(imx208->dev); return ret; } @@ -620,7 +623,6 @@ static int imx208_set_pad_format(struct v4l2_subdev *sd, static int imx208_identify_module(struct imx208 *imx208) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); int ret; u32 val; @@ -630,13 +632,13 @@ static int imx208_identify_module(struct imx208 *imx208) ret = imx208_read_reg(imx208, IMX208_REG_CHIP_ID, 2, &val); if (ret) { - dev_err(&client->dev, "failed to read chip id %x\n", + dev_err(imx208->dev, "failed to read chip id %x\n", IMX208_CHIP_ID); return ret; } if (val != IMX208_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(imx208->dev, "chip id mismatch: %x!=%x\n", IMX208_CHIP_ID, val); return -EIO; } @@ -649,7 +651,6 @@ static int imx208_identify_module(struct imx208 *imx208) /* Start streaming */ static int imx208_start_streaming(struct imx208 *imx208) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); const struct imx208_reg_list *reg_list; int ret, link_freq_index; @@ -662,7 +663,7 @@ static int imx208_start_streaming(struct imx208 *imx208) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(imx208->dev, "%s failed to set plls\n", __func__); return ret; } @@ -670,7 +671,7 @@ static int imx208_start_streaming(struct imx208 *imx208) reg_list = &imx208->cur_mode->reg_list; ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(imx208->dev, "%s failed to set mode\n", __func__); return ret; } @@ -687,14 +688,13 @@ static int imx208_start_streaming(struct imx208 *imx208) /* Stop streaming */ static int imx208_stop_streaming(struct imx208 *imx208) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); int ret; /* set stream off register */ ret = imx208_write_reg(imx208, IMX208_REG_MODE_SELECT, 1, IMX208_MODE_STANDBY); if (ret) - dev_err(&client->dev, "%s failed to set stream\n", __func__); + dev_err(imx208->dev, "%s failed to set stream\n", __func__); /* * Return success even if it was an error, as there is nothing the @@ -706,13 +706,12 @@ static int imx208_stop_streaming(struct imx208 *imx208) static int imx208_set_stream(struct v4l2_subdev *sd, int enable) { struct imx208 *imx208 = to_imx208(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&imx208->imx208_mx); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx208->dev); if (ret) { mutex_unlock(&imx208->imx208_mx); return ret; @@ -727,7 +726,7 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx208_stop_streaming(imx208); - pm_runtime_put(&client->dev); + pm_runtime_put(imx208->dev); } mutex_unlock(&imx208->imx208_mx); @@ -739,7 +738,7 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx208->dev); mutex_unlock(&imx208->imx208_mx); return ret; @@ -778,7 +777,7 @@ static int imx208_read_otp(struct imx208 *imx208) if (imx208->otp_read) goto out_unlock; - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx208->dev); if (ret) goto out_unlock; @@ -805,7 +804,7 @@ static int imx208_read_otp(struct imx208 *imx208) } out_pm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx208->dev); out_unlock: mutex_unlock(&imx208->imx208_mx); @@ -835,7 +834,6 @@ static const BIN_ATTR_RO(otp, IMX208_OTP_SIZE); /* Initialize control handlers */ static int imx208_init_controls(struct imx208 *imx208) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); struct v4l2_ctrl_handler *ctrl_hdlr = &imx208->ctrl_handler; s64 exposure_max; s64 vblank_def; @@ -914,7 +912,7 @@ static int imx208_init_controls(struct imx208 *imx208) if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(imx208->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } @@ -938,31 +936,36 @@ static void imx208_free_controls(struct imx208 *imx208) static int imx208_probe(struct i2c_client *client) { struct imx208 *imx208; + unsigned long freq; int ret; bool full_power; - u32 val = 0; - - device_property_read_u32(&client->dev, "clock-frequency", &val); - if (val != 19200000) { - dev_err(&client->dev, - "Unsupported clock-frequency %u. Expected 19200000.\n", - val); - return -EINVAL; - } imx208 = devm_kzalloc(&client->dev, sizeof(*imx208), GFP_KERNEL); if (!imx208) return -ENOMEM; + imx208->dev = &client->dev; + + imx208->clk = devm_v4l2_sensor_clk_get(imx208->dev, NULL); + if (IS_ERR(imx208->clk)) + return dev_err_probe(imx208->dev, PTR_ERR(imx208->clk), + "failed to get clock\n"); + + freq = clk_get_rate(imx208->clk); + if (freq != 19200000) + return dev_err_probe(imx208->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + /* Initialize subdev */ v4l2_i2c_subdev_init(&imx208->sd, client, &imx208_subdev_ops); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(imx208->dev); if (full_power) { /* Check module identity */ ret = imx208_identify_module(imx208); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(imx208->dev, "failed to find sensor: %d", ret); goto error_probe; } } @@ -972,7 +975,7 @@ static int imx208_probe(struct i2c_client *client) ret = imx208_init_controls(imx208); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(imx208->dev, "failed to init controls: %d", ret); goto error_probe; } @@ -985,7 +988,7 @@ static int imx208_probe(struct i2c_client *client) imx208->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&imx208->sd.entity, 1, &imx208->pad); if (ret) { - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(imx208->dev, "%s failed:%d\n", __func__, ret); goto error_handler_free; } @@ -993,17 +996,17 @@ static int imx208_probe(struct i2c_client *client) if (ret < 0) goto error_media_entity; - ret = device_create_bin_file(&client->dev, &bin_attr_otp); + ret = device_create_bin_file(imx208->dev, &bin_attr_otp); if (ret) { - dev_err(&client->dev, "sysfs otp creation failed\n"); + dev_err(imx208->dev, "sysfs otp creation failed\n"); goto error_async_subdev; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(imx208->dev); + pm_runtime_enable(imx208->dev); + pm_runtime_idle(imx208->dev); return 0; @@ -1027,13 +1030,13 @@ static void imx208_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct imx208 *imx208 = to_imx208(sd); - device_remove_bin_file(&client->dev, &bin_attr_otp); + device_remove_bin_file(imx208->dev, &bin_attr_otp); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); imx208_free_controls(imx208); - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx208->dev); + pm_runtime_set_suspended(imx208->dev); mutex_destroy(&imx208->imx208_mx); } diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index a0cef9e61b41..d4945b192776 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -881,6 +881,109 @@ static const struct v4l2_ctrl_ops imx214_ctrl_ops = { .s_ctrl = imx214_set_ctrl, }; +static int imx214_pll_calculate(struct imx214 *imx214, struct ccs_pll *pll, + unsigned int link_freq) +{ + struct ccs_pll_limits limits = { + .min_ext_clk_freq_hz = 6000000, + .max_ext_clk_freq_hz = 27000000, + + .vt_fr = { + .min_pre_pll_clk_div = 1, + .max_pre_pll_clk_div = 15, + /* Value is educated guess as we don't have a spec */ + .min_pll_ip_clk_freq_hz = 6000000, + /* Value is educated guess as we don't have a spec */ + .max_pll_ip_clk_freq_hz = 12000000, + .min_pll_multiplier = 12, + .max_pll_multiplier = 1200, + .min_pll_op_clk_freq_hz = 338000000, + .max_pll_op_clk_freq_hz = 1200000000, + }, + .vt_bk = { + .min_sys_clk_div = 2, + .max_sys_clk_div = 4, + .min_pix_clk_div = 5, + .max_pix_clk_div = 10, + .min_pix_clk_freq_hz = 30000000, + .max_pix_clk_freq_hz = 120000000, + }, + .op_bk = { + .min_sys_clk_div = 1, + .max_sys_clk_div = 2, + .min_pix_clk_div = 6, + .max_pix_clk_div = 10, + .min_pix_clk_freq_hz = 30000000, + .max_pix_clk_freq_hz = 120000000, + }, + + .min_line_length_pck_bin = IMX214_PPL_DEFAULT, + .min_line_length_pck = IMX214_PPL_DEFAULT, + }; + unsigned int num_lanes = imx214->bus_cfg.bus.mipi_csi2.num_data_lanes; + + /* + * There are no documented constraints on the sys clock frequency, for + * either branch. Recover them based on the PLL output clock frequency + * and sys_clk_div limits on one hand, and the pix clock frequency and + * the pix_clk_div limits on the other hand. + */ + limits.vt_bk.min_sys_clk_freq_hz = + max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.vt_bk.max_sys_clk_div, + limits.vt_bk.min_pix_clk_freq_hz * limits.vt_bk.min_pix_clk_div); + limits.vt_bk.max_sys_clk_freq_hz = + min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.vt_bk.min_sys_clk_div, + limits.vt_bk.max_pix_clk_freq_hz * limits.vt_bk.max_pix_clk_div); + + limits.op_bk.min_sys_clk_freq_hz = + max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.op_bk.max_sys_clk_div, + limits.op_bk.min_pix_clk_freq_hz * limits.op_bk.min_pix_clk_div); + limits.op_bk.max_sys_clk_freq_hz = + min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.op_bk.min_sys_clk_div, + limits.op_bk.max_pix_clk_freq_hz * limits.op_bk.max_pix_clk_div); + + memset(pll, 0, sizeof(*pll)); + + pll->bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; + pll->op_lanes = num_lanes; + pll->vt_lanes = num_lanes; + pll->csi2.lanes = num_lanes; + + pll->binning_horizontal = 1; + pll->binning_vertical = 1; + pll->scale_m = 1; + pll->scale_n = 1; + pll->bits_per_pixel = + IMX214_CSI_DATA_FORMAT_RAW10 & IMX214_BITS_PER_PIXEL_MASK; + pll->flags = CCS_PLL_FLAG_LANE_SPEED_MODEL; + pll->link_freq = link_freq; + pll->ext_clk_freq_hz = clk_get_rate(imx214->xclk); + + return ccs_pll_calculate(imx214->dev, &limits, pll); +} + +static int imx214_pll_update(struct imx214 *imx214) +{ + u64 link_freq; + int ret; + + link_freq = imx214->bus_cfg.link_frequencies[imx214->link_freq->val]; + ret = imx214_pll_calculate(imx214, &imx214->pll, link_freq); + if (ret) { + dev_err(imx214->dev, "PLL calculations failed: %d\n", ret); + return ret; + } + + ret = v4l2_ctrl_s_ctrl_int64(imx214->pixel_rate, + imx214->pll.pixel_rate_pixel_array); + if (ret) { + dev_err(imx214->dev, "failed to set pixel rate\n"); + return ret; + } + + return 0; +} + static int imx214_ctrls_init(struct imx214 *imx214) { static const struct v4l2_area unit_size = { @@ -911,8 +1014,6 @@ static int imx214_ctrls_init(struct imx214 *imx214) V4L2_CID_LINK_FREQ, imx214->bus_cfg.nr_of_link_frequencies - 1, 0, imx214->bus_cfg.link_frequencies); - if (imx214->link_freq) - imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* * WARNING! @@ -935,9 +1036,6 @@ static int imx214_ctrls_init(struct imx214 *imx214) imx214->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops, V4L2_CID_HBLANK, hblank, hblank, 1, hblank); - if (imx214->hblank) - imx214->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - exposure_max = mode->vts_def - IMX214_EXPOSURE_OFFSET; exposure_def = min(exposure_max, IMX214_EXPOSURE_DEFAULT); imx214->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops, @@ -957,13 +1055,9 @@ static int imx214_ctrls_init(struct imx214 *imx214) imx214->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); - if (imx214->hflip) - imx214->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; imx214->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx214_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); - if (imx214->vflip) - imx214->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; v4l2_ctrl_cluster(2, &imx214->hflip); @@ -1003,6 +1097,19 @@ static int imx214_ctrls_init(struct imx214 *imx214) return ret; } + /* Now that the controls have been properly created, set their flags. */ + imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + imx214->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + imx214->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + imx214->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + ret = imx214_pll_update(imx214); + if (ret < 0) { + v4l2_ctrl_handler_free(ctrl_hdlr); + dev_err(imx214->dev, "failed to update PLL\n"); + return ret; + } + imx214->sd.ctrl_handler = ctrl_hdlr; return 0; @@ -1029,8 +1136,8 @@ static int imx214_start_streaming(struct imx214 *imx214) return ret; } - bit_rate_mbps = (imx214->pll.pixel_rate_csi / 1000000) - * imx214->pll.bits_per_pixel; + bit_rate_mbps = imx214->pll.pixel_rate_csi / 1000000 + * imx214->pll.bits_per_pixel; ret = cci_write(imx214->regmap, IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(bit_rate_mbps), NULL); if (ret) { @@ -1115,109 +1222,6 @@ err_rpm_put: return ret; } -static int imx214_pll_calculate(struct imx214 *imx214, struct ccs_pll *pll, - unsigned int link_freq) -{ - struct ccs_pll_limits limits = { - .min_ext_clk_freq_hz = 6000000, - .max_ext_clk_freq_hz = 27000000, - - .vt_fr = { - .min_pre_pll_clk_div = 1, - .max_pre_pll_clk_div = 15, - /* Value is educated guess as we don't have a spec */ - .min_pll_ip_clk_freq_hz = 6000000, - /* Value is educated guess as we don't have a spec */ - .max_pll_ip_clk_freq_hz = 12000000, - .min_pll_multiplier = 12, - .max_pll_multiplier = 1200, - .min_pll_op_clk_freq_hz = 338000000, - .max_pll_op_clk_freq_hz = 1200000000, - }, - .vt_bk = { - .min_sys_clk_div = 2, - .max_sys_clk_div = 4, - .min_pix_clk_div = 5, - .max_pix_clk_div = 10, - .min_pix_clk_freq_hz = 30000000, - .max_pix_clk_freq_hz = 120000000, - }, - .op_bk = { - .min_sys_clk_div = 1, - .max_sys_clk_div = 2, - .min_pix_clk_div = 6, - .max_pix_clk_div = 10, - .min_pix_clk_freq_hz = 30000000, - .max_pix_clk_freq_hz = 120000000, - }, - - .min_line_length_pck_bin = IMX214_PPL_DEFAULT, - .min_line_length_pck = IMX214_PPL_DEFAULT, - }; - unsigned int num_lanes = imx214->bus_cfg.bus.mipi_csi2.num_data_lanes; - - /* - * There are no documented constraints on the sys clock frequency, for - * either branch. Recover them based on the PLL output clock frequency - * and sys_clk_div limits on one hand, and the pix clock frequency and - * the pix_clk_div limits on the other hand. - */ - limits.vt_bk.min_sys_clk_freq_hz = - max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.vt_bk.max_sys_clk_div, - limits.vt_bk.min_pix_clk_freq_hz * limits.vt_bk.min_pix_clk_div); - limits.vt_bk.max_sys_clk_freq_hz = - min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.vt_bk.min_sys_clk_div, - limits.vt_bk.max_pix_clk_freq_hz * limits.vt_bk.max_pix_clk_div); - - limits.op_bk.min_sys_clk_freq_hz = - max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.op_bk.max_sys_clk_div, - limits.op_bk.min_pix_clk_freq_hz * limits.op_bk.min_pix_clk_div); - limits.op_bk.max_sys_clk_freq_hz = - min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.op_bk.min_sys_clk_div, - limits.op_bk.max_pix_clk_freq_hz * limits.op_bk.max_pix_clk_div); - - memset(pll, 0, sizeof(*pll)); - - pll->bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; - pll->op_lanes = num_lanes; - pll->vt_lanes = num_lanes; - pll->csi2.lanes = num_lanes; - - pll->binning_horizontal = 1; - pll->binning_vertical = 1; - pll->scale_m = 1; - pll->scale_n = 1; - pll->bits_per_pixel = - IMX214_CSI_DATA_FORMAT_RAW10 & IMX214_BITS_PER_PIXEL_MASK; - pll->flags = CCS_PLL_FLAG_LANE_SPEED_MODEL; - pll->link_freq = link_freq; - pll->ext_clk_freq_hz = clk_get_rate(imx214->xclk); - - return ccs_pll_calculate(imx214->dev, &limits, pll); -} - -static int imx214_pll_update(struct imx214 *imx214) -{ - u64 link_freq; - int ret; - - link_freq = imx214->bus_cfg.link_frequencies[imx214->link_freq->val]; - ret = imx214_pll_calculate(imx214, &imx214->pll, link_freq); - if (ret) { - dev_err(imx214->dev, "PLL calculations failed: %d\n", ret); - return ret; - } - - ret = v4l2_ctrl_s_ctrl_int64(imx214->pixel_rate, - imx214->pll.pixel_rate_pixel_array); - if (ret) { - dev_err(imx214->dev, "failed to set pixel rate\n"); - return ret; - } - - return 0; -} - static int imx214_get_frame_interval(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval *fival) @@ -1324,10 +1328,11 @@ static int imx214_identify_module(struct imx214 *imx214) return 0; } -static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214) +static int imx214_parse_fwnode(struct imx214 *imx214) { + struct fwnode_handle *endpoint __free(fwnode_handle) = NULL; struct v4l2_fwnode_endpoint *bus_cfg = &imx214->bus_cfg; - struct fwnode_handle *endpoint; + struct device *dev = imx214->dev; unsigned int i; int ret; @@ -1337,11 +1342,8 @@ static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214) bus_cfg->bus_type = V4L2_MBUS_CSI2_DPHY; ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, bus_cfg); - fwnode_handle_put(endpoint); - if (ret) { - dev_err_probe(dev, ret, "parsing endpoint node failed\n"); - goto error; - } + if (ret) + return dev_err_probe(dev, ret, "parsing endpoint node failed\n"); /* Check the number of MIPI CSI2 data lanes */ if (bus_cfg->bus.mipi_csi2.num_data_lanes != 4) { @@ -1357,18 +1359,16 @@ static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214) u64 freq = bus_cfg->link_frequencies[i]; struct ccs_pll pll; - if (!imx214_pll_calculate(imx214, &pll, freq)) - break; if (freq == IMX214_DEFAULT_LINK_FREQ_LEGACY) { dev_warn(dev, "link-frequencies %d not supported, please review your DT. Continuing anyway\n", IMX214_DEFAULT_LINK_FREQ); freq = IMX214_DEFAULT_LINK_FREQ; - if (imx214_pll_calculate(imx214, &pll, freq)) - continue; bus_cfg->link_frequencies[i] = freq; - break; } + + if (!imx214_pll_calculate(imx214, &pll, freq)) + break; } if (i == bus_cfg->nr_of_link_frequencies) @@ -1396,7 +1396,7 @@ static int imx214_probe(struct i2c_client *client) imx214->dev = dev; - imx214->xclk = devm_clk_get(dev, NULL); + imx214->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(imx214->xclk)) return dev_err_probe(dev, PTR_ERR(imx214->xclk), "failed to get xclk\n"); @@ -1415,7 +1415,7 @@ static int imx214_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(imx214->regmap), "failed to initialize CCI\n"); - ret = imx214_parse_fwnode(dev, imx214); + ret = imx214_parse_fwnode(imx214); if (ret) return ret; @@ -1459,12 +1459,6 @@ static int imx214_probe(struct i2c_client *client) pm_runtime_set_active(imx214->dev); pm_runtime_enable(imx214->dev); - ret = imx214_pll_update(imx214); - if (ret < 0) { - dev_err_probe(dev, ret, "failed to update PLL\n"); - goto error_subdev_cleanup; - } - ret = v4l2_async_register_subdev_sensor(&imx214->sd); if (ret < 0) { dev_err_probe(dev, ret, diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 3b4f68543342..bc55fe2a93b4 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -68,6 +68,7 @@ #define IMX219_EXPOSURE_STEP 1 #define IMX219_EXPOSURE_DEFAULT 0x640 #define IMX219_EXPOSURE_MAX 65535 +#define IMX219_EXPOSURE_OFFSET 4 /* V_TIMING internal */ #define IMX219_REG_FRM_LENGTH_A CCI_REG16(0x0160) @@ -409,24 +410,14 @@ static void imx219_get_binning(struct v4l2_subdev_state *state, u8 *bin_h, u32 hbin = crop->width / format->width; u32 vbin = crop->height / format->height; - *bin_h = IMX219_BINNING_NONE; - *bin_v = IMX219_BINNING_NONE; - - /* - * Use analog binning only if both dimensions are binned, as it crops - * the other dimension. - */ if (hbin == 2 && vbin == 2) { *bin_h = IMX219_BINNING_X2_ANALOG; *bin_v = IMX219_BINNING_X2_ANALOG; - - return; + } else { + *bin_h = IMX219_BINNING_NONE; + *bin_v = IMX219_BINNING_NONE; } - if (hbin == 2) - *bin_h = IMX219_BINNING_X2; - if (vbin == 2) - *bin_v = IMX219_BINNING_X2; } static inline u32 imx219_get_rate_factor(struct v4l2_subdev_state *state) @@ -460,13 +451,17 @@ static int imx219_set_ctrl(struct v4l2_ctrl *ctrl) int exposure_max, exposure_def; /* Update max exposure while meeting expected vblanking */ - exposure_max = format->height + ctrl->val - 4; + exposure_max = format->height + ctrl->val - IMX219_EXPOSURE_OFFSET; exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? - exposure_max : IMX219_EXPOSURE_DEFAULT; - __v4l2_ctrl_modify_range(imx219->exposure, - imx219->exposure->minimum, - exposure_max, imx219->exposure->step, - exposure_def); + exposure_max : IMX219_EXPOSURE_DEFAULT; + ret = __v4l2_ctrl_modify_range(imx219->exposure, + imx219->exposure->minimum, + exposure_max, + imx219->exposure->step, + exposure_def); + if (ret) + return ret; + } /* @@ -585,9 +580,9 @@ static int imx219_init_controls(struct imx219 *imx219) IMX219_LLP_MIN - mode->width, IMX219_LLP_MAX - mode->width, 1, IMX219_LLP_MIN - mode->width); - exposure_max = mode->fll_def - 4; + exposure_max = mode->fll_def - IMX219_EXPOSURE_OFFSET; exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? - exposure_max : IMX219_EXPOSURE_DEFAULT; + exposure_max : IMX219_EXPOSURE_DEFAULT; imx219->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx219_ctrl_ops, V4L2_CID_EXPOSURE, IMX219_EXPOSURE_MIN, exposure_max, @@ -771,7 +766,6 @@ static int imx219_enable_streams(struct v4l2_subdev *sd, return 0; err_rpm_put: - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; } @@ -793,7 +787,6 @@ static int imx219_disable_streams(struct v4l2_subdev *sd, __v4l2_ctrl_grab(imx219->vflip, false); __v4l2_ctrl_grab(imx219->hflip, false); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; @@ -858,8 +851,9 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, const struct imx219_mode *mode; struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - u8 bin_h, bin_v; + u8 bin_h, bin_v, binning; u32 prev_line_len; + int ret; format = v4l2_subdev_state_get_format(state, 0); prev_line_len = format->width + imx219->hblank->val; @@ -879,9 +873,12 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, bin_h = min(IMX219_PIXEL_ARRAY_WIDTH / format->width, 2U); bin_v = min(IMX219_PIXEL_ARRAY_HEIGHT / format->height, 2U); + /* Ensure bin_h and bin_v are same to avoid 1:2 or 2:1 stretching */ + binning = min(bin_h, bin_v); + crop = v4l2_subdev_state_get_crop(state, 0); - crop->width = format->width * bin_h; - crop->height = format->height * bin_v; + crop->width = format->width * binning; + crop->height = format->height * binning; crop->left = (IMX219_NATIVE_WIDTH - crop->width) / 2; crop->top = (IMX219_NATIVE_HEIGHT - crop->height) / 2; @@ -892,19 +889,28 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, int pixel_rate; /* Update limits and set FPS to default */ - __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, - IMX219_FLL_MAX - mode->height, 1, + ret = __v4l2_ctrl_modify_range(imx219->vblank, IMX219_VBLANK_MIN, + IMX219_FLL_MAX - mode->height, 1, + mode->fll_def - mode->height); + if (ret) + return ret; + + ret = __v4l2_ctrl_s_ctrl(imx219->vblank, mode->fll_def - mode->height); - __v4l2_ctrl_s_ctrl(imx219->vblank, - mode->fll_def - mode->height); + if (ret) + return ret; + /* Update max exposure while meeting expected vblanking */ - exposure_max = mode->fll_def - 4; + exposure_max = mode->fll_def - IMX219_EXPOSURE_OFFSET; exposure_def = (exposure_max < IMX219_EXPOSURE_DEFAULT) ? - exposure_max : IMX219_EXPOSURE_DEFAULT; - __v4l2_ctrl_modify_range(imx219->exposure, - imx219->exposure->minimum, - exposure_max, imx219->exposure->step, - exposure_def); + exposure_max : IMX219_EXPOSURE_DEFAULT; + ret = __v4l2_ctrl_modify_range(imx219->exposure, + imx219->exposure->minimum, + exposure_max, + imx219->exposure->step, + exposure_def); + if (ret) + return ret; /* * With analog binning the default minimum line length of 3448 @@ -915,9 +921,12 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, imx219_get_binning(state, &bin_h, &bin_v); llp_min = (bin_h & bin_v) == IMX219_BINNING_X2_ANALOG ? IMX219_BINNED_LLP_MIN : IMX219_LLP_MIN; - __v4l2_ctrl_modify_range(imx219->hblank, llp_min - mode->width, - IMX219_LLP_MAX - mode->width, 1, - llp_min - mode->width); + ret = __v4l2_ctrl_modify_range(imx219->hblank, + llp_min - mode->width, + IMX219_LLP_MAX - mode->width, 1, + llp_min - mode->width); + if (ret) + return ret; /* * Retain PPL setting from previous mode so that the * line time does not change on a mode change. @@ -926,13 +935,17 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, * mode width subtracted. */ hblank = prev_line_len - mode->width; - __v4l2_ctrl_s_ctrl(imx219->hblank, hblank); + ret = __v4l2_ctrl_s_ctrl(imx219->hblank, hblank); + if (ret) + return ret; /* Scale the pixel rate based on the mode specific factor */ pixel_rate = imx219_get_pixel_rate(imx219) * imx219_get_rate_factor(state); - __v4l2_ctrl_modify_range(imx219->pixel_rate, pixel_rate, - pixel_rate, 1, pixel_rate); + ret = __v4l2_ctrl_modify_range(imx219->pixel_rate, pixel_rate, + pixel_rate, 1, pixel_rate); + if (ret) + return ret; } return 0; @@ -981,9 +994,7 @@ static int imx219_init_state(struct v4l2_subdev *sd, }, }; - imx219_set_pad_format(sd, state, &fmt); - - return 0; + return imx219_set_pad_format(sd, state, &fmt); } static const struct v4l2_subdev_video_ops imx219_video_ops = { @@ -1034,6 +1045,10 @@ static int imx219_power_on(struct device *dev) goto reg_off; } + /* + * Note: Misinterpretation of reset assertion - do not re-use this code. + * XCLR pin is using incorrect (for reset signal) logical level. + */ gpiod_set_value_cansleep(imx219->reset_gpio, 1); usleep_range(IMX219_XCLR_MIN_DELAY_US, IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US); @@ -1188,7 +1203,7 @@ static int imx219_probe(struct i2c_client *client) "failed to initialize CCI\n"); /* Get system clock (xclk) */ - imx219->xclk = devm_clk_get(dev, NULL); + imx219->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(imx219->xclk)) return dev_err_probe(dev, PTR_ERR(imx219->xclk), "failed to get xclk\n"); diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index 9e30fce1f223..e50dcfd830f5 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -8,11 +8,12 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> -#include <linux/unaligned.h> #define IMX258_REG_MODE_SELECT CCI_REG8(0x0100) #define IMX258_MODE_STANDBY 0x00 @@ -645,6 +646,8 @@ static const struct imx258_mode supported_modes[] = { }; struct imx258 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct regmap *regmap; @@ -751,7 +754,6 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx258 *imx258 = container_of(ctrl->handler, struct imx258, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); int ret = 0; /* @@ -765,7 +767,7 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (pm_runtime_get_if_in_use(&client->dev) == 0) + if (pm_runtime_get_if_in_use(imx258->dev) == 0) return 0; switch (ctrl->id) { @@ -811,14 +813,14 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) NULL); break; default: - dev_info(&client->dev, + dev_info(imx258->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); ret = -EINVAL; break; } - pm_runtime_put(&client->dev); + pm_runtime_put(imx258->dev); return ret; } @@ -1013,14 +1015,13 @@ static int imx258_get_selection(struct v4l2_subdev *sd, /* Start streaming */ static int imx258_start_streaming(struct imx258 *imx258) { - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); const struct imx258_reg_list *reg_list; const struct imx258_link_freq_config *link_freq_cfg; int ret, link_freq_index; ret = cci_write(imx258->regmap, IMX258_REG_RESET, 0x01, NULL); if (ret) { - dev_err(&client->dev, "%s failed to reset sensor\n", __func__); + dev_err(imx258->dev, "%s failed to reset sensor\n", __func__); return ret; } @@ -1034,21 +1035,21 @@ static int imx258_start_streaming(struct imx258 *imx258) reg_list = &link_freq_cfg->link_cfg[imx258->lane_mode_idx].reg_list; ret = cci_multi_reg_write(imx258->regmap, reg_list->regs, reg_list->num_of_regs, NULL); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(imx258->dev, "%s failed to set plls\n", __func__); return ret; } ret = cci_multi_reg_write(imx258->regmap, mode_common_regs, ARRAY_SIZE(mode_common_regs), NULL); if (ret) { - dev_err(&client->dev, "%s failed to set common regs\n", __func__); + dev_err(imx258->dev, "%s failed to set common regs\n", __func__); return ret; } ret = cci_multi_reg_write(imx258->regmap, imx258->variant_cfg->regs, imx258->variant_cfg->num_regs, NULL); if (ret) { - dev_err(&client->dev, "%s failed to set variant config\n", + dev_err(imx258->dev, "%s failed to set variant config\n", __func__); return ret; } @@ -1057,7 +1058,7 @@ static int imx258_start_streaming(struct imx258 *imx258) !!(imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK), NULL); if (ret) { - dev_err(&client->dev, "%s failed to set clock lane mode\n", __func__); + dev_err(imx258->dev, "%s failed to set clock lane mode\n", __func__); return ret; } @@ -1065,7 +1066,7 @@ static int imx258_start_streaming(struct imx258 *imx258) reg_list = &imx258->cur_mode->reg_list; ret = cci_multi_reg_write(imx258->regmap, reg_list->regs, reg_list->num_of_regs, NULL); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(imx258->dev, "%s failed to set mode\n", __func__); return ret; } @@ -1082,14 +1083,13 @@ static int imx258_start_streaming(struct imx258 *imx258) /* Stop streaming */ static int imx258_stop_streaming(struct imx258 *imx258) { - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); int ret; /* set stream off register */ ret = cci_write(imx258->regmap, IMX258_REG_MODE_SELECT, IMX258_MODE_STANDBY, NULL); if (ret) - dev_err(&client->dev, "%s failed to set stream\n", __func__); + dev_err(imx258->dev, "%s failed to set stream\n", __func__); /* * Return success even if it was an error, as there is nothing the @@ -1135,13 +1135,12 @@ static int imx258_power_off(struct device *dev) static int imx258_set_stream(struct v4l2_subdev *sd, int enable) { struct imx258 *imx258 = to_imx258(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&imx258->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx258->dev); if (ret < 0) goto err_unlock; @@ -1154,7 +1153,7 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx258_stop_streaming(imx258); - pm_runtime_put(&client->dev); + pm_runtime_put(imx258->dev); } mutex_unlock(&imx258->mutex); @@ -1162,7 +1161,7 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx258->dev); err_unlock: mutex_unlock(&imx258->mutex); @@ -1172,20 +1171,19 @@ err_unlock: /* Verify chip ID */ static int imx258_identify_module(struct imx258 *imx258) { - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); int ret; u64 val; ret = cci_read(imx258->regmap, IMX258_REG_CHIP_ID, &val, NULL); if (ret) { - dev_err(&client->dev, "failed to read chip id %x\n", + dev_err(imx258->dev, "failed to read chip id %x\n", IMX258_CHIP_ID); return ret; } if (val != IMX258_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", + dev_err(imx258->dev, "chip id mismatch: %x!=%llx\n", IMX258_CHIP_ID, val); return -EIO; } @@ -1217,7 +1215,6 @@ static const struct v4l2_subdev_internal_ops imx258_internal_ops = { /* Initialize control handlers */ static int imx258_init_controls(struct imx258 *imx258) { - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); const struct imx258_link_freq_config *link_freq_cfgs; struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; @@ -1308,12 +1305,12 @@ static int imx258_init_controls(struct imx258 *imx258) if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(imx258->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(imx258->dev, &props); if (ret) goto error; @@ -1339,15 +1336,14 @@ static void imx258_free_controls(struct imx258 *imx258) mutex_destroy(&imx258->mutex); } -static int imx258_get_regulators(struct imx258 *imx258, - struct i2c_client *client) +static int imx258_get_regulators(struct imx258 *imx258) { unsigned int i; for (i = 0; i < IMX258_NUM_SUPPLIES; i++) imx258->supplies[i].supply = imx258_supply_name[i]; - return devm_regulator_bulk_get(&client->dev, + return devm_regulator_bulk_get(imx258->dev, IMX258_NUM_SUPPLIES, imx258->supplies); } @@ -1365,30 +1361,27 @@ static int imx258_probe(struct i2c_client *client) if (!imx258) return -ENOMEM; + imx258->dev = &client->dev; + imx258->regmap = devm_cci_regmap_init_i2c(client, 16); if (IS_ERR(imx258->regmap)) { ret = PTR_ERR(imx258->regmap); - dev_err(&client->dev, "failed to initialize CCI: %d\n", ret); + dev_err(imx258->dev, "failed to initialize CCI: %d\n", ret); return ret; } - ret = imx258_get_regulators(imx258, client); + ret = imx258_get_regulators(imx258); if (ret) - return dev_err_probe(&client->dev, ret, + return dev_err_probe(imx258->dev, ret, "failed to get regulators\n"); - imx258->clk = devm_clk_get_optional(&client->dev, NULL); + imx258->clk = devm_v4l2_sensor_clk_get_legacy(imx258->dev, NULL, false, + 0); if (IS_ERR(imx258->clk)) - return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), + return dev_err_probe(imx258->dev, PTR_ERR(imx258->clk), "error getting clock\n"); - if (!imx258->clk) { - dev_dbg(&client->dev, - "no clock provided, using clock-frequency property\n"); - device_property_read_u32(&client->dev, "clock-frequency", &val); - } else { - val = clk_get_rate(imx258->clk); - } + val = clk_get_rate(imx258->clk); switch (val) { case 19200000: @@ -1400,32 +1393,32 @@ static int imx258_probe(struct i2c_client *client) imx258->link_freq_menu_items = link_freq_menu_items_24; break; default: - dev_err(&client->dev, "input clock frequency of %u not supported\n", + dev_err(imx258->dev, "input clock frequency of %u not supported\n", val); return -EINVAL; } - endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(imx258->dev), NULL); if (!endpoint) { - dev_err(&client->dev, "Endpoint node not found\n"); + dev_err(imx258->dev, "Endpoint node not found\n"); return -EINVAL; } ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); fwnode_handle_put(endpoint); if (ret) { - dev_err(&client->dev, "Parsing endpoint node failed\n"); + dev_err(imx258->dev, "Parsing endpoint node failed\n"); return ret; } - ret = v4l2_link_freq_to_bitmap(&client->dev, + ret = v4l2_link_freq_to_bitmap(imx258->dev, ep.link_frequencies, ep.nr_of_link_frequencies, imx258->link_freq_menu_items, ARRAY_SIZE(link_freq_menu_items_19_2), &imx258->link_freq_bitmap); if (ret) { - dev_err(&client->dev, "Link frequency not supported\n"); + dev_err(imx258->dev, "Link frequency not supported\n"); goto error_endpoint_free; } @@ -1438,7 +1431,7 @@ static int imx258_probe(struct i2c_client *client) imx258->lane_mode_idx = IMX258_4_LANE_MODE; break; default: - dev_err(&client->dev, "Invalid data lanes: %u\n", + dev_err(imx258->dev, "Invalid data lanes: %u\n", ep.bus.mipi_csi2.num_data_lanes); ret = -EINVAL; goto error_endpoint_free; @@ -1446,7 +1439,7 @@ static int imx258_probe(struct i2c_client *client) imx258->csi2_flags = ep.bus.mipi_csi2.flags; - imx258->variant_cfg = device_get_match_data(&client->dev); + imx258->variant_cfg = device_get_match_data(imx258->dev); if (!imx258->variant_cfg) imx258->variant_cfg = &imx258_cfg; @@ -1454,7 +1447,7 @@ static int imx258_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); /* Will be powered off via pm_runtime_idle */ - ret = imx258_power_on(&client->dev); + ret = imx258_power_on(imx258->dev); if (ret) goto error_endpoint_free; @@ -1486,9 +1479,9 @@ static int imx258_probe(struct i2c_client *client) if (ret < 0) goto error_media_entity; - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(imx258->dev); + pm_runtime_enable(imx258->dev); + pm_runtime_idle(imx258->dev); v4l2_fwnode_endpoint_free(&ep); return 0; @@ -1500,7 +1493,7 @@ error_handler_free: imx258_free_controls(imx258); error_identify: - imx258_power_off(&client->dev); + imx258_power_off(imx258->dev); error_endpoint_free: v4l2_fwnode_endpoint_free(&ep); @@ -1517,10 +1510,10 @@ static void imx258_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); imx258_free_controls(imx258); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - imx258_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx258->dev); + if (!pm_runtime_status_suspended(imx258->dev)) + imx258_power_off(imx258->dev); + pm_runtime_set_suspended(imx258->dev); } static const struct dev_pm_ops imx258_pm_ops = { diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index a2b824986027..8ec78b60bea6 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -826,6 +826,8 @@ static int imx274_start_stream(struct stimx274 *priv) * if rst = 0, keep it in reset; * if rst = 1, bring it out of reset. * + * Note: Misinterpretation of reset assertion - do not re-use this code. + * XCLR pin is using incorrect (for reset signal) logical level. */ static void imx274_reset(struct stimx274 *priv, int rst) { @@ -2032,8 +2034,7 @@ static int imx274_probe(struct i2c_client *client) /* initialize regmap */ imx274->regmap = devm_regmap_init_i2c(client, &imx274_regmap_config); if (IS_ERR(imx274->regmap)) { - dev_err(dev, - "regmap init failed: %ld\n", PTR_ERR(imx274->regmap)); + dev_err(dev, "regmap init failed: %pe\n", imx274->regmap); ret = -ENODEV; goto err_regmap; } diff --git a/drivers/media/i2c/imx283.c b/drivers/media/i2c/imx283.c index da618c8cbadc..8ab63ad8f385 100644 --- a/drivers/media/i2c/imx283.c +++ b/drivers/media/i2c/imx283.c @@ -1143,7 +1143,6 @@ static int imx283_enable_streams(struct v4l2_subdev *sd, return 0; err_rpm_put: - pm_runtime_mark_last_busy(imx283->dev); pm_runtime_put_autosuspend(imx283->dev); return ret; @@ -1163,7 +1162,6 @@ static int imx283_disable_streams(struct v4l2_subdev *sd, if (ret) dev_err(imx283->dev, "Failed to stop stream\n"); - pm_runtime_mark_last_busy(imx283->dev); pm_runtime_put_autosuspend(imx283->dev); return ret; @@ -1462,11 +1460,10 @@ static int imx283_probe(struct i2c_client *client) } /* Get system clock (xclk) */ - imx283->xclk = devm_clk_get(imx283->dev, NULL); - if (IS_ERR(imx283->xclk)) { + imx283->xclk = devm_v4l2_sensor_clk_get(imx283->dev, NULL); + if (IS_ERR(imx283->xclk)) return dev_err_probe(imx283->dev, PTR_ERR(imx283->xclk), "failed to get xclk\n"); - } xclk_freq = clk_get_rate(imx283->xclk); for (i = 0; i < ARRAY_SIZE(imx283_frequencies); i++) { @@ -1558,7 +1555,6 @@ static int imx283_probe(struct i2c_client *client) * Decrease the PM usage count. The device will get suspended after the * autosuspend delay, turning the power off. */ - pm_runtime_mark_last_busy(imx283->dev); pm_runtime_put_autosuspend(imx283->dev); return 0; diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 4f3f386c5353..21cbc81cb2ed 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -869,7 +869,6 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(imx290->dev); pm_runtime_put_autosuspend(imx290->dev); return ret; @@ -1099,7 +1098,6 @@ static int imx290_set_stream(struct v4l2_subdev *sd, int enable) } } else { imx290_stop_streaming(imx290); - pm_runtime_mark_last_busy(imx290->dev); pm_runtime_put_autosuspend(imx290->dev); } @@ -1294,7 +1292,6 @@ static int imx290_subdev_init(struct imx290 *imx290) * will already be prevented even before the delay. */ v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); - pm_runtime_mark_last_busy(imx290->dev); pm_runtime_put_autosuspend(imx290->dev); imx290->sd.internal_ops = &imx290_internal_ops; @@ -1425,14 +1422,14 @@ static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) static int imx290_init_clk(struct imx290 *imx290) { u32 xclk_freq; - int ret; - ret = device_property_read_u32(imx290->dev, "clock-frequency", - &xclk_freq); - if (ret) { - dev_err(imx290->dev, "Could not get xclk frequency\n"); - return ret; - } + imx290->xclk = devm_v4l2_sensor_clk_get_legacy(imx290->dev, "xclk", + false, 0); + if (IS_ERR(imx290->xclk)) + return dev_err_probe(imx290->dev, PTR_ERR(imx290->xclk), + "Could not get xclk\n"); + + xclk_freq = clk_get_rate(imx290->xclk); /* external clock must be 37.125 MHz or 74.25MHz */ switch (xclk_freq) { @@ -1448,12 +1445,6 @@ static int imx290_init_clk(struct imx290 *imx290) return -EINVAL; } - ret = clk_set_rate(imx290->xclk, xclk_freq); - if (ret) { - dev_err(imx290->dev, "Could not set xclk frequency\n"); - return ret; - } - return 0; } @@ -1599,11 +1590,6 @@ static int imx290_probe(struct i2c_client *client) return ret; /* Acquire resources. */ - imx290->xclk = devm_clk_get(dev, "xclk"); - if (IS_ERR(imx290->xclk)) - return dev_err_probe(dev, PTR_ERR(imx290->xclk), - "Could not get xclk\n"); - ret = imx290_get_regulators(dev, imx290); if (ret < 0) return dev_err_probe(dev, ret, "Cannot get regulators\n"); @@ -1614,7 +1600,7 @@ static int imx290_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(imx290->rst_gpio), "Cannot get reset gpio\n"); - /* Initialize external clock frequency. */ + /* Initialize external clock. */ ret = imx290_init_clk(imx290); if (ret) return ret; diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c index f3bec16b527c..69636db11a2b 100644 --- a/drivers/media/i2c/imx296.c +++ b/drivers/media/i2c/imx296.c @@ -604,7 +604,6 @@ static int imx296_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { ret = imx296_stream_off(sensor); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); goto unlock; @@ -922,7 +921,7 @@ static int imx296_read_temperature(struct imx296 *sensor, int *temp) tmdout &= IMX296_TMDOUT_MASK; - /* T(°C) = 246.312 - 0.304 * TMDOUT */; + /* T(°C) = 246.312 - 0.304 * TMDOUT */ *temp = 246312 - 304 * tmdout; return imx296_write(sensor, IMX296_TMDCTRL, 0, NULL); @@ -1044,7 +1043,7 @@ static int imx296_probe(struct i2c_client *client) return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), "failed to get reset GPIO\n"); - sensor->clk = devm_clk_get(sensor->dev, "inck"); + sensor->clk = devm_v4l2_sensor_clk_get(sensor->dev, "inck"); if (IS_ERR(sensor->clk)) return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), "failed to get clock\n"); diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 701840f4a5cc..953310ef3046 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2018 Intel Corporation -#include <linux/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> @@ -106,11 +108,12 @@ struct imx319_mode { }; struct imx319_hwcfg { - u32 ext_clk; /* sensor external clk */ unsigned long link_freq_bitmap; }; struct imx319 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; @@ -1839,14 +1842,13 @@ static int imx319_write_reg(struct imx319 *imx319, u16 reg, u32 len, u32 val) static int imx319_write_regs(struct imx319 *imx319, const struct imx319_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); int ret; u32 i; for (i = 0; i < len; i++) { ret = imx319_write_reg(imx319, regs[i].address, 1, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(imx319->dev, "write reg 0x%4.4x return err %d", regs[i].address, ret); return ret; @@ -1880,7 +1882,6 @@ static int imx319_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx319 *imx319 = container_of(ctrl->handler, struct imx319, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); s64 max; int ret; @@ -1899,7 +1900,7 @@ static int imx319_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(imx319->dev)) return 0; switch (ctrl->id) { @@ -1933,12 +1934,12 @@ static int imx319_set_ctrl(struct v4l2_ctrl *ctrl) break; default: ret = -EINVAL; - dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled", + dev_info(imx319->dev, "ctrl(id:0x%x,val:0x%x) is not handled", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(imx319->dev); return ret; } @@ -2087,7 +2088,6 @@ imx319_set_pad_format(struct v4l2_subdev *sd, /* Verify chip ID */ static int imx319_identify_module(struct imx319 *imx319) { - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); int ret; u32 val; @@ -2099,7 +2099,7 @@ static int imx319_identify_module(struct imx319 *imx319) return ret; if (val != IMX319_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(imx319->dev, "chip id mismatch: %x!=%x", IMX319_CHIP_ID, val); return -EIO; } @@ -2112,7 +2112,6 @@ static int imx319_identify_module(struct imx319 *imx319) /* Start streaming */ static int imx319_start_streaming(struct imx319 *imx319) { - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); const struct imx319_reg_list *reg_list; int ret; @@ -2124,7 +2123,7 @@ static int imx319_start_streaming(struct imx319 *imx319) reg_list = &imx319_global_setting; ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "failed to set global settings"); + dev_err(imx319->dev, "failed to set global settings"); return ret; } @@ -2132,7 +2131,7 @@ static int imx319_start_streaming(struct imx319 *imx319) reg_list = &imx319->cur_mode->reg_list; ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(imx319->dev, "failed to set mode"); return ret; } @@ -2160,13 +2159,12 @@ static int imx319_stop_streaming(struct imx319 *imx319) static int imx319_set_stream(struct v4l2_subdev *sd, int enable) { struct imx319 *imx319 = to_imx319(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&imx319->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx319->dev); if (ret < 0) goto err_unlock; @@ -2179,7 +2177,7 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx319_stop_streaming(imx319); - pm_runtime_put(&client->dev); + pm_runtime_put(imx319->dev); } /* vflip and hflip cannot change during streaming */ @@ -2191,7 +2189,7 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx319->dev); err_unlock: mutex_unlock(&imx319->mutex); @@ -2231,7 +2229,6 @@ static const struct v4l2_subdev_internal_ops imx319_internal_ops = { /* Initialize control handlers */ static int imx319_init_controls(struct imx319 *imx319) { - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; s64 vblank_def; @@ -2311,7 +2308,7 @@ static int imx319_init_controls(struct imx319 *imx319) 0, 0, imx319_test_pattern_menu); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "control init failed: %d", ret); + dev_err(imx319->dev, "control init failed: %d", ret); goto error; } @@ -2350,20 +2347,6 @@ static struct imx319_hwcfg *imx319_get_hwcfg(struct device *dev) if (!cfg) goto out_err; - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &cfg->ext_clk); - if (ret) { - dev_err(dev, "can't get clock frequency"); - goto out_err; - } - - dev_dbg(dev, "ext clk: %d", cfg->ext_clk); - if (cfg->ext_clk != IMX319_EXT_CLK) { - dev_err(dev, "external clock %d is not supported", - cfg->ext_clk); - goto out_err; - } - ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, bus_cfg.nr_of_link_frequencies, link_freq_menu_items, @@ -2385,6 +2368,8 @@ out_err: static int imx319_probe(struct i2c_client *client) { struct imx319 *imx319; + unsigned long freq; + struct clk *clk; bool full_power; int ret; @@ -2392,24 +2377,37 @@ static int imx319_probe(struct i2c_client *client) if (!imx319) return -ENOMEM; + imx319->dev = &client->dev; + mutex_init(&imx319->mutex); + clk = devm_v4l2_sensor_clk_get(imx319->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(imx319->dev, PTR_ERR(clk), + "failed to acquire clock\n"); + + freq = clk_get_rate(clk); + if (freq != IMX319_EXT_CLK) + return dev_err_probe(imx319->dev, -EINVAL, + "external clock %lu is not supported", + freq); + /* Initialize subdev */ v4l2_i2c_subdev_init(&imx319->sd, client, &imx319_subdev_ops); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(imx319->dev); if (full_power) { /* Check module identity */ ret = imx319_identify_module(imx319); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(imx319->dev, "failed to find sensor: %d", ret); goto error_probe; } } - imx319->hwcfg = imx319_get_hwcfg(&client->dev); + imx319->hwcfg = imx319_get_hwcfg(imx319->dev); if (!imx319->hwcfg) { - dev_err(&client->dev, "failed to get hwcfg"); + dev_err(imx319->dev, "failed to get hwcfg"); ret = -ENODEV; goto error_probe; } @@ -2419,7 +2417,7 @@ static int imx319_probe(struct i2c_client *client) ret = imx319_init_controls(imx319); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(imx319->dev, "failed to init controls: %d", ret); goto error_probe; } @@ -2434,27 +2432,27 @@ static int imx319_probe(struct i2c_client *client) imx319->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&imx319->sd.entity, 1, &imx319->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(imx319->dev, "failed to init entity pads: %d", ret); goto error_handler_free; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_active(imx319->dev); + pm_runtime_enable(imx319->dev); ret = v4l2_async_register_subdev_sensor(&imx319->sd); if (ret < 0) goto error_media_entity_pm; - pm_runtime_idle(&client->dev); + pm_runtime_idle(imx319->dev); return 0; error_media_entity_pm: - pm_runtime_disable(&client->dev); + pm_runtime_disable(imx319->dev); if (full_power) - pm_runtime_set_suspended(&client->dev); + pm_runtime_set_suspended(imx319->dev); media_entity_cleanup(&imx319->sd.entity); error_handler_free: @@ -2475,9 +2473,9 @@ static void imx319_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx319->dev); + if (!pm_runtime_status_suspended(imx319->dev)) + pm_runtime_set_suspended(imx319->dev); mutex_destroy(&imx319->mutex); } diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index 846b9928d4e8..9654f9268056 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -118,6 +118,9 @@ #define IMX334_REG_TP CCI_REG8(0x329e) #define IMX334_TP_COLOR_HBARS 0xa #define IMX334_TP_COLOR_VBARS 0xb +#define IMX334_TP_BLACK 0x0 +#define IMX334_TP_WHITE 0x1 +#define IMX334_TP_BLACK_GREY 0xc #define IMX334_TPG_EN_DOUT CCI_REG8(0x329c) #define IMX334_TP_ENABLE 0x1 @@ -398,12 +401,18 @@ static const char * const imx334_test_pattern_menu[] = { "Disabled", "Vertical Color Bars", "Horizontal Color Bars", + "Black and Grey Bars", + "Black Color", + "White Color", }; static const int imx334_test_pattern_val[] = { IMX334_TP_DISABLE, IMX334_TP_COLOR_HBARS, IMX334_TP_COLOR_VBARS, + IMX334_TP_BLACK_GREY, + IMX334_TP_BLACK, + IMX334_TP_WHITE, }; static const struct cci_reg_sequence raw10_framefmt_regs[] = { @@ -997,7 +1006,7 @@ static int imx334_parse_hw_config(struct imx334 *imx334) "failed to get reset gpio\n"); /* Get sensor input clock */ - imx334->inclk = devm_clk_get(imx334->dev, NULL); + imx334->inclk = devm_v4l2_sensor_clk_get(imx334->dev, NULL); if (IS_ERR(imx334->inclk)) return dev_err_probe(imx334->dev, PTR_ERR(imx334->inclk), "could not get inclk\n"); @@ -1070,6 +1079,10 @@ static int imx334_power_on(struct device *dev) struct imx334 *imx334 = to_imx334(sd); int ret; + /* + * Note: Misinterpretation of reset assertion - do not re-use this code. + * XCLR pin is using incorrect (for reset signal) logical level. + */ gpiod_set_value_cansleep(imx334->reset_gpio, 1); ret = clk_prepare_enable(imx334->inclk); diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index 9b4db4cd4929..5790aa4fabeb 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -35,6 +35,7 @@ /* Lines per frame */ #define IMX335_REG_VMAX CCI_REG24_LE(0x3030) +#define IMX335_REG_HMAX CCI_REG16_LE(0x3034) #define IMX335_REG_OPB_SIZE_V CCI_REG8(0x304c) #define IMX335_REG_ADBIT CCI_REG8(0x3050) @@ -42,10 +43,13 @@ #define IMX335_REG_SHUTTER CCI_REG24_LE(0x3058) #define IMX335_EXPOSURE_MIN 1 -#define IMX335_EXPOSURE_OFFSET 9 +#define IMX335_SHUTTER_MIN 9 +#define IMX335_SHUTTER_MIN_BINNED 17 #define IMX335_EXPOSURE_STEP 1 #define IMX335_EXPOSURE_DEFAULT 0x0648 +#define IMX335_REG_AREA2_WIDTH_1 CCI_REG16_LE(0x3072) + #define IMX335_REG_AREA3_ST_ADR_1 CCI_REG16_LE(0x3074) #define IMX335_REG_AREA3_WIDTH_1 CCI_REG16_LE(0x3076) @@ -56,6 +60,9 @@ #define IMX335_AGAIN_STEP 1 #define IMX335_AGAIN_DEFAULT 0 +/* Vertical flip */ +#define IMX335_REG_VREVERSE CCI_REG8(0x304f) + #define IMX335_REG_TPG_TESTCLKEN CCI_REG8(0x3148) #define IMX335_REG_INCLKSEL1 CCI_REG16_LE(0x314c) @@ -121,12 +128,19 @@ #define IMX335_NUM_DATA_LANES 4 /* IMX335 native and active pixel array size. */ -#define IMX335_NATIVE_WIDTH 2616U -#define IMX335_NATIVE_HEIGHT 1964U -#define IMX335_PIXEL_ARRAY_LEFT 12U -#define IMX335_PIXEL_ARRAY_TOP 12U -#define IMX335_PIXEL_ARRAY_WIDTH 2592U -#define IMX335_PIXEL_ARRAY_HEIGHT 1944U +static const struct v4l2_rect imx335_native_area = { + .top = 0, + .left = 0, + .width = 2696, + .height = 2044, +}; + +static const struct v4l2_rect imx335_active_area = { + .top = 50, + .left = 36, + .width = 2624, + .height = 1944, +}; /** * struct imx335_reg_list - imx335 sensor register list @@ -144,8 +158,14 @@ static const char * const imx335_supply_name[] = { "dvdd", /* Digital Core (1.2V) supply */ }; +enum imx335_scan_mode { + IMX335_ALL_PIXEL, + IMX335_2_2_BINNING, +}; + /** * struct imx335_mode - imx335 sensor mode structure + * @scan_mode: Configuration scan mode (All pixel / 2x2Binning) * @width: Frame width * @height: Frame height * @code: Format code @@ -155,8 +175,11 @@ static const char * const imx335_supply_name[] = { * @vblank_max: Maximum vertical blanking in lines * @pclk: Sensor pixel clock * @reg_list: Register list for sensor mode + * @vflip_normal: Register list vflip (normal readout) + * @vflip_inverted: Register list vflip (inverted readout) */ struct imx335_mode { + enum imx335_scan_mode scan_mode; u32 width; u32 height; u32 code; @@ -166,6 +189,8 @@ struct imx335_mode { u32 vblank_max; u64 pclk; struct imx335_reg_list reg_list; + struct imx335_reg_list vflip_normal; + struct imx335_reg_list vflip_inverted; }; /** @@ -183,12 +208,12 @@ struct imx335_mode { * @pclk_ctrl: Pointer to pixel clock control * @hblank_ctrl: Pointer to horizontal blanking control * @vblank_ctrl: Pointer to vertical blanking control + * @vflip: Pointer to vertical flip control * @exp_ctrl: Pointer to exposure control * @again_ctrl: Pointer to analog gain control * @vblank: Vertical blanking in lines * @lane_mode: Mode for number of connected data lanes * @cur_mode: Pointer to current selected sensor mode - * @mutex: Mutex for serializing sensor controls * @link_freq_bitmap: Menu bitmap for link_freq_ctrl * @cur_mbus_code: Currently selected media bus format code */ @@ -207,6 +232,7 @@ struct imx335 { struct v4l2_ctrl *pclk_ctrl; struct v4l2_ctrl *hblank_ctrl; struct v4l2_ctrl *vblank_ctrl; + struct v4l2_ctrl *vflip; struct { struct v4l2_ctrl *exp_ctrl; struct v4l2_ctrl *again_ctrl; @@ -214,7 +240,6 @@ struct imx335 { u32 vblank; u32 lane_mode; const struct imx335_mode *cur_mode; - struct mutex mutex; unsigned long link_freq_bitmap; u32 cur_mbus_code; }; @@ -252,17 +277,37 @@ static const int imx335_tpg_val[] = { }; /* Sensor mode registers */ -static const struct cci_reg_sequence mode_2592x1940_regs[] = { +static const struct cci_reg_sequence mode_2592x1944_regs[] = { { IMX335_REG_MODE_SELECT, IMX335_MODE_STANDBY }, { IMX335_REG_MASTER_MODE, 0x00 }, { IMX335_REG_WINMODE, 0x04 }, + { IMX335_REG_HMAX, 550 }, { IMX335_REG_HTRIMMING_START, 48 }, { IMX335_REG_HNUM, 2592 }, { IMX335_REG_Y_OUT_SIZE, 1944 }, - { IMX335_REG_AREA3_ST_ADR_1, 176 }, + { IMX335_REG_AREA2_WIDTH_1, 40 }, { IMX335_REG_AREA3_WIDTH_1, 3928 }, { IMX335_REG_OPB_SIZE_V, 0 }, { IMX335_REG_XVS_XHS_DRV, 0x00 }, +}; + +static const struct cci_reg_sequence mode_1312x972_regs[] = { + { IMX335_REG_MODE_SELECT, IMX335_MODE_STANDBY }, + { IMX335_REG_MASTER_MODE, 0x00 }, + { IMX335_REG_WINMODE, 0x01 }, + { IMX335_REG_HMAX, 275 }, + { IMX335_REG_HTRIMMING_START, 48 }, + { IMX335_REG_HNUM, 2600 }, + { IMX335_REG_Y_OUT_SIZE, 972 }, + { IMX335_REG_AREA2_WIDTH_1, 48 }, + { IMX335_REG_AREA3_WIDTH_1, 3936 }, + { IMX335_REG_OPB_SIZE_V, 0 }, + { IMX335_REG_XVS_XHS_DRV, 0x00 }, + { CCI_REG8(0x3300), 1 }, /* TCYCLE */ + { CCI_REG8(0x3199), 0x30 }, /* HADD/VADD */ +}; + +static const struct cci_reg_sequence imx335_common_regs[] = { { CCI_REG8(0x3288), 0x21 }, { CCI_REG8(0x328a), 0x02 }, { CCI_REG8(0x3414), 0x05 }, @@ -333,16 +378,92 @@ static const struct cci_reg_sequence mode_2592x1940_regs[] = { { CCI_REG8(0x3a00), 0x00 }, }; -static const struct cci_reg_sequence raw10_framefmt_regs[] = { - { IMX335_REG_ADBIT, 0x00 }, - { IMX335_REG_MDBIT, 0x00 }, - { IMX335_REG_ADBIT1, 0x1ff }, +static const struct cci_reg_sequence mode_2592x1944_vflip_normal[] = { + { IMX335_REG_AREA3_ST_ADR_1, 176 }, + + /* Undocumented V-Flip related registers on Page 55 of datasheet. */ + { CCI_REG8(0x3081), 0x02, }, + { CCI_REG8(0x3083), 0x02, }, + { CCI_REG16_LE(0x30b6), 0x00 }, + { CCI_REG16_LE(0x3116), 0x08 }, }; -static const struct cci_reg_sequence raw12_framefmt_regs[] = { - { IMX335_REG_ADBIT, 0x01 }, - { IMX335_REG_MDBIT, 0x01 }, - { IMX335_REG_ADBIT1, 0x47 }, +static const struct cci_reg_sequence mode_2592x1944_vflip_inverted[] = { + { IMX335_REG_AREA3_ST_ADR_1, 4112 }, + + /* Undocumented V-Flip related registers on Page 55 of datasheet. */ + { CCI_REG8(0x3081), 0xfe, }, + { CCI_REG8(0x3083), 0xfe, }, + { CCI_REG16_LE(0x30b6), 0x1fa }, + { CCI_REG16_LE(0x3116), 0x002 }, +}; + +static const struct cci_reg_sequence mode_1312x972_vflip_normal[] = { + { IMX335_REG_AREA3_ST_ADR_1, 176 }, + + /* Undocumented */ + { CCI_REG8(0x3078), 0x04 }, + { CCI_REG8(0x3079), 0xfd }, + { CCI_REG8(0x307a), 0x04 }, + { CCI_REG8(0x307b), 0xfe }, + { CCI_REG8(0x307c), 0x04 }, + { CCI_REG8(0x307d), 0xfb }, + { CCI_REG8(0x307e), 0x04 }, + { CCI_REG8(0x307f), 0x02 }, + { CCI_REG8(0x3080), 0x04 }, + { CCI_REG8(0x3081), 0xfd }, + { CCI_REG8(0x3082), 0x04 }, + { CCI_REG8(0x3083), 0xfe }, + { CCI_REG8(0x3084), 0x04 }, + { CCI_REG8(0x3085), 0xfb }, + { CCI_REG8(0x3086), 0x04 }, + { CCI_REG8(0x3087), 0x02 }, + { CCI_REG8(0x30a4), 0x77 }, + { CCI_REG8(0x30a8), 0x20 }, + { CCI_REG8(0x30a9), 0x00 }, + { CCI_REG8(0x30ac), 0x08 }, + { CCI_REG8(0x30ad), 0x08 }, + { CCI_REG8(0x30b0), 0x20 }, + { CCI_REG8(0x30b1), 0x00 }, + { CCI_REG8(0x30b4), 0x10 }, + { CCI_REG8(0x30b5), 0x10 }, + { CCI_REG16_LE(0x30b6), 0x00 }, + { CCI_REG16_LE(0x3112), 0x10 }, + { CCI_REG16_LE(0x3116), 0x10 }, +}; + +static const struct cci_reg_sequence mode_1312x972_vflip_inverted[] = { + { IMX335_REG_AREA3_ST_ADR_1, 4112 }, + + /* Undocumented */ + { CCI_REG8(0x3078), 0x04 }, + { CCI_REG8(0x3079), 0xfd }, + { CCI_REG8(0x307a), 0x04 }, + { CCI_REG8(0x307b), 0xfe }, + { CCI_REG8(0x307c), 0x04 }, + { CCI_REG8(0x307d), 0xfb }, + { CCI_REG8(0x307e), 0x04 }, + { CCI_REG8(0x307f), 0x02 }, + { CCI_REG8(0x3080), 0xfc }, + { CCI_REG8(0x3081), 0x05 }, + { CCI_REG8(0x3082), 0xfc }, + { CCI_REG8(0x3083), 0x02 }, + { CCI_REG8(0x3084), 0xfc }, + { CCI_REG8(0x3085), 0x03 }, + { CCI_REG8(0x3086), 0xfc }, + { CCI_REG8(0x3087), 0xfe }, + { CCI_REG8(0x30a4), 0x77 }, + { CCI_REG8(0x30a8), 0x20 }, + { CCI_REG8(0x30a9), 0x00 }, + { CCI_REG8(0x30ac), 0x08 }, + { CCI_REG8(0x30ad), 0x78 }, + { CCI_REG8(0x30b0), 0x20 }, + { CCI_REG8(0x30b1), 0x00 }, + { CCI_REG8(0x30b4), 0x10 }, + { CCI_REG8(0x30b5), 0x70 }, + { CCI_REG16_LE(0x30b6), 0x01f2 }, + { CCI_REG16_LE(0x3112), 0x10 }, + { CCI_REG16_LE(0x3116), 0x02 }, }; static const struct cci_reg_sequence mipi_data_rate_1188Mbps[] = { @@ -407,17 +528,49 @@ static const u32 imx335_mbus_codes[] = { }; /* Supported sensor mode configurations */ -static const struct imx335_mode supported_mode = { - .width = 2592, - .height = 1944, - .hblank = 342, - .vblank = 2556, - .vblank_min = 2556, - .vblank_max = 133060, - .pclk = 396000000, - .reg_list = { - .num_of_regs = ARRAY_SIZE(mode_2592x1940_regs), - .regs = mode_2592x1940_regs, +static const struct imx335_mode supported_modes[] = { + { + .scan_mode = IMX335_ALL_PIXEL, + .width = 2592, + .height = 1944, + .hblank = 342, + .vblank = 2556, + .vblank_min = 2556, + .vblank_max = 133060, + .pclk = 396000000, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2592x1944_regs), + .regs = mode_2592x1944_regs, + }, + .vflip_normal = { + .num_of_regs = ARRAY_SIZE(mode_2592x1944_vflip_normal), + .regs = mode_2592x1944_vflip_normal, + }, + .vflip_inverted = { + .num_of_regs = ARRAY_SIZE(mode_2592x1944_vflip_inverted), + .regs = mode_2592x1944_vflip_inverted, + } + }, { + .scan_mode = IMX335_2_2_BINNING, + .width = 1312, + .height = 972, + .hblank = 155, + .vblank = 3528, + .vblank_min = 3528, + .vblank_max = 133060, + .pclk = 396000000, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1312x972_regs), + .regs = mode_1312x972_regs, + }, + .vflip_normal = { + .num_of_regs = ARRAY_SIZE(mode_1312x972_vflip_normal), + .regs = mode_1312x972_vflip_normal, + }, + .vflip_inverted = { + .num_of_regs = ARRAY_SIZE(mode_1312x972_vflip_inverted), + .regs = mode_1312x972_vflip_inverted, + }, }, }; @@ -449,7 +602,8 @@ static int imx335_update_controls(struct imx335 *imx335, if (ret) return ret; - ret = __v4l2_ctrl_s_ctrl(imx335->hblank_ctrl, mode->hblank); + ret = __v4l2_ctrl_modify_range(imx335->hblank_ctrl, mode->hblank, + mode->hblank, 1, mode->hblank); if (ret) return ret; @@ -492,6 +646,19 @@ static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain) return ret; } +static int imx335_update_vertical_flip(struct imx335 *imx335, u32 vflip) +{ + const struct imx335_reg_list * const vflip_regs = + vflip ? &imx335->cur_mode->vflip_inverted : + &imx335->cur_mode->vflip_normal; + int ret = 0; + + cci_multi_reg_write(imx335->cci, vflip_regs->regs, + vflip_regs->num_of_regs, &ret); + + return cci_write(imx335->cci, IMX335_REG_VREVERSE, vflip, &ret); +} + static int imx335_update_test_pattern(struct imx335 *imx335, u32 pattern_index) { int ret = 0; @@ -553,18 +720,22 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) /* Propagate change of current control to all related controls */ if (ctrl->id == V4L2_CID_VBLANK) { + u32 shutter_min = IMX335_SHUTTER_MIN; + u32 lpfr; + imx335->vblank = imx335->vblank_ctrl->val; + lpfr = imx335->vblank + imx335->cur_mode->height; dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u\n", - imx335->vblank, - imx335->vblank + imx335->cur_mode->height); + imx335->vblank, lpfr); + + if (imx335->cur_mode->scan_mode == IMX335_2_2_BINNING) + shutter_min = IMX335_SHUTTER_MIN_BINNED; ret = __v4l2_ctrl_modify_range(imx335->exp_ctrl, IMX335_EXPOSURE_MIN, - imx335->vblank + - imx335->cur_mode->height - - IMX335_EXPOSURE_OFFSET, - 1, IMX335_EXPOSURE_DEFAULT); + lpfr - shutter_min, 1, + IMX335_EXPOSURE_DEFAULT); if (ret) return ret; } @@ -594,6 +765,10 @@ static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) ret = imx335_update_exp_gain(imx335, exposure, analog_gain); break; + case V4L2_CID_VFLIP: + ret = imx335_update_vertical_flip(imx335, ctrl->val); + + break; case V4L2_CID_TEST_PATTERN: ret = imx335_update_test_pattern(imx335, ctrl->val); @@ -660,17 +835,16 @@ static int imx335_enum_frame_size(struct v4l2_subdev *sd, struct imx335 *imx335 = to_imx335(sd); u32 code; - /* Only a single supported_mode available. */ - if (fsize->index > 0) + if (fsize->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; code = imx335_get_format_code(imx335, fsize->code); if (fsize->code != code) return -EINVAL; - fsize->min_width = supported_mode.width; + fsize->min_width = supported_modes[fsize->index].width; fsize->max_width = fsize->min_width; - fsize->min_height = supported_mode.height; + fsize->min_height = supported_modes[fsize->index].height; fsize->max_height = fsize->min_height; return 0; @@ -698,36 +872,6 @@ static void imx335_fill_pad_format(struct imx335 *imx335, } /** - * imx335_get_pad_format() - Get subdevice pad format - * @sd: pointer to imx335 V4L2 sub-device structure - * @sd_state: V4L2 sub-device configuration - * @fmt: V4L2 sub-device format need to be set - * - * Return: 0 if successful, error code otherwise. - */ -static int imx335_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct imx335 *imx335 = to_imx335(sd); - - mutex_lock(&imx335->mutex); - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_mbus_framefmt *framefmt; - - framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); - fmt->format = *framefmt; - } else { - imx335_fill_pad_format(imx335, imx335->cur_mode, fmt); - } - - mutex_unlock(&imx335->mutex); - - return 0; -} - -/** * imx335_set_pad_format() - Set subdevice pad format * @sd: pointer to imx335 V4L2 sub-device structure * @sd_state: V4L2 sub-device configuration @@ -740,12 +884,16 @@ static int imx335_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_format *fmt) { struct imx335 *imx335 = to_imx335(sd); + struct v4l2_mbus_framefmt *format; const struct imx335_mode *mode; + struct v4l2_rect *crop; int i, ret = 0; - mutex_lock(&imx335->mutex); + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, fmt->format.height); - mode = &supported_mode; for (i = 0; i < ARRAY_SIZE(imx335_mbus_codes); i++) { if (imx335_mbus_codes[i] == fmt->format.code) imx335->cur_mbus_code = imx335_mbus_codes[i]; @@ -753,19 +901,25 @@ static int imx335_set_pad_format(struct v4l2_subdev *sd, imx335_fill_pad_format(imx335, mode, fmt); - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_mbus_framefmt *framefmt; + format = v4l2_subdev_state_get_format(sd_state, fmt->pad); + *format = fmt->format; - framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); - *framefmt = fmt->format; - } else { + crop = v4l2_subdev_state_get_crop(sd_state, fmt->pad); + crop->width = fmt->format.width; + crop->height = fmt->format.height; + if (mode->scan_mode == IMX335_2_2_BINNING) { + crop->width *= 2; + crop->height *= 2; + } + crop->left = (imx335_native_area.width - crop->width) / 2; + crop->top = (imx335_native_area.height - crop->height) / 2; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { ret = imx335_update_controls(imx335, mode); if (!ret) imx335->cur_mode = mode; } - mutex_unlock(&imx335->mutex); - return ret; } @@ -783,14 +937,12 @@ static int imx335_init_state(struct v4l2_subdev *sd, struct v4l2_subdev_format fmt = { 0 }; fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - imx335_fill_pad_format(imx335, &supported_mode, &fmt); + imx335_fill_pad_format(imx335, &supported_modes[0], &fmt); - mutex_lock(&imx335->mutex); __v4l2_ctrl_modify_range(imx335->link_freq_ctrl, 0, __fls(imx335->link_freq_bitmap), ~(imx335->link_freq_bitmap), __ffs(imx335->link_freq_bitmap)); - mutex_unlock(&imx335->mutex); return imx335_set_pad_format(sd, sd_state, &fmt); } @@ -808,22 +960,18 @@ static int imx335_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_selection *sel) { switch (sel->target) { - case V4L2_SEL_TGT_NATIVE_SIZE: - sel->r.top = 0; - sel->r.left = 0; - sel->r.width = IMX335_NATIVE_WIDTH; - sel->r.height = IMX335_NATIVE_HEIGHT; + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); return 0; - case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r = imx335_native_area; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.top = IMX335_PIXEL_ARRAY_TOP; - sel->r.left = IMX335_PIXEL_ARRAY_LEFT; - sel->r.width = IMX335_PIXEL_ARRAY_WIDTH; - sel->r.height = IMX335_PIXEL_ARRAY_HEIGHT; - + sel->r = imx335_active_area; return 0; } @@ -832,39 +980,65 @@ static int imx335_get_selection(struct v4l2_subdev *sd, static int imx335_set_framefmt(struct imx335 *imx335) { - switch (imx335->cur_mbus_code) { - case MEDIA_BUS_FMT_SRGGB10_1X10: - return cci_multi_reg_write(imx335->cci, raw10_framefmt_regs, - ARRAY_SIZE(raw10_framefmt_regs), - NULL); - - case MEDIA_BUS_FMT_SRGGB12_1X12: - return cci_multi_reg_write(imx335->cci, raw12_framefmt_regs, - ARRAY_SIZE(raw12_framefmt_regs), - NULL); + /* + * In the all-pixel scan mode the AD conversion shall match the output + * bit width requested. + * + * However, when 2/2 binning is enabled, the AD conversion is always + * 10-bit, so we ensure ADBIT is clear and ADBIT1 is assigned 0x1ff. + * That's as much as the documentation gives us... + */ + int ret = 0; + u8 bpp = imx335->cur_mbus_code == MEDIA_BUS_FMT_SRGGB10_1X10 ? 10 : 12; + u8 ad_conv = bpp; + + /* Start with the output mode */ + cci_write(imx335->cci, IMX335_REG_MDBIT, bpp == 12, &ret); + + /* Enforce 10 bit AD on binning modes */ + if (imx335->cur_mode->scan_mode == IMX335_2_2_BINNING) + ad_conv = 10; + + /* AD Conversion configuration */ + if (ad_conv == 10) { + cci_write(imx335->cci, IMX335_REG_ADBIT, 0x00, &ret); + cci_write(imx335->cci, IMX335_REG_ADBIT1, 0x1ff, &ret); + } else { /* 12 bit AD Conversion */ + cci_write(imx335->cci, IMX335_REG_ADBIT, 0x01, &ret); + cci_write(imx335->cci, IMX335_REG_ADBIT1, 0x47, &ret); } - return -EINVAL; + return ret; } /** - * imx335_start_streaming() - Start sensor stream - * @imx335: pointer to imx335 device + * imx335_enable_streams() - Enable sensor streams + * @sd: V4L2 subdevice + * @state: V4L2 subdevice state + * @pad: The pad to enable + * @streams_mask: Bitmask of streams to enable * * Return: 0 if successful, error code otherwise. */ -static int imx335_start_streaming(struct imx335 *imx335) +static int imx335_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { + struct imx335 *imx335 = to_imx335(sd); const struct imx335_reg_list *reg_list; int ret; + ret = pm_runtime_resume_and_get(imx335->dev); + if (ret < 0) + return ret; + /* Setup PLL */ reg_list = &link_freq_reglist[__ffs(imx335->link_freq_bitmap)]; ret = cci_multi_reg_write(imx335->cci, reg_list->regs, reg_list->num_of_regs, NULL); if (ret) { dev_err(imx335->dev, "%s failed to set plls\n", __func__); - return ret; + goto err_rpm_put; } /* Write sensor mode registers */ @@ -873,27 +1047,35 @@ static int imx335_start_streaming(struct imx335 *imx335) reg_list->num_of_regs, NULL); if (ret) { dev_err(imx335->dev, "fail to write initial registers\n"); - return ret; + goto err_rpm_put; + } + + /* Write sensor common registers */ + ret = cci_multi_reg_write(imx335->cci, imx335_common_regs, + ARRAY_SIZE(imx335_common_regs), NULL); + if (ret) { + dev_err(imx335->dev, "fail to write initial registers\n"); + goto err_rpm_put; } ret = imx335_set_framefmt(imx335); if (ret) { dev_err(imx335->dev, "%s failed to set frame format: %d\n", __func__, ret); - return ret; + goto err_rpm_put; } /* Configure lanes */ ret = cci_write(imx335->cci, IMX335_REG_LANEMODE, imx335->lane_mode, NULL); if (ret) - return ret; + goto err_rpm_put; /* Setup handler will write actual exposure and gain */ ret = __v4l2_ctrl_handler_setup(imx335->sd.ctrl_handler); if (ret) { dev_err(imx335->dev, "fail to setup handler\n"); - return ret; + goto err_rpm_put; } /* Start streaming */ @@ -901,62 +1083,39 @@ static int imx335_start_streaming(struct imx335 *imx335) IMX335_MODE_STREAMING, NULL); if (ret) { dev_err(imx335->dev, "fail to start streaming\n"); - return ret; + goto err_rpm_put; } /* Initial regulator stabilization period */ usleep_range(18000, 20000); return 0; -} -/** - * imx335_stop_streaming() - Stop sensor stream - * @imx335: pointer to imx335 device - * - * Return: 0 if successful, error code otherwise. - */ -static int imx335_stop_streaming(struct imx335 *imx335) -{ - return cci_write(imx335->cci, IMX335_REG_MODE_SELECT, - IMX335_MODE_STANDBY, NULL); +err_rpm_put: + pm_runtime_put(imx335->dev); + + return ret; } /** - * imx335_set_stream() - Enable sensor streaming - * @sd: pointer to imx335 subdevice - * @enable: set to enable sensor streaming + * imx335_disable_streams() - Disable sensor streams + * @sd: V4L2 subdevice + * @state: V4L2 subdevice state + * @pad: The pad to disable + * @streams_mask: Bitmask of streams to disable * * Return: 0 if successful, error code otherwise. */ -static int imx335_set_stream(struct v4l2_subdev *sd, int enable) +static int imx335_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) { struct imx335 *imx335 = to_imx335(sd); int ret; - mutex_lock(&imx335->mutex); - - if (enable) { - ret = pm_runtime_resume_and_get(imx335->dev); - if (ret) - goto error_unlock; - - ret = imx335_start_streaming(imx335); - if (ret) - goto error_power_off; - } else { - imx335_stop_streaming(imx335); - pm_runtime_put(imx335->dev); - } - - mutex_unlock(&imx335->mutex); - - return 0; - -error_power_off: + ret = cci_write(imx335->cci, IMX335_REG_MODE_SELECT, + IMX335_MODE_STANDBY, NULL); pm_runtime_put(imx335->dev); -error_unlock: - mutex_unlock(&imx335->mutex); return ret; } @@ -1009,8 +1168,8 @@ static int imx335_parse_hw_config(struct imx335 *imx335) imx335->reset_gpio = devm_gpiod_get_optional(imx335->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(imx335->reset_gpio)) { - dev_err(imx335->dev, "failed to get reset gpio %ld\n", - PTR_ERR(imx335->reset_gpio)); + dev_err(imx335->dev, "failed to get reset gpio %pe\n", + imx335->reset_gpio); return PTR_ERR(imx335->reset_gpio); } @@ -1026,11 +1185,10 @@ static int imx335_parse_hw_config(struct imx335 *imx335) } /* Get sensor input clock */ - imx335->inclk = devm_clk_get(imx335->dev, NULL); - if (IS_ERR(imx335->inclk)) { - dev_err(imx335->dev, "could not get inclk\n"); - return PTR_ERR(imx335->inclk); - } + imx335->inclk = devm_v4l2_sensor_clk_get(imx335->dev, NULL); + if (IS_ERR(imx335->inclk)) + return dev_err_probe(imx335->dev, PTR_ERR(imx335->inclk), + "could not get inclk\n"); rate = clk_get_rate(imx335->inclk); if (rate != IMX335_INCLK_RATE) { @@ -1077,7 +1235,7 @@ done_endpoint_free: /* V4l2 subdevice ops */ static const struct v4l2_subdev_video_ops imx335_video_ops = { - .s_stream = imx335_set_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops imx335_pad_ops = { @@ -1085,8 +1243,10 @@ static const struct v4l2_subdev_pad_ops imx335_pad_ops = { .enum_frame_size = imx335_enum_frame_size, .get_selection = imx335_get_selection, .set_selection = imx335_get_selection, - .get_fmt = imx335_get_pad_format, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx335_set_pad_format, + .enable_streams = imx335_enable_streams, + .disable_streams = imx335_disable_streams, }; static const struct v4l2_subdev_ops imx335_subdev_ops = { @@ -1168,7 +1328,7 @@ static int imx335_init_controls(struct imx335 *imx335) struct v4l2_ctrl_handler *ctrl_hdlr = &imx335->ctrl_handler; const struct imx335_mode *mode = imx335->cur_mode; struct v4l2_fwnode_device_properties props; - u32 lpfr; + u32 lpfr, shutter_min; int ret; ret = v4l2_fwnode_device_parse(imx335->dev, &props); @@ -1176,20 +1336,20 @@ static int imx335_init_controls(struct imx335 *imx335) return ret; /* v4l2_fwnode_device_properties can add two more controls */ - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9); + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); if (ret) return ret; - /* Serialize controls with sensor device */ - ctrl_hdlr->lock = &imx335->mutex; - /* Initialize exposure and gain */ lpfr = mode->vblank + mode->height; + shutter_min = IMX335_SHUTTER_MIN; + if (mode->scan_mode == IMX335_2_2_BINNING) + shutter_min = IMX335_SHUTTER_MIN_BINNED; imx335->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &imx335_ctrl_ops, V4L2_CID_EXPOSURE, IMX335_EXPOSURE_MIN, - lpfr - IMX335_EXPOSURE_OFFSET, + lpfr - shutter_min, IMX335_EXPOSURE_STEP, IMX335_EXPOSURE_DEFAULT); @@ -1211,6 +1371,13 @@ static int imx335_init_controls(struct imx335 *imx335) v4l2_ctrl_cluster(2, &imx335->exp_ctrl); + imx335->vflip = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_VFLIP, + 0, 1, 1, 0); + if (imx335->vflip) + imx335->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + imx335->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &imx335_ctrl_ops, V4L2_CID_VBLANK, @@ -1295,12 +1462,10 @@ static int imx335_probe(struct i2c_client *client) return ret; } - mutex_init(&imx335->mutex); - ret = imx335_power_on(imx335->dev); if (ret) { dev_err(imx335->dev, "failed to power-on the sensor\n"); - goto error_mutex_destroy; + return ret; } /* Check module identity */ @@ -1311,7 +1476,7 @@ static int imx335_probe(struct i2c_client *client) } /* Set default mode to max resolution */ - imx335->cur_mode = &supported_mode; + imx335->cur_mode = &supported_modes[0]; imx335->cur_mbus_code = imx335_mbus_codes[0]; imx335->vblank = imx335->cur_mode->vblank; @@ -1333,11 +1498,18 @@ static int imx335_probe(struct i2c_client *client) goto error_handler_free; } + imx335->sd.state_lock = imx335->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&imx335->sd); + if (ret < 0) { + dev_err(imx335->dev, "subdev init error\n"); + goto error_media_entity; + } + ret = v4l2_async_register_subdev_sensor(&imx335->sd); if (ret < 0) { dev_err(imx335->dev, "failed to register async subdev: %d\n", ret); - goto error_media_entity; + goto error_subdev_cleanup; } pm_runtime_set_active(imx335->dev); @@ -1346,14 +1518,14 @@ static int imx335_probe(struct i2c_client *client) return 0; +error_subdev_cleanup: + v4l2_subdev_cleanup(&imx335->sd); error_media_entity: media_entity_cleanup(&imx335->sd.entity); error_handler_free: v4l2_ctrl_handler_free(imx335->sd.ctrl_handler); error_power_off: imx335_power_off(imx335->dev); -error_mutex_destroy: - mutex_destroy(&imx335->mutex); return ret; } @@ -1367,9 +1539,9 @@ error_mutex_destroy: static void imx335_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx335 *imx335 = to_imx335(sd); v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); @@ -1377,8 +1549,6 @@ static void imx335_remove(struct i2c_client *client) if (!pm_runtime_status_suspended(&client->dev)) imx335_power_off(&client->dev); pm_runtime_set_suspended(&client->dev); - - mutex_destroy(&imx335->mutex); } static const struct dev_pm_ops imx335_pm_ops = { diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index b2dce67c0b6b..776107efe386 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2018 Intel Corporation -#include <linux/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> @@ -92,11 +94,13 @@ struct imx355_mode { }; struct imx355_hwcfg { - u32 ext_clk; /* sensor external clk */ unsigned long link_freq_bitmap; }; struct imx355 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; @@ -1136,14 +1140,13 @@ static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val) static int imx355_write_regs(struct imx355 *imx355, const struct imx355_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); int ret; u32 i; for (i = 0; i < len; i++) { ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(imx355->dev, "write reg 0x%4.4x return err %d", regs[i].address, ret); @@ -1178,7 +1181,6 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx355 *imx355 = container_of(ctrl->handler, struct imx355, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); s64 max; int ret; @@ -1197,7 +1199,7 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(imx355->dev)) return 0; switch (ctrl->id) { @@ -1231,12 +1233,12 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) break; default: ret = -EINVAL; - dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled", + dev_info(imx355->dev, "ctrl(id:0x%x,val:0x%x) is not handled", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(imx355->dev); return ret; } @@ -1385,7 +1387,6 @@ imx355_set_pad_format(struct v4l2_subdev *sd, /* Start streaming */ static int imx355_start_streaming(struct imx355 *imx355) { - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); const struct imx355_reg_list *reg_list; int ret; @@ -1393,7 +1394,7 @@ static int imx355_start_streaming(struct imx355 *imx355) reg_list = &imx355_global_setting; ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "failed to set global settings"); + dev_err(imx355->dev, "failed to set global settings"); return ret; } @@ -1401,7 +1402,7 @@ static int imx355_start_streaming(struct imx355 *imx355) reg_list = &imx355->cur_mode->reg_list; ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(imx355->dev, "failed to set mode"); return ret; } @@ -1429,13 +1430,12 @@ static int imx355_stop_streaming(struct imx355 *imx355) static int imx355_set_stream(struct v4l2_subdev *sd, int enable) { struct imx355 *imx355 = to_imx355(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&imx355->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx355->dev); if (ret < 0) goto err_unlock; @@ -1448,7 +1448,7 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx355_stop_streaming(imx355); - pm_runtime_put(&client->dev); + pm_runtime_put(imx355->dev); } /* vflip and hflip cannot change during streaming */ @@ -1460,7 +1460,7 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx355->dev); err_unlock: mutex_unlock(&imx355->mutex); @@ -1470,7 +1470,6 @@ err_unlock: /* Verify chip ID */ static int imx355_identify_module(struct imx355 *imx355) { - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); int ret; u32 val; @@ -1479,7 +1478,7 @@ static int imx355_identify_module(struct imx355 *imx355) return ret; if (val != IMX355_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(imx355->dev, "chip id mismatch: %x!=%x", IMX355_CHIP_ID, val); return -EIO; } @@ -1519,7 +1518,6 @@ static const struct v4l2_subdev_internal_ops imx355_internal_ops = { /* Initialize control handlers */ static int imx355_init_controls(struct imx355 *imx355) { - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; @@ -1600,11 +1598,11 @@ static int imx355_init_controls(struct imx355 *imx355) 0, 0, imx355_test_pattern_menu); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "control init failed: %d", ret); + dev_err(imx355->dev, "control init failed: %d", ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(imx355->dev, &props); if (ret) goto error; @@ -1648,20 +1646,6 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) if (!cfg) goto out_err; - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &cfg->ext_clk); - if (ret) { - dev_err(dev, "can't get clock frequency"); - goto out_err; - } - - dev_dbg(dev, "ext clk: %d", cfg->ext_clk); - if (cfg->ext_clk != IMX355_EXT_CLK) { - dev_err(dev, "external clock %d is not supported", - cfg->ext_clk); - goto out_err; - } - ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, bus_cfg.nr_of_link_frequencies, link_freq_menu_items, @@ -1683,27 +1667,41 @@ out_err: static int imx355_probe(struct i2c_client *client) { struct imx355 *imx355; + unsigned long freq; int ret; imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL); if (!imx355) return -ENOMEM; + imx355->dev = &client->dev; + mutex_init(&imx355->mutex); + imx355->clk = devm_v4l2_sensor_clk_get(imx355->dev, NULL); + if (IS_ERR(imx355->clk)) + return dev_err_probe(imx355->dev, PTR_ERR(imx355->clk), + "failed to get clock\n"); + + freq = clk_get_rate(imx355->clk); + if (freq != IMX355_EXT_CLK) + return dev_err_probe(imx355->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + /* Initialize subdev */ v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops); /* Check module identity */ ret = imx355_identify_module(imx355); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(imx355->dev, "failed to find sensor: %d", ret); goto error_probe; } - imx355->hwcfg = imx355_get_hwcfg(&client->dev); + imx355->hwcfg = imx355_get_hwcfg(imx355->dev); if (!imx355->hwcfg) { - dev_err(&client->dev, "failed to get hwcfg"); + dev_err(imx355->dev, "failed to get hwcfg"); ret = -ENODEV; goto error_probe; } @@ -1713,7 +1711,7 @@ static int imx355_probe(struct i2c_client *client) ret = imx355_init_controls(imx355); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(imx355->dev, "failed to init controls: %d", ret); goto error_probe; } @@ -1728,7 +1726,7 @@ static int imx355_probe(struct i2c_client *client) imx355->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&imx355->sd.entity, 1, &imx355->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(imx355->dev, "failed to init entity pads: %d", ret); goto error_handler_free; } @@ -1736,9 +1734,9 @@ static int imx355_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(imx355->dev); + pm_runtime_enable(imx355->dev); + pm_runtime_idle(imx355->dev); ret = v4l2_async_register_subdev_sensor(&imx355->sd); if (ret < 0) @@ -1747,8 +1745,8 @@ static int imx355_probe(struct i2c_client *client) return 0; error_media_entity_runtime_pm: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx355->dev); + pm_runtime_set_suspended(imx355->dev); media_entity_cleanup(&imx355->sd.entity); error_handler_free: @@ -1769,8 +1767,8 @@ static void imx355_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx355->dev); + pm_runtime_set_suspended(imx355->dev); mutex_destroy(&imx355->mutex); } diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index c74097a59c42..b3826f803547 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -927,17 +927,16 @@ static int imx412_parse_hw_config(struct imx412 *imx412) imx412->reset_gpio = devm_gpiod_get_optional(imx412->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(imx412->reset_gpio)) { - dev_err(imx412->dev, "failed to get reset gpio %ld\n", - PTR_ERR(imx412->reset_gpio)); + dev_err(imx412->dev, "failed to get reset gpio %pe\n", + imx412->reset_gpio); return PTR_ERR(imx412->reset_gpio); } /* Get sensor input clock */ - imx412->inclk = devm_clk_get(imx412->dev, NULL); - if (IS_ERR(imx412->inclk)) { - dev_err(imx412->dev, "could not get inclk\n"); - return PTR_ERR(imx412->inclk); - } + imx412->inclk = devm_v4l2_sensor_clk_get(imx412->dev, NULL); + if (IS_ERR(imx412->inclk)) + return dev_err_probe(imx412->dev, PTR_ERR(imx412->inclk), + "could not get inclk\n"); rate = clk_get_rate(imx412->inclk); if (rate != IMX412_INCLK_RATE) { diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 278e743646ea..0b424c17e880 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -952,7 +952,6 @@ static int imx415_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { ret = imx415_stream_off(sensor); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); goto unlock; @@ -1251,7 +1250,7 @@ static int imx415_parse_hw_config(struct imx415 *sensor) return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), "failed to get reset GPIO\n"); - sensor->clk = devm_clk_get(sensor->dev, NULL); + sensor->clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); if (IS_ERR(sensor->clk)) return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), "failed to get clock\n"); diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index c84e1e0e6109..5588cdd7ec20 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -321,9 +321,9 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, static int ir_key_poll(struct IR_i2c *ir) { - enum rc_proto protocol; - u32 scancode; - u8 toggle; + enum rc_proto protocol = 0; + u32 scancode = 0; + u8 toggle = 0; int rc; dev_dbg(&ir->rc->dev, "%s\n", __func__); diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index 7c0961688d61..e6e214f8294b 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -751,8 +751,8 @@ static int max9286_v4l2_notifier_register(struct max9286_priv *priv) mas = v4l2_async_nf_add_fwnode(&priv->notifier, source->fwnode, struct max9286_asd); if (IS_ERR(mas)) { - dev_err(dev, "Failed to add subdev for source %u: %ld", - i, PTR_ERR(mas)); + dev_err(dev, "Failed to add subdev for source %u: %pe", + i, mas); v4l2_async_nf_cleanup(&priv->notifier); return PTR_ERR(mas); } diff --git a/drivers/media/i2c/max96717.c b/drivers/media/i2c/max96717.c index c8ae7890d9fa..72f021b1a7b9 100644 --- a/drivers/media/i2c/max96717.c +++ b/drivers/media/i2c/max96717.c @@ -650,7 +650,7 @@ static int max96717_v4l2_notifier_register(struct max96717_priv *priv) fwnode_handle_put(ep_fwnode); if (IS_ERR(asd)) { - dev_err(dev, "Failed to add subdev: %ld", PTR_ERR(asd)); + dev_err(dev, "Failed to add subdev: %pe", asd); v4l2_async_nf_cleanup(&priv->notifier); return PTR_ERR(asd); } @@ -782,21 +782,23 @@ static unsigned int max96717_clk_find_best_index(struct max96717_priv *priv, return idx; } -static long max96717_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int max96717_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct max96717_priv *priv = clk_hw_to_max96717(hw); struct device *dev = &priv->client->dev; unsigned int idx; - idx = max96717_clk_find_best_index(priv, rate); + idx = max96717_clk_find_best_index(priv, req->rate); - if (rate != max96717_predef_freqs[idx].freq) { + if (req->rate != max96717_predef_freqs[idx].freq) { dev_warn(dev, "Request CLK freq:%lu, found CLK freq:%lu\n", - rate, max96717_predef_freqs[idx].freq); + req->rate, max96717_predef_freqs[idx].freq); } - return max96717_predef_freqs[idx].freq; + req->rate = max96717_predef_freqs[idx].freq; + + return 0; } static int max96717_clk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -847,7 +849,7 @@ static const struct clk_ops max96717_clk_ops = { .unprepare = max96717_clk_unprepare, .set_rate = max96717_clk_set_rate, .recalc_rate = max96717_clk_recalc_rate, - .round_rate = max96717_clk_round_rate, + .determine_rate = max96717_clk_determine_rate, }; static int max96717_register_clkout(struct max96717_priv *priv) diff --git a/drivers/media/i2c/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c index ecabc0e1d32e..1d9f41dd7c21 100644 --- a/drivers/media/i2c/msp3400-kthreads.c +++ b/drivers/media/i2c/msp3400-kthreads.c @@ -596,6 +596,8 @@ restart: "carrier2 val: %5d / %s\n", val, cd[i].name); } + if (max1 < 0 || max1 > 3) + goto restart; /* program the msp3400 according to the results */ state->main = msp3400c_carrier_detect_main[max1].cdo; switch (max1) { diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 12d3e86bdc0f..7a6114d18dfc 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -743,9 +743,10 @@ static int mt9m001_probe(struct i2c_client *client) if (!mt9m001) return -ENOMEM; - mt9m001->clk = devm_clk_get(&client->dev, NULL); + mt9m001->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9m001->clk)) - return PTR_ERR(mt9m001->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9m001->clk), + "failed to get the clock\n"); mt9m001->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", GPIOD_OUT_LOW); diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 9aa5dcda3805..3532c7c38bec 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -1279,14 +1279,15 @@ static int mt9m111_probe(struct i2c_client *client) return ret; } - mt9m111->clk = devm_clk_get(&client->dev, "mclk"); + mt9m111->clk = devm_v4l2_sensor_clk_get(&client->dev, "mclk"); if (IS_ERR(mt9m111->clk)) - return PTR_ERR(mt9m111->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9m111->clk), + "failed to get mclk\n"); mt9m111->regulator = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(mt9m111->regulator)) { - dev_err(&client->dev, "regulator not found: %ld\n", - PTR_ERR(mt9m111->regulator)); + dev_err(&client->dev, "regulator not found: %pe\n", + mt9m111->regulator); return PTR_ERR(mt9m111->regulator); } diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c index 3f540ca40f3c..51ebbe7ae996 100644 --- a/drivers/media/i2c/mt9m114.c +++ b/drivers/media/i2c/mt9m114.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/types.h> @@ -42,6 +43,9 @@ #define MT9M114_RESET_AND_MISC_CONTROL CCI_REG16(0x001a) #define MT9M114_RESET_SOC BIT(0) #define MT9M114_PAD_SLEW CCI_REG16(0x001e) +#define MT9M114_PAD_SLEW_MIN 0 +#define MT9M114_PAD_SLEW_MAX 7 +#define MT9M114_PAD_SLEW_DEFAULT 7 #define MT9M114_PAD_CONTROL CCI_REG16(0x0032) /* XDMA registers */ @@ -388,6 +392,7 @@ struct mt9m114 { unsigned int pixrate; bool streaming; + u32 pad_slew_rate; /* Pixel Array */ struct { @@ -645,9 +650,6 @@ static const struct cci_reg_sequence mt9m114_init[] = { { MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX, 1459 }, { MT9M114_CAM_SENSOR_CFG_FINE_CORRECTION, 96 }, { MT9M114_CAM_SENSOR_CFG_REG_0_DATA, 32 }, - - /* Miscellaneous settings */ - { MT9M114_PAD_SLEW, 0x0777 }, }; /* ----------------------------------------------------------------------------- @@ -779,6 +781,13 @@ static int mt9m114_initialize(struct mt9m114 *sensor) if (ret < 0) return ret; + value = sensor->pad_slew_rate + | sensor->pad_slew_rate << 4 + | sensor->pad_slew_rate << 8; + cci_write(sensor->regmap, MT9M114_PAD_SLEW, value, &ret); + if (ret < 0) + return ret; + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); if (ret < 0) return ret; @@ -974,7 +983,6 @@ static int mt9m114_start_streaming(struct mt9m114 *sensor, return 0; error: - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -988,7 +996,6 @@ static int mt9m114_stop_streaming(struct mt9m114 *sensor) ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND); - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -1046,7 +1053,6 @@ static int mt9m114_pa_g_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -1113,7 +1119,6 @@ static int mt9m114_pa_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -1287,6 +1292,7 @@ static int mt9m114_pa_set_selection(struct v4l2_subdev *sd, struct mt9m114 *sensor = pa_to_mt9m114(sd); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; + int ret = 0; if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; @@ -1302,25 +1308,41 @@ static int mt9m114_pa_set_selection(struct v4l2_subdev *sd, * binning, but binning is configured after setting the selection, so * we can't know tell here if it will be used. */ - crop->left = ALIGN(sel->r.left, 4); - crop->top = ALIGN(sel->r.top, 2); - crop->width = clamp_t(unsigned int, ALIGN(sel->r.width, 4), - MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, - MT9M114_PIXEL_ARRAY_WIDTH - crop->left); - crop->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), - MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, - MT9M114_PIXEL_ARRAY_HEIGHT - crop->top); - - sel->r = *crop; + sel->r.left = ALIGN(sel->r.left, 4); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = clamp_t(unsigned int, ALIGN(sel->r.width, 4), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, + MT9M114_PIXEL_ARRAY_WIDTH - sel->r.left); + sel->r.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, + MT9M114_PIXEL_ARRAY_HEIGHT - sel->r.top); + + /* Changing the selection size is not allowed in streaming state. */ + if (sensor->streaming && + (sel->r.height != crop->height || sel->r.width != crop->width)) + return -EBUSY; + + *crop = sel->r; /* Reset the format. */ format->width = crop->width; format->height = crop->height; - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) - mt9m114_pa_ctrl_update_blanking(sensor, format); + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return ret; - return 0; + mt9m114_pa_ctrl_update_blanking(sensor, format); + + /* Apply values immediately if streaming. */ + if (sensor->streaming) { + ret = mt9m114_configure_pa(sensor, state); + if (ret) + return ret; + /* Changing the cropping config requires a CONFIG_CHANGE. */ + ret = mt9m114_set_state(sensor, + MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); + } + return ret; } static const struct v4l2_subdev_pad_ops mt9m114_pa_pad_ops = { @@ -1565,7 +1587,6 @@ static int mt9m114_ifp_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -2365,6 +2386,17 @@ static int mt9m114_parse_dt(struct mt9m114 *sensor) goto error; } + sensor->pad_slew_rate = MT9M114_PAD_SLEW_DEFAULT; + device_property_read_u32(&sensor->client->dev, "slew-rate", + &sensor->pad_slew_rate); + + if (sensor->pad_slew_rate < MT9M114_PAD_SLEW_MIN || + sensor->pad_slew_rate > MT9M114_PAD_SLEW_MAX) { + dev_err(&sensor->client->dev, "Invalid slew-rate %u\n", + sensor->pad_slew_rate); + return -EINVAL; + } + return 0; error: @@ -2395,10 +2427,10 @@ static int mt9m114_probe(struct i2c_client *client) return ret; /* Acquire clocks, GPIOs and regulators. */ - sensor->clk = devm_clk_get(dev, NULL); + sensor->clk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->clk)) { - ret = PTR_ERR(sensor->clk); - dev_err_probe(dev, ret, "Failed to get clock\n"); + ret = dev_err_probe(dev, PTR_ERR(sensor->clk), + "Failed to get clock\n"); goto error_ep_free; } @@ -2472,7 +2504,6 @@ static int mt9m114_probe(struct i2c_client *client) * 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; diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 4ef5fb06131d..1500ee4db47e 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -233,9 +233,10 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) unsigned long ext_freq; int ret; - mt9p031->clk = devm_clk_get(&client->dev, NULL); + mt9p031->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9p031->clk)) - return PTR_ERR(mt9p031->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9p031->clk), + "failed to get the clock\n"); ret = clk_set_rate(mt9p031->clk, mt9p031->ext_freq); if (ret < 0) @@ -1092,6 +1093,7 @@ static int mt9p031_parse_properties(struct mt9p031 *mt9p031, struct device *dev) static int mt9p031_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; + const struct mt9p031_model_info *info; struct mt9p031 *mt9p031; unsigned int i; int ret; @@ -1112,7 +1114,8 @@ static int mt9p031_probe(struct i2c_client *client) mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF; mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC; - mt9p031->code = (uintptr_t)device_get_match_data(&client->dev); + info = device_get_match_data(&client->dev); + mt9p031->code = info->code; mt9p031->regulators[0].supply = "vdd"; mt9p031->regulators[1].supply = "vdd_io"; diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index 878dff9b7577..2d2c840fc002 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -1078,13 +1078,12 @@ static int mt9t112_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - priv->clk = devm_clk_get(&client->dev, "extclk"); - if (PTR_ERR(priv->clk) == -ENOENT) { + priv->clk = devm_v4l2_sensor_clk_get(&client->dev, "extclk"); + if (PTR_ERR(priv->clk) == -ENOENT) priv->clk = NULL; - } else if (IS_ERR(priv->clk)) { - dev_err(&client->dev, "Unable to get clock \"extclk\"\n"); - return PTR_ERR(priv->clk); - } + else if (IS_ERR(priv->clk)) + return dev_err_probe(&client->dev, PTR_ERR(priv->clk), + "Unable to get clock \"extclk\"\n"); priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", GPIOD_OUT_HIGH); diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 302120ff125e..d4359d5b92bb 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -15,16 +15,15 @@ #include <linux/i2c.h> #include <linux/log2.h> #include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> #include <linux/of_graph.h> #include <linux/regmap.h> #include <linux/slab.h> -#include <linux/videodev2.h> #include <linux/v4l2-mediabus.h> -#include <linux/module.h> +#include <linux/videodev2.h> -#include <media/i2c/mt9v032.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -182,7 +181,16 @@ static const struct mt9v032_model_version mt9v032_versions[] = { { MT9V034_CHIP_ID_REV1, "MT9V024/MT9V034 rev1" }, }; +struct mt9v032_platform_data { + unsigned int clk_pol:1; + + const s64 *link_freqs; + s64 link_def_freq; +}; + struct mt9v032 { + struct device *dev; + struct v4l2_subdev subdev; struct media_pad pad; @@ -205,7 +213,7 @@ struct mt9v032 { struct gpio_desc *reset_gpio; struct gpio_desc *standby_gpio; - struct mt9v032_platform_data *pdata; + struct mt9v032_platform_data pdata; const struct mt9v032_model_info *model; const struct mt9v032_model_version *version; @@ -330,7 +338,7 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on) return ret; /* Configure the pixel clock polarity */ - if (mt9v032->pdata && mt9v032->pdata->clk_pol) { + if (mt9v032->pdata.clk_pol) { ret = regmap_write(map, mt9v032->model->data->pclk_reg, MT9V032_PIXEL_CLOCK_INV_PXL_CLK); if (ret < 0) @@ -473,13 +481,12 @@ static int mt9v032_get_format(struct v4l2_subdev *subdev, static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032) { - struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); int ret; ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate, mt9v032->sysclk / mt9v032->hratio); if (ret < 0) - dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret); + dev_warn(mt9v032->dev, "failed to set pixel rate (%d)\n", ret); } static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output) @@ -682,7 +689,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) if (mt9v032->link_freq == NULL) break; - freq = mt9v032->pdata->link_freqs[mt9v032->link_freq->val]; + freq = mt9v032->pdata.link_freqs[mt9v032->link_freq->val]; *mt9v032->pixel_rate->p_new.p_s64 = freq; mt9v032->sysclk = freq; break; @@ -883,12 +890,12 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) u32 version; int ret; - dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n", + dev_info(mt9v032->dev, "Probing MT9V032 at address 0x%02x\n", client->addr); ret = mt9v032_power_on(mt9v032); if (ret < 0) { - dev_err(&client->dev, "MT9V032 power up failed\n"); + dev_err(mt9v032->dev, "MT9V032 power up failed\n"); return ret; } @@ -898,7 +905,7 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) mt9v032_power_off(mt9v032); if (ret < 0) { - dev_err(&client->dev, "Failed reading chip version\n"); + dev_err(mt9v032->dev, "Failed reading chip version\n"); return ret; } @@ -910,12 +917,12 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) } if (mt9v032->version == NULL) { - dev_err(&client->dev, "Unsupported chip version 0x%04x\n", + dev_err(mt9v032->dev, "Unsupported chip version 0x%04x\n", version); return -ENODEV; } - dev_info(&client->dev, "%s detected at address 0x%02x\n", + dev_info(mt9v032->dev, "%s detected at address 0x%02x\n", mt9v032->version->name, client->addr); mt9v032_configure_pixel_rate(mt9v032); @@ -995,41 +1002,33 @@ static const struct regmap_config mt9v032_regmap_config = { * Driver initialization and probing */ -static struct mt9v032_platform_data * -mt9v032_get_pdata(struct i2c_client *client) +static int mt9v032_get_pdata(struct mt9v032 *mt9v032) { - struct mt9v032_platform_data *pdata = NULL; + struct mt9v032_platform_data *pdata = &mt9v032->pdata; struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 }; - struct device_node *np; + struct device_node *np __free(device_node) = NULL; struct property *prop; - 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 = of_graph_get_endpoint_by_regs(mt9v032->dev->of_node, 0, -1); if (!np) - return NULL; + return -EINVAL; if (v4l2_fwnode_endpoint_parse(of_fwnode_handle(np), &endpoint) < 0) - goto done; - - pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - goto done; + return -EINVAL; prop = of_find_property(np, "link-frequencies", NULL); if (prop) { u64 *link_freqs; size_t size = prop->length / sizeof(*link_freqs); - link_freqs = devm_kcalloc(&client->dev, size, + link_freqs = devm_kcalloc(mt9v032->dev, size, sizeof(*link_freqs), GFP_KERNEL); if (!link_freqs) - goto done; + return -EINVAL; if (of_property_read_u64_array(np, "link-frequencies", link_freqs, size) < 0) - goto done; + return -EINVAL; pdata->link_freqs = link_freqs; pdata->link_def_freq = link_freqs[0]; @@ -1038,14 +1037,11 @@ mt9v032_get_pdata(struct i2c_client *client) pdata->clk_pol = !!(endpoint.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING); -done: - of_node_put(np); - return pdata; + return 0; } static int mt9v032_probe(struct i2c_client *client) { - struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client); struct mt9v032 *mt9v032; unsigned int i; int ret; @@ -1054,27 +1050,35 @@ static int mt9v032_probe(struct i2c_client *client) if (!mt9v032) return -ENOMEM; + mt9v032->dev = &client->dev; + mt9v032->regmap = devm_regmap_init_i2c(client, &mt9v032_regmap_config); if (IS_ERR(mt9v032->regmap)) return PTR_ERR(mt9v032->regmap); - mt9v032->clk = devm_clk_get(&client->dev, NULL); + mt9v032->clk = devm_v4l2_sensor_clk_get(mt9v032->dev, NULL); if (IS_ERR(mt9v032->clk)) - return PTR_ERR(mt9v032->clk); + return dev_err_probe(mt9v032->dev, PTR_ERR(mt9v032->clk), + "failed to get the clock\n"); - mt9v032->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + mt9v032->reset_gpio = devm_gpiod_get_optional(mt9v032->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(mt9v032->reset_gpio)) return PTR_ERR(mt9v032->reset_gpio); - mt9v032->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", + mt9v032->standby_gpio = devm_gpiod_get_optional(mt9v032->dev, "standby", GPIOD_OUT_LOW); if (IS_ERR(mt9v032->standby_gpio)) return PTR_ERR(mt9v032->standby_gpio); mutex_init(&mt9v032->power_lock); - mt9v032->pdata = pdata; - mt9v032->model = i2c_get_match_data(client); + + ret = mt9v032_get_pdata(mt9v032); + if (ret) + return dev_err_probe(mt9v032->dev, -EINVAL, + "Failed to parse DT properties\n"); + + mt9v032->model = device_get_match_data(mt9v032->dev); v4l2_ctrl_handler_init(&mt9v032->ctrls, 11 + ARRAY_SIZE(mt9v032_aegc_controls)); @@ -1119,7 +1123,8 @@ static int mt9v032_probe(struct i2c_client *client) v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); - if (pdata && pdata->link_freqs) { + if (mt9v032->pdata.link_freqs) { + const struct mt9v032_platform_data *pdata = &mt9v032->pdata; unsigned int def = 0; for (i = 0; pdata->link_freqs[i]; ++i) { @@ -1139,7 +1144,7 @@ static int mt9v032_probe(struct i2c_client *client) mt9v032->subdev.ctrl_handler = &mt9v032->ctrls; if (mt9v032->ctrls.error) { - dev_err(&client->dev, "control initialization error %d\n", + dev_err(mt9v032->dev, "control initialization error %d\n", mt9v032->ctrls.error); ret = mt9v032->ctrls.error; goto err; @@ -1177,7 +1182,7 @@ static int mt9v032_probe(struct i2c_client *client) if (ret < 0) goto err; - mt9v032->subdev.dev = &client->dev; + mt9v032->subdev.dev = mt9v032->dev; ret = v4l2_async_register_subdev(&mt9v032->subdev); if (ret < 0) goto err; @@ -1261,19 +1266,6 @@ static const struct mt9v032_model_info mt9v032_models[] = { }, }; -static const struct i2c_device_id mt9v032_id[] = { - { "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] }, - { "mt9v022m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_MONO] }, - { "mt9v024", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_COLOR] }, - { "mt9v024m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_MONO] }, - { "mt9v032", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_COLOR] }, - { "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] }, - { "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] }, - { "mt9v034m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_MONO] }, - { /* Sentinel */ } -}; -MODULE_DEVICE_TABLE(i2c, mt9v032_id); - static const struct of_device_id mt9v032_of_match[] = { { .compatible = "aptina,mt9v022", .data = &mt9v032_models[MT9V032_MODEL_V022_COLOR] }, { .compatible = "aptina,mt9v022m", .data = &mt9v032_models[MT9V032_MODEL_V022_MONO] }, @@ -1294,7 +1286,6 @@ static struct i2c_driver mt9v032_driver = { }, .probe = mt9v032_probe, .remove = mt9v032_remove, - .id_table = mt9v032_id, }; module_i2c_driver(mt9v032_driver); diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c index 723fe138e7bc..64a758c95ab7 100644 --- a/drivers/media/i2c/mt9v111.c +++ b/drivers/media/i2c/mt9v111.c @@ -365,8 +365,6 @@ static int __mt9v111_power_on(struct v4l2_subdev *sd) if (ret) return ret; - clk_set_rate(mt9v111->clk, mt9v111->sysclk); - gpiod_set_value(mt9v111->standby, 0); usleep_range(500, 1000); @@ -532,8 +530,8 @@ static int mt9v111_calc_frame_rate(struct mt9v111_dev *mt9v111, static int mt9v111_hw_config(struct mt9v111_dev *mt9v111) { struct i2c_client *c = mt9v111->client; - unsigned int ret; u16 outfmtctrl2; + int ret; /* Force device reset. */ ret = __mt9v111_hw_reset(mt9v111); @@ -1129,9 +1127,10 @@ static int mt9v111_probe(struct i2c_client *client) mt9v111->dev = &client->dev; mt9v111->client = client; - mt9v111->clk = devm_clk_get(&client->dev, NULL); + mt9v111->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9v111->clk)) - return PTR_ERR(mt9v111->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9v111->clk), + "failed to get the clock\n"); mt9v111->sysclk = clk_get_rate(mt9v111->clk); if (mt9v111->sysclk > MT9V111_MAX_CLKIN) @@ -1140,24 +1139,24 @@ static int mt9v111_probe(struct i2c_client *client) mt9v111->oe = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(mt9v111->oe)) { - dev_err(&client->dev, "Unable to get GPIO \"enable\": %ld\n", - PTR_ERR(mt9v111->oe)); + dev_err(&client->dev, "Unable to get GPIO \"enable\": %pe\n", + mt9v111->oe); return PTR_ERR(mt9v111->oe); } mt9v111->standby = devm_gpiod_get_optional(&client->dev, "standby", GPIOD_OUT_HIGH); if (IS_ERR(mt9v111->standby)) { - dev_err(&client->dev, "Unable to get GPIO \"standby\": %ld\n", - PTR_ERR(mt9v111->standby)); + dev_err(&client->dev, "Unable to get GPIO \"standby\": %pe\n", + mt9v111->standby); return PTR_ERR(mt9v111->standby); } mt9v111->reset = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(mt9v111->reset)) { - dev_err(&client->dev, "Unable to get GPIO \"reset\": %ld\n", - PTR_ERR(mt9v111->reset)); + dev_err(&client->dev, "Unable to get GPIO \"reset\": %pe\n", + mt9v111->reset); return PTR_ERR(mt9v111->reset); } diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c index 78d5d406e4b7..c7184de6251a 100644 --- a/drivers/media/i2c/og01a1b.c +++ b/drivers/media/i2c/og01a1b.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -10,6 +9,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -421,6 +422,7 @@ static const struct og01a1b_mode supported_modes[] = { }; struct og01a1b { + struct device *dev; struct clk *xvclk; struct gpio_desc *reset_gpio; struct regulator *avdd; @@ -512,7 +514,6 @@ static int og01a1b_write_reg(struct og01a1b *og01a1b, u16 reg, u16 len, u32 val) static int og01a1b_write_reg_list(struct og01a1b *og01a1b, const struct og01a1b_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); unsigned int i; int ret; @@ -520,7 +521,7 @@ static int og01a1b_write_reg_list(struct og01a1b *og01a1b, ret = og01a1b_write_reg(og01a1b, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(og01a1b->dev, "failed to write reg 0x%4.4x. error = %d", r_list->regs[i].address, ret); return ret; @@ -544,7 +545,6 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) { struct og01a1b *og01a1b = container_of(ctrl->handler, struct og01a1b, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); s64 exposure_max; int ret = 0; @@ -560,7 +560,7 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(og01a1b->dev)) return 0; switch (ctrl->id) { @@ -596,7 +596,7 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(og01a1b->dev); return ret; } @@ -682,13 +682,12 @@ static void og01a1b_update_pad_format(const struct og01a1b_mode *mode, { fmt->width = mode->width; fmt->height = mode->height; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->code = MEDIA_BUS_FMT_Y10_1X10; fmt->field = V4L2_FIELD_NONE; } static int og01a1b_start_streaming(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); const struct og01a1b_reg_list *reg_list; int link_freq_index, ret; @@ -697,14 +696,14 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) ret = og01a1b_write_reg_list(og01a1b, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(og01a1b->dev, "failed to set plls"); return ret; } reg_list = &og01a1b->cur_mode->reg_list; ret = og01a1b_write_reg_list(og01a1b, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(og01a1b->dev, "failed to set mode"); return ret; } @@ -716,7 +715,7 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) OG01A1B_REG_VALUE_08BIT, OG01A1B_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream"); + dev_err(og01a1b->dev, "failed to set stream"); return ret; } @@ -725,22 +724,19 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) static void og01a1b_stop_streaming(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); - if (og01a1b_write_reg(og01a1b, OG01A1B_REG_MODE_SELECT, OG01A1B_REG_VALUE_08BIT, OG01A1B_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream"); + dev_err(og01a1b->dev, "failed to set stream"); } static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) { struct og01a1b *og01a1b = to_og01a1b(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&og01a1b->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(og01a1b->dev); if (ret) { mutex_unlock(&og01a1b->mutex); return ret; @@ -750,11 +746,11 @@ static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; og01a1b_stop_streaming(og01a1b); - pm_runtime_put(&client->dev); + pm_runtime_put(og01a1b->dev); } } else { og01a1b_stop_streaming(og01a1b); - pm_runtime_put(&client->dev); + pm_runtime_put(og01a1b->dev); } mutex_unlock(&og01a1b->mutex); @@ -828,7 +824,7 @@ static int og01a1b_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + code->code = MEDIA_BUS_FMT_Y10_1X10; return 0; } @@ -840,7 +836,7 @@ static int og01a1b_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; - if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + if (fse->code != MEDIA_BUS_FMT_Y10_1X10) return -EINVAL; fse->min_width = supported_modes[fse->index].width; @@ -889,7 +885,6 @@ static const struct v4l2_subdev_internal_ops og01a1b_internal_ops = { static int og01a1b_identify_module(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); int ret; u32 val; @@ -899,7 +894,7 @@ static int og01a1b_identify_module(struct og01a1b *og01a1b) return ret; if (val != OG01A1B_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(og01a1b->dev, "chip id mismatch: %x!=%x", OG01A1B_CHIP_ID, val); return -ENXIO; } @@ -909,35 +904,18 @@ static int og01a1b_identify_module(struct og01a1b *og01a1b) static int og01a1b_check_hwcfg(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); - struct device *dev = &client->dev; + struct device *dev = og01a1b->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret; unsigned int i, j; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - if (!og01a1b->xvclk) { - dev_err(dev, "can't get clock frequency"); - return ret; - } - - mclk = clk_get_rate(og01a1b->xvclk); - } - - if (mclk != OG01A1B_MCLK) { - dev_err(dev, "external clock %d is not supported", mclk); - return -EINVAL; - } - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -1066,47 +1044,54 @@ static void og01a1b_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(og01a1b->dev); mutex_destroy(&og01a1b->mutex); } static int og01a1b_probe(struct i2c_client *client) { struct og01a1b *og01a1b; + unsigned long freq; int ret; og01a1b = devm_kzalloc(&client->dev, sizeof(*og01a1b), GFP_KERNEL); if (!og01a1b) return -ENOMEM; + og01a1b->dev = &client->dev; + v4l2_i2c_subdev_init(&og01a1b->sd, client, &og01a1b_subdev_ops); - og01a1b->xvclk = devm_clk_get_optional(&client->dev, NULL); - if (IS_ERR(og01a1b->xvclk)) { - ret = PTR_ERR(og01a1b->xvclk); - dev_err(&client->dev, "failed to get xvclk clock: %d\n", ret); - return ret; - } + og01a1b->xvclk = devm_v4l2_sensor_clk_get(og01a1b->dev, NULL); + if (IS_ERR(og01a1b->xvclk)) + return dev_err_probe(og01a1b->dev, PTR_ERR(og01a1b->xvclk), + "failed to get xvclk clock\n"); + + freq = clk_get_rate(og01a1b->xvclk); + if (freq != OG01A1B_MCLK) + return dev_err_probe(og01a1b->dev, -EINVAL, + "external clock %lu is not supported", + freq); ret = og01a1b_check_hwcfg(og01a1b); if (ret) { - dev_err(&client->dev, "failed to check HW configuration: %d", + dev_err(og01a1b->dev, "failed to check HW configuration: %d", ret); return ret; } - og01a1b->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + og01a1b->reset_gpio = devm_gpiod_get_optional(og01a1b->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(og01a1b->reset_gpio)) { - dev_err(&client->dev, "cannot get reset GPIO\n"); + dev_err(og01a1b->dev, "cannot get reset GPIO\n"); return PTR_ERR(og01a1b->reset_gpio); } - og01a1b->avdd = devm_regulator_get_optional(&client->dev, "avdd"); + og01a1b->avdd = devm_regulator_get_optional(og01a1b->dev, "avdd"); if (IS_ERR(og01a1b->avdd)) { ret = PTR_ERR(og01a1b->avdd); if (ret != -ENODEV) { - dev_err_probe(&client->dev, ret, + dev_err_probe(og01a1b->dev, ret, "Failed to get 'avdd' regulator\n"); return ret; } @@ -1114,11 +1099,11 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->avdd = NULL; } - og01a1b->dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); + og01a1b->dovdd = devm_regulator_get_optional(og01a1b->dev, "dovdd"); if (IS_ERR(og01a1b->dovdd)) { ret = PTR_ERR(og01a1b->dovdd); if (ret != -ENODEV) { - dev_err_probe(&client->dev, ret, + dev_err_probe(og01a1b->dev, ret, "Failed to get 'dovdd' regulator\n"); return ret; } @@ -1126,11 +1111,11 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->dovdd = NULL; } - og01a1b->dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); + og01a1b->dvdd = devm_regulator_get_optional(og01a1b->dev, "dvdd"); if (IS_ERR(og01a1b->dvdd)) { ret = PTR_ERR(og01a1b->dvdd); if (ret != -ENODEV) { - dev_err_probe(&client->dev, ret, + dev_err_probe(og01a1b->dev, ret, "Failed to get 'dvdd' regulator\n"); return ret; } @@ -1139,13 +1124,13 @@ static int og01a1b_probe(struct i2c_client *client) } /* The sensor must be powered on to read the CHIP_ID register */ - ret = og01a1b_power_on(&client->dev); + ret = og01a1b_power_on(og01a1b->dev); if (ret) return ret; ret = og01a1b_identify_module(og01a1b); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(og01a1b->dev, "failed to find sensor: %d", ret); goto power_off; } @@ -1153,7 +1138,7 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->cur_mode = &supported_modes[0]; ret = og01a1b_init_controls(og01a1b); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(og01a1b->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -1164,21 +1149,21 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&og01a1b->sd.entity, 1, &og01a1b->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(og01a1b->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&og01a1b->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(og01a1b->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } /* Enable runtime PM and turn off the device */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(og01a1b->dev); + pm_runtime_enable(og01a1b->dev); + pm_runtime_idle(og01a1b->dev); return 0; @@ -1190,7 +1175,7 @@ probe_error_v4l2_ctrl_handler_free: mutex_destroy(&og01a1b->mutex); power_off: - og01a1b_power_off(&client->dev); + og01a1b_power_off(og01a1b->dev); return ret; } diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c new file mode 100644 index 000000000000..262d9df766fe --- /dev/null +++ b/drivers/media/i2c/og0ve1b.c @@ -0,0 +1,816 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2024-2025 Linaro Ltd + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/units.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define OG0VE1B_LINK_FREQ_500MHZ (500 * HZ_PER_MHZ) +#define OG0VE1B_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ) + +#define OG0VE1B_REG_CHIP_ID CCI_REG24(0x300a) +#define OG0VE1B_CHIP_ID 0xc75645 + +#define OG0VE1B_REG_MODE_SELECT CCI_REG8(0x0100) +#define OG0VE1B_MODE_STANDBY 0x00 +#define OG0VE1B_MODE_STREAMING BIT(0) + +#define OG0VE1B_REG_SOFTWARE_RST CCI_REG8(0x0103) +#define OG0VE1B_SOFTWARE_RST BIT(0) + +/* Exposure controls from sensor */ +#define OG0VE1B_REG_EXPOSURE CCI_REG24(0x3500) +#define OG0VE1B_EXPOSURE_MIN 1 +#define OG0VE1B_EXPOSURE_MAX_MARGIN 14 +#define OG0VE1B_EXPOSURE_STEP 1 +#define OG0VE1B_EXPOSURE_DEFAULT 554 + +/* Analogue gain controls from sensor */ +#define OG0VE1B_REG_ANALOGUE_GAIN CCI_REG16(0x350a) +#define OG0VE1B_ANALOGUE_GAIN_MIN 1 +#define OG0VE1B_ANALOGUE_GAIN_MAX 0x1ff +#define OG0VE1B_ANALOGUE_GAIN_STEP 1 +#define OG0VE1B_ANALOGUE_GAIN_DEFAULT 16 + +/* Test pattern */ +#define OG0VE1B_REG_PRE_ISP CCI_REG8(0x5e00) +#define OG0VE1B_TEST_PATTERN_ENABLE BIT(7) + +#define to_og0ve1b(_sd) container_of(_sd, struct og0ve1b, sd) + +static const s64 og0ve1b_link_freq_menu[] = { + OG0VE1B_LINK_FREQ_500MHZ, +}; + +struct og0ve1b_reg_list { + const struct cci_reg_sequence *regs; + unsigned int num_regs; +}; + +struct og0ve1b_mode { + u32 width; /* Frame width in pixels */ + u32 height; /* Frame height in pixels */ + u32 hts; /* Horizontal timing size */ + u32 vts; /* Default vertical timing size */ + u32 bpp; /* Bits per pixel */ + + const struct og0ve1b_reg_list reg_list; /* Sensor register setting */ +}; + +static const char * const og0ve1b_test_pattern_menu[] = { + "Disabled", + "Vertical Colour Bars", +}; + +static const char * const og0ve1b_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OG0VE1B_NUM_SUPPLIES ARRAY_SIZE(og0ve1b_supply_names) + +struct og0ve1b { + struct device *dev; + struct regmap *regmap; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OG0VE1B_NUM_SUPPLIES]; + + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + + /* Saved register value */ + u64 pre_isp; +}; + +static const struct cci_reg_sequence og0ve1b_640x480_120fps_mode[] = { + { CCI_REG8(0x30a0), 0x02 }, + { CCI_REG8(0x30a1), 0x00 }, + { CCI_REG8(0x30a2), 0x48 }, + { CCI_REG8(0x30a3), 0x34 }, + { CCI_REG8(0x30a4), 0xf7 }, + { CCI_REG8(0x30a5), 0x00 }, + { CCI_REG8(0x3082), 0x32 }, + { CCI_REG8(0x3083), 0x01 }, + { CCI_REG8(0x301c), 0xf0 }, + { CCI_REG8(0x301e), 0x0b }, + { CCI_REG8(0x3106), 0x10 }, + { CCI_REG8(0x3708), 0x77 }, + { CCI_REG8(0x3709), 0xf8 }, + { CCI_REG8(0x3717), 0x00 }, + { CCI_REG8(0x3782), 0x00 }, + { CCI_REG8(0x3783), 0x47 }, + { CCI_REG8(0x37a2), 0x00 }, + { CCI_REG8(0x3503), 0x07 }, + { CCI_REG8(0x3509), 0x10 }, + { CCI_REG8(0x3600), 0x83 }, + { CCI_REG8(0x3601), 0x21 }, + { CCI_REG8(0x3602), 0xf1 }, + { CCI_REG8(0x360a), 0x18 }, + { CCI_REG8(0x360e), 0xb3 }, + { CCI_REG8(0x3613), 0x20 }, + { CCI_REG8(0x366a), 0x78 }, + { CCI_REG8(0x3706), 0x63 }, + { CCI_REG8(0x3713), 0x00 }, + { CCI_REG8(0x3716), 0xb0 }, + { CCI_REG8(0x37a1), 0x38 }, + { CCI_REG8(0x3800), 0x00 }, + { CCI_REG8(0x3801), 0x04 }, + { CCI_REG8(0x3802), 0x00 }, + { CCI_REG8(0x3803), 0x04 }, + { CCI_REG8(0x3804), 0x02 }, + { CCI_REG8(0x3805), 0x8b }, + { CCI_REG8(0x3806), 0x01 }, + { CCI_REG8(0x3807), 0xeb }, + { CCI_REG8(0x3808), 0x02 }, /* output width */ + { CCI_REG8(0x3809), 0x80 }, + { CCI_REG8(0x380a), 0x01 }, /* output height */ + { CCI_REG8(0x380b), 0xe0 }, + { CCI_REG8(0x380c), 0x03 }, /* horizontal timing size */ + { CCI_REG8(0x380d), 0x18 }, + { CCI_REG8(0x380e), 0x02 }, /* vertical timing size */ + { CCI_REG8(0x380f), 0x38 }, + { CCI_REG8(0x3811), 0x04 }, + { CCI_REG8(0x3813), 0x04 }, + { CCI_REG8(0x3814), 0x11 }, + { CCI_REG8(0x3815), 0x11 }, + { CCI_REG8(0x3820), 0x00 }, + { CCI_REG8(0x3821), 0x00 }, + { CCI_REG8(0x3823), 0x04 }, + { CCI_REG8(0x382a), 0x00 }, + { CCI_REG8(0x382b), 0x03 }, + { CCI_REG8(0x3840), 0x00 }, + { CCI_REG8(0x389e), 0x00 }, + { CCI_REG8(0x3c05), 0x08 }, + { CCI_REG8(0x3c26), 0x02 }, + { CCI_REG8(0x3c27), 0xc0 }, + { CCI_REG8(0x3c28), 0x00 }, + { CCI_REG8(0x3c29), 0x40 }, + { CCI_REG8(0x3c2c), 0x00 }, + { CCI_REG8(0x3c2d), 0x50 }, + { CCI_REG8(0x3c2e), 0x02 }, + { CCI_REG8(0x3c2f), 0x66 }, + { CCI_REG8(0x3c33), 0x08 }, + { CCI_REG8(0x3c35), 0x00 }, + { CCI_REG8(0x3c36), 0x00 }, + { CCI_REG8(0x3c37), 0x00 }, + { CCI_REG8(0x3f52), 0x9b }, + { CCI_REG8(0x4001), 0x42 }, + { CCI_REG8(0x4004), 0x08 }, + { CCI_REG8(0x4005), 0x00 }, + { CCI_REG8(0x4007), 0x28 }, + { CCI_REG8(0x4009), 0x40 }, + { CCI_REG8(0x4307), 0x30 }, + { CCI_REG8(0x4500), 0x80 }, + { CCI_REG8(0x4501), 0x02 }, + { CCI_REG8(0x4502), 0x47 }, + { CCI_REG8(0x4504), 0x7f }, + { CCI_REG8(0x4601), 0x48 }, + { CCI_REG8(0x4800), 0x64 }, + { CCI_REG8(0x4801), 0x0f }, + { CCI_REG8(0x4806), 0x2f }, + { CCI_REG8(0x4819), 0xaa }, + { CCI_REG8(0x4823), 0x3e }, + { CCI_REG8(0x5000), 0x85 }, + { CCI_REG8(0x5e00), 0x0c }, + { CCI_REG8(0x3899), 0x09 }, + { CCI_REG8(0x4f00), 0x64 }, + { CCI_REG8(0x4f02), 0x0a }, + { CCI_REG8(0x4f05), 0x0e }, + { CCI_REG8(0x4f06), 0x11 }, + { CCI_REG8(0x4f08), 0x0b }, + { CCI_REG8(0x4f0a), 0xc4 }, + { CCI_REG8(0x4f20), 0x1f }, + { CCI_REG8(0x4f25), 0x10 }, + { CCI_REG8(0x3016), 0x10 }, + { CCI_REG8(0x3017), 0x00 }, + { CCI_REG8(0x3018), 0x00 }, + { CCI_REG8(0x3019), 0x00 }, + { CCI_REG8(0x301a), 0x00 }, + { CCI_REG8(0x301b), 0x00 }, + { CCI_REG8(0x301c), 0x72 }, + { CCI_REG8(0x3037), 0x40 }, + { CCI_REG8(0x4f2c), 0x00 }, + { CCI_REG8(0x4f21), 0x00 }, + { CCI_REG8(0x4f23), 0x00 }, + { CCI_REG8(0x4f2a), 0x00 }, + { CCI_REG8(0x3665), 0xe7 }, + { CCI_REG8(0x3668), 0x48 }, + { CCI_REG8(0x3671), 0x3c }, + { CCI_REG8(0x389a), 0x02 }, + { CCI_REG8(0x389b), 0x00 }, + { CCI_REG8(0x303c), 0xa0 }, + { CCI_REG8(0x300f), 0xf0 }, + { CCI_REG8(0x304b), 0x0f }, + { CCI_REG8(0x3662), 0x24 }, + { CCI_REG8(0x3006), 0x40 }, + { CCI_REG8(0x4f26), 0x45 }, + { CCI_REG8(0x3607), 0x34 }, + { CCI_REG8(0x3608), 0x01 }, + { CCI_REG8(0x360a), 0x0c }, + { CCI_REG8(0x360b), 0x86 }, + { CCI_REG8(0x360c), 0xcc }, + { CCI_REG8(0x3013), 0x00 }, + { CCI_REG8(0x3083), 0x02 }, + { CCI_REG8(0x3084), 0x12 }, + { CCI_REG8(0x4601), 0x38 }, + { CCI_REG8(0x366f), 0x3a }, + { CCI_REG8(0x3713), 0x19 }, + { CCI_REG8(0x37a2), 0x00 }, + { CCI_REG8(0x3f43), 0x27 }, + { CCI_REG8(0x3f45), 0x27 }, + { CCI_REG8(0x3f47), 0x32 }, + { CCI_REG8(0x3f49), 0x3e }, + { CCI_REG8(0x3f4b), 0x20 }, + { CCI_REG8(0x3f4d), 0x30 }, + { CCI_REG8(0x4300), 0x3f }, + { CCI_REG8(0x4009), 0x10 }, + { CCI_REG8(0x3f02), 0x68 }, + { CCI_REG8(0x3700), 0x8c }, + { CCI_REG8(0x370b), 0x7e }, + { CCI_REG8(0x3f47), 0x35 }, +}; + +static const struct og0ve1b_mode supported_modes[] = { + { + .width = 640, + .height = 480, + .hts = 792, + .vts = 568, + .bpp = 8, + .reg_list = { + .regs = og0ve1b_640x480_120fps_mode, + .num_regs = ARRAY_SIZE(og0ve1b_640x480_120fps_mode), + }, + }, +}; + +static int og0ve1b_enable_test_pattern(struct og0ve1b *og0ve1b, u32 pattern) +{ + u64 val = og0ve1b->pre_isp; + + if (pattern) + val |= OG0VE1B_TEST_PATTERN_ENABLE; + else + val &= ~OG0VE1B_TEST_PATTERN_ENABLE; + + return cci_write(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, val, NULL); +} + +static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct og0ve1b *og0ve1b = container_of(ctrl->handler, struct og0ve1b, + ctrl_handler); + int ret; + + /* V4L2 controls are applied, when sensor is powered up for streaming */ + if (!pm_runtime_get_if_active(og0ve1b->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_ANALOGUE_GAIN, + ctrl->val, NULL); + break; + case V4L2_CID_EXPOSURE: + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_EXPOSURE, + ctrl->val << 4, NULL); + break; + case V4L2_CID_TEST_PATTERN: + ret = og0ve1b_enable_test_pattern(og0ve1b, ctrl->val); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(og0ve1b->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops og0ve1b_ctrl_ops = { + .s_ctrl = og0ve1b_set_ctrl, +}; + +static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &og0ve1b->ctrl_handler; + const struct og0ve1b_mode *mode = &supported_modes[0]; + struct v4l2_fwnode_device_properties props; + s64 exposure_max, pixel_rate, h_blank; + struct v4l2_ctrl *ctrl; + int ret; + + v4l2_ctrl_handler_init(ctrl_hdlr, 9); + + ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &og0ve1b_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(og0ve1b_link_freq_menu) - 1, + 0, og0ve1b_link_freq_menu); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + pixel_rate = og0ve1b_link_freq_menu[0] / mode->bpp; + v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_PIXEL_RATE, + 0, pixel_rate, 1, pixel_rate); + + h_blank = mode->hts - mode->width; + ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_VBLANK, + mode->vts - mode->height, + mode->vts - mode->height, 1, + mode->vts - mode->height); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OG0VE1B_ANALOGUE_GAIN_MIN, OG0VE1B_ANALOGUE_GAIN_MAX, + OG0VE1B_ANALOGUE_GAIN_STEP, + OG0VE1B_ANALOGUE_GAIN_DEFAULT); + + exposure_max = (mode->vts - OG0VE1B_EXPOSURE_MAX_MARGIN); + v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, + V4L2_CID_EXPOSURE, + OG0VE1B_EXPOSURE_MIN, exposure_max, + OG0VE1B_EXPOSURE_STEP, + OG0VE1B_EXPOSURE_DEFAULT); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &og0ve1b_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(og0ve1b_test_pattern_menu) - 1, + 0, 0, og0ve1b_test_pattern_menu); + + if (ctrl_hdlr->error) + return ctrl_hdlr->error; + + ret = v4l2_fwnode_device_parse(og0ve1b->dev, &props); + if (ret) + goto error_free_hdlr; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &og0ve1b_ctrl_ops, + &props); + if (ret) + goto error_free_hdlr; + + og0ve1b->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error_free_hdlr: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; +} + +static void og0ve1b_update_pad_format(const struct og0ve1b_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->code = MEDIA_BUS_FMT_Y8_1X8; + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_RAW; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_XFER_FUNC_NONE; +} + +static int og0ve1b_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + const struct og0ve1b_reg_list *reg_list = &supported_modes[0].reg_list; + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + int ret; + + ret = pm_runtime_resume_and_get(og0ve1b->dev); + if (ret) + return ret; + + /* Skip a step of explicit entering into the standby mode */ + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_SOFTWARE_RST, + OG0VE1B_SOFTWARE_RST, NULL); + if (ret) { + dev_err(og0ve1b->dev, "failed to software reset: %d\n", ret); + goto error; + } + + ret = cci_multi_reg_write(og0ve1b->regmap, reg_list->regs, + reg_list->num_regs, NULL); + if (ret) { + dev_err(og0ve1b->dev, "failed to set mode: %d\n", ret); + goto error; + } + + ret = __v4l2_ctrl_handler_setup(og0ve1b->sd.ctrl_handler); + if (ret) + goto error; + + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_MODE_SELECT, + OG0VE1B_MODE_STREAMING, NULL); + if (ret) { + dev_err(og0ve1b->dev, "failed to start streaming: %d\n", ret); + goto error; + } + + return 0; + +error: + pm_runtime_put_autosuspend(og0ve1b->dev); + + return ret; +} + +static int og0ve1b_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + int ret; + + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_MODE_SELECT, + OG0VE1B_MODE_STANDBY, NULL); + if (ret) + dev_err(og0ve1b->dev, "failed to stop streaming: %d\n", ret); + + pm_runtime_put_autosuspend(og0ve1b->dev); + + return ret; +} + +static int og0ve1b_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *format; + const struct og0ve1b_mode *mode; + + format = v4l2_subdev_state_get_format(state, 0); + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, + fmt->format.height); + + og0ve1b_update_pad_format(mode, &fmt->format); + *format = fmt->format; + + return 0; +} + +static int og0ve1b_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_Y8_1X8; + + return 0; +} + +static int og0ve1b_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_Y8_1X8) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int og0ve1b_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .pad = 0, + .format = { + .code = MEDIA_BUS_FMT_Y8_1X8, + .width = supported_modes[0].width, + .height = supported_modes[0].height, + }, + }; + + og0ve1b_set_pad_format(sd, state, &fmt); + + return 0; +} + +static const struct v4l2_subdev_video_ops og0ve1b_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops og0ve1b_pad_ops = { + .set_fmt = og0ve1b_set_pad_format, + .get_fmt = v4l2_subdev_get_fmt, + .enum_mbus_code = og0ve1b_enum_mbus_code, + .enum_frame_size = og0ve1b_enum_frame_size, + .enable_streams = og0ve1b_enable_streams, + .disable_streams = og0ve1b_disable_streams, +}; + +static const struct v4l2_subdev_ops og0ve1b_subdev_ops = { + .video = &og0ve1b_video_ops, + .pad = &og0ve1b_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops og0ve1b_internal_ops = { + .init_state = og0ve1b_init_state, +}; + +static const struct media_entity_operations og0ve1b_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int og0ve1b_identify_sensor(struct og0ve1b *og0ve1b) +{ + u64 val; + int ret; + + ret = cci_read(og0ve1b->regmap, OG0VE1B_REG_CHIP_ID, &val, NULL); + if (ret) { + dev_err(og0ve1b->dev, "failed to read chip id: %d\n", ret); + return ret; + } + + if (val != OG0VE1B_CHIP_ID) { + dev_err(og0ve1b->dev, "chip id mismatch: %x!=%llx\n", + OG0VE1B_CHIP_ID, val); + return -ENODEV; + } + + ret = cci_read(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, + &og0ve1b->pre_isp, NULL); + if (ret) + dev_err(og0ve1b->dev, "failed to read pre_isp: %d\n", ret); + + return ret; +} + +static int og0ve1b_check_hwcfg(struct og0ve1b *og0ve1b) +{ + struct fwnode_handle *fwnode = dev_fwnode(og0ve1b->dev), *ep; + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + unsigned long freq_bitmap; + int ret; + + if (!fwnode) + return -ENODEV; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -EINVAL; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + ret = v4l2_link_freq_to_bitmap(og0ve1b->dev, + bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + og0ve1b_link_freq_menu, + ARRAY_SIZE(og0ve1b_link_freq_menu), + &freq_bitmap); + + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int og0ve1b_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + int ret; + + ret = regulator_bulk_enable(OG0VE1B_NUM_SUPPLIES, og0ve1b->supplies); + if (ret) + return ret; + + gpiod_set_value_cansleep(og0ve1b->reset_gpio, 0); + usleep_range(10 * USEC_PER_MSEC, 15 * USEC_PER_MSEC); + + ret = clk_prepare_enable(og0ve1b->xvclk); + if (ret) + goto reset_gpio; + + return 0; + +reset_gpio: + gpiod_set_value_cansleep(og0ve1b->reset_gpio, 1); + + regulator_bulk_disable(OG0VE1B_NUM_SUPPLIES, og0ve1b->supplies); + + return ret; +} + +static int og0ve1b_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + + clk_disable_unprepare(og0ve1b->xvclk); + + gpiod_set_value_cansleep(og0ve1b->reset_gpio, 1); + + regulator_bulk_disable(OG0VE1B_NUM_SUPPLIES, og0ve1b->supplies); + + return 0; +} + +static int og0ve1b_probe(struct i2c_client *client) +{ + struct og0ve1b *og0ve1b; + unsigned long freq; + unsigned int i; + int ret; + + og0ve1b = devm_kzalloc(&client->dev, sizeof(*og0ve1b), GFP_KERNEL); + if (!og0ve1b) + return -ENOMEM; + + og0ve1b->dev = &client->dev; + + v4l2_i2c_subdev_init(&og0ve1b->sd, client, &og0ve1b_subdev_ops); + + og0ve1b->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(og0ve1b->regmap)) + return dev_err_probe(og0ve1b->dev, PTR_ERR(og0ve1b->regmap), + "failed to init CCI\n"); + + og0ve1b->xvclk = devm_v4l2_sensor_clk_get(og0ve1b->dev, NULL); + if (IS_ERR(og0ve1b->xvclk)) + return dev_err_probe(og0ve1b->dev, PTR_ERR(og0ve1b->xvclk), + "failed to get XVCLK clock\n"); + + freq = clk_get_rate(og0ve1b->xvclk); + if (freq && freq != OG0VE1B_MCLK_FREQ_24MHZ) + return dev_err_probe(og0ve1b->dev, -EINVAL, + "XVCLK clock frequency %lu is not supported\n", + freq); + + ret = og0ve1b_check_hwcfg(og0ve1b); + if (ret) + return dev_err_probe(og0ve1b->dev, ret, + "failed to check HW configuration\n"); + + og0ve1b->reset_gpio = devm_gpiod_get_optional(og0ve1b->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(og0ve1b->reset_gpio)) + return dev_err_probe(og0ve1b->dev, PTR_ERR(og0ve1b->reset_gpio), + "cannot get reset GPIO\n"); + + for (i = 0; i < OG0VE1B_NUM_SUPPLIES; i++) + og0ve1b->supplies[i].supply = og0ve1b_supply_names[i]; + + ret = devm_regulator_bulk_get(og0ve1b->dev, OG0VE1B_NUM_SUPPLIES, + og0ve1b->supplies); + if (ret) + return dev_err_probe(og0ve1b->dev, ret, + "failed to get supply regulators\n"); + + /* The sensor must be powered on to read the CHIP_ID register */ + ret = og0ve1b_power_on(og0ve1b->dev); + if (ret) + return ret; + + ret = og0ve1b_identify_sensor(og0ve1b); + if (ret) { + dev_err_probe(og0ve1b->dev, ret, "failed to find sensor\n"); + goto power_off; + } + + ret = og0ve1b_init_controls(og0ve1b); + if (ret) { + dev_err_probe(og0ve1b->dev, ret, "failed to init controls\n"); + goto power_off; + } + + og0ve1b->sd.state_lock = og0ve1b->ctrl_handler.lock; + og0ve1b->sd.internal_ops = &og0ve1b_internal_ops; + og0ve1b->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + og0ve1b->sd.entity.ops = &og0ve1b_subdev_entity_ops; + og0ve1b->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + og0ve1b->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&og0ve1b->sd.entity, 1, &og0ve1b->pad); + if (ret) { + dev_err_probe(og0ve1b->dev, ret, + "failed to init media entity pads\n"); + goto v4l2_ctrl_handler_free; + } + + ret = v4l2_subdev_init_finalize(&og0ve1b->sd); + if (ret < 0) { + dev_err_probe(og0ve1b->dev, ret, + "failed to init media entity pads\n"); + goto media_entity_cleanup; + } + + pm_runtime_set_active(og0ve1b->dev); + pm_runtime_enable(og0ve1b->dev); + + ret = v4l2_async_register_subdev_sensor(&og0ve1b->sd); + if (ret < 0) { + dev_err_probe(og0ve1b->dev, ret, + "failed to register V4L2 subdev\n"); + goto subdev_cleanup; + } + + /* Enable runtime PM and turn off the device */ + pm_runtime_idle(og0ve1b->dev); + pm_runtime_set_autosuspend_delay(og0ve1b->dev, 1000); + pm_runtime_use_autosuspend(og0ve1b->dev); + + return 0; + +subdev_cleanup: + v4l2_subdev_cleanup(&og0ve1b->sd); + pm_runtime_disable(og0ve1b->dev); + pm_runtime_set_suspended(og0ve1b->dev); + +media_entity_cleanup: + media_entity_cleanup(&og0ve1b->sd.entity); + +v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(og0ve1b->sd.ctrl_handler); + +power_off: + og0ve1b_power_off(og0ve1b->dev); + + return ret; +} + +static void og0ve1b_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(og0ve1b->dev); + + if (!pm_runtime_status_suspended(og0ve1b->dev)) { + og0ve1b_power_off(og0ve1b->dev); + pm_runtime_set_suspended(og0ve1b->dev); + } +} + +static const struct dev_pm_ops og0ve1b_pm_ops = { + SET_RUNTIME_PM_OPS(og0ve1b_power_off, og0ve1b_power_on, NULL) +}; + +static const struct of_device_id og0ve1b_of_match[] = { + { .compatible = "ovti,og0ve1b" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, og0ve1b_of_match); + +static struct i2c_driver og0ve1b_i2c_driver = { + .driver = { + .name = "og0ve1b", + .pm = &og0ve1b_pm_ops, + .of_match_table = og0ve1b_of_match, + }, + .probe = og0ve1b_probe, + .remove = og0ve1b_remove, +}; + +module_i2c_driver(og0ve1b_i2c_driver); + +MODULE_AUTHOR("Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>"); +MODULE_DESCRIPTION("OmniVision OG0VE1B sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 6c30e1a0d814..70d9d7c43f18 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -100,7 +100,8 @@ struct ov02a10_mode { }; struct ov02a10 { - u32 eclk_freq; + struct device *dev; + /* Indication of MIPI transmission speed select */ u32 mipi_clock_voltage; @@ -392,7 +393,7 @@ static int ov02a10_check_sensor_id(struct ov02a10 *ov02a10) chip_id = le16_to_cpu((__force __le16)ret); if ((chip_id & OV02A10_ID_MASK) != OV02A10_ID) { - dev_err(&client->dev, "unexpected sensor id(0x%04x)\n", chip_id); + dev_err(ov02a10->dev, "unexpected sensor id(0x%04x)\n", chip_id); return -EINVAL; } @@ -481,7 +482,7 @@ static int __ov02a10_start_stream(struct ov02a10 *ov02a10) ret = i2c_smbus_write_byte_data(client, REG_MIRROR_FLIP_CONTROL, REG_MIRROR_FLIP_ENABLE); if (ret < 0) { - dev_err(&client->dev, "failed to set orientation\n"); + dev_err(ov02a10->dev, "failed to set orientation\n"); return ret; } ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, @@ -530,7 +531,6 @@ static int ov02a10_init_state(struct v4l2_subdev *sd, static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) { struct ov02a10 *ov02a10 = to_ov02a10(sd); - struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); int ret; mutex_lock(&ov02a10->mutex); @@ -541,7 +541,7 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) } if (on) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov02a10->dev); if (ret < 0) goto unlock_and_return; @@ -553,7 +553,7 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) } } else { __ov02a10_stop_stream(ov02a10); - pm_runtime_put(&client->dev); + pm_runtime_put(ov02a10->dev); } ov02a10->streaming = on; @@ -562,7 +562,7 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) return 0; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(ov02a10->dev); unlock_and_return: mutex_unlock(&ov02a10->mutex); @@ -662,7 +662,6 @@ static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov02a10 *ov02a10 = container_of(ctrl->handler, struct ov02a10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); s64 max_expo; int ret; @@ -678,7 +677,7 @@ static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov02a10->dev)) return 0; switch (ctrl->id) { @@ -699,7 +698,7 @@ static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov02a10->dev); return ret; } @@ -734,7 +733,6 @@ static const struct v4l2_ctrl_ops ov02a10_ctrl_ops = { static int ov02a10_initialize_controls(struct ov02a10 *ov02a10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); const struct ov02a10_mode *mode; struct v4l2_ctrl_handler *handler; struct v4l2_ctrl *ctrl; @@ -790,7 +788,7 @@ static int ov02a10_initialize_controls(struct ov02a10 *ov02a10) if (handler->error) { ret = handler->error; - dev_err(&client->dev, "failed to init controls(%d)\n", ret); + dev_err(ov02a10->dev, "failed to init controls(%d)\n", ret); goto err_free_handler; } @@ -866,6 +864,8 @@ static int ov02a10_probe(struct i2c_client *client) if (!ov02a10) return -ENOMEM; + ov02a10->dev = dev; + ret = ov02a10_check_hwcfg(dev, ov02a10); if (ret) return dev_err_probe(dev, ret, @@ -885,22 +885,11 @@ static int ov02a10_probe(struct i2c_client *client) ov02a10->fmt.code = MEDIA_BUS_FMT_SRGGB10_1X10; } - ov02a10->eclk = devm_clk_get(dev, "eclk"); + ov02a10->eclk = devm_v4l2_sensor_clk_get_legacy(dev, "eclk", false, 0); if (IS_ERR(ov02a10->eclk)) return dev_err_probe(dev, PTR_ERR(ov02a10->eclk), "failed to get eclk\n"); - ret = device_property_read_u32(dev, "clock-frequency", - &ov02a10->eclk_freq); - if (ret < 0) - return dev_err_probe(dev, ret, - "failed to get eclk frequency\n"); - - ret = clk_set_rate(ov02a10->eclk, ov02a10->eclk_freq); - if (ret < 0) - return dev_err_probe(dev, ret, - "failed to set eclk frequency (24MHz)\n"); - if (clk_get_rate(ov02a10->eclk) != OV02A10_ECLK_FREQ) dev_warn(dev, "eclk mismatched, mode is based on 24MHz\n"); @@ -985,10 +974,10 @@ static void ov02a10_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - ov02a10_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov02a10->dev); + if (!pm_runtime_status_suspended(ov02a10->dev)) + ov02a10_power_off(ov02a10->dev); + pm_runtime_set_suspended(ov02a10->dev); mutex_destroy(&ov02a10->mutex); } diff --git a/drivers/media/i2c/ov02c10.c b/drivers/media/i2c/ov02c10.c index 089a4fd9627c..b1e540eb8326 100644 --- a/drivers/media/i2c/ov02c10.c +++ b/drivers/media/i2c/ov02c10.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> -#include <linux/version.h> #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -175,7 +174,7 @@ static const struct reg_sequence sensor_1928x1092_30fps_setting[] = { {0x3816, 0x01}, {0x3817, 0x01}, - {0x3820, 0xb0}, + {0x3820, 0xa0}, {0x3821, 0x00}, {0x3822, 0x80}, {0x3823, 0x08}, @@ -373,6 +372,8 @@ static const char * const ov02c10_supply_names[] = { }; struct ov02c10 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -384,6 +385,8 @@ struct ov02c10 { struct v4l2_ctrl *vblank; struct v4l2_ctrl *hblank; struct v4l2_ctrl *exposure; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; struct clk *img_clk; struct gpio_desc *reset; @@ -418,7 +421,6 @@ static int ov02c10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov02c10 *ov02c10 = container_of(ctrl->handler, struct ov02c10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov02c10->sd); const u32 height = supported_modes[0].height; s64 exposure_max; int ret = 0; @@ -434,7 +436,7 @@ static int ov02c10_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov02c10->dev)) return 0; switch (ctrl->id) { @@ -462,12 +464,22 @@ static int ov02c10_set_ctrl(struct v4l2_ctrl *ctrl) ret = ov02c10_test_pattern(ov02c10, ctrl->val); break; + case V4L2_CID_HFLIP: + cci_update_bits(ov02c10->regmap, OV02C10_ROTATE_CONTROL, + BIT(3), ov02c10->hflip->val << 3, &ret); + break; + + case V4L2_CID_VFLIP: + cci_update_bits(ov02c10->regmap, OV02C10_ROTATE_CONTROL, + BIT(4), ov02c10->vflip->val << 4, &ret); + break; + default: ret = -EINVAL; break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov02c10->dev); return ret; } @@ -478,7 +490,6 @@ static const struct v4l2_ctrl_ops ov02c10_ctrl_ops = { static int ov02c10_init_controls(struct ov02c10 *ov02c10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02c10->sd); struct v4l2_ctrl_handler *ctrl_hdlr = &ov02c10->ctrl_handler; const struct ov02c10_mode *mode = &supported_modes[0]; u32 vblank_min, vblank_max, vblank_default, vts_def; @@ -486,7 +497,7 @@ static int ov02c10_init_controls(struct ov02c10 *ov02c10) s64 exposure_max, h_blank, pixel_rate; int ret; - v4l2_ctrl_handler_init(ctrl_hdlr, 10); + v4l2_ctrl_handler_init(ctrl_hdlr, 12); ov02c10->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov02c10_ctrl_ops, @@ -537,12 +548,23 @@ static int ov02c10_init_controls(struct ov02c10 *ov02c10) exposure_max, OV02C10_EXPOSURE_STEP, exposure_max); + + ov02c10->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov02c10_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + if (ov02c10->hflip) + ov02c10->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + ov02c10->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov02c10_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + if (ov02c10->vflip) + ov02c10->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov02c10_ctrl_ops, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov02c10_test_pattern_menu) - 1, 0, 0, ov02c10_test_pattern_menu); - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov02c10->dev, &props); if (ret) return ret; @@ -570,12 +592,11 @@ static int ov02c10_enable_streams(struct v4l2_subdev *sd, u32 pad, u64 streams_mask) { const struct ov02c10_mode *mode = &supported_modes[0]; - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov02c10 *ov02c10 = to_ov02c10(sd); const struct reg_sequence *reg_sequence; int ret, sequence_length; - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov02c10->dev); if (ret) return ret; @@ -584,7 +605,7 @@ static int ov02c10_enable_streams(struct v4l2_subdev *sd, ret = regmap_multi_reg_write(ov02c10->regmap, reg_sequence, sequence_length); if (ret) { - dev_err(&client->dev, "failed to set mode\n"); + dev_err(ov02c10->dev, "failed to set mode\n"); goto out; } @@ -593,7 +614,7 @@ static int ov02c10_enable_streams(struct v4l2_subdev *sd, ret = regmap_multi_reg_write(ov02c10->regmap, reg_sequence, sequence_length); if (ret) { - dev_err(&client->dev, "failed to write lane settings\n"); + dev_err(ov02c10->dev, "failed to write lane settings\n"); goto out; } @@ -604,7 +625,7 @@ static int ov02c10_enable_streams(struct v4l2_subdev *sd, ret = cci_write(ov02c10->regmap, OV02C10_REG_STREAM_CONTROL, 1, NULL); out: if (ret) - pm_runtime_put(&client->dev); + pm_runtime_put(ov02c10->dev); return ret; } @@ -613,11 +634,10 @@ static int ov02c10_disable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov02c10 *ov02c10 = to_ov02c10(sd); cci_write(ov02c10->regmap, OV02C10_REG_STREAM_CONTROL, 0, NULL); - pm_runtime_put(&client->dev); + pm_runtime_put(ov02c10->dev); return 0; } @@ -778,7 +798,6 @@ static const struct v4l2_subdev_internal_ops ov02c10_internal_ops = { static int ov02c10_identify_module(struct ov02c10 *ov02c10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02c10->sd); u64 chip_id; int ret; @@ -787,7 +806,7 @@ static int ov02c10_identify_module(struct ov02c10 *ov02c10) return ret; if (chip_id != OV02C10_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%llx", + dev_err(ov02c10->dev, "chip id mismatch: %x!=%llx", OV02C10_CHIP_ID, chip_id); return -ENXIO; } @@ -795,14 +814,14 @@ static int ov02c10_identify_module(struct ov02c10 *ov02c10) return 0; } -static int ov02c10_check_hwcfg(struct device *dev, struct ov02c10 *ov02c10) +static int ov02c10_check_hwcfg(struct ov02c10 *ov02c10) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct device *dev = ov02c10->dev; struct fwnode_handle *ep, *fwnode = dev_fwnode(dev); unsigned long link_freq_bitmap; - u32 mclk; int ret; /* @@ -814,31 +833,6 @@ static int ov02c10_check_hwcfg(struct device *dev, struct ov02c10 *ov02c10) return dev_err_probe(dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n"); - ov02c10->img_clk = devm_clk_get_optional(dev, NULL); - if (IS_ERR(ov02c10->img_clk)) { - fwnode_handle_put(ep); - return dev_err_probe(dev, PTR_ERR(ov02c10->img_clk), - "failed to get imaging clock\n"); - } - - if (ov02c10->img_clk) { - mclk = clk_get_rate(ov02c10->img_clk); - } else { - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - fwnode_handle_put(ep); - return dev_err_probe(dev, ret, - "reading clock-frequency property\n"); - } - } - - if (mclk != OV02C10_MCLK) { - fwnode_handle_put(ep); - return dev_err_probe(dev, -EINVAL, - "external clock %u is not supported\n", - mclk); - } - ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); if (ret) @@ -873,35 +867,50 @@ check_hwcfg_error: static void ov02c10_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov02c10 *ov02c10 = to_ov02c10(sd); v4l2_async_unregister_subdev(sd); v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) { - ov02c10_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov02c10->dev); + if (!pm_runtime_status_suspended(ov02c10->dev)) { + ov02c10_power_off(ov02c10->dev); + pm_runtime_set_suspended(ov02c10->dev); } } static int ov02c10_probe(struct i2c_client *client) { struct ov02c10 *ov02c10; + unsigned long freq; int ret; ov02c10 = devm_kzalloc(&client->dev, sizeof(*ov02c10), GFP_KERNEL); if (!ov02c10) return -ENOMEM; + ov02c10->dev = &client->dev; + + ov02c10->img_clk = devm_v4l2_sensor_clk_get(ov02c10->dev, NULL); + if (IS_ERR(ov02c10->img_clk)) + return dev_err_probe(ov02c10->dev, PTR_ERR(ov02c10->img_clk), + "failed to get imaging clock\n"); + + freq = clk_get_rate(ov02c10->img_clk); + if (freq != OV02C10_MCLK) + return dev_err_probe(ov02c10->dev, -EINVAL, + "external clock %lu is not supported", + freq); + v4l2_i2c_subdev_init(&ov02c10->sd, client, &ov02c10_subdev_ops); /* Check HW config */ - ret = ov02c10_check_hwcfg(&client->dev, ov02c10); + ret = ov02c10_check_hwcfg(ov02c10); if (ret) return ret; - ret = ov02c10_get_pm_resources(&client->dev); + ret = ov02c10_get_pm_resources(ov02c10->dev); if (ret) return ret; @@ -909,21 +918,21 @@ static int ov02c10_probe(struct i2c_client *client) if (IS_ERR(ov02c10->regmap)) return PTR_ERR(ov02c10->regmap); - ret = ov02c10_power_on(&client->dev); + ret = ov02c10_power_on(ov02c10->dev); if (ret) { - dev_err_probe(&client->dev, ret, "failed to power on\n"); + dev_err_probe(ov02c10->dev, ret, "failed to power on\n"); return ret; } ret = ov02c10_identify_module(ov02c10); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov02c10->dev, "failed to find sensor: %d", ret); goto probe_error_power_off; } ret = ov02c10_init_controls(ov02c10); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov02c10->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -934,33 +943,33 @@ static int ov02c10_probe(struct i2c_client *client) ov02c10->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov02c10->sd.entity, 1, &ov02c10->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov02c10->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ov02c10->sd.state_lock = ov02c10->ctrl_handler.lock; ret = v4l2_subdev_init_finalize(&ov02c10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to init subdev: %d", ret); + dev_err(ov02c10->dev, "failed to init subdev: %d", ret); goto probe_error_media_entity_cleanup; } - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_active(ov02c10->dev); + pm_runtime_enable(ov02c10->dev); ret = v4l2_async_register_subdev_sensor(&ov02c10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov02c10->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_v4l2_subdev_cleanup; } - pm_runtime_idle(&client->dev); + pm_runtime_idle(ov02c10->dev); return 0; probe_error_v4l2_subdev_cleanup: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov02c10->dev); + pm_runtime_set_suspended(ov02c10->dev); v4l2_subdev_cleanup(&ov02c10->sd); probe_error_media_entity_cleanup: @@ -970,7 +979,7 @@ probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov02c10->sd.ctrl_handler); probe_error_power_off: - ov02c10_power_off(&client->dev); + ov02c10_power_off(ov02c10->dev); return ret; } diff --git a/drivers/media/i2c/ov02e10.c b/drivers/media/i2c/ov02e10.c index d74dc62e189d..4a64cba99991 100644 --- a/drivers/media/i2c/ov02e10.c +++ b/drivers/media/i2c/ov02e10.c @@ -226,6 +226,8 @@ static const char * const ov02e10_supply_names[] = { }; struct ov02e10 { + struct device *dev; + struct regmap *regmap; struct v4l2_subdev sd; struct media_pad pad; @@ -288,7 +290,6 @@ static int ov02e10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov02e10 *ov02e10 = container_of(ctrl->handler, struct ov02e10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov02e10->sd); s64 exposure_max; int ret; @@ -307,7 +308,7 @@ static int ov02e10_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov02e10->dev)) return 0; ret = cci_write(ov02e10->regmap, OV02E10_REG_COMMAND_UPDATE, @@ -363,7 +364,7 @@ static int ov02e10_set_ctrl(struct v4l2_ctrl *ctrl) cci_write(ov02e10->regmap, OV02E10_REG_COMMAND_UPDATE, OV02E10_COMMAND_UPDATE, &ret); - pm_runtime_put(&client->dev); + pm_runtime_put(ov02e10->dev); return ret; } @@ -374,7 +375,6 @@ static const struct v4l2_ctrl_ops ov02e10_ctrl_ops = { static int ov02e10_init_controls(struct ov02e10 *ov02e10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02e10->sd); struct v4l2_ctrl_handler *ctrl_hdlr = &ov02e10->ctrl_handler; const struct ov02e10_mode *mode = ov02e10->cur_mode; u32 vblank_min, vblank_max, vblank_def; @@ -442,7 +442,7 @@ static int ov02e10_init_controls(struct ov02e10 *ov02e10) ARRAY_SIZE(ov02e10_test_pattern_menu) - 1, 0, 0, ov02e10_test_pattern_menu); - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov02e10->dev, &props); if (ret) return ret; @@ -481,12 +481,11 @@ static int ov02e10_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov02e10 *ov02e10 = to_ov02e10(sd); const struct reg_sequence_list *reg_list; int ret; - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov02e10->dev); if (ret) return ret; @@ -494,7 +493,7 @@ static int ov02e10_enable_streams(struct v4l2_subdev *sd, ret = regmap_multi_reg_write(ov02e10->regmap, reg_list->regs, reg_list->num_regs); if (ret) { - dev_err(&client->dev, "failed to set mode\n"); + dev_err(ov02e10->dev, "failed to set mode\n"); goto out; } @@ -506,7 +505,7 @@ static int ov02e10_enable_streams(struct v4l2_subdev *sd, out: if (ret) - pm_runtime_put(&client->dev); + pm_runtime_put(ov02e10->dev); return ret; } @@ -515,11 +514,10 @@ static int ov02e10_disable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov02e10 *ov02e10 = to_ov02e10(sd); ov02e10_set_stream_mode(ov02e10, 0); - pm_runtime_put(&client->dev); + pm_runtime_put(ov02e10->dev); return 0; } @@ -724,7 +722,6 @@ static const struct v4l2_subdev_internal_ops ov02e10_internal_ops = { static int ov02e10_identify_module(struct ov02e10 *ov02e10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02e10->sd); int ret; u64 val; @@ -735,7 +732,7 @@ static int ov02e10_identify_module(struct ov02e10 *ov02e10) return ret; if (val != OV02E10_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov02e10->dev, "chip id mismatch: %x!=%x\n", OV02E10_CHIP_ID, (u32)val); return -ENXIO; } @@ -743,15 +740,15 @@ static int ov02e10_identify_module(struct ov02e10 *ov02e10) return 0; } -static int ov02e10_check_hwcfg(struct device *dev, struct ov02e10 *ov02e10) +static int ov02e10_check_hwcfg(struct ov02e10 *ov02e10) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct device *dev = ov02e10->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); unsigned long link_freq_bitmap; - u32 ext_clk; int ret; ep = fwnode_graph_get_next_endpoint(fwnode, NULL); @@ -764,31 +761,6 @@ static int ov02e10_check_hwcfg(struct device *dev, struct ov02e10 *ov02e10) if (ret) return dev_err_probe(dev, ret, "parsing endpoint failed\n"); - ov02e10->img_clk = devm_clk_get_optional(dev, NULL); - if (IS_ERR(ov02e10->img_clk)) { - ret = dev_err_probe(dev, PTR_ERR(ov02e10->img_clk), - "failed to get imaging clock\n"); - goto out_err; - } - - if (ov02e10->img_clk) { - ext_clk = clk_get_rate(ov02e10->img_clk); - } else { - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &ext_clk); - if (ret) { - dev_err(dev, "can't get clock frequency\n"); - goto out_err; - } - } - - if (ext_clk != OV02E10_MCLK) { - dev_err(dev, "external clock %d is not supported\n", - ext_clk); - ret = -EINVAL; - goto out_err; - } - if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV02E10_DATA_LANES) { dev_err(dev, "number of CSI2 data lanes %d is not supported\n", bus_cfg.bus.mipi_csi2.num_data_lanes); @@ -823,32 +795,47 @@ out_err: static void ov02e10_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov02e10 *ov02e10 = to_ov02e10(sd); v4l2_async_unregister_subdev(sd); v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov02e10->dev); - if (!pm_runtime_status_suspended(&client->dev)) { - ov02e10_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + if (!pm_runtime_status_suspended(ov02e10->dev)) { + ov02e10_power_off(ov02e10->dev); + pm_runtime_set_suspended(ov02e10->dev); } } static int ov02e10_probe(struct i2c_client *client) { struct ov02e10 *ov02e10; + unsigned long freq; int ret; ov02e10 = devm_kzalloc(&client->dev, sizeof(*ov02e10), GFP_KERNEL); if (!ov02e10) return -ENOMEM; + ov02e10->dev = &client->dev; + + ov02e10->img_clk = devm_v4l2_sensor_clk_get(ov02e10->dev, NULL); + if (IS_ERR(ov02e10->img_clk)) + return dev_err_probe(ov02e10->dev, PTR_ERR(ov02e10->img_clk), + "failed to get imaging clock\n"); + + freq = clk_get_rate(ov02e10->img_clk); + if (freq != OV02E10_MCLK) + return dev_err_probe(ov02e10->dev, -EINVAL, + "external clock %lu is not supported", + freq); + v4l2_i2c_subdev_init(&ov02e10->sd, client, &ov02e10_subdev_ops); /* Check HW config */ - ret = ov02e10_check_hwcfg(&client->dev, ov02e10); + ret = ov02e10_check_hwcfg(ov02e10); if (ret) return ret; @@ -857,27 +844,27 @@ static int ov02e10_probe(struct i2c_client *client) if (IS_ERR(ov02e10->regmap)) return PTR_ERR(ov02e10->regmap); - ret = ov02e10_get_pm_resources(&client->dev); + ret = ov02e10_get_pm_resources(ov02e10->dev); if (ret) return ret; - ret = ov02e10_power_on(&client->dev); + ret = ov02e10_power_on(ov02e10->dev); if (ret) { - dev_err_probe(&client->dev, ret, "failed to power on\n"); + dev_err_probe(ov02e10->dev, ret, "failed to power on\n"); return ret; } /* Check module identity */ ret = ov02e10_identify_module(ov02e10); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); + dev_err(ov02e10->dev, "failed to find sensor: %d\n", ret); goto probe_error_power_off; } ov02e10->cur_mode = &supported_modes[0]; ret = ov02e10_init_controls(ov02e10); if (ret) { - dev_err(&client->dev, "failed to init controls: %d\n", ret); + dev_err(ov02e10->dev, "failed to init controls: %d\n", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -891,33 +878,33 @@ static int ov02e10_probe(struct i2c_client *client) ov02e10->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov02e10->sd.entity, 1, &ov02e10->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov02e10->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ov02e10->sd.state_lock = ov02e10->ctrl_handler.lock; ret = v4l2_subdev_init_finalize(&ov02e10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to init subdev: %d", ret); + dev_err(ov02e10->dev, "failed to init subdev: %d", ret); goto probe_error_media_entity_cleanup; } - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_active(ov02e10->dev); + pm_runtime_enable(ov02e10->dev); ret = v4l2_async_register_subdev_sensor(&ov02e10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov02e10->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_v4l2_subdev_cleanup; } - pm_runtime_idle(&client->dev); + pm_runtime_idle(ov02e10->dev); return 0; probe_error_v4l2_subdev_cleanup: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov02e10->dev); + pm_runtime_set_suspended(ov02e10->dev); v4l2_subdev_cleanup(&ov02e10->sd); probe_error_media_entity_cleanup: @@ -927,7 +914,7 @@ probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov02e10->sd.ctrl_handler); probe_error_power_off: - ov02e10_power_off(&client->dev); + ov02e10_power_off(ov02e10->dev); return ret; } @@ -961,7 +948,7 @@ static struct i2c_driver ov02e10_i2c_driver = { module_i2c_driver(ov02e10_i2c_driver); -MODULE_AUTHOR("Jingjing Xiong <jingjing.xiong@intel.com>"); +MODULE_AUTHOR("Jingjing Xiong"); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_AUTHOR("Alan Stern <stern@rowland.harvard.edu>"); MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linaro.org>"); diff --git a/drivers/media/i2c/ov08d10.c b/drivers/media/i2c/ov08d10.c index 1bacbdfa4298..43ec2a1f2fcf 100644 --- a/drivers/media/i2c/ov08d10.c +++ b/drivers/media/i2c/ov08d10.c @@ -515,12 +515,13 @@ static const char * const ov08d10_test_pattern_menu[] = { }; struct ov08d10 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; - struct clk *xvclk; - /* V4L2 Controls */ struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate; @@ -663,7 +664,7 @@ static int ov08d10_write_reg_list(struct ov08d10 *ov08d10, ret = i2c_smbus_write_byte_data(client, r_list->regs[i].address, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov08d10->dev, "failed to write reg 0x%2.2x. error = %d", r_list->regs[i].address, ret); return ret; @@ -849,7 +850,6 @@ static int ov08d10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov08d10 *ov08d10 = container_of(ctrl->handler, struct ov08d10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov08d10->sd); s64 exposure_max; int ret; @@ -865,7 +865,7 @@ static int ov08d10_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov08d10->dev)) return 0; switch (ctrl->id) { @@ -901,7 +901,7 @@ static int ov08d10_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov08d10->dev); return ret; } @@ -1025,32 +1025,32 @@ static int ov08d10_start_streaming(struct ov08d10 *ov08d10) /* soft reset */ ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, 0x00); if (ret < 0) { - dev_err(&client->dev, "failed to reset sensor"); + dev_err(ov08d10->dev, "failed to reset sensor"); return ret; } ret = i2c_smbus_write_byte_data(client, 0x20, 0x0e); if (ret < 0) { - dev_err(&client->dev, "failed to reset sensor"); + dev_err(ov08d10->dev, "failed to reset sensor"); return ret; } usleep_range(3000, 4000); ret = i2c_smbus_write_byte_data(client, 0x20, 0x0b); if (ret < 0) { - dev_err(&client->dev, "failed to reset sensor"); + dev_err(ov08d10->dev, "failed to reset sensor"); return ret; } /* update sensor setting */ ret = ov08d10_write_reg_list(ov08d10, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(ov08d10->dev, "failed to set plls"); return ret; } reg_list = &ov08d10->cur_mode->reg_list; ret = ov08d10_write_reg_list(ov08d10, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(ov08d10->dev, "failed to set mode"); return ret; } @@ -1077,19 +1077,19 @@ static void ov08d10_stop_streaming(struct ov08d10 *ov08d10) ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, 0x00); if (ret < 0) { - dev_err(&client->dev, "failed to stop streaming"); + dev_err(ov08d10->dev, "failed to stop streaming"); return; } ret = i2c_smbus_write_byte_data(client, OV08D10_REG_MODE_SELECT, OV08D10_MODE_STANDBY); if (ret < 0) { - dev_err(&client->dev, "failed to stop streaming"); + dev_err(ov08d10->dev, "failed to stop streaming"); return; } ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, 0x01); if (ret < 0) { - dev_err(&client->dev, "failed to stop streaming"); + dev_err(ov08d10->dev, "failed to stop streaming"); return; } } @@ -1097,12 +1097,11 @@ static void ov08d10_stop_streaming(struct ov08d10 *ov08d10) static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) { struct ov08d10 *ov08d10 = to_ov08d10(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov08d10->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov08d10->dev); if (ret < 0) { mutex_unlock(&ov08d10->mutex); return ret; @@ -1112,11 +1111,11 @@ static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov08d10_stop_streaming(ov08d10); - pm_runtime_put(&client->dev); + pm_runtime_put(ov08d10->dev); } } else { ov08d10_stop_streaming(ov08d10); - pm_runtime_put(&client->dev); + pm_runtime_put(ov08d10->dev); } /* vflip and hflip cannot change during streaming */ @@ -1293,7 +1292,7 @@ static int ov08d10_identify_module(struct ov08d10 *ov08d10) chip_id = val | ret; if ((chip_id & OV08D10_ID_MASK) != OV08D10_CHIP_ID) { - dev_err(&client->dev, "unexpected sensor id(0x%04x)\n", + dev_err(ov08d10->dev, "unexpected sensor id(0x%04x)\n", chip_id); return -EINVAL; } @@ -1301,28 +1300,20 @@ static int ov08d10_identify_module(struct ov08d10 *ov08d10) return 0; } -static int ov08d10_get_hwcfg(struct ov08d10 *ov08d10, struct device *dev) +static int ov08d10_get_hwcfg(struct ov08d10 *ov08d10) { + struct device *dev = ov08d10->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 xvclk_rate; unsigned int i, j; int ret; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &xvclk_rate); - if (ret) - return ret; - - if (xvclk_rate != OV08D10_XVCLK_19_2) - dev_warn(dev, "external clock rate %u is unsupported", - xvclk_rate); - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -1380,22 +1371,35 @@ static void ov08d10_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov08d10->dev); mutex_destroy(&ov08d10->mutex); } static int ov08d10_probe(struct i2c_client *client) { struct ov08d10 *ov08d10; + unsigned long freq; int ret; ov08d10 = devm_kzalloc(&client->dev, sizeof(*ov08d10), GFP_KERNEL); if (!ov08d10) return -ENOMEM; - ret = ov08d10_get_hwcfg(ov08d10, &client->dev); + ov08d10->dev = &client->dev; + + ov08d10->clk = devm_v4l2_sensor_clk_get(ov08d10->dev, NULL); + if (IS_ERR(ov08d10->clk)) + return dev_err_probe(ov08d10->dev, PTR_ERR(ov08d10->clk), + "failed to get clock\n"); + + freq = clk_get_rate(ov08d10->clk); + if (freq != OV08D10_XVCLK_19_2) + dev_warn(ov08d10->dev, + "external clock rate %lu is not supported\n", freq); + + ret = ov08d10_get_hwcfg(ov08d10); if (ret) { - dev_err(&client->dev, "failed to get HW configuration: %d", + dev_err(ov08d10->dev, "failed to get HW configuration: %d", ret); return ret; } @@ -1404,7 +1408,7 @@ static int ov08d10_probe(struct i2c_client *client) ret = ov08d10_identify_module(ov08d10); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov08d10->dev, "failed to find sensor: %d", ret); return ret; } @@ -1412,7 +1416,7 @@ static int ov08d10_probe(struct i2c_client *client) ov08d10->cur_mode = &ov08d10->priv_lane->sp_modes[0]; ret = ov08d10_init_controls(ov08d10); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov08d10->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -1422,13 +1426,13 @@ static int ov08d10_probe(struct i2c_client *client) ov08d10->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov08d10->sd.entity, 1, &ov08d10->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov08d10->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&ov08d10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov08d10->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } @@ -1437,9 +1441,9 @@ static int ov08d10_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov08d10->dev); + pm_runtime_enable(ov08d10->dev); + pm_runtime_idle(ov08d10->dev); return 0; diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index e0094305ca2a..5eaf454f4763 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -1,15 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> -#include <linux/i2c.h> +#include <linux/delay.h> #include <linux/gpio/consumer.h> +#include <linux/i2c.h> #include <linux/module.h> -#include <linux/delay.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -1305,6 +1306,8 @@ static const char * const ov08x40_supply_names[] = { }; struct ov08x40 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; @@ -1513,7 +1516,6 @@ static int ov08x40_write_reg(struct ov08x40 *ov08x, static int ov08x40_write_regs(struct ov08x40 *ov08x, const struct ov08x40_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); int ret; u32 i; @@ -1522,7 +1524,7 @@ static int ov08x40_write_regs(struct ov08x40 *ov08x, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov08x->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -1648,7 +1650,7 @@ static int ov08x40_set_ctrl_hflip(struct ov08x40 *ov08x, u32 ctrl_val) return ov08x40_write_reg(ov08x, OV08X40_REG_MIRROR, OV08X40_REG_VALUE_08BIT, - ctrl_val ? val | BIT(2) : val & ~BIT(2)); + ctrl_val ? val & ~BIT(2) : val | BIT(2)); } static int ov08x40_set_ctrl_vflip(struct ov08x40 *ov08x, u32 ctrl_val) @@ -1670,7 +1672,6 @@ static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov08x40 *ov08x = container_of(ctrl->handler, struct ov08x40, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); s64 max; int exp; int fll; @@ -1699,7 +1700,7 @@ static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov08x->dev)) return 0; switch (ctrl->id) { @@ -1737,13 +1738,13 @@ static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl) ov08x40_set_ctrl_vflip(ov08x, ctrl->val); break; default: - dev_info(&client->dev, + dev_info(ov08x->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov08x->dev); return ret; } @@ -1912,7 +1913,6 @@ ov08x40_set_pad_format(struct v4l2_subdev *sd, static int ov08x40_start_streaming(struct ov08x40 *ov08x) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); const struct ov08x40_reg_list *reg_list; int ret, link_freq_index; @@ -1920,7 +1920,7 @@ static int ov08x40_start_streaming(struct ov08x40 *ov08x) ret = ov08x40_write_reg(ov08x, OV08X40_REG_SOFTWARE_RST, OV08X40_REG_VALUE_08BIT, OV08X40_SOFTWARE_RST); if (ret) { - dev_err(&client->dev, "%s failed to set powerup registers\n", + dev_err(ov08x->dev, "%s failed to set powerup registers\n", __func__); return ret; } @@ -1930,14 +1930,14 @@ static int ov08x40_start_streaming(struct ov08x40 *ov08x) ret = ov08x40_write_reg_list(ov08x, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(ov08x->dev, "%s failed to set plls\n", __func__); return ret; } reg_list = &ov08x40_global_setting; ret = ov08x40_write_reg_list(ov08x, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set global setting\n", + dev_err(ov08x->dev, "%s failed to set global setting\n", __func__); return ret; } @@ -1946,7 +1946,7 @@ static int ov08x40_start_streaming(struct ov08x40 *ov08x) reg_list = &ov08x->cur_mode->reg_list; ret = ov08x40_write_reg_list(ov08x, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(ov08x->dev, "%s failed to set mode\n", __func__); return ret; } @@ -1962,7 +1962,7 @@ static int ov08x40_start_streaming(struct ov08x40 *ov08x) } if (ret) { - dev_err(&client->dev, "%s failed to set regs\n", __func__); + dev_err(ov08x->dev, "%s failed to set regs\n", __func__); return ret; } @@ -1986,7 +1986,6 @@ static int ov08x40_stop_streaming(struct ov08x40 *ov08x) /* Verify chip ID */ static int ov08x40_identify_module(struct ov08x40 *ov08x) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); int ret; u32 val; @@ -1996,17 +1995,17 @@ static int ov08x40_identify_module(struct ov08x40 *ov08x) ret = ov08x40_read_reg(ov08x, OV08X40_REG_CHIP_ID, OV08X40_REG_VALUE_24BIT, &val); if (ret) { - dev_err(&client->dev, "error reading chip-id register: %d\n", ret); + dev_err(ov08x->dev, "error reading chip-id register: %d\n", ret); return ret; } if (val != OV08X40_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov08x->dev, "chip id mismatch: %x!=%x\n", OV08X40_CHIP_ID, val); return -ENXIO; } - dev_dbg(&client->dev, "chip id 0x%x\n", val); + dev_dbg(ov08x->dev, "chip id 0x%x\n", val); ov08x->identified = true; return 0; @@ -2015,13 +2014,12 @@ static int ov08x40_identify_module(struct ov08x40 *ov08x) static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) { struct ov08x40 *ov08x = to_ov08x40(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov08x->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov08x->dev); if (ret < 0) goto err_unlock; @@ -2038,7 +2036,7 @@ static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { ov08x40_stop_streaming(ov08x); - pm_runtime_put(&client->dev); + pm_runtime_put(ov08x->dev); } mutex_unlock(&ov08x->mutex); @@ -2046,7 +2044,7 @@ static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(ov08x->dev); err_unlock: mutex_unlock(&ov08x->mutex); @@ -2079,7 +2077,6 @@ static const struct v4l2_subdev_internal_ops ov08x40_internal_ops = { static int ov08x40_init_controls(struct ov08x40 *ov08x) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; @@ -2160,12 +2157,12 @@ static int ov08x40_init_controls(struct ov08x40 *ov08x) if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(ov08x->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov08x->dev, &props); if (ret) goto error; @@ -2191,11 +2188,12 @@ static void ov08x40_free_controls(struct ov08x40 *ov08x) mutex_destroy(&ov08x->mutex); } -static int ov08x40_check_hwcfg(struct ov08x40 *ov08x, struct device *dev) +static int ov08x40_check_hwcfg(struct ov08x40 *ov08x) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct device *dev = ov08x->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); unsigned int i; @@ -2232,23 +2230,14 @@ static int ov08x40_check_hwcfg(struct ov08x40 *ov08x, struct device *dev) if (ret) goto out_err; - ov08x->xvclk = devm_clk_get_optional(dev, NULL); + ov08x->xvclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(ov08x->xvclk)) { ret = dev_err_probe(dev, PTR_ERR(ov08x->xvclk), "getting xvclk\n"); goto out_err; } - if (ov08x->xvclk) { - xvclk_rate = clk_get_rate(ov08x->xvclk); - } else { - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &xvclk_rate); - if (ret) { - dev_err(dev, "can't get clock frequency\n"); - goto out_err; - } - } + xvclk_rate = clk_get_rate(ov08x->xvclk); if (xvclk_rate != OV08X40_XVCLK) { dev_err(dev, "external clock %d is not supported\n", xvclk_rate); @@ -2294,19 +2283,21 @@ static int ov08x40_probe(struct i2c_client *client) if (!ov08x) return -ENOMEM; + ov08x->dev = &client->dev; + /* Check HW config */ - ret = ov08x40_check_hwcfg(ov08x, &client->dev); + ret = ov08x40_check_hwcfg(ov08x); if (ret) return ret; /* Initialize subdev */ v4l2_i2c_subdev_init(&ov08x->sd, client, &ov08x40_subdev_ops); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov08x->dev); if (full_power) { - ret = ov08x40_power_on(&client->dev); + ret = ov08x40_power_on(ov08x->dev); if (ret) { - dev_err(&client->dev, "failed to power on\n"); + dev_err(ov08x->dev, "failed to power on\n"); return ret; } @@ -2333,7 +2324,7 @@ static int ov08x40_probe(struct i2c_client *client) ov08x->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov08x->sd.entity, 1, &ov08x->pad); if (ret) { - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov08x->dev, "%s failed:%d\n", __func__, ret); goto error_handler_free; } @@ -2342,9 +2333,9 @@ static int ov08x40_probe(struct i2c_client *client) goto error_media_entity; if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov08x->dev); + pm_runtime_enable(ov08x->dev); + pm_runtime_idle(ov08x->dev); return 0; @@ -2355,7 +2346,7 @@ error_handler_free: ov08x40_free_controls(ov08x); probe_power_off: - ov08x40_power_off(&client->dev); + ov08x40_power_off(ov08x->dev); return ret; } @@ -2369,10 +2360,10 @@ static void ov08x40_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); ov08x40_free_controls(ov08x); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - ov08x40_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov08x->dev); + if (!pm_runtime_status_suspended(ov08x->dev)) + ov08x40_power_off(ov08x->dev); + pm_runtime_set_suspended(ov08x->dev); } static DEFINE_RUNTIME_DEV_PM_OPS(ov08x40_pm_ops, ov08x40_power_off, diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 7a3fc1d28514..162b49046990 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -2,6 +2,7 @@ // Copyright (c) 2017 Intel Corporation. #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> @@ -1028,6 +1029,9 @@ static const struct ov13858_mode supported_modes[] = { }; struct ov13858 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; @@ -1117,7 +1121,6 @@ static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, static int ov13858_write_regs(struct ov13858 *ov13858, const struct ov13858_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); int ret; u32 i; @@ -1126,7 +1129,7 @@ static int ov13858_write_regs(struct ov13858 *ov13858, regs[i].val); if (ret) { dev_err_ratelimited( - &client->dev, + ov13858->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -1209,7 +1212,6 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov13858 *ov13858 = container_of(ctrl->handler, struct ov13858, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); s64 max; int ret; @@ -1228,7 +1230,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov13858->dev)) return 0; ret = 0; @@ -1256,13 +1258,13 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) ret = ov13858_enable_test_pattern(ov13858, ctrl->val); break; default: - dev_info(&client->dev, + dev_info(ov13858->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov13858->dev); return ret; } @@ -1408,7 +1410,6 @@ static int ov13858_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) /* Start streaming */ static int ov13858_start_streaming(struct ov13858 *ov13858) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); const struct ov13858_reg_list *reg_list; int ret, link_freq_index; @@ -1416,7 +1417,7 @@ static int ov13858_start_streaming(struct ov13858 *ov13858) ret = ov13858_write_reg(ov13858, OV13858_REG_SOFTWARE_RST, OV13858_REG_VALUE_08BIT, OV13858_SOFTWARE_RST); if (ret) { - dev_err(&client->dev, "%s failed to set powerup registers\n", + dev_err(ov13858->dev, "%s failed to set powerup registers\n", __func__); return ret; } @@ -1426,7 +1427,7 @@ static int ov13858_start_streaming(struct ov13858 *ov13858) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov13858_write_reg_list(ov13858, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(ov13858->dev, "%s failed to set plls\n", __func__); return ret; } @@ -1434,7 +1435,7 @@ static int ov13858_start_streaming(struct ov13858 *ov13858) reg_list = &ov13858->cur_mode->reg_list; ret = ov13858_write_reg_list(ov13858, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(ov13858->dev, "%s failed to set mode\n", __func__); return ret; } @@ -1458,13 +1459,12 @@ static int ov13858_stop_streaming(struct ov13858 *ov13858) static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) { struct ov13858 *ov13858 = to_ov13858(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov13858->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov13858->dev); if (ret < 0) goto err_unlock; @@ -1477,7 +1477,7 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { ov13858_stop_streaming(ov13858); - pm_runtime_put(&client->dev); + pm_runtime_put(ov13858->dev); } mutex_unlock(&ov13858->mutex); @@ -1485,7 +1485,7 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(ov13858->dev); err_unlock: mutex_unlock(&ov13858->mutex); @@ -1495,7 +1495,6 @@ err_unlock: /* Verify chip ID */ static int ov13858_identify_module(struct ov13858 *ov13858) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); int ret; u32 val; @@ -1505,7 +1504,7 @@ static int ov13858_identify_module(struct ov13858 *ov13858) return ret; if (val != OV13858_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov13858->dev, "chip id mismatch: %x!=%x\n", OV13858_CHIP_ID, val); return -EIO; } @@ -1552,7 +1551,6 @@ static const struct v4l2_subdev_internal_ops ov13858_internal_ops = { /* Initialize control handlers */ static int ov13858_init_controls(struct ov13858 *ov13858) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; @@ -1626,12 +1624,12 @@ static int ov13858_init_controls(struct ov13858 *ov13858) 0, 0, ov13858_test_pattern_menu); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(ov13858->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov13858->dev, &props); if (ret) goto error; @@ -1660,24 +1658,33 @@ static void ov13858_free_controls(struct ov13858 *ov13858) static int ov13858_probe(struct i2c_client *client) { struct ov13858 *ov13858; + unsigned long freq; int ret; - u32 val = 0; - - device_property_read_u32(&client->dev, "clock-frequency", &val); - if (val != 19200000) - return -EINVAL; ov13858 = devm_kzalloc(&client->dev, sizeof(*ov13858), GFP_KERNEL); if (!ov13858) return -ENOMEM; + ov13858->dev = &client->dev; + + ov13858->clk = devm_v4l2_sensor_clk_get(ov13858->dev, NULL); + if (IS_ERR(ov13858->clk)) + return dev_err_probe(ov13858->dev, PTR_ERR(ov13858->clk), + "failed to get clock\n"); + + freq = clk_get_rate(ov13858->clk); + if (freq != 19200000) + return dev_err_probe(ov13858->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + /* Initialize subdev */ v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops); /* Check module identity */ ret = ov13858_identify_module(ov13858); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); + dev_err(ov13858->dev, "failed to find sensor: %d\n", ret); return ret; } @@ -1699,7 +1706,7 @@ static int ov13858_probe(struct i2c_client *client) ov13858->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov13858->sd.entity, 1, &ov13858->pad); if (ret) { - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov13858->dev, "%s failed:%d\n", __func__, ret); goto error_handler_free; } @@ -1711,9 +1718,9 @@ static int ov13858_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov13858->dev); + pm_runtime_enable(ov13858->dev); + pm_runtime_idle(ov13858->dev); return 0; @@ -1722,7 +1729,7 @@ error_media_entity: error_handler_free: ov13858_free_controls(ov13858); - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov13858->dev, "%s failed:%d\n", __func__, ret); return ret; } @@ -1736,7 +1743,7 @@ static void ov13858_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); ov13858_free_controls(ov13858); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov13858->dev); } static const struct i2c_device_id ov13858_id_table[] = { diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c index e85c7d33a670..5421874732bc 100644 --- a/drivers/media/i2c/ov13b10.c +++ b/drivers/media/i2c/ov13b10.c @@ -700,6 +700,8 @@ static const struct ov13b10_mode supported_2_lanes_modes[] = { }; struct ov13b10 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; @@ -805,7 +807,6 @@ static int ov13b10_write_reg(struct ov13b10 *ov13b, static int ov13b10_write_regs(struct ov13b10 *ov13b, const struct ov13b10_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); int ret; u32 i; @@ -813,7 +814,7 @@ static int ov13b10_write_regs(struct ov13b10 *ov13b, ret = ov13b10_write_reg(ov13b, regs[i].address, 1, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov13b->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -968,7 +969,6 @@ static int ov13b10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov13b10 *ov13b = container_of(ctrl->handler, struct ov13b10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); s64 max; int ret; @@ -987,7 +987,7 @@ static int ov13b10_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov13b->dev)) return 0; ret = 0; @@ -1021,13 +1021,13 @@ static int ov13b10_set_ctrl(struct v4l2_ctrl *ctrl) ov13b10_set_ctrl_vflip(ov13b, ctrl->val); break; default: - dev_info(&client->dev, + dev_info(ov13b->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov13b->dev); return ret; } @@ -1166,7 +1166,6 @@ ov13b10_set_pad_format(struct v4l2_subdev *sd, /* Verify chip ID */ static int ov13b10_identify_module(struct ov13b10 *ov13b) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); int ret; u32 val; @@ -1179,7 +1178,7 @@ static int ov13b10_identify_module(struct ov13b10 *ov13b) return ret; if (val != OV13B10_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov13b->dev, "chip id mismatch: %x!=%x\n", OV13B10_CHIP_ID, val); return -EIO; } @@ -1234,7 +1233,6 @@ static int ov13b10_power_on(struct device *dev) static int ov13b10_start_streaming(struct ov13b10 *ov13b) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); const struct ov13b10_reg_list *reg_list; int ret, link_freq_index; @@ -1246,7 +1244,7 @@ static int ov13b10_start_streaming(struct ov13b10 *ov13b) ret = ov13b10_write_reg(ov13b, OV13B10_REG_SOFTWARE_RST, OV13B10_REG_VALUE_08BIT, OV13B10_SOFTWARE_RST); if (ret) { - dev_err(&client->dev, "%s failed to set powerup registers\n", + dev_err(ov13b->dev, "%s failed to set powerup registers\n", __func__); return ret; } @@ -1255,7 +1253,7 @@ static int ov13b10_start_streaming(struct ov13b10 *ov13b) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov13b10_write_reg_list(ov13b, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(ov13b->dev, "%s failed to set plls\n", __func__); return ret; } @@ -1263,7 +1261,7 @@ static int ov13b10_start_streaming(struct ov13b10 *ov13b) reg_list = &ov13b->cur_mode->reg_list; ret = ov13b10_write_reg_list(ov13b, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(ov13b->dev, "%s failed to set mode\n", __func__); return ret; } @@ -1287,13 +1285,12 @@ static int ov13b10_stop_streaming(struct ov13b10 *ov13b) static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) { struct ov13b10 *ov13b = to_ov13b10(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov13b->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov13b->dev); if (ret < 0) goto err_unlock; @@ -1306,7 +1303,7 @@ static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { ov13b10_stop_streaming(ov13b); - pm_runtime_put(&client->dev); + pm_runtime_put(ov13b->dev); } mutex_unlock(&ov13b->mutex); @@ -1314,7 +1311,7 @@ static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(ov13b->dev); err_unlock: mutex_unlock(&ov13b->mutex); @@ -1360,7 +1357,6 @@ static const struct v4l2_subdev_internal_ops ov13b10_internal_ops = { /* Initialize control handlers */ static int ov13b10_init_controls(struct ov13b10 *ov13b) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; @@ -1443,12 +1439,12 @@ static int ov13b10_init_controls(struct ov13b10 *ov13b) if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(ov13b->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov13b->dev, &props); if (ret) goto error; @@ -1474,44 +1470,49 @@ static void ov13b10_free_controls(struct ov13b10 *ov13b) mutex_destroy(&ov13b->mutex); } -static int ov13b10_get_pm_resources(struct device *dev) +static int ov13b10_get_pm_resources(struct ov13b10 *ov13b) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13b10 *ov13b = to_ov13b10(sd); + unsigned long freq; int ret; - ov13b->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + ov13b->reset = devm_gpiod_get_optional(ov13b->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ov13b->reset)) - return dev_err_probe(dev, PTR_ERR(ov13b->reset), + return dev_err_probe(ov13b->dev, PTR_ERR(ov13b->reset), "failed to get reset gpio\n"); - ov13b->img_clk = devm_clk_get_optional(dev, NULL); + ov13b->img_clk = devm_v4l2_sensor_clk_get(ov13b->dev, NULL); if (IS_ERR(ov13b->img_clk)) - return dev_err_probe(dev, PTR_ERR(ov13b->img_clk), + return dev_err_probe(ov13b->dev, PTR_ERR(ov13b->img_clk), "failed to get imaging clock\n"); - ov13b->avdd = devm_regulator_get_optional(dev, "avdd"); + freq = clk_get_rate(ov13b->img_clk); + if (freq != OV13B10_EXT_CLK) + return dev_err_probe(ov13b->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + + ov13b->avdd = devm_regulator_get_optional(ov13b->dev, "avdd"); if (IS_ERR(ov13b->avdd)) { ret = PTR_ERR(ov13b->avdd); ov13b->avdd = NULL; if (ret != -ENODEV) - return dev_err_probe(dev, ret, + return dev_err_probe(ov13b->dev, ret, "failed to get avdd regulator\n"); } return 0; } -static int ov13b10_check_hwcfg(struct device *dev, struct ov13b10 *ov13b) +static int ov13b10_check_hwcfg(struct ov13b10 *ov13b) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct device *dev = ov13b->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); unsigned int i, j; int ret; - u32 ext_clk; u8 dlane; if (!fwnode) @@ -1521,19 +1522,6 @@ static int ov13b10_check_hwcfg(struct device *dev, struct ov13b10 *ov13b) if (!ep) return -EPROBE_DEFER; - 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 (ext_clk != OV13B10_EXT_CLK) { - dev_err(dev, "external clock %d is not supported", - ext_clk); - return -EINVAL; - } - ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); if (ret) @@ -1602,32 +1590,34 @@ static int ov13b10_probe(struct i2c_client *client) if (!ov13b) return -ENOMEM; + ov13b->dev = &client->dev; + /* Check HW config */ - ret = ov13b10_check_hwcfg(&client->dev, ov13b); + ret = ov13b10_check_hwcfg(ov13b); if (ret) { - dev_err(&client->dev, "failed to check hwcfg: %d", ret); + dev_err(ov13b->dev, "failed to check hwcfg: %d", ret); return ret; } /* Initialize subdev */ v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops); - ret = ov13b10_get_pm_resources(&client->dev); + ret = ov13b10_get_pm_resources(ov13b); if (ret) return ret; - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov13b->dev); if (full_power) { - ret = ov13b10_power_on(&client->dev); + ret = ov13b10_power_on(ov13b->dev); if (ret) { - dev_err(&client->dev, "failed to power on\n"); + dev_err(ov13b->dev, "failed to power on\n"); return ret; } /* Check module identity */ ret = ov13b10_identify_module(ov13b); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); + dev_err(ov13b->dev, "failed to find sensor: %d\n", ret); goto error_power_off; } } @@ -1646,7 +1636,7 @@ static int ov13b10_probe(struct i2c_client *client) ov13b->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov13b->sd.entity, 1, &ov13b->pad); if (ret) { - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov13b->dev, "%s failed:%d\n", __func__, ret); goto error_handler_free; } @@ -1657,9 +1647,9 @@ static int ov13b10_probe(struct i2c_client *client) */ /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov13b->dev); + pm_runtime_enable(ov13b->dev); + pm_runtime_idle(ov13b->dev); ret = v4l2_async_register_subdev_sensor(&ov13b->sd); if (ret < 0) @@ -1668,17 +1658,17 @@ static int ov13b10_probe(struct i2c_client *client) return 0; error_media_entity_runtime_pm: - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov13b->dev); if (full_power) - pm_runtime_set_suspended(&client->dev); + pm_runtime_set_suspended(ov13b->dev); media_entity_cleanup(&ov13b->sd.entity); error_handler_free: ov13b10_free_controls(ov13b); - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov13b->dev, "%s failed:%d\n", __func__, ret); error_power_off: - ov13b10_power_off(&client->dev); + ov13b10_power_off(ov13b->dev); return ret; } @@ -1692,8 +1682,8 @@ static void ov13b10_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); ov13b10_free_controls(ov13b); - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov13b->dev); + pm_runtime_set_suspended(ov13b->dev); } static DEFINE_RUNTIME_DEV_PM_OPS(ov13b10_pm_ops, ov13b10_suspend, @@ -1703,6 +1693,7 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ov13b10_pm_ops, ov13b10_suspend, static const struct acpi_device_id ov13b10_acpi_ids[] = { {"OVTIDB10"}, {"OVTI13B1"}, + {"OMNI13B1"}, /* ASUS ROG Flow Z13 (GZ302) uses this ACPI ID */ { /* sentinel */ } }; diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 586b31ba076b..061401b020fc 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1437,9 +1437,10 @@ static int ov2659_probe(struct i2c_client *client) ov2659->pdata = pdata; ov2659->client = client; - ov2659->clk = devm_clk_get(&client->dev, "xvclk"); + ov2659->clk = devm_v4l2_sensor_clk_get(&client->dev, "xvclk"); if (IS_ERR(ov2659->clk)) - return PTR_ERR(ov2659->clk); + return dev_err_probe(&client->dev, PTR_ERR(ov2659->clk), + "failed to get xvclk\n"); ov2659->xvclk_frequency = clk_get_rate(ov2659->clk); if (ov2659->xvclk_frequency < 6000000 || diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index 7237fb27ecd0..78e63bd1b35b 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -1079,7 +1079,6 @@ static int ov2680_parse_dt(struct ov2680_dev *sensor) struct device *dev = sensor->dev; struct fwnode_handle *ep_fwnode; struct gpio_desc *gpio; - unsigned int rate = 0; int i, ret; /* @@ -1114,38 +1113,14 @@ static int ov2680_parse_dt(struct ov2680_dev *sensor) sensor->pwdn_gpio = gpio; - sensor->xvclk = devm_clk_get_optional(dev, "xvclk"); + sensor->xvclk = devm_v4l2_sensor_clk_get(dev, "xvclk"); if (IS_ERR(sensor->xvclk)) { ret = dev_err_probe(dev, PTR_ERR(sensor->xvclk), "xvclk clock missing or invalid\n"); goto out_free_bus_cfg; } - /* - * We could have either a 24MHz or 19.2MHz clock rate from either DT or - * ACPI... but we also need to support the weird IPU3 case which will - * have an external clock AND a clock-frequency property. Check for the - * clock-frequency property and if found, set that rate if we managed - * to acquire a clock. This should cover the ACPI case. If the system - * uses devicetree then the configured rate should already be set, so - * we can just read it. - */ - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &rate); - if (ret && !sensor->xvclk) { - dev_err_probe(dev, ret, "invalid clock config\n"); - goto out_free_bus_cfg; - } - - if (!ret && sensor->xvclk) { - ret = clk_set_rate(sensor->xvclk, rate); - if (ret) { - dev_err_probe(dev, ret, "failed to set clock rate\n"); - goto out_free_bus_cfg; - } - } - - sensor->xvclk_freq = rate ?: clk_get_rate(sensor->xvclk); + sensor->xvclk_freq = clk_get_rate(sensor->xvclk); for (i = 0; i < ARRAY_SIZE(ov2680_xvclk_freqs); i++) { if (sensor->xvclk_freq == ov2680_xvclk_freqs[i]) diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 9b8481b8dcd4..4911a4eea126 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -783,16 +783,12 @@ static int ov2685_probe(struct i2c_client *client) ov2685->client = client; ov2685->cur_mode = &supported_modes[0]; - ov2685->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(ov2685->xvclk)) { - dev_err(dev, "Failed to get xvclk\n"); - return -EINVAL; - } - ret = clk_set_rate(ov2685->xvclk, OV2685_XVCLK_FREQ); - if (ret < 0) { - dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); - return ret; - } + ov2685->xvclk = devm_v4l2_sensor_clk_get_legacy(dev, "xvclk", true, + OV2685_XVCLK_FREQ); + if (IS_ERR(ov2685->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov2685->xvclk), + "Failed to get xvclk\n"); + if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ) dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); diff --git a/drivers/media/i2c/ov2735.c b/drivers/media/i2c/ov2735.c new file mode 100644 index 000000000000..b96600204141 --- /dev/null +++ b/drivers/media/i2c/ov2735.c @@ -0,0 +1,1109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 Support for the OV2735 + * + * Copyright (C) 2025 Silicon Signals Pvt. Ltd. + * + * Based on Rockchip ov2735 Camera Driver + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + * + * Inspired from ov8858, imx219, imx283 camera drivers. + */ + +#include <linux/array_size.h> +#include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/container_of.h> +#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <linux/units.h> +#include <linux/types.h> +#include <linux/time.h> + +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mediabus.h> + +#define OV2735_XCLK_FREQ (24 * HZ_PER_MHZ) + +/* Add page number in CCI private bits [31:28] of the register address */ +#define OV2735_PAGE_REG8(p, x) (((p) << CCI_REG_PRIVATE_SHIFT) | CCI_REG8(x)) +#define OV2735_PAGE_REG16(p, x) (((p) << CCI_REG_PRIVATE_SHIFT) | CCI_REG16(x)) + +#define OV2735_REG_PAGE_SELECT CCI_REG8(0xfd) + +/* Page 0 */ +#define OV2735_REG_CHIPID OV2735_PAGE_REG16(0x00, 0x02) +#define OV2735_CHIPID 0x2735 + +#define OV2735_REG_SOFT_RESET OV2735_PAGE_REG8(0x00, 0x20) + +/* Clock Settings */ +#define OV2735_REG_PLL_CTRL OV2735_PAGE_REG8(0x00, 0x2f) +#define OV2735_PLL_CTRL_ENABLE 0x7f +#define OV2735_REG_PLL_OUTDIV OV2735_PAGE_REG8(0x00, 0x34) +#define OV2735_REG_CLK_MODE OV2735_PAGE_REG8(0x00, 0x30) +#define OV2735_REG_CLOCK_REG1 OV2735_PAGE_REG8(0x00, 0x33) +#define OV2735_REG_CLOCK_REG2 OV2735_PAGE_REG8(0x00, 0x35) + +/* Page 1 */ +#define OV2735_REG_STREAM_CTRL OV2735_PAGE_REG8(0x01, 0xa0) +#define OV2735_STREAM_CTRL_ON 0x01 +#define OV2735_STREAM_CTRL_OFF 0x00 + +#define OV2735_REG_UPDOWN_MIRROR OV2735_PAGE_REG8(0x01, 0x3f) +#define OV2735_REG_BINNING_DAC_CODE_MODE OV2735_PAGE_REG8(0x01, 0x30) +#define OV2735_REG_FRAME_LENGTH OV2735_PAGE_REG16(0x01, 0x0e) +#define OV2735_FRAME_LENGTH_MAX 0x0fff +#define OV2735_REG_FRAME_EXP_SEPERATE_EN OV2735_PAGE_REG8(0x01, 0x0d) +#define OV2735_FRAME_EXP_SEPERATE_EN 0x10 +#define OV2735_REG_FRAME_SYNC OV2735_PAGE_REG8(0x01, 0x01) + +#define OV2735_REG_HBLANK OV2735_PAGE_REG16(0x01, 0x09) + +#define OV2735_REG_HS_MIPI OV2735_PAGE_REG8(0x01, 0xb1) +#define OV2735_REG_MIPI_CTRL1 OV2735_PAGE_REG8(0x01, 0x92) +#define OV2735_REG_MIPI_CTRL2 OV2735_PAGE_REG8(0x01, 0x94) +#define OV2735_REG_MIPI_CTRL3 OV2735_PAGE_REG8(0x01, 0xa1) +#define OV2735_REG_MIPI_CTRL4 OV2735_PAGE_REG8(0x01, 0xb2) +#define OV2735_REG_MIPI_CTRL5 OV2735_PAGE_REG8(0x01, 0xb3) +#define OV2735_REG_MIPI_CTRL6 OV2735_PAGE_REG8(0x01, 0xb4) +#define OV2735_REG_MIPI_CTRL7 OV2735_PAGE_REG8(0x01, 0xb5) +#define OV2735_REG_HIGH_SPEED OV2735_PAGE_REG8(0x01, 0x9d) +#define OV2735_REG_PREPARE OV2735_PAGE_REG8(0x01, 0x95) +#define OV2735_REG_R_HS_ZERO OV2735_PAGE_REG8(0x01, 0x96) +#define OV2735_REG_TRAIL OV2735_PAGE_REG8(0x01, 0x98) +#define OV2735_REG_R_CLK_ZERO OV2735_PAGE_REG8(0x01, 0x9c) +#define OV2735_REG_MIPI_COLOMN_NUMBER OV2735_PAGE_REG16(0x01, 0x8e) +#define OV2735_REG_MIPI_LINE_NUMBER OV2735_PAGE_REG16(0x01, 0x90) + +/* Timing control registers */ +#define OV2735_REG_TIMING_CTRL2 OV2735_PAGE_REG8(0x01, 0x1a) +#define OV2735_REG_TIMING_CTRL3 OV2735_PAGE_REG8(0x01, 0x1c) +#define OV2735_REG_TIMING_CTRL1 OV2735_PAGE_REG8(0x01, 0x16) +#define OV2735_REG_RST_NUM OV2735_PAGE_REG16(0x01, 0x10) +#define OV2735_REG_RST_NUM2 OV2735_PAGE_REG16(0x01, 0x32) +#define OV2735_REG_BOOST_EN OV2735_PAGE_REG8(0x01, 0xd0) +#define OV2735_REG_B2_NUM OV2735_PAGE_REG16(0x01, 0xd1) +#define OV2735_REG_B4_NUM OV2735_PAGE_REG16(0x01, 0xd3) +#define OV2735_REG_PIXEL_CYCLE_P0 OV2735_PAGE_REG8(0x01, 0x50) +#define OV2735_REG_PIXEL_CYCLE_P1 OV2735_PAGE_REG8(0x01, 0x51) +#define OV2735_REG_PIXEL_CYCLE_P2 OV2735_PAGE_REG8(0x01, 0x52) +#define OV2735_REG_PIXEL_CYCLE_P3 OV2735_PAGE_REG8(0x01, 0x53) +#define OV2735_REG_PIXEL_CYCLE_P5 OV2735_PAGE_REG8(0x01, 0x55) +#define OV2735_REG_PIXEL_CYCLE_P7 OV2735_PAGE_REG16(0x01, 0x57) +#define OV2735_REG_PIXEL_CYCLE_P9 OV2735_PAGE_REG8(0x01, 0x5a) +#define OV2735_REG_PIXEL_CYCLE_P10 OV2735_PAGE_REG8(0x01, 0x5b) +#define OV2735_REG_PIXEL_CYCLE_P12 OV2735_PAGE_REG8(0x01, 0x5d) +#define OV2735_REG_PIXEL_CYCLE_P18 OV2735_PAGE_REG8(0x01, 0x64) +#define OV2735_REG_PIXEL_CYCLE_P20 OV2735_PAGE_REG8(0x01, 0x66) +#define OV2735_REG_PIXEL_CYCLE_P22 OV2735_PAGE_REG8(0x01, 0x68) +#define OV2735_REG_PIXEL_CYCLE_P33 OV2735_PAGE_REG16(0x01, 0x74) +#define OV2735_REG_PIXEL_CYCLE_P34 OV2735_PAGE_REG8(0x01, 0x76) +#define OV2735_REG_PIXEL_CYCLE_P35_P36 OV2735_PAGE_REG8(0x01, 0x77) +#define OV2735_REG_PIXEL_CYCLE_P37_P38 OV2735_PAGE_REG8(0x01, 0x78) +#define OV2735_REG_PIXEL_CYCLE_P31 OV2735_PAGE_REG8(0x01, 0x72) +#define OV2735_REG_PIXEL_CYCLE_P32 OV2735_PAGE_REG8(0x01, 0x73) +#define OV2735_REG_PIXEL_CYCLE_P44 OV2735_PAGE_REG8(0x01, 0x7d) +#define OV2735_REG_PIXEL_CYCLE_P45 OV2735_PAGE_REG8(0x01, 0x7e) +#define OV2735_REG_PIXEL_BIAS_CTRL_RH_RL OV2735_PAGE_REG8(0x01, 0x8a) +#define OV2735_REG_PIXEL_BIAS_CTRL_SH_SL OV2735_PAGE_REG8(0x01, 0x8b) + +/* Analog Control registers */ +#define OV2735_REG_ICOMP OV2735_PAGE_REG8(0x01, 0x19) +#define OV2735_REG_PCP_RST_SEL OV2735_PAGE_REG8(0x01, 0x21) +#define OV2735_REG_VNCP OV2735_PAGE_REG8(0x01, 0x20) +#define OV2735_REG_ANALOG_CTRL3 OV2735_PAGE_REG8(0x01, 0x25) +#define OV2735_REG_ANALOG_CTRL4 OV2735_PAGE_REG8(0x01, 0x26) +#define OV2735_REG_ANALOG_CTRL5 OV2735_PAGE_REG8(0x01, 0x29) +#define OV2735_REG_ANALOG_CTRL6 OV2735_PAGE_REG8(0x01, 0x2a) +#define OV2735_REG_ANALOG_CTRL8 OV2735_PAGE_REG8(0x01, 0x2c) + +/* BLC registers */ +#define OV2735_REG_BLC_GAIN_BLUE OV2735_PAGE_REG8(0x01, 0x86) +#define OV2735_REG_BLC_GAIN_RED OV2735_PAGE_REG8(0x01, 0x87) +#define OV2735_REG_BLC_GAIN_GR OV2735_PAGE_REG8(0x01, 0x88) +#define OV2735_REG_BLC_GAIN_GB OV2735_PAGE_REG8(0x01, 0x89) +#define OV2735_REG_GB_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf0) +#define OV2735_REG_BLUE_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf1) +#define OV2735_REG_RED_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf2) +#define OV2735_REG_GR_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf3) +#define OV2735_REG_BLC_BPC_TH_P OV2735_PAGE_REG8(0x01, 0xfc) +#define OV2735_REG_BLC_BPC_TH_N OV2735_PAGE_REG8(0x01, 0xfe) +#define OV2735_REG_ABL OV2735_PAGE_REG8(0x01, 0xfb) + +#define OV2735_REG_TEST_PATTERN OV2735_PAGE_REG8(0x01, 0xb2) +#define OV2735_TEST_PATTERN_ENABLE 0x01 +#define OV2735_TEST_PATTERN_DISABLE 0xfe + +#define OV2735_REG_LONG_EXPOSURE OV2735_PAGE_REG16(0x01, 0x03) +#define OV2735_EXPOSURE_MIN 4 +#define OV2735_EXPOSURE_STEP 1 +#define OV2735_EXPOSURE_MARGIN 4 + +#define OV2735_REG_ANALOG_GAIN OV2735_PAGE_REG8(0x01, 0x24) +#define OV2735_ANALOG_GAIN_MIN 0x10 +#define OV2735_ANALOG_GAIN_MAX 0xff +#define OV2735_ANALOG_GAIN_STEP 1 +#define OV2735_ANALOG_GAIN_DEFAULT 0x10 + +/* Page 2 */ +#define OV2735_REG_V_START OV2735_PAGE_REG16(0x02, 0xa0) +#define OV2735_REG_V_SIZE OV2735_PAGE_REG16(0x02, 0xa2) +#define OV2735_REG_H_START OV2735_PAGE_REG16(0x02, 0xa4) +#define OV2735_REG_H_SIZE OV2735_PAGE_REG16(0x02, 0xa6) + +#define OV2735_LINK_FREQ_420MHZ (420 * HZ_PER_MHZ) +#define OV2735_PIXEL_RATE (168 * HZ_PER_MHZ) + +/* OV2735 native and active pixel array size */ +static const struct v4l2_rect ov2735_native_area = { + .top = 0, + .left = 0, + .width = 1936, + .height = 1096, +}; + +static const struct v4l2_rect ov2735_active_area = { + .top = 8, + .left = 8, + .width = 1920, + .height = 1080, +}; + +static const char * const ov2735_supply_name[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +/* PLL_OUT = [PLL_IN * (pll_nc +3)] / [(pll_mc + 1) * (pll_outdiv + 1)] */ +struct ov2735_pll_parameters { + u8 pll_nc; + u8 pll_mc; + u8 pll_outdiv; +}; + +struct ov2735 { + struct device *dev; + struct regmap *cci; + struct v4l2_subdev sd; + struct media_pad pad; + struct clk *xclk; + struct gpio_desc *reset_gpio; + struct gpio_desc *enable_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(ov2735_supply_name)]; + + /* V4L2 Controls */ + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *test_pattern; + + u32 link_freq_index; + + u8 current_page; + struct mutex page_lock; +}; + +struct ov2735_mode { + u32 width; + u32 height; + u32 hts_def; + u32 vts_def; + u32 exp_def; + struct v4l2_rect crop; +}; + +static const struct cci_reg_sequence ov2735_common_regs[] = { + { OV2735_REG_CLK_MODE, 0x15 }, + { OV2735_REG_CLOCK_REG1, 0x01 }, + { OV2735_REG_CLOCK_REG2, 0x20 }, + { OV2735_REG_BINNING_DAC_CODE_MODE, 0x00 }, + { OV2735_REG_ABL, 0x73 }, + { OV2735_REG_FRAME_SYNC, 0x01 }, + + /* Timing ctrl */ + { OV2735_REG_TIMING_CTRL2, 0x6b }, + { OV2735_REG_TIMING_CTRL3, 0xea }, + { OV2735_REG_TIMING_CTRL1, 0x0c }, + { OV2735_REG_RST_NUM, 0x0063 }, + { OV2735_REG_RST_NUM2, 0x006f }, + { OV2735_REG_BOOST_EN, 0x02 }, + { OV2735_REG_B2_NUM, 0x0120 }, + { OV2735_REG_B4_NUM, 0x042a }, + { OV2735_REG_PIXEL_CYCLE_P0, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P1, 0x2c }, + { OV2735_REG_PIXEL_CYCLE_P2, 0x29 }, + { OV2735_REG_PIXEL_CYCLE_P3, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P5, 0x44 }, + { OV2735_REG_PIXEL_CYCLE_P7, 0x0029 }, + { OV2735_REG_PIXEL_CYCLE_P9, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P10, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P12, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P18, 0x2f }, + { OV2735_REG_PIXEL_CYCLE_P20, 0x62 }, + { OV2735_REG_PIXEL_CYCLE_P22, 0x5b }, + { OV2735_REG_PIXEL_CYCLE_P33, 0x0046 }, + { OV2735_REG_PIXEL_CYCLE_P34, 0x36 }, + { OV2735_REG_PIXEL_CYCLE_P35_P36, 0x4f }, + { OV2735_REG_PIXEL_CYCLE_P37_P38, 0xef }, + { OV2735_REG_PIXEL_CYCLE_P31, 0xcf }, + { OV2735_REG_PIXEL_CYCLE_P32, 0x36 }, + { OV2735_REG_PIXEL_CYCLE_P44, 0x0d }, + { OV2735_REG_PIXEL_CYCLE_P45, 0x0d }, + { OV2735_REG_PIXEL_BIAS_CTRL_RH_RL, 0x77 }, + { OV2735_REG_PIXEL_BIAS_CTRL_SH_SL, 0x77 }, + + /* Analog ctrl */ + { OV2735_REG_ANALOG_CTRL4, 0x5a }, + { OV2735_REG_ANALOG_CTRL5, 0x01 }, + { OV2735_REG_ANALOG_CTRL6, 0xd2 }, + { OV2735_REG_ANALOG_CTRL8, 0x40 }, + { OV2735_REG_PCP_RST_SEL, 0x00 }, + { OV2735_REG_ICOMP, 0xc3 }, + + { OV2735_REG_HS_MIPI, 0x83 }, + { OV2735_REG_MIPI_CTRL5, 0x0b }, + { OV2735_REG_MIPI_CTRL6, 0x14 }, + { OV2735_REG_HIGH_SPEED, 0x40 }, + { OV2735_REG_MIPI_CTRL3, 0x05 }, + { OV2735_REG_MIPI_CTRL2, 0x44 }, + { OV2735_REG_PREPARE, 0x33 }, + { OV2735_REG_R_HS_ZERO, 0x1f }, + { OV2735_REG_TRAIL, 0x45 }, + { OV2735_REG_R_CLK_ZERO, 0x10 }, + { OV2735_REG_MIPI_CTRL7, 0x70 }, + { OV2735_REG_ANALOG_CTRL3, 0xe0 }, + { OV2735_REG_VNCP, 0x7b }, + + /* BLC */ + { OV2735_REG_BLC_GAIN_BLUE, 0x77 }, + { OV2735_REG_BLC_GAIN_GB, 0x77 }, + { OV2735_REG_BLC_GAIN_RED, 0x74 }, + { OV2735_REG_BLC_GAIN_GR, 0x74 }, + { OV2735_REG_BLC_BPC_TH_P, 0xe0 }, + { OV2735_REG_BLC_BPC_TH_N, 0xe0 }, + { OV2735_REG_GB_SUBOFFSET, 0x40 }, + { OV2735_REG_BLUE_SUBOFFSET, 0x40 }, + { OV2735_REG_RED_SUBOFFSET, 0x40 }, + { OV2735_REG_GR_SUBOFFSET, 0x40 }, +}; + +static const struct ov2735_mode supported_modes[] = { + { + .width = 1920, + .height = 1080, + .exp_def = 399, + .hts_def = 2200, + .vts_def = 2545, + .crop = { + .top = 8, + .left = 8, + .width = 1920, + .height = 1080, + }, + }, +}; + +static const s64 link_freq_menu_items[] = { + OV2735_LINK_FREQ_420MHZ, +}; + +static const struct ov2735_pll_parameters pll_configs[] = { + /* For 420MHz pll_configs */ + { + .pll_nc = 4, + .pll_mc = 0, + .pll_outdiv = 1, + }, +}; + +static const char * const ov2735_test_pattern_menu[] = { + "Disabled", + "Vertical Color", +}; + +static int ov2735_page_access(struct ov2735 *ov2735, u32 reg, int *err) +{ + u8 page = reg >> CCI_REG_PRIVATE_SHIFT; + int ret = 0; + + if (err && *err) + return *err; + + guard(mutex)(&ov2735->page_lock); + + /* Perform page access before read/write */ + if (ov2735->current_page == page) + return ret; + + ret = cci_write(ov2735->cci, OV2735_REG_PAGE_SELECT, page, err); + if (!ret) + ov2735->current_page = page; + + return ret; +} + +static int ov2735_read(struct ov2735 *ov2735, u32 reg, u64 *val, int *err) +{ + u32 addr = reg & ~CCI_REG_PRIVATE_MASK; + int ret; + + ret = ov2735_page_access(ov2735, reg, err); + if (ret) + return ret; + + return cci_read(ov2735->cci, addr, val, err); +} + +static int ov2735_write(struct ov2735 *ov2735, u32 reg, u64 val, int *err) +{ + u32 addr = reg & ~CCI_REG_PRIVATE_MASK; + int ret; + + ret = ov2735_page_access(ov2735, reg, err); + if (ret) + return ret; + + return cci_write(ov2735->cci, addr, val, err); +} + +static int ov2735_multi_reg_write(struct ov2735 *ov2735, + const struct cci_reg_sequence *regs, + unsigned int num_regs, int *err) +{ + unsigned int i; + int ret; + + for (i = 0; i < num_regs; i++) { + ret = ov2735_write(ov2735, regs[i].reg, regs[i].val, err); + if (ret) + return ret; + } + + return 0; +} + +static inline struct ov2735 *to_ov2735(struct v4l2_subdev *_sd) +{ + return container_of_const(_sd, struct ov2735, sd); +} + +static int ov2735_enable_test_pattern(struct ov2735 *ov2735, u32 pattern) +{ + int ret; + u64 val; + + ret = ov2735_read(ov2735, OV2735_REG_TEST_PATTERN, &val, NULL); + if (ret) + return ret; + + switch (pattern) { + case 0: + val &= ~OV2735_TEST_PATTERN_ENABLE; + break; + case 1: + val |= OV2735_TEST_PATTERN_ENABLE; + break; + } + + return ov2735_write(ov2735, OV2735_REG_TEST_PATTERN, val, NULL); +} + +static int ov2735_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2735 *ov2735 = + container_of_const(ctrl->handler, struct ov2735, handler); + struct v4l2_mbus_framefmt *fmt; + struct v4l2_subdev_state *state; + u64 vts; + int ret = 0; + + state = v4l2_subdev_get_locked_active_state(&ov2735->sd); + fmt = v4l2_subdev_state_get_format(state, 0); + + if (ctrl->id == V4L2_CID_VBLANK) { + /* Honour the VBLANK limits when setting exposure */ + s64 max = fmt->height + ctrl->val - OV2735_EXPOSURE_MARGIN; + + ret = __v4l2_ctrl_modify_range(ov2735->exposure, + ov2735->exposure->minimum, max, + ov2735->exposure->step, + ov2735->exposure->default_value); + if (ret) + return ret; + } + + if (pm_runtime_get_if_in_use(ov2735->dev) == 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ov2735_write(ov2735, OV2735_REG_LONG_EXPOSURE, ctrl->val, &ret); + break; + case V4L2_CID_ANALOGUE_GAIN: + ov2735_write(ov2735, OV2735_REG_ANALOG_GAIN, ctrl->val, &ret); + break; + case V4L2_CID_HBLANK: + ov2735_write(ov2735, OV2735_REG_HBLANK, ctrl->val, &ret); + break; + case V4L2_CID_VBLANK: + vts = ctrl->val + fmt->height; + ov2735_write(ov2735, OV2735_REG_FRAME_EXP_SEPERATE_EN, + OV2735_FRAME_EXP_SEPERATE_EN, &ret); + ov2735_write(ov2735, OV2735_REG_FRAME_LENGTH, vts, &ret); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov2735_enable_test_pattern(ov2735, ctrl->val); + break; + default: + ret = -EINVAL; + break; + } + ov2735_write(ov2735, OV2735_REG_FRAME_SYNC, 0x01, &ret); + + pm_runtime_put(ov2735->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov2735_ctrl_ops = { + .s_ctrl = ov2735_set_ctrl, +}; + +static int ov2735_init_controls(struct ov2735 *ov2735) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + struct v4l2_fwnode_device_properties props; + const struct ov2735_mode *mode = &supported_modes[0]; + u64 hblank_def, vblank_def, exp_max; + int ret; + + ctrl_hdlr = &ov2735->handler; + v4l2_ctrl_handler_init(ctrl_hdlr, 9); + + ov2735->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_PIXEL_RATE, 0, + OV2735_PIXEL_RATE, 1, + OV2735_PIXEL_RATE); + + ov2735->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_LINK_FREQ, + ov2735->link_freq_index, + 0, link_freq_menu_items); + if (ov2735->link_freq) + ov2735->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + hblank_def = mode->hts_def - mode->width; + ov2735->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_HBLANK, hblank_def, + hblank_def, 1, hblank_def); + + vblank_def = mode->vts_def - mode->height; + ov2735->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_VBLANK, vblank_def, + OV2735_FRAME_LENGTH_MAX - mode->height, + 1, vblank_def); + + exp_max = mode->vts_def - OV2735_EXPOSURE_MARGIN; + ov2735->exposure = + v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_EXPOSURE, + OV2735_EXPOSURE_MIN, exp_max, + OV2735_EXPOSURE_STEP, mode->exp_def); + + ov2735->gain = + v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, OV2735_ANALOG_GAIN_MIN, + OV2735_ANALOG_GAIN_MAX, OV2735_ANALOG_GAIN_STEP, + OV2735_ANALOG_GAIN_DEFAULT); + + ov2735->test_pattern = + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov2735_test_pattern_menu) - 1, + 0, 0, ov2735_test_pattern_menu); + + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + dev_err(ov2735->dev, "control init failed (%d)\n", ret); + goto err_handler_free; + } + + ret = v4l2_fwnode_device_parse(ov2735->dev, &props); + if (ret) + goto err_handler_free; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, + &ov2735_ctrl_ops, &props); + if (ret) + goto err_handler_free; + + ov2735->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +err_handler_free: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; +} + +static int ov2735_set_pll_ctrl(struct ov2735 *ov2735) +{ + const struct ov2735_pll_parameters *pll_parameters; + u8 pll_ctrl; + u8 pll_outdiv; + int ret = 0; + + pll_parameters = &pll_configs[ov2735->link_freq_index]; + + /* BIT[7]: pll_clk_sel, BIT[6:2]: pll_nc, BIT[1:0]: pll_mc */ + pll_ctrl = ((pll_parameters->pll_nc << 2) | (pll_parameters->pll_mc << 0)) & + OV2735_PLL_CTRL_ENABLE; + + pll_outdiv = pll_parameters->pll_outdiv; + + ov2735_write(ov2735, OV2735_REG_PLL_CTRL, pll_ctrl, &ret); + ov2735_write(ov2735, OV2735_REG_PLL_OUTDIV, pll_outdiv, &ret); + + return ret; +} + +static int ov2735_set_framefmt(struct ov2735 *ov2735, + struct v4l2_subdev_state *state) +{ + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *crop; + int ret = 0; + + format = v4l2_subdev_state_get_format(state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); + + ov2735_write(ov2735, OV2735_REG_V_START, crop->top, &ret); + ov2735_write(ov2735, OV2735_REG_V_SIZE, format->height, &ret); + ov2735_write(ov2735, OV2735_REG_MIPI_LINE_NUMBER, format->height, &ret); + ov2735_write(ov2735, OV2735_REG_H_START, crop->left, &ret); + /* OV2735_REG_H_SIZE: Image half horizontal size */ + ov2735_write(ov2735, OV2735_REG_H_SIZE, (format->width / 2), &ret); + ov2735_write(ov2735, OV2735_REG_MIPI_COLOMN_NUMBER, format->width, &ret); + + return ret; +} + +static int ov2735_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ov2735 *ov2735 = to_ov2735(sd); + int ret; + + ret = pm_runtime_resume_and_get(ov2735->dev); + if (ret < 0) + return ret; + + /* Apply pll settings */ + ret = ov2735_set_pll_ctrl(ov2735); + if (ret) { + dev_err(ov2735->dev, "failed to set frame format: %d\n", ret); + goto err_rpm_put; + } + + ret = ov2735_multi_reg_write(ov2735, ov2735_common_regs, + ARRAY_SIZE(ov2735_common_regs), NULL); + if (ret) { + dev_err(ov2735->dev, "failed to write common registers\n"); + goto err_rpm_put; + } + + /* Apply format settings */ + ret = ov2735_set_framefmt(ov2735, state); + if (ret) { + dev_err(ov2735->dev, "failed to set frame format: %d\n", ret); + goto err_rpm_put; + } + + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(ov2735->sd.ctrl_handler); + if (ret) + goto err_rpm_put; + + ret = ov2735_write(ov2735, OV2735_REG_STREAM_CTRL, + OV2735_STREAM_CTRL_ON, NULL); + if (ret) + goto err_rpm_put; + + return 0; + +err_rpm_put: + pm_runtime_put(ov2735->dev); + return ret; +} + +static int ov2735_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ov2735 *ov2735 = to_ov2735(sd); + int ret; + + ret = ov2735_write(ov2735, OV2735_REG_STREAM_CTRL, + OV2735_STREAM_CTRL_OFF, NULL); + if (ret) + dev_err(ov2735->dev, "%s failed to set stream\n", __func__); + + pm_runtime_put(ov2735->dev); + + return ret; +} + +static int ov2735_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); + return 0; + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r = ov2735_native_area; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r = ov2735_active_area; + return 0; + default: + return -EINVAL; + } +} + +static int ov2735_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int ov2735_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int ov2735_set_framing_limits(struct ov2735 *ov2735, + const struct ov2735_mode *mode) +{ + u32 hblank, vblank_def; + int ret; + + hblank = mode->hts_def - mode->width; + ret = __v4l2_ctrl_modify_range(ov2735->hblank, hblank, hblank, 1, + hblank); + if (ret) + return ret; + + vblank_def = mode->vts_def - mode->height; + return __v4l2_ctrl_modify_range(ov2735->vblank, vblank_def, + OV2735_FRAME_LENGTH_MAX - mode->height, + 1, vblank_def); +} + +static int ov2735_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *format; + const struct ov2735_mode *mode; + struct v4l2_rect *crop; + struct ov2735 *ov2735 = to_ov2735(sd); + int ret; + + format = v4l2_subdev_state_get_format(sd_state, 0); + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, fmt->format.height); + + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.field = V4L2_FIELD_NONE; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + ret = ov2735_set_framing_limits(ov2735, mode); + if (ret) + return ret; + } + + *format = fmt->format; + + /* Initialize crop rectangle */ + crop = v4l2_subdev_state_get_crop(sd_state, 0); + *crop = mode->crop; + + return 0; +} + +static int ov2735_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .format = { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .width = supported_modes[0].width, + .height = supported_modes[0].height, + }, + }; + + ov2735_set_pad_format(sd, state, &fmt); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov2735_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops ov2735_pad_ops = { + .enum_mbus_code = ov2735_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ov2735_set_pad_format, + .get_selection = ov2735_get_selection, + .enum_frame_size = ov2735_enum_frame_size, + .enable_streams = ov2735_enable_streams, + .disable_streams = ov2735_disable_streams, +}; + +static const struct v4l2_subdev_ops ov2735_subdev_ops = { + .video = &ov2735_video_ops, + .pad = &ov2735_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops ov2735_internal_ops = { + .init_state = ov2735_init_state, +}; + +static int ov2735_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2735 *ov2735 = to_ov2735(sd); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ov2735_supply_name), + ov2735->supplies); + if (ret) { + dev_err(ov2735->dev, "failed to enable regulators\n"); + return ret; + } + + gpiod_set_value_cansleep(ov2735->enable_gpio, 1); + /* T4: delay from PWDN pulling low to RSTB pulling high */ + fsleep(4 * USEC_PER_MSEC); + + ret = clk_prepare_enable(ov2735->xclk); + if (ret) { + dev_err(ov2735->dev, "failed to enable clock\n"); + goto err_regulator_off; + } + + gpiod_set_value_cansleep(ov2735->reset_gpio, 0); + /* T5: delay from RSTB pulling high to first I2C command */ + fsleep(5 * USEC_PER_MSEC); + + return 0; + +err_regulator_off: + regulator_bulk_disable(ARRAY_SIZE(ov2735_supply_name), ov2735->supplies); + return ret; +} + +static int ov2735_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2735 *ov2735 = to_ov2735(sd); + + gpiod_set_value_cansleep(ov2735->enable_gpio, 0); + clk_disable_unprepare(ov2735->xclk); + gpiod_set_value_cansleep(ov2735->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ov2735_supply_name), ov2735->supplies); + + return 0; +} + +static int ov2735_get_regulators(struct ov2735 *ov2735) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ov2735_supply_name); i++) + ov2735->supplies[i].supply = ov2735_supply_name[i]; + + return devm_regulator_bulk_get(ov2735->dev, + ARRAY_SIZE(ov2735_supply_name), + ov2735->supplies); +} + +static int ov2735_identify_module(struct ov2735 *ov2735) +{ + u64 chip_id; + int ret; + + ret = ov2735_read(ov2735, OV2735_REG_CHIPID, &chip_id, NULL); + if (ret) + return dev_err_probe(ov2735->dev, ret, + "failed to read chip id %x\n", + OV2735_CHIPID); + + if (chip_id != OV2735_CHIPID) + return dev_err_probe(ov2735->dev, -EIO, + "chip id mismatch: %x!=%llx\n", + OV2735_CHIPID, chip_id); + + return 0; +} + +static int ov2735_parse_endpoint(struct ov2735 *ov2735) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct fwnode_handle *ep; + unsigned long link_freq_bitmap; + int ret; + + ep = fwnode_graph_get_next_endpoint(dev_fwnode(ov2735->dev), NULL); + if (!ep) + return dev_err_probe(ov2735->dev, -ENXIO, + "Failed to get next endpoint\n"); + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { + ret = dev_err_probe(ov2735->dev, -EINVAL, + "only 2 data lanes are supported\n"); + goto error_out; + } + + ret = v4l2_link_freq_to_bitmap(ov2735->dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq_menu_items, + ARRAY_SIZE(link_freq_menu_items), + &link_freq_bitmap); + if (ret) { + ret = dev_err_probe(ov2735->dev, -EINVAL, + "only 420MHz frequency is available\n"); + goto error_out; + } + + ov2735->link_freq_index = __ffs(link_freq_bitmap); + +error_out: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +}; + +static int ov2735_probe(struct i2c_client *client) +{ + struct ov2735 *ov2735; + unsigned int xclk_freq; + int ret; + + ov2735 = devm_kzalloc(&client->dev, sizeof(*ov2735), GFP_KERNEL); + if (!ov2735) + return -ENOMEM; + + ov2735->dev = &client->dev; + + v4l2_i2c_subdev_init(&ov2735->sd, client, &ov2735_subdev_ops); + ov2735->sd.internal_ops = &ov2735_internal_ops; + + ov2735->cci = devm_cci_regmap_init_i2c(client, 8); + if (IS_ERR(ov2735->cci)) + return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->cci), + "failed to initialize CCI\n"); + + /* Set Current page to 0 */ + ov2735->current_page = 0; + + ret = devm_mutex_init(ov2735->dev, &ov2735->page_lock); + if (ret) + return dev_err_probe(ov2735->dev, ret, + "Failed to initialize lock\n"); + + /* Get system clock (xvclk) */ + ov2735->xclk = devm_v4l2_sensor_clk_get(ov2735->dev, NULL); + if (IS_ERR(ov2735->xclk)) + return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->xclk), + "failed to get xclk\n"); + + xclk_freq = clk_get_rate(ov2735->xclk); + if (xclk_freq != OV2735_XCLK_FREQ) + return dev_err_probe(ov2735->dev, -EINVAL, + "xclk frequency not supported: %u Hz\n", + xclk_freq); + + ret = ov2735_get_regulators(ov2735); + if (ret) + return dev_err_probe(ov2735->dev, ret, + "failed to get regulators\n"); + + ret = ov2735_parse_endpoint(ov2735); + if (ret) + return dev_err_probe(ov2735->dev, ret, + "failed to parse endpoint configuration\n"); + + ov2735->reset_gpio = devm_gpiod_get_optional(ov2735->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(ov2735->reset_gpio)) + return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->reset_gpio), + "failed to get reset GPIO\n"); + + ov2735->enable_gpio = devm_gpiod_get_optional(ov2735->dev, + "enable", GPIOD_OUT_LOW); + if (IS_ERR(ov2735->enable_gpio)) + return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->enable_gpio), + "failed to get enable GPIO\n"); + + ret = ov2735_power_on(ov2735->dev); + if (ret) + return ret; + + ret = ov2735_identify_module(ov2735); + if (ret) + goto error_power_off; + + ret = ov2735_init_controls(ov2735); + if (ret) + goto error_power_off; + + /* Initialize subdev */ + ov2735->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov2735->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov2735->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&ov2735->sd.entity, 1, &ov2735->pad); + if (ret) { + dev_err_probe(ov2735->dev, ret, "failed to init entity pads\n"); + goto error_handler_free; + } + + ov2735->sd.state_lock = ov2735->handler.lock; + ret = v4l2_subdev_init_finalize(&ov2735->sd); + if (ret) { + dev_err_probe(ov2735->dev, ret, "subdev init error\n"); + goto error_media_entity; + } + + ret = devm_pm_runtime_get_noresume(ov2735->dev); + if (ret) { + dev_err_probe(ov2735->dev, ret, + "failed to get runtime PM noresume\n"); + goto error_subdev_cleanup; + } + + ret = devm_pm_runtime_set_active_enabled(ov2735->dev); + if (ret) { + dev_err_probe(ov2735->dev, ret, + "failed to set runtime PM active+enabled\n"); + goto error_subdev_cleanup; + } + + ret = v4l2_async_register_subdev_sensor(&ov2735->sd); + if (ret) { + dev_err_probe(ov2735->dev, ret, + "failed to register ov2735 sub-device\n"); + goto error_subdev_cleanup; + } + + return 0; + +error_subdev_cleanup: + v4l2_subdev_cleanup(&ov2735->sd); + +error_media_entity: + media_entity_cleanup(&ov2735->sd.entity); + +error_handler_free: + v4l2_ctrl_handler_free(ov2735->sd.ctrl_handler); + +error_power_off: + ov2735_power_off(ov2735->dev); + + return ret; +} + +static void ov2735_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2735 *ov2735 = to_ov2735(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(&ov2735->sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(ov2735->sd.ctrl_handler); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ov2735_pm_ops, + ov2735_power_off, ov2735_power_on, NULL); + +static const struct of_device_id ov2735_id[] = { + { .compatible = "ovti,ov2735" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov2735_id); + +static struct i2c_driver ov2735_driver = { + .driver = { + .name = "ov2735", + .pm = pm_ptr(&ov2735_pm_ops), + .of_match_table = ov2735_id, + }, + .probe = ov2735_probe, + .remove = ov2735_remove, +}; +module_i2c_driver(ov2735_driver); + +MODULE_DESCRIPTION("OV2735 Camera Sensor Driver"); +MODULE_AUTHOR("Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>"); +MODULE_AUTHOR("Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 4e959534e6e7..fb590dfadda1 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -1,17 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2020 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/pm_runtime.h> #include <linux/nvmem-provider.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -519,6 +519,8 @@ static const struct ov2740_mode supported_modes_180mhz[] = { }; struct ov2740 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -616,7 +618,6 @@ static int ov2740_write_reg(struct ov2740 *ov2740, u16 reg, u16 len, u32 val) static int ov2740_write_reg_list(struct ov2740 *ov2740, const struct ov2740_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); unsigned int i; int ret; @@ -624,7 +625,7 @@ static int ov2740_write_reg_list(struct ov2740 *ov2740, ret = ov2740_write_reg(ov2740, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov2740->dev, "write reg 0x%4.4x return err = %d\n", r_list->regs[i].address, ret); return ret; @@ -636,7 +637,6 @@ static int ov2740_write_reg_list(struct ov2740 *ov2740, static int ov2740_identify_module(struct ov2740 *ov2740) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); int ret; u32 val; @@ -648,12 +648,12 @@ static int ov2740_identify_module(struct ov2740 *ov2740) return ret; if (val != OV2740_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x != %x\n", + dev_err(ov2740->dev, "chip id mismatch: %x != %x\n", OV2740_CHIP_ID, val); return -ENXIO; } - dev_dbg(&client->dev, "chip id: 0x%x\n", val); + dev_dbg(ov2740->dev, "chip id: 0x%x\n", val); ov2740->identified = true; @@ -704,7 +704,6 @@ static int ov2740_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov2740 *ov2740 = container_of(ctrl->handler, struct ov2740, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); s64 exposure_max; int ret; @@ -720,7 +719,7 @@ static int ov2740_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov2740->dev)) return 0; switch (ctrl->id) { @@ -753,7 +752,7 @@ static int ov2740_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov2740->dev); return ret; } @@ -764,7 +763,6 @@ static const struct v4l2_ctrl_ops ov2740_ctrl_ops = { static int ov2740_init_controls(struct ov2740 *ov2740) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max, h_blank, pixel_rate; u32 vblank_min, vblank_max, vblank_default; @@ -821,7 +819,7 @@ static int ov2740_init_controls(struct ov2740 *ov2740) ARRAY_SIZE(ov2740_test_pattern_menu) - 1, 0, 0, ov2740_test_pattern_menu); - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov2740->dev, &props); if (ret) { v4l2_ctrl_handler_free(ctrl_hdlr); return ret; @@ -940,7 +938,6 @@ err: static int ov2740_start_streaming(struct ov2740 *ov2740) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); const struct ov2740_reg_list *reg_list; int link_freq_index; int ret; @@ -955,7 +952,7 @@ static int ov2740_start_streaming(struct ov2740 *ov2740) /* Reset the sensor */ ret = ov2740_write_reg(ov2740, 0x0103, 1, 0x01); if (ret) { - dev_err(&client->dev, "failed to reset\n"); + dev_err(ov2740->dev, "failed to reset\n"); return ret; } @@ -965,14 +962,14 @@ static int ov2740_start_streaming(struct ov2740 *ov2740) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov2740_write_reg_list(ov2740, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls\n"); + dev_err(ov2740->dev, "failed to set plls\n"); return ret; } reg_list = &ov2740->cur_mode->reg_list; ret = ov2740_write_reg_list(ov2740, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode\n"); + dev_err(ov2740->dev, "failed to set mode\n"); return ret; } @@ -983,31 +980,28 @@ static int ov2740_start_streaming(struct ov2740 *ov2740) ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, OV2740_MODE_STREAMING); if (ret) - dev_err(&client->dev, "failed to start streaming\n"); + dev_err(ov2740->dev, "failed to start streaming\n"); return ret; } static void ov2740_stop_streaming(struct ov2740 *ov2740) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); - if (ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, OV2740_MODE_STANDBY)) - dev_err(&client->dev, "failed to stop streaming\n"); + dev_err(ov2740->dev, "failed to stop streaming\n"); } static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) { struct ov2740 *ov2740 = to_ov2740(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); struct v4l2_subdev_state *sd_state; int ret = 0; sd_state = v4l2_subdev_lock_and_get_active_state(&ov2740->sd); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov2740->dev); if (ret < 0) goto out_unlock; @@ -1015,11 +1009,11 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov2740_stop_streaming(ov2740); - pm_runtime_put(&client->dev); + pm_runtime_put(ov2740->dev); } } else { ov2740_stop_streaming(ov2740); - pm_runtime_put(&client->dev); + pm_runtime_put(ov2740->dev); } out_unlock: @@ -1131,16 +1125,14 @@ static const struct media_entity_operations ov2740_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; -static int ov2740_check_hwcfg(struct device *dev) +static int ov2740_check_hwcfg(struct ov2740 *ov2740) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov2740 *ov2740 = to_ov2740(sd); + struct device *dev = ov2740->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret; unsigned int i, j; @@ -1153,20 +1145,6 @@ static int ov2740_check_hwcfg(struct device *dev) return dev_err_probe(dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n"); - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - fwnode_handle_put(ep); - return dev_err_probe(dev, ret, - "reading clock-frequency property\n"); - } - - if (mclk != OV2740_MCLK) { - fwnode_handle_put(ep); - return dev_err_probe(dev, -EINVAL, - "external clock %d is not supported\n", - mclk); - } - ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); if (ret) @@ -1270,7 +1248,7 @@ static int ov2740_register_nvmem(struct i2c_client *client, struct regmap_config regmap_config = { }; struct nvmem_config nvmem_config = { }; struct regmap *regmap; - struct device *dev = &client->dev; + struct device *dev = ov2740->dev; nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL); if (!nvm) @@ -1349,6 +1327,7 @@ static int ov2740_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ov2740 *ov2740; + unsigned long freq; bool full_power; unsigned int i; int ret; @@ -1357,10 +1336,12 @@ static int ov2740_probe(struct i2c_client *client) if (!ov2740) return -ENOMEM; + ov2740->dev = &client->dev; + v4l2_i2c_subdev_init(&ov2740->sd, client, &ov2740_subdev_ops); ov2740->sd.internal_ops = &ov2740_internal_ops; - ret = ov2740_check_hwcfg(dev); + ret = ov2740_check_hwcfg(ov2740); if (ret) return ret; @@ -1384,11 +1365,17 @@ static int ov2740_probe(struct i2c_client *client) msleep(20); } - ov2740->clk = devm_clk_get_optional(dev, "clk"); + ov2740->clk = devm_v4l2_sensor_clk_get(dev, "clk"); if (IS_ERR(ov2740->clk)) return dev_err_probe(dev, PTR_ERR(ov2740->clk), "failed to get clock\n"); + freq = clk_get_rate(ov2740->clk); + if (freq != OV2740_MCLK) + return dev_err_probe(dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + for (i = 0; i < ARRAY_SIZE(ov2740_supply_name); i++) ov2740->supplies[i].supply = ov2740_supply_name[i]; @@ -1397,7 +1384,7 @@ static int ov2740_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "failed to get regulators\n"); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov2740->dev); if (full_power) { /* ACPI does not always clear the reset GPIO / enable the clock */ ret = ov2740_resume(dev); @@ -1435,9 +1422,9 @@ static int ov2740_probe(struct i2c_client *client) /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov2740->dev); + pm_runtime_enable(ov2740->dev); + pm_runtime_idle(ov2740->dev); ret = v4l2_async_register_subdev_sensor(&ov2740->sd); if (ret < 0) { @@ -1447,13 +1434,13 @@ static int ov2740_probe(struct i2c_client *client) ret = ov2740_register_nvmem(client, ov2740); if (ret) - dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret); + dev_warn(ov2740->dev, "register nvmem failed, ret %d\n", ret); return 0; probe_error_v4l2_subdev_cleanup: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov2740->dev); + pm_runtime_set_suspended(ov2740->dev); v4l2_subdev_cleanup(&ov2740->sd); probe_error_media_entity_cleanup: diff --git a/drivers/media/i2c/ov4689.c b/drivers/media/i2c/ov4689.c index 1c3a449f9354..a59d25b09b5b 100644 --- a/drivers/media/i2c/ov4689.c +++ b/drivers/media/i2c/ov4689.c @@ -497,7 +497,6 @@ static int ov4689_s_stream(struct v4l2_subdev *sd, int on) } else { cci_write(ov4689->regmap, OV4689_REG_CTRL_MODE, OV4689_MODE_SW_STANDBY, NULL); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); } @@ -702,7 +701,6 @@ static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -909,20 +907,12 @@ static int ov4689_probe(struct i2c_client *client) ov4689->cur_mode = &supported_modes[OV4689_MODE_2688_1520]; - ov4689->xvclk = devm_clk_get_optional(dev, NULL); + ov4689->xvclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(ov4689->xvclk)) return dev_err_probe(dev, PTR_ERR(ov4689->xvclk), "Failed to get external clock\n"); - if (!ov4689->xvclk) { - dev_dbg(dev, - "No clock provided, using clock-frequency property\n"); - device_property_read_u32(dev, "clock-frequency", - &ov4689->clock_rate); - } else { - ov4689->clock_rate = clk_get_rate(ov4689->xvclk); - } - + ov4689->clock_rate = clk_get_rate(ov4689->xvclk); if (ov4689->clock_rate != OV4689_XVCLK_FREQ) { dev_err(dev, "External clock rate mismatch: got %d Hz, expected %d Hz\n", @@ -999,7 +989,6 @@ static int ov4689_probe(struct i2c_client *client) goto err_clean_subdev_pm; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 0dae0438aa80..85ecc23b3587 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -3341,7 +3341,6 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return 0; @@ -3417,7 +3416,6 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return ret; @@ -3754,7 +3752,6 @@ out: mutex_unlock(&sensor->lock); if (!enable || ret) { - pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); } @@ -3898,11 +3895,10 @@ static int ov5640_probe(struct i2c_client *client) ov5640_dvp_default_fmt; /* get system clock (xclk) */ - sensor->xclk = devm_clk_get(dev, "xclk"); - if (IS_ERR(sensor->xclk)) { - dev_err(dev, "failed to get xclk\n"); - return PTR_ERR(sensor->xclk); - } + sensor->xclk = devm_v4l2_sensor_clk_get(dev, "xclk"); + if (IS_ERR(sensor->xclk)) + return dev_err_probe(dev, PTR_ERR(sensor->xclk), + "failed to get xclk\n"); sensor->xclk_freq = clk_get_rate(sensor->xclk); if (sensor->xclk_freq < OV5640_XCLK_MIN || @@ -3965,7 +3961,6 @@ static int ov5640_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 004d0ee5c3f5..b10d408034a1 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -808,7 +808,6 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); return ret; @@ -979,7 +978,6 @@ static int ov5645_disable_streams(struct v4l2_subdev *sd, OV5645_SYSTEM_CTRL0_STOP); rpm_put: - pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); return ret; @@ -1044,27 +1042,18 @@ static int ov5645_probe(struct i2c_client *client) "invalid bus type, must be CSI2\n"); /* get system clock (xclk) */ - ov5645->xclk = devm_clk_get(dev, NULL); + ov5645->xclk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, false, 0); 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) - return dev_err_probe(dev, ret, - "could not get xclk frequency\n"); - /* external clock must be 24MHz, allow 1% tolerance */ + xclk_freq = clk_get_rate(ov5645->xclk); 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) - 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]; @@ -1196,7 +1185,6 @@ static int ov5645_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index a727beb9d57e..e193fef4fced 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -1398,11 +1398,10 @@ static int ov5647_probe(struct i2c_client *client) } } - sensor->xclk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->xclk)) { - dev_err(dev, "could not get xclk"); - return PTR_ERR(sensor->xclk); - } + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->xclk)) + return dev_err_probe(dev, PTR_ERR(sensor->xclk), + "could not get xclk\n"); xclk_freq = clk_get_rate(sensor->xclk); if (xclk_freq != 25000000) { diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c index 4b86d2631bd1..f0b839cd65f1 100644 --- a/drivers/media/i2c/ov5648.c +++ b/drivers/media/i2c/ov5648.c @@ -1061,8 +1061,8 @@ static int ov5648_sw_standby(struct ov5648_sensor *sensor, int standby) static int ov5648_chip_id_check(struct ov5648_sensor *sensor) { - u16 regs[] = { OV5648_CHIP_ID_H_REG, OV5648_CHIP_ID_L_REG }; - u8 values[] = { OV5648_CHIP_ID_H_VALUE, OV5648_CHIP_ID_L_VALUE }; + static const u16 regs[] = { OV5648_CHIP_ID_H_REG, OV5648_CHIP_ID_L_REG }; + static const u8 values[] = { OV5648_CHIP_ID_H_VALUE, OV5648_CHIP_ID_L_VALUE }; unsigned int i; u8 value; int ret; @@ -2521,10 +2521,10 @@ static int ov5648_probe(struct i2c_client *client) /* External Clock */ - sensor->xvclk = devm_clk_get(dev, NULL); + sensor->xvclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->xvclk)) { - dev_err(dev, "failed to get external clock\n"); - ret = PTR_ERR(sensor->xvclk); + ret = dev_err_probe(dev, PTR_ERR(sensor->xvclk), + "failed to get external clock\n"); goto error_endpoint; } diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index b9efb2d2276a..04b3183b7bcb 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -12,6 +11,8 @@ #include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> @@ -1854,6 +1855,8 @@ static const struct ov5670_mode supported_modes[] = { }; struct ov5670 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_fwnode_endpoint endpoint; @@ -1959,7 +1962,6 @@ static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, static int ov5670_write_regs(struct ov5670 *ov5670, const struct ov5670_reg *regs, unsigned int len) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); unsigned int i; int ret; @@ -1967,7 +1969,7 @@ static int ov5670_write_regs(struct ov5670 *ov5670, ret = ov5670_write_reg(ov5670, regs[i].address, 1, regs[i].val); if (ret) { dev_err_ratelimited( - &client->dev, + ov5670->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -2032,7 +2034,6 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov5670 *ov5670 = container_of(ctrl->handler, struct ov5670, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); s64 max; int ret; @@ -2048,7 +2049,7 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov5670->dev)) return 0; switch (ctrl->id) { @@ -2080,12 +2081,12 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) break; default: ret = -EINVAL; - dev_info(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", + dev_info(ov5670->dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov5670->dev); return ret; } @@ -2099,7 +2100,6 @@ static int ov5670_init_controls(struct ov5670 *ov5670) { struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 = &ov5670->endpoint.bus.mipi_csi2; - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; unsigned int lanes_count; @@ -2177,7 +2177,7 @@ static int ov5670_init_controls(struct ov5670 *ov5670) goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov5670->dev, &props); if (ret) goto error; @@ -2350,7 +2350,6 @@ static int ov5670_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) /* Verify chip ID */ static int ov5670_identify_module(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); int ret; u32 val; @@ -2363,7 +2362,7 @@ static int ov5670_identify_module(struct ov5670 *ov5670) return ret; if (val != OV5670_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov5670->dev, "chip id mismatch: %x!=%x\n", OV5670_CHIP_ID, val); return -ENXIO; } @@ -2389,7 +2388,6 @@ static int ov5670_mipi_configure(struct ov5670 *ov5670) /* Prepare streaming by writing default values and customized values */ static int ov5670_start_streaming(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); const struct ov5670_reg_list *reg_list; int link_freq_index; int ret; @@ -2402,7 +2400,7 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) ret = ov5670_write_reg(ov5670, OV5670_REG_SOFTWARE_RST, OV5670_REG_VALUE_08BIT, OV5670_SOFTWARE_RST); if (ret) { - dev_err(&client->dev, "%s failed to set powerup registers\n", + dev_err(ov5670->dev, "%s failed to set powerup registers\n", __func__); return ret; } @@ -2412,7 +2410,7 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov5670_write_reg_list(ov5670, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(ov5670->dev, "%s failed to set plls\n", __func__); return ret; } @@ -2420,13 +2418,13 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) reg_list = &ov5670->cur_mode->reg_list; ret = ov5670_write_reg_list(ov5670, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(ov5670->dev, "%s failed to set mode\n", __func__); return ret; } ret = ov5670_mipi_configure(ov5670); if (ret) { - dev_err(&client->dev, "%s failed to configure MIPI\n", __func__); + dev_err(ov5670->dev, "%s failed to configure MIPI\n", __func__); return ret; } @@ -2438,7 +2436,7 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) ret = ov5670_write_reg(ov5670, OV5670_REG_MODE_SELECT, OV5670_REG_VALUE_08BIT, OV5670_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "%s failed to set stream\n", __func__); + dev_err(ov5670->dev, "%s failed to set stream\n", __func__); return ret; } @@ -2447,13 +2445,12 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) static int ov5670_stop_streaming(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); int ret; ret = ov5670_write_reg(ov5670, OV5670_REG_MODE_SELECT, OV5670_REG_VALUE_08BIT, OV5670_MODE_STANDBY); if (ret) - dev_err(&client->dev, "%s failed to set stream\n", __func__); + dev_err(ov5670->dev, "%s failed to set stream\n", __func__); /* Return success even if it was an error, as there is nothing the * caller can do about it. @@ -2464,13 +2461,12 @@ static int ov5670_stop_streaming(struct ov5670 *ov5670) static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) { struct ov5670 *ov5670 = to_ov5670(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov5670->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov5670->dev); if (ret < 0) goto unlock_and_return; @@ -2479,12 +2475,12 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) goto error; } else { ret = ov5670_stop_streaming(ov5670); - pm_runtime_put(&client->dev); + pm_runtime_put(ov5670->dev); } goto unlock_and_return; error: - pm_runtime_put(&client->dev); + pm_runtime_put(ov5670->dev); unlock_and_return: mutex_unlock(&ov5670->mutex); @@ -2621,26 +2617,23 @@ static const struct media_entity_operations ov5670_subdev_entity_ops = { static int ov5670_regulators_probe(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); unsigned int i; for (i = 0; i < OV5670_NUM_SUPPLIES; i++) ov5670->supplies[i].supply = ov5670_supply_names[i]; - return devm_regulator_bulk_get(&client->dev, OV5670_NUM_SUPPLIES, + return devm_regulator_bulk_get(ov5670->dev, OV5670_NUM_SUPPLIES, ov5670->supplies); } static int ov5670_gpio_probe(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); - - ov5670->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", + ov5670->pwdn_gpio = devm_gpiod_get_optional(ov5670->dev, "powerdown", GPIOD_OUT_LOW); if (IS_ERR(ov5670->pwdn_gpio)) return PTR_ERR(ov5670->pwdn_gpio); - ov5670->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + ov5670->reset_gpio = devm_gpiod_get_optional(ov5670->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ov5670->reset_gpio)) return PTR_ERR(ov5670->reset_gpio); @@ -2660,18 +2653,16 @@ static int ov5670_probe(struct i2c_client *client) if (!ov5670) return -ENOMEM; - ov5670->xvclk = devm_clk_get_optional(&client->dev, NULL); - if (!IS_ERR_OR_NULL(ov5670->xvclk)) - input_clk = clk_get_rate(ov5670->xvclk); - else if (!ov5670->xvclk || PTR_ERR(ov5670->xvclk) == -ENOENT) - device_property_read_u32(&client->dev, "clock-frequency", - &input_clk); - else - return dev_err_probe(&client->dev, PTR_ERR(ov5670->xvclk), + ov5670->dev = &client->dev; + + ov5670->xvclk = devm_v4l2_sensor_clk_get(ov5670->dev, NULL); + if (IS_ERR(ov5670->xvclk)) + return dev_err_probe(ov5670->dev, PTR_ERR(ov5670->xvclk), "error getting clock\n"); + input_clk = clk_get_rate(ov5670->xvclk); if (input_clk != OV5670_XVCLK_FREQ) { - dev_err(&client->dev, + dev_err(ov5670->dev, "Unsupported clock frequency %u\n", input_clk); return -EINVAL; } @@ -2682,20 +2673,20 @@ static int ov5670_probe(struct i2c_client *client) ret = ov5670_regulators_probe(ov5670); if (ret) - return dev_err_probe(&client->dev, ret, "Regulators probe failed\n"); + return dev_err_probe(ov5670->dev, ret, "Regulators probe failed\n"); ret = ov5670_gpio_probe(ov5670); if (ret) - return dev_err_probe(&client->dev, ret, "GPIO probe failed\n"); + return dev_err_probe(ov5670->dev, ret, "GPIO probe failed\n"); /* * Graph Endpoint. If it's missing we defer rather than fail, as this * sensor is known to co-exist on systems with the IPU3 and so it might * be created by the ipu-bridge. */ - handle = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); + handle = fwnode_graph_get_next_endpoint(dev_fwnode(ov5670->dev), NULL); if (!handle) - return dev_err_probe(&client->dev, -EPROBE_DEFER, + return dev_err_probe(ov5670->dev, -EPROBE_DEFER, "Endpoint for node get failed\n"); ov5670->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; @@ -2704,20 +2695,20 @@ static int ov5670_probe(struct i2c_client *client) ret = v4l2_fwnode_endpoint_alloc_parse(handle, &ov5670->endpoint); fwnode_handle_put(handle); if (ret) - return dev_err_probe(&client->dev, ret, "Endpoint parse failed\n"); + return dev_err_probe(ov5670->dev, ret, "Endpoint parse failed\n"); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov5670->dev); if (full_power) { - ret = ov5670_runtime_resume(&client->dev); + ret = ov5670_runtime_resume(ov5670->dev); if (ret) { - dev_err_probe(&client->dev, ret, "Power up failed\n"); + dev_err_probe(ov5670->dev, ret, "Power up failed\n"); goto error_endpoint; } /* Check module identity */ ret = ov5670_identify_module(ov5670); if (ret) { - dev_err_probe(&client->dev, ret, "ov5670_identify_module() error\n"); + dev_err_probe(ov5670->dev, ret, "ov5670_identify_module() error\n"); goto error_power_off; } } @@ -2729,7 +2720,7 @@ static int ov5670_probe(struct i2c_client *client) ret = ov5670_init_controls(ov5670); if (ret) { - dev_err_probe(&client->dev, ret, "ov5670_init_controls() error\n"); + dev_err_probe(ov5670->dev, ret, "ov5670_init_controls() error\n"); goto error_mutex_destroy; } @@ -2742,28 +2733,28 @@ static int ov5670_probe(struct i2c_client *client) ov5670->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov5670->sd.entity, 1, &ov5670->pad); if (ret) { - dev_err_probe(&client->dev, ret, "media_entity_pads_init() error\n"); + dev_err_probe(ov5670->dev, ret, "media_entity_pads_init() error\n"); goto error_handler_free; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_active(ov5670->dev); + pm_runtime_enable(ov5670->dev); /* Async register for subdev */ ret = v4l2_async_register_subdev_sensor(&ov5670->sd); if (ret < 0) { - dev_err_probe(&client->dev, ret, "v4l2_async_register_subdev() error\n"); + dev_err_probe(ov5670->dev, ret, "v4l2_async_register_subdev() error\n"); goto error_pm_disable; } - pm_runtime_idle(&client->dev); + pm_runtime_idle(ov5670->dev); return 0; error_pm_disable: - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov5670->dev); media_entity_cleanup(&ov5670->sd.entity); @@ -2775,7 +2766,7 @@ error_mutex_destroy: error_power_off: if (full_power) - ov5670_runtime_suspend(&client->dev); + ov5670_runtime_suspend(ov5670->dev); error_endpoint: v4l2_fwnode_endpoint_free(&ov5670->endpoint); @@ -2793,8 +2784,8 @@ static void ov5670_remove(struct i2c_client *client) v4l2_ctrl_handler_free(sd->ctrl_handler); mutex_destroy(&ov5670->mutex); - pm_runtime_disable(&client->dev); - ov5670_runtime_suspend(&client->dev); + pm_runtime_disable(ov5670->dev); + ov5670_runtime_suspend(ov5670->dev); v4l2_fwnode_endpoint_free(&ov5670->endpoint); } diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index e7aec281e9a4..ea26df328189 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -11,6 +10,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -493,6 +494,8 @@ static const struct ov5675_mode supported_modes[] = { }; struct ov5675 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -584,7 +587,6 @@ static int ov5675_write_reg(struct ov5675 *ov5675, u16 reg, u16 len, u32 val) static int ov5675_write_reg_list(struct ov5675 *ov5675, const struct ov5675_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); unsigned int i; int ret; @@ -592,7 +594,7 @@ static int ov5675_write_reg_list(struct ov5675 *ov5675, ret = ov5675_write_reg(ov5675, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov5675->dev, "failed to write reg 0x%4.4x. error = %d", r_list->regs[i].address, ret); return ret; @@ -700,7 +702,6 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov5675 *ov5675 = container_of(ctrl->handler, struct ov5675, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); s64 exposure_max; int ret = 0; @@ -716,7 +717,7 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov5675->dev)) return 0; switch (ctrl->id) { @@ -765,7 +766,7 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov5675->dev); return ret; } @@ -776,7 +777,6 @@ static const struct v4l2_ctrl_ops ov5675_ctrl_ops = { static int ov5675_init_controls(struct ov5675 *ov5675) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max, h_blank; @@ -839,7 +839,7 @@ static int ov5675_init_controls(struct ov5675 *ov5675) return ctrl_hdlr->error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov5675->dev, &props); if (ret) goto error; @@ -869,7 +869,6 @@ static void ov5675_update_pad_format(const struct ov5675_mode *mode, static int ov5675_identify_module(struct ov5675 *ov5675) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); int ret; u32 val; @@ -882,7 +881,7 @@ static int ov5675_identify_module(struct ov5675 *ov5675) return ret; if (val != OV5675_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(ov5675->dev, "chip id mismatch: %x!=%x", OV5675_CHIP_ID, val); return -ENXIO; } @@ -894,7 +893,6 @@ static int ov5675_identify_module(struct ov5675 *ov5675) static int ov5675_start_streaming(struct ov5675 *ov5675) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); const struct ov5675_reg_list *reg_list; int link_freq_index, ret; @@ -906,14 +904,14 @@ static int ov5675_start_streaming(struct ov5675 *ov5675) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov5675_write_reg_list(ov5675, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(ov5675->dev, "failed to set plls"); return ret; } reg_list = &ov5675->cur_mode->reg_list; ret = ov5675_write_reg_list(ov5675, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(ov5675->dev, "failed to set mode"); return ret; } @@ -924,7 +922,7 @@ static int ov5675_start_streaming(struct ov5675 *ov5675) ret = ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT, OV5675_REG_VALUE_08BIT, OV5675_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream"); + dev_err(ov5675->dev, "failed to set stream"); return ret; } @@ -933,22 +931,19 @@ static int ov5675_start_streaming(struct ov5675 *ov5675) static void ov5675_stop_streaming(struct ov5675 *ov5675) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); - if (ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT, OV5675_REG_VALUE_08BIT, OV5675_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream"); + dev_err(ov5675->dev, "failed to set stream"); } static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) { struct ov5675 *ov5675 = to_ov5675(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov5675->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov5675->dev); if (ret < 0) { mutex_unlock(&ov5675->mutex); return ret; @@ -958,11 +953,11 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov5675_stop_streaming(ov5675); - pm_runtime_put(&client->dev); + pm_runtime_put(ov5675->dev); } } else { ov5675_stop_streaming(ov5675); - pm_runtime_put(&client->dev); + pm_runtime_put(ov5675->dev); } mutex_unlock(&ov5675->mutex); @@ -1171,8 +1166,9 @@ static const struct v4l2_subdev_internal_ops ov5675_internal_ops = { .open = ov5675_open, }; -static int ov5675_get_hwcfg(struct ov5675 *ov5675, struct device *dev) +static int ov5675_get_hwcfg(struct ov5675 *ov5675) { + struct device *dev = ov5675->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { @@ -1185,24 +1181,13 @@ static int ov5675_get_hwcfg(struct ov5675 *ov5675, struct device *dev) if (!fwnode) return -ENXIO; - ov5675->xvclk = devm_clk_get_optional(dev, NULL); + ov5675->xvclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(ov5675->xvclk)) return dev_err_probe(dev, PTR_ERR(ov5675->xvclk), - "failed to get xvclk: %ld\n", - PTR_ERR(ov5675->xvclk)); - - if (ov5675->xvclk) { - xvclk_rate = clk_get_rate(ov5675->xvclk); - } else { - ret = fwnode_property_read_u32(fwnode, "clock-frequency", - &xvclk_rate); - - if (ret) { - dev_err(dev, "can't get clock frequency"); - return ret; - } - } + "failed to get xvclk: %pe\n", + ov5675->xvclk); + xvclk_rate = clk_get_rate(ov5675->xvclk); if (xvclk_rate != OV5675_XVCLK_19_2) { dev_err(dev, "external clock rate %u is unsupported", xvclk_rate); @@ -1276,12 +1261,12 @@ static void ov5675_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov5675->dev); mutex_destroy(&ov5675->mutex); - if (!pm_runtime_status_suspended(&client->dev)) - ov5675_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + if (!pm_runtime_status_suspended(ov5675->dev)) + ov5675_power_off(ov5675->dev); + pm_runtime_set_suspended(ov5675->dev); } static int ov5675_probe(struct i2c_client *client) @@ -1294,23 +1279,25 @@ static int ov5675_probe(struct i2c_client *client) if (!ov5675) return -ENOMEM; - ret = ov5675_get_hwcfg(ov5675, &client->dev); + ov5675->dev = &client->dev; + + ret = ov5675_get_hwcfg(ov5675); if (ret) return ret; v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops); - ret = ov5675_power_on(&client->dev); + ret = ov5675_power_on(ov5675->dev); if (ret) { - dev_err(&client->dev, "failed to power on: %d\n", ret); + dev_err(ov5675->dev, "failed to power on: %d\n", ret); return ret; } - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov5675->dev); if (full_power) { ret = ov5675_identify_module(ov5675); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov5675->dev, "failed to find sensor: %d", ret); goto probe_power_off; } } @@ -1319,7 +1306,7 @@ static int ov5675_probe(struct i2c_client *client) ov5675->cur_mode = &supported_modes[0]; ret = ov5675_init_controls(ov5675); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov5675->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -1330,22 +1317,22 @@ static int ov5675_probe(struct i2c_client *client) ov5675->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov5675->sd.entity, 1, &ov5675->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov5675->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&ov5675->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov5675->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov5675->dev); + pm_runtime_enable(ov5675->dev); + pm_runtime_idle(ov5675->dev); return 0; @@ -1356,7 +1343,7 @@ probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov5675->sd.ctrl_handler); mutex_destroy(&ov5675->mutex); probe_power_off: - ov5675_power_off(&client->dev); + ov5675_power_off(ov5675->dev); return ret; } diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c index 485efd15257e..4cc796bbee92 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -1289,25 +1289,13 @@ static int ov5693_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&ov5693->sd, client, &ov5693_ops); - ov5693->xvclk = devm_clk_get_optional(&client->dev, "xvclk"); + ov5693->xvclk = devm_v4l2_sensor_clk_get(&client->dev, "xvclk"); if (IS_ERR(ov5693->xvclk)) return dev_err_probe(&client->dev, PTR_ERR(ov5693->xvclk), - "failed to get xvclk: %ld\n", - PTR_ERR(ov5693->xvclk)); - - if (ov5693->xvclk) { - xvclk_rate = clk_get_rate(ov5693->xvclk); - } else { - ret = fwnode_property_read_u32(dev_fwnode(&client->dev), - "clock-frequency", - &xvclk_rate); - - if (ret) { - dev_err(&client->dev, "can't get clock frequency"); - return ret; - } - } + "failed to get xvclk: %pe\n", + ov5693->xvclk); + xvclk_rate = clk_get_rate(ov5693->xvclk); if (xvclk_rate != OV5693_XVCLK_FREQ) dev_warn(&client->dev, "Found clk freq %u, expected %u\n", xvclk_rate, OV5693_XVCLK_FREQ); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 663eccdfea6a..5bb6ce7b3237 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1264,16 +1264,12 @@ static int ov5695_probe(struct i2c_client *client) ov5695->client = client; ov5695->cur_mode = &supported_modes[0]; - ov5695->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(ov5695->xvclk)) { - dev_err(dev, "Failed to get xvclk\n"); - return -EINVAL; - } - ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ); - if (ret < 0) { - dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); - return ret; - } + ov5695->xvclk = devm_v4l2_sensor_clk_get_legacy(dev, "xvclk", true, + OV5695_XVCLK_FREQ); + if (IS_ERR(ov5695->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov5695->xvclk), + "Failed to get xvclk\n"); + if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ) dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); diff --git a/drivers/media/i2c/ov6211.c b/drivers/media/i2c/ov6211.c new file mode 100644 index 000000000000..e3ac5ecf27d1 --- /dev/null +++ b/drivers/media/i2c/ov6211.c @@ -0,0 +1,793 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2024-2025 Linaro Ltd + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/units.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define OV6211_LINK_FREQ_480MHZ (480 * HZ_PER_MHZ) +#define OV6211_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ) + +#define OV6211_REG_CHIP_ID CCI_REG16(0x300a) +#define OV6211_CHIP_ID 0x6710 + +#define OV6211_REG_MODE_SELECT CCI_REG8(0x0100) +#define OV6211_MODE_STANDBY 0x00 +#define OV6211_MODE_STREAMING BIT(0) + +#define OV6211_REG_SOFTWARE_RST CCI_REG8(0x0103) +#define OV6211_SOFTWARE_RST BIT(0) + +/* Exposure controls from sensor */ +#define OV6211_REG_EXPOSURE CCI_REG24(0x3500) +#define OV6211_EXPOSURE_MIN 1 +#define OV6211_EXPOSURE_MAX_MARGIN 4 +#define OV6211_EXPOSURE_STEP 1 +#define OV6211_EXPOSURE_DEFAULT 210 + +/* Analogue gain controls from sensor */ +#define OV6211_REG_ANALOGUE_GAIN CCI_REG16(0x350a) +#define OV6211_ANALOGUE_GAIN_MIN 1 +#define OV6211_ANALOGUE_GAIN_MAX 0x3ff +#define OV6211_ANALOGUE_GAIN_STEP 1 +#define OV6211_ANALOGUE_GAIN_DEFAULT 160 + +/* Test pattern */ +#define OV6211_REG_PRE_ISP CCI_REG8(0x5e00) +#define OV6211_TEST_PATTERN_ENABLE BIT(7) + +#define to_ov6211(_sd) container_of(_sd, struct ov6211, sd) + +static const s64 ov6211_link_freq_menu[] = { + OV6211_LINK_FREQ_480MHZ, +}; + +struct ov6211_reg_list { + const struct cci_reg_sequence *regs; + unsigned int num_regs; +}; + +struct ov6211_mode { + u32 width; /* Frame width in pixels */ + u32 height; /* Frame height in pixels */ + u32 hts; /* Horizontal timing size */ + u32 vts; /* Default vertical timing size */ + u32 bpp; /* Bits per pixel */ + + const struct ov6211_reg_list reg_list; /* Sensor register setting */ +}; + +static const char * const ov6211_test_pattern_menu[] = { + "Disabled", + "Vertical Colour Bars", +}; + +static const char * const ov6211_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OV6211_NUM_SUPPLIES ARRAY_SIZE(ov6211_supply_names) + +struct ov6211 { + struct device *dev; + struct regmap *regmap; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OV6211_NUM_SUPPLIES]; + + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + + /* Saved register values */ + u64 pre_isp; +}; + +static const struct cci_reg_sequence ov6211_400x400_120fps_mode[] = { + { CCI_REG8(0x3005), 0x00 }, + { CCI_REG8(0x3013), 0x12 }, + { CCI_REG8(0x3014), 0x04 }, + { CCI_REG8(0x3016), 0x10 }, + { CCI_REG8(0x3017), 0x00 }, + { CCI_REG8(0x3018), 0x00 }, + { CCI_REG8(0x301a), 0x00 }, + { CCI_REG8(0x301b), 0x00 }, + { CCI_REG8(0x301c), 0x00 }, + { CCI_REG8(0x3037), 0xf0 }, + { CCI_REG8(0x3080), 0x01 }, + { CCI_REG8(0x3081), 0x00 }, + { CCI_REG8(0x3082), 0x01 }, + { CCI_REG8(0x3098), 0x04 }, + { CCI_REG8(0x3099), 0x28 }, + { CCI_REG8(0x309a), 0x06 }, + { CCI_REG8(0x309b), 0x04 }, + { CCI_REG8(0x309c), 0x00 }, + { CCI_REG8(0x309d), 0x00 }, + { CCI_REG8(0x309e), 0x01 }, + { CCI_REG8(0x309f), 0x00 }, + { CCI_REG8(0x30b0), 0x08 }, + { CCI_REG8(0x30b1), 0x02 }, + { CCI_REG8(0x30b2), 0x00 }, + { CCI_REG8(0x30b3), 0x28 }, + { CCI_REG8(0x30b4), 0x02 }, + { CCI_REG8(0x30b5), 0x00 }, + { CCI_REG8(0x3106), 0xd9 }, + { CCI_REG8(0x3503), 0x07 }, + { CCI_REG8(0x3509), 0x10 }, + { CCI_REG8(0x3600), 0xfc }, + { CCI_REG8(0x3620), 0xb7 }, + { CCI_REG8(0x3621), 0x05 }, + { CCI_REG8(0x3626), 0x31 }, + { CCI_REG8(0x3627), 0x40 }, + { CCI_REG8(0x3632), 0xa3 }, + { CCI_REG8(0x3633), 0x34 }, + { CCI_REG8(0x3634), 0x40 }, + { CCI_REG8(0x3636), 0x00 }, + { CCI_REG8(0x3660), 0x80 }, + { CCI_REG8(0x3662), 0x03 }, + { CCI_REG8(0x3664), 0xf0 }, + { CCI_REG8(0x366a), 0x10 }, + { CCI_REG8(0x366b), 0x06 }, + { CCI_REG8(0x3680), 0xf4 }, + { CCI_REG8(0x3681), 0x50 }, + { CCI_REG8(0x3682), 0x00 }, + { CCI_REG8(0x3708), 0x20 }, + { CCI_REG8(0x3709), 0x40 }, + { CCI_REG8(0x370d), 0x03 }, + { CCI_REG8(0x373b), 0x02 }, + { CCI_REG8(0x373c), 0x08 }, + { CCI_REG8(0x3742), 0x00 }, + { CCI_REG8(0x3744), 0x16 }, + { CCI_REG8(0x3745), 0x08 }, + { CCI_REG8(0x3781), 0xfc }, + { CCI_REG8(0x3788), 0x00 }, + { CCI_REG8(0x3800), 0x00 }, + { CCI_REG8(0x3801), 0x04 }, + { CCI_REG8(0x3802), 0x00 }, + { CCI_REG8(0x3803), 0x04 }, + { CCI_REG8(0x3804), 0x01 }, + { CCI_REG8(0x3805), 0x9b }, + { CCI_REG8(0x3806), 0x01 }, + { CCI_REG8(0x3807), 0x9b }, + { CCI_REG8(0x3808), 0x01 }, /* output width */ + { CCI_REG8(0x3809), 0x90 }, + { CCI_REG8(0x380a), 0x01 }, /* output height */ + { CCI_REG8(0x380b), 0x90 }, + { CCI_REG8(0x380c), 0x05 }, /* horizontal timing size */ + { CCI_REG8(0x380d), 0xf2 }, + { CCI_REG8(0x380e), 0x01 }, /* vertical timing size */ + { CCI_REG8(0x380f), 0xb6 }, + { CCI_REG8(0x3810), 0x00 }, + { CCI_REG8(0x3811), 0x04 }, + { CCI_REG8(0x3812), 0x00 }, + { CCI_REG8(0x3813), 0x04 }, + { CCI_REG8(0x3814), 0x11 }, + { CCI_REG8(0x3815), 0x11 }, + { CCI_REG8(0x3820), 0x00 }, + { CCI_REG8(0x3821), 0x00 }, + { CCI_REG8(0x382b), 0xfa }, + { CCI_REG8(0x382f), 0x04 }, + { CCI_REG8(0x3832), 0x00 }, + { CCI_REG8(0x3833), 0x05 }, + { CCI_REG8(0x3834), 0x00 }, + { CCI_REG8(0x3835), 0x05 }, + { CCI_REG8(0x3882), 0x04 }, + { CCI_REG8(0x3883), 0x00 }, + { CCI_REG8(0x38a4), 0x10 }, + { CCI_REG8(0x38a5), 0x00 }, + { CCI_REG8(0x38b1), 0x03 }, + { CCI_REG8(0x3b80), 0x00 }, + { CCI_REG8(0x3b81), 0xff }, + { CCI_REG8(0x3b82), 0x10 }, + { CCI_REG8(0x3b83), 0x00 }, + { CCI_REG8(0x3b84), 0x08 }, + { CCI_REG8(0x3b85), 0x00 }, + { CCI_REG8(0x3b86), 0x01 }, + { CCI_REG8(0x3b87), 0x00 }, + { CCI_REG8(0x3b88), 0x00 }, + { CCI_REG8(0x3b89), 0x00 }, + { CCI_REG8(0x3b8a), 0x00 }, + { CCI_REG8(0x3b8b), 0x05 }, + { CCI_REG8(0x3b8c), 0x00 }, + { CCI_REG8(0x3b8d), 0x00 }, + { CCI_REG8(0x3b8e), 0x01 }, + { CCI_REG8(0x3b8f), 0xb2 }, + { CCI_REG8(0x3b94), 0x05 }, + { CCI_REG8(0x3b95), 0xf2 }, + { CCI_REG8(0x3b96), 0xc0 }, + { CCI_REG8(0x4004), 0x04 }, + { CCI_REG8(0x404e), 0x01 }, + { CCI_REG8(0x4801), 0x0f }, + { CCI_REG8(0x4806), 0x0f }, + { CCI_REG8(0x4837), 0x43 }, + { CCI_REG8(0x5a08), 0x00 }, + { CCI_REG8(0x5a01), 0x00 }, + { CCI_REG8(0x5a03), 0x00 }, + { CCI_REG8(0x5a04), 0x10 }, + { CCI_REG8(0x5a05), 0xa0 }, + { CCI_REG8(0x5a06), 0x0c }, + { CCI_REG8(0x5a07), 0x78 }, +}; + +static const struct ov6211_mode supported_modes[] = { + { + .width = 400, + .height = 400, + .hts = 1522, + .vts = 438, + .bpp = 8, + .reg_list = { + .regs = ov6211_400x400_120fps_mode, + .num_regs = ARRAY_SIZE(ov6211_400x400_120fps_mode), + }, + }, +}; + +static int ov6211_set_test_pattern(struct ov6211 *ov6211, u32 pattern) +{ + u64 val = ov6211->pre_isp; + + if (pattern) + val |= OV6211_TEST_PATTERN_ENABLE; + else + val &= ~OV6211_TEST_PATTERN_ENABLE; + + return cci_write(ov6211->regmap, OV6211_REG_PRE_ISP, val, NULL); +} + +static int ov6211_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov6211 *ov6211 = container_of(ctrl->handler, struct ov6211, + ctrl_handler); + int ret; + + /* V4L2 controls are applied, when sensor is powered up for streaming */ + if (!pm_runtime_get_if_active(ov6211->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = cci_write(ov6211->regmap, OV6211_REG_ANALOGUE_GAIN, + ctrl->val, NULL); + break; + case V4L2_CID_EXPOSURE: + ret = cci_write(ov6211->regmap, OV6211_REG_EXPOSURE, + ctrl->val << 4, NULL); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov6211_set_test_pattern(ov6211, ctrl->val); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(ov6211->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov6211_ctrl_ops = { + .s_ctrl = ov6211_set_ctrl, +}; + +static int ov6211_init_controls(struct ov6211 *ov6211) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &ov6211->ctrl_handler; + const struct ov6211_mode *mode = &supported_modes[0]; + struct v4l2_fwnode_device_properties props; + s64 exposure_max, pixel_rate, h_blank; + struct v4l2_ctrl *ctrl; + int ret; + + v4l2_ctrl_handler_init(ctrl_hdlr, 9); + + ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov6211_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(ov6211_link_freq_menu) - 1, + 0, ov6211_link_freq_menu); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + pixel_rate = ov6211_link_freq_menu[0] / mode->bpp; + v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_PIXEL_RATE, + 0, pixel_rate, 1, pixel_rate); + + h_blank = mode->hts - mode->width; + ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_VBLANK, + mode->vts - mode->height, + mode->vts - mode->height, 1, + mode->vts - mode->height); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OV6211_ANALOGUE_GAIN_MIN, OV6211_ANALOGUE_GAIN_MAX, + OV6211_ANALOGUE_GAIN_STEP, + OV6211_ANALOGUE_GAIN_DEFAULT); + + exposure_max = (mode->vts - OV6211_EXPOSURE_MAX_MARGIN); + v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, + V4L2_CID_EXPOSURE, + OV6211_EXPOSURE_MIN, exposure_max, + OV6211_EXPOSURE_STEP, + OV6211_EXPOSURE_DEFAULT); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov6211_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov6211_test_pattern_menu) - 1, + 0, 0, ov6211_test_pattern_menu); + + if (ctrl_hdlr->error) + return ctrl_hdlr->error; + + ret = v4l2_fwnode_device_parse(ov6211->dev, &props); + if (ret) + goto error_free_hdlr; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov6211_ctrl_ops, + &props); + if (ret) + goto error_free_hdlr; + + ov6211->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error_free_hdlr: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; +} + +static void ov6211_update_pad_format(const struct ov6211_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->code = MEDIA_BUS_FMT_Y8_1X8; + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_RAW; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_XFER_FUNC_NONE; +} + +static int ov6211_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + const struct ov6211_reg_list *reg_list = &supported_modes[0].reg_list; + struct ov6211 *ov6211 = to_ov6211(sd); + int ret; + + ret = pm_runtime_resume_and_get(ov6211->dev); + if (ret) + return ret; + + /* Skip a step of explicit entering into the standby mode */ + ret = cci_write(ov6211->regmap, OV6211_REG_SOFTWARE_RST, + OV6211_SOFTWARE_RST, NULL); + if (ret) { + dev_err(ov6211->dev, "failed to software reset: %d\n", ret); + goto error; + } + + ret = cci_multi_reg_write(ov6211->regmap, reg_list->regs, + reg_list->num_regs, NULL); + if (ret) { + dev_err(ov6211->dev, "failed to set mode: %d\n", ret); + goto error; + } + + ret = __v4l2_ctrl_handler_setup(ov6211->sd.ctrl_handler); + if (ret) + goto error; + + ret = cci_write(ov6211->regmap, OV6211_REG_MODE_SELECT, + OV6211_MODE_STREAMING, NULL); + if (ret) { + dev_err(ov6211->dev, "failed to start streaming: %d\n", ret); + goto error; + } + + return 0; + +error: + pm_runtime_put_autosuspend(ov6211->dev); + + return ret; +} + +static int ov6211_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ov6211 *ov6211 = to_ov6211(sd); + int ret; + + ret = cci_write(ov6211->regmap, OV6211_REG_MODE_SELECT, + OV6211_MODE_STANDBY, NULL); + if (ret) + dev_err(ov6211->dev, "failed to stop streaming: %d\n", ret); + + pm_runtime_put_autosuspend(ov6211->dev); + + return ret; +} + +static int ov6211_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *format; + const struct ov6211_mode *mode; + + format = v4l2_subdev_state_get_format(state, 0); + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, + fmt->format.height); + + ov6211_update_pad_format(mode, &fmt->format); + *format = fmt->format; + + return 0; +} + +static int ov6211_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_Y8_1X8; + + return 0; +} + +static int ov6211_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_Y8_1X8) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int ov6211_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .pad = 0, + .format = { + .code = MEDIA_BUS_FMT_Y8_1X8, + .width = supported_modes[0].width, + .height = supported_modes[0].height, + }, + }; + + ov6211_set_pad_format(sd, state, &fmt); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov6211_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops ov6211_pad_ops = { + .set_fmt = ov6211_set_pad_format, + .get_fmt = v4l2_subdev_get_fmt, + .enum_mbus_code = ov6211_enum_mbus_code, + .enum_frame_size = ov6211_enum_frame_size, + .enable_streams = ov6211_enable_streams, + .disable_streams = ov6211_disable_streams, +}; + +static const struct v4l2_subdev_ops ov6211_subdev_ops = { + .video = &ov6211_video_ops, + .pad = &ov6211_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops ov6211_internal_ops = { + .init_state = ov6211_init_state, +}; + +static const struct media_entity_operations ov6211_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int ov6211_identify_sensor(struct ov6211 *ov6211) +{ + u64 val; + int ret; + + ret = cci_read(ov6211->regmap, OV6211_REG_CHIP_ID, &val, NULL); + if (ret) { + dev_err(ov6211->dev, "failed to read chip id: %d\n", ret); + return ret; + } + + if (val != OV6211_CHIP_ID) { + dev_err(ov6211->dev, "chip id mismatch: %x!=%llx\n", + OV6211_CHIP_ID, val); + return -ENODEV; + } + + ret = cci_read(ov6211->regmap, OV6211_REG_PRE_ISP, + &ov6211->pre_isp, NULL); + if (ret) + dev_err(ov6211->dev, "failed to read pre_isp: %d\n", ret); + + return ret; +} + +static int ov6211_check_hwcfg(struct ov6211 *ov6211) +{ + struct fwnode_handle *fwnode = dev_fwnode(ov6211->dev), *ep; + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + unsigned long freq_bitmap; + int ret; + + if (!fwnode) + return -ENODEV; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -EINVAL; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + ret = v4l2_link_freq_to_bitmap(ov6211->dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + ov6211_link_freq_menu, + ARRAY_SIZE(ov6211_link_freq_menu), + &freq_bitmap); + + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int ov6211_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov6211 *ov6211 = to_ov6211(sd); + int ret; + + ret = regulator_bulk_enable(OV6211_NUM_SUPPLIES, ov6211->supplies); + if (ret) + return ret; + + gpiod_set_value_cansleep(ov6211->reset_gpio, 0); + usleep_range(10 * USEC_PER_MSEC, 15 * USEC_PER_MSEC); + + ret = clk_prepare_enable(ov6211->xvclk); + if (ret) + goto reset_gpio; + + return 0; + +reset_gpio: + gpiod_set_value_cansleep(ov6211->reset_gpio, 1); + + regulator_bulk_disable(OV6211_NUM_SUPPLIES, ov6211->supplies); + + return ret; +} + +static int ov6211_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov6211 *ov6211 = to_ov6211(sd); + + clk_disable_unprepare(ov6211->xvclk); + + gpiod_set_value_cansleep(ov6211->reset_gpio, 1); + + regulator_bulk_disable(OV6211_NUM_SUPPLIES, ov6211->supplies); + + return 0; +} + +static int ov6211_probe(struct i2c_client *client) +{ + struct ov6211 *ov6211; + unsigned long freq; + unsigned int i; + int ret; + + ov6211 = devm_kzalloc(&client->dev, sizeof(*ov6211), GFP_KERNEL); + if (!ov6211) + return -ENOMEM; + + ov6211->dev = &client->dev; + + v4l2_i2c_subdev_init(&ov6211->sd, client, &ov6211_subdev_ops); + + ov6211->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(ov6211->regmap)) + return dev_err_probe(ov6211->dev, PTR_ERR(ov6211->regmap), + "failed to init CCI\n"); + + ov6211->xvclk = devm_v4l2_sensor_clk_get(ov6211->dev, NULL); + if (IS_ERR(ov6211->xvclk)) + return dev_err_probe(ov6211->dev, PTR_ERR(ov6211->xvclk), + "failed to get XVCLK clock\n"); + + freq = clk_get_rate(ov6211->xvclk); + if (freq && freq != OV6211_MCLK_FREQ_24MHZ) + return dev_err_probe(ov6211->dev, -EINVAL, + "XVCLK clock frequency %lu is not supported\n", + freq); + + ret = ov6211_check_hwcfg(ov6211); + if (ret) + return dev_err_probe(ov6211->dev, ret, + "failed to check HW configuration\n"); + + ov6211->reset_gpio = devm_gpiod_get_optional(ov6211->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov6211->reset_gpio)) + return dev_err_probe(ov6211->dev, PTR_ERR(ov6211->reset_gpio), + "cannot get reset GPIO\n"); + + for (i = 0; i < OV6211_NUM_SUPPLIES; i++) + ov6211->supplies[i].supply = ov6211_supply_names[i]; + + ret = devm_regulator_bulk_get(ov6211->dev, OV6211_NUM_SUPPLIES, + ov6211->supplies); + if (ret) + return dev_err_probe(ov6211->dev, ret, + "failed to get supply regulators\n"); + + /* The sensor must be powered on to read the CHIP_ID register */ + ret = ov6211_power_on(ov6211->dev); + if (ret) + return ret; + + ret = ov6211_identify_sensor(ov6211); + if (ret) { + dev_err_probe(ov6211->dev, ret, "failed to find sensor\n"); + goto power_off; + } + + ret = ov6211_init_controls(ov6211); + if (ret) { + dev_err_probe(ov6211->dev, ret, "failed to init controls\n"); + goto power_off; + } + + ov6211->sd.state_lock = ov6211->ctrl_handler.lock; + ov6211->sd.internal_ops = &ov6211_internal_ops; + ov6211->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov6211->sd.entity.ops = &ov6211_subdev_entity_ops; + ov6211->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov6211->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&ov6211->sd.entity, 1, &ov6211->pad); + if (ret) { + dev_err_probe(ov6211->dev, ret, + "failed to init media entity pads\n"); + goto v4l2_ctrl_handler_free; + } + + ret = v4l2_subdev_init_finalize(&ov6211->sd); + if (ret < 0) { + dev_err_probe(ov6211->dev, ret, + "failed to init media entity pads\n"); + goto media_entity_cleanup; + } + + pm_runtime_set_active(ov6211->dev); + pm_runtime_enable(ov6211->dev); + + ret = v4l2_async_register_subdev_sensor(&ov6211->sd); + if (ret < 0) { + dev_err_probe(ov6211->dev, ret, + "failed to register V4L2 subdev\n"); + goto subdev_cleanup; + } + + /* Enable runtime PM and turn off the device */ + pm_runtime_idle(ov6211->dev); + pm_runtime_set_autosuspend_delay(ov6211->dev, 1000); + pm_runtime_use_autosuspend(ov6211->dev); + + return 0; + +subdev_cleanup: + v4l2_subdev_cleanup(&ov6211->sd); + pm_runtime_disable(ov6211->dev); + pm_runtime_set_suspended(ov6211->dev); + +media_entity_cleanup: + media_entity_cleanup(&ov6211->sd.entity); + +v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(ov6211->sd.ctrl_handler); + +power_off: + ov6211_power_off(ov6211->dev); + + return ret; +} + +static void ov6211_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov6211 *ov6211 = to_ov6211(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(ov6211->dev); + + if (!pm_runtime_status_suspended(ov6211->dev)) { + ov6211_power_off(ov6211->dev); + pm_runtime_set_suspended(ov6211->dev); + } +} + +static const struct dev_pm_ops ov6211_pm_ops = { + SET_RUNTIME_PM_OPS(ov6211_power_off, ov6211_power_on, NULL) +}; + +static const struct of_device_id ov6211_of_match[] = { + { .compatible = "ovti,ov6211" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov6211_of_match); + +static struct i2c_driver ov6211_i2c_driver = { + .driver = { + .name = "ov6211", + .pm = &ov6211_pm_ops, + .of_match_table = ov6211_of_match, + }, + .probe = ov6211_probe, + .remove = ov6211_remove, +}; + +module_i2c_driver(ov6211_i2c_driver); + +MODULE_AUTHOR("Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>"); +MODULE_DESCRIPTION("OmniVision OV6211 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c index a5da4fe47e0b..78b62c169b99 100644 --- a/drivers/media/i2c/ov64a40.c +++ b/drivers/media/i2c/ov64a40.c @@ -2990,7 +2990,6 @@ static int ov64a40_start_streaming(struct ov64a40 *ov64a40, return 0; error_power_off: - pm_runtime_mark_last_busy(ov64a40->dev); pm_runtime_put_autosuspend(ov64a40->dev); return ret; @@ -3000,7 +2999,6 @@ static int ov64a40_stop_streaming(struct ov64a40 *ov64a40, struct v4l2_subdev_state *state) { cci_update_bits(ov64a40->cci, OV64A40_REG_SMIA, BIT(0), 0, NULL); - pm_runtime_mark_last_busy(ov64a40->dev); pm_runtime_put_autosuspend(ov64a40->dev); __v4l2_ctrl_grab(ov64a40->link_freq, false); @@ -3329,10 +3327,8 @@ static int ov64a40_set_ctrl(struct v4l2_ctrl *ctrl) break; } - if (pm_status > 0) { - pm_runtime_mark_last_busy(ov64a40->dev); + if (pm_status > 0) pm_runtime_put_autosuspend(ov64a40->dev); - } return ret; } @@ -3550,7 +3546,7 @@ static int ov64a40_probe(struct i2c_client *client) return PTR_ERR(ov64a40->cci); } - ov64a40->xclk = devm_clk_get(&client->dev, NULL); + ov64a40->xclk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(ov64a40->xclk)) return dev_err_probe(&client->dev, PTR_ERR(ov64a40->xclk), "Failed to get clock\n"); @@ -3622,7 +3618,6 @@ static int ov64a40_probe(struct i2c_client *client) goto error_subdev_cleanup; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c deleted file mode 100644 index 9c7627161142..000000000000 --- a/drivers/media/i2c/ov6650.c +++ /dev/null @@ -1,1149 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * V4L2 subdevice driver for OmniVision OV6650 Camera Sensor - * - * Copyright (C) 2010 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> - * - * Based on OmniVision OV96xx Camera Driver - * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com> - * - * Based on ov772x camera driver: - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto <morimoto.kuninori@renesas.com> - * - * Based on ov7670 and soc_camera_platform driver, - * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * Hardware specific bits initially based on former work by Matt Callow - * drivers/media/video/omap/sensor_ov6650.c - * Copyright (C) 2006 Matt Callow - */ - -#include <linux/bitops.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/v4l2-mediabus.h> -#include <linux/module.h> - -#include <media/v4l2-ctrls.h> -#include <media/v4l2-device.h> - -/* Register definitions */ -#define REG_GAIN 0x00 /* range 00 - 3F */ -#define REG_BLUE 0x01 -#define REG_RED 0x02 -#define REG_SAT 0x03 /* [7:4] saturation [0:3] reserved */ -#define REG_HUE 0x04 /* [7:6] rsrvd [5] hue en [4:0] hue */ - -#define REG_BRT 0x06 - -#define REG_PIDH 0x0a -#define REG_PIDL 0x0b - -#define REG_AECH 0x10 -#define REG_CLKRC 0x11 /* Data Format and Internal Clock */ - /* [7:6] Input system clock (MHz)*/ - /* 00=8, 01=12, 10=16, 11=24 */ - /* [5:0]: Internal Clock Pre-Scaler */ -#define REG_COMA 0x12 /* [7] Reset */ -#define REG_COMB 0x13 -#define REG_COMC 0x14 -#define REG_COMD 0x15 -#define REG_COML 0x16 -#define REG_HSTRT 0x17 -#define REG_HSTOP 0x18 -#define REG_VSTRT 0x19 -#define REG_VSTOP 0x1a -#define REG_PSHFT 0x1b -#define REG_MIDH 0x1c -#define REG_MIDL 0x1d -#define REG_HSYNS 0x1e -#define REG_HSYNE 0x1f -#define REG_COME 0x20 -#define REG_YOFF 0x21 -#define REG_UOFF 0x22 -#define REG_VOFF 0x23 -#define REG_AEW 0x24 -#define REG_AEB 0x25 -#define REG_COMF 0x26 -#define REG_COMG 0x27 -#define REG_COMH 0x28 -#define REG_COMI 0x29 - -#define REG_FRARL 0x2b -#define REG_COMJ 0x2c -#define REG_COMK 0x2d -#define REG_AVGY 0x2e -#define REG_REF0 0x2f -#define REG_REF1 0x30 -#define REG_REF2 0x31 -#define REG_FRAJH 0x32 -#define REG_FRAJL 0x33 -#define REG_FACT 0x34 -#define REG_L1AEC 0x35 -#define REG_AVGU 0x36 -#define REG_AVGV 0x37 - -#define REG_SPCB 0x60 -#define REG_SPCC 0x61 -#define REG_GAM1 0x62 -#define REG_GAM2 0x63 -#define REG_GAM3 0x64 -#define REG_SPCD 0x65 - -#define REG_SPCE 0x68 -#define REG_ADCL 0x69 - -#define REG_RMCO 0x6c -#define REG_GMCO 0x6d -#define REG_BMCO 0x6e - - -/* Register bits, values, etc. */ -#define OV6650_PIDH 0x66 /* high byte of product ID number */ -#define OV6650_PIDL 0x50 /* low byte of product ID number */ -#define OV6650_MIDH 0x7F /* high byte of mfg ID */ -#define OV6650_MIDL 0xA2 /* low byte of mfg ID */ - -#define DEF_GAIN 0x00 -#define DEF_BLUE 0x80 -#define DEF_RED 0x80 - -#define SAT_SHIFT 4 -#define SAT_MASK (0xf << SAT_SHIFT) -#define SET_SAT(x) (((x) << SAT_SHIFT) & SAT_MASK) - -#define HUE_EN BIT(5) -#define HUE_MASK 0x1f -#define DEF_HUE 0x10 -#define SET_HUE(x) (HUE_EN | ((x) & HUE_MASK)) - -#define DEF_AECH 0x4D - -#define CLKRC_8MHz 0x00 -#define CLKRC_12MHz 0x40 -#define CLKRC_16MHz 0x80 -#define CLKRC_24MHz 0xc0 -#define CLKRC_DIV_MASK 0x3f -#define GET_CLKRC_DIV(x) (((x) & CLKRC_DIV_MASK) + 1) -#define DEF_CLKRC 0x00 - -#define COMA_RESET BIT(7) -#define COMA_QCIF BIT(5) -#define COMA_RAW_RGB BIT(4) -#define COMA_RGB BIT(3) -#define COMA_BW BIT(2) -#define COMA_WORD_SWAP BIT(1) -#define COMA_BYTE_SWAP BIT(0) -#define DEF_COMA 0x00 - -#define COMB_FLIP_V BIT(7) -#define COMB_FLIP_H BIT(5) -#define COMB_BAND_FILTER BIT(4) -#define COMB_AWB BIT(2) -#define COMB_AGC BIT(1) -#define COMB_AEC BIT(0) -#define DEF_COMB 0x5f - -#define COML_ONE_CHANNEL BIT(7) - -#define DEF_HSTRT 0x24 -#define DEF_HSTOP 0xd4 -#define DEF_VSTRT 0x04 -#define DEF_VSTOP 0x94 - -#define COMF_HREF_LOW BIT(4) - -#define COMJ_PCLK_RISING BIT(4) -#define COMJ_VSYNC_HIGH BIT(0) - -/* supported resolutions */ -#define W_QCIF (DEF_HSTOP - DEF_HSTRT) -#define W_CIF (W_QCIF << 1) -#define H_QCIF (DEF_VSTOP - DEF_VSTRT) -#define H_CIF (H_QCIF << 1) - -#define FRAME_RATE_MAX 30 - - -struct ov6650_reg { - u8 reg; - u8 val; -}; - -struct ov6650 { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct { - /* exposure/autoexposure cluster */ - struct v4l2_ctrl *autoexposure; - struct v4l2_ctrl *exposure; - }; - struct { - /* gain/autogain cluster */ - struct v4l2_ctrl *autogain; - struct v4l2_ctrl *gain; - }; - struct { - /* blue/red/autowhitebalance cluster */ - struct v4l2_ctrl *autowb; - struct v4l2_ctrl *blue; - struct v4l2_ctrl *red; - }; - struct clk *clk; - bool half_scale; /* scale down output by 2 */ - struct v4l2_rect rect; /* sensor cropping window */ - struct v4l2_fract tpf; /* as requested with set_frame_interval */ - u32 code; -}; - -struct ov6650_xclk { - unsigned long rate; - u8 clkrc; -}; - -static const struct ov6650_xclk ov6650_xclk[] = { -{ - .rate = 8000000, - .clkrc = CLKRC_8MHz, -}, -{ - .rate = 12000000, - .clkrc = CLKRC_12MHz, -}, -{ - .rate = 16000000, - .clkrc = CLKRC_16MHz, -}, -{ - .rate = 24000000, - .clkrc = CLKRC_24MHz, -}, -}; - -static u32 ov6650_codes[] = { - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_SBGGR8_1X8, - MEDIA_BUS_FMT_Y8_1X8, -}; - -static const struct v4l2_mbus_framefmt ov6650_def_fmt = { - .width = W_CIF, - .height = H_CIF, - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .field = V4L2_FIELD_NONE, - .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, - .quantization = V4L2_QUANTIZATION_DEFAULT, - .xfer_func = V4L2_XFER_FUNC_DEFAULT, -}; - -/* read a register */ -static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) -{ - int ret; - u8 data = reg; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - msg.flags = I2C_M_RD; - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - *val = data; - return 0; - -err: - dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg); - return ret; -} - -/* write a register */ -static int ov6650_reg_write(struct i2c_client *client, u8 reg, u8 val) -{ - int ret; - unsigned char data[2] = { reg, val }; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - udelay(100); - - if (ret < 0) { - dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg); - return ret; - } - return 0; -} - - -/* Read a register, alter its bits, write it back */ -static int ov6650_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 mask) -{ - u8 val; - int ret; - - ret = ov6650_reg_read(client, reg, &val); - if (ret) { - dev_err(&client->dev, - "[Read]-Modify-Write of register 0x%02x failed!\n", - reg); - return ret; - } - - val &= ~mask; - val |= set; - - ret = ov6650_reg_write(client, reg, val); - if (ret) - dev_err(&client->dev, - "Read-Modify-[Write] of register 0x%02x failed!\n", - reg); - - return ret; -} - -static struct ov6650 *to_ov6650(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct ov6650, subdev); -} - -/* Start/Stop streaming from the device */ -static int ov6650_s_stream(struct v4l2_subdev *sd, int enable) -{ - return 0; -} - -/* Get status of additional camera capabilities */ -static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); - struct v4l2_subdev *sd = &priv->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - uint8_t reg, reg2; - int ret; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - ret = ov6650_reg_read(client, REG_GAIN, ®); - if (!ret) - priv->gain->val = reg; - return ret; - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = ov6650_reg_read(client, REG_BLUE, ®); - if (!ret) - ret = ov6650_reg_read(client, REG_RED, ®2); - if (!ret) { - priv->blue->val = reg; - priv->red->val = reg2; - } - return ret; - case V4L2_CID_EXPOSURE_AUTO: - ret = ov6650_reg_read(client, REG_AECH, ®); - if (!ret) - priv->exposure->val = reg; - return ret; - } - return -EINVAL; -} - -/* Set status of additional camera capabilities */ -static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); - struct v4l2_subdev *sd = &priv->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->val ? COMB_AGC : 0, COMB_AGC); - if (!ret && !ctrl->val) - ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val); - return ret; - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->val ? COMB_AWB : 0, COMB_AWB); - if (!ret && !ctrl->val) { - ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val); - if (!ret) - ret = ov6650_reg_write(client, REG_RED, - priv->red->val); - } - return ret; - case V4L2_CID_SATURATION: - return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val), - SAT_MASK); - case V4L2_CID_HUE: - return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val), - HUE_MASK); - case V4L2_CID_BRIGHTNESS: - return ov6650_reg_write(client, REG_BRT, ctrl->val); - case V4L2_CID_EXPOSURE_AUTO: - ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val == - V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC); - if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) - ret = ov6650_reg_write(client, REG_AECH, - priv->exposure->val); - return ret; - case V4L2_CID_GAMMA: - return ov6650_reg_write(client, REG_GAM1, ctrl->val); - case V4L2_CID_VFLIP: - return ov6650_reg_rmw(client, REG_COMB, - ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V); - case V4L2_CID_HFLIP: - return ov6650_reg_rmw(client, REG_COMB, - ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H); - } - - return -EINVAL; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov6650_get_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 val; - - if (reg->reg & ~0xff) - return -EINVAL; - - reg->size = 1; - - ret = ov6650_reg_read(client, reg->reg, &val); - if (!ret) - reg->val = (__u64)val; - - return ret; -} - -static int ov6650_set_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg & ~0xff || reg->val & ~0xff) - return -EINVAL; - - return ov6650_reg_write(client, reg->reg, reg->val); -} -#endif - -static int ov6650_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - int ret = 0; - - if (on) - ret = clk_prepare_enable(priv->clk); - else - clk_disable_unprepare(priv->clk); - - return ret; -} - -static int ov6650_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - struct v4l2_rect *rect; - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - /* pre-select try crop rectangle */ - rect = v4l2_subdev_state_get_crop(sd_state, 0); - - } else { - /* pre-select active crop rectangle */ - rect = &priv->rect; - } - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.left = DEF_HSTRT << 1; - sel->r.top = DEF_VSTRT << 1; - sel->r.width = W_CIF; - sel->r.height = H_CIF; - return 0; - - case V4L2_SEL_TGT_CROP: - /* use selected crop rectangle */ - sel->r = *rect; - return 0; - - default: - return -EINVAL; - } -} - -static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect) -{ - return width > rect->width >> 1 || height > rect->height >> 1; -} - -static void ov6650_bind_align_crop_rectangle(struct v4l2_rect *rect) -{ - v4l_bound_align_image(&rect->width, 2, W_CIF, 1, - &rect->height, 2, H_CIF, 1, 0); - v4l_bound_align_image(&rect->left, DEF_HSTRT << 1, - (DEF_HSTRT << 1) + W_CIF - (__s32)rect->width, 1, - &rect->top, DEF_VSTRT << 1, - (DEF_VSTRT << 1) + H_CIF - (__s32)rect->height, - 1, 0); -} - -static int ov6650_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - int ret; - - if (sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - ov6650_bind_align_crop_rectangle(&sel->r); - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_rect *crop = - v4l2_subdev_state_get_crop(sd_state, 0); - struct v4l2_mbus_framefmt *mf = - v4l2_subdev_state_get_format(sd_state, 0); - /* detect current pad config scaling factor */ - bool half_scale = !is_unscaled_ok(mf->width, mf->height, crop); - - /* store new crop rectangle */ - *crop = sel->r; - - /* adjust frame size */ - mf->width = crop->width >> half_scale; - mf->height = crop->height >> half_scale; - - return 0; - } - - /* V4L2_SUBDEV_FORMAT_ACTIVE */ - - /* apply new crop rectangle */ - ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1); - if (!ret) { - priv->rect.width += priv->rect.left - sel->r.left; - priv->rect.left = sel->r.left; - ret = ov6650_reg_write(client, REG_HSTOP, - (sel->r.left + sel->r.width) >> 1); - } - if (!ret) { - priv->rect.width = sel->r.width; - ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1); - } - if (!ret) { - priv->rect.height += priv->rect.top - sel->r.top; - priv->rect.top = sel->r.top; - ret = ov6650_reg_write(client, REG_VSTOP, - (sel->r.top + sel->r.height) >> 1); - } - if (!ret) - priv->rect.height = sel->r.height; - - return ret; -} - -static int ov6650_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - - if (format->pad) - return -EINVAL; - - /* initialize response with default media bus frame format */ - *mf = ov6650_def_fmt; - - /* update media bus format code and frame size */ - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_state_get_format(sd_state, 0); - - mf->width = try_fmt->width; - mf->height = try_fmt->height; - mf->code = try_fmt->code; - - } else { - mf->width = priv->rect.width >> priv->half_scale; - mf->height = priv->rect.height >> priv->half_scale; - mf->code = priv->code; - } - return 0; -} - -#define to_clkrc(div) ((div) - 1) - -/* set the format we will capture in */ -static int ov6650_s_fmt(struct v4l2_subdev *sd, u32 code, bool half_scale) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask; - int ret; - - /* select color matrix configuration for given color encoding */ - switch (code) { - case MEDIA_BUS_FMT_Y8_1X8: - dev_dbg(&client->dev, "pixel format GREY8_1X8\n"); - coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP; - coma_set |= COMA_BW; - break; - case MEDIA_BUS_FMT_YUYV8_2X8: - dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n"); - coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP; - coma_set |= COMA_WORD_SWAP; - break; - case MEDIA_BUS_FMT_YVYU8_2X8: - dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n"); - coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP | - COMA_BYTE_SWAP; - break; - case MEDIA_BUS_FMT_UYVY8_2X8: - dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n"); - if (half_scale) { - coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP; - coma_set |= COMA_BYTE_SWAP; - } else { - coma_mask |= COMA_RGB | COMA_BW; - coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP; - } - break; - case MEDIA_BUS_FMT_VYUY8_2X8: - dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n"); - if (half_scale) { - coma_mask |= COMA_RGB | COMA_BW; - coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP; - } else { - coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP; - coma_set |= COMA_BYTE_SWAP; - } - break; - case MEDIA_BUS_FMT_SBGGR8_1X8: - dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n"); - coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP; - coma_set |= COMA_RAW_RGB | COMA_RGB; - break; - default: - dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code); - return -EINVAL; - } - - if (code == MEDIA_BUS_FMT_Y8_1X8 || - code == MEDIA_BUS_FMT_SBGGR8_1X8) { - coml_mask = COML_ONE_CHANNEL; - coml_set = 0; - } else { - coml_mask = 0; - coml_set = COML_ONE_CHANNEL; - } - - if (half_scale) { - dev_dbg(&client->dev, "max resolution: QCIF\n"); - coma_set |= COMA_QCIF; - } else { - dev_dbg(&client->dev, "max resolution: CIF\n"); - coma_mask |= COMA_QCIF; - } - - ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); - if (!ret) { - priv->half_scale = half_scale; - - ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask); - } - if (!ret) - priv->code = code; - - return ret; -} - -static int ov6650_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - struct v4l2_rect *crop; - bool half_scale; - - if (format->pad) - return -EINVAL; - - switch (mf->code) { - case MEDIA_BUS_FMT_Y10_1X10: - mf->code = MEDIA_BUS_FMT_Y8_1X8; - fallthrough; - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - break; - default: - mf->code = MEDIA_BUS_FMT_SBGGR8_1X8; - fallthrough; - case MEDIA_BUS_FMT_SBGGR8_1X8: - break; - } - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) - crop = v4l2_subdev_state_get_crop(sd_state, 0); - else - crop = &priv->rect; - - half_scale = !is_unscaled_ok(mf->width, mf->height, crop); - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_state_get_format(sd_state, 0); - - /* store new mbus frame format code and size in pad config */ - try_fmt->width = crop->width >> half_scale; - try_fmt->height = crop->height >> half_scale; - try_fmt->code = mf->code; - - /* return default mbus frame format updated with pad config */ - *mf = ov6650_def_fmt; - mf->width = try_fmt->width; - mf->height = try_fmt->height; - mf->code = try_fmt->code; - - } else { - int ret = 0; - - /* apply new media bus frame format and scaling if changed */ - if (mf->code != priv->code || half_scale != priv->half_scale) - ret = ov6650_s_fmt(sd, mf->code, half_scale); - if (ret) - return ret; - - /* return default format updated with active size and code */ - *mf = ov6650_def_fmt; - mf->width = priv->rect.width >> priv->half_scale; - mf->height = priv->rect.height >> priv->half_scale; - mf->code = priv->code; - } - return 0; -} - -static int ov6650_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || code->index >= ARRAY_SIZE(ov6650_codes)) - return -EINVAL; - - code->code = ov6650_codes[code->index]; - return 0; -} - -static int ov6650_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval_enum *fie) -{ - int i; - - /* enumerate supported frame intervals not exceeding 1 second */ - if (fie->index > CLKRC_DIV_MASK || - GET_CLKRC_DIV(fie->index) > FRAME_RATE_MAX) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(ov6650_codes); i++) - if (fie->code == ov6650_codes[i]) - break; - if (i == ARRAY_SIZE(ov6650_codes)) - return -EINVAL; - - if (!fie->width || fie->width > W_CIF || - !fie->height || fie->height > H_CIF) - return -EINVAL; - - fie->interval.numerator = GET_CLKRC_DIV(fie->index); - fie->interval.denominator = FRAME_RATE_MAX; - - return 0; -} - -static int ov6650_get_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval *ival) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - - /* - * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 - * subdev active state API. - */ - if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - ival->interval = priv->tpf; - - dev_dbg(&client->dev, "Frame interval: %u/%u s\n", - ival->interval.numerator, ival->interval.denominator); - - return 0; -} - -static int ov6650_set_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval *ival) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - struct v4l2_fract *tpf = &ival->interval; - int div, ret; - - /* - * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 - * subdev active state API. - */ - if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (tpf->numerator == 0 || tpf->denominator == 0) - div = 1; /* Reset to full rate */ - else - div = (tpf->numerator * FRAME_RATE_MAX) / tpf->denominator; - - if (div == 0) - div = 1; - else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK)) - div = GET_CLKRC_DIV(CLKRC_DIV_MASK); - - ret = ov6650_reg_rmw(client, REG_CLKRC, to_clkrc(div), CLKRC_DIV_MASK); - if (!ret) { - priv->tpf.numerator = div; - priv->tpf.denominator = FRAME_RATE_MAX; - - *tpf = priv->tpf; - } - - return ret; -} - -/* Soft reset the camera. This has nothing to do with the RESET pin! */ -static int ov6650_reset(struct i2c_client *client) -{ - int ret; - - dev_dbg(&client->dev, "reset\n"); - - ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0); - if (ret) - dev_err(&client->dev, - "An error occurred while entering soft reset!\n"); - - return ret; -} - -/* program default register values */ -static int ov6650_prog_dflt(struct i2c_client *client, u8 clkrc) -{ - int ret; - - dev_dbg(&client->dev, "initializing\n"); - - ret = ov6650_reg_write(client, REG_COMA, 0); /* ~COMA_RESET */ - if (!ret) - ret = ov6650_reg_write(client, REG_CLKRC, clkrc); - if (!ret) - ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER); - - return ret; -} - -static int ov6650_video_probe(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - const struct ov6650_xclk *xclk = NULL; - unsigned long rate; - u8 pidh, pidl, midh, midl; - int i, ret = 0; - - priv->clk = devm_clk_get(&client->dev, NULL); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - dev_err(&client->dev, "clk request err: %d\n", ret); - return ret; - } - - rate = clk_get_rate(priv->clk); - for (i = 0; rate && i < ARRAY_SIZE(ov6650_xclk); i++) { - if (rate != ov6650_xclk[i].rate) - continue; - - xclk = &ov6650_xclk[i]; - dev_info(&client->dev, "using host default clock rate %lukHz\n", - rate / 1000); - break; - } - for (i = 0; !xclk && i < ARRAY_SIZE(ov6650_xclk); i++) { - ret = clk_set_rate(priv->clk, ov6650_xclk[i].rate); - if (ret || clk_get_rate(priv->clk) != ov6650_xclk[i].rate) - continue; - - xclk = &ov6650_xclk[i]; - dev_info(&client->dev, "using negotiated clock rate %lukHz\n", - xclk->rate / 1000); - break; - } - if (!xclk) { - dev_err(&client->dev, "unable to get supported clock rate\n"); - if (!ret) - ret = -EINVAL; - return ret; - } - - ret = ov6650_s_power(sd, 1); - if (ret < 0) - return ret; - - msleep(20); - - /* - * check and show product ID and manufacturer ID - */ - ret = ov6650_reg_read(client, REG_PIDH, &pidh); - if (!ret) - ret = ov6650_reg_read(client, REG_PIDL, &pidl); - if (!ret) - ret = ov6650_reg_read(client, REG_MIDH, &midh); - if (!ret) - ret = ov6650_reg_read(client, REG_MIDL, &midl); - - if (ret) - goto done; - - if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) { - dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n", - pidh, pidl); - ret = -ENODEV; - goto done; - } - - dev_info(&client->dev, - "ov6650 Product ID 0x%02x:0x%02x Manufacturer ID 0x%02x:0x%02x\n", - pidh, pidl, midh, midl); - - ret = ov6650_reset(client); - if (!ret) - ret = ov6650_prog_dflt(client, xclk->clkrc); - if (!ret) { - /* driver default frame format, no scaling */ - ret = ov6650_s_fmt(sd, ov6650_def_fmt.code, false); - } - if (!ret) - ret = v4l2_ctrl_handler_setup(&priv->hdl); - -done: - ov6650_s_power(sd, 0); - return ret; -} - -static const struct v4l2_ctrl_ops ov6550_ctrl_ops = { - .g_volatile_ctrl = ov6550_g_volatile_ctrl, - .s_ctrl = ov6550_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops ov6650_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov6650_get_register, - .s_register = ov6650_set_register, -#endif - .s_power = ov6650_s_power, -}; - -/* Request bus settings on camera side */ -static int ov6650_get_mbus_config(struct v4l2_subdev *sd, - unsigned int pad, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 comj, comf; - int ret; - - ret = ov6650_reg_read(client, REG_COMJ, &comj); - if (ret) - return ret; - - ret = ov6650_reg_read(client, REG_COMF, &comf); - if (ret) - return ret; - - cfg->type = V4L2_MBUS_PARALLEL; - - cfg->bus.parallel.flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH - | ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH - : V4L2_MBUS_VSYNC_ACTIVE_LOW) - | ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW - : V4L2_MBUS_HSYNC_ACTIVE_HIGH) - | ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING - : V4L2_MBUS_PCLK_SAMPLE_FALLING); - return 0; -} - -static const struct v4l2_subdev_video_ops ov6650_video_ops = { - .s_stream = ov6650_s_stream, -}; - -static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { - .enum_mbus_code = ov6650_enum_mbus_code, - .enum_frame_interval = ov6650_enum_frame_interval, - .get_selection = ov6650_get_selection, - .set_selection = ov6650_set_selection, - .get_fmt = ov6650_get_fmt, - .set_fmt = ov6650_set_fmt, - .get_frame_interval = ov6650_get_frame_interval, - .set_frame_interval = ov6650_set_frame_interval, - .get_mbus_config = ov6650_get_mbus_config, -}; - -static const struct v4l2_subdev_ops ov6650_subdev_ops = { - .core = &ov6650_core_ops, - .video = &ov6650_video_ops, - .pad = &ov6650_pad_ops, -}; - -static const struct v4l2_subdev_internal_ops ov6650_internal_ops = { - .registered = ov6650_video_probe, -}; - -/* - * i2c_driver function - */ -static int ov6650_probe(struct i2c_client *client) -{ - struct ov6650 *priv; - int ret; - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); - v4l2_ctrl_handler_init(&priv->hdl, 13); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN); - priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); - priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE); - priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_SATURATION, 0, 0xf, 1, 0x8); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); - priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, - &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, - V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); - priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); - - priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) { - ret = priv->hdl.error; - goto ectlhdlfree; - } - - v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); - v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); - v4l2_ctrl_auto_cluster(2, &priv->autoexposure, - V4L2_EXPOSURE_MANUAL, true); - - priv->rect.left = DEF_HSTRT << 1; - priv->rect.top = DEF_VSTRT << 1; - priv->rect.width = W_CIF; - priv->rect.height = H_CIF; - - /* Hardware default frame interval */ - priv->tpf.numerator = GET_CLKRC_DIV(DEF_CLKRC); - priv->tpf.denominator = FRAME_RATE_MAX; - - priv->subdev.internal_ops = &ov6650_internal_ops; - - ret = v4l2_async_register_subdev(&priv->subdev); - if (!ret) - return 0; -ectlhdlfree: - v4l2_ctrl_handler_free(&priv->hdl); - - return ret; -} - -static void ov6650_remove(struct i2c_client *client) -{ - struct ov6650 *priv = to_ov6650(client); - - v4l2_async_unregister_subdev(&priv->subdev); - v4l2_ctrl_handler_free(&priv->hdl); -} - -static const struct i2c_device_id ov6650_id[] = { - { "ov6650" }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov6650_id); - -static struct i2c_driver ov6650_i2c_driver = { - .driver = { - .name = "ov6650", - }, - .probe = ov6650_probe, - .remove = ov6650_remove, - .id_table = ov6650_id, -}; - -module_i2c_driver(ov6650_i2c_driver); - -MODULE_DESCRIPTION("V4L2 subdevice driver for OmniVision OV6650 camera sensor"); -MODULE_AUTHOR("Janusz Krzysztofik <jmkrzyszt@gmail.com"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index 31a42d81e970..27afc3fc0175 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1630,7 +1630,6 @@ static int ov7251_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ov7251 *ov7251; - unsigned int rate = 0, clk_rate = 0; int ret; int i; @@ -1646,33 +1645,12 @@ static int ov7251_probe(struct i2c_client *client) return ret; /* get system clock (xclk) */ - ov7251->xclk = devm_clk_get_optional(dev, NULL); + ov7251->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(ov7251->xclk)) return dev_err_probe(dev, PTR_ERR(ov7251->xclk), "could not get xclk"); - /* - * We could have either a 24MHz or 19.2MHz clock rate from either DT or - * ACPI. We also need to support the IPU3 case which will have both an - * external clock AND a clock-frequency property. - */ - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &rate); - if (ret && !ov7251->xclk) - return dev_err_probe(dev, ret, "invalid clock config\n"); - - clk_rate = clk_get_rate(ov7251->xclk); - ov7251->xclk_freq = clk_rate ? clk_rate : rate; - - if (ov7251->xclk_freq == 0) - return dev_err_probe(dev, -EINVAL, "invalid clock frequency\n"); - - if (!ret && ov7251->xclk) { - ret = clk_set_rate(ov7251->xclk, rate); - if (ret) - return dev_err_probe(dev, ret, - "failed to set clock rate\n"); - } + ov7251->xclk_freq = clk_get_rate(ov7251->xclk); for (i = 0; i < ARRAY_SIZE(supported_xclk_rates); i++) if (ov7251->xclk_freq == supported_xclk_rates[i]) diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 1f1c0de8e510..632fb80469be 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -1036,13 +1036,10 @@ static int ov7740_probe(struct i2c_client *client) if (!ov7740) return -ENOMEM; - ov7740->xvclk = devm_clk_get(&client->dev, "xvclk"); - if (IS_ERR(ov7740->xvclk)) { - ret = PTR_ERR(ov7740->xvclk); - dev_err(&client->dev, - "OV7740: fail to get xvclk: %d\n", ret); - return ret; - } + ov7740->xvclk = devm_v4l2_sensor_clk_get(&client->dev, "xvclk"); + if (IS_ERR(ov7740->xvclk)) + return dev_err_probe(&client->dev, PTR_ERR(ov7740->xvclk), + "OV7740: fail to get xvclk\n"); ret = ov7740_probe_dt(client, ov7740); if (ret) diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 4b6874d2a104..e2998cfa0d18 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -10,6 +9,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -1414,6 +1415,8 @@ static const struct ov8856_reg_list bayer_offset_configs[] = { }; struct ov8856 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -1668,7 +1671,6 @@ static int ov8856_write_reg(struct ov8856 *ov8856, u16 reg, u16 len, u32 val) static int ov8856_write_reg_list(struct ov8856 *ov8856, const struct ov8856_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); unsigned int i; int ret; @@ -1676,7 +1678,7 @@ static int ov8856_write_reg_list(struct ov8856 *ov8856, ret = ov8856_write_reg(ov8856, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov8856->dev, "failed to write reg 0x%4.4x. error = %d", r_list->regs[i].address, ret); return ret; @@ -1688,7 +1690,6 @@ static int ov8856_write_reg_list(struct ov8856 *ov8856, static int ov8856_identify_module(struct ov8856 *ov8856) { - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); int ret; u32 val; @@ -1701,7 +1702,7 @@ static int ov8856_identify_module(struct ov8856 *ov8856) return ret; if (val != OV8856_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(ov8856->dev, "chip id mismatch: %x!=%x", OV8856_CHIP_ID, val); return -ENXIO; } @@ -1818,7 +1819,6 @@ static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov8856 *ov8856 = container_of(ctrl->handler, struct ov8856, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); s64 exposure_max; int ret = 0; @@ -1834,7 +1834,7 @@ static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov8856->dev)) return 0; switch (ctrl->id) { @@ -1876,7 +1876,7 @@ static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov8856->dev); return ret; } @@ -1979,7 +1979,6 @@ static void ov8856_update_pad_format(struct ov8856 *ov8856, static int ov8856_start_streaming(struct ov8856 *ov8856) { - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); const struct ov8856_reg_list *reg_list; int link_freq_index, ret; @@ -1992,21 +1991,21 @@ static int ov8856_start_streaming(struct ov8856 *ov8856) ret = ov8856_write_reg_list(ov8856, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(ov8856->dev, "failed to set plls"); return ret; } reg_list = &ov8856->cur_mode->reg_list; ret = ov8856_write_reg_list(ov8856, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(ov8856->dev, "failed to set mode"); return ret; } reg_list = &bayer_offset_configs[ov8856->cur_mbus_index]; ret = ov8856_write_reg_list(ov8856, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mbus format"); + dev_err(ov8856->dev, "failed to set mbus format"); return ret; } @@ -2017,7 +2016,7 @@ static int ov8856_start_streaming(struct ov8856 *ov8856) ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, OV8856_REG_VALUE_08BIT, OV8856_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream"); + dev_err(ov8856->dev, "failed to set stream"); return ret; } @@ -2026,22 +2025,19 @@ static int ov8856_start_streaming(struct ov8856 *ov8856) static void ov8856_stop_streaming(struct ov8856 *ov8856) { - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); - if (ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, OV8856_REG_VALUE_08BIT, OV8856_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream"); + dev_err(ov8856->dev, "failed to set stream"); } static int ov8856_set_stream(struct v4l2_subdev *sd, int enable) { struct ov8856 *ov8856 = to_ov8856(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov8856->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov8856->dev); if (ret < 0) { mutex_unlock(&ov8856->mutex); return ret; @@ -2051,11 +2047,11 @@ static int ov8856_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov8856_stop_streaming(ov8856); - pm_runtime_put(&client->dev); + pm_runtime_put(ov8856->dev); } } else { ov8856_stop_streaming(ov8856); - pm_runtime_put(&client->dev); + pm_runtime_put(ov8856->dev); } mutex_unlock(&ov8856->mutex); @@ -2255,8 +2251,9 @@ static const struct v4l2_subdev_internal_ops ov8856_internal_ops = { }; -static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) +static int ov8856_get_hwcfg(struct ov8856 *ov8856) { + struct device *dev = ov8856->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { @@ -2269,21 +2266,17 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &xvclk_rate); - if (ret) - return ret; - - if (!is_acpi_node(fwnode)) { - ov8856->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(ov8856->xvclk)) { - dev_err_probe(dev, PTR_ERR(ov8856->xvclk), - "could not get xvclk clock\n"); - return PTR_ERR(ov8856->xvclk); - } + ov8856->xvclk = devm_v4l2_sensor_clk_get_legacy(dev, "xvclk", false, 0); + if (IS_ERR(ov8856->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov8856->xvclk), + "could not get xvclk clock\n"); - clk_set_rate(ov8856->xvclk, xvclk_rate); - xvclk_rate = clk_get_rate(ov8856->xvclk); + xvclk_rate = clk_get_rate(ov8856->xvclk); + if (xvclk_rate != OV8856_XVCLK_19_2) + dev_warn(dev, "external clock rate %u is unsupported", + xvclk_rate); + if (!is_acpi_node(fwnode)) { ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ov8856->reset_gpio)) @@ -2299,10 +2292,6 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) return ret; } - if (xvclk_rate != OV8856_XVCLK_19_2) - dev_warn(dev, "external clock rate %u is unsupported", - xvclk_rate); - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -2365,10 +2354,10 @@ static void ov8856_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov8856->dev); mutex_destroy(&ov8856->mutex); - ov8856_power_off(&client->dev); + ov8856_power_off(ov8856->dev); } static int ov8856_probe(struct i2c_client *client) @@ -2381,23 +2370,25 @@ static int ov8856_probe(struct i2c_client *client) if (!ov8856) return -ENOMEM; - ret = ov8856_get_hwcfg(ov8856, &client->dev); + ov8856->dev = &client->dev; + + ret = ov8856_get_hwcfg(ov8856); if (ret) return ret; v4l2_i2c_subdev_init(&ov8856->sd, client, &ov8856_subdev_ops); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov8856->dev); if (full_power) { - ret = ov8856_power_on(&client->dev); + ret = ov8856_power_on(ov8856->dev); if (ret) { - dev_err(&client->dev, "failed to power on\n"); + dev_err(ov8856->dev, "failed to power on\n"); return ret; } ret = ov8856_identify_module(ov8856); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov8856->dev, "failed to find sensor: %d", ret); goto probe_power_off; } } @@ -2407,7 +2398,7 @@ static int ov8856_probe(struct i2c_client *client) ov8856->cur_mbus_index = ov8856->cur_mode->default_mbus_index; ret = ov8856_init_controls(ov8856); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov8856->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -2418,22 +2409,22 @@ static int ov8856_probe(struct i2c_client *client) ov8856->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov8856->sd.entity, 1, &ov8856->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov8856->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&ov8856->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov8856->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov8856->dev); + pm_runtime_enable(ov8856->dev); + pm_runtime_idle(ov8856->dev); return 0; @@ -2445,7 +2436,7 @@ probe_error_v4l2_ctrl_handler_free: mutex_destroy(&ov8856->mutex); probe_power_off: - ov8856_power_off(&client->dev); + ov8856_power_off(ov8856->dev); return ret; } diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c index 95f9ae794846..3f45f7fab833 100644 --- a/drivers/media/i2c/ov8858.c +++ b/drivers/media/i2c/ov8858.c @@ -1391,7 +1391,6 @@ static int ov8858_s_stream(struct v4l2_subdev *sd, int on) } } else { ov8858_stop_stream(ov8858); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } @@ -1877,7 +1876,7 @@ static int ov8858_probe(struct i2c_client *client) if (!ov8858) return -ENOMEM; - ov8858->xvclk = devm_clk_get(dev, "xvclk"); + ov8858->xvclk = devm_v4l2_sensor_clk_get(dev, "xvclk"); if (IS_ERR(ov8858->xvclk)) return dev_err_probe(dev, PTR_ERR(ov8858->xvclk), "Failed to get xvclk\n"); @@ -1945,7 +1944,6 @@ static int ov8858_probe(struct i2c_client *client) goto err_power_off; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index a2138f7988aa..a8586df14f77 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -2304,14 +2304,6 @@ static int ov8865_state_configure(struct ov8865_sensor *sensor, if (sensor->state.streaming) return -EBUSY; - /* State will be configured at first power on otherwise. */ - if (pm_runtime_enabled(sensor->dev) && - !pm_runtime_suspended(sensor->dev)) { - ret = ov8865_mode_configure(sensor, mode, mbus_code); - if (ret) - return ret; - } - ret = ov8865_state_mipi_configure(sensor, mode, mbus_code); if (ret) return ret; @@ -2384,10 +2376,10 @@ static int ov8865_sensor_init(struct ov8865_sensor *sensor) } /* Configure current mode. */ - ret = ov8865_state_configure(sensor, sensor->state.mode, - sensor->state.mbus_code); + ret = ov8865_mode_configure(sensor, sensor->state.mode, + sensor->state.mbus_code); if (ret) { - dev_err(sensor->dev, "failed to configure state\n"); + dev_err(sensor->dev, "failed to configure mode\n"); return ret; } @@ -2956,7 +2948,6 @@ static int ov8865_probe(struct i2c_client *client) struct ov8865_sensor *sensor; struct v4l2_subdev *subdev; struct media_pad *pad; - unsigned int rate = 0; unsigned int i; int ret; @@ -3020,39 +3011,14 @@ static int ov8865_probe(struct i2c_client *client) /* External Clock */ - sensor->extclk = devm_clk_get(dev, NULL); - if (PTR_ERR(sensor->extclk) == -ENOENT) { - dev_info(dev, "no external clock found, continuing...\n"); - sensor->extclk = NULL; - } else if (IS_ERR(sensor->extclk)) { - dev_err(dev, "failed to get external clock\n"); - ret = PTR_ERR(sensor->extclk); - goto error_endpoint; - } - - /* - * We could have either a 24MHz or 19.2MHz clock rate from either dt or - * ACPI...but we also need to support the weird IPU3 case which will - * have an external clock AND a clock-frequency property. Check for the - * clock-frequency property and if found, set that rate if we managed - * to acquire a clock. This should cover the ACPI case. If the system - * uses devicetree then the configured rate should already be set, so - * we can just read it. - */ - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &rate); - if (!ret && sensor->extclk) { - ret = clk_set_rate(sensor->extclk, rate); - if (ret) { - dev_err_probe(dev, ret, "failed to set clock rate\n"); - goto error_endpoint; - } - } else if (ret && !sensor->extclk) { - dev_err_probe(dev, ret, "invalid clock config\n"); + sensor->extclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->extclk)) { + ret = dev_err_probe(dev, PTR_ERR(sensor->extclk), + "failed to get external clock\n"); goto error_endpoint; } - sensor->extclk_rate = rate ? rate : clk_get_rate(sensor->extclk); + sensor->extclk_rate = clk_get_rate(sensor->extclk); for (i = 0; i < ARRAY_SIZE(supported_extclk_rates); i++) { if (sensor->extclk_rate == supported_extclk_rates[i]) diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index c882a021cf18..3e24d88f603c 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -1129,17 +1129,16 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282) ov9282->reset_gpio = devm_gpiod_get_optional(ov9282->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ov9282->reset_gpio)) { - dev_err(ov9282->dev, "failed to get reset gpio %ld", - PTR_ERR(ov9282->reset_gpio)); + dev_err(ov9282->dev, "failed to get reset gpio %pe", + ov9282->reset_gpio); return PTR_ERR(ov9282->reset_gpio); } /* Get sensor input clock */ - ov9282->inclk = devm_clk_get(ov9282->dev, NULL); - if (IS_ERR(ov9282->inclk)) { - dev_err(ov9282->dev, "could not get inclk"); - return PTR_ERR(ov9282->inclk); - } + ov9282->inclk = devm_v4l2_sensor_clk_get(ov9282->dev, NULL); + if (IS_ERR(ov9282->inclk)) + return dev_err_probe(ov9282->dev, PTR_ERR(ov9282->inclk), + "could not get inclk\n"); ret = ov9282_configure_regulators(ov9282); if (ret) diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index 01dbc0ba89c8..2190c52b1433 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -718,9 +718,10 @@ static int ov9640_probe(struct i2c_client *client) priv->subdev.ctrl_handler = &priv->hdl; - priv->clk = devm_clk_get(&client->dev, "mclk"); + priv->clk = devm_v4l2_sensor_clk_get(&client->dev, "mclk"); if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); + ret = dev_err_probe(&client->dev, PTR_ERR(priv->clk), + "failed to get mclk\n"); goto ectrlinit; } diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 026ea34d6291..c94e8fe29f22 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -1494,9 +1494,10 @@ static int ov965x_probe(struct i2c_client *client) } if (dev_fwnode(&client->dev)) { - ov965x->clk = devm_clk_get(&client->dev, NULL); + ov965x->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(ov965x->clk)) - return PTR_ERR(ov965x->clk); + return dev_err_probe(&client->dev, PTR_ERR(ov965x->clk), + "failed to get the clock\n"); ov965x->mclk_frequency = clk_get_rate(ov965x->clk); ret = ov965x_configure_gpios(ov965x); diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index cae3aeefb616..0eaf33807fc9 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2020 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -321,6 +323,9 @@ static const struct ov9734_mode supported_modes[] = { }; struct ov9734 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -414,7 +419,6 @@ static int ov9734_write_reg(struct ov9734 *ov9734, u16 reg, u16 len, u32 val) static int ov9734_write_reg_list(struct ov9734 *ov9734, const struct ov9734_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); unsigned int i; int ret; @@ -422,7 +426,7 @@ static int ov9734_write_reg_list(struct ov9734 *ov9734, ret = ov9734_write_reg(ov9734, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov9734->dev, "write reg 0x%4.4x return err = %d", r_list->regs[i].address, ret); return ret; @@ -476,7 +480,6 @@ static int ov9734_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov9734 *ov9734 = container_of(ctrl->handler, struct ov9734, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); s64 exposure_max; int ret = 0; @@ -492,7 +495,7 @@ static int ov9734_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov9734->dev)) return 0; switch (ctrl->id) { @@ -525,7 +528,7 @@ static int ov9734_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov9734->dev); return ret; } @@ -610,7 +613,6 @@ static void ov9734_update_pad_format(const struct ov9734_mode *mode, static int ov9734_start_streaming(struct ov9734 *ov9734) { - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); const struct ov9734_reg_list *reg_list; int link_freq_index, ret; @@ -618,14 +620,14 @@ static int ov9734_start_streaming(struct ov9734 *ov9734) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov9734_write_reg_list(ov9734, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(ov9734->dev, "failed to set plls"); return ret; } reg_list = &ov9734->cur_mode->reg_list; ret = ov9734_write_reg_list(ov9734, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(ov9734->dev, "failed to set mode"); return ret; } @@ -636,30 +638,27 @@ static int ov9734_start_streaming(struct ov9734 *ov9734) ret = ov9734_write_reg(ov9734, OV9734_REG_MODE_SELECT, 1, OV9734_MODE_STREAMING); if (ret) - dev_err(&client->dev, "failed to start stream"); + dev_err(ov9734->dev, "failed to start stream"); return ret; } static void ov9734_stop_streaming(struct ov9734 *ov9734) { - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); - if (ov9734_write_reg(ov9734, OV9734_REG_MODE_SELECT, 1, OV9734_MODE_STANDBY)) - dev_err(&client->dev, "failed to stop stream"); + dev_err(ov9734->dev, "failed to stop stream"); } static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) { struct ov9734 *ov9734 = to_ov9734(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov9734->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov9734->dev); if (ret < 0) { mutex_unlock(&ov9734->mutex); return ret; @@ -669,11 +668,11 @@ static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov9734_stop_streaming(ov9734); - pm_runtime_put(&client->dev); + pm_runtime_put(ov9734->dev); } } else { ov9734_stop_streaming(ov9734); - pm_runtime_put(&client->dev); + pm_runtime_put(ov9734->dev); } mutex_unlock(&ov9734->mutex); @@ -808,7 +807,6 @@ static const struct v4l2_subdev_internal_ops ov9734_internal_ops = { static int ov9734_identify_module(struct ov9734 *ov9734) { - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); int ret; u32 val; @@ -817,7 +815,7 @@ static int ov9734_identify_module(struct ov9734 *ov9734) return ret; if (val != OV9734_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(ov9734->dev, "chip id mismatch: %x!=%x", OV9734_CHIP_ID, val); return -ENXIO; } @@ -832,22 +830,12 @@ static int ov9734_check_hwcfg(struct device *dev) struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret; unsigned int i, j; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) - return ret; - - if (mclk != OV9734_MCLK) { - dev_err(dev, "external clock %d is not supported", mclk); - return -EINVAL; - } - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -892,14 +880,15 @@ static void ov9734_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov9734->dev); + pm_runtime_set_suspended(ov9734->dev); mutex_destroy(&ov9734->mutex); } static int ov9734_probe(struct i2c_client *client) { struct ov9734 *ov9734; + unsigned long freq; int ret; ret = ov9734_check_hwcfg(&client->dev); @@ -913,10 +902,23 @@ static int ov9734_probe(struct i2c_client *client) if (!ov9734) return -ENOMEM; + ov9734->dev = &client->dev; + + ov9734->clk = devm_v4l2_sensor_clk_get(ov9734->dev, NULL); + if (IS_ERR(ov9734->clk)) + return dev_err_probe(ov9734->dev, PTR_ERR(ov9734->clk), + "failed to get clock\n"); + + freq = clk_get_rate(ov9734->clk); + if (freq != OV9734_MCLK) + return dev_err_probe(ov9734->dev, -EINVAL, + "external clock %lu is not supported", + freq); + v4l2_i2c_subdev_init(&ov9734->sd, client, &ov9734_subdev_ops); ret = ov9734_identify_module(ov9734); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov9734->dev, "failed to find sensor: %d", ret); return ret; } @@ -924,7 +926,7 @@ static int ov9734_probe(struct i2c_client *client) ov9734->cur_mode = &supported_modes[0]; ret = ov9734_init_controls(ov9734); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov9734->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -935,7 +937,7 @@ static int ov9734_probe(struct i2c_client *client) ov9734->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov9734->sd.entity, 1, &ov9734->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov9734->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -943,13 +945,13 @@ static int ov9734_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov9734->dev); + pm_runtime_enable(ov9734->dev); + pm_runtime_idle(ov9734->dev); ret = v4l2_async_register_subdev_sensor(&ov9734->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov9734->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup_pm; } @@ -957,8 +959,8 @@ static int ov9734_probe(struct i2c_client *client) return 0; probe_error_media_entity_cleanup_pm: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov9734->dev); + pm_runtime_set_suspended(ov9734->dev); media_entity_cleanup(&ov9734->sd.entity); probe_error_v4l2_ctrl_handler_free: diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c index b7ca39f63dba..e95342d706c3 100644 --- a/drivers/media/i2c/rj54n1cb0c.c +++ b/drivers/media/i2c/rj54n1cb0c.c @@ -1329,10 +1329,13 @@ static int rj54n1_probe(struct i2c_client *client) V4L2_CID_GAIN, 0, 127, 1, 66); v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); - rj54n1->subdev.ctrl_handler = &rj54n1->hdl; - if (rj54n1->hdl.error) - return rj54n1->hdl.error; + if (rj54n1->hdl.error) { + ret = rj54n1->hdl.error; + goto err_free_ctrl; + } + + rj54n1->subdev.ctrl_handler = &rj54n1->hdl; rj54n1->clk_div = clk_div; rj54n1->rect.left = RJ54N1_COLUMN_SKIP; rj54n1->rect.top = RJ54N1_ROW_SKIP; @@ -1354,8 +1357,8 @@ static int rj54n1_probe(struct i2c_client *client) rj54n1->pwup_gpio = gpiod_get_optional(&client->dev, "powerup", GPIOD_OUT_LOW); if (IS_ERR(rj54n1->pwup_gpio)) { - dev_info(&client->dev, "Unable to get GPIO \"powerup\": %ld\n", - PTR_ERR(rj54n1->pwup_gpio)); + dev_info(&client->dev, "Unable to get GPIO \"powerup\": %pe\n", + rj54n1->pwup_gpio); ret = PTR_ERR(rj54n1->pwup_gpio); goto err_clk_put; } @@ -1363,8 +1366,8 @@ static int rj54n1_probe(struct i2c_client *client) rj54n1->enable_gpio = gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_LOW); if (IS_ERR(rj54n1->enable_gpio)) { - dev_info(&client->dev, "Unable to get GPIO \"enable\": %ld\n", - PTR_ERR(rj54n1->enable_gpio)); + dev_info(&client->dev, "Unable to get GPIO \"enable\": %pe\n", + rj54n1->enable_gpio); ret = PTR_ERR(rj54n1->enable_gpio); goto err_gpio_put; } diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 7716dfe2b8c9..ab31ee2b596b 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1368,10 +1368,6 @@ static int __s5c73m3_power_on(struct s5c73m3 *state) goto err_reg_dis; } - ret = clk_set_rate(state->clock, state->mclk_frequency); - if (ret < 0) - goto err_reg_dis; - ret = clk_prepare_enable(state->clock); if (ret < 0) goto err_reg_dis; @@ -1556,16 +1552,13 @@ static int s5c73m3_get_dt_data(struct s5c73m3 *state) if (!node) return -EINVAL; - state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME); + state->clock = devm_v4l2_sensor_clk_get_legacy(dev, S5C73M3_CLK_NAME, + false, + S5C73M3_DEFAULT_MCLK_FREQ); if (IS_ERR(state->clock)) - return PTR_ERR(state->clock); - - if (of_property_read_u32(node, "clock-frequency", - &state->mclk_frequency)) { - state->mclk_frequency = S5C73M3_DEFAULT_MCLK_FREQ; - dev_info(dev, "using default %u Hz clock frequency\n", - state->mclk_frequency); - } + return dev_err_probe(dev, PTR_ERR(state->clock), + "Failed to get the clock %s\n", + S5C73M3_CLK_NAME); /* Request GPIO lines asserted */ state->stby = devm_gpiod_get(dev, "standby", GPIOD_OUT_HIGH); diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h index 627e80cf5b72..68a19c2c8db8 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3.h +++ b/drivers/media/i2c/s5c73m3/s5c73m3.h @@ -382,8 +382,6 @@ struct s5c73m3 { struct clk *clock; - /* External master clock frequency */ - u32 mclk_frequency; /* Video bus type - MIPI-CSI2/parallel */ enum v4l2_mbus_type bus_type; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 24f399cd2124..d1d00eca8708 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -284,7 +284,6 @@ struct s5k5baf { struct regulator_bulk_data supplies[S5K5BAF_NUM_SUPPLIES]; struct clk *clock; - u32 mclk_frequency; struct s5k5baf_fw *fw; @@ -576,7 +575,7 @@ static void s5k5baf_hw_patch(struct s5k5baf *state) static void s5k5baf_hw_set_clocks(struct s5k5baf *state) { - unsigned long mclk = state->mclk_frequency / 1000; + unsigned long mclk = clk_get_rate(state->clock) / 1000; u16 status; static const u16 nseq_clk_cfg[] = { NSEQ(REG_I_USE_NPVI_CLOCKS, @@ -946,10 +945,6 @@ static int s5k5baf_power_on(struct s5k5baf *state) if (ret < 0) goto err; - ret = clk_set_rate(state->clock, state->mclk_frequency); - if (ret < 0) - goto err_reg_dis; - ret = clk_prepare_enable(state->clock); if (ret < 0) goto err_reg_dis; @@ -1841,14 +1836,6 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) return -EINVAL; } - ret = of_property_read_u32(node, "clock-frequency", - &state->mclk_frequency); - if (ret < 0) { - state->mclk_frequency = S5K5BAF_DEFAULT_MCLK_FREQ; - dev_info(dev, "using default %u Hz clock frequency\n", - state->mclk_frequency); - } - node_ep = of_graph_get_endpoint_by_regs(node, 0, -1); if (!node_ep) { dev_err(dev, "no endpoint defined at node %pOF\n", node); @@ -1967,9 +1954,11 @@ static int s5k5baf_probe(struct i2c_client *c) if (ret < 0) goto err_me; - state->clock = devm_clk_get(state->sd.dev, S5K5BAF_CLK_NAME); + state->clock = devm_v4l2_sensor_clk_get_legacy(state->sd.dev, + S5K5BAF_CLK_NAME, false, + S5K5BAF_DEFAULT_MCLK_FREQ); if (IS_ERR(state->clock)) { - ret = -EPROBE_DEFER; + ret = PTR_ERR(state->clock); goto err_me; } diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 0c2674115b7b..ba6477e88da3 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -51,7 +51,6 @@ enum { * @lock: mutex protecting the structure's members below * @format: media bus format at the sensor's source pad * @clock: pointer to &struct clk. - * @clock_frequency: clock frequency * @power_count: stores state if device is powered */ struct s5k6a3 { @@ -63,7 +62,6 @@ struct s5k6a3 { struct mutex lock; struct v4l2_mbus_framefmt format; struct clk *clock; - u32 clock_frequency; int power_count; }; @@ -192,10 +190,6 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor) int i = S5K6A3_SUPP_VDDA; int ret; - ret = clk_set_rate(sensor->clock, sensor->clock_frequency); - if (ret < 0) - return ret; - ret = pm_runtime_get(sensor->dev); if (ret < 0) goto error_rpm_put; @@ -292,22 +286,18 @@ static int s5k6a3_probe(struct i2c_client *client) mutex_init(&sensor->lock); sensor->dev = dev; - sensor->clock = devm_clk_get(sensor->dev, S5K6A3_CLK_NAME); + sensor->clock = devm_v4l2_sensor_clk_get_legacy(sensor->dev, + S5K6A3_CLK_NAME, false, + S5K6A3_DEFAULT_CLK_FREQ); if (IS_ERR(sensor->clock)) - return PTR_ERR(sensor->clock); + return dev_err_probe(sensor->dev, PTR_ERR(sensor->clock), + "failed to get extclk\n"); sensor->gpio_reset = devm_gpiod_get(dev, NULL, GPIOD_OUT_HIGH); ret = PTR_ERR_OR_ZERO(sensor->gpio_reset); if (ret) return ret; - if (of_property_read_u32(dev->of_node, "clock-frequency", - &sensor->clock_frequency)) { - sensor->clock_frequency = S5K6A3_DEFAULT_CLK_FREQ; - dev_info(dev, "using default %u Hz clock frequency\n", - sensor->clock_frequency); - } - for (i = 0; i < S5K6A3_NUM_SUPPLIES; i++) sensor->supplies[i].supply = s5k6a3_supply_names[i]; diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index 1ed8b5edb3fb..1c0031ba43b4 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -6,7 +6,7 @@ AC-3 support: - Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index b8b8f206ec3a..48d6730d9271 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -18,7 +18,7 @@ // Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com> // (2/17/2003) // -// VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl> +// VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@kernel.org> // // Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@kernel.org> // SAA7111, SAA7113 and SAA7118 support diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c index 818ed19cf37b..a42a7ffe3768 100644 --- a/drivers/media/i2c/saa7127.c +++ b/drivers/media/i2c/saa7127.c @@ -25,7 +25,7 @@ * Copyright (C) 2004 Chris Kennedy <c@groovy.org> * * VBI additions & cleanup: - * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@kernel.org> * * Note: the saa7126 is identical to the saa7127, and the saa7128 is * identical to the saa7129, except that the saa7126 and saa7128 have diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index b0793bb0c02a..713331be947c 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -10,7 +10,7 @@ * Changes by T.Adachi (tadachi@tadachi-net.com) * - support audio, video scaler etc, and checked the initialize sequence. * - * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl> + * Cleaned up by Hans Verkuil <hverkuil@kernel.org> * * Note: this is a reversed engineered driver based on captures from * the I2C bus under Windows. This chip is very similar to the saa7134, diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index f4568e87f018..4675181af5fb 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -465,7 +465,6 @@ static int mipid02_disable_streams(struct v4l2_subdev *sd, if (ret) goto error; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); error: @@ -542,7 +541,6 @@ error: 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; } @@ -749,8 +747,8 @@ static int mipid02_parse_rx_ep(struct mipid02_dev *bridge) of_node_put(ep_node); if (IS_ERR(asd)) { - dev_err(&client->dev, "fail to register asd to notifier %ld", - PTR_ERR(asd)); + dev_err(&client->dev, "fail to register asd to notifier %pe", + asd); return PTR_ERR(asd); } bridge->notifier.ops = &mipid02_notifier_ops; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 1cc7636e446d..a0ca19359c43 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -38,7 +38,21 @@ static int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-3)"); +MODULE_PARM_DESC(debug, " debug level (0-3)"); + +static int packet_type = 0x87; +module_param(packet_type, int, 0644); +MODULE_PARM_DESC(packet_type, + " Programmable Packet Type. Possible values:\n" + "\t\t 0x87: DRM InfoFrame (Default).\n" + "\t\t 0x01: Audio Clock Regeneration Packet\n" + "\t\t 0x02: Audio Sample Packet\n" + "\t\t 0x03: General Control Packet\n" + "\t\t 0x04: ACP Packet\n" + "\t\t 0x07: One Bit Audio Sample Packet\n" + "\t\t 0x08: DST Audio Packet\n" + "\t\t 0x09: High Bitrate Audio Stream Packet\n" + "\t\t 0x0a: Gamut Metadata Packet\n"); MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver"); MODULE_AUTHOR("Ramakrishnan Muthukrishnan <ram@rkrishnan.org>"); @@ -466,10 +480,29 @@ tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp, if (!is_hdmi(sd)) return 0; - if (type != V4L2_DEBUGFS_IF_AVI) + switch (type) { + case V4L2_DEBUGFS_IF_AVI: + i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_LEN); + break; + case V4L2_DEBUGFS_IF_AUDIO: + i2c_rd(sd, PK_AUD_0HEAD, buf, PK_AUD_LEN); + break; + case V4L2_DEBUGFS_IF_SPD: + i2c_rd(sd, PK_SPD_0HEAD, buf, PK_SPD_LEN); + break; + case V4L2_DEBUGFS_IF_HDMI: + i2c_rd(sd, PK_VS_0HEAD, buf, PK_VS_LEN); + break; + case V4L2_DEBUGFS_IF_DRM: + i2c_rd(sd, PK_ACP_0HEAD, buf, PK_ACP_LEN); + break; + default: return 0; + } + + if (!buf[2]) + return -ENOENT; - 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; @@ -478,26 +511,69 @@ tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp, return len < 0 ? 0 : len; } -static void print_avi_infoframe(struct v4l2_subdev *sd) +static void print_infoframes(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[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + + /* + * Updating the ACP TYPE here allows for dynamically + * changing the type you want to monitor, without having + * to reload the driver with a new packet_type module option value. + * + * Instead you can set it with the new value, then call + * VIDIOC_LOG_STATUS. + */ + i2c_wr8(sd, TYP_ACP_SET, packet_type); if (!is_hdmi(sd)) { - v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); + v4l2_info(sd, "DVI-D signal - InfoFrames not supported\n"); return; } - i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI)); + i2c_rd(sd, PK_AVI_0HEAD, buffer, PK_AVI_LEN); + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); - if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { - v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__); - return; + i2c_rd(sd, PK_VS_0HEAD, buffer, PK_VS_LEN); + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); + + i2c_rd(sd, PK_AUD_0HEAD, buffer, PK_AUD_LEN); + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); + + i2c_rd(sd, PK_SPD_0HEAD, buffer, PK_SPD_LEN); + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); + + i2c_rd(sd, PK_ACP_0HEAD, buffer, PK_ACP_LEN); + if (buffer[0] == packet_type) { + if (packet_type < 0x80) + v4l2_info(sd, "Packet: %*ph\n", PK_ACP_LEN, buffer); + else if (packet_type != 0x87) + v4l2_info(sd, "InfoFrame: %*ph\n", PK_ACP_LEN, buffer); + else if (hdmi_infoframe_unpack(&frame, buffer, + sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); } - hdmi_infoframe_log(KERN_INFO, dev, &frame); + i2c_rd(sd, PK_MS_0HEAD, buffer, PK_MS_LEN); + if (buffer[2] && buffer[2] + 3 <= PK_MS_LEN) + v4l2_info(sd, "MPEG Source InfoFrame: %*ph\n", + buffer[2] + 3, buffer); + + i2c_rd(sd, PK_ISRC1_0HEAD, buffer, PK_ISRC1_LEN); + if (buffer[0] == 0x05) + v4l2_info(sd, "ISRC1 Packet: %*ph\n", + PK_ISRC1_LEN, buffer); + + i2c_rd(sd, PK_ISRC2_0HEAD, buffer, PK_ISRC2_LEN); + if (buffer[0] == 0x06) + v4l2_info(sd, "ISRC2 Packet: %*ph\n", + PK_ISRC2_LEN, buffer); } /* --------------- CTRLS --------------- */ @@ -1375,7 +1451,7 @@ static int tc358743_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "Deep color mode: %d-bits per channel\n", deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & MASK_S_DEEPCOLOR) >> 2]); - print_avi_infoframe(sd); + print_infoframes(sd); return 0; } @@ -2232,10 +2308,15 @@ static int tc358743_probe(struct i2c_client *client) if (err < 0) goto err_work_queues; + i2c_wr8(sd, TYP_ACP_SET, packet_type); + i2c_wr8(sd, PK_AUTO_CLR, 0xff); + i2c_wr8(sd, NO_PKT_CLR, MASK_NO_ACP_CLR); + 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_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO | + V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI | + V4L2_DEBUGFS_IF_DRM, sd, tc358743_debugfs_if_read); v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); @@ -2245,10 +2326,10 @@ static int tc358743_probe(struct i2c_client *client) err_work_queues: cec_unregister_adapter(state->cec_adap); if (!state->i2c_client->irq) { - timer_delete(&state->timer); + timer_delete_sync(&state->timer); flush_work(&state->work_i2c_poll); } - cancel_delayed_work(&state->delayed_work_enable_hotplug); + cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); mutex_destroy(&state->confctl_mutex); err_hdl: media_entity_cleanup(&sd->entity); diff --git a/drivers/media/i2c/tc358743_regs.h b/drivers/media/i2c/tc358743_regs.h index 2495878dc358..aae288f8add3 100644 --- a/drivers/media/i2c/tc358743_regs.h +++ b/drivers/media/i2c/tc358743_regs.h @@ -692,6 +692,8 @@ #define MASK_NCO_F0_MOD_42MHZ 0x00 #define MASK_NCO_F0_MOD_27MHZ 0x01 +#define TYP_ACP_SET 0x8706 + #define PK_INT_MODE 0x8709 #define MASK_ISRC2_INT_MODE 0x80 #define MASK_ISRC_INT_MODE 0x40 @@ -702,6 +704,8 @@ #define MASK_AUD_INT_MODE 0x02 #define MASK_AVI_INT_MODE 0x01 +#define PK_AUTO_CLR 0x870a + #define NO_PKT_LIMIT 0x870B #define MASK_NO_ACP_LIMIT 0xf0 #define SET_NO_ACP_LIMIT_MS(milliseconds) ((((milliseconds) / 80) << 4) & \ @@ -720,25 +724,44 @@ #define ERR_PK_LIMIT 0x870D #define NO_PKT_LIMIT2 0x870E #define PK_AVI_0HEAD 0x8710 -#define PK_AVI_1HEAD 0x8711 -#define PK_AVI_2HEAD 0x8712 #define PK_AVI_0BYTE 0x8713 -#define PK_AVI_1BYTE 0x8714 -#define PK_AVI_2BYTE 0x8715 -#define PK_AVI_3BYTE 0x8716 -#define PK_AVI_4BYTE 0x8717 -#define PK_AVI_5BYTE 0x8718 -#define PK_AVI_6BYTE 0x8719 -#define PK_AVI_7BYTE 0x871A -#define PK_AVI_8BYTE 0x871B -#define PK_AVI_9BYTE 0x871C -#define PK_AVI_10BYTE 0x871D -#define PK_AVI_11BYTE 0x871E -#define PK_AVI_12BYTE 0x871F -#define PK_AVI_13BYTE 0x8720 -#define PK_AVI_14BYTE 0x8721 -#define PK_AVI_15BYTE 0x8722 #define PK_AVI_16BYTE 0x8723 +#define PK_AVI_LEN (PK_AVI_16BYTE - PK_AVI_0HEAD + 1) + +#define PK_AUD_0HEAD 0x8730 +#define PK_AUD_0BYTE 0x8733 +#define PK_AUD_10BYTE 0x873d +#define PK_AUD_LEN (PK_AUD_10BYTE - PK_AUD_0HEAD + 1) + +#define PK_MS_0HEAD 0x8740 +#define PK_MS_0BYTE 0x8743 +#define PK_MS_10BYTE 0x874d +#define PK_MS_LEN (PK_MS_10BYTE - PK_MS_0HEAD + 1) + +#define PK_SPD_0HEAD 0x8750 +#define PK_SPD_0BYTE 0x8753 +#define PK_SPD_27BYTE 0x876e +#define PK_SPD_LEN (PK_SPD_27BYTE - PK_SPD_0HEAD + 1) + +#define PK_VS_0HEAD 0x8770 +#define PK_VS_0BYTE 0x8773 +#define PK_VS_27BYTE 0x878e +#define PK_VS_LEN (PK_VS_27BYTE - PK_VS_0HEAD + 1) + +#define PK_ACP_0HEAD 0x8790 +#define PK_ACP_0BYTE 0x8793 +#define PK_ACP_27BYTE 0x87ae +#define PK_ACP_LEN (PK_ACP_27BYTE - PK_ACP_0HEAD + 1) + +#define PK_ISRC1_0HEAD 0x87b0 +#define PK_ISRC1_0BYTE 0x87b3 +#define PK_ISRC1_27BYTE 0x87c2 +#define PK_ISRC1_LEN (PK_ISRC1_27BYTE - PK_ISRC1_0HEAD + 1) + +#define PK_ISRC2_0HEAD 0x87d0 +#define PK_ISRC2_0BYTE 0x87d3 +#define PK_ISRC2_27BYTE 0x87ee +#define PK_ISRC2_LEN (PK_ISRC2_27BYTE - PK_ISRC2_0HEAD + 1) #define BKSV 0x8800 diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index 143aa1359aba..86d9ba3ea4e5 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -816,7 +816,6 @@ static int tc358746_s_stream(struct v4l2_subdev *sd, int enable) return 0; err_out: - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return err; @@ -838,7 +837,6 @@ err_out: if (err) return err; - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return v4l2_subdev_call(src, video, s_stream, 0); @@ -1016,7 +1014,6 @@ tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) err = tc358746_read(tc358746, reg->reg, &val); reg->val = val; - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return err; @@ -1032,7 +1029,6 @@ tc358746_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) tc358746_write(tc358746, (u32)reg->reg, (u32)reg->val); - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return 0; @@ -1226,14 +1222,16 @@ tc358746_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return tc358746->pll_rate / (prediv * postdiv); } -static long tc358746_mclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int tc358746_mclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { struct tc358746 *tc358746 = clk_hw_to_tc358746(hw); - *parent_rate = tc358746->pll_rate; + req->best_parent_rate = tc358746->pll_rate; - return tc358746_find_mclk_settings(tc358746, rate); + req->rate = tc358746_find_mclk_settings(tc358746, req->rate); + + return 0; } static int tc358746_mclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -1250,7 +1248,7 @@ static const struct clk_ops tc358746_mclk_ops = { .enable = tc358746_mclk_enable, .disable = tc358746_mclk_disable, .recalc_rate = tc358746_recalc_rate, - .round_rate = tc358746_mclk_round_rate, + .determine_rate = tc358746_mclk_determine_rate, .set_rate = tc358746_mclk_set_rate, }; @@ -1395,7 +1393,6 @@ static int tc358746_init_hw(struct tc358746 *tc358746) } err = tc358746_read(tc358746, CHIPID_REG, &val); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); if (err) return -ENODEV; diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 1087d2bddaf2..3532766cd795 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -2797,7 +2797,6 @@ err_free_media: err_free_handler: v4l2_ctrl_handler_free(&state->hdl); err_free_mutex: - cancel_delayed_work(&state->delayed_work_enable_hpd); mutex_destroy(&state->page_lock); mutex_destroy(&state->lock); tda1997x_set_power(state, 0); diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c index d61da811c9da..e3b266db571f 100644 --- a/drivers/media/i2c/tda9840.c +++ b/drivers/media/i2c/tda9840.c @@ -3,7 +3,7 @@ tda9840 - i2c-driver for the tda9840 by SGS Thomson Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> - Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> The tda9840 is a stereo/dual sound processor with digital identification. It can be found at address 0x84 on the i2c-bus. diff --git a/drivers/media/i2c/tea6415c.c b/drivers/media/i2c/tea6415c.c index 4aaf66353610..0cd2e6c52e20 100644 --- a/drivers/media/i2c/tea6415c.c +++ b/drivers/media/i2c/tea6415c.c @@ -3,7 +3,7 @@ tea6415c - i2c-driver for the tea6415c by SGS Thomson Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> - Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> The tea6415c is a bus controlled video-matrix-switch with 8 inputs and 6 outputs. diff --git a/drivers/media/i2c/tea6420.c b/drivers/media/i2c/tea6420.c index 5c5ea3973251..400883fc0c0f 100644 --- a/drivers/media/i2c/tea6420.c +++ b/drivers/media/i2c/tea6420.c @@ -3,7 +3,7 @@ tea6420 - i2c-driver for the tea6420 by SGS Thomson Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> - Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> The tea6420 is a bus controlled audio-matrix with 5 stereo inputs, 4 stereo outputs and gain control for each output. diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c index 8852c56431fe..775cfba188d8 100644 --- a/drivers/media/i2c/thp7312.c +++ b/drivers/media/i2c/thp7312.c @@ -808,7 +808,6 @@ static int thp7312_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { thp7312_stream_enable(thp7312, false); - pm_runtime_mark_last_busy(thp7312->dev); pm_runtime_put_autosuspend(thp7312->dev); v4l2_subdev_unlock_state(sd_state); @@ -839,7 +838,6 @@ static int thp7312_s_stream(struct v4l2_subdev *sd, int enable) goto finish_unlock; finish_pm: - pm_runtime_mark_last_busy(thp7312->dev); pm_runtime_put_autosuspend(thp7312->dev); finish_unlock: v4l2_subdev_unlock_state(sd_state); @@ -1147,7 +1145,6 @@ static int thp7312_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(thp7312->dev); pm_runtime_put_autosuspend(thp7312->dev); return ret; @@ -2183,7 +2180,6 @@ static int thp7312_probe(struct i2c_client *client) * 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); dev_info(dev, "THP7312 firmware version %02u.%02u\n", diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index b7cedc5b3e8e..ff268ebeb4d9 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 <hansverk@cisco.com> + * Hans Verkuil <hverkuil@kernel.org> * Lad, Prabhakar <prabhakar.lad@ti.com> * Martin Bugge <marbugge@cisco.com> * diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c index b7b31b6192af..6f6bc5236565 100644 --- a/drivers/media/i2c/tlv320aic23b.c +++ b/drivers/media/i2c/tlv320aic23b.c @@ -7,7 +7,7 @@ * Based on wm8775 driver * * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to> - * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2005 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/module.h> diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c index 9d0b72a213be..a178af46e695 100644 --- a/drivers/media/i2c/upd64031a.c +++ b/drivers/media/i2c/upd64031a.c @@ -4,7 +4,7 @@ * * 2003 by T.Adachi <tadachi@tadachi-net.com> * 2003 by Takeru KOMORIYA <komoriya@paken.org> - * 2006 by Hans Verkuil <hverkuil@xs4all.nl> + * 2006 by Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c index 2e99ed5da42c..5421dc5e32c9 100644 --- a/drivers/media/i2c/upd64083.c +++ b/drivers/media/i2c/upd64083.c @@ -4,7 +4,7 @@ * * 2003 by T.Adachi (tadachi@tadachi-net.com) * 2003 by Takeru KOMORIYA <komoriya@paken.org> - * 2006 by Hans Verkuil <hverkuil@xs4all.nl> + * 2006 by Hans Verkuil <hverkuil@kernel.org> */ #include <linux/module.h> diff --git a/drivers/media/i2c/vd55g1.c b/drivers/media/i2c/vd55g1.c index c0754fd03b1d..78d18c028154 100644 --- a/drivers/media/i2c/vd55g1.c +++ b/drivers/media/i2c/vd55g1.c @@ -29,9 +29,11 @@ /* Register Map */ #define VD55G1_REG_MODEL_ID CCI_REG32_LE(0x0000) -#define VD55G1_MODEL_ID 0x53354731 +#define VD55G1_MODEL_ID_VD55G1 0x53354731 /* Mono */ +#define VD55G1_MODEL_ID_VD65G4 0x53354733 /* RGB */ #define VD55G1_REG_REVISION CCI_REG16_LE(0x0004) #define VD55G1_REVISION_CCB 0x2020 +#define VD55G1_REVISION_BAYER 0x3030 #define VD55G1_REG_FWPATCH_REVISION CCI_REG16_LE(0x0012) #define VD55G1_REG_FWPATCH_START_ADDR CCI_REG8(0x2000) #define VD55G1_REG_SYSTEM_FSM CCI_REG8(0x001c) @@ -39,7 +41,8 @@ #define VD55G1_SYSTEM_FSM_SW_STBY 0x02 #define VD55G1_SYSTEM_FSM_STREAMING 0x03 #define VD55G1_REG_BOOT CCI_REG8(0x0200) -#define VD55G1_BOOT_PATCH_SETUP 2 +#define VD55G1_BOOT_BOOT 1 +#define VD55G1_BOOT_PATCH_AND_BOOT 2 #define VD55G1_REG_STBY CCI_REG8(0x0201) #define VD55G1_STBY_START_STREAM 1 #define VD55G1_REG_STREAMING CCI_REG8(0x0202) @@ -66,7 +69,7 @@ #define VD55G1_REG_READOUT_CTRL CCI_REG8(0x052e) #define VD55G1_READOUT_CTRL_BIN_MODE_NORMAL 0 #define VD55G1_READOUT_CTRL_BIN_MODE_DIGITAL_X2 1 -#define VD55G1_REG_DUSTER_CTRL CCI_REG8(0x03ea) +#define VD55G1_REG_DUSTER_CTRL CCI_REG8(0x03ae) #define VD55G1_DUSTER_ENABLE BIT(0) #define VD55G1_DUSTER_DISABLE 0 #define VD55G1_DUSTER_DYN_ENABLE BIT(1) @@ -132,7 +135,10 @@ #define VD55G1_MIPI_RATE_MIN (250 * MEGA) #define VD55G1_MIPI_RATE_MAX (1200 * MEGA) -static const u8 patch_array[] = { +#define VD55G1_MODEL_ID_NAME(id) \ + ((id) == VD55G1_MODEL_ID_VD55G1 ? "vd55g1" : "vd65g4") + +static const u8 vd55g1_patch_array[] = { 0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00, 0xf0, 0x01, 0x42, 0x00, 0xe6, 0x01, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -466,22 +472,24 @@ struct vd55g1_mode { u32 height; }; -struct vd55g1_fmt_desc { - u32 code; - u8 bpp; - u8 data_type; +static const u32 vd55g1_mbus_formats_mono[] = { + MEDIA_BUS_FMT_Y8_1X8, + MEDIA_BUS_FMT_Y10_1X10, }; -static const struct vd55g1_fmt_desc vd55g1_mbus_codes[] = { +/* Format order is : no flip, hflip, vflip, both */ +static const u32 vd55g1_mbus_formats_bayer[][4] = { { - .code = MEDIA_BUS_FMT_Y8_1X8, - .bpp = 8, - .data_type = MIPI_CSI2_DT_RAW8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SBGGR8_1X8, }, { - .code = MEDIA_BUS_FMT_Y10_1X10, - .bpp = 10, - .data_type = MIPI_CSI2_DT_RAW10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SBGGR10_1X10, }, }; @@ -524,6 +532,7 @@ struct vd55g1_vblank_limits { struct vd55g1 { struct device *dev; + unsigned int id; struct v4l2_subdev sd; struct media_pad pad; struct regulator_bulk_data supplies[ARRAY_SIZE(vd55g1_supply_name)]; @@ -572,27 +581,78 @@ static inline struct vd55g1 *ctrl_to_vd55g1(struct v4l2_ctrl *ctrl) return to_vd55g1(sd); } -static const struct vd55g1_fmt_desc *vd55g1_get_fmt_desc(struct vd55g1 *sensor, - u32 code) +static unsigned int vd55g1_get_fmt_bpp(u32 code) { - unsigned int i; + switch (code) { + case MEDIA_BUS_FMT_Y8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SBGGR8_1X8: + default: + return 8; + + case MEDIA_BUS_FMT_Y10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: + return 10; + } +} + +static unsigned int vd55g1_get_fmt_data_type(u32 code) +{ + switch (code) { + case MEDIA_BUS_FMT_Y8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SBGGR8_1X8: + default: + return MIPI_CSI2_DT_RAW8; + + case MEDIA_BUS_FMT_Y10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SBGGR10_1X10: + return MIPI_CSI2_DT_RAW10; + } +} + +static u32 vd55g1_get_fmt_code(struct vd55g1 *sensor, u32 code) +{ + unsigned int i, j; - for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_codes); i++) { - if (vd55g1_mbus_codes[i].code == code) - return &vd55g1_mbus_codes[i]; + if (sensor->id == VD55G1_MODEL_ID_VD55G1) + return code; + + for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_bayer); i++) { + for (j = 0; j < ARRAY_SIZE(vd55g1_mbus_formats_bayer[i]); j++) { + if (vd55g1_mbus_formats_bayer[i][j] == code) + goto adapt_bayer_pattern; + } } + dev_warn(sensor->dev, "Unsupported mbus format\n"); - /* Should never happen */ - dev_warn(sensor->dev, "Unsupported code %d. default to 8 bpp\n", code); + return code; + +adapt_bayer_pattern: + j = 0; + /* In first init_state() call, controls might not be initialized yet */ + if (sensor->hflip_ctrl && sensor->vflip_ctrl) { + j = (sensor->hflip_ctrl->val ? 1 : 0) + + (sensor->vflip_ctrl->val ? 2 : 0); + } - return &vd55g1_mbus_codes[0]; + return vd55g1_mbus_formats_bayer[i][j]; } static s32 vd55g1_get_pixel_rate(struct vd55g1 *sensor, struct v4l2_mbus_framefmt *format) { - return sensor->mipi_rate / - vd55g1_get_fmt_desc(sensor, format->code)->bpp; + return sensor->mipi_rate / vd55g1_get_fmt_bpp(format->code); } static unsigned int vd55g1_get_hblank_min(struct vd55g1 *sensor, @@ -605,7 +665,7 @@ static unsigned int vd55g1_get_hblank_min(struct vd55g1 *sensor, /* MIPI required time */ mipi_req_line_time = (crop->width * - vd55g1_get_fmt_desc(sensor, format->code)->bpp + + vd55g1_get_fmt_bpp(format->code) + VD55G1_MIPI_MARGIN) / (sensor->mipi_rate / MEGA); mipi_req_line_length = mipi_req_line_time * sensor->pixel_clock / @@ -887,7 +947,7 @@ static void vd55g1_update_pad_fmt(struct vd55g1 *sensor, const struct vd55g1_mode *mode, u32 code, struct v4l2_mbus_framefmt *fmt) { - fmt->code = code; + fmt->code = vd55g1_get_fmt_code(sensor, code); fmt->width = mode->width; fmt->height = mode->height; fmt->colorspace = V4L2_COLORSPACE_RAW; @@ -951,10 +1011,9 @@ static int vd55g1_set_framefmt(struct vd55g1 *sensor, int ret = 0; vd55g1_write(sensor, VD55G1_REG_FORMAT_CTRL, - vd55g1_get_fmt_desc(sensor, format->code)->bpp, &ret); + vd55g1_get_fmt_bpp(format->code), &ret); vd55g1_write(sensor, VD55G1_REG_OIF_IMG_CTRL, - vd55g1_get_fmt_desc(sensor, format->code)->data_type, - &ret); + vd55g1_get_fmt_data_type(format->code), &ret); switch (crop->width / format->width) { case 1: @@ -1104,7 +1163,6 @@ static int vd55g1_disable_streams(struct v4l2_subdev *sd, vd55g1_grab_ctrls(sensor, false); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1115,26 +1173,45 @@ static int vd55g1_patch(struct vd55g1 *sensor) u64 patch; int ret = 0; - vd55g1_write_array(sensor, VD55G1_REG_FWPATCH_START_ADDR, - sizeof(patch_array), patch_array, &ret); - vd55g1_write(sensor, VD55G1_REG_BOOT, VD55G1_BOOT_PATCH_SETUP, &ret); - vd55g1_poll_reg(sensor, VD55G1_REG_BOOT, 0, &ret); - if (ret) { - dev_err(sensor->dev, "Failed to apply patch\n"); - return ret; - } + /* vd55g1 needs a patch while vd65g4 does not */ + if (sensor->id == VD55G1_MODEL_ID_VD55G1) { + vd55g1_write_array(sensor, VD55G1_REG_FWPATCH_START_ADDR, + sizeof(vd55g1_patch_array), + vd55g1_patch_array, &ret); + vd55g1_write(sensor, VD55G1_REG_BOOT, + VD55G1_BOOT_PATCH_AND_BOOT, &ret); + vd55g1_poll_reg(sensor, VD55G1_REG_BOOT, 0, &ret); + if (ret) { + dev_err(sensor->dev, "Failed to apply patch\n"); + return ret; + } - vd55g1_read(sensor, VD55G1_REG_FWPATCH_REVISION, &patch, &ret); - if (patch != (VD55G1_FWPATCH_REVISION_MAJOR << 8) + - VD55G1_FWPATCH_REVISION_MINOR) { - dev_err(sensor->dev, "Bad patch version expected %d.%d got %d.%d\n", - VD55G1_FWPATCH_REVISION_MAJOR, - VD55G1_FWPATCH_REVISION_MINOR, + vd55g1_read(sensor, VD55G1_REG_FWPATCH_REVISION, &patch, &ret); + if (patch != (VD55G1_FWPATCH_REVISION_MAJOR << 8) + + VD55G1_FWPATCH_REVISION_MINOR) { + dev_err(sensor->dev, "Bad patch version expected %d.%d got %d.%d\n", + VD55G1_FWPATCH_REVISION_MAJOR, + VD55G1_FWPATCH_REVISION_MINOR, + (u8)(patch >> 8), (u8)(patch & 0xff)); + return -ENODEV; + } + dev_dbg(sensor->dev, "patch %d.%d applied\n", (u8)(patch >> 8), (u8)(patch & 0xff)); - return -ENODEV; + + } else { + vd55g1_write(sensor, VD55G1_REG_BOOT, VD55G1_BOOT_BOOT, &ret); + vd55g1_poll_reg(sensor, VD55G1_REG_BOOT, 0, &ret); + if (ret) { + dev_err(sensor->dev, "Failed to boot\n"); + return ret; + } + } + + ret = vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_SW_STBY, NULL); + if (ret) { + dev_err(sensor->dev, "Sensor waiting after boot failed\n"); + return ret; } - dev_dbg(sensor->dev, "patch %d.%d applied\n", - (u8)(patch >> 8), (u8)(patch & 0xff)); return 0; } @@ -1166,10 +1243,19 @@ static int vd55g1_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - if (code->index >= ARRAY_SIZE(vd55g1_mbus_codes)) - return -EINVAL; + struct vd55g1 *sensor = to_vd55g1(sd); + u32 base_code; - code->code = vd55g1_mbus_codes[code->index].code; + if (sensor->id == VD55G1_MODEL_ID_VD55G1) { + if (code->index >= ARRAY_SIZE(vd55g1_mbus_formats_mono)) + return -EINVAL; + base_code = vd55g1_mbus_formats_mono[code->index]; + } else { + if (code->index >= ARRAY_SIZE(vd55g1_mbus_formats_bayer)) + return -EINVAL; + base_code = vd55g1_mbus_formats_bayer[code->index][0]; + } + code->code = vd55g1_get_fmt_code(sensor, base_code); return 0; } @@ -1276,7 +1362,7 @@ static int vd55g1_init_state(struct v4l2_subdev *sd, return ret; vd55g1_update_pad_fmt(sensor, &vd55g1_supported_modes[VD55G1_MODE_DEF], - vd55g1_mbus_codes[VD55G1_MBUS_CODE_DEF].code, + vd55g1_get_fmt_code(sensor, VD55G1_MBUS_CODE_DEF), &fmt.format); return vd55g1_set_pad_fmt(sd, sd_state, &fmt); @@ -1286,9 +1372,16 @@ static int vd55g1_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { + struct vd55g1 *sensor = to_vd55g1(sd); + u32 code; + if (fse->index >= ARRAY_SIZE(vd55g1_supported_modes)) return -EINVAL; + code = vd55g1_get_fmt_code(sensor, fse->code); + if (fse->code != code) + return -EINVAL; + fse->min_width = vd55g1_supported_modes[fse->index].width; fse->max_width = fse->min_width; fse->min_height = vd55g1_supported_modes[fse->index].height; @@ -1338,7 +1431,6 @@ static int vd55g1_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1433,7 +1525,6 @@ static int vd55g1_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1466,8 +1557,12 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor) /* Flip cluster */ sensor->hflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + if (sensor->hflip_ctrl) + sensor->hflip_ctrl->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; sensor->vflip_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + if (sensor->vflip_ctrl) + sensor->vflip_ctrl->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; v4l2_ctrl_cluster(2, &sensor->hflip_ctrl); /* Exposition cluster */ @@ -1551,26 +1646,34 @@ unlock_state: static int vd55g1_detect(struct vd55g1 *sensor) { - u64 device_rev; - u64 id; + unsigned int dt_id = (uintptr_t)device_get_match_data(sensor->dev); + u64 rev, id; int ret; ret = vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, NULL); if (ret) return ret; - if (id != VD55G1_MODEL_ID) { - dev_warn(sensor->dev, "Unsupported sensor id %x\n", (u32)id); + if (id != VD55G1_MODEL_ID_VD55G1 && id != VD55G1_MODEL_ID_VD65G4) { + dev_warn(sensor->dev, "Unsupported sensor id 0x%x\n", + (u32)id); + return -ENODEV; + } + if (id != dt_id) { + dev_err(sensor->dev, "Probed sensor %s and device tree definition (%s) mismatch", + VD55G1_MODEL_ID_NAME(id), VD55G1_MODEL_ID_NAME(dt_id)); return -ENODEV; } + sensor->id = id; - ret = vd55g1_read(sensor, VD55G1_REG_REVISION, &device_rev, NULL); + ret = vd55g1_read(sensor, VD55G1_REG_REVISION, &rev, NULL); if (ret) return ret; - if (device_rev != VD55G1_REVISION_CCB) { - dev_err(sensor->dev, "Unsupported sensor revision (0x%x)\n", - (u16)device_rev); + if ((id == VD55G1_MODEL_ID_VD55G1 && rev != VD55G1_REVISION_CCB) && + (id == VD55G1_MODEL_ID_VD65G4 && rev != VD55G1_REVISION_BAYER)) { + dev_err(sensor->dev, "Unsupported sensor revision 0x%x for sensor %s\n", + (u16)rev, VD55G1_MODEL_ID_NAME(id)); return -ENODEV; } @@ -1619,13 +1722,6 @@ static int vd55g1_power_on(struct device *dev) goto disable_clock; } - ret = vd55g1_wait_state(sensor, VD55G1_SYSTEM_FSM_SW_STBY, NULL); - if (ret) { - dev_err(dev, "Sensor waiting after patch failed %d\n", - ret); - goto disable_clock; - } - return 0; disable_clock: @@ -1863,7 +1959,7 @@ static int vd55g1_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "Failed to get regulators\n"); - sensor->xclk = devm_clk_get(dev, NULL); + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->xclk)) return dev_err_probe(dev, PTR_ERR(sensor->xclk), "Failed to get xclk\n"); @@ -1895,7 +1991,6 @@ static int vd55g1_probe(struct i2c_client *client) pm_runtime_enable(dev); pm_runtime_set_autosuspend_delay(dev, 4000); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); ret = vd55g1_subdev_init(sensor); @@ -1938,7 +2033,8 @@ static void vd55g1_remove(struct i2c_client *client) } static const struct of_device_id vd55g1_dt_ids[] = { - { .compatible = "st,vd55g1" }, + { .compatible = "st,vd55g1", .data = (void *)VD55G1_MODEL_ID_VD55G1 }, + { .compatible = "st,vd65g4", .data = (void *)VD55G1_MODEL_ID_VD65G4 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, vd55g1_dt_ids); diff --git a/drivers/media/i2c/vd56g3.c b/drivers/media/i2c/vd56g3.c index 5d951ad0b478..157acea9e286 100644 --- a/drivers/media/i2c/vd56g3.c +++ b/drivers/media/i2c/vd56g3.c @@ -493,7 +493,6 @@ static int vd56g3_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -577,7 +576,6 @@ static int vd56g3_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1021,7 +1019,6 @@ static int vd56g3_disable_streams(struct v4l2_subdev *sd, __v4l2_ctrl_grab(sensor->vflip_ctrl, false); __v4l2_ctrl_grab(sensor->patgen_ctrl, false); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1474,7 +1471,7 @@ static int vd56g3_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "Failed to get regulators\n"); - sensor->xclk = devm_clk_get(dev, NULL); + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->xclk)) return dev_err_probe(dev, PTR_ERR(sensor->xclk), "Failed to get xclk\n"); @@ -1527,7 +1524,6 @@ static int vd56g3_probe(struct i2c_client *client) } /* Sensor could now be powered off (after the autosuspend delay) */ - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); dev_dbg(dev, "Successfully probe %s sensor\n", diff --git a/drivers/media/i2c/vgxy61.c b/drivers/media/i2c/vgxy61.c index 5b0479f3a3c0..d64d0099e6fe 100644 --- a/drivers/media/i2c/vgxy61.c +++ b/drivers/media/i2c/vgxy61.c @@ -1181,6 +1181,21 @@ static int vgxy61_s_stream(struct v4l2_subdev *sd, int enable) return ret; } +static int vgxy61_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct vgxy61_dev *sensor = to_vgxy61_dev(sd); + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + fd->num_entries = 1; + fd->entry[0].pixelcode = sensor->fmt.code; + fd->entry[0].stream = 0; + fd->entry[0].bus.csi2.vc = 0; + fd->entry[0].bus.csi2.dt = get_data_type_by_code(sensor->fmt.code); + + return 0; +} + static int vgxy61_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) @@ -1402,6 +1417,7 @@ static const struct v4l2_subdev_pad_ops vgxy61_pad_ops = { .set_fmt = vgxy61_set_fmt, .get_selection = vgxy61_get_selection, .enum_frame_size = vgxy61_enum_frame_size, + .get_frame_desc = vgxy61_get_frame_desc, }; static const struct v4l2_subdev_ops vgxy61_subdev_ops = { @@ -1761,11 +1777,11 @@ static int vgxy61_probe(struct i2c_client *client) return ret; } - sensor->xclk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->xclk)) { - dev_err(dev, "failed to get xclk\n"); - return PTR_ERR(sensor->xclk); - } + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->xclk)) + return dev_err_probe(dev, PTR_ERR(sensor->xclk), + "failed to get xclk\n"); + sensor->clk_freq = clk_get_rate(sensor->xclk); if (sensor->clk_freq < 6 * HZ_PER_MHZ || sensor->clk_freq > 27 * HZ_PER_MHZ) { diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 0dd991d70d53..1eee2d4f5b40 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -288,7 +288,6 @@ static int amg88xx_read(struct device *dev, enum hwmon_sensor_types type, return tmp; tmp = regmap_bulk_read(data->regmap, AMG88XX_REG_TTHL, &buf, 2); - pm_runtime_mark_last_busy(regmap_get_device(data->regmap)); pm_runtime_put_autosuspend(regmap_get_device(data->regmap)); if (tmp) return tmp; @@ -527,7 +526,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) return 0; error_rpm_put: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); error_del_list: video_i2c_del_list(vq, VB2_BUF_STATE_QUEUED); @@ -544,7 +542,6 @@ static void stop_streaming(struct vb2_queue *vq) kthread_stop(data->kthread_vid_cap); data->kthread_vid_cap = NULL; - pm_runtime_mark_last_busy(regmap_get_device(data->regmap)); pm_runtime_put_autosuspend(regmap_get_device(data->regmap)); video_i2c_del_list(vq, VB2_BUF_STATE_ERROR); @@ -853,7 +850,6 @@ static int video_i2c_probe(struct i2c_client *client) if (ret < 0) goto error_pm_disable; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c index 06fd46a63c72..df21950be24f 100644 --- a/drivers/media/i2c/vp27smpx.c +++ b/drivers/media/i2c/vp27smpx.c @@ -2,7 +2,7 @@ /* * vp27smpx - driver version 0.0.1 * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * * Based on a tvaudio patch from Takahiro Adachi <tadachi@tadachi-net.com> * and Kazuhiko Kawakami <kazz-0@mail.goo.ne.jp> diff --git a/drivers/media/i2c/wm8739.c b/drivers/media/i2c/wm8739.c index c091b78a5b41..72eb10339d06 100644 --- a/drivers/media/i2c/wm8739.c +++ b/drivers/media/i2c/wm8739.c @@ -4,7 +4,7 @@ * * Copyright (C) 2005 T. Adachi <tadachi@tadachi-net.com> * - * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2005 Hans Verkuil <hverkuil@kernel.org> * - Cleanup */ diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c index 619b2988577c..56778d3bc28a 100644 --- a/drivers/media/i2c/wm8775.c +++ b/drivers/media/i2c/wm8775.c @@ -6,7 +6,7 @@ * * Based on saa7115 driver * - * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2005 Hans Verkuil <hverkuil@kernel.org> * - Cleanup * - V4L2 API update * - sound fixes diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c index 56444edaf136..6daa7aa99442 100644 --- a/drivers/media/mc/mc-devnode.c +++ b/drivers/media/mc/mc-devnode.c @@ -50,11 +50,6 @@ static void media_devnode_release(struct device *cd) { struct media_devnode *devnode = to_media_devnode(cd); - mutex_lock(&media_devnode_lock); - /* Mark device node number as free */ - clear_bit(devnode->minor, media_devnode_nums); - mutex_unlock(&media_devnode_lock); - /* Release media_devnode and perform other cleanups as needed. */ if (devnode->release) devnode->release(devnode); @@ -281,6 +276,7 @@ void media_devnode_unregister(struct media_devnode *devnode) /* Delete the cdev on this minor as well */ cdev_device_del(&devnode->cdev, &devnode->dev); devnode->media_dev = NULL; + clear_bit(devnode->minor, media_devnode_nums); mutex_unlock(&media_devnode_lock); put_device(&devnode->dev); diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 045590905582..9519a537bfa2 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -682,8 +682,8 @@ done: return 0; dev_dbg(walk->mdev->dev, - "media pipeline: adding unconnected pads of '%s'\n", - local->entity->name); + "media pipeline: adding unconnected pads of '%s' reachable from pad %u\n", + origin->entity->name, origin->index); media_entity_for_each_pad(origin->entity, local) { /* @@ -691,7 +691,7 @@ done: * (already discovered through iterating over links) and pads * not internally connected. */ - if (origin == local || !local->num_links || + if (origin == local || local->num_links || !media_entity_has_pad_interdep(origin->entity, origin->index, local->index)) continue; diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c index 5edfc2791ce7..2ac9ac0a740b 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 <hansverk@cisco.com> + * Author: Hans Verkuil <hverkuil@kernel.org> * Author: Sakari Ailus <sakari.ailus@linux.intel.com> */ @@ -282,8 +282,6 @@ EXPORT_SYMBOL_GPL(media_request_get_by_fd); int media_request_alloc(struct media_device *mdev, int *alloc_fd) { struct media_request *req; - struct file *filp; - int fd; int ret; /* Either both are NULL or both are non-NULL */ @@ -297,19 +295,6 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd) if (!req) return -ENOMEM; - fd = get_unused_fd_flags(O_CLOEXEC); - if (fd < 0) { - ret = fd; - goto err_free_req; - } - - filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC); - if (IS_ERR(filp)) { - ret = PTR_ERR(filp); - goto err_put_fd; - } - - filp->private_data = req; req->mdev = mdev; req->state = MEDIA_REQUEST_STATE_IDLE; req->num_incomplete_objects = 0; @@ -320,19 +305,24 @@ int media_request_alloc(struct media_device *mdev, int *alloc_fd) req->updating_count = 0; req->access_count = 0; - *alloc_fd = fd; + FD_PREPARE(fdf, O_CLOEXEC, + anon_inode_getfile("request", &request_fops, NULL, + O_CLOEXEC)); + if (fdf.err) { + ret = fdf.err; + goto err_free_req; + } + + fd_prepare_file(fdf)->private_data = req; + + *alloc_fd = fd_publish(fdf); snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d", - atomic_inc_return(&mdev->request_id), fd); + atomic_inc_return(&mdev->request_id), *alloc_fd); dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str); - fd_install(fd, filp); - return 0; -err_put_fd: - put_unused_fd(fd); - err_free_req: if (mdev->ops->req_free) mdev->ops->req_free(req); diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c index 486c8ec0fa60..ab53c5b02c48 100644 --- a/drivers/media/pci/b2c2/flexcop-pci.c +++ b/drivers/media/pci/b2c2/flexcop-pci.c @@ -411,7 +411,7 @@ static void flexcop_pci_remove(struct pci_dev *pdev) struct flexcop_pci *fc_pci = pci_get_drvdata(pdev); if (irq_chk_intv > 0) - cancel_delayed_work(&fc_pci->irq_check_work); + cancel_delayed_work_sync(&fc_pci->irq_check_work); flexcop_pci_dma_exit(fc_pci); flexcop_device_exit(fc_pci->fc_dev); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 9ce67f515843..17e4529e537a 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1620,7 +1620,7 @@ static int bttv_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id) +static int bttv_querystd(struct file *file, void *priv, v4l2_std_id *id) { struct bttv *btv = video_drvdata(file); @@ -1750,7 +1750,7 @@ static int bttv_s_frequency(struct file *file, void *priv, return 0; } -static int bttv_log_status(struct file *file, void *f) +static int bttv_log_status(struct file *file, void *priv) { struct video_device *vdev = video_devdata(file); struct bttv *btv = video_drvdata(file); @@ -1761,7 +1761,7 @@ static int bttv_log_status(struct file *file, void *f) } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int bttv_g_register(struct file *file, void *f, +static int bttv_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct bttv *btv = video_drvdata(file); @@ -1774,7 +1774,7 @@ static int bttv_g_register(struct file *file, void *f, return 0; } -static int bttv_s_register(struct file *file, void *f, +static int bttv_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *reg) { struct bttv *btv = video_drvdata(file); @@ -2159,7 +2159,7 @@ static int bttv_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int bttv_g_parm(struct file *file, void *f, +static int bttv_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct bttv *btv = video_drvdata(file); @@ -2208,7 +2208,7 @@ static int bttv_g_pixelaspect(struct file *file, void *priv, return 0; } -static int bttv_g_selection(struct file *file, void *f, struct v4l2_selection *sel) +static int bttv_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct bttv *btv = video_drvdata(file); @@ -2232,7 +2232,7 @@ static int bttv_g_selection(struct file *file, void *f, struct v4l2_selection *s return 0; } -static int bttv_s_selection(struct file *file, void *f, struct v4l2_selection *sel) +static int bttv_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct bttv *btv = video_drvdata(file); const struct v4l2_rect *b; diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c index a71440611e46..0ca88a2400ee 100644 --- a/drivers/media/pci/bt8xx/bttv-vbi.c +++ b/drivers/media/pci/bt8xx/bttv-vbi.c @@ -241,7 +241,7 @@ static int try_fmt(struct v4l2_vbi_format *f, const struct bttv_tvnorm *tvnorm, return 0; } -int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +int bttv_try_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *frt) { struct bttv *btv = video_drvdata(file); const struct bttv_tvnorm *tvnorm; @@ -258,7 +258,7 @@ int bttv_try_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) } -int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +int bttv_s_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *frt) { struct bttv *btv = video_drvdata(file); const struct bttv_tvnorm *tvnorm; @@ -301,7 +301,7 @@ int bttv_s_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) } -int bttv_g_fmt_vbi_cap(struct file *file, void *f, struct v4l2_format *frt) +int bttv_g_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *frt) { const struct bttv_tvnorm *tvnorm; struct bttv *btv = video_drvdata(file); diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 39e25cc53edb..b7695705fdee 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 <hansverk@cisco.com> & Morten Hestnes"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org> & 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 ae82427e3479..51fd9576c6c2 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -447,7 +447,7 @@ static int cobalt_cobaltc(struct cobalt *cobalt, unsigned int cmd, void *arg) return 0; } -static int cobalt_g_register(struct file *file, void *priv_fh, +static int cobalt_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct cobalt_stream *s = video_drvdata(file); @@ -456,7 +456,7 @@ static int cobalt_g_register(struct file *file, void *priv_fh, return cobalt_cobaltc(cobalt, VIDIOC_DBG_G_REGISTER, reg); } -static int cobalt_s_register(struct file *file, void *priv_fh, +static int cobalt_s_register(struct file *file, void *priv, const struct v4l2_dbg_register *reg) { struct cobalt_stream *s = video_drvdata(file); @@ -467,7 +467,7 @@ static int cobalt_s_register(struct file *file, void *priv_fh, } #endif -static int cobalt_querycap(struct file *file, void *priv_fh, +static int cobalt_querycap(struct file *file, void *priv, struct v4l2_capability *vcap) { struct cobalt_stream *s = video_drvdata(file); @@ -562,7 +562,7 @@ static void cobalt_video_input_status_show(struct cobalt_stream *s) cobalt_info("rx%d: Packer: %x\n", rx, ioread32(&packer->control)); } -static int cobalt_log_status(struct file *file, void *priv_fh) +static int cobalt_log_status(struct file *file, void *priv) { struct cobalt_stream *s = video_drvdata(file); struct cobalt *cobalt = s->cobalt; @@ -596,7 +596,7 @@ static int cobalt_log_status(struct file *file, void *priv_fh) return 0; } -static int cobalt_enum_dv_timings(struct file *file, void *priv_fh, +static int cobalt_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct cobalt_stream *s = video_drvdata(file); @@ -613,7 +613,7 @@ static int cobalt_enum_dv_timings(struct file *file, void *priv_fh, pad, enum_dv_timings, timings); } -static int cobalt_s_dv_timings(struct file *file, void *priv_fh, +static int cobalt_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct cobalt_stream *s = video_drvdata(file); @@ -641,7 +641,7 @@ static int cobalt_s_dv_timings(struct file *file, void *priv_fh, return err; } -static int cobalt_g_dv_timings(struct file *file, void *priv_fh, +static int cobalt_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct cobalt_stream *s = video_drvdata(file); @@ -654,7 +654,7 @@ static int cobalt_g_dv_timings(struct file *file, void *priv_fh, pad, g_dv_timings, 0, timings); } -static int cobalt_query_dv_timings(struct file *file, void *priv_fh, +static int cobalt_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct cobalt_stream *s = video_drvdata(file); @@ -667,7 +667,7 @@ static int cobalt_query_dv_timings(struct file *file, void *priv_fh, pad, query_dv_timings, 0, timings); } -static int cobalt_dv_timings_cap(struct file *file, void *priv_fh, +static int cobalt_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap) { struct cobalt_stream *s = video_drvdata(file); @@ -677,7 +677,7 @@ static int cobalt_dv_timings_cap(struct file *file, void *priv_fh, pad, dv_timings_cap, cap); } -static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh, +static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { switch (f->index) { @@ -697,7 +697,7 @@ static int cobalt_enum_fmt_vid_cap(struct file *file, void *priv_fh, return 0; } -static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh, +static int cobalt_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -726,7 +726,7 @@ static int cobalt_g_fmt_vid_cap(struct file *file, void *priv_fh, return 0; } -static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh, +static int cobalt_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -787,7 +787,7 @@ static int cobalt_try_fmt_vid_cap(struct file *file, void *priv_fh, return 0; } -static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh, +static int cobalt_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -796,7 +796,7 @@ static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh, if (vb2_is_busy(&s->q)) return -EBUSY; - if (cobalt_try_fmt_vid_cap(file, priv_fh, f)) + if (cobalt_try_fmt_vid_cap(file, priv, f)) return -EINVAL; s->width = pix->width; @@ -821,7 +821,7 @@ static int cobalt_s_fmt_vid_cap(struct file *file, void *priv_fh, return 0; } -static int cobalt_try_fmt_vid_out(struct file *file, void *priv_fh, +static int cobalt_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format *pix = &f->fmt.pix; @@ -862,7 +862,7 @@ static int cobalt_try_fmt_vid_out(struct file *file, void *priv_fh, return 0; } -static int cobalt_g_fmt_vid_out(struct file *file, void *priv_fh, +static int cobalt_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -882,7 +882,7 @@ static int cobalt_g_fmt_vid_out(struct file *file, void *priv_fh, return 0; } -static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh, +static int cobalt_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { switch (f->index) { @@ -899,7 +899,7 @@ static int cobalt_enum_fmt_vid_out(struct file *file, void *priv_fh, return 0; } -static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh, +static int cobalt_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct cobalt_stream *s = video_drvdata(file); @@ -909,7 +909,7 @@ static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh, }; u32 code; - if (cobalt_try_fmt_vid_out(file, priv_fh, f)) + if (cobalt_try_fmt_vid_out(file, priv, f)) return -EINVAL; if (vb2_is_busy(&s->q) && (pix->pixelformat != s->pixfmt || @@ -942,7 +942,7 @@ static int cobalt_s_fmt_vid_out(struct file *file, void *priv_fh, return 0; } -static int cobalt_enum_input(struct file *file, void *priv_fh, +static int cobalt_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { struct cobalt_stream *s = video_drvdata(file); @@ -963,7 +963,7 @@ static int cobalt_enum_input(struct file *file, void *priv_fh, video, g_input_status, &inp->status); } -static int cobalt_g_input(struct file *file, void *priv_fh, unsigned int *i) +static int cobalt_g_input(struct file *file, void *priv, unsigned int *i) { struct cobalt_stream *s = video_drvdata(file); @@ -971,7 +971,7 @@ static int cobalt_g_input(struct file *file, void *priv_fh, unsigned int *i) return 0; } -static int cobalt_s_input(struct file *file, void *priv_fh, unsigned int i) +static int cobalt_s_input(struct file *file, void *priv, unsigned int i) { struct cobalt_stream *s = video_drvdata(file); @@ -990,7 +990,7 @@ static int cobalt_s_input(struct file *file, void *priv_fh, unsigned int i) ADV76XX_PAD_HDMI_PORT_A, 0, 0); } -static int cobalt_enum_output(struct file *file, void *priv_fh, +static int cobalt_enum_output(struct file *file, void *priv, struct v4l2_output *out) { if (out->index) @@ -1001,18 +1001,18 @@ static int cobalt_enum_output(struct file *file, void *priv_fh, return 0; } -static int cobalt_g_output(struct file *file, void *priv_fh, unsigned int *i) +static int cobalt_g_output(struct file *file, void *priv, unsigned int *i) { *i = 0; return 0; } -static int cobalt_s_output(struct file *file, void *priv_fh, unsigned int i) +static int cobalt_s_output(struct file *file, void *priv, unsigned int i) { return i ? -EINVAL : 0; } -static int cobalt_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) +static int cobalt_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct cobalt_stream *s = video_drvdata(file); u32 pad = edid->pad; @@ -1026,7 +1026,7 @@ static int cobalt_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) return ret; } -static int cobalt_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) +static int cobalt_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct cobalt_stream *s = video_drvdata(file); u32 pad = edid->pad; @@ -1050,7 +1050,7 @@ static int cobalt_subscribe_event(struct v4l2_fh *fh, return v4l2_ctrl_subscribe_event(fh, sub); } -static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +static int cobalt_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { struct cobalt_stream *s = video_drvdata(file); struct v4l2_fract fps; @@ -1065,7 +1065,7 @@ static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) return 0; } -static int cobalt_g_pixelaspect(struct file *file, void *fh, +static int cobalt_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { struct cobalt_stream *s = video_drvdata(file); @@ -1084,7 +1084,7 @@ static int cobalt_g_pixelaspect(struct file *file, void *fh, return err; } -static int cobalt_g_selection(struct file *file, void *fh, +static int cobalt_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct cobalt_stream *s = video_drvdata(file); diff --git a/drivers/media/pci/cx18/cx18-audio.c b/drivers/media/pci/cx18/cx18-audio.c index 8602d088601b..1464795619f9 100644 --- a/drivers/media/pci/cx18/cx18-audio.c +++ b/drivers/media/pci/cx18/cx18-audio.c @@ -4,7 +4,7 @@ * * Derived from ivtv-audio.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ #include "cx18-driver.h" diff --git a/drivers/media/pci/cx18/cx18-audio.h b/drivers/media/pci/cx18/cx18-audio.h index 36ce333ab07a..29cf89d38d60 100644 --- a/drivers/media/pci/cx18/cx18-audio.h +++ b/drivers/media/pci/cx18/cx18-audio.h @@ -4,7 +4,7 @@ * * Derived from ivtv-audio.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ int cx18_audio_set_io(struct cx18 *cx); diff --git a/drivers/media/pci/cx18/cx18-av-audio.c b/drivers/media/pci/cx18/cx18-av-audio.c index 78e05df9a7ba..644d8ca4519b 100644 --- a/drivers/media/pci/cx18/cx18-av-audio.c +++ b/drivers/media/pci/cx18/cx18-av-audio.c @@ -4,7 +4,7 @@ * * Derived from cx25840-audio.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index ee6e71157786..4fb19d26ee29 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -4,7 +4,7 @@ * * Derived from cx25840-core.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-av-core.h b/drivers/media/pci/cx18/cx18-av-core.h index 55aceb064b33..71ac9d7af28f 100644 --- a/drivers/media/pci/cx18/cx18-av-core.h +++ b/drivers/media/pci/cx18/cx18-av-core.h @@ -4,7 +4,7 @@ * * Derived from cx25840-core.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-av-firmware.c b/drivers/media/pci/cx18/cx18-av-firmware.c index 61aeb8c9af7f..02dde685a6ad 100644 --- a/drivers/media/pci/cx18/cx18-av-firmware.c +++ b/drivers/media/pci/cx18/cx18-av-firmware.c @@ -2,7 +2,7 @@ /* * cx18 ADEC firmware functions * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-av-vbi.c b/drivers/media/pci/cx18/cx18-av-vbi.c index 1a113aad9cd4..f9beeaeaa1cb 100644 --- a/drivers/media/pci/cx18/cx18-av-vbi.c +++ b/drivers/media/pci/cx18/cx18-av-vbi.c @@ -4,7 +4,7 @@ * * Derived from cx25840-vbi.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/cx18/cx18-cards.c b/drivers/media/pci/cx18/cx18-cards.c index f5a30959a367..bddb9e0fffe0 100644 --- a/drivers/media/pci/cx18/cx18-cards.c +++ b/drivers/media/pci/cx18/cx18-cards.c @@ -4,7 +4,7 @@ * * Derived from ivtv-cards.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-cards.h b/drivers/media/pci/cx18/cx18-cards.h index ae9cf5bfdd59..511123b741d5 100644 --- a/drivers/media/pci/cx18/cx18-cards.h +++ b/drivers/media/pci/cx18/cx18-cards.h @@ -4,7 +4,7 @@ * * Derived from ivtv-cards.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c index bb5fc120473c..78eadad8b6e8 100644 --- a/drivers/media/pci/cx18/cx18-controls.c +++ b/drivers/media/pci/cx18/cx18-controls.c @@ -4,7 +4,7 @@ * * Derived from ivtv-controls.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/kernel.h> #include <linux/slab.h> diff --git a/drivers/media/pci/cx18/cx18-controls.h b/drivers/media/pci/cx18/cx18-controls.h index 458a3595a2ae..99de78878a76 100644 --- a/drivers/media/pci/cx18/cx18-controls.h +++ b/drivers/media/pci/cx18/cx18-controls.h @@ -4,7 +4,7 @@ * * Derived from ivtv-controls.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 743fcc961374..74c59a94b2b0 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -4,7 +4,7 @@ * * Derived from ivtv-driver.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ @@ -1136,11 +1136,8 @@ int cx18_init_on_first_open(struct cx18 *cx) int video_input; int fw_retry_count = 3; struct v4l2_frequency vf; - struct cx18_open_id fh; v4l2_std_id std; - fh.cx = cx; - if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) return -ENXIO; @@ -1220,14 +1217,14 @@ int cx18_init_on_first_open(struct cx18 *cx) video_input = cx->active_input; cx->active_input++; /* Force update of input */ - cx18_s_input(NULL, &fh, video_input); + cx18_do_s_input(cx, video_input); /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code in one place. */ cx->std++; /* Force full standard initialization */ std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std; - cx18_s_std(NULL, &fh, std); - cx18_s_frequency(NULL, &fh, &vf); + cx18_do_s_std(cx, std); + cx18_do_s_frequency(cx, &vf); return 0; } diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h index 485ca9747c4c..ef38903709d0 100644 --- a/drivers/media/pci/cx18/cx18-driver.h +++ b/drivers/media/pci/cx18/cx18-driver.h @@ -4,7 +4,7 @@ * * Derived from ivtv-driver.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ @@ -414,7 +414,7 @@ static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) static inline struct cx18_open_id *file2id(struct file *file) { - return fh2id(file->private_data); + return fh2id(file_to_v4l2_fh(file)); } /* forward declaration of struct defined in cx18-cards.h */ diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index cefa91b37f89..4944033dbb20 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -4,7 +4,7 @@ * * Derived from ivtv-fileops.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ @@ -678,7 +678,7 @@ void cx18_stop_capture(struct cx18_stream *s, int gop_end) int cx18_v4l2_close(struct file *filp) { - struct v4l2_fh *fh = filp->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(filp); struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[id->type]; @@ -709,11 +709,11 @@ int cx18_v4l2_close(struct file *filp) } if (id->type == CX18_ENC_STREAM_TYPE_YUV && - filp->private_data == vdev->queue->owner) { + file_to_v4l2_fh(filp) == vdev->queue->owner) { vb2_queue_release(vdev->queue); vdev->queue->owner = NULL; } - v4l2_fh_del(fh); + v4l2_fh_del(fh, filp); v4l2_fh_exit(fh); /* 'Unclaim' this stream */ @@ -743,8 +743,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) item->type = s->type; item->open_id = cx->open_id++; - filp->private_data = &item->fh; - v4l2_fh_add(&item->fh); + v4l2_fh_add(&item->fh, filp); if (item->type == CX18_ENC_STREAM_TYPE_RAD && v4l2_fh_is_singular_file(filp)) { @@ -752,7 +751,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) if (atomic_read(&cx->ana_capturing) > 0) { /* switching to radio while capture is in progress is not polite */ - v4l2_fh_del(&item->fh); + v4l2_fh_del(&item->fh, filp); v4l2_fh_exit(&item->fh); kfree(item); return -EBUSY; diff --git a/drivers/media/pci/cx18/cx18-fileops.h b/drivers/media/pci/cx18/cx18-fileops.h index 943057b83d94..bc999ea85dc2 100644 --- a/drivers/media/pci/cx18/cx18-fileops.h +++ b/drivers/media/pci/cx18/cx18-fileops.h @@ -4,7 +4,7 @@ * * Derived from ivtv-fileops.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ /* Testing/Debugging */ diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c index 1b038b2802bf..94e17948fb30 100644 --- a/drivers/media/pci/cx18/cx18-firmware.c +++ b/drivers/media/pci/cx18/cx18-firmware.c @@ -2,7 +2,7 @@ /* * cx18 firmware functions * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-firmware.h b/drivers/media/pci/cx18/cx18-firmware.h index 1357f76d613e..8e63677284bd 100644 --- a/drivers/media/pci/cx18/cx18-firmware.h +++ b/drivers/media/pci/cx18/cx18-firmware.h @@ -2,7 +2,7 @@ /* * cx18 firmware functions * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ int cx18_firmware_init(struct cx18 *cx); diff --git a/drivers/media/pci/cx18/cx18-gpio.c b/drivers/media/pci/cx18/cx18-gpio.c index 485a6cbeb15a..4aea92639599 100644 --- a/drivers/media/pci/cx18/cx18-gpio.c +++ b/drivers/media/pci/cx18/cx18-gpio.c @@ -4,7 +4,7 @@ * * Derived from ivtv-gpio.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-gpio.h b/drivers/media/pci/cx18/cx18-gpio.h index 8d5797dea7f5..3eefc4644101 100644 --- a/drivers/media/pci/cx18/cx18-gpio.h +++ b/drivers/media/pci/cx18/cx18-gpio.h @@ -4,7 +4,7 @@ * * Derived from ivtv-gpio.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-i2c.c b/drivers/media/pci/cx18/cx18-i2c.c index a83435245251..a1abb0631cae 100644 --- a/drivers/media/pci/cx18/cx18-i2c.c +++ b/drivers/media/pci/cx18/cx18-i2c.c @@ -4,7 +4,7 @@ * * Derived from ivtv-i2c.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-i2c.h b/drivers/media/pci/cx18/cx18-i2c.h index 4526cb324fec..8ae3125c78c0 100644 --- a/drivers/media/pci/cx18/cx18-i2c.h +++ b/drivers/media/pci/cx18/cx18-i2c.h @@ -4,7 +4,7 @@ * * Derived from ivtv-i2c.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ int cx18_i2c_register(struct cx18 *cx, unsigned idx); diff --git a/drivers/media/pci/cx18/cx18-io.c b/drivers/media/pci/cx18/cx18-io.c index 50e4e8a598d4..1d3d006e6329 100644 --- a/drivers/media/pci/cx18/cx18-io.c +++ b/drivers/media/pci/cx18/cx18-io.c @@ -2,7 +2,7 @@ /* * cx18 driver PCI memory mapped IO access routines * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-io.h b/drivers/media/pci/cx18/cx18-io.h index 190b142d047e..1f0bfad7d0f0 100644 --- a/drivers/media/pci/cx18/cx18-io.h +++ b/drivers/media/pci/cx18/cx18-io.h @@ -2,7 +2,7 @@ /* * cx18 driver PCI memory mapped IO access routines * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 9a1512b1ccaa..0d676a57e24e 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -4,7 +4,7 @@ * * Derived from ivtv-ioctl.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ @@ -52,7 +52,7 @@ static const struct v4l2_fmtdesc cx18_formats_mpeg[] = { static int cx18_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[id->type]; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; @@ -76,7 +76,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, static int cx18_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; int w = pixfmt->width; @@ -121,7 +121,7 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh, static int cx18_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, @@ -261,7 +261,7 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; vbifmt->sampling_rate = 27000000; @@ -280,7 +280,7 @@ static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; /* sane, V4L2 spec compliant, defaults */ @@ -311,7 +311,7 @@ static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; @@ -330,7 +330,7 @@ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; int ret; @@ -360,7 +360,7 @@ static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; int ret; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; @@ -392,7 +392,7 @@ static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, static int cx18_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (reg->reg & 0x3) return -EINVAL; @@ -406,7 +406,7 @@ static int cx18_g_register(struct file *file, void *fh, static int cx18_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (reg->reg & 0x3) return -EINVAL; @@ -420,7 +420,7 @@ static int cx18_s_register(struct file *file, void *fh, static int cx18_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); @@ -431,14 +431,14 @@ static int cx18_querycap(struct file *file, void *fh, static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; return cx18_get_audio_input(cx, vin->index, vin); } static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; vin->index = cx->audio_input; return cx18_get_audio_input(cx, vin->index, vin); @@ -446,7 +446,7 @@ static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) static int cx18_s_audio(struct file *file, void *fh, const struct v4l2_audio *vout) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (vout->index >= cx->nof_audio_inputs) return -EINVAL; @@ -457,7 +457,7 @@ static int cx18_s_audio(struct file *file, void *fh, const struct v4l2_audio *vo static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; /* set it to defaults from our table */ return cx18_get_input(cx, vin->index, vin); @@ -466,7 +466,7 @@ static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) static int cx18_g_pixelaspect(struct file *file, void *fh, int type, struct v4l2_fract *f) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -479,7 +479,7 @@ static int cx18_g_pixelaspect(struct file *file, void *fh, static int cx18_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -499,7 +499,7 @@ static int cx18_g_selection(struct file *file, void *fh, static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); if (id->type == CX18_ENC_STREAM_TYPE_YUV) { if (fmt->index >= ARRAY_SIZE(cx18_formats_yuv)) @@ -515,16 +515,14 @@ static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, static int cx18_g_input(struct file *file, void *fh, unsigned int *i) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; *i = cx->active_input; return 0; } -int cx18_s_input(struct file *file, void *fh, unsigned int inp) +int cx18_do_s_input(struct cx18 *cx, unsigned int inp) { - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; v4l2_std_id std = V4L2_STD_ALL; const struct cx18_card_video_input *card_input = cx->card->video_inputs + inp; @@ -558,10 +556,15 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp) return 0; } +static int cx18_s_input(struct file *file, void *fh, unsigned int inp) +{ + return cx18_do_s_input(file2id(file)->cx, inp); +} + static int cx18_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (vf->tuner != 0) return -EINVAL; @@ -570,11 +573,8 @@ static int cx18_g_frequency(struct file *file, void *fh, return 0; } -int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +int cx18_do_s_frequency(struct cx18 *cx, const struct v4l2_frequency *vf) { - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - if (vf->tuner != 0) return -EINVAL; @@ -585,19 +585,22 @@ int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *v return 0; } +static int cx18_s_frequency(struct file *file, void *fh, + const struct v4l2_frequency *vf) +{ + return cx18_do_s_frequency(file2id(file)->cx, vf); +} + static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; *std = cx->std; return 0; } -int cx18_s_std(struct file *file, void *fh, v4l2_std_id std) +int cx18_do_s_std(struct cx18 *cx, v4l2_std_id std) { - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - if ((std & V4L2_STD_ALL) == 0) return -EINVAL; @@ -642,9 +645,14 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id std) return 0; } +static int cx18_s_std(struct file *file, void *fh, v4l2_std_id std) +{ + return cx18_do_s_std(file2id(file)->cx, std); +} + static int cx18_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; if (vt->index != 0) @@ -656,7 +664,7 @@ static int cx18_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; if (vt->index != 0) return -EINVAL; @@ -673,7 +681,7 @@ static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; int f, l; @@ -794,7 +802,7 @@ static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl, static int cx18_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; s32 tmp; struct cx18_mdl *mdl; @@ -841,7 +849,7 @@ static int cx18_g_enc_index(struct file *file, void *fh, static int cx18_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct cx18_open_id *id = fh2id(fh); + struct cx18_open_id *id = file2id(file); struct cx18 *cx = id->cx; u32 h; @@ -900,7 +908,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh, static int cx18_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; switch (enc->cmd) { case V4L2_ENC_CMD_START: @@ -932,7 +940,7 @@ static int cx18_try_encoder_cmd(struct file *file, void *fh, static int cx18_log_status(struct file *file, void *fh) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; struct v4l2_input vidin; struct v4l2_audio audin; int i; @@ -976,7 +984,7 @@ static int cx18_log_status(struct file *file, void *fh) static long cx18_default(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg) { - struct cx18 *cx = fh2id(fh)->cx; + struct cx18 *cx = file2id(file)->cx; switch (cmd) { case VIDIOC_INT_RESET: { diff --git a/drivers/media/pci/cx18/cx18-ioctl.h b/drivers/media/pci/cx18/cx18-ioctl.h index 221e2400fb3e..42a8acd69735 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.h +++ b/drivers/media/pci/cx18/cx18-ioctl.h @@ -4,7 +4,7 @@ * * Derived from ivtv-ioctl.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ @@ -12,6 +12,8 @@ u16 cx18_service2vbi(int type); void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); void cx18_set_funcs(struct video_device *vdev); -int cx18_s_std(struct file *file, void *fh, v4l2_std_id std); -int cx18_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); -int cx18_s_input(struct file *file, void *fh, unsigned int inp); + +struct cx18; +int cx18_do_s_std(struct cx18 *cx, v4l2_std_id std); +int cx18_do_s_frequency(struct cx18 *cx, const struct v4l2_frequency *vf); +int cx18_do_s_input(struct cx18 *cx, unsigned int inp); diff --git a/drivers/media/pci/cx18/cx18-irq.c b/drivers/media/pci/cx18/cx18-irq.c index db63077821b1..0ef01e98255d 100644 --- a/drivers/media/pci/cx18/cx18-irq.c +++ b/drivers/media/pci/cx18/cx18-irq.c @@ -2,7 +2,7 @@ /* * cx18 interrupt handling * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-irq.h b/drivers/media/pci/cx18/cx18-irq.h index fdb585a72827..c1456d69dffa 100644 --- a/drivers/media/pci/cx18/cx18-irq.h +++ b/drivers/media/pci/cx18/cx18-irq.h @@ -2,7 +2,7 @@ /* * cx18 interrupt handling * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c index a6457c23d18c..8c70b638a40c 100644 --- a/drivers/media/pci/cx18/cx18-mailbox.c +++ b/drivers/media/pci/cx18/cx18-mailbox.c @@ -2,7 +2,7 @@ /* * cx18 mailbox functions * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-mailbox.h b/drivers/media/pci/cx18/cx18-mailbox.h index 971382ac0eca..1752b8e1ca13 100644 --- a/drivers/media/pci/cx18/cx18-mailbox.h +++ b/drivers/media/pci/cx18/cx18-mailbox.h @@ -2,7 +2,7 @@ /* * cx18 mailbox functions * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c index 013694bfcb1c..eeb5513b1d52 100644 --- a/drivers/media/pci/cx18/cx18-queue.c +++ b/drivers/media/pci/cx18/cx18-queue.c @@ -4,7 +4,7 @@ * * Derived from ivtv-queue.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ @@ -379,15 +379,22 @@ int cx18_stream_alloc(struct cx18_stream *s) break; } + buf->dma_handle = dma_map_single(&s->cx->pci_dev->dev, + buf->buf, s->buf_size, + s->dma); + if (dma_mapping_error(&s->cx->pci_dev->dev, buf->dma_handle)) { + kfree(buf->buf); + kfree(mdl); + kfree(buf); + break; + } + INIT_LIST_HEAD(&mdl->list); INIT_LIST_HEAD(&mdl->buf_list); mdl->id = s->mdl_base_idx; /* a somewhat safe value */ cx18_enqueue(s, mdl, &s->q_idle); INIT_LIST_HEAD(&buf->list); - buf->dma_handle = dma_map_single(&s->cx->pci_dev->dev, - buf->buf, s->buf_size, - s->dma); cx18_buf_sync_for_cpu(s, buf); list_add_tail(&buf->list, &s->buf_pool); } diff --git a/drivers/media/pci/cx18/cx18-queue.h b/drivers/media/pci/cx18/cx18-queue.h index 26f2097c0496..972f234ffead 100644 --- a/drivers/media/pci/cx18/cx18-queue.h +++ b/drivers/media/pci/cx18/cx18-queue.h @@ -4,7 +4,7 @@ * * Derived from ivtv-queue.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-scb.c b/drivers/media/pci/cx18/cx18-scb.c index 4a0edc1e42e7..670dd9b0a332 100644 --- a/drivers/media/pci/cx18/cx18-scb.c +++ b/drivers/media/pci/cx18/cx18-scb.c @@ -2,7 +2,7 @@ /* * cx18 System Control Block initialization * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-scb.h b/drivers/media/pci/cx18/cx18-scb.h index 841edc0712ab..900f7291979f 100644 --- a/drivers/media/pci/cx18/cx18-scb.h +++ b/drivers/media/pci/cx18/cx18-scb.h @@ -2,7 +2,7 @@ /* * cx18 System Control Block initialization * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 42d6f7b90ede..48203ba16387 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -4,7 +4,7 @@ * * Derived from ivtv-streams.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-streams.h b/drivers/media/pci/cx18/cx18-streams.h index bba4349c5c2e..e01bed6b4827 100644 --- a/drivers/media/pci/cx18/cx18-streams.h +++ b/drivers/media/pci/cx18/cx18-streams.h @@ -4,7 +4,7 @@ * * Derived from ivtv-streams.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> */ diff --git a/drivers/media/pci/cx18/cx18-vbi.c b/drivers/media/pci/cx18/cx18-vbi.c index c7cce38dd754..8dc4ce325935 100644 --- a/drivers/media/pci/cx18/cx18-vbi.c +++ b/drivers/media/pci/cx18/cx18-vbi.c @@ -4,7 +4,7 @@ * * Derived from ivtv-vbi.c * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ #include "cx18-driver.h" diff --git a/drivers/media/pci/cx18/cx18-vbi.h b/drivers/media/pci/cx18/cx18-vbi.h index a5f81c6159f0..41f5026696c4 100644 --- a/drivers/media/pci/cx18/cx18-vbi.h +++ b/drivers/media/pci/cx18/cx18-vbi.h @@ -4,7 +4,7 @@ * * Derived from ivtv-vbi.h * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, diff --git a/drivers/media/pci/cx18/cx18-version.h b/drivers/media/pci/cx18/cx18-version.h index e7396182fc5a..e8636ac5d5a5 100644 --- a/drivers/media/pci/cx18/cx18-version.h +++ b/drivers/media/pci/cx18/cx18-version.h @@ -2,7 +2,7 @@ /* * cx18 driver version information * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ #ifndef CX18_VERSION_H diff --git a/drivers/media/pci/cx18/cx18-video.c b/drivers/media/pci/cx18/cx18-video.c index 2fde8c2d3fdc..86cd44053d34 100644 --- a/drivers/media/pci/cx18/cx18-video.c +++ b/drivers/media/pci/cx18/cx18-video.c @@ -2,7 +2,7 @@ /* * cx18 video interface functions * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ #include "cx18-driver.h" diff --git a/drivers/media/pci/cx18/cx18-video.h b/drivers/media/pci/cx18/cx18-video.h index f613975ca5f0..ef212f1c5b17 100644 --- a/drivers/media/pci/cx18/cx18-video.h +++ b/drivers/media/pci/cx18/cx18-video.h @@ -2,7 +2,7 @@ /* * cx18 video interface functions * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ void cx18_video_set_io(struct cx18 *cx); diff --git a/drivers/media/pci/cx18/cx23418.h b/drivers/media/pci/cx18/cx23418.h index 8859c0e8557f..22486f39bcda 100644 --- a/drivers/media/pci/cx18/cx23418.h +++ b/drivers/media/pci/cx18/cx23418.h @@ -2,7 +2,7 @@ /* * cx18 header containing common defines. * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> */ #ifndef CX23418_H diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c index 4e579352ab2c..c9827e9fe6ff 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -79,6 +79,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { IPU_SENSOR_CONFIG("OVTI02C1", 1, 400000000), /* Omnivision OV02E10 */ IPU_SENSOR_CONFIG("OVTI02E1", 1, 360000000), + /* Omnivision ov05c10 */ + IPU_SENSOR_CONFIG("OVTI05C1", 1, 480000000), /* Omnivision OV08A10 */ IPU_SENSOR_CONFIG("OVTI08A1", 1, 500000000), /* Omnivision OV08x40 */ @@ -90,6 +92,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), /* Omnivision OV8856 */ IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), + /* Sony IMX471 */ + IPU_SENSOR_CONFIG("SONY471A", 1, 200000000), /* Toshiba T4KA3 */ IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000), }; @@ -563,8 +567,8 @@ static void ipu_bridge_instantiate_vcm_work(struct work_struct *work) vcm_client = i2c_acpi_new_device_by_fwnode(acpi_fwnode_handle(adev), 1, &data->board_info); if (IS_ERR(vcm_client)) { - dev_err(data->sensor, "Error instantiating VCM client: %ld\n", - PTR_ERR(vcm_client)); + dev_err(data->sensor, "Error instantiating VCM client: %pe\n", + vcm_client); goto out_pm_put; } diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index a87f105beb5e..986b9afd7cb5 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -314,8 +314,8 @@ static int cio2_csi2_calc_timing(struct cio2_device *cio2, struct cio2_queue *q, src_pad = media_entity_remote_source_pad_unique(&q->subdev.entity); if (IS_ERR(src_pad)) { - dev_err(dev, "can't get source pad of %s (%ld)\n", - q->subdev.name, PTR_ERR(src_pad)); + dev_err(dev, "can't get source pad of %s (%pe)\n", + q->subdev.name, src_pad); return PTR_ERR(src_pad); } diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c index 6030bd23b4b9..43a2a16a3c2a 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c @@ -42,6 +42,10 @@ static const u32 csi2_supported_codes[] = { MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_Y8_1X8, + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y12_1X12, + MEDIA_BUS_FMT_Y16_1X16, MEDIA_BUS_FMT_META_8, MEDIA_BUS_FMT_META_10, MEDIA_BUS_FMT_META_12, @@ -87,8 +91,8 @@ s64 ipu6_isys_csi2_get_link_freq(struct ipu6_isys_csi2 *csi2) src_pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity); if (IS_ERR(src_pad)) { dev_err(&csi2->isys->adev->auxdev.dev, - "can't get source pad of %s (%ld)\n", - csi2->asd.sd.name, PTR_ERR(src_pad)); + "can't get source pad of %s (%pe)\n", + csi2->asd.sd.name, src_pad); return PTR_ERR(src_pad); } @@ -109,7 +113,7 @@ static int csi2_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, case V4L2_EVENT_FRAME_SYNC: return v4l2_event_subscribe(fh, sub, 10, NULL); case V4L2_EVENT_CTRL: - return v4l2_ctrl_subscribe_event(fh, sub); + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); default: return -EINVAL; } diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c b/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c index 0a06de5c739c..869e7d4ba572 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c @@ -25,24 +25,28 @@ unsigned int ipu6_isys_mbus_code_to_bpp(u32 code) case MEDIA_BUS_FMT_RGB565_1X16: case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_Y16_1X16: case MEDIA_BUS_FMT_META_16: return 16; case MEDIA_BUS_FMT_SBGGR12_1X12: case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_Y12_1X12: case MEDIA_BUS_FMT_META_12: return 12; case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_Y10_1X10: case MEDIA_BUS_FMT_META_10: return 10; case MEDIA_BUS_FMT_SBGGR8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_Y8_1X8: case MEDIA_BUS_FMT_META_8: return 8; default: @@ -65,22 +69,32 @@ unsigned int ipu6_isys_mbus_code_to_mipi(u32 code) case MEDIA_BUS_FMT_SGBRG16_1X16: case MEDIA_BUS_FMT_SGRBG16_1X16: case MEDIA_BUS_FMT_SRGGB16_1X16: + case MEDIA_BUS_FMT_Y16_1X16: return MIPI_CSI2_DT_RAW16; case MEDIA_BUS_FMT_SBGGR12_1X12: case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_Y12_1X12: return MIPI_CSI2_DT_RAW12; case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_Y10_1X10: return MIPI_CSI2_DT_RAW10; case MEDIA_BUS_FMT_SBGGR8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_Y8_1X8: return MIPI_CSI2_DT_RAW8; + case MEDIA_BUS_FMT_META_8: + case MEDIA_BUS_FMT_META_10: + case MEDIA_BUS_FMT_META_12: + case MEDIA_BUS_FMT_META_16: + case MEDIA_BUS_FMT_META_24: + return MIPI_CSI2_DT_EMBEDDED_8B; default: /* return unavailable MIPI data type - 0x3f */ WARN_ON(1); @@ -90,15 +104,23 @@ unsigned int ipu6_isys_mbus_code_to_mipi(u32 code) bool ipu6_isys_is_bayer_format(u32 code) { - switch (ipu6_isys_mbus_code_to_mipi(code)) { - case MIPI_CSI2_DT_RAW8: - case MIPI_CSI2_DT_RAW10: - case MIPI_CSI2_DT_RAW12: - case MIPI_CSI2_DT_RAW14: - case MIPI_CSI2_DT_RAW16: - case MIPI_CSI2_DT_RAW20: - case MIPI_CSI2_DT_RAW24: - case MIPI_CSI2_DT_RAW28: + switch (code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_SRGGB16_1X16: + case MEDIA_BUS_FMT_SGRBG16_1X16: + case MEDIA_BUS_FMT_SGBRG16_1X16: + case MEDIA_BUS_FMT_SBGGR16_1X16: return true; default: return false; diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c index 24a2ef93474c..dec8f5ffcfa5 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c @@ -77,6 +77,20 @@ const struct ipu6_isys_pixelformat ipu6_isys_pfmts[] = { IPU6_FW_ISYS_FRAME_FORMAT_RAW10 }, { V4L2_PIX_FMT_SRGGB10P, 10, 10, MEDIA_BUS_FMT_SRGGB10_1X10, IPU6_FW_ISYS_FRAME_FORMAT_RAW10 }, + + { V4L2_PIX_FMT_GREY, 8, 8, MEDIA_BUS_FMT_Y8_1X8, + IPU6_FW_ISYS_FRAME_FORMAT_RAW8 }, + { V4L2_PIX_FMT_Y10, 16, 10, MEDIA_BUS_FMT_Y10_1X10, + IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, + { V4L2_PIX_FMT_Y12, 16, 12, MEDIA_BUS_FMT_Y12_1X12, + IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, + { V4L2_PIX_FMT_Y16, 16, 16, MEDIA_BUS_FMT_Y16_1X16, + IPU6_FW_ISYS_FRAME_FORMAT_RAW16 }, + { V4L2_PIX_FMT_Y10P, 10, 10, MEDIA_BUS_FMT_Y10_1X10, + IPU6_FW_ISYS_FRAME_FORMAT_RAW10 }, + { V4L2_PIX_FMT_Y12P, 12, 12, MEDIA_BUS_FMT_Y12_1X12, + IPU6_FW_ISYS_FRAME_FORMAT_RAW12 }, + { V4L2_PIX_FMT_UYVY, 16, 16, MEDIA_BUS_FMT_UYVY8_1X16, IPU6_FW_ISYS_FRAME_FORMAT_UYVY}, { V4L2_PIX_FMT_YUYV, 16, 16, MEDIA_BUS_FMT_YUYV8_1X16, @@ -1306,7 +1320,6 @@ int ipu6_isys_video_init(struct ipu6_isys_video *av) __ipu6_isys_vidioc_try_fmt_meta_cap(av, &format_meta); av->meta_fmt = format_meta.fmt.meta; - set_bit(V4L2_FL_USES_V4L2_FH, &av->vdev.flags); video_set_drvdata(&av->vdev, av); ret = video_register_device(&av->vdev, VFL_TYPE_VIDEO, -1); diff --git a/drivers/media/pci/intel/ivsc/mei_ace.c b/drivers/media/pci/intel/ivsc/mei_ace.c index 98310b8511b1..b306a320b70f 100644 --- a/drivers/media/pci/intel/ivsc/mei_ace.c +++ b/drivers/media/pci/intel/ivsc/mei_ace.c @@ -414,10 +414,11 @@ static int mei_ace_setup_dev_link(struct mei_ace *ace) /* setup link between mei_ace and mei_csi */ ace->csi_link = device_link_add(csi_dev, dev, DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE | DL_FLAG_STATELESS); + put_device(csi_dev); if (!ace->csi_link) { ret = -EINVAL; dev_err(dev, "failed to link to %s\n", dev_name(csi_dev)); - goto err_put; + goto err; } ace->csi_dev = csi_dev; @@ -522,7 +523,6 @@ static void mei_ace_remove(struct mei_cl_device *cldev) cancel_work_sync(&ace->work); device_link_del(ace->csi_link); - put_device(ace->csi_dev); pm_runtime_disable(&cldev->dev); pm_runtime_set_suspended(&cldev->dev); diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c index 8f346d7da9c8..269a799ec046 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c @@ -148,14 +148,12 @@ static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream) s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; - v4l2_fh_init(&item.fh, &s->vdev); item.itv = itv; item.type = s->type; /* See if the stream is available */ if (ivtv_claim_stream(&item, item.type)) { /* No, it's already in use */ - v4l2_fh_exit(&item.fh); snd_ivtv_unlock(itvsc); return -EBUSY; } diff --git a/drivers/media/pci/ivtv/ivtv-cards.c b/drivers/media/pci/ivtv/ivtv-cards.c index c8f4ed7ff2c6..f2ccf8e98664 100644 --- a/drivers/media/pci/ivtv/ivtv-cards.c +++ b/drivers/media/pci/ivtv/ivtv-cards.c @@ -2,7 +2,7 @@ /* Functions to query card hardware Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-cards.h b/drivers/media/pci/ivtv/ivtv-cards.h index c252733df340..af64e55d3b80 100644 --- a/drivers/media/pci/ivtv/ivtv-cards.h +++ b/drivers/media/pci/ivtv/ivtv-cards.h @@ -2,7 +2,7 @@ /* Functions to query card hardware Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c index a0b9a5a5c7f1..f087a12c4ebd 100644 --- a/drivers/media/pci/ivtv/ivtv-controls.c +++ b/drivers/media/pci/ivtv/ivtv-controls.c @@ -2,7 +2,7 @@ /* ioctl control functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-controls.h b/drivers/media/pci/ivtv/ivtv-controls.h index 444c86a47e5a..d152691ea255 100644 --- a/drivers/media/pci/ivtv/ivtv-controls.h +++ b/drivers/media/pci/ivtv/ivtv-controls.h @@ -2,7 +2,7 @@ /* ioctl control functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index ecc20cd89926..459eb6cc370c 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* ivtv driver initialization and card probing Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ /* Main Driver file for the ivtv project: @@ -1260,15 +1247,12 @@ err: int ivtv_init_on_first_open(struct ivtv *itv) { - struct v4l2_frequency vf; /* Needed to call ioctls later */ - struct ivtv_open_id fh; + struct ivtv_stream *s = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; + struct v4l2_frequency vf; int fw_retry_count = 3; int video_input; - fh.itv = itv; - fh.type = IVTV_ENC_STREAM_TYPE_MPG; - if (test_bit(IVTV_F_I_FAILED, &itv->i_flags)) return -ENXIO; @@ -1310,13 +1294,13 @@ int ivtv_init_on_first_open(struct ivtv *itv) video_input = itv->active_input; itv->active_input++; /* Force update of input */ - ivtv_s_input(NULL, &fh, video_input); + ivtv_do_s_input(itv, video_input); /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code in one place. */ itv->std++; /* Force full standard initialization */ itv->std_out = itv->std; - ivtv_s_frequency(NULL, &fh, &vf); + ivtv_do_s_frequency(s, &vf); if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) { /* Turn on the TV-out: ivtv_init_mpeg_decoder() initializes diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index a6ffa99e16bc..f1f18911332e 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -1,22 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* ivtv driver internal defines and structures Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ #ifndef IVTV_DRIVER_H @@ -322,6 +309,7 @@ struct ivtv_queue { }; struct ivtv; /* forward reference */ +struct ivtv_open_id; struct ivtv_stream { /* These first four fields are always set, even if the stream @@ -331,7 +319,7 @@ struct ivtv_stream { const char *name; /* name of the stream */ int type; /* stream type */ - struct v4l2_fh *fh; /* pointer to the streaming filehandle */ + struct ivtv_open_id *id; /* pointer to the streaming ivtv_open_id */ spinlock_t qlock; /* locks access to the queues */ unsigned long s_flags; /* status flags, see above */ int dma; /* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */ @@ -383,9 +371,9 @@ struct ivtv_open_id { struct ivtv *itv; }; -static inline struct ivtv_open_id *fh2id(struct v4l2_fh *fh) +static inline struct ivtv_open_id *file2id(struct file *filp) { - return container_of(fh, struct ivtv_open_id, fh); + return container_of(file_to_v4l2_fh(filp), struct ivtv_open_id, fh); } struct yuv_frame_info diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index cfa28d035586..ef9ec062c03a 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -3,7 +3,7 @@ file operation functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ @@ -39,16 +39,16 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type) if (test_and_set_bit(IVTV_F_S_CLAIMED, &s->s_flags)) { /* someone already claimed this stream */ - if (s->fh == &id->fh) { + if (s->id == id) { /* yes, this file descriptor did. So that's OK. */ return 0; } - if (s->fh == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI || + if (s->id == NULL && (type == IVTV_DEC_STREAM_TYPE_VBI || type == IVTV_ENC_STREAM_TYPE_VBI)) { /* VBI is handled already internally, now also assign the file descriptor to this stream for external reading of the stream. */ - s->fh = &id->fh; + s->id = id; IVTV_DEBUG_INFO("Start Read VBI\n"); return 0; } @@ -56,7 +56,7 @@ int ivtv_claim_stream(struct ivtv_open_id *id, int type) IVTV_DEBUG_INFO("Stream %d is busy\n", type); return -EBUSY; } - s->fh = &id->fh; + s->id = id; if (type == IVTV_DEC_STREAM_TYPE_VBI) { /* Enable reinsertion interrupt */ ivtv_clear_irq_mask(itv, IVTV_IRQ_DEC_VBI_RE_INSERT); @@ -94,7 +94,7 @@ void ivtv_release_stream(struct ivtv_stream *s) struct ivtv *itv = s->itv; struct ivtv_stream *s_vbi; - s->fh = NULL; + s->id = NULL; if ((s->type == IVTV_DEC_STREAM_TYPE_VBI || s->type == IVTV_ENC_STREAM_TYPE_VBI) && test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { /* this stream is still in use internally */ @@ -126,7 +126,7 @@ void ivtv_release_stream(struct ivtv_stream *s) /* was already cleared */ return; } - if (s_vbi->fh) { + if (s_vbi->id) { /* VBI stream still claimed by a file descriptor */ return; } @@ -359,7 +359,7 @@ static ssize_t ivtv_read(struct ivtv_stream *s, char __user *ubuf, size_t tot_co size_t tot_written = 0; int single_frame = 0; - if (atomic_read(&itv->capturing) == 0 && s->fh == NULL) { + if (atomic_read(&itv->capturing) == 0 && s->id == NULL) { /* shouldn't happen */ IVTV_DEBUG_WARN("Stream %s not initialized before read\n", s->name); return -EIO; @@ -502,7 +502,7 @@ int ivtv_start_capture(struct ivtv_open_id *id) ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_t * pos) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; ssize_t rc; @@ -564,7 +564,7 @@ static int ivtv_schedule_dma(struct ivtv_stream *s) static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; struct yuv_playback_info *yi = &itv->yuv_info; @@ -719,7 +719,7 @@ retry: ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; ssize_t res; @@ -732,7 +732,7 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c __poll_t ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; __poll_t res = 0; @@ -767,7 +767,7 @@ __poll_t ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait) __poll_t ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait) { __poll_t req_events = poll_requested_events(wait); - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; int eof = test_bit(IVTV_F_S_STREAMOFF, &s->s_flags); @@ -831,7 +831,7 @@ void ivtv_stop_capture(struct ivtv_open_id *id, int gop_end) id->type == IVTV_ENC_STREAM_TYPE_VBI) && test_bit(IVTV_F_S_INTERNAL_USE, &s->s_flags)) { /* Also used internally, don't stop capturing */ - s->fh = NULL; + s->id = NULL; } else { ivtv_stop_v4l2_encode_stream(s, gop_end); @@ -877,8 +877,8 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts) int ivtv_v4l2_close(struct file *filp) { - struct v4l2_fh *fh = filp->private_data; - struct ivtv_open_id *id = fh2id(fh); + struct v4l2_fh *fh = file_to_v4l2_fh(filp); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; @@ -911,11 +911,11 @@ int ivtv_v4l2_close(struct file *filp) ivtv_unmute(itv); } - v4l2_fh_del(fh); + v4l2_fh_del(fh, filp); v4l2_fh_exit(fh); /* Easy case first: this stream was never claimed by us */ - if (s->fh != &id->fh) + if (s->id != id) goto close_done; /* 'Unclaim' this stream */ @@ -998,9 +998,7 @@ static int ivtv_open(struct file *filp) v4l2_fh_init(&item->fh, &s->vdev); item->itv = itv; item->type = s->type; - - filp->private_data = &item->fh; - v4l2_fh_add(&item->fh); + v4l2_fh_add(&item->fh, filp); if (item->type == IVTV_ENC_STREAM_TYPE_RAD && v4l2_fh_is_singular_file(filp)) { @@ -1008,7 +1006,7 @@ static int ivtv_open(struct file *filp) if (atomic_read(&itv->capturing) > 0) { /* switching to radio while capture is in progress is not polite */ - v4l2_fh_del(&item->fh); + v4l2_fh_del(&item->fh, filp); v4l2_fh_exit(&item->fh); kfree(item); return -EBUSY; diff --git a/drivers/media/pci/ivtv/ivtv-fileops.h b/drivers/media/pci/ivtv/ivtv-fileops.h index c2c01bba5d03..7bbe42b0030c 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.h +++ b/drivers/media/pci/ivtv/ivtv-fileops.h @@ -2,7 +2,7 @@ /* file operation functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c index 56b25255faf5..1bc873ebef73 100644 --- a/drivers/media/pci/ivtv/ivtv-firmware.c +++ b/drivers/media/pci/ivtv/ivtv-firmware.c @@ -3,7 +3,7 @@ ivtv firmware functions. Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-firmware.h b/drivers/media/pci/ivtv/ivtv-firmware.h index 393e94a8d0e4..ce94b6c385de 100644 --- a/drivers/media/pci/ivtv/ivtv-firmware.h +++ b/drivers/media/pci/ivtv/ivtv-firmware.h @@ -3,7 +3,7 @@ ivtv firmware functions. Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c index 6434c0d03a6d..d3477e1529c9 100644 --- a/drivers/media/pci/ivtv/ivtv-gpio.c +++ b/drivers/media/pci/ivtv/ivtv-gpio.c @@ -3,7 +3,7 @@ gpio functions. Merging GPIO support into driver: Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-gpio.h b/drivers/media/pci/ivtv/ivtv-gpio.h index 4ad817173f04..686c9b5e9c19 100644 --- a/drivers/media/pci/ivtv/ivtv-gpio.h +++ b/drivers/media/pci/ivtv/ivtv-gpio.h @@ -2,7 +2,7 @@ /* gpio functions. Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c index c052c57c6dce..28cb22d6a892 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.c +++ b/drivers/media/pci/ivtv/ivtv-i2c.c @@ -2,7 +2,7 @@ /* I2C functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-i2c.h b/drivers/media/pci/ivtv/ivtv-i2c.h index 2d9cdaa682c5..504bbc1dee25 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.h +++ b/drivers/media/pci/ivtv/ivtv-i2c.h @@ -2,7 +2,7 @@ /* I2C functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 7947dcd615e8..8d5ea3aec06f 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -2,7 +2,7 @@ /* ioctl system call Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ @@ -308,7 +308,7 @@ static int ivtv_video_command(struct ivtv *itv, struct ivtv_open_id *id, static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; vbifmt->reserved[0] = 0; @@ -330,7 +330,7 @@ static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_fo static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; @@ -353,7 +353,7 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; vbifmt->sampling_rate = 27000000; @@ -372,7 +372,7 @@ static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; vbifmt->reserved[0] = 0; @@ -394,7 +394,7 @@ static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; @@ -434,8 +434,8 @@ static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; struct v4l2_window *winfmt = &fmt->fmt.win; if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) @@ -461,7 +461,7 @@ static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_ static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; @@ -490,7 +490,7 @@ static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; if (id->type == IVTV_DEC_STREAM_TYPE_VBI) @@ -510,7 +510,7 @@ static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); s32 w = fmt->fmt.pix.width; s32 h = fmt->fmt.pix.height; int field = fmt->fmt.pix.field; @@ -544,8 +544,8 @@ static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; u32 chromakey = fmt->fmt.win.chromakey; u8 global_alpha = fmt->fmt.win.global_alpha; @@ -566,7 +566,7 @@ static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_fo static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, @@ -597,7 +597,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (!ivtv_raw_vbi(itv) && atomic_read(&itv->capturing) > 0) return -EBUSY; @@ -610,7 +610,7 @@ static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt); @@ -628,7 +628,7 @@ static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; int ret = ivtv_try_fmt_vid_out(file, fh, fmt); @@ -673,7 +673,7 @@ static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt); if (ret == 0) { @@ -710,7 +710,7 @@ static int ivtv_itvc(struct ivtv *itv, bool get, u64 reg, u64 *val) static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; reg->size = 4; return ivtv_itvc(itv, true, reg->reg, ®->val); @@ -718,7 +718,7 @@ static int ivtv_g_register(struct file *file, void *fh, struct v4l2_dbg_register static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; u64 val = reg->val; return ivtv_itvc(itv, false, reg->reg, &val); @@ -727,7 +727,7 @@ static int ivtv_s_register(struct file *file, void *fh, const struct v4l2_dbg_re static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { - struct ivtv_open_id *id = fh2id(file->private_data); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); @@ -738,14 +738,14 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; return ivtv_get_audio_input(itv, vin->index, vin); } static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; vin->index = itv->audio_input; return ivtv_get_audio_input(itv, vin->index, vin); @@ -753,7 +753,7 @@ static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) static int ivtv_s_audio(struct file *file, void *fh, const struct v4l2_audio *vout) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (vout->index >= itv->nof_audio_inputs) return -EINVAL; @@ -766,7 +766,7 @@ static int ivtv_s_audio(struct file *file, void *fh, const struct v4l2_audio *vo static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; /* set it to defaults from our table */ return ivtv_get_audio_output(itv, vin->index, vin); @@ -774,7 +774,7 @@ static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vi static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; vin->index = 0; return ivtv_get_audio_output(itv, vin->index, vin); @@ -782,7 +782,7 @@ static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin) static int ivtv_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (itv->card->video_outputs == NULL || vout->index != 0) return -EINVAL; @@ -791,7 +791,7 @@ static int ivtv_s_audout(struct file *file, void *fh, const struct v4l2_audioout static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; /* set it to defaults from our table */ return ivtv_get_input(itv, vin->index, vin); @@ -799,7 +799,7 @@ static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin) static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; return ivtv_get_output(itv, vout->index, vout); } @@ -807,7 +807,7 @@ static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vou static int ivtv_g_pixelaspect(struct file *file, void *fh, int type, struct v4l2_fract *f) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -825,7 +825,7 @@ static int ivtv_g_pixelaspect(struct file *file, void *fh, static int ivtv_s_selection(struct file *file, void *fh, struct v4l2_selection *sel) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; struct v4l2_rect r = { 0, 0, 720, 0 }; @@ -868,7 +868,7 @@ static int ivtv_s_selection(struct file *file, void *fh, static int ivtv_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; struct yuv_playback_info *yi = &itv->yuv_info; struct v4l2_rect r = { 0, 0, 720, 0 }; @@ -924,8 +924,8 @@ static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdes .description = "MPEG", .pixelformat = V4L2_PIX_FMT_MPEG, }; - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; if (fmt->index) return -EINVAL; @@ -951,8 +951,8 @@ static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdes .description = "MPEG", .pixelformat = V4L2_PIX_FMT_MPEG, }; - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; if (fmt->index) return -EINVAL; @@ -967,16 +967,15 @@ static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdes static int ivtv_g_input(struct file *file, void *fh, unsigned int *i) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; *i = itv->active_input; return 0; } -int ivtv_s_input(struct file *file, void *fh, unsigned int inp) +int ivtv_do_s_input(struct ivtv *itv, unsigned int inp) { - struct ivtv *itv = fh2id(fh)->itv; v4l2_std_id std; int i; @@ -1017,9 +1016,14 @@ int ivtv_s_input(struct file *file, void *fh, unsigned int inp) return 0; } +static int ivtv_s_input(struct file *file, void *fh, unsigned int inp) +{ + return ivtv_do_s_input(file2id(file)->itv, inp); +} + static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) return -EINVAL; @@ -1031,7 +1035,7 @@ static int ivtv_g_output(struct file *file, void *fh, unsigned int *i) static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (outp >= itv->card->nof_outputs) return -EINVAL; @@ -1053,8 +1057,8 @@ static int ivtv_s_output(struct file *file, void *fh, unsigned int outp) static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; if (s->vdev.vfl_dir) return -ENOTTY; @@ -1065,10 +1069,9 @@ static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency * return 0; } -int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +int ivtv_do_s_frequency(struct ivtv_stream *s, const struct v4l2_frequency *vf) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = s->itv; if (s->vdev.vfl_dir) return -ENOTTY; @@ -1082,9 +1085,18 @@ int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *v return 0; } +static int ivtv_s_frequency(struct file *file, void *fh, + const struct v4l2_frequency *vf) +{ + struct ivtv_open_id *id = file2id(file); + struct ivtv *itv = id->itv; + + return ivtv_do_s_frequency(&itv->streams[id->type], vf); +} + static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; *std = itv->std; return 0; @@ -1157,7 +1169,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std) static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id std) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if ((std & V4L2_STD_ALL) == 0) return -EINVAL; @@ -1185,7 +1197,7 @@ static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id std) static int ivtv_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; if (vt->index != 0) @@ -1198,7 +1210,7 @@ static int ivtv_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (vt->index != 0) return -EINVAL; @@ -1214,7 +1226,7 @@ static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; int f, l; @@ -1249,7 +1261,7 @@ static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; struct v4l2_enc_idx_entry *e = idx->entry; int entries; int i; @@ -1275,7 +1287,7 @@ static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *id static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; @@ -1327,7 +1339,7 @@ static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; switch (enc->cmd) { case V4L2_ENC_CMD_START: @@ -1357,8 +1369,8 @@ static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) { - struct ivtv *itv = fh2id(fh)->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv *itv = file2id(file)->itv; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; u32 data[CX2341X_MBOX_MAX_DATA]; struct yuv_playback_info *yi = &itv->yuv_info; @@ -1444,9 +1456,9 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb) static int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *fb) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; struct yuv_playback_info *yi = &itv->yuv_info; if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) @@ -1465,9 +1477,9 @@ static int ivtv_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffe static int ivtv_overlay(struct file *file, void *fh, unsigned int on) { - struct ivtv_open_id *id = fh2id(fh); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[fh2id(fh)->type]; + struct ivtv_stream *s = &itv->streams[file2id(file)->type]; if (!(s->vdev.device_caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY)) return -ENOTTY; @@ -1492,7 +1504,7 @@ static int ivtv_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subs static int ivtv_log_status(struct file *file, void *fh) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; u32 data[CX2341X_MBOX_MAX_DATA]; int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT; @@ -1584,7 +1596,7 @@ static int ivtv_log_status(struct file *file, void *fh) static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) { - struct ivtv_open_id *id = fh2id(file->private_data); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; IVTV_DEBUG_IOCTL("VIDIOC_DECODER_CMD %d\n", dec->cmd); @@ -1593,7 +1605,7 @@ static int ivtv_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) { - struct ivtv_open_id *id = fh2id(file->private_data); + struct ivtv_open_id *id = file2id(file); struct ivtv *itv = id->itv; IVTV_DEBUG_IOCTL("VIDIOC_TRY_DECODER_CMD %d\n", dec->cmd); @@ -1602,7 +1614,7 @@ static int ivtv_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) { - struct ivtv_open_id *id = fh2id(filp->private_data); + struct ivtv_open_id *id = file2id(filp); struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[id->type]; @@ -1645,7 +1657,7 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg) static long ivtv_default(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg) { - struct ivtv *itv = fh2id(fh)->itv; + struct ivtv *itv = file2id(file)->itv; if (!valid_prio) { switch (cmd) { diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.h b/drivers/media/pci/ivtv/ivtv-ioctl.h index 42c2516379fc..96ca7e2ef973 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.h +++ b/drivers/media/pci/ivtv/ivtv-ioctl.h @@ -2,13 +2,15 @@ /* ioctl system call Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ #ifndef IVTV_IOCTL_H #define IVTV_IOCTL_H +struct ivtv; + u16 ivtv_service2vbi(int type); void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt); @@ -17,7 +19,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed); void ivtv_set_funcs(struct video_device *vdev); void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std); void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std); -int ivtv_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); -int ivtv_s_input(struct file *file, void *fh, unsigned int inp); +int ivtv_do_s_frequency(struct ivtv_stream *s, const struct v4l2_frequency *vf); +int ivtv_do_s_input(struct ivtv *itv, unsigned int inp); #endif diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c index 748c14e87963..05e0293b4d44 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.c +++ b/drivers/media/pci/ivtv/ivtv-irq.c @@ -2,7 +2,7 @@ /* interrupt handling Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ @@ -305,7 +305,7 @@ static void dma_post(struct ivtv_stream *s) ivtv_process_vbi_data(itv, buf, 0, s->type); s->q_dma.bytesused += buf->bytesused; } - if (s->fh == NULL) { + if (s->id == NULL) { ivtv_queue_move(s, &s->q_dma, NULL, &s->q_free, 0); return; } @@ -330,7 +330,7 @@ static void dma_post(struct ivtv_stream *s) set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags); } - if (s->fh) + if (s->id) wake_up(&s->waitq); } @@ -351,7 +351,7 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock) /* Insert buffer block for YUV if needed */ if (s->type == IVTV_DEC_STREAM_TYPE_YUV && f->offset_y) { - if (yi->blanking_dmaptr) { + if (yi->blanking_ptr) { s->sg_pending[idx].src = yi->blanking_dmaptr; s->sg_pending[idx].dst = offset; s->sg_pending[idx].size = 720 * 16; diff --git a/drivers/media/pci/ivtv/ivtv-irq.h b/drivers/media/pci/ivtv/ivtv-irq.h index b8b0703a1c82..8a780bea7de4 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.h +++ b/drivers/media/pci/ivtv/ivtv-irq.h @@ -3,7 +3,7 @@ interrupt handling Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-mailbox.c b/drivers/media/pci/ivtv/ivtv-mailbox.c index d3fdaaa903f1..cd7c9f2d473f 100644 --- a/drivers/media/pci/ivtv/ivtv-mailbox.c +++ b/drivers/media/pci/ivtv/ivtv-mailbox.c @@ -3,7 +3,7 @@ mailbox functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-mailbox.h b/drivers/media/pci/ivtv/ivtv-mailbox.h index 537c90437e1d..364e7f51508e 100644 --- a/drivers/media/pci/ivtv/ivtv-mailbox.h +++ b/drivers/media/pci/ivtv/ivtv-mailbox.h @@ -2,7 +2,7 @@ /* mailbox functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-queue.c b/drivers/media/pci/ivtv/ivtv-queue.c index f9b192ab7e7c..f7d2d159d800 100644 --- a/drivers/media/pci/ivtv/ivtv-queue.c +++ b/drivers/media/pci/ivtv/ivtv-queue.c @@ -3,7 +3,7 @@ buffer queues. Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-queue.h b/drivers/media/pci/ivtv/ivtv-queue.h index 983e99642364..9619745d6de1 100644 --- a/drivers/media/pci/ivtv/ivtv-queue.h +++ b/drivers/media/pci/ivtv/ivtv-queue.h @@ -3,7 +3,7 @@ buffer queues. Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-routing.c b/drivers/media/pci/ivtv/ivtv-routing.c index 57d4d5a3cb87..b1dfc2e96d91 100644 --- a/drivers/media/pci/ivtv/ivtv-routing.c +++ b/drivers/media/pci/ivtv/ivtv-routing.c @@ -2,7 +2,7 @@ /* Audio/video-routing-related ivtv functions. Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-routing.h b/drivers/media/pci/ivtv/ivtv-routing.h index e4a0ae0694d2..69ddb66ef26f 100644 --- a/drivers/media/pci/ivtv/ivtv-routing.h +++ b/drivers/media/pci/ivtv/ivtv-routing.h @@ -2,7 +2,7 @@ /* Audio/video-routing-related ivtv functions. Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c index ac085925d3cb..d98fe0c9d9f1 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.c +++ b/drivers/media/pci/ivtv/ivtv-streams.c @@ -1,22 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* init/start/stop/exit stream functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ /* License: GPL diff --git a/drivers/media/pci/ivtv/ivtv-streams.h b/drivers/media/pci/ivtv/ivtv-streams.h index 5f35c57fcdfd..43d4ecd6dd6f 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.h +++ b/drivers/media/pci/ivtv/ivtv-streams.h @@ -2,7 +2,7 @@ /* init/start/stop/exit stream functions Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c index f467a00492f4..7dedf04f9f87 100644 --- a/drivers/media/pci/ivtv/ivtv-udma.c +++ b/drivers/media/pci/ivtv/ivtv-udma.c @@ -4,7 +4,7 @@ Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-udma.h b/drivers/media/pci/ivtv/ivtv-udma.h index 12b9426b2db2..3030fadfdbc7 100644 --- a/drivers/media/pci/ivtv/ivtv-udma.h +++ b/drivers/media/pci/ivtv/ivtv-udma.h @@ -2,7 +2,7 @@ /* Copyright (C) 2003-2004 Kevin Thayer <nufan_wfk at yahoo.com> Copyright (C) 2004 Chris Kennedy <c@groovy.org> - Copyright (C) 2006-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2006-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-vbi.c b/drivers/media/pci/ivtv/ivtv-vbi.c index 80478b026d75..ae7a00f46257 100644 --- a/drivers/media/pci/ivtv/ivtv-vbi.c +++ b/drivers/media/pci/ivtv/ivtv-vbi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* Vertical Blank Interval support functions - Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2004-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-vbi.h b/drivers/media/pci/ivtv/ivtv-vbi.h index 780f73d2ab6b..12fe27da544b 100644 --- a/drivers/media/pci/ivtv/ivtv-vbi.h +++ b/drivers/media/pci/ivtv/ivtv-vbi.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* Vertical Blank Interval support functions - Copyright (C) 2004-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2004-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-version.h b/drivers/media/pci/ivtv/ivtv-version.h index 996f1871e49c..21e26d1f66b8 100644 --- a/drivers/media/pci/ivtv/ivtv-version.h +++ b/drivers/media/pci/ivtv/ivtv-version.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* ivtv driver version information - Copyright (C) 2005-2007 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2005-2007 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c index 2d9274537725..71f040106647 100644 --- a/drivers/media/pci/ivtv/ivtv-yuv.c +++ b/drivers/media/pci/ivtv/ivtv-yuv.c @@ -125,7 +125,7 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); /* If we've offset the y plane, ensure top area is blanked */ - if (f->offset_y && yi->blanking_dmaptr) { + if (f->offset_y && yi->blanking_ptr) { dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16); dma->SGarray[dma->SG_length].src = cpu_to_le32(yi->blanking_dmaptr); dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]); @@ -929,6 +929,12 @@ static void ivtv_yuv_init(struct ivtv *itv) yi->blanking_dmaptr = dma_map_single(&itv->pdev->dev, yi->blanking_ptr, 720 * 16, DMA_TO_DEVICE); + if (dma_mapping_error(&itv->pdev->dev, yi->blanking_dmaptr)) { + kfree(yi->blanking_ptr); + yi->blanking_ptr = NULL; + yi->blanking_dmaptr = 0; + IVTV_DEBUG_WARN("Failed to dma_map yuv blanking buffer\n"); + } } else { yi->blanking_dmaptr = 0; IVTV_DEBUG_WARN("Failed to allocate yuv blanking buffer\n"); diff --git a/drivers/media/pci/mgb4/mgb4_trigger.c b/drivers/media/pci/mgb4/mgb4_trigger.c index 923650d53d4c..4f9a35904b41 100644 --- a/drivers/media/pci/mgb4/mgb4_trigger.c +++ b/drivers/media/pci/mgb4/mgb4_trigger.c @@ -17,6 +17,7 @@ #include <linux/iio/triggered_buffer.h> #include <linux/pci.h> #include <linux/dma/amd_xdma.h> +#include <linux/types.h> #include "mgb4_core.h" #include "mgb4_trigger.h" @@ -90,13 +91,13 @@ static irqreturn_t trigger_handler(int irq, void *p) struct trigger_data *st = iio_priv(indio_dev); struct { u32 data; - s64 ts __aligned(8); - } scan; + aligned_s64 ts; + } scan = { }; scan.data = mgb4_read_reg(&st->mgbdev->video, 0xA0); mgb4_write_reg(&st->mgbdev->video, 0xA0, scan.data); - iio_push_to_buffers_with_timestamp(indio_dev, &scan, pf->timestamp); + iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan), pf->timestamp); iio_trigger_notify_done(indio_dev->trig); mgb4_write_reg(&st->mgbdev->video, 0xB4, 1U << 11); diff --git a/drivers/media/pci/mgb4/mgb4_vin.c b/drivers/media/pci/mgb4/mgb4_vin.c index 989e93f67f75..4b38076486ff 100644 --- a/drivers/media/pci/mgb4/mgb4_vin.c +++ b/drivers/media/pci/mgb4/mgb4_vin.c @@ -64,10 +64,10 @@ static const struct mgb4_i2c_kv gmsl_i2c[] = { static const struct v4l2_dv_timings_cap video_timings_cap = { .type = V4L2_DV_BT_656_1120, .bt = { - .min_width = 320, + .min_width = 240, .max_width = 4096, .min_height = 240, - .max_height = 2160, + .max_height = 4096, .min_pixelclock = 1843200, /* 320 x 240 x 24Hz */ .max_pixelclock = 530841600, /* 4096 x 2160 x 60Hz */ .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | @@ -610,8 +610,7 @@ static int vidioc_s_dv_timings(struct file *file, void *fh, timings->bt.height < video_timings_cap.bt.min_height || timings->bt.height > video_timings_cap.bt.max_height) return -EINVAL; - if (timings->bt.width == vindev->timings.bt.width && - timings->bt.height == vindev->timings.bt.height) + if (v4l2_match_dv_timings(timings, &vindev->timings, 0, false)) return 0; if (vb2_is_busy(&vindev->queue)) return -EBUSY; diff --git a/drivers/media/pci/mgb4/mgb4_vout.c b/drivers/media/pci/mgb4/mgb4_vout.c index c179c425e167..fd93fbbaf755 100644 --- a/drivers/media/pci/mgb4/mgb4_vout.c +++ b/drivers/media/pci/mgb4/mgb4_vout.c @@ -44,10 +44,10 @@ static const struct mgb4_i2c_kv fpdl3_i2c[] = { static const struct v4l2_dv_timings_cap video_timings_cap = { .type = V4L2_DV_BT_656_1120, .bt = { - .min_width = 320, + .min_width = 240, .max_width = 4096, .min_height = 240, - .max_height = 2160, + .max_height = 4096, .min_pixelclock = 1843200, /* 320 x 240 x 24Hz */ .max_pixelclock = 530841600, /* 4096 x 2160 x 60Hz */ .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index 121a4a92ea10..1ced093583ac 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -639,7 +639,7 @@ static int pt1_init_tables(struct pt1 *pt1) if (!pt1_nr_tables) return 0; - tables = vmalloc(array_size(pt1_nr_tables, sizeof(struct pt1_table))); + tables = vmalloc_array(pt1_nr_tables, sizeof(struct pt1_table)); if (tables == NULL) return -ENOMEM; diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index c88939bce56b..4a51b873e47a 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1302,7 +1302,7 @@ static int saa7134_g_pixelaspect(struct file *file, void *priv, return 0; } -static int saa7134_g_selection(struct file *file, void *f, struct v4l2_selection *sel) +static int saa7134_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct saa7134_dev *dev = video_drvdata(file); @@ -1325,7 +1325,7 @@ static int saa7134_g_selection(struct file *file, void *f, struct v4l2_selection return 0; } -static int saa7134_s_selection(struct file *file, void *f, struct v4l2_selection *sel) +static int saa7134_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct saa7134_dev *dev = video_drvdata(file); struct v4l2_rect *b = &dev->crop_bounds; diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index bf73e9e83f52..66d650b5f69a 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -219,7 +219,7 @@ int saa7164_s_std(struct saa7164_port *port, v4l2_std_id id) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_s_std(fh->port, id); } @@ -232,7 +232,7 @@ int saa7164_g_std(struct saa7164_port *port, v4l2_std_id *id) static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_g_std(fh->port, id); } @@ -277,7 +277,7 @@ int saa7164_g_input(struct saa7164_port *port, unsigned int *i) static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_g_input(fh->port, i); } @@ -301,14 +301,14 @@ int saa7164_s_input(struct saa7164_port *port, unsigned int i) static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_s_input(fh->port, i); } int saa7164_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -347,7 +347,7 @@ int saa7164_g_frequency(struct saa7164_port *port, struct v4l2_frequency *f) static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_g_frequency(fh->port, f); } @@ -400,7 +400,7 @@ int saa7164_s_frequency(struct saa7164_port *port, static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); return saa7164_s_frequency(fh->port, f); } @@ -483,7 +483,7 @@ static int saa7164_s_ctrl(struct v4l2_ctrl *ctrl) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -510,7 +510,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; @@ -725,15 +725,14 @@ static int fops_open(struct file *file) fh->port = port; v4l2_fh_init(&fh->fh, video_devdata(file)); - v4l2_fh_add(&fh->fh); - file->private_data = fh; + v4l2_fh_add(&fh->fh, file); return 0; } static int fops_release(struct file *file) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -747,7 +746,7 @@ static int fops_release(struct file *file) } } - v4l2_fh_del(&fh->fh); + v4l2_fh_del(&fh->fh, file); v4l2_fh_exit(&fh->fh); kfree(fh); @@ -787,7 +786,7 @@ saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port) static ssize_t fops_read(struct file *file, char __user *buffer, size_t count, loff_t *pos) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; struct saa7164_user_buffer *ubuf = NULL; struct saa7164_dev *dev = port->dev; @@ -893,8 +892,7 @@ err: static __poll_t fops_poll(struct file *file, poll_table *wait) { __poll_t req_events = poll_requested_events(wait); - struct saa7164_encoder_fh *fh = - (struct saa7164_encoder_fh *)file->private_data; + struct saa7164_encoder_fh *fh = to_saa7164_encoder_fh(file); struct saa7164_port *port = fh->port; __poll_t mask = v4l2_ctrl_poll(file, wait); diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index ac958a5fca78..57e4362c0d19 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -144,28 +144,28 @@ static int saa7164_vbi_initialize(struct saa7164_port *port) /* -- V4L2 --------------------------------------------------------- */ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_s_std(fh->port->enc_port, id); } static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct saa7164_encoder_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_g_std(fh->port->enc_port, id); } static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_g_input(fh->port->enc_port, i); } static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_s_input(fh->port->enc_port, i); } @@ -173,7 +173,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); return saa7164_g_frequency(fh->port->enc_port, f); } @@ -181,7 +181,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); int ret = saa7164_s_frequency(fh->port->enc_port, f); if (ret == 0) @@ -192,7 +192,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -428,15 +428,14 @@ static int fops_open(struct file *file) fh->port = port; v4l2_fh_init(&fh->fh, video_devdata(file)); - v4l2_fh_add(&fh->fh); - file->private_data = fh; + v4l2_fh_add(&fh->fh, file); return 0; } static int fops_release(struct file *file) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); struct saa7164_port *port = fh->port; struct saa7164_dev *dev = port->dev; @@ -450,7 +449,7 @@ static int fops_release(struct file *file) } } - v4l2_fh_del(&fh->fh); + v4l2_fh_del(&fh->fh, file); v4l2_fh_exit(&fh->fh); kfree(fh); @@ -489,7 +488,7 @@ saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port) static ssize_t fops_read(struct file *file, char __user *buffer, size_t count, loff_t *pos) { - struct saa7164_vbi_fh *fh = file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); struct saa7164_port *port = fh->port; struct saa7164_user_buffer *ubuf = NULL; struct saa7164_dev *dev = port->dev; @@ -596,7 +595,7 @@ err: static __poll_t fops_poll(struct file *file, poll_table *wait) { - struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data; + struct saa7164_vbi_fh *fh = to_saa7164_vbi_fh(file); struct saa7164_port *port = fh->port; __poll_t mask = 0; diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h index e1bac1fe19d3..94e987e7b5e5 100644 --- a/drivers/media/pci/saa7164/saa7164.h +++ b/drivers/media/pci/saa7164/saa7164.h @@ -180,12 +180,22 @@ struct saa7164_encoder_fh { atomic_t v4l_reading; }; +static inline struct saa7164_encoder_fh *to_saa7164_encoder_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct saa7164_encoder_fh, fh); +} + struct saa7164_vbi_fh { struct v4l2_fh fh; struct saa7164_port *port; atomic_t v4l_reading; }; +static inline struct saa7164_vbi_fh *to_saa7164_vbi_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct saa7164_vbi_fh, fh); +} + struct saa7164_histogram_bucket { u32 val; u32 count; diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 35dd19b2427e..08b7ce1043aa 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -14,7 +14,7 @@ * * Refactored and updated to the latest v4l core frameworks: * - * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2014 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/init.h> @@ -37,7 +37,7 @@ MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards"); MODULE_AUTHOR("William M. Brack"); -MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_LICENSE("GPL"); static unsigned int latency = UNSET; diff --git a/drivers/media/pci/tw68/tw68-reg.h b/drivers/media/pci/tw68/tw68-reg.h index dcd9931b25cc..8aeef452ea8a 100644 --- a/drivers/media/pci/tw68/tw68-reg.h +++ b/drivers/media/pci/tw68/tw68-reg.h @@ -13,7 +13,7 @@ * * Refactored and updated to the latest v4l core frameworks: * - * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2014 Hans Verkuil <hverkuil@kernel.org> */ #ifndef _TW68_REG_H_ diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c index dacb136c4f3a..e793db6134e4 100644 --- a/drivers/media/pci/tw68/tw68-risc.c +++ b/drivers/media/pci/tw68/tw68-risc.c @@ -14,7 +14,7 @@ * * Refactored and updated to the latest v4l core frameworks: * - * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2014 Hans Verkuil <hverkuil@kernel.org> */ #include "tw68.h" diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 77773dec48b8..6232bac170d0 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -13,7 +13,7 @@ * * Refactored and updated to the latest v4l core frameworks: * - * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2014 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/module.h> diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h index a1f422d6e600..66be6b3bb7b6 100644 --- a/drivers/media/pci/tw68/tw68.h +++ b/drivers/media/pci/tw68/tw68.h @@ -13,7 +13,7 @@ * * Refactored and updated to the latest v4l core frameworks: * - * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2014 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/pci.h> diff --git a/drivers/media/pci/zoran/zoran.h b/drivers/media/pci/zoran/zoran.h index 1cd990468d3d..d05e222b3921 100644 --- a/drivers/media/pci/zoran/zoran.h +++ b/drivers/media/pci/zoran/zoran.h @@ -154,12 +154,6 @@ struct zoran_jpg_settings { struct zoran; -/* zoran_fh contains per-open() settings */ -struct zoran_fh { - struct v4l2_fh fh; - struct zoran *zr; -}; - struct card_info { enum card_type type; char name[32]; diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c index e31f9f19a48a..d81facf735d9 100644 --- a/drivers/media/pci/zoran/zoran_card.c +++ b/drivers/media/pci/zoran/zoran_card.c @@ -67,10 +67,6 @@ module_param(pass_through, int, 0644); MODULE_PARM_DESC(pass_through, "Pass TV signal through to TV-out when idling"); -int zr36067_debug = 1; -module_param_named(debug, zr36067_debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-5)"); - #define ZORAN_VERSION "0.10.1" MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); diff --git a/drivers/media/pci/zoran/zoran_card.h b/drivers/media/pci/zoran/zoran_card.h index 518cb426b446..c4f81777e6ce 100644 --- a/drivers/media/pci/zoran/zoran_card.h +++ b/drivers/media/pci/zoran/zoran_card.h @@ -12,8 +12,6 @@ #ifndef __ZORAN_CARD_H__ #define __ZORAN_CARD_H__ -extern int zr36067_debug; - /* Anybody who uses more than four? */ #define BUZ_MAX 4 diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index f42f596d3e62..5b4d5dd06edb 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -245,7 +245,7 @@ static int zoran_set_input(struct zoran *zr, int input) * ioctl routine */ -static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap) +static int zoran_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { struct zoran *zr = video_drvdata(file); @@ -278,7 +278,7 @@ static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag) return -EINVAL; } -static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, +static int zoran_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) { struct zoran *zr = video_drvdata(file); @@ -286,7 +286,7 @@ static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE); } -static int zoran_g_fmt_vid_out(struct file *file, void *__fh, +static int zoran_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); @@ -308,13 +308,13 @@ static int zoran_g_fmt_vid_out(struct file *file, void *__fh, return 0; } -static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, +static int zoran_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); if (zr->map_mode != ZORAN_MAP_MODE_RAW) - return zoran_g_fmt_vid_out(file, __fh, fmt); + return zoran_g_fmt_vid_out(file, fh, fmt); fmt->fmt.pix.width = zr->v4l_settings.width; fmt->fmt.pix.height = zr->v4l_settings.height; fmt->fmt.pix.sizeimage = zr->buffer_size; @@ -328,7 +328,7 @@ static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, return 0; } -static int zoran_try_fmt_vid_out(struct file *file, void *__fh, +static int zoran_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); @@ -391,7 +391,7 @@ static int zoran_try_fmt_vid_out(struct file *file, void *__fh, return res; } -static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, +static int zoran_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); @@ -399,7 +399,7 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, int i; if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) - return zoran_try_fmt_vid_out(file, __fh, fmt); + return zoran_try_fmt_vid_out(file, fh, fmt); for (i = 0; i < NUM_FORMATS; i++) if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat) @@ -427,7 +427,7 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, return 0; } -static int zoran_s_fmt_vid_out(struct file *file, void *__fh, +static int zoran_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); @@ -507,11 +507,10 @@ static int zoran_s_fmt_vid_out(struct file *file, void *__fh, return res; } -static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, +static int zoran_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) { struct zoran *zr = video_drvdata(file); - struct zoran_fh *fh = __fh; int i; int res = 0; @@ -556,7 +555,7 @@ static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, return res; } -static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) +static int zoran_g_std(struct file *file, void *fh, v4l2_std_id *std) { struct zoran *zr = video_drvdata(file); @@ -564,7 +563,7 @@ static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) return 0; } -static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) +static int zoran_s_std(struct file *file, void *fh, v4l2_std_id std) { struct zoran *zr = video_drvdata(file); int res = 0; @@ -579,7 +578,7 @@ static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) return res; } -static int zoran_enum_input(struct file *file, void *__fh, +static int zoran_enum_input(struct file *file, void *fh, struct v4l2_input *inp) { struct zoran *zr = video_drvdata(file); @@ -596,7 +595,7 @@ static int zoran_enum_input(struct file *file, void *__fh, return 0; } -static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) +static int zoran_g_input(struct file *file, void *fh, unsigned int *input) { struct zoran *zr = video_drvdata(file); @@ -605,7 +604,7 @@ static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) return 0; } -static int zoran_s_input(struct file *file, void *__fh, unsigned int input) +static int zoran_s_input(struct file *file, void *fh, unsigned int input) { struct zoran *zr = video_drvdata(file); int res; @@ -618,7 +617,7 @@ static int zoran_s_input(struct file *file, void *__fh, unsigned int input) } /* cropping (sub-frame capture) */ -static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selection *sel) +static int zoran_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { struct zoran *zr = video_drvdata(file); @@ -653,7 +652,7 @@ static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selectio return 0; } -static int zoran_s_selection(struct file *file, void *__fh, struct v4l2_selection *sel) +static int zoran_s_selection(struct file *file, void *fh, struct v4l2_selection *sel) { struct zoran *zr = video_drvdata(file); struct zoran_jpg_settings settings; diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 9287faafdce5..3f0b7bb68cc9 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -65,6 +65,7 @@ config VIDEO_MUX source "drivers/media/platform/allegro-dvt/Kconfig" source "drivers/media/platform/amlogic/Kconfig" source "drivers/media/platform/amphion/Kconfig" +source "drivers/media/platform/arm/Kconfig" source "drivers/media/platform/aspeed/Kconfig" source "drivers/media/platform/atmel/Kconfig" source "drivers/media/platform/broadcom/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 6fd7db0541c7..6d5f79ddfcc3 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -8,6 +8,7 @@ obj-y += allegro-dvt/ obj-y += amlogic/ obj-y += amphion/ +obj-y += arm/ obj-y += aspeed/ obj-y += atmel/ obj-y += broadcom/ diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index eb03df0d8652..eec0b8b30b7f 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -177,6 +177,7 @@ struct allegro_dev { */ unsigned long channel_user_ids; struct list_head channels; + struct mutex channels_lock; }; static const struct regmap_config allegro_regmap_config = { @@ -197,9 +198,8 @@ static const struct regmap_config allegro_sram_config = { .cache_type = REGCACHE_NONE, }; -#define fh_to_channel(__fh) container_of(__fh, struct allegro_channel, fh) - struct allegro_channel { + struct kref ref; struct allegro_dev *dev; struct v4l2_fh fh; struct v4l2_ctrl_handler ctrl_handler; @@ -302,6 +302,11 @@ struct allegro_channel { unsigned int error; }; +static inline struct allegro_channel *file_to_channel(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct allegro_channel, fh); +} + static inline int allegro_channel_get_i_frame_qp(struct allegro_channel *channel) { @@ -427,33 +432,55 @@ static unsigned long allegro_next_user_id(struct allegro_dev *dev) } static struct allegro_channel * -allegro_find_channel_by_user_id(struct allegro_dev *dev, - unsigned int user_id) +allegro_ref_get_channel_by_user_id(struct allegro_dev *dev, + unsigned int user_id) { struct allegro_channel *channel; + guard(mutex)(&dev->channels_lock); + list_for_each_entry(channel, &dev->channels, list) { - if (channel->user_id == user_id) - return channel; + if (channel->user_id == user_id) { + if (kref_get_unless_zero(&channel->ref)) + return channel; + break; + } } return ERR_PTR(-EINVAL); } static struct allegro_channel * -allegro_find_channel_by_channel_id(struct allegro_dev *dev, - unsigned int channel_id) +allegro_ref_get_channel_by_channel_id(struct allegro_dev *dev, + unsigned int channel_id) { struct allegro_channel *channel; + guard(mutex)(&dev->channels_lock); + list_for_each_entry(channel, &dev->channels, list) { - if (channel->mcu_channel_id == channel_id) - return channel; + if (channel->mcu_channel_id == channel_id) { + if (kref_get_unless_zero(&channel->ref)) + return channel; + break; + } } return ERR_PTR(-EINVAL); } +static void allegro_free_channel(struct kref *ref) +{ + struct allegro_channel *channel = container_of(ref, struct allegro_channel, ref); + + kfree(channel); +} + +static int allegro_ref_put_channel(struct allegro_channel *channel) +{ + return kref_put(&channel->ref, allegro_free_channel); +} + static inline bool channel_exists(struct allegro_channel *channel) { return channel->mcu_channel_id != -1; @@ -828,6 +855,20 @@ out: return err; } +static unsigned int allegro_mbox_get_available(struct allegro_mbox *mbox) +{ + struct regmap *sram = mbox->dev->sram; + unsigned int head, tail; + + regmap_read(sram, mbox->head, &head); + regmap_read(sram, mbox->tail, &tail); + + if (tail >= head) + return tail - head; + else + return mbox->size - (head - tail); +} + static ssize_t allegro_mbox_read(struct allegro_mbox *mbox, u32 *dst, size_t nbyte) { @@ -836,11 +877,15 @@ static ssize_t allegro_mbox_read(struct allegro_mbox *mbox, u16 type; } __attribute__ ((__packed__)) *header; struct regmap *sram = mbox->dev->sram; - unsigned int head; + unsigned int available, head; ssize_t size; size_t body_no_wrap; int stride = regmap_get_reg_stride(sram); + available = allegro_mbox_get_available(mbox); + if (available < sizeof(*header)) + return -EAGAIN; + regmap_read(sram, mbox->head, &head); if (head > mbox->size) return -EIO; @@ -854,6 +899,8 @@ static ssize_t allegro_mbox_read(struct allegro_mbox *mbox, return -EIO; if (size > nbyte) return -EINVAL; + if (size > available) + return -EAGAIN; /* * The message might wrap within the mailbox. If the message does not @@ -913,26 +960,27 @@ out: * allegro_mbox_notify() - Notify the mailbox about a new message * @mbox: The allegro_mbox to notify */ -static void allegro_mbox_notify(struct allegro_mbox *mbox) +static int allegro_mbox_notify(struct allegro_mbox *mbox) { struct allegro_dev *dev = mbox->dev; union mcu_msg_response *msg; - ssize_t size; u32 *tmp; int err; msg = kmalloc(sizeof(*msg), GFP_KERNEL); if (!msg) - return; + return -ENOMEM; msg->header.version = dev->fw_info->mailbox_version; tmp = kmalloc(mbox->size, GFP_KERNEL); - if (!tmp) + if (!tmp) { + err = -ENOMEM; goto out; + } - size = allegro_mbox_read(mbox, tmp, mbox->size); - if (size < 0) + err = allegro_mbox_read(mbox, tmp, mbox->size); + if (err < 0) goto out; err = allegro_decode_mail(msg, tmp); @@ -944,6 +992,8 @@ static void allegro_mbox_notify(struct allegro_mbox *mbox) out: kfree(tmp); kfree(msg); + + return err; } static int allegro_encoder_buffer_init(struct allegro_dev *dev, @@ -2121,7 +2171,7 @@ static void allegro_channel_finish_frame(struct allegro_channel *channel, state = VB2_BUF_STATE_DONE; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); if (msg->is_idr) dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; else @@ -2160,7 +2210,7 @@ allegro_handle_create_channel(struct allegro_dev *dev, int err = 0; struct create_channel_param param; - channel = allegro_find_channel_by_user_id(dev, msg->user_id); + channel = allegro_ref_get_channel_by_user_id(dev, msg->user_id); if (IS_ERR(channel)) { v4l2_warn(&dev->v4l2_dev, "received %s for unknown user %d\n", @@ -2227,6 +2277,7 @@ allegro_handle_create_channel(struct allegro_dev *dev, out: channel->error = err; complete(&channel->completion); + allegro_ref_put_channel(channel); /* Handled successfully, error is passed via channel->error */ return 0; @@ -2238,7 +2289,7 @@ allegro_handle_destroy_channel(struct allegro_dev *dev, { struct allegro_channel *channel; - channel = allegro_find_channel_by_channel_id(dev, msg->channel_id); + channel = allegro_ref_get_channel_by_channel_id(dev, msg->channel_id); if (IS_ERR(channel)) { v4l2_err(&dev->v4l2_dev, "received %s for unknown channel %d\n", @@ -2251,6 +2302,7 @@ allegro_handle_destroy_channel(struct allegro_dev *dev, "user %d: vcu destroyed channel %d\n", channel->user_id, channel->mcu_channel_id); complete(&channel->completion); + allegro_ref_put_channel(channel); return 0; } @@ -2261,7 +2313,7 @@ allegro_handle_encode_frame(struct allegro_dev *dev, { struct allegro_channel *channel; - channel = allegro_find_channel_by_channel_id(dev, msg->channel_id); + channel = allegro_ref_get_channel_by_channel_id(dev, msg->channel_id); if (IS_ERR(channel)) { v4l2_err(&dev->v4l2_dev, "received %s for unknown channel %d\n", @@ -2271,6 +2323,7 @@ allegro_handle_encode_frame(struct allegro_dev *dev, } allegro_channel_finish_frame(channel, msg); + allegro_ref_put_channel(channel); return 0; } @@ -2326,7 +2379,10 @@ static irqreturn_t allegro_irq_thread(int irq, void *data) if (!dev->mbox_status) return IRQ_NONE; - allegro_mbox_notify(dev->mbox_status); + while (allegro_mbox_get_available(dev->mbox_status) > 0) { + if (allegro_mbox_notify(dev->mbox_status)) + break; + } return IRQ_HANDLED; } @@ -2599,8 +2655,14 @@ static int allegro_create_channel(struct allegro_channel *channel) allegro_mcu_send_create_channel(dev, channel); time_left = wait_for_completion_timeout(&channel->completion, msecs_to_jiffies(5000)); - if (time_left == 0) + if (time_left == 0) { + v4l2_warn(&dev->v4l2_dev, + "user %d: timeout while creating channel\n", + channel->user_id); + channel->error = -ETIMEDOUT; + } + if (channel->error) goto err; @@ -3047,6 +3109,8 @@ static int allegro_open(struct file *file) if (!channel) return -ENOMEM; + kref_init(&channel->ref); + v4l2_fh_init(&channel->fh, vdev); init_completion(&channel->completion); @@ -3213,9 +3277,11 @@ static int allegro_open(struct file *file) goto error; } - list_add(&channel->list, &dev->channels); - file->private_data = &channel->fh; - v4l2_fh_add(&channel->fh); + scoped_guard(mutex, &dev->channels_lock) { + list_add(&channel->list, &dev->channels); + } + + v4l2_fh_add(&channel->fh, file); allegro_channel_adjust(channel); @@ -3229,18 +3295,21 @@ error: static int allegro_release(struct file *file) { - struct allegro_channel *channel = fh_to_channel(file->private_data); + struct allegro_channel *channel = file_to_channel(file); + struct allegro_dev *dev = channel->dev; v4l2_m2m_ctx_release(channel->fh.m2m_ctx); - list_del(&channel->list); + scoped_guard(mutex, &dev->channels_lock) { + list_del(&channel->list); + } v4l2_ctrl_handler_free(&channel->ctrl_handler); - v4l2_fh_del(&channel->fh); + v4l2_fh_del(&channel->fh, file); v4l2_fh_exit(&channel->fh); - kfree(channel); + allegro_ref_put_channel(channel); return 0; } @@ -3280,7 +3349,7 @@ static int allegro_enum_fmt_vid(struct file *file, void *fh, static int allegro_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); f->fmt.pix.field = V4L2_FIELD_NONE; f->fmt.pix.width = channel->width; @@ -3322,7 +3391,7 @@ static int allegro_try_fmt_vid_cap(struct file *file, void *fh, static int allegro_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); struct vb2_queue *vq; int err; @@ -3331,8 +3400,6 @@ static int allegro_s_fmt_vid_cap(struct file *file, void *fh, return err; vq = v4l2_m2m_get_vq(channel->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; if (vb2_is_busy(vq)) return -EBUSY; @@ -3346,7 +3413,7 @@ static int allegro_s_fmt_vid_cap(struct file *file, void *fh, static int allegro_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); f->fmt.pix.field = V4L2_FIELD_NONE; @@ -3393,7 +3460,7 @@ static int allegro_try_fmt_vid_out(struct file *file, void *fh, static int allegro_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); int err; err = allegro_try_fmt_vid_out(file, fh, f); @@ -3434,7 +3501,7 @@ static int allegro_channel_cmd_start(struct allegro_channel *channel) static int allegro_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *cmd) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); int err; err = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd); @@ -3483,8 +3550,7 @@ static int allegro_enum_framesizes(struct file *file, void *fh, static int allegro_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct v4l2_fh *fh = file->private_data; - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); int err; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -3493,13 +3559,13 @@ static int allegro_ioctl_streamon(struct file *file, void *priv, return err; } - return v4l2_m2m_streamon(file, fh->m2m_ctx, type); + return v4l2_m2m_streamon(file, channel->fh.m2m_ctx, type); } static int allegro_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); struct v4l2_fract *timeperframe; if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -3516,7 +3582,7 @@ static int allegro_g_parm(struct file *file, void *fh, static int allegro_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct allegro_channel *channel = fh_to_channel(fh); + struct allegro_channel *channel = file_to_channel(file); struct v4l2_fract *timeperframe; int div; @@ -3835,6 +3901,7 @@ static int allegro_probe(struct platform_device *pdev) dev->plat_dev = pdev; init_completion(&dev->init_complete); INIT_LIST_HEAD(&dev->channels); + mutex_init(&dev->channels_lock); mutex_init(&dev->lock); diff --git a/drivers/media/platform/amlogic/c3/isp/Kconfig b/drivers/media/platform/amlogic/c3/isp/Kconfig index 02c62a50a5e8..809208cd7e3a 100644 --- a/drivers/media/platform/amlogic/c3/isp/Kconfig +++ b/drivers/media/platform/amlogic/c3/isp/Kconfig @@ -10,6 +10,7 @@ config VIDEO_C3_ISP select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC + select V4L2_ISP help Video4Linux2 driver for Amlogic C3 ISP pipeline. The C3 ISP is used for processing raw images and diff --git a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c index c80667dd7662..6f9ca7a7dd88 100644 --- a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c +++ b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c @@ -3,11 +3,13 @@ * Copyright (C) 2024 Amlogic, Inc. All rights reserved */ +#include <linux/build_bug.h> #include <linux/cleanup.h> #include <linux/media/amlogic/c3-isp-config.h> #include <linux/pm_runtime.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-isp.h> #include <media/v4l2-mc.h> #include <media/videobuf2-vmalloc.h> @@ -51,11 +53,6 @@ union c3_isp_params_block { typedef void (*c3_isp_block_handler)(struct c3_isp_device *isp, const union c3_isp_params_block *block); -struct c3_isp_params_handler { - size_t size; - c3_isp_block_handler handler; -}; - #define to_c3_isp_params_buffer(vbuf) \ container_of(vbuf, struct c3_isp_params_buffer, vb) @@ -523,41 +520,37 @@ static void c3_isp_params_cfg_blc(struct c3_isp_device *isp, ISP_TOP_BEO_CTRL_BLC_EN); } -static const struct c3_isp_params_handler c3_isp_params_handlers[] = { - [C3_ISP_PARAMS_BLOCK_AWB_GAINS] = { - .size = sizeof(struct c3_isp_params_awb_gains), - .handler = c3_isp_params_cfg_awb_gains, - }, - [C3_ISP_PARAMS_BLOCK_AWB_CONFIG] = { - .size = sizeof(struct c3_isp_params_awb_config), - .handler = c3_isp_params_cfg_awb_config, - }, - [C3_ISP_PARAMS_BLOCK_AE_CONFIG] = { - .size = sizeof(struct c3_isp_params_ae_config), - .handler = c3_isp_params_cfg_ae_config, - }, - [C3_ISP_PARAMS_BLOCK_AF_CONFIG] = { - .size = sizeof(struct c3_isp_params_af_config), - .handler = c3_isp_params_cfg_af_config, - }, - [C3_ISP_PARAMS_BLOCK_PST_GAMMA] = { - .size = sizeof(struct c3_isp_params_pst_gamma), - .handler = c3_isp_params_cfg_pst_gamma, - }, - [C3_ISP_PARAMS_BLOCK_CCM] = { - .size = sizeof(struct c3_isp_params_ccm), - .handler = c3_isp_params_cfg_ccm, - }, - [C3_ISP_PARAMS_BLOCK_CSC] = { - .size = sizeof(struct c3_isp_params_csc), - .handler = c3_isp_params_cfg_csc, - }, - [C3_ISP_PARAMS_BLOCK_BLC] = { - .size = sizeof(struct c3_isp_params_blc), - .handler = c3_isp_params_cfg_blc, - }, +static const c3_isp_block_handler c3_isp_params_handlers[] = { + [C3_ISP_PARAMS_BLOCK_AWB_GAINS] = c3_isp_params_cfg_awb_gains, + [C3_ISP_PARAMS_BLOCK_AWB_CONFIG] = c3_isp_params_cfg_awb_config, + [C3_ISP_PARAMS_BLOCK_AE_CONFIG] = c3_isp_params_cfg_ae_config, + [C3_ISP_PARAMS_BLOCK_AF_CONFIG] = c3_isp_params_cfg_af_config, + [C3_ISP_PARAMS_BLOCK_PST_GAMMA] = c3_isp_params_cfg_pst_gamma, + [C3_ISP_PARAMS_BLOCK_CCM] = c3_isp_params_cfg_ccm, + [C3_ISP_PARAMS_BLOCK_CSC] = c3_isp_params_cfg_csc, + [C3_ISP_PARAMS_BLOCK_BLC] = c3_isp_params_cfg_blc, +}; + +#define C3_ISP_PARAMS_BLOCK_INFO(block, data) \ + [C3_ISP_PARAMS_BLOCK_ ## block] = { \ + .size = sizeof(struct c3_isp_params_ ## data), \ + } + +static const struct v4l2_isp_params_block_type_info +c3_isp_params_block_types_info[] = { + C3_ISP_PARAMS_BLOCK_INFO(AWB_GAINS, awb_gains), + C3_ISP_PARAMS_BLOCK_INFO(AWB_CONFIG, awb_config), + C3_ISP_PARAMS_BLOCK_INFO(AE_CONFIG, ae_config), + C3_ISP_PARAMS_BLOCK_INFO(AF_CONFIG, af_config), + C3_ISP_PARAMS_BLOCK_INFO(PST_GAMMA, pst_gamma), + C3_ISP_PARAMS_BLOCK_INFO(CCM, ccm), + C3_ISP_PARAMS_BLOCK_INFO(CSC, csc), + C3_ISP_PARAMS_BLOCK_INFO(BLC, blc), }; +static_assert(ARRAY_SIZE(c3_isp_params_handlers) == + ARRAY_SIZE(c3_isp_params_block_types_info)); + static void c3_isp_params_cfg_blocks(struct c3_isp_params *params) { struct c3_isp_params_cfg *config = params->buff->cfg; @@ -568,14 +561,14 @@ static void c3_isp_params_cfg_blocks(struct c3_isp_params *params) /* Walk the list of parameter blocks and process them */ while (block_offset < config->data_size) { - const struct c3_isp_params_handler *block_handler; const union c3_isp_params_block *block; + c3_isp_block_handler block_handler; block = (const union c3_isp_params_block *) &config->data[block_offset]; - block_handler = &c3_isp_params_handlers[block->header.type]; - block_handler->handler(params->isp, block); + block_handler = c3_isp_params_handlers[block->header.type]; + block_handler(params->isp, block); block_offset += block->header.size; } @@ -771,26 +764,15 @@ static int c3_isp_params_vb2_buf_prepare(struct vb2_buffer *vb) struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct c3_isp_params_buffer *buf = to_c3_isp_params_buffer(vbuf); struct c3_isp_params *params = vb2_get_drv_priv(vb->vb2_queue); - struct c3_isp_params_cfg *cfg = buf->cfg; struct c3_isp_params_cfg *usr_cfg = vb2_plane_vaddr(vb, 0); size_t payload_size = vb2_get_plane_payload(vb, 0); - size_t header_size = offsetof(struct c3_isp_params_cfg, data); - size_t block_offset = 0; - size_t cfg_size; - - /* Payload size can't be greater than the destination buffer size */ - if (payload_size > params->vfmt.fmt.meta.buffersize) { - dev_dbg(params->isp->dev, - "Payload size is too large: %zu\n", payload_size); - return -EINVAL; - } + struct c3_isp_params_cfg *cfg = buf->cfg; + int ret; - /* Payload size can't be smaller than the header size */ - if (payload_size < header_size) { - dev_dbg(params->isp->dev, - "Payload size is too small: %zu\n", payload_size); - return -EINVAL; - } + ret = v4l2_isp_params_validate_buffer_size(params->isp->dev, vb, + params->vfmt.fmt.meta.buffersize); + if (ret) + return ret; /* * Use the internal scratch buffer to avoid userspace modifying @@ -798,70 +780,10 @@ static int c3_isp_params_vb2_buf_prepare(struct vb2_buffer *vb) */ memcpy(cfg, usr_cfg, payload_size); - /* Only v0 is supported at the moment */ - if (cfg->version != C3_ISP_PARAMS_BUFFER_V0) { - dev_dbg(params->isp->dev, - "Invalid params buffer version: %u\n", cfg->version); - return -EINVAL; - } - - /* Validate the size reported in the parameter buffer header */ - cfg_size = header_size + cfg->data_size; - if (cfg_size != payload_size) { - dev_dbg(params->isp->dev, - "Data size %zu and payload size %zu are different\n", - cfg_size, payload_size); - return -EINVAL; - } - - /* Walk the list of parameter blocks and validate them */ - cfg_size = cfg->data_size; - while (cfg_size >= sizeof(struct c3_isp_params_block_header)) { - const struct c3_isp_params_block_header *block; - const struct c3_isp_params_handler *handler; - - block = (struct c3_isp_params_block_header *) - &cfg->data[block_offset]; - - if (block->type >= ARRAY_SIZE(c3_isp_params_handlers)) { - dev_dbg(params->isp->dev, - "Invalid params block type\n"); - return -EINVAL; - } - - if (block->size > cfg_size) { - dev_dbg(params->isp->dev, - "Block size is greater than cfg size\n"); - return -EINVAL; - } - - if ((block->flags & (C3_ISP_PARAMS_BLOCK_FL_ENABLE | - C3_ISP_PARAMS_BLOCK_FL_DISABLE)) == - (C3_ISP_PARAMS_BLOCK_FL_ENABLE | - C3_ISP_PARAMS_BLOCK_FL_DISABLE)) { - dev_dbg(params->isp->dev, - "Invalid parameters block flags\n"); - return -EINVAL; - } - - handler = &c3_isp_params_handlers[block->type]; - if (block->size != handler->size) { - dev_dbg(params->isp->dev, - "Invalid params block size\n"); - return -EINVAL; - } - - block_offset += block->size; - cfg_size -= block->size; - } - - if (cfg_size) { - dev_dbg(params->isp->dev, - "Unexpected data after the params buffer end\n"); - return -EINVAL; - } - - return 0; + return v4l2_isp_params_validate_buffer(params->isp->dev, vb, + (struct v4l2_isp_params_buffer *)cfg, + c3_isp_params_block_types_info, + ARRAY_SIZE(c3_isp_params_block_types_info)); } static int c3_isp_params_vb2_buf_init(struct vb2_buffer *vb) diff --git a/drivers/media/platform/amlogic/c3/mipi-csi2/c3-mipi-csi2.c b/drivers/media/platform/amlogic/c3/mipi-csi2/c3-mipi-csi2.c index 1011ab3ebac7..b9e4ef3fc308 100644 --- a/drivers/media/platform/amlogic/c3/mipi-csi2/c3-mipi-csi2.c +++ b/drivers/media/platform/amlogic/c3/mipi-csi2/c3-mipi-csi2.c @@ -388,13 +388,12 @@ static void c3_mipi_csi_cfg_host(struct c3_csi_device *csi) c3_mipi_csi_write(csi, CSI2_HOST_N_LANES, csi->bus.num_data_lanes - 1); } -static int c3_mipi_csi_start_stream(struct c3_csi_device *csi, - struct v4l2_subdev *src_sd) +static int c3_mipi_csi_start_stream(struct c3_csi_device *csi) { s64 link_freq; s64 lane_rate; - link_freq = v4l2_get_link_freq(src_sd->ctrl_handler, 0, 0); + link_freq = v4l2_get_link_freq(csi->src_pad, 0, 0); if (link_freq < 0) { dev_err(csi->dev, "Unable to obtain link frequency: %lld\n", link_freq); @@ -434,7 +433,7 @@ static int c3_mipi_csi_enable_streams(struct v4l2_subdev *sd, pm_runtime_resume_and_get(csi->dev); - c3_mipi_csi_start_stream(csi, src_sd); + c3_mipi_csi_start_stream(csi); ret = v4l2_subdev_enable_streams(src_sd, csi->src_pad->index, BIT(0)); if (ret) { diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c index 0c004bb8ba05..c51c6f4e41dc 100644 --- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c +++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c @@ -82,6 +82,11 @@ struct ge2d_ctx { u32 xy_swap; }; +static inline struct ge2d_ctx *file_to_ge2d_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct ge2d_ctx, fh); +} + struct meson_ge2d { struct v4l2_device v4l2_dev; struct v4l2_m2m_dev *m2m_dev; @@ -452,7 +457,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct ge2d_ctx *ctx = priv; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct ge2d_frame *f; bool use_frame = false; @@ -502,7 +507,7 @@ static int vidioc_g_selection(struct file *file, void *priv, static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct ge2d_ctx *ctx = priv; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct meson_ge2d *ge2d = ctx->ge2d; struct ge2d_frame *f; int ret = 0; @@ -569,8 +574,8 @@ static void vidioc_setup_cap_fmt(struct ge2d_ctx *ctx, struct v4l2_pix_format *f static int vidioc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); const struct ge2d_fmt *fmt = find_fmt(f); - struct ge2d_ctx *ctx = priv; struct v4l2_pix_format fmt_cap; vidioc_setup_cap_fmt(ctx, &fmt_cap); @@ -590,7 +595,7 @@ static int vidioc_try_fmt_cap(struct file *file, void *priv, struct v4l2_format static int vidioc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct ge2d_ctx *ctx = priv; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct meson_ge2d *ge2d = ctx->ge2d; struct vb2_queue *vq; struct ge2d_frame *frm; @@ -626,14 +631,9 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct ge2d_ctx *ctx = priv; - struct vb2_queue *vq; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct ge2d_frame *frm; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - frm = get_frame(ctx, f->type); f->fmt.pix = frm->pix_fmt; @@ -665,7 +665,7 @@ static int vidioc_try_fmt_out(struct file *file, void *priv, struct v4l2_format static int vidioc_s_fmt_out(struct file *file, void *priv, struct v4l2_format *f) { - struct ge2d_ctx *ctx = priv; + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct meson_ge2d *ge2d = ctx->ge2d; struct vb2_queue *vq; struct ge2d_frame *frm, *frm_cap; @@ -855,8 +855,7 @@ static int ge2d_open(struct file *file) return ret; } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ge2d_setup_ctrls(ctx); @@ -871,8 +870,7 @@ static int ge2d_open(struct file *file) static int ge2d_release(struct file *file) { - struct ge2d_ctx *ctx = - container_of(file->private_data, struct ge2d_ctx, fh); + struct ge2d_ctx *ctx = file_to_ge2d_ctx(file); struct meson_ge2d *ge2d = ctx->ge2d; mutex_lock(&ge2d->mutex); @@ -880,7 +878,7 @@ static int ge2d_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index 32eef2fd1f2a..c0d2aabb9e0e 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -532,8 +532,6 @@ static int vdec_s_fmt_common(struct vpu_inst *inst, struct v4l2_format *f) return -EINVAL; q = v4l2_m2m_get_vq(inst->fh.m2m_ctx, f->type); - if (!q) - return -EINVAL; if (vb2_is_busy(q)) return -EBUSY; @@ -823,7 +821,7 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) vbuf = &vpu_buf->m2m_buf.vb; src_buf = vdec_get_src_buffer(inst, info->consumed_count); if (src_buf) { - v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true); + v4l2_m2m_buf_copy_metadata(src_buf, vbuf); if (info->consumed_count) { v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index c5c1f1fbaa80..aced76401b69 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -223,8 +223,6 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; q = v4l2_m2m_get_vq(inst->fh.m2m_ctx, f->type); - if (!q) - return -EINVAL; if (vb2_is_busy(q)) return -EBUSY; @@ -790,7 +788,7 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst, src_buf = vpu_find_buf_by_sequence(inst, inst->out_format.type, frame->info.frame_id); if (src_buf) { - v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true); + v4l2_m2m_buf_copy_metadata(src_buf, vbuf); vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, src_buf); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h index cac0f1a64fea..bfd171a3ded4 100644 --- a/drivers/media/platform/amphion/vpu.h +++ b/drivers/media/platform/amphion/vpu.h @@ -328,7 +328,7 @@ static inline const char *vpu_core_type_desc(enum vpu_core_type type) static inline struct vpu_inst *to_inst(struct file *filp) { - return container_of(filp->private_data, struct vpu_inst, fh); + return container_of(file_to_v4l2_fh(filp), struct vpu_inst, fh); } #define ctrl_to_inst(ctrl) \ diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c index da00f5fc0e5d..168f0514851e 100644 --- a/drivers/media/platform/amphion/vpu_core.c +++ b/drivers/media/platform/amphion/vpu_core.c @@ -10,7 +10,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_address.h> +#include <linux/of_reserved_mem.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/types.h> @@ -542,47 +542,30 @@ const struct vpu_core_resources *vpu_get_resource(struct vpu_inst *inst) static int vpu_core_parse_dt(struct vpu_core *core, struct device_node *np) { - struct device_node *node; struct resource res; int ret; - if (of_count_phandle_with_args(np, "memory-region", NULL) < 2) { - dev_err(core->dev, "need 2 memory-region for boot and rpc\n"); - return -ENODEV; + ret = of_reserved_mem_region_to_resource(np, 0, &res); + if (ret) { + dev_err(core->dev, "Cannot get boot-region\n"); + return ret; } - node = of_parse_phandle(np, "memory-region", 0); - if (!node) { - dev_err(core->dev, "boot-region of_parse_phandle error\n"); - return -ENODEV; - } - if (of_address_to_resource(node, 0, &res)) { - dev_err(core->dev, "boot-region of_address_to_resource error\n"); - of_node_put(node); - return -EINVAL; - } core->fw.phys = res.start; core->fw.length = resource_size(&res); - of_node_put(node); - - node = of_parse_phandle(np, "memory-region", 1); - if (!node) { - dev_err(core->dev, "rpc-region of_parse_phandle error\n"); - return -ENODEV; - } - if (of_address_to_resource(node, 0, &res)) { - dev_err(core->dev, "rpc-region of_address_to_resource error\n"); - of_node_put(node); - return -EINVAL; + ret = of_reserved_mem_region_to_resource(np, 1, &res); + if (ret) { + dev_err(core->dev, "Cannot get rpc-region\n"); + return ret; } + core->rpc.phys = res.start; core->rpc.length = resource_size(&res); if (core->rpc.length < core->res->rpc_size + core->res->fwlog_size) { dev_err(core->dev, "the rpc-region <%pad, 0x%x> is not enough\n", &core->rpc.phys, core->rpc.length); - of_node_put(node); return -EINVAL; } @@ -594,7 +577,6 @@ static int vpu_core_parse_dt(struct vpu_core *core, struct device_node *np) if (ret != VPU_CORE_MEMORY_UNCACHED) { dev_err(core->dev, "rpc region<%pad, 0x%x> isn't uncached\n", &core->rpc.phys, core->rpc.length); - of_node_put(node); return -EINVAL; } @@ -606,8 +588,6 @@ static int vpu_core_parse_dt(struct vpu_core *core, struct device_node *np) core->act.length = core->rpc.length - core->res->rpc_size - core->log.length; core->rpc.length = core->res->rpc_size; - of_node_put(node); - return 0; } diff --git a/drivers/media/platform/amphion/vpu_drv.c b/drivers/media/platform/amphion/vpu_drv.c index efbfd2652721..2cca61f41bea 100644 --- a/drivers/media/platform/amphion/vpu_drv.c +++ b/drivers/media/platform/amphion/vpu_drv.c @@ -175,31 +175,6 @@ static void vpu_remove(struct platform_device *pdev) mutex_destroy(&vpu->lock); } -static int __maybe_unused vpu_runtime_resume(struct device *dev) -{ - return 0; -} - -static int __maybe_unused vpu_runtime_suspend(struct device *dev) -{ - return 0; -} - -static int __maybe_unused vpu_resume(struct device *dev) -{ - return 0; -} - -static int __maybe_unused vpu_suspend(struct device *dev) -{ - return 0; -} - -static const struct dev_pm_ops vpu_pm_ops = { - SET_RUNTIME_PM_OPS(vpu_runtime_suspend, vpu_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(vpu_suspend, vpu_resume) -}; - static struct vpu_resources imx8qxp_res = { .plat_type = IMX8QXP, .mreg_base = 0x40000000, @@ -231,7 +206,6 @@ static struct platform_driver amphion_vpu_driver = { .driver = { .name = "amphion-vpu", .of_match_table = vpu_dt_match, - .pm = &vpu_pm_ops, }, }; diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c index ba688566dffd..80802975c4f1 100644 --- a/drivers/media/platform/amphion/vpu_malone.c +++ b/drivers/media/platform/amphion/vpu_malone.c @@ -1337,22 +1337,18 @@ static int vpu_malone_insert_scode_vc1_g_seq(struct malone_scode_t *scode) { if (!scode->inst->total_input_count) return 0; - if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) - scode->need_data = 0; return 0; } static int vpu_malone_insert_scode_vc1_g_pic(struct malone_scode_t *scode) { - struct vb2_v4l2_buffer *vbuf; u8 nal_hdr[MALONE_VC1_NAL_HEADER_LEN]; u32 *data = NULL; int ret; - vbuf = to_vb2_v4l2_buffer(scode->vb); data = vb2_plane_vaddr(scode->vb, 0); - if (scode->inst->total_input_count == 0 || vpu_vb_is_codecconfig(vbuf)) + if (scode->inst->total_input_count == 0) return 0; if (MALONE_VC1_CONTAIN_NAL(*data)) return 0; @@ -1373,8 +1369,6 @@ static int vpu_malone_insert_scode_vc1_l_seq(struct malone_scode_t *scode) int size = 0; u8 rcv_seqhdr[MALONE_VC1_RCV_SEQ_HEADER_LEN]; - if (vpu_vb_is_codecconfig(to_vb2_v4l2_buffer(scode->vb))) - scode->need_data = 0; if (scode->inst->total_input_count) return 0; scode->need_data = 0; @@ -1560,7 +1554,7 @@ static int vpu_malone_input_frame_data(struct vpu_malone_str_buffer __iomem *str scode.vb = vb; scode.wptr = wptr; scode.need_data = 1; - if (vbuf->sequence == 0 || vpu_vb_is_codecconfig(vbuf)) + if (vbuf->sequence == 0) ret = vpu_malone_insert_scode(&scode, SCODE_SEQUENCE); if (ret < 0) @@ -1596,7 +1590,7 @@ static int vpu_malone_input_frame_data(struct vpu_malone_str_buffer __iomem *str * This module is currently only supported for the H264 and HEVC formats, * for other formats, vpu_malone_add_scode() will return 0. */ - if ((disp_imm || low_latency) && !vpu_vb_is_codecconfig(vbuf)) { + if (disp_imm || low_latency) { ret = vpu_malone_add_scode(inst->core->iface, inst->id, &inst->stream_buffer, @@ -1643,7 +1637,6 @@ int vpu_malone_input_frame(struct vpu_shared_addr *shared, struct vpu_inst *inst, struct vb2_buffer *vb) { struct vpu_dec_ctrl *hc = shared->priv; - struct vb2_v4l2_buffer *vbuf; struct vpu_malone_str_buffer __iomem *str_buf = hc->str_buf[inst->id]; u32 disp_imm = hc->codec_param[inst->id].disp_imm; u32 size; @@ -1657,16 +1650,6 @@ int vpu_malone_input_frame(struct vpu_shared_addr *shared, return ret; size = ret; - /* - * if buffer only contain codec data, and the timestamp is invalid, - * don't put the invalid timestamp to resync - * merge the data to next frame - */ - vbuf = to_vb2_v4l2_buffer(vb); - if (vpu_vb_is_codecconfig(vbuf)) { - inst->extra_size += size; - return 0; - } if (inst->extra_size) { size += inst->extra_size; inst->extra_size = 0; diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 74668fa362e2..47dff9a35bb4 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -24,6 +24,11 @@ #include "vpu_msgs.h" #include "vpu_helpers.h" +static char *vpu_type_name(u32 type) +{ + return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; +} + void vpu_inst_lock(struct vpu_inst *inst) { mutex_lock(&inst->lock); @@ -42,7 +47,7 @@ dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no) vb->planes[plane_no].data_offset; } -unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) +static unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no) { if (plane_no >= vb->num_planes) return 0; @@ -81,7 +86,7 @@ void vpu_v4l2_set_error(struct vpu_inst *inst) vpu_inst_unlock(inst); } -int vpu_notify_eos(struct vpu_inst *inst) +static int vpu_notify_eos(struct vpu_inst *inst) { static const struct v4l2_event ev = { .id = 0, @@ -344,16 +349,6 @@ struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst) if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) return NULL; - while (vpu_vb_is_codecconfig(src_buf)) { - v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); - vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); - v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - - src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx); - if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) - return NULL; - } - return src_buf; } @@ -573,7 +568,8 @@ static void vpu_vb2_buf_finish(struct vb2_buffer *vb) call_void_vop(inst, on_queue_empty, q->type); } -void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state) +static void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, + enum vb2_buffer_state state) { struct vb2_v4l2_buffer *buf; @@ -707,19 +703,17 @@ static int vpu_v4l2_release(struct vpu_inst *inst) { vpu_trace(inst->vpu->dev, "%p\n", inst); - vpu_release_core(inst->core); - put_device(inst->dev); - if (inst->workqueue) { cancel_work_sync(&inst->msg_work); destroy_workqueue(inst->workqueue); inst->workqueue = NULL; } + vpu_release_core(inst->core); + put_device(inst->dev); + v4l2_ctrl_handler_free(&inst->ctrl_handler); mutex_destroy(&inst->lock); - v4l2_fh_del(&inst->fh); - v4l2_fh_exit(&inst->fh); call_void_vop(inst, cleanup); @@ -756,7 +750,7 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst) inst->min_buffer_cap = 2; inst->min_buffer_out = 2; v4l2_fh_init(&inst->fh, func->vfd); - v4l2_fh_add(&inst->fh); + v4l2_fh_add(&inst->fh, file); ret = call_vop(inst, ctrl_init); if (ret) @@ -770,7 +764,6 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst) } inst->fh.ctrl_handler = &inst->ctrl_handler; - file->private_data = &inst->fh; inst->state = VPU_CODEC_STATE_DEINIT; inst->workqueue = alloc_ordered_workqueue("vpu_inst", WQ_MEM_RECLAIM); if (inst->workqueue) { @@ -788,6 +781,8 @@ int vpu_v4l2_open(struct file *file, struct vpu_inst *inst) return 0; error: + v4l2_fh_del(&inst->fh, file); + v4l2_fh_exit(&inst->fh); vpu_inst_put(inst); return ret; } @@ -807,6 +802,9 @@ int vpu_v4l2_close(struct file *file) call_void_vop(inst, release); vpu_inst_unlock(inst); + v4l2_fh_del(&inst->fh, file); + v4l2_fh_exit(&inst->fh); + vpu_inst_unregister(inst); vpu_inst_put(inst); diff --git a/drivers/media/platform/amphion/vpu_v4l2.h b/drivers/media/platform/amphion/vpu_v4l2.h index 56f2939fa84d..da9945f25e32 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.h +++ b/drivers/media/platform/amphion/vpu_v4l2.h @@ -26,15 +26,12 @@ void vpu_skip_frame(struct vpu_inst *inst, int count); struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence); struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx); void vpu_v4l2_set_error(struct vpu_inst *inst); -int vpu_notify_eos(struct vpu_inst *inst); int vpu_notify_source_change(struct vpu_inst *inst); int vpu_set_last_buffer_dequeued(struct vpu_inst *inst, bool eos); -void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state); int vpu_get_num_buffers(struct vpu_inst *inst, u32 type); bool vpu_is_source_empty(struct vpu_inst *inst); dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no); -unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no); static inline struct vpu_format *vpu_get_format(struct vpu_inst *inst, u32 type) { if (V4L2_TYPE_IS_OUTPUT(type)) @@ -42,19 +39,4 @@ static inline struct vpu_format *vpu_get_format(struct vpu_inst *inst, u32 type) else return &inst->cap_format; } - -static inline char *vpu_type_name(u32 type) -{ - return V4L2_TYPE_IS_OUTPUT(type) ? "output" : "capture"; -} - -static inline int vpu_vb_is_codecconfig(struct vb2_v4l2_buffer *vbuf) -{ -#ifdef V4L2_BUF_FLAG_CODECCONFIG - return (vbuf->flags & V4L2_BUF_FLAG_CODECCONFIG) ? 1 : 0; -#else - return 0; -#endif -} - #endif diff --git a/drivers/media/platform/arm/Kconfig b/drivers/media/platform/arm/Kconfig new file mode 100644 index 000000000000..4f0764c329c7 --- /dev/null +++ b/drivers/media/platform/arm/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +comment "ARM media platform drivers" + +source "drivers/media/platform/arm/mali-c55/Kconfig" diff --git a/drivers/media/platform/arm/Makefile b/drivers/media/platform/arm/Makefile new file mode 100644 index 000000000000..8cc4918725ef --- /dev/null +++ b/drivers/media/platform/arm/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += mali-c55/ diff --git a/drivers/media/platform/arm/mali-c55/Kconfig b/drivers/media/platform/arm/mali-c55/Kconfig new file mode 100644 index 000000000000..5b084b3c3340 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_MALI_C55 + tristate "ARM Mali-C55 Image Signal Processor driver" + depends on ARCH_VEXPRESS || ARCH_RENESAS || COMPILE_TEST + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV && OF + select GENERIC_PHY_MIPI_DPHY + select MEDIA_CONTROLLER + select V4L2_FWNODE + select V4L2_ISP + select VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_VMALLOC + help + Enable this to support Arm's Mali-C55 Image Signal Processor. + + To compile this driver as a module, choose M here: the module + will be called mali-c55. diff --git a/drivers/media/platform/arm/mali-c55/Makefile b/drivers/media/platform/arm/mali-c55/Makefile new file mode 100644 index 000000000000..d5718b0b23e0 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 + +mali-c55-y := mali-c55-capture.o \ + mali-c55-core.o \ + mali-c55-isp.o \ + mali-c55-params.o \ + mali-c55-resizer.o \ + mali-c55-stats.o \ + mali-c55-tpg.o + +obj-$(CONFIG_VIDEO_MALI_C55) += mali-c55.o diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-capture.c b/drivers/media/platform/arm/mali-c55/mali-c55-capture.c new file mode 100644 index 000000000000..7aaa5c3f7354 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/mali-c55-capture.c @@ -0,0 +1,959 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM Mali-C55 ISP Driver - Video capture devices + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include <linux/cleanup.h> +#include <linux/minmax.h> +#include <linux/lockdep.h> +#include <linux/pm_runtime.h> +#include <linux/string.h> +#include <linux/videodev2.h> + +#include <media/v4l2-dev.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "mali-c55-common.h" +#include "mali-c55-registers.h" + +static const struct mali_c55_format_info mali_c55_fmts[] = { + /* + * This table is missing some entries which need further work or + * investigation: + * + * Base mode 5 is "Generic Data" + * Base mode 8 is a backwards V4L2_PIX_FMT_XYUV32 - no V4L2 equivalent + * Base mode 9 seems to have no V4L2 equivalent + * Base mode 17, 19 and 20 describe formats which seem to have no V4L2 + * equivalent + */ + { + .fourcc = V4L2_PIX_FMT_XBGR32, + .mbus_codes = { + MEDIA_BUS_FMT_RGB121212_1X36, + MEDIA_BUS_FMT_RGB202020_1X60, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_RGB32, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_ARGB2101010, + .mbus_codes = { + MEDIA_BUS_FMT_RGB121212_1X36, + MEDIA_BUS_FMT_RGB202020_1X60, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_A2R10G10B10, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .mbus_codes = { + MEDIA_BUS_FMT_RGB121212_1X36, + MEDIA_BUS_FMT_RGB202020_1X60, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_RGB565, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_BGR24, + .mbus_codes = { + MEDIA_BUS_FMT_RGB121212_1X36, + MEDIA_BUS_FMT_RGB202020_1X60, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_RGB24, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_codes = { + MEDIA_BUS_FMT_YUV10_1X30, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_YUY2, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .mbus_codes = { + MEDIA_BUS_FMT_YUV10_1X30, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_UYVY, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_Y210, + .mbus_codes = { + MEDIA_BUS_FMT_YUV10_1X30, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_Y210, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + /* + * This is something of a hack, the ISP thinks it's running NV12M but + * by setting uv_plane = 0 we simply discard that planes and only output + * the Y-plane. + */ + { + .fourcc = V4L2_PIX_FMT_GREY, + .mbus_codes = { + MEDIA_BUS_FMT_YUV10_1X30, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_NV12_21, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .mbus_codes = { + MEDIA_BUS_FMT_YUV10_1X30, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_NV12_21, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT1 + } + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .mbus_codes = { + MEDIA_BUS_FMT_YUV10_1X30, + }, + .is_raw = false, + .registers = { + .base_mode = MALI_C55_OUTPUT_NV12_21, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT2 + } + }, + /* + * RAW uncompressed formats are all packed in 16 bpp. + * TODO: Expand this list to encompass all possible RAW formats. + */ + { + .fourcc = V4L2_PIX_FMT_SRGGB16, + .mbus_codes = { + MEDIA_BUS_FMT_SRGGB16_1X16, + }, + .is_raw = true, + .registers = { + .base_mode = MALI_C55_OUTPUT_RAW16, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .mbus_codes = { + MEDIA_BUS_FMT_SBGGR16_1X16, + }, + .is_raw = true, + .registers = { + .base_mode = MALI_C55_OUTPUT_RAW16, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .mbus_codes = { + MEDIA_BUS_FMT_SGBRG16_1X16, + }, + .is_raw = true, + .registers = { + .base_mode = MALI_C55_OUTPUT_RAW16, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .mbus_codes = { + MEDIA_BUS_FMT_SGRBG16_1X16, + }, + .is_raw = true, + .registers = { + .base_mode = MALI_C55_OUTPUT_RAW16, + .uv_plane = MALI_C55_OUTPUT_PLANE_ALT0 + } + }, +}; + +void mali_c55_cap_dev_write(struct mali_c55_cap_dev *cap_dev, unsigned int addr, + u32 val) +{ + mali_c55_ctx_write(cap_dev->mali_c55, addr + cap_dev->reg_offset, val); +} + +static u32 mali_c55_cap_dev_read(struct mali_c55_cap_dev *cap_dev, unsigned int addr) +{ + return mali_c55_ctx_read(cap_dev->mali_c55, addr + cap_dev->reg_offset); +} + +static void mali_c55_cap_dev_update_bits(struct mali_c55_cap_dev *cap_dev, + unsigned int addr, u32 mask, u32 val) +{ + u32 orig, tmp; + + orig = mali_c55_cap_dev_read(cap_dev, addr); + + tmp = orig & ~mask; + tmp |= val & mask; + + if (tmp != orig) + mali_c55_cap_dev_write(cap_dev, addr, tmp); +} + +static bool +mali_c55_mbus_code_can_produce_fmt(const struct mali_c55_format_info *fmt, + u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(fmt->mbus_codes); i++) { + if (fmt->mbus_codes[i] == code) + return true; + } + + return false; +} + +bool mali_c55_format_is_raw(unsigned int mbus_code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mali_c55_fmts); i++) { + if (mali_c55_fmts[i].mbus_codes[0] == mbus_code) + return mali_c55_fmts[i].is_raw; + } + + return false; +} + +static const struct mali_c55_format_info * +mali_c55_format_from_pix(const u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mali_c55_fmts); i++) { + if (mali_c55_fmts[i].fourcc == pixelformat) + return &mali_c55_fmts[i]; + } + + /* + * If we find no matching pixelformat, we'll just default to the first + * one for now. + */ + + return &mali_c55_fmts[0]; +} + +static const char * const capture_device_names[] = { + "mali-c55 fr", + "mali-c55 ds", +}; + +static int mali_c55_link_validate(struct media_link *link) +{ + struct video_device *vdev = + media_entity_to_video_device(link->sink->entity); + struct mali_c55_cap_dev *cap_dev = video_get_drvdata(vdev); + struct v4l2_subdev *sd = + media_entity_to_v4l2_subdev(link->source->entity); + const struct v4l2_pix_format_mplane *pix_mp; + const struct mali_c55_format_info *cap_fmt; + struct v4l2_subdev_format sd_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .pad = link->source->index, + }; + int ret; + + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); + if (ret) + return ret; + + pix_mp = &cap_dev->format.format; + cap_fmt = cap_dev->format.info; + + if (sd_fmt.format.width != pix_mp->width || + sd_fmt.format.height != pix_mp->height) { + dev_dbg(cap_dev->mali_c55->dev, + "link '%s':%u -> '%s':%u not valid: %ux%u != %ux%u\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index, + sd_fmt.format.width, sd_fmt.format.height, + pix_mp->width, pix_mp->height); + return -EPIPE; + } + + if (!mali_c55_mbus_code_can_produce_fmt(cap_fmt, sd_fmt.format.code)) { + dev_dbg(cap_dev->mali_c55->dev, + "link '%s':%u -> '%s':%u not valid: mbus_code 0x%04x cannot produce pixel format %p4cc\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index, + sd_fmt.format.code, &pix_mp->pixelformat); + return -EPIPE; + } + + return 0; +} + +static const struct media_entity_operations mali_c55_media_ops = { + .link_validate = mali_c55_link_validate, +}; + +static int mali_c55_vb2_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct mali_c55_cap_dev *cap_dev = q->drv_priv; + unsigned int i; + + if (*num_planes) { + if (*num_planes != cap_dev->format.format.num_planes) + return -EINVAL; + + for (i = 0; i < cap_dev->format.format.num_planes; i++) + if (sizes[i] < cap_dev->format.format.plane_fmt[i].sizeimage) + return -EINVAL; + } else { + *num_planes = cap_dev->format.format.num_planes; + for (i = 0; i < cap_dev->format.format.num_planes; i++) + sizes[i] = cap_dev->format.format.plane_fmt[i].sizeimage; + } + + return 0; +} + +static void mali_c55_buf_queue(struct vb2_buffer *vb) +{ + struct mali_c55_cap_dev *cap_dev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mali_c55_buffer *buf = container_of(vbuf, + struct mali_c55_buffer, vb); + unsigned int i; + + buf->planes_pending = cap_dev->format.format.num_planes; + + for (i = 0; i < cap_dev->format.format.num_planes; i++) { + unsigned long size = cap_dev->format.format.plane_fmt[i].sizeimage; + + vb2_set_plane_payload(vb, i, size); + } + + buf->vb.field = V4L2_FIELD_NONE; + + guard(spinlock)(&cap_dev->buffers.lock); + list_add_tail(&buf->queue, &cap_dev->buffers.input); +} + +static int mali_c55_buf_init(struct vb2_buffer *vb) +{ + struct mali_c55_cap_dev *cap_dev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mali_c55_buffer *buf = container_of(vbuf, + struct mali_c55_buffer, vb); + unsigned int i; + + for (i = 0; i < cap_dev->format.format.num_planes; i++) + buf->addrs[i] = vb2_dma_contig_plane_dma_addr(vb, i); + + return 0; +} + +void mali_c55_set_next_buffer(struct mali_c55_cap_dev *cap_dev) +{ + struct v4l2_pix_format_mplane *pix_mp; + struct mali_c55_buffer *buf; + dma_addr_t *addrs; + + scoped_guard(spinlock, &cap_dev->buffers.lock) { + buf = list_first_entry_or_null(&cap_dev->buffers.input, + struct mali_c55_buffer, queue); + if (buf) + list_del(&buf->queue); + } + + if (!buf) { + /* + * If we underflow then we can tell the ISP that we don't want + * to write out the next frame. + */ + mali_c55_cap_dev_update_bits(cap_dev, + MALI_C55_REG_Y_WRITER_MODE, + MALI_C55_WRITER_FRAME_WRITE_MASK, + 0x00); + mali_c55_cap_dev_update_bits(cap_dev, + MALI_C55_REG_UV_WRITER_MODE, + MALI_C55_WRITER_FRAME_WRITE_MASK, + 0x00); + return; + } + + pix_mp = &cap_dev->format.format; + + mali_c55_cap_dev_update_bits(cap_dev, MALI_C55_REG_Y_WRITER_MODE, + MALI_C55_WRITER_FRAME_WRITE_MASK, + MALI_C55_WRITER_FRAME_WRITE_ENABLE); + if (cap_dev->format.info->registers.uv_plane) + mali_c55_cap_dev_update_bits(cap_dev, + MALI_C55_REG_UV_WRITER_MODE, + MALI_C55_WRITER_FRAME_WRITE_MASK, + MALI_C55_WRITER_FRAME_WRITE_ENABLE); + + addrs = buf->addrs; + mali_c55_cap_dev_write(cap_dev, + MALI_C55_REG_Y_WRITER_BANKS_BASE, + addrs[MALI_C55_PLANE_Y]); + mali_c55_cap_dev_write(cap_dev, + MALI_C55_REG_UV_WRITER_BANKS_BASE, + addrs[MALI_C55_PLANE_UV]); + + mali_c55_cap_dev_write(cap_dev, + MALI_C55_REG_Y_WRITER_OFFSET, + pix_mp->plane_fmt[MALI_C55_PLANE_Y].bytesperline); + mali_c55_cap_dev_write(cap_dev, + MALI_C55_REG_UV_WRITER_OFFSET, + pix_mp->plane_fmt[MALI_C55_PLANE_UV].bytesperline); + + guard(spinlock)(&cap_dev->buffers.processing_lock); + list_add_tail(&buf->queue, &cap_dev->buffers.processing); +} + +/** + * mali_c55_set_plane_done - mark the plane as written and process the buffer if + * both planes are finished. + * @cap_dev: pointer to the fr or ds pipe output + * @plane: the plane to mark as completed + * + * The Mali C55 ISP has muliplanar outputs for some formats that come with two + * separate "buffer write completed" interrupts - we need to flag each plane's + * completion and check whether both planes are done - if so, complete the buf + * in vb2. + */ +void mali_c55_set_plane_done(struct mali_c55_cap_dev *cap_dev, + enum mali_c55_planes plane) +{ + struct mali_c55_isp *isp = &cap_dev->mali_c55->isp; + struct mali_c55_buffer *buf; + + scoped_guard(spinlock, &cap_dev->buffers.processing_lock) { + buf = list_first_entry_or_null(&cap_dev->buffers.processing, + struct mali_c55_buffer, queue); + + /* + * If the stream was stopped, the buffer might have been sent + * back to userspace already. + */ + if (!buf || --buf->planes_pending) + return; + + list_del(&buf->queue); + } + + /* If the other plane is also done... */ + buf->vb.vb2_buf.timestamp = ktime_get_boottime_ns(); + buf->vb.sequence = isp->frame_sequence++; + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); +} + +static void mali_c55_cap_dev_stream_disable(struct mali_c55_cap_dev *cap_dev) +{ + mali_c55_cap_dev_update_bits(cap_dev, MALI_C55_REG_Y_WRITER_MODE, + MALI_C55_WRITER_FRAME_WRITE_MASK, 0x00); + mali_c55_cap_dev_update_bits(cap_dev, MALI_C55_REG_UV_WRITER_MODE, + MALI_C55_WRITER_FRAME_WRITE_MASK, 0x00); +} + +static void mali_c55_cap_dev_stream_enable(struct mali_c55_cap_dev *cap_dev) +{ + /* + * The Mali ISP can hold up to 5 buffer addresses and simply cycle + * through them, but it's not clear to me that the vb2 queue _guarantees_ + * it will queue buffers to the driver in a fixed order, and ensuring + * we call vb2_buffer_done() for the right buffer seems to me to add + * pointless complexity given in multi-context mode we'd need to + * re-write those registers every frame anyway...so we tell the ISP to + * use a single register and update it for each frame. + */ + mali_c55_cap_dev_update_bits(cap_dev, + MALI_C55_REG_Y_WRITER_BANKS_CONFIG, + MALI_C55_REG_Y_WRITER_MAX_BANKS_MASK, 0); + mali_c55_cap_dev_update_bits(cap_dev, + MALI_C55_REG_UV_WRITER_BANKS_CONFIG, + MALI_C55_REG_UV_WRITER_MAX_BANKS_MASK, 0); + + mali_c55_set_next_buffer(cap_dev); +} + +static void mali_c55_cap_dev_return_buffers(struct mali_c55_cap_dev *cap_dev, + enum vb2_buffer_state state) +{ + struct mali_c55_buffer *buf, *tmp; + + scoped_guard(spinlock, &cap_dev->buffers.lock) { + list_for_each_entry_safe(buf, tmp, &cap_dev->buffers.input, + queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } + } + + guard(spinlock)(&cap_dev->buffers.processing_lock); + list_for_each_entry_safe(buf, tmp, &cap_dev->buffers.processing, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } +} + +static void mali_c55_cap_dev_format_configure(struct mali_c55_cap_dev *cap_dev) +{ + const struct mali_c55_format_info *capture_format = cap_dev->format.info; + const struct v4l2_pix_format_mplane *pix_mp = &cap_dev->format.format; + const struct v4l2_format_info *info; + + info = v4l2_format_info(pix_mp->pixelformat); + if (WARN_ON(!info)) + return; + + mali_c55_cap_dev_write(cap_dev, MALI_C55_REG_Y_WRITER_MODE, + capture_format->registers.base_mode); + mali_c55_cap_dev_write(cap_dev, MALI_C55_REG_ACTIVE_OUT_Y_SIZE, + MALI_C55_REG_ACTIVE_OUT_SIZE_W(pix_mp->width) | + MALI_C55_REG_ACTIVE_OUT_SIZE_H(pix_mp->height)); + + if (info->mem_planes > 1) { + mali_c55_cap_dev_write(cap_dev, MALI_C55_REG_UV_WRITER_MODE, + capture_format->registers.base_mode); + mali_c55_cap_dev_update_bits(cap_dev, + MALI_C55_REG_UV_WRITER_MODE, + MALI_C55_WRITER_SUBMODE_MASK, + MALI_C55_WRITER_SUBMODE(capture_format->registers.uv_plane)); + + mali_c55_cap_dev_write(cap_dev, MALI_C55_REG_ACTIVE_OUT_UV_SIZE, + MALI_C55_REG_ACTIVE_OUT_SIZE_W(pix_mp->width) | + MALI_C55_REG_ACTIVE_OUT_SIZE_H(pix_mp->height)); + } + + if (info->pixel_enc == V4L2_PIXEL_ENC_YUV) { + mali_c55_cap_dev_write(cap_dev, MALI_C55_REG_CS_CONV_CONFIG, + MALI_C55_CS_CONV_MATRIX_MASK); + + if (info->hdiv > 1) + mali_c55_cap_dev_update_bits(cap_dev, + MALI_C55_REG_CS_CONV_CONFIG, + MALI_C55_CS_CONV_HORZ_DOWNSAMPLE_MASK, + MALI_C55_CS_CONV_HORZ_DOWNSAMPLE_ENABLE); + if (info->vdiv > 1) + mali_c55_cap_dev_update_bits(cap_dev, + MALI_C55_REG_CS_CONV_CONFIG, + MALI_C55_CS_CONV_VERT_DOWNSAMPLE_MASK, + MALI_C55_CS_CONV_VERT_DOWNSAMPLE_ENABLE); + if (info->hdiv > 1 || info->vdiv > 1) + mali_c55_cap_dev_update_bits(cap_dev, + MALI_C55_REG_CS_CONV_CONFIG, + MALI_C55_CS_CONV_FILTER_MASK, + MALI_C55_CS_CONV_FILTER_ENABLE); + } +} + +static int mali_c55_vb2_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct mali_c55_cap_dev *cap_dev = q->drv_priv; + struct mali_c55 *mali_c55 = cap_dev->mali_c55; + struct mali_c55_resizer *rsz = cap_dev->rsz; + struct mali_c55_isp *isp = &mali_c55->isp; + int ret; + + guard(mutex)(&isp->capture_lock); + + ret = pm_runtime_resume_and_get(mali_c55->dev); + if (ret) + goto err_return_buffers; + + ret = video_device_pipeline_alloc_start(&cap_dev->vdev); + if (ret) { + dev_dbg(mali_c55->dev, "%s failed to start media pipeline\n", + cap_dev->vdev.name); + goto err_pm_put; + } + + mali_c55_cap_dev_format_configure(cap_dev); + mali_c55_cap_dev_stream_enable(cap_dev); + + ret = v4l2_subdev_enable_streams(&rsz->sd, MALI_C55_RSZ_SOURCE_PAD, + BIT(0)); + if (ret) + goto err_disable_cap_dev; + + if (mali_c55_pipeline_ready(mali_c55)) { + ret = v4l2_subdev_enable_streams(&mali_c55->isp.sd, + MALI_C55_ISP_PAD_SOURCE_VIDEO, + BIT(0)); + if (ret < 0) + goto err_disable_rsz; + } + + return 0; + +err_disable_rsz: + v4l2_subdev_disable_streams(&rsz->sd, MALI_C55_RSZ_SOURCE_PAD, BIT(0)); +err_disable_cap_dev: + mali_c55_cap_dev_stream_disable(cap_dev); + video_device_pipeline_stop(&cap_dev->vdev); +err_pm_put: + pm_runtime_put_autosuspend(mali_c55->dev); +err_return_buffers: + mali_c55_cap_dev_return_buffers(cap_dev, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void mali_c55_vb2_stop_streaming(struct vb2_queue *q) +{ + struct mali_c55_cap_dev *cap_dev = q->drv_priv; + struct mali_c55 *mali_c55 = cap_dev->mali_c55; + struct mali_c55_resizer *rsz = cap_dev->rsz; + struct mali_c55_isp *isp = &mali_c55->isp; + + guard(mutex)(&isp->capture_lock); + + if (mali_c55_pipeline_ready(mali_c55)) { + if (v4l2_subdev_is_streaming(&isp->sd)) + v4l2_subdev_disable_streams(&isp->sd, + MALI_C55_ISP_PAD_SOURCE_VIDEO, + BIT(0)); + } + + v4l2_subdev_disable_streams(&rsz->sd, MALI_C55_RSZ_SOURCE_PAD, BIT(0)); + mali_c55_cap_dev_stream_disable(cap_dev); + mali_c55_cap_dev_return_buffers(cap_dev, VB2_BUF_STATE_ERROR); + video_device_pipeline_stop(&cap_dev->vdev); + pm_runtime_put_autosuspend(mali_c55->dev); +} + +static const struct vb2_ops mali_c55_vb2_ops = { + .queue_setup = &mali_c55_vb2_queue_setup, + .buf_queue = &mali_c55_buf_queue, + .buf_init = &mali_c55_buf_init, + .start_streaming = &mali_c55_vb2_start_streaming, + .stop_streaming = &mali_c55_vb2_stop_streaming, +}; + +static const struct v4l2_file_operations mali_c55_v4l2_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +static void mali_c55_try_fmt(struct v4l2_pix_format_mplane *pix_mp) +{ + const struct mali_c55_format_info *capture_format; + const struct v4l2_format_info *info; + struct v4l2_plane_pix_format *plane, *y_plane; + unsigned int padding; + unsigned int i; + + capture_format = mali_c55_format_from_pix(pix_mp->pixelformat); + pix_mp->pixelformat = capture_format->fourcc; + + pix_mp->width = clamp(pix_mp->width, MALI_C55_MIN_WIDTH, + MALI_C55_MAX_WIDTH); + pix_mp->height = clamp(pix_mp->height, MALI_C55_MIN_HEIGHT, + MALI_C55_MAX_HEIGHT); + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->colorspace = V4L2_COLORSPACE_DEFAULT; + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT; + + info = v4l2_format_info(pix_mp->pixelformat); + pix_mp->num_planes = info->mem_planes; + memset(pix_mp->plane_fmt, 0, sizeof(pix_mp->plane_fmt)); + + y_plane = &pix_mp->plane_fmt[0]; + y_plane->bytesperline = clamp(y_plane->bytesperline, + info->bpp[0] * pix_mp->width, 65535U); + + /* + * The ISP requires that the stride be aligned to 16-bytes. This is not + * detailed in the documentation but has been verified experimentally. + */ + y_plane->bytesperline = ALIGN(y_plane->bytesperline, 16); + y_plane->sizeimage = y_plane->bytesperline * pix_mp->height; + + padding = y_plane->bytesperline - (pix_mp->width * info->bpp[0]); + + for (i = 1; i < info->comp_planes; i++) { + plane = &pix_mp->plane_fmt[i]; + + plane->bytesperline = DIV_ROUND_UP(info->bpp[i] * pix_mp->width, + info->hdiv) + padding; + plane->sizeimage = DIV_ROUND_UP(plane->bytesperline * + pix_mp->height, info->vdiv); + } + + if (info->mem_planes == 1) { + for (i = 1; i < info->comp_planes; i++) { + plane = &pix_mp->plane_fmt[i]; + y_plane->sizeimage += plane->sizeimage; + } + } +} + +static int mali_c55_try_fmt_vid_cap_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + mali_c55_try_fmt(&f->fmt.pix_mp); + + return 0; +} + +static void mali_c55_set_format(struct mali_c55_cap_dev *cap_dev, + struct v4l2_pix_format_mplane *pix_mp) +{ + mali_c55_try_fmt(pix_mp); + + cap_dev->format.format = *pix_mp; + cap_dev->format.info = mali_c55_format_from_pix(pix_mp->pixelformat); +} + +static int mali_c55_s_fmt_vid_cap_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mali_c55_cap_dev *cap_dev = video_drvdata(file); + + if (vb2_is_busy(&cap_dev->queue)) + return -EBUSY; + + mali_c55_set_format(cap_dev, &f->fmt.pix_mp); + + return 0; +} + +static int mali_c55_g_fmt_vid_cap_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mali_c55_cap_dev *cap_dev = video_drvdata(file); + + f->fmt.pix_mp = cap_dev->format.format; + + return 0; +} + +static int mali_c55_enum_fmt_vid_cap_mplane(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + struct mali_c55_cap_dev *cap_dev = video_drvdata(file); + unsigned int j = 0; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mali_c55_fmts); i++) { + if (f->mbus_code && + !mali_c55_mbus_code_can_produce_fmt(&mali_c55_fmts[i], + f->mbus_code)) + continue; + + /* Downscale pipe can't output RAW formats */ + if (mali_c55_fmts[i].is_raw && + cap_dev->reg_offset == MALI_C55_CAP_DEV_DS_REG_OFFSET) + continue; + + if (j++ == f->index) { + f->pixelformat = mali_c55_fmts[i].fourcc; + return 0; + } + } + + return -EINVAL; +} + +static int mali_c55_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, MALI_C55_DRIVER_NAME, sizeof(cap->driver)); + strscpy(cap->card, "ARM Mali-C55 ISP", sizeof(cap->card)); + + return 0; +} + +static const struct v4l2_ioctl_ops mali_c55_v4l2_ioctl_ops = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_try_fmt_vid_cap_mplane = mali_c55_try_fmt_vid_cap_mplane, + .vidioc_s_fmt_vid_cap_mplane = mali_c55_s_fmt_vid_cap_mplane, + .vidioc_g_fmt_vid_cap_mplane = mali_c55_g_fmt_vid_cap_mplane, + .vidioc_enum_fmt_vid_cap = mali_c55_enum_fmt_vid_cap_mplane, + .vidioc_querycap = mali_c55_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int mali_c55_register_cap_dev(struct mali_c55 *mali_c55, + enum mali_c55_cap_devs cap_dev_id) +{ + struct mali_c55_cap_dev *cap_dev = &mali_c55->cap_devs[cap_dev_id]; + struct v4l2_pix_format_mplane pix_mp; + struct video_device *vdev; + struct vb2_queue *vb2q; + int ret; + + vdev = &cap_dev->vdev; + vb2q = &cap_dev->queue; + + cap_dev->mali_c55 = mali_c55; + mutex_init(&cap_dev->lock); + INIT_LIST_HEAD(&cap_dev->buffers.input); + INIT_LIST_HEAD(&cap_dev->buffers.processing); + spin_lock_init(&cap_dev->buffers.lock); + spin_lock_init(&cap_dev->buffers.processing_lock); + + switch (cap_dev_id) { + case MALI_C55_CAP_DEV_FR: + cap_dev->rsz = &mali_c55->resizers[MALI_C55_RSZ_FR]; + cap_dev->reg_offset = MALI_C55_CAP_DEV_FR_REG_OFFSET; + break; + case MALI_C55_CAP_DEV_DS: + cap_dev->rsz = &mali_c55->resizers[MALI_C55_RSZ_DS]; + cap_dev->reg_offset = MALI_C55_CAP_DEV_DS_REG_OFFSET; + break; + default: + ret = -EINVAL; + goto err_destroy_mutex; + } + + cap_dev->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&cap_dev->vdev.entity, 1, &cap_dev->pad); + if (ret) { + mutex_destroy(&cap_dev->lock); + goto err_destroy_mutex; + } + + vb2q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + vb2q->io_modes = VB2_MMAP | VB2_DMABUF; + vb2q->drv_priv = cap_dev; + vb2q->mem_ops = &vb2_dma_contig_memops; + vb2q->ops = &mali_c55_vb2_ops; + vb2q->buf_struct_size = sizeof(struct mali_c55_buffer); + vb2q->min_queued_buffers = 1; + vb2q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vb2q->lock = &cap_dev->lock; + vb2q->dev = mali_c55->dev; + + ret = vb2_queue_init(vb2q); + if (ret) { + dev_err(mali_c55->dev, "%s vb2 queue init failed\n", + cap_dev->vdev.name); + goto err_cleanup_media_entity; + } + + strscpy(cap_dev->vdev.name, capture_device_names[cap_dev_id], + sizeof(cap_dev->vdev.name)); + vdev->release = video_device_release_empty; + vdev->fops = &mali_c55_v4l2_fops; + vdev->ioctl_ops = &mali_c55_v4l2_ioctl_ops; + vdev->lock = &cap_dev->lock; + vdev->v4l2_dev = &mali_c55->v4l2_dev; + vdev->queue = &cap_dev->queue; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; + vdev->entity.ops = &mali_c55_media_ops; + video_set_drvdata(vdev, cap_dev); + + memset(&pix_mp, 0, sizeof(pix_mp)); + pix_mp.pixelformat = V4L2_PIX_FMT_RGB565; + pix_mp.width = MALI_C55_DEFAULT_WIDTH; + pix_mp.height = MALI_C55_DEFAULT_HEIGHT; + mali_c55_set_format(cap_dev, &pix_mp); + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(mali_c55->dev, + "%s failed to register video device\n", + cap_dev->vdev.name); + goto err_release_vb2q; + } + + return 0; + +err_release_vb2q: + vb2_queue_release(vb2q); +err_cleanup_media_entity: + media_entity_cleanup(&cap_dev->vdev.entity); +err_destroy_mutex: + mutex_destroy(&cap_dev->lock); + + return ret; +} + +int mali_c55_register_capture_devs(struct mali_c55 *mali_c55) +{ + int ret; + + ret = mali_c55_register_cap_dev(mali_c55, MALI_C55_CAP_DEV_FR); + if (ret) + return ret; + + if (mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) { + ret = mali_c55_register_cap_dev(mali_c55, MALI_C55_CAP_DEV_DS); + if (ret) { + mali_c55_unregister_capture_devs(mali_c55); + return ret; + } + } + + return 0; +} + +static void mali_c55_unregister_cap_dev(struct mali_c55 *mali_c55, + enum mali_c55_cap_devs cap_dev_id) +{ + struct mali_c55_cap_dev *cap_dev = &mali_c55->cap_devs[cap_dev_id]; + + if (!video_is_registered(&cap_dev->vdev)) + return; + + vb2_video_unregister_device(&cap_dev->vdev); + media_entity_cleanup(&cap_dev->vdev.entity); + mutex_destroy(&cap_dev->lock); +} + +void mali_c55_unregister_capture_devs(struct mali_c55 *mali_c55) +{ + mali_c55_unregister_cap_dev(mali_c55, MALI_C55_CAP_DEV_FR); + if (mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) + mali_c55_unregister_cap_dev(mali_c55, MALI_C55_CAP_DEV_DS); +} diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-common.h b/drivers/media/platform/arm/mali-c55/mali-c55-common.h new file mode 100644 index 000000000000..31c1deaca146 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/mali-c55-common.h @@ -0,0 +1,310 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ARM Mali-C55 ISP Driver - Common definitions + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#ifndef _MALI_C55_COMMON_H +#define _MALI_C55_COMMON_H + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/reset.h> +#include <linux/spinlock.h> +#include <linux/videodev2.h> + +#include <media/media-device.h> +#include <media/v4l2-async.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-isp.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-v4l2.h> + +#define MALI_C55_DRIVER_NAME "mali-c55" + +/* min and max values for the image sizes */ +#define MALI_C55_MIN_WIDTH 640U +#define MALI_C55_MIN_HEIGHT 480U +#define MALI_C55_MAX_WIDTH 8192U +#define MALI_C55_MAX_HEIGHT 8192U +#define MALI_C55_DEFAULT_WIDTH 1920U +#define MALI_C55_DEFAULT_HEIGHT 1080U + +#define MALI_C55_DEFAULT_MEDIA_BUS_FMT MEDIA_BUS_FMT_RGB121212_1X36 + +#define MALI_C55_NUM_CLKS 3 +#define MALI_C55_NUM_RESETS 3 + +struct device; +struct mali_c55; +struct mali_c55_cap_dev; +struct media_pipeline; +struct mali_c55_params_buffer; +struct platform_device; +struct resource; + +enum mali_c55_isp_pads { + MALI_C55_ISP_PAD_SINK_VIDEO, + MALI_C55_ISP_PAD_SOURCE_VIDEO, + MALI_C55_ISP_PAD_SOURCE_BYPASS, + MALI_C55_ISP_PAD_SOURCE_STATS, + MALI_C55_ISP_PAD_SINK_PARAMS, + MALI_C55_ISP_NUM_PADS, +}; + +struct mali_c55_tpg { + struct mali_c55 *mali_c55; + struct v4l2_subdev sd; + struct media_pad pad; + struct mali_c55_tpg_ctrls { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *vblank; + } ctrls; +}; + +struct mali_c55_isp { + struct mali_c55 *mali_c55; + struct v4l2_subdev sd; + struct media_pad pads[MALI_C55_ISP_NUM_PADS]; + struct v4l2_ctrl_handler handler; + struct media_pad *remote_src; + /* Mutex to guard vb2 start/stop streaming */ + struct mutex capture_lock; + unsigned int frame_sequence; +}; + +enum mali_c55_resizer_ids { + MALI_C55_RSZ_FR, + MALI_C55_RSZ_DS, + MALI_C55_NUM_RSZS, +}; + +enum mali_c55_rsz_pads { + MALI_C55_RSZ_SINK_PAD, + MALI_C55_RSZ_SOURCE_PAD, + MALI_C55_RSZ_SINK_BYPASS_PAD, + MALI_C55_RSZ_NUM_PADS +}; + +struct mali_c55_resizer { + struct mali_c55 *mali_c55; + struct mali_c55_cap_dev *cap_dev; + enum mali_c55_resizer_ids id; + struct v4l2_subdev sd; + struct media_pad pads[MALI_C55_RSZ_NUM_PADS]; + unsigned int num_routes; +}; + +enum mali_c55_cap_devs { + MALI_C55_CAP_DEV_FR, + MALI_C55_CAP_DEV_DS, + MALI_C55_NUM_CAP_DEVS +}; + +struct mali_c55_format_info { + u32 fourcc; + /* + * The output formats can be produced by a couple of different media bus + * formats, depending on how the ISP is configured. + */ + unsigned int mbus_codes[2]; + bool is_raw; + struct { + u32 base_mode; + u32 uv_plane; + } registers; +}; + +struct mali_c55_isp_format_info { + u32 code; + u32 shifted_code; + bool bypass; + u32 order; +}; + +enum mali_c55_planes { + MALI_C55_PLANE_Y, + MALI_C55_PLANE_UV, + MALI_C55_NUM_PLANES +}; + +struct mali_c55_buffer { + struct vb2_v4l2_buffer vb; + unsigned int planes_pending; + struct list_head queue; + dma_addr_t addrs[MALI_C55_NUM_PLANES]; +}; + +struct mali_c55_cap_dev { + struct mali_c55 *mali_c55; + struct mali_c55_resizer *rsz; + struct video_device vdev; + struct media_pad pad; + struct vb2_queue queue; + /* Mutex to provide to vb2 */ + struct mutex lock; + unsigned int reg_offset; + + struct { + const struct mali_c55_format_info *info; + struct v4l2_pix_format_mplane format; + } format; + + struct { + /* Spinlock to guard buffer queue */ + spinlock_t lock; + /* Spinlock to guard the queue of buffers being processed */ + spinlock_t processing_lock; + struct list_head input; + struct list_head processing; + } buffers; +}; + +struct mali_c55_stats_buf { + struct vb2_v4l2_buffer vb; + unsigned int segments_remaining; + struct list_head queue; + bool failed; +}; + +struct mali_c55_params_buf { + struct vb2_v4l2_buffer vb; + struct list_head queue; + struct v4l2_isp_params_buffer *config; +}; + +struct mali_c55_stats { + struct mali_c55 *mali_c55; + struct video_device vdev; + struct vb2_queue queue; + struct media_pad pad; + /* Mutex to provide to vb2 */ + struct mutex lock; + + struct { + /* Spinlock to guard buffer queue */ + spinlock_t lock; + struct list_head queue; + } buffers; +}; + +struct mali_c55_params { + struct mali_c55 *mali_c55; + struct video_device vdev; + struct vb2_queue queue; + struct media_pad pad; + /* Mutex to provide to vb2 */ + struct mutex lock; + + struct { + /* Spinlock to guard buffer queue */ + spinlock_t lock; + struct list_head queue; + } buffers; +}; + +enum mali_c55_config_spaces { + MALI_C55_CONFIG_PONG, + MALI_C55_CONFIG_PING, +}; + +/** + * struct mali_c55_context - Fields relating to a single camera context + * + * @mali_c55: Pointer to the main struct mali_c55 + * @registers: A pointer to some allocated memory holding register + * values to be written to the hardware at frame interrupt + * @base: Base address of the config space in the hardware + * @lock: A spinlock to protect against writes to @registers whilst that + * space is being copied to the hardware + * @list: A list head to facilitate a context queue + */ +struct mali_c55_context { + struct mali_c55 *mali_c55; + u32 *registers; + phys_addr_t base; + /* Spinlock to prevent simultaneous access of register space */ + spinlock_t lock; + struct list_head list; +}; + +struct mali_c55 { + struct device *dev; + void __iomem *base; + struct clk_bulk_data clks[MALI_C55_NUM_CLKS]; + struct reset_control_bulk_data resets[MALI_C55_NUM_RESETS]; + int irqnum; + + u16 capabilities; + bool inline_mode; + struct media_device media_dev; + struct v4l2_device v4l2_dev; + struct v4l2_async_notifier notifier; + struct media_pipeline pipe; + + struct mali_c55_tpg tpg; + struct mali_c55_isp isp; + struct mali_c55_resizer resizers[MALI_C55_NUM_RSZS]; + struct mali_c55_cap_dev cap_devs[MALI_C55_NUM_CAP_DEVS]; + struct mali_c55_params params; + struct mali_c55_stats stats; + + struct mali_c55_context context; + u32 next_config; +}; + +void mali_c55_write(struct mali_c55 *mali_c55, unsigned int addr, u32 val); +void mali_c55_cap_dev_write(struct mali_c55_cap_dev *cap_dev, unsigned int addr, + u32 val); +void mali_c55_update_bits(struct mali_c55 *mali_c55, unsigned int addr, + u32 mask, u32 val); +u32 mali_c55_read(struct mali_c55 *mali_c55, unsigned int addr); +void mali_c55_ctx_write(struct mali_c55 *mali_c55, unsigned int addr, u32 val); +u32 mali_c55_ctx_read(struct mali_c55 *mali_c55, unsigned int addr); +void mali_c55_ctx_update_bits(struct mali_c55 *mali_c55, unsigned int addr, + u32 mask, u32 val); + +int mali_c55_config_write(struct mali_c55_context *ctx, + enum mali_c55_config_spaces cfg_space, + bool force_synchronous); + +int mali_c55_register_isp(struct mali_c55 *mali_c55); +int mali_c55_register_tpg(struct mali_c55 *mali_c55); +void mali_c55_unregister_tpg(struct mali_c55 *mali_c55); +void mali_c55_unregister_isp(struct mali_c55 *mali_c55); +int mali_c55_register_resizers(struct mali_c55 *mali_c55); +void mali_c55_unregister_resizers(struct mali_c55 *mali_c55); +int mali_c55_register_capture_devs(struct mali_c55 *mali_c55); +void mali_c55_unregister_capture_devs(struct mali_c55 *mali_c55); +int mali_c55_register_stats(struct mali_c55 *mali_c55); +void mali_c55_unregister_stats(struct mali_c55 *mali_c55); +int mali_c55_register_params(struct mali_c55 *mali_c55); +void mali_c55_unregister_params(struct mali_c55 *mali_c55); +struct mali_c55_context *mali_c55_get_active_context(struct mali_c55 *mali_c55); +void mali_c55_set_plane_done(struct mali_c55_cap_dev *cap_dev, + enum mali_c55_planes plane); +void mali_c55_set_next_buffer(struct mali_c55_cap_dev *cap_dev); +void mali_c55_isp_queue_event_sof(struct mali_c55 *mali_c55); + +bool mali_c55_format_is_raw(unsigned int mbus_code); + +const struct mali_c55_isp_format_info * +mali_c55_isp_fmt_next(const struct mali_c55_isp_format_info *fmt); +const struct mali_c55_isp_format_info * +mali_c55_isp_get_mbus_config_by_code(u32 code); +const struct mali_c55_isp_format_info * +mali_c55_isp_get_mbus_config_by_shifted_code(u32 code); +const struct mali_c55_isp_format_info * +mali_c55_isp_get_mbus_config_by_index(u32 index); +bool mali_c55_pipeline_ready(struct mali_c55 *mali_c55); +void mali_c55_stats_fill_buffer(struct mali_c55 *mali_c55, + enum mali_c55_config_spaces cfg_space); +void mali_c55_params_write_config(struct mali_c55 *mali_c55); + +#endif /* _MALI_C55_COMMON_H */ diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-core.c b/drivers/media/platform/arm/mali-c55/mali-c55-core.c new file mode 100644 index 000000000000..43b834459ccf --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/mali-c55-core.c @@ -0,0 +1,917 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM Mali-C55 ISP Driver - Core driver code + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> +#include <linux/mod_devicetable.h> +#include <linux/of.h> +#include <linux/of_reserved_mem.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> +#include <linux/slab.h> +#include <linux/string.h> + +#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-mc.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "mali-c55-common.h" +#include "mali-c55-registers.h" + +static const char * const mali_c55_interrupt_names[] = { + [MALI_C55_IRQ_ISP_START] = "ISP start", + [MALI_C55_IRQ_ISP_DONE] = "ISP done", + [MALI_C55_IRQ_MCM_ERROR] = "Multi-context management error", + [MALI_C55_IRQ_BROKEN_FRAME_ERROR] = "Broken frame error", + [MALI_C55_IRQ_MET_AF_DONE] = "AF metering done", + [MALI_C55_IRQ_MET_AEXP_DONE] = "AEXP metering done", + [MALI_C55_IRQ_MET_AWB_DONE] = "AWB metering done", + [MALI_C55_IRQ_AEXP_1024_DONE] = "AEXP 1024-bit histogram done", + [MALI_C55_IRQ_IRIDIX_MET_DONE] = "Iridix metering done", + [MALI_C55_IRQ_LUT_INIT_DONE] = "LUT memory init done", + [MALI_C55_IRQ_FR_Y_DONE] = "Full resolution Y plane DMA done", + [MALI_C55_IRQ_FR_UV_DONE] = "Full resolution U/V plane DMA done", + [MALI_C55_IRQ_DS_Y_DONE] = "Downscale Y plane DMA done", + [MALI_C55_IRQ_DS_UV_DONE] = "Downscale U/V plane DMA done", + [MALI_C55_IRQ_LINEARIZATION_DONE] = "Linearisation done", + [MALI_C55_IRQ_RAW_FRONTEND_DONE] = "Raw frontend processing done", + [MALI_C55_IRQ_NOISE_REDUCTION_DONE] = "Noise reduction done", + [MALI_C55_IRQ_IRIDIX_DONE] = "Iridix done", + [MALI_C55_IRQ_BAYER2RGB_DONE] = "Bayer to RGB conversion done", + [MALI_C55_IRQ_WATCHDOG_TIMER] = "Watchdog timer timed out", + [MALI_C55_IRQ_FRAME_COLLISION] = "Frame collision error", + [MALI_C55_IRQ_UNUSED] = "IRQ bit unused", + [MALI_C55_IRQ_DMA_ERROR] = "DMA error", + [MALI_C55_IRQ_INPUT_STOPPED] = "Input port safely stopped", + [MALI_C55_IRQ_MET_AWB_TARGET1_HIT] = "AWB metering target 1 address hit", + [MALI_C55_IRQ_MET_AWB_TARGET2_HIT] = "AWB metering target 2 address hit" +}; + +static const unsigned int config_space_addrs[] = { + [MALI_C55_CONFIG_PING] = 0x0ab6c, + [MALI_C55_CONFIG_PONG] = 0x22b2c, +}; + +static const char * const mali_c55_clk_names[MALI_C55_NUM_CLKS] = { + "vclk", + "aclk", + "hclk", +}; + +static const char * const mali_c55_reset_names[MALI_C55_NUM_RESETS] = { + "vresetn", + "aresetn", + "hresetn", +}; + +/* + * System IO + * + * The Mali-C55 ISP has up to two configuration register spaces (called 'ping' + * and 'pong'), with the expectation that the 'active' space will be left + * untouched whilst a frame is being processed and the 'inactive' space + * configured ready to be switched to during the blanking period before the next + * frame processing starts. These spaces should ideally be set via DMA transfer + * from a buffer rather than through individual register set operations. There + * is also a shared global register space which should be set normally. For now + * though we will simply use a CPU write and target DMA transfers of the config + * space in the future. + * + * As groundwork for that path any read/write call that is made to an address + * within those config spaces should infact be directed to a buffer that was + * allocated to hold them rather than the IO memory itself. The actual copy of + * that buffer to IO mem will happen on interrupt. + */ + +void mali_c55_write(struct mali_c55 *mali_c55, unsigned int addr, u32 val) +{ + WARN_ON(addr >= MALI_C55_REG_CONFIG_SPACES_OFFSET); + + writel(val, mali_c55->base + addr); +} + +u32 mali_c55_read(struct mali_c55 *mali_c55, unsigned int addr) +{ + WARN_ON(addr >= MALI_C55_REG_CONFIG_SPACES_OFFSET); + + return readl(mali_c55->base + addr); +} + +void mali_c55_update_bits(struct mali_c55 *mali_c55, unsigned int addr, + u32 mask, u32 val) +{ + u32 orig, new; + + orig = mali_c55_read(mali_c55, addr); + + new = orig & ~mask; + new |= val & mask; + + if (new != orig) + mali_c55_write(mali_c55, addr, new); +} + +static void __mali_c55_ctx_write(struct mali_c55_context *ctx, + unsigned int addr, u32 val) +{ + addr = (addr - MALI_C55_REG_CONFIG_SPACES_OFFSET) / 4; + ctx->registers[addr] = val; +} + +void mali_c55_ctx_write(struct mali_c55 *mali_c55, unsigned int addr, u32 val) +{ + struct mali_c55_context *ctx = mali_c55_get_active_context(mali_c55); + + WARN_ON(addr < MALI_C55_REG_CONFIG_SPACES_OFFSET); + + spin_lock(&ctx->lock); + __mali_c55_ctx_write(ctx, addr, val); + spin_unlock(&ctx->lock); +} + +static u32 __mali_c55_ctx_read(struct mali_c55_context *ctx, unsigned int addr) +{ + addr = (addr - MALI_C55_REG_CONFIG_SPACES_OFFSET) / 4; + return ctx->registers[addr]; +} + +u32 mali_c55_ctx_read(struct mali_c55 *mali_c55, unsigned int addr) +{ + struct mali_c55_context *ctx = mali_c55_get_active_context(mali_c55); + u32 val; + + WARN_ON(addr < MALI_C55_REG_CONFIG_SPACES_OFFSET); + + spin_lock(&ctx->lock); + val = __mali_c55_ctx_read(ctx, addr); + spin_unlock(&ctx->lock); + + return val; +} + +void mali_c55_ctx_update_bits(struct mali_c55 *mali_c55, unsigned int addr, + u32 mask, u32 val) +{ + struct mali_c55_context *ctx = mali_c55_get_active_context(mali_c55); + u32 orig, tmp; + + WARN_ON(addr < MALI_C55_REG_CONFIG_SPACES_OFFSET); + + spin_lock(&ctx->lock); + + orig = __mali_c55_ctx_read(ctx, addr); + + tmp = orig & ~mask; + tmp |= val & mask; + + if (tmp != orig) + __mali_c55_ctx_write(ctx, addr, tmp); + + spin_unlock(&ctx->lock); +} + +int mali_c55_config_write(struct mali_c55_context *ctx, + enum mali_c55_config_spaces cfg_space, + bool force_synchronous) +{ + struct mali_c55 *mali_c55 = ctx->mali_c55; + + memcpy_toio(mali_c55->base + config_space_addrs[cfg_space], + ctx->registers, MALI_C55_CONFIG_SPACE_SIZE); + + return 0; +} + +struct mali_c55_context *mali_c55_get_active_context(struct mali_c55 *mali_c55) +{ + return &mali_c55->context; +} + +static void mali_c55_remove_links(struct mali_c55 *mali_c55) +{ + unsigned int i; + + media_entity_remove_links(&mali_c55->tpg.sd.entity); + media_entity_remove_links(&mali_c55->isp.sd.entity); + + for (i = 0; i < MALI_C55_NUM_RSZS; i++) + media_entity_remove_links(&mali_c55->resizers[i].sd.entity); + + for (i = 0; i < MALI_C55_NUM_CAP_DEVS; i++) + media_entity_remove_links(&mali_c55->cap_devs[i].vdev.entity); +} + +static int mali_c55_create_links(struct mali_c55 *mali_c55) +{ + int ret; + + /* Test pattern generator to ISP */ + ret = media_create_pad_link(&mali_c55->tpg.sd.entity, 0, + &mali_c55->isp.sd.entity, + MALI_C55_ISP_PAD_SINK_VIDEO, 0); + if (ret) { + dev_err(mali_c55->dev, "failed to link TPG and ISP\n"); + goto err_remove_links; + } + + /* Full resolution resizer pipe. */ + ret = media_create_pad_link(&mali_c55->isp.sd.entity, + MALI_C55_ISP_PAD_SOURCE_VIDEO, + &mali_c55->resizers[MALI_C55_RSZ_FR].sd.entity, + MALI_C55_RSZ_SINK_PAD, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(mali_c55->dev, "failed to link ISP and FR resizer\n"); + goto err_remove_links; + } + + /* Full resolution bypass. */ + ret = media_create_pad_link(&mali_c55->isp.sd.entity, + MALI_C55_ISP_PAD_SOURCE_BYPASS, + &mali_c55->resizers[MALI_C55_RSZ_FR].sd.entity, + MALI_C55_RSZ_SINK_BYPASS_PAD, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(mali_c55->dev, "failed to link ISP and FR resizer\n"); + goto err_remove_links; + } + + /* Resizer pipe to video capture nodes. */ + ret = media_create_pad_link(&mali_c55->resizers[0].sd.entity, + MALI_C55_RSZ_SOURCE_PAD, + &mali_c55->cap_devs[MALI_C55_CAP_DEV_FR].vdev.entity, + 0, MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_err(mali_c55->dev, + "failed to link FR resizer and video device\n"); + goto err_remove_links; + } + + /* The downscale pipe is an optional hardware block */ + if (mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) { + ret = media_create_pad_link(&mali_c55->isp.sd.entity, + MALI_C55_ISP_PAD_SOURCE_VIDEO, + &mali_c55->resizers[MALI_C55_RSZ_DS].sd.entity, + MALI_C55_RSZ_SINK_PAD, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(mali_c55->dev, + "failed to link ISP and DS resizer\n"); + goto err_remove_links; + } + + ret = media_create_pad_link(&mali_c55->resizers[1].sd.entity, + MALI_C55_RSZ_SOURCE_PAD, + &mali_c55->cap_devs[MALI_C55_CAP_DEV_DS].vdev.entity, + 0, MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_err(mali_c55->dev, + "failed to link DS resizer and video device\n"); + goto err_remove_links; + } + } + + ret = media_create_pad_link(&mali_c55->isp.sd.entity, + MALI_C55_ISP_PAD_SOURCE_STATS, + &mali_c55->stats.vdev.entity, 0, + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_err(mali_c55->dev, + "failed to link ISP and 3a stats node\n"); + goto err_remove_links; + } + + ret = media_create_pad_link(&mali_c55->params.vdev.entity, 0, + &mali_c55->isp.sd.entity, + MALI_C55_ISP_PAD_SINK_PARAMS, + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_err(mali_c55->dev, + "failed to link ISP and parameters video node\n"); + goto err_remove_links; + } + + return 0; + +err_remove_links: + mali_c55_remove_links(mali_c55); + return ret; +} + +static void mali_c55_unregister_entities(struct mali_c55 *mali_c55) +{ + mali_c55_remove_links(mali_c55); + mali_c55_unregister_tpg(mali_c55); + mali_c55_unregister_isp(mali_c55); + mali_c55_unregister_resizers(mali_c55); + mali_c55_unregister_capture_devs(mali_c55); + mali_c55_unregister_params(mali_c55); + mali_c55_unregister_stats(mali_c55); +} + +static void mali_c55_swap_next_config(struct mali_c55 *mali_c55) +{ + struct mali_c55_context *ctx = mali_c55_get_active_context(mali_c55); + + mali_c55_config_write(ctx, mali_c55->next_config ? + MALI_C55_CONFIG_PING : MALI_C55_CONFIG_PONG, + false); + + mali_c55_update_bits(mali_c55, MALI_C55_REG_MCU_CONFIG, + MALI_C55_REG_MCU_CONFIG_WRITE_MASK, + MALI_C55_MCU_CONFIG_WRITE(mali_c55->next_config)); +} + +static int mali_c55_register_entities(struct mali_c55 *mali_c55) +{ + int ret; + + ret = mali_c55_register_tpg(mali_c55); + if (ret) + return ret; + + ret = mali_c55_register_isp(mali_c55); + if (ret) + goto err_unregister_entities; + + ret = mali_c55_register_resizers(mali_c55); + if (ret) + goto err_unregister_entities; + + ret = mali_c55_register_capture_devs(mali_c55); + if (ret) + goto err_unregister_entities; + + ret = mali_c55_register_params(mali_c55); + if (ret) + goto err_unregister_entities; + + ret = mali_c55_register_stats(mali_c55); + if (ret) + goto err_unregister_entities; + + ret = mali_c55_create_links(mali_c55); + if (ret) + goto err_unregister_entities; + + return 0; + +err_unregister_entities: + mali_c55_unregister_entities(mali_c55); + + return ret; +} + +static int mali_c55_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asc) +{ + struct mali_c55 *mali_c55 = container_of(notifier, + struct mali_c55, notifier); + struct media_pad *pad = &mali_c55->isp.pads[MALI_C55_ISP_PAD_SINK_VIDEO]; + int ret; + + /* + * By default we'll flag this link enabled and the TPG disabled, but + * no immutable flag because we need to be able to switch between the + * two. + */ + ret = v4l2_create_fwnode_links_to_pad(subdev, pad, + MEDIA_LNK_FL_ENABLED); + if (ret) + dev_err(mali_c55->dev, "failed to create link for %s\n", + subdev->name); + + return ret; +} + +static int mali_c55_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct mali_c55 *mali_c55 = container_of(notifier, + struct mali_c55, notifier); + + return v4l2_device_register_subdev_nodes(&mali_c55->v4l2_dev); +} + +static const struct v4l2_async_notifier_operations mali_c55_notifier_ops = { + .bound = mali_c55_notifier_bound, + .complete = mali_c55_notifier_complete, +}; + +static int mali_c55_parse_endpoint(struct mali_c55 *mali_c55) +{ + struct v4l2_async_connection *asc; + struct fwnode_handle *ep; + + /* + * The ISP should have a single endpoint pointing to some flavour of + * CSI-2 receiver...but for now at least we do want everything to work + * normally even with no sensors connected, as we have the TPG. If we + * don't find a sensor just warn and return success. + */ + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(mali_c55->dev), + 0, 0, 0); + if (!ep) { + dev_warn(mali_c55->dev, "no local endpoint found\n"); + return 0; + } + + asc = v4l2_async_nf_add_fwnode_remote(&mali_c55->notifier, ep, + struct v4l2_async_connection); + fwnode_handle_put(ep); + if (IS_ERR(asc)) { + dev_err(mali_c55->dev, "failed to add remote fwnode\n"); + return PTR_ERR(asc); + } + + return 0; +} + +static int mali_c55_media_frameworks_init(struct mali_c55 *mali_c55) +{ + int ret; + + strscpy(mali_c55->media_dev.model, "ARM Mali-C55 ISP", + sizeof(mali_c55->media_dev.model)); + + media_device_init(&mali_c55->media_dev); + + ret = media_device_register(&mali_c55->media_dev); + if (ret) + goto err_cleanup_media_device; + + mali_c55->v4l2_dev.mdev = &mali_c55->media_dev; + ret = v4l2_device_register(mali_c55->dev, &mali_c55->v4l2_dev); + if (ret) { + dev_err(mali_c55->dev, "failed to register V4L2 device\n"); + goto err_unregister_media_device; + }; + + mali_c55->notifier.ops = &mali_c55_notifier_ops; + v4l2_async_nf_init(&mali_c55->notifier, &mali_c55->v4l2_dev); + + ret = mali_c55_register_entities(mali_c55); + if (ret) { + dev_err(mali_c55->dev, "failed to register entities\n"); + goto err_cleanup_nf; + } + + ret = mali_c55_parse_endpoint(mali_c55); + if (ret) + goto err_cleanup_nf; + + ret = v4l2_async_nf_register(&mali_c55->notifier); + if (ret) { + dev_err(mali_c55->dev, "failed to register notifier\n"); + goto err_unregister_entities; + } + + return 0; + +err_unregister_entities: + mali_c55_unregister_entities(mali_c55); +err_cleanup_nf: + v4l2_async_nf_cleanup(&mali_c55->notifier); + v4l2_device_unregister(&mali_c55->v4l2_dev); +err_unregister_media_device: + media_device_unregister(&mali_c55->media_dev); +err_cleanup_media_device: + media_device_cleanup(&mali_c55->media_dev); + + return ret; +} + +static void mali_c55_media_frameworks_deinit(struct mali_c55 *mali_c55) +{ + v4l2_async_nf_unregister(&mali_c55->notifier); + mali_c55_unregister_entities(mali_c55); + v4l2_async_nf_cleanup(&mali_c55->notifier); + v4l2_device_unregister(&mali_c55->v4l2_dev); + media_device_unregister(&mali_c55->media_dev); + media_device_cleanup(&mali_c55->media_dev); +} + +bool mali_c55_pipeline_ready(struct mali_c55 *mali_c55) +{ + struct mali_c55_cap_dev *fr = &mali_c55->cap_devs[MALI_C55_CAP_DEV_FR]; + struct mali_c55_cap_dev *ds = &mali_c55->cap_devs[MALI_C55_CAP_DEV_DS]; + struct mali_c55_params *params = &mali_c55->params; + struct mali_c55_stats *stats = &mali_c55->stats; + + return vb2_start_streaming_called(&fr->queue) && + (!(mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) || + vb2_start_streaming_called(&ds->queue)) && + vb2_start_streaming_called(¶ms->queue) && + vb2_start_streaming_called(&stats->queue); +} + +static int mali_c55_check_hwcfg(struct mali_c55 *mali_c55) +{ + u32 product, version, revision, capabilities; + + product = mali_c55_read(mali_c55, MALI_C55_REG_PRODUCT); + version = mali_c55_read(mali_c55, MALI_C55_REG_VERSION); + revision = mali_c55_read(mali_c55, MALI_C55_REG_REVISION); + + mali_c55->media_dev.hw_revision = version; + + dev_info(mali_c55->dev, "Detected Mali-C55 ISP %u.%u.%u\n", + product, version, revision); + + capabilities = mali_c55_read(mali_c55, + MALI_C55_REG_GLOBAL_PARAMETER_STATUS); + + /* + * In its current iteration, the driver only supports inline mode. Given + * we cannot control input data timing in this mode, we cannot guarantee + * that the vertical blanking periods between frames will be long enough + * for us to write configuration data to the ISP during them. For that + * reason we can't really support single config space configuration + * until memory input mode is implemented. + */ + if (!(capabilities & MALI_C55_GPS_PONG_FITTED)) { + dev_err(mali_c55->dev, "Pong config space not fitted.\n"); + return -EINVAL; + } + + mali_c55->capabilities = capabilities & 0xffff; + + return 0; +} + +static irqreturn_t mali_c55_isr(int irq, void *context) +{ + struct device *dev = context; + struct mali_c55 *mali_c55 = dev_get_drvdata(dev); + unsigned long interrupt_status; + u32 curr_config; + unsigned int i; + + interrupt_status = mali_c55_read(mali_c55, + MALI_C55_REG_INTERRUPT_STATUS_VECTOR); + if (!interrupt_status) + return IRQ_NONE; + + mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR_VECTOR, + interrupt_status); + mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR, 1); + mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR, 0); + + for_each_set_bit(i, &interrupt_status, MALI_C55_NUM_IRQ_BITS) { + switch (i) { + case MALI_C55_IRQ_ISP_START: + mali_c55_isp_queue_event_sof(mali_c55); + + mali_c55_set_next_buffer(&mali_c55->cap_devs[MALI_C55_CAP_DEV_FR]); + if (mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) + mali_c55_set_next_buffer(&mali_c55->cap_devs[MALI_C55_CAP_DEV_DS]); + + /* + * When the ISP starts a frame we have some work to do: + * + * 1. Copy over the config for the **next** frame + * 2. Read out the metering stats for the **last** frame + */ + + curr_config = mali_c55_read(mali_c55, + MALI_C55_REG_PING_PONG_READ); + curr_config &= MALI_C55_REG_PING_PONG_READ_MASK; + curr_config >>= ffs(MALI_C55_REG_PING_PONG_READ_MASK) - 1; + mali_c55->next_config = curr_config ^ 1; + + /* + * Write the configuration parameters received from + * userspace into the configuration buffer, which will + * be transferred to the 'next' active config space at + * by mali_c55_swap_next_config(). + */ + mali_c55_params_write_config(mali_c55); + + mali_c55_stats_fill_buffer(mali_c55, + mali_c55->next_config ^ 1); + + mali_c55_swap_next_config(mali_c55); + + break; + case MALI_C55_IRQ_ISP_DONE: + /* + * TODO: Where the ISP has no Pong config fitted, we'd + * have to do the mali_c55_swap_next_config() call here. + */ + break; + case MALI_C55_IRQ_FR_Y_DONE: + mali_c55_set_plane_done(&mali_c55->cap_devs[MALI_C55_CAP_DEV_FR], + MALI_C55_PLANE_Y); + break; + case MALI_C55_IRQ_FR_UV_DONE: + mali_c55_set_plane_done(&mali_c55->cap_devs[MALI_C55_CAP_DEV_FR], + MALI_C55_PLANE_UV); + break; + case MALI_C55_IRQ_DS_Y_DONE: + mali_c55_set_plane_done(&mali_c55->cap_devs[MALI_C55_CAP_DEV_DS], + MALI_C55_PLANE_Y); + break; + case MALI_C55_IRQ_DS_UV_DONE: + mali_c55_set_plane_done(&mali_c55->cap_devs[MALI_C55_CAP_DEV_DS], + MALI_C55_PLANE_UV); + break; + default: + /* + * Only the above interrupts are currently unmasked. If + * we receive anything else here then something weird + * has gone on. + */ + dev_err(dev, "masked interrupt %s triggered\n", + mali_c55_interrupt_names[i]); + } + } + + return IRQ_HANDLED; +} + +static int mali_c55_init_context(struct mali_c55 *mali_c55, + struct resource *res) +{ + struct mali_c55_context *ctx = &mali_c55->context; + + ctx->base = res->start; + ctx->mali_c55 = mali_c55; + spin_lock_init(&ctx->lock); + + ctx->registers = kzalloc(MALI_C55_CONFIG_SPACE_SIZE, GFP_KERNEL); + if (!ctx->registers) + return -ENOMEM; + + /* + * The allocated memory is empty, we need to load the default + * register settings. We just read Ping; it's identical to Pong. + */ + memcpy_fromio(ctx->registers, + mali_c55->base + config_space_addrs[MALI_C55_CONFIG_PING], + MALI_C55_CONFIG_SPACE_SIZE); + + /* + * Some features of the ISP need to be disabled by default and only + * enabled at the same time as they're configured by a parameters buffer + */ + + /* Bypass the sqrt and square compression and expansion modules */ + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BYPASS_1, + MALI_C55_REG_BYPASS_1_FE_SQRT, + MALI_C55_REG_BYPASS_1_FE_SQRT); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BYPASS_3, + MALI_C55_REG_BYPASS_3_SQUARE_BE, + MALI_C55_REG_BYPASS_3_SQUARE_BE); + + /* Bypass the temper module */ + mali_c55_ctx_write(mali_c55, MALI_C55_REG_BYPASS_2, + MALI_C55_REG_BYPASS_2_TEMPER); + + /* Disable the temper module's DMA read/write */ + mali_c55_ctx_write(mali_c55, MALI_C55_REG_TEMPER_DMA_IO, 0x0); + + /* Bypass the colour noise reduction */ + mali_c55_ctx_write(mali_c55, MALI_C55_REG_BYPASS_4, + MALI_C55_REG_BYPASS_4_CNR); + + /* Disable the sinter module */ + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_SINTER_CONFIG, + MALI_C55_SINTER_ENABLE_MASK, 0); + + /* Disable the RGB Gamma module for each output */ + mali_c55_ctx_write(mali_c55, MALI_C55_REG_FR_GAMMA_RGB_ENABLE, 0); + mali_c55_ctx_write(mali_c55, MALI_C55_REG_DS_GAMMA_RGB_ENABLE, 0); + + /* Disable the colour correction matrix */ + mali_c55_ctx_write(mali_c55, MALI_C55_REG_CCM_ENABLE, 0); + + return 0; +} + +static void __mali_c55_power_off(struct mali_c55 *mali_c55) +{ + reset_control_bulk_assert(ARRAY_SIZE(mali_c55->resets), mali_c55->resets); + clk_bulk_disable_unprepare(ARRAY_SIZE(mali_c55->clks), mali_c55->clks); +} + +static int __maybe_unused mali_c55_runtime_suspend(struct device *dev) +{ + struct mali_c55 *mali_c55 = dev_get_drvdata(dev); + + if (irq_has_action(mali_c55->irqnum)) + free_irq(mali_c55->irqnum, dev); + __mali_c55_power_off(mali_c55); + + return 0; +} + +static int __mali_c55_power_on(struct mali_c55 *mali_c55) +{ + int ret; + u32 val; + + ret = clk_bulk_prepare_enable(ARRAY_SIZE(mali_c55->clks), + mali_c55->clks); + if (ret) { + dev_err(mali_c55->dev, "failed to enable clocks\n"); + return ret; + } + + ret = reset_control_bulk_deassert(ARRAY_SIZE(mali_c55->resets), + mali_c55->resets); + if (ret) { + dev_err(mali_c55->dev, "failed to deassert resets\n"); + return ret; + } + + /* Use "software only" context management. */ + mali_c55_update_bits(mali_c55, MALI_C55_REG_MCU_CONFIG, + MALI_C55_REG_MCU_CONFIG_OVERRIDE_MASK, 0x01); + + /* + * Mask the interrupts and clear any that were set, then unmask the ones + * that we actually want to handle. + */ + mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_MASK_VECTOR, + MALI_C55_INTERRUPT_MASK_ALL); + mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR_VECTOR, + MALI_C55_INTERRUPT_MASK_ALL); + mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR, 0x01); + mali_c55_write(mali_c55, MALI_C55_REG_INTERRUPT_CLEAR, 0x00); + + mali_c55_update_bits(mali_c55, MALI_C55_REG_INTERRUPT_MASK_VECTOR, + MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_ISP_START) | + MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_ISP_DONE) | + MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_FR_Y_DONE) | + MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_FR_UV_DONE) | + MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_DS_Y_DONE) | + MALI_C55_INTERRUPT_BIT(MALI_C55_IRQ_DS_UV_DONE), + 0x00); + + /* Set safe stop to ensure we're in a non-streaming state */ + mali_c55_write(mali_c55, MALI_C55_REG_INPUT_MODE_REQUEST, + MALI_C55_INPUT_SAFE_STOP); + readl_poll_timeout(mali_c55->base + MALI_C55_REG_MODE_STATUS, + val, !val, 10 * USEC_PER_MSEC, 250 * USEC_PER_MSEC); + + return 0; +} + +static int __maybe_unused mali_c55_runtime_resume(struct device *dev) +{ + struct mali_c55 *mali_c55 = dev_get_drvdata(dev); + int ret; + + ret = __mali_c55_power_on(mali_c55); + if (ret) + return ret; + + /* + * The driver needs to transfer large amounts of register settings to + * the ISP each frame, using either a DMA transfer or memcpy. We use a + * threaded IRQ to avoid disabling interrupts the entire time that's + * happening. + */ + ret = request_threaded_irq(mali_c55->irqnum, NULL, mali_c55_isr, + IRQF_ONESHOT, dev_driver_string(dev), dev); + if (ret) { + __mali_c55_power_off(mali_c55); + dev_err(dev, "failed to request irq\n"); + } + + return ret; +} + +static const struct dev_pm_ops mali_c55_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(mali_c55_runtime_suspend, mali_c55_runtime_resume, + NULL) +}; + +static int mali_c55_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mali_c55 *mali_c55; + struct resource *res; + int ret; + + mali_c55 = devm_kzalloc(dev, sizeof(*mali_c55), GFP_KERNEL); + if (!mali_c55) + return -ENOMEM; + + mali_c55->dev = dev; + platform_set_drvdata(pdev, mali_c55); + + mali_c55->base = devm_platform_get_and_ioremap_resource(pdev, 0, + &res); + if (IS_ERR(mali_c55->base)) + return dev_err_probe(dev, PTR_ERR(mali_c55->base), + "failed to map IO memory\n"); + + for (unsigned int i = 0; i < ARRAY_SIZE(mali_c55_clk_names); i++) + mali_c55->clks[i].id = mali_c55_clk_names[i]; + + ret = devm_clk_bulk_get(dev, ARRAY_SIZE(mali_c55->clks), mali_c55->clks); + if (ret) + return dev_err_probe(dev, ret, "failed to acquire clocks\n"); + + for (unsigned int i = 0; i < ARRAY_SIZE(mali_c55_reset_names); i++) + mali_c55->resets[i].id = mali_c55_reset_names[i]; + + ret = devm_reset_control_bulk_get_optional_shared(dev, + ARRAY_SIZE(mali_c55_reset_names), mali_c55->resets); + if (ret) + return dev_err_probe(dev, ret, "failed to acquire resets\n"); + + of_reserved_mem_device_init(dev); + vb2_dma_contig_set_max_seg_size(dev, UINT_MAX); + + ret = __mali_c55_power_on(mali_c55); + if (ret) + return dev_err_probe(dev, ret, "failed to power on\n"); + + ret = mali_c55_check_hwcfg(mali_c55); + if (ret) + goto err_power_off; + + ret = mali_c55_init_context(mali_c55, res); + if (ret) + goto err_power_off; + + mali_c55->media_dev.dev = dev; + + pm_runtime_set_autosuspend_delay(&pdev->dev, 2000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = mali_c55_media_frameworks_init(mali_c55); + if (ret) + goto err_free_context_registers; + + pm_runtime_idle(&pdev->dev); + + mali_c55->irqnum = platform_get_irq(pdev, 0); + if (mali_c55->irqnum < 0) { + ret = mali_c55->irqnum; + dev_err(dev, "failed to get interrupt\n"); + goto err_deinit_media_frameworks; + } + + return 0; + +err_deinit_media_frameworks: + mali_c55_media_frameworks_deinit(mali_c55); + pm_runtime_disable(&pdev->dev); +err_free_context_registers: + kfree(mali_c55->context.registers); +err_power_off: + __mali_c55_power_off(mali_c55); + + return ret; +} + +static void mali_c55_remove(struct platform_device *pdev) +{ + struct mali_c55 *mali_c55 = platform_get_drvdata(pdev); + + kfree(mali_c55->context.registers); + mali_c55_media_frameworks_deinit(mali_c55); +} + +static const struct of_device_id mali_c55_of_match[] = { + { .compatible = "arm,mali-c55", }, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mali_c55_of_match); + +static struct platform_driver mali_c55_driver = { + .driver = { + .name = "mali-c55", + .of_match_table = mali_c55_of_match, + .pm = &mali_c55_pm_ops, + }, + .probe = mali_c55_probe, + .remove = mali_c55_remove, +}; + +module_platform_driver(mali_c55_driver); + +MODULE_AUTHOR("Daniel Scally <dan.scally@ideasonboard.com>"); +MODULE_AUTHOR("Jacopo Mondi <jacopo.mondi@ideasonboard.com>"); +MODULE_DESCRIPTION("ARM Mali-C55 ISP platform driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-isp.c b/drivers/media/platform/arm/mali-c55/mali-c55-isp.c new file mode 100644 index 000000000000..497f25fbdd13 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/mali-c55-isp.c @@ -0,0 +1,665 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM Mali-C55 ISP Driver - Image signal processor + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include <linux/media/arm/mali-c55-config.h> + +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/property.h> +#include <linux/string.h> + +#include <uapi/linux/media/arm/mali-c55-config.h> + +#include <media/media-entity.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-mc.h> +#include <media/v4l2-subdev.h> + +#include "mali-c55-common.h" +#include "mali-c55-registers.h" + +static const struct mali_c55_isp_format_info mali_c55_isp_fmts[] = { + { + .code = MEDIA_BUS_FMT_SRGGB20_1X20, + .shifted_code = MEDIA_BUS_FMT_SRGGB16_1X16, + .order = MALI_C55_BAYER_ORDER_RGGB, + .bypass = false, + }, + { + .code = MEDIA_BUS_FMT_SGRBG20_1X20, + .shifted_code = MEDIA_BUS_FMT_SGRBG16_1X16, + .order = MALI_C55_BAYER_ORDER_GRBG, + .bypass = false, + }, + { + .code = MEDIA_BUS_FMT_SGBRG20_1X20, + .shifted_code = MEDIA_BUS_FMT_SGBRG16_1X16, + .order = MALI_C55_BAYER_ORDER_GBRG, + .bypass = false, + }, + { + .code = MEDIA_BUS_FMT_SBGGR20_1X20, + .shifted_code = MEDIA_BUS_FMT_SBGGR16_1X16, + .order = MALI_C55_BAYER_ORDER_BGGR, + .bypass = false, + }, + { + .code = MEDIA_BUS_FMT_RGB202020_1X60, + .shifted_code = 0, /* Not relevant for this format */ + .order = 0, /* Not relevant for this format */ + .bypass = true, + } + /* + * TODO: Support MEDIA_BUS_FMT_YUV20_1X60 here. This is so that we can + * also support YUV input from a sensor passed-through to the output. At + * present we have no mechanism to test that though so it may have to + * wait a while... + */ +}; + +const struct mali_c55_isp_format_info * +mali_c55_isp_get_mbus_config_by_index(u32 index) +{ + if (index < ARRAY_SIZE(mali_c55_isp_fmts)) + return &mali_c55_isp_fmts[index]; + + return NULL; +} + +const struct mali_c55_isp_format_info * +mali_c55_isp_get_mbus_config_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mali_c55_isp_fmts); i++) { + if (mali_c55_isp_fmts[i].code == code) + return &mali_c55_isp_fmts[i]; + } + + return NULL; +} + +const struct mali_c55_isp_format_info * +mali_c55_isp_get_mbus_config_by_shifted_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mali_c55_isp_fmts); i++) { + if (mali_c55_isp_fmts[i].shifted_code == code) + return &mali_c55_isp_fmts[i]; + } + + return NULL; +} + +static void mali_c55_isp_stop(struct mali_c55 *mali_c55) +{ + u32 val; + + mali_c55_write(mali_c55, MALI_C55_REG_INPUT_MODE_REQUEST, + MALI_C55_INPUT_SAFE_STOP); + readl_poll_timeout(mali_c55->base + MALI_C55_REG_MODE_STATUS, + val, !val, 10 * USEC_PER_MSEC, 250 * USEC_PER_MSEC); +} + +static int mali_c55_isp_start(struct mali_c55 *mali_c55, + const struct v4l2_subdev_state *state) +{ + struct mali_c55_context *ctx = mali_c55_get_active_context(mali_c55); + const struct mali_c55_isp_format_info *cfg; + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *crop; + u32 val; + int ret; + + mali_c55_update_bits(mali_c55, MALI_C55_REG_MCU_CONFIG, + MALI_C55_REG_MCU_CONFIG_WRITE_MASK, + MALI_C55_REG_MCU_CONFIG_WRITE_PING); + + /* Apply input windowing */ + crop = v4l2_subdev_state_get_crop(state, MALI_C55_ISP_PAD_SINK_VIDEO); + format = v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SINK_VIDEO); + cfg = mali_c55_isp_get_mbus_config_by_code(format->code); + + mali_c55_write(mali_c55, MALI_C55_REG_HC_START, + MALI_C55_HC_START(crop->left)); + mali_c55_write(mali_c55, MALI_C55_REG_HC_SIZE, + MALI_C55_HC_SIZE(crop->width)); + mali_c55_write(mali_c55, MALI_C55_REG_VC_START_SIZE, + MALI_C55_VC_START(crop->top) | + MALI_C55_VC_SIZE(crop->height)); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BASE_ADDR, + MALI_C55_REG_ACTIVE_WIDTH_MASK, format->width); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BASE_ADDR, + MALI_C55_REG_ACTIVE_HEIGHT_MASK, + format->height << 16); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BAYER_ORDER, + MALI_C55_BAYER_ORDER_MASK, cfg->order); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_INPUT_WIDTH, + MALI_C55_INPUT_WIDTH_MASK, + MALI_C55_INPUT_WIDTH_20BIT); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_ISP_RAW_BYPASS, + MALI_C55_ISP_RAW_BYPASS_BYPASS_MASK, + cfg->bypass ? MALI_C55_ISP_RAW_BYPASS_BYPASS_MASK : + 0x00); + + mali_c55_params_write_config(mali_c55); + ret = mali_c55_config_write(ctx, MALI_C55_CONFIG_PING, true); + if (ret) { + dev_err(mali_c55->dev, "failed to write ISP config\n"); + return ret; + } + + mali_c55_write(mali_c55, MALI_C55_REG_INPUT_MODE_REQUEST, + MALI_C55_INPUT_SAFE_START); + + ret = readl_poll_timeout(mali_c55->base + MALI_C55_REG_MODE_STATUS, val, + val, 10 * USEC_PER_MSEC, 250 * USEC_PER_MSEC); + if (ret) { + mali_c55_isp_stop(mali_c55); + dev_err(mali_c55->dev, "timeout starting ISP\n"); + return ret; + } + + return 0; +} + +static int mali_c55_isp_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + /* + * Only the internal RGB processed format is allowed on the regular + * processing source pad. + */ + if (code->pad == MALI_C55_ISP_PAD_SOURCE_VIDEO) { + if (code->index) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_RGB121212_1X36; + return 0; + } + + /* On the sink and bypass pads all the supported formats are allowed. */ + if (code->index >= ARRAY_SIZE(mali_c55_isp_fmts)) + return -EINVAL; + + code->code = mali_c55_isp_fmts[code->index].code; + + return 0; +} + +static int mali_c55_isp_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct mali_c55_isp_format_info *cfg; + + if (fse->index > 0) + return -EINVAL; + + /* + * Only the internal RGB processed format is allowed on the regular + * processing source pad. + * + * On the sink and bypass pads all the supported formats are allowed. + */ + if (fse->pad == MALI_C55_ISP_PAD_SOURCE_VIDEO) { + if (fse->code != MEDIA_BUS_FMT_RGB121212_1X36) + return -EINVAL; + } else { + cfg = mali_c55_isp_get_mbus_config_by_code(fse->code); + if (!cfg) + return -EINVAL; + } + + fse->min_width = MALI_C55_MIN_WIDTH; + fse->min_height = MALI_C55_MIN_HEIGHT; + fse->max_width = MALI_C55_MAX_WIDTH; + fse->max_height = MALI_C55_MAX_HEIGHT; + + return 0; +} + +static int mali_c55_isp_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; + const struct mali_c55_isp_format_info *cfg; + struct v4l2_rect *crop; + + /* + * Disallow set_fmt on the source pads; format is fixed and the sizes + * are the result of applying the sink crop rectangle to the sink + * format. + */ + if (format->pad != MALI_C55_ISP_PAD_SINK_VIDEO) + return v4l2_subdev_get_fmt(sd, state, format); + + sink_fmt = v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SINK_VIDEO); + + cfg = mali_c55_isp_get_mbus_config_by_code(fmt->code); + sink_fmt->code = cfg ? fmt->code : MEDIA_BUS_FMT_SRGGB20_1X20; + + /* + * Clamp sizes in the accepted limits and clamp the crop rectangle in + * the new sizes. + */ + sink_fmt->width = clamp(fmt->width, MALI_C55_MIN_WIDTH, + MALI_C55_MAX_WIDTH); + sink_fmt->height = clamp(fmt->height, MALI_C55_MIN_HEIGHT, + MALI_C55_MAX_HEIGHT); + + *fmt = *sink_fmt; + + crop = v4l2_subdev_state_get_crop(state, MALI_C55_ISP_PAD_SINK_VIDEO); + crop->left = 0; + crop->top = 0; + crop->width = sink_fmt->width; + crop->height = sink_fmt->height; + + /* + * Propagate format to source pads. On the 'regular' output pad use + * the internal RGB processed format, while on the bypass pad simply + * replicate the ISP sink format. The sizes on both pads are the same as + * the ISP sink crop rectangle. The "field" and "colorspace" fields are + * set in .init_state() and fixed for both source pads, as is the "code" + * field for the processed data source pad. + */ + src_fmt = v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SOURCE_VIDEO); + src_fmt->width = crop->width; + src_fmt->height = crop->height; + + src_fmt = v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SOURCE_BYPASS); + src_fmt->code = sink_fmt->code; + src_fmt->width = crop->width; + src_fmt->height = crop->height; + + return 0; +} + +static int mali_c55_isp_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + if (sel->pad != MALI_C55_ISP_PAD_SINK_VIDEO || + sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + sel->r = *v4l2_subdev_state_get_crop(state, MALI_C55_ISP_PAD_SINK_VIDEO); + + return 0; +} + +static int mali_c55_isp_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *src_fmt; + const struct v4l2_mbus_framefmt *fmt; + struct v4l2_rect *crop; + + if (sel->pad != MALI_C55_ISP_PAD_SINK_VIDEO || + sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + fmt = v4l2_subdev_state_get_format(state, MALI_C55_ISP_PAD_SINK_VIDEO); + + sel->r.left = clamp_t(unsigned int, sel->r.left, 0, fmt->width); + sel->r.top = clamp_t(unsigned int, sel->r.top, 0, fmt->height); + sel->r.width = clamp_t(unsigned int, sel->r.width, MALI_C55_MIN_WIDTH, + fmt->width - sel->r.left); + sel->r.height = clamp_t(unsigned int, sel->r.height, + MALI_C55_MIN_HEIGHT, + fmt->height - sel->r.top); + + crop = v4l2_subdev_state_get_crop(state, MALI_C55_ISP_PAD_SINK_VIDEO); + *crop = sel->r; + + /* + * Propagate the crop rectangle sizes to the source pad format. The crop + * isn't propagated to the bypass source pad, because the bypassed data + * cannot be cropped. + */ + src_fmt = v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SOURCE_VIDEO); + src_fmt->width = crop->width; + src_fmt->height = crop->height; + + return 0; +} + +static int mali_c55_isp_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct mali_c55_isp *isp = container_of(sd, struct mali_c55_isp, sd); + struct mali_c55 *mali_c55 = isp->mali_c55; + struct v4l2_subdev *src_sd; + struct media_pad *sink_pad; + int ret; + + /* + * We have two source pads, both of which have only a single stream. The + * core v4l2 code already validated those parameters so we can just get + * on with starting the ISP. + */ + + sink_pad = &isp->pads[MALI_C55_ISP_PAD_SINK_VIDEO]; + isp->remote_src = media_pad_remote_pad_unique(sink_pad); + src_sd = media_entity_to_v4l2_subdev(isp->remote_src->entity); + + isp->frame_sequence = 0; + ret = mali_c55_isp_start(mali_c55, state); + if (ret) { + dev_err(mali_c55->dev, "Failed to start ISP\n"); + isp->remote_src = NULL; + return ret; + } + + /* + * We only support a single input stream, so we can just enable the 1st + * entry in the streams mask. + */ + ret = v4l2_subdev_enable_streams(src_sd, isp->remote_src->index, BIT(0)); + if (ret) { + dev_err(mali_c55->dev, "Failed to start ISP source\n"); + mali_c55_isp_stop(mali_c55); + return ret; + } + + return 0; +} + +static int mali_c55_isp_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct mali_c55_isp *isp = container_of(sd, struct mali_c55_isp, sd); + struct mali_c55 *mali_c55 = isp->mali_c55; + struct v4l2_subdev *src_sd; + + if (isp->remote_src) { + src_sd = media_entity_to_v4l2_subdev(isp->remote_src->entity); + v4l2_subdev_disable_streams(src_sd, isp->remote_src->index, + BIT(0)); + } + isp->remote_src = NULL; + + mali_c55_isp_stop(mali_c55); + + return 0; +} + +static const struct v4l2_subdev_pad_ops mali_c55_isp_pad_ops = { + .enum_mbus_code = mali_c55_isp_enum_mbus_code, + .enum_frame_size = mali_c55_isp_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = mali_c55_isp_set_fmt, + .get_selection = mali_c55_isp_get_selection, + .set_selection = mali_c55_isp_set_selection, + .link_validate = v4l2_subdev_link_validate_default, + .enable_streams = mali_c55_isp_enable_streams, + .disable_streams = mali_c55_isp_disable_streams, +}; + +void mali_c55_isp_queue_event_sof(struct mali_c55 *mali_c55) +{ + struct v4l2_event event = { + .type = V4L2_EVENT_FRAME_SYNC, + }; + + event.u.frame_sync.frame_sequence = mali_c55->isp.frame_sequence; + v4l2_event_queue(mali_c55->isp.sd.devnode, &event); +} + +static int +mali_c55_isp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_FRAME_SYNC: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(fh, sub); + default: + return -EINVAL; + } +} + +static const struct v4l2_subdev_core_ops mali_c55_isp_core_ops = { + .subscribe_event = mali_c55_isp_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops mali_c55_isp_ops = { + .pad = &mali_c55_isp_pad_ops, + .core = &mali_c55_isp_core_ops, +}; + +static int mali_c55_isp_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + struct v4l2_rect *in_crop; + + sink_fmt = v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SINK_VIDEO); + src_fmt = v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SOURCE_VIDEO); + in_crop = v4l2_subdev_state_get_crop(state, + MALI_C55_ISP_PAD_SINK_VIDEO); + + sink_fmt->width = MALI_C55_DEFAULT_WIDTH; + sink_fmt->height = MALI_C55_DEFAULT_HEIGHT; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = MEDIA_BUS_FMT_SRGGB20_1X20; + sink_fmt->colorspace = V4L2_COLORSPACE_RAW; + sink_fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(sink_fmt->colorspace); + sink_fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(sink_fmt->colorspace); + sink_fmt->quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(false, sink_fmt->colorspace, + sink_fmt->ycbcr_enc); + + *v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SOURCE_BYPASS) = *sink_fmt; + + src_fmt->width = MALI_C55_DEFAULT_WIDTH; + src_fmt->height = MALI_C55_DEFAULT_HEIGHT; + src_fmt->field = V4L2_FIELD_NONE; + src_fmt->code = MEDIA_BUS_FMT_RGB121212_1X36; + src_fmt->colorspace = V4L2_COLORSPACE_SRGB; + src_fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(sink_fmt->colorspace); + src_fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(sink_fmt->colorspace); + src_fmt->quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(false, sink_fmt->colorspace, + sink_fmt->ycbcr_enc); + + in_crop->top = 0; + in_crop->left = 0; + in_crop->width = MALI_C55_DEFAULT_WIDTH; + in_crop->height = MALI_C55_DEFAULT_HEIGHT; + + src_fmt = v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SOURCE_STATS); + sink_fmt = v4l2_subdev_state_get_format(state, + MALI_C55_ISP_PAD_SINK_PARAMS); + + src_fmt->width = 0; + src_fmt->height = 0; + src_fmt->field = V4L2_FIELD_NONE; + src_fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; + + sink_fmt->width = 0; + sink_fmt->height = 0; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = MEDIA_BUS_FMT_METADATA_FIXED; + + return 0; +} + +static const struct v4l2_subdev_internal_ops mali_c55_isp_internal_ops = { + .init_state = mali_c55_isp_init_state, +}; + +static int mali_c55_subdev_link_validate(struct media_link *link) +{ + /* + * Skip validation for the parameters sink pad, as the source is not + * a subdevice. + */ + if (link->sink->index == MALI_C55_ISP_PAD_SINK_PARAMS) + return 0; + + return v4l2_subdev_link_validate(link); +} + +static const struct media_entity_operations mali_c55_isp_media_ops = { + .link_validate = mali_c55_subdev_link_validate, +}; + +static int mali_c55_isp_s_ctrl(struct v4l2_ctrl *ctrl) +{ + /* + * .s_ctrl() is a mandatory operation, but the driver has only a single + * read only control. If we got here, something went badly wrong. + */ + return -EINVAL; +} + +static const struct v4l2_ctrl_ops mali_c55_isp_ctrl_ops = { + .s_ctrl = mali_c55_isp_s_ctrl, +}; + +/* NOT const because the default needs to be filled in at runtime */ +static struct v4l2_ctrl_config mali_c55_isp_v4l2_custom_ctrls[] = { + { + .ops = &mali_c55_isp_ctrl_ops, + .id = V4L2_CID_MALI_C55_CAPABILITIES, + .name = "Mali-C55 ISP Capabilities", + .type = V4L2_CTRL_TYPE_BITMASK, + .min = 0, + .max = MALI_C55_GPS_PONG_FITTED | + MALI_C55_GPS_WDR_FITTED | + MALI_C55_GPS_COMPRESSION_FITTED | + MALI_C55_GPS_TEMPER_FITTED | + MALI_C55_GPS_SINTER_LITE_FITTED | + MALI_C55_GPS_SINTER_FITTED | + MALI_C55_GPS_IRIDIX_LTM_FITTED | + MALI_C55_GPS_IRIDIX_GTM_FITTED | + MALI_C55_GPS_CNR_FITTED | + MALI_C55_GPS_FRSCALER_FITTED | + MALI_C55_GPS_DS_PIPE_FITTED, + .def = 0, + }, +}; + +static int mali_c55_isp_init_controls(struct mali_c55 *mali_c55) +{ + struct v4l2_ctrl_handler *handler = &mali_c55->isp.handler; + struct v4l2_ctrl *capabilities; + int ret; + + ret = v4l2_ctrl_handler_init(handler, 1); + if (ret) + return ret; + + mali_c55_isp_v4l2_custom_ctrls[0].def = mali_c55->capabilities; + + capabilities = v4l2_ctrl_new_custom(handler, + &mali_c55_isp_v4l2_custom_ctrls[0], + NULL); + if (capabilities) + capabilities->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + if (handler->error) { + dev_err(mali_c55->dev, "failed to register capabilities control\n"); + ret = handler->error; + v4l2_ctrl_handler_free(handler); + return ret; + } + + mali_c55->isp.sd.ctrl_handler = handler; + + return 0; +} + +int mali_c55_register_isp(struct mali_c55 *mali_c55) +{ + struct mali_c55_isp *isp = &mali_c55->isp; + struct v4l2_subdev *sd = &isp->sd; + int ret; + + isp->mali_c55 = mali_c55; + + v4l2_subdev_init(sd, &mali_c55_isp_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->entity.ops = &mali_c55_isp_media_ops; + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_ISP; + sd->internal_ops = &mali_c55_isp_internal_ops; + strscpy(sd->name, MALI_C55_DRIVER_NAME " isp", sizeof(sd->name)); + + isp->pads[MALI_C55_ISP_PAD_SINK_VIDEO].flags = MEDIA_PAD_FL_SINK | + MEDIA_PAD_FL_MUST_CONNECT; + isp->pads[MALI_C55_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE; + isp->pads[MALI_C55_ISP_PAD_SOURCE_BYPASS].flags = MEDIA_PAD_FL_SOURCE; + isp->pads[MALI_C55_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE; + isp->pads[MALI_C55_ISP_PAD_SINK_PARAMS].flags = MEDIA_PAD_FL_SINK; + + ret = media_entity_pads_init(&sd->entity, MALI_C55_ISP_NUM_PADS, + isp->pads); + if (ret) + return ret; + + ret = mali_c55_isp_init_controls(mali_c55); + if (ret) + goto err_cleanup_media_entity; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_free_ctrl_handler; + + ret = v4l2_device_register_subdev(&mali_c55->v4l2_dev, sd); + if (ret) + goto err_cleanup_subdev; + + mutex_init(&isp->capture_lock); + + return 0; + +err_cleanup_subdev: + v4l2_subdev_cleanup(sd); +err_free_ctrl_handler: + v4l2_ctrl_handler_free(&isp->handler); +err_cleanup_media_entity: + media_entity_cleanup(&sd->entity); + isp->mali_c55 = NULL; + + return ret; +} + +void mali_c55_unregister_isp(struct mali_c55 *mali_c55) +{ + struct mali_c55_isp *isp = &mali_c55->isp; + + if (!isp->mali_c55) + return; + + mutex_destroy(&isp->capture_lock); + v4l2_device_unregister_subdev(&isp->sd); + v4l2_subdev_cleanup(&isp->sd); + media_entity_cleanup(&isp->sd.entity); +} diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-params.c b/drivers/media/platform/arm/mali-c55/mali-c55-params.c new file mode 100644 index 000000000000..082cda4f4f63 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/mali-c55-params.c @@ -0,0 +1,819 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM Mali-C55 ISP Driver - Configuration parameters output device + * + * Copyright (C) 2025 Ideas on Board Oy + */ +#include <linux/media/arm/mali-c55-config.h> +#include <linux/pm_runtime.h> + +#include <media/media-entity.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-isp.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "mali-c55-common.h" +#include "mali-c55-registers.h" + +/** + * union mali_c55_params_block - Generalisation of a parameter block + * + * This union allows the driver to treat a block as a generic pointer to this + * union and safely access the header and block-specific struct without having + * to resort to casting. The header member is accessed first, and the type field + * checked which allows the driver to determine which of the other members + * should be used. The data member at the end allows a pointer to an address + * within the data member of :c:type:`mali_c55_params_buffer` to initialise a + * union variable. + * + * @header: Pointer to the shared header struct embedded as the + * first member of all the possible other members (except + * @data). This member would be accessed first and the type + * field checked to determine which of the other members + * should be accessed. + * @sensor_offs: For header->type == MALI_C55_PARAM_BLOCK_SENSOR_OFFS + * @aexp_hist: For header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST and + * header->type == MALI_C55_PARAM_BLOCK_AEXP_IHIST + * @aexp_weights: For header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS + * and header->type = MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS + * @digital_gain: For header->type == MALI_C55_PARAM_BLOCK_DIGITAL_GAIN + * @awb_gains: For header->type == MALI_C55_PARAM_BLOCK_AWB_GAINS and + * header->type = MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP + * @awb_config: For header->type == MALI_C55_PARAM_MESH_SHADING_CONFIG + * @shading_config: For header->type == MALI_C55_PARAM_MESH_SHADING_SELECTION + * @shading_selection: For header->type == MALI_C55_PARAM_BLOCK_SENSOR_OFFS + * @data: Allows easy initialisation of a union variable with a + * pointer into a __u8 array. + */ +union mali_c55_params_block { + const struct v4l2_isp_params_block_header *header; + const struct mali_c55_params_sensor_off_preshading *sensor_offs; + const struct mali_c55_params_aexp_hist *aexp_hist; + const struct mali_c55_params_aexp_weights *aexp_weights; + const struct mali_c55_params_digital_gain *digital_gain; + const struct mali_c55_params_awb_gains *awb_gains; + const struct mali_c55_params_awb_config *awb_config; + const struct mali_c55_params_mesh_shading_config *shading_config; + const struct mali_c55_params_mesh_shading_selection *shading_selection; + const __u8 *data; +}; + +typedef void (*mali_c55_params_handler)(struct mali_c55 *mali_c55, + union mali_c55_params_block block); + +#define to_mali_c55_params_buf(vbuf) \ + container_of(vbuf, struct mali_c55_params_buf, vb) + +static void mali_c55_params_sensor_offs(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_sensor_off_preshading *p; + __u32 global_offset; + + p = block.sensor_offs; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BYPASS_3, + MALI_C55_REG_BYPASS_3_SENSOR_OFFSET_PRE_SH, + MALI_C55_REG_BYPASS_3_SENSOR_OFFSET_PRE_SH); + return; + } + + if (!(p->chan00 || p->chan01 || p->chan10 || p->chan11)) + return; + + mali_c55_ctx_write(mali_c55, MALI_C55_REG_SENSOR_OFF_PRE_SHA_00, + p->chan00 & MALI_C55_SENSOR_OFF_PRE_SHA_MASK); + mali_c55_ctx_write(mali_c55, MALI_C55_REG_SENSOR_OFF_PRE_SHA_01, + p->chan01 & MALI_C55_SENSOR_OFF_PRE_SHA_MASK); + mali_c55_ctx_write(mali_c55, MALI_C55_REG_SENSOR_OFF_PRE_SHA_10, + p->chan10 & MALI_C55_SENSOR_OFF_PRE_SHA_MASK); + mali_c55_ctx_write(mali_c55, MALI_C55_REG_SENSOR_OFF_PRE_SHA_11, + p->chan11 & MALI_C55_SENSOR_OFF_PRE_SHA_MASK); + + /* + * The average offset is applied as a global offset for the digital + * gain block + */ + global_offset = (p->chan00 + p->chan01 + p->chan10 + p->chan11) >> 2; + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_DIGITAL_GAIN_OFFSET, + MALI_C55_DIGITAL_GAIN_OFFSET_MASK, + global_offset); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_BYPASS_3, + MALI_C55_REG_BYPASS_3_SENSOR_OFFSET_PRE_SH, + 0x00); +} + +static void mali_c55_params_aexp_hist(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_aexp_hist *params; + u32 disable_mask; + u32 disable_val; + u32 base; + + if (block.header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST) { + disable_mask = MALI_C55_AEXP_HIST_DISABLE_MASK; + disable_val = MALI_C55_AEXP_HIST_DISABLE; + base = MALI_C55_REG_AEXP_HIST_BASE; + } else { + disable_mask = MALI_C55_AEXP_IHIST_DISABLE_MASK; + disable_val = MALI_C55_AEXP_IHIST_DISABLE; + base = MALI_C55_REG_AEXP_IHIST_BASE; + } + + params = block.aexp_hist; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, + disable_mask, disable_val); + return; + } + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, + disable_mask, false); + + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SKIP_OFFSET, + MALI_C55_AEXP_HIST_SKIP_X_MASK, params->skip_x); + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SKIP_OFFSET, + MALI_C55_AEXP_HIST_OFFSET_X_MASK, + MALI_C55_AEXP_HIST_OFFSET_X(params->offset_x)); + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SKIP_OFFSET, + MALI_C55_AEXP_HIST_SKIP_Y_MASK, + MALI_C55_AEXP_HIST_SKIP_Y(params->skip_y)); + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SKIP_OFFSET, + MALI_C55_AEXP_HIST_OFFSET_Y_MASK, + MALI_C55_AEXP_HIST_OFFSET_Y(params->offset_y)); + + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SCALE_OFFSET, + MALI_C55_AEXP_HIST_SCALE_BOTTOM_MASK, + params->scale_bottom); + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_SCALE_OFFSET, + MALI_C55_AEXP_HIST_SCALE_TOP_MASK, + MALI_C55_AEXP_HIST_SCALE_TOP(params->scale_top)); + + mali_c55_ctx_update_bits(mali_c55, base + MALI_C55_AEXP_HIST_PLANE_MODE_OFFSET, + MALI_C55_AEXP_HIST_PLANE_MODE_MASK, + params->plane_mode); + + if (block.header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST) + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, + MALI_C55_AEXP_HIST_SWITCH_MASK, + MALI_C55_AEXP_HIST_SWITCH(params->tap_point)); +} + +static void +mali_c55_params_aexp_hist_weights(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_aexp_weights *params; + u32 base, val, addr; + + params = block.aexp_weights; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) + return; + + base = block.header->type == MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS ? + MALI_C55_REG_AEXP_HIST_BASE : + MALI_C55_REG_AEXP_IHIST_BASE; + + mali_c55_ctx_update_bits(mali_c55, + base + MALI_C55_AEXP_HIST_NODES_USED_OFFSET, + MALI_C55_AEXP_HIST_NODES_USED_HORIZ_MASK, + params->nodes_used_horiz); + mali_c55_ctx_update_bits(mali_c55, + base + MALI_C55_AEXP_HIST_NODES_USED_OFFSET, + MALI_C55_AEXP_HIST_NODES_USED_VERT_MASK, + MALI_C55_AEXP_HIST_NODES_USED_VERT(params->nodes_used_vert)); + + /* + * The zone weights array is a 225-element array of u8 values, but that + * is a bit annoying to handle given the ISP expects 32-bit writes. We + * just reinterpret it as 56-element array of 32-bit values for the + * purposes of this transaction. The last register is handled separately + * to stop static analysers worrying about buffer overflow. The 3 bytes + * of additional space at the end of the write is just padding for the + * array of weights in the ISP memory space anyway, so there's no risk + * of overwriting other registers. + */ + for (unsigned int i = 0; i < 56; i++) { + val = ((u32 *)params->zone_weights)[i] + & MALI_C55_AEXP_HIST_ZONE_WEIGHT_MASK; + addr = base + MALI_C55_AEXP_HIST_ZONE_WEIGHTS_OFFSET + (4 * i); + + mali_c55_ctx_write(mali_c55, addr, val); + } + + val = params->zone_weights[MALI_C55_MAX_ZONES - 1]; + addr = base + MALI_C55_AEXP_HIST_ZONE_WEIGHTS_OFFSET + (4 * 56); +} + +static void mali_c55_params_digital_gain(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_digital_gain *dgain; + u32 gain; + + dgain = block.digital_gain; + + /* + * If the block is flagged as disabled we write a gain of 1.0, which in + * Q5.8 format is 256. + */ + gain = block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE ? + 256 : dgain->gain; + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_DIGITAL_GAIN, + MALI_C55_DIGITAL_GAIN_MASK, + gain); +} + +static void mali_c55_params_awb_gains(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_awb_gains *gains; + u32 gain00, gain01, gain10, gain11; + + gains = block.awb_gains; + + /* + * There are two places AWB gains can be set in the ISP; one affects the + * image output data and the other affects the statistics for the + * AEXP-0 tap point. + */ + u32 addr1 = block.header->type == MALI_C55_PARAM_BLOCK_AWB_GAINS ? + MALI_C55_REG_AWB_GAINS1 : + MALI_C55_REG_AWB_GAINS1_AEXP; + u32 addr2 = block.header->type == MALI_C55_PARAM_BLOCK_AWB_GAINS ? + MALI_C55_REG_AWB_GAINS2 : + MALI_C55_REG_AWB_GAINS2_AEXP; + + /* If the block is flagged disabled, set all of the gains to 1.0 */ + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + gain00 = 256; + gain01 = 256; + gain10 = 256; + gain11 = 256; + } else { + gain00 = gains->gain00; + gain01 = gains->gain01; + gain10 = gains->gain10; + gain11 = gains->gain11; + } + + mali_c55_ctx_update_bits(mali_c55, addr1, MALI_C55_AWB_GAIN00_MASK, + gain00); + mali_c55_ctx_update_bits(mali_c55, addr1, MALI_C55_AWB_GAIN01_MASK, + MALI_C55_AWB_GAIN01(gain01)); + mali_c55_ctx_update_bits(mali_c55, addr2, MALI_C55_AWB_GAIN10_MASK, + gain10); + mali_c55_ctx_update_bits(mali_c55, addr2, MALI_C55_AWB_GAIN11_MASK, + MALI_C55_AWB_GAIN11(gain11)); +} + +static void mali_c55_params_awb_config(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_awb_config *params; + + params = block.awb_config; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, + MALI_C55_AWB_DISABLE_MASK, + MALI_C55_AWB_DISABLE_MASK); + return; + } + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, + MALI_C55_AWB_DISABLE_MASK, false); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_STATS_MODE, + MALI_C55_AWB_STATS_MODE_MASK, params->stats_mode); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_WHITE_LEVEL, + MALI_C55_AWB_WHITE_LEVEL_MASK, params->white_level); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_BLACK_LEVEL, + MALI_C55_AWB_BLACK_LEVEL_MASK, params->black_level); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CR_MAX, + MALI_C55_AWB_CR_MAX_MASK, params->cr_max); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CR_MIN, + MALI_C55_AWB_CR_MIN_MASK, params->cr_min); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CB_MAX, + MALI_C55_AWB_CB_MAX_MASK, params->cb_max); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CB_MIN, + MALI_C55_AWB_CB_MIN_MASK, params->cb_min); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_NODES_USED, + MALI_C55_AWB_NODES_USED_HORIZ_MASK, + params->nodes_used_horiz); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_NODES_USED, + MALI_C55_AWB_NODES_USED_VERT_MASK, + MALI_C55_AWB_NODES_USED_VERT(params->nodes_used_vert)); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CR_HIGH, + MALI_C55_AWB_CR_HIGH_MASK, params->cr_high); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CR_LOW, + MALI_C55_AWB_CR_LOW_MASK, params->cr_low); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CB_HIGH, + MALI_C55_AWB_CB_HIGH_MASK, params->cb_high); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_AWB_CB_LOW, + MALI_C55_AWB_CB_LOW_MASK, params->cb_low); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_METERING_CONFIG, + MALI_C55_AWB_SWITCH_MASK, + MALI_C55_AWB_SWITCH(params->tap_point)); +} + +static void mali_c55_params_lsc_config(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_mesh_shading_config *params; + unsigned int i; + u32 addr; + + params = block.shading_config; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, + MALI_C55_MESH_SHADING_ENABLE_MASK, + false); + return; + } + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, + MALI_C55_MESH_SHADING_ENABLE_MASK, true); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, + MALI_C55_MESH_SHADING_MESH_SHOW_MASK, + MALI_C55_MESH_SHADING_MESH_SHOW(params->mesh_show)); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, + MALI_C55_MESH_SHADING_SCALE_MASK, + MALI_C55_MESH_SHADING_SCALE(params->mesh_scale)); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, + MALI_C55_MESH_SHADING_PAGE_R_MASK, + MALI_C55_MESH_SHADING_PAGE_R(params->mesh_page_r)); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, + MALI_C55_MESH_SHADING_PAGE_G_MASK, + MALI_C55_MESH_SHADING_PAGE_G(params->mesh_page_g)); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, + MALI_C55_MESH_SHADING_PAGE_B_MASK, + MALI_C55_MESH_SHADING_PAGE_B(params->mesh_page_b)); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, + MALI_C55_MESH_SHADING_MESH_WIDTH_MASK, + MALI_C55_MESH_SHADING_MESH_WIDTH(params->mesh_width)); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_CONFIG, + MALI_C55_MESH_SHADING_MESH_HEIGHT_MASK, + MALI_C55_MESH_SHADING_MESH_HEIGHT(params->mesh_height)); + + for (i = 0; i < MALI_C55_NUM_MESH_SHADING_ELEMENTS; i++) { + addr = MALI_C55_REG_MESH_SHADING_TABLES + (i * 4); + mali_c55_ctx_write(mali_c55, addr, params->mesh[i]); + } +} + +static void mali_c55_params_lsc_selection(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_mesh_shading_selection *params; + + params = block.shading_selection; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) + return; + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA_BANK, + MALI_C55_MESH_SHADING_ALPHA_BANK_R_MASK, + params->mesh_alpha_bank_r); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA_BANK, + MALI_C55_MESH_SHADING_ALPHA_BANK_G_MASK, + MALI_C55_MESH_SHADING_ALPHA_BANK_G(params->mesh_alpha_bank_g)); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA_BANK, + MALI_C55_MESH_SHADING_ALPHA_BANK_B_MASK, + MALI_C55_MESH_SHADING_ALPHA_BANK_B(params->mesh_alpha_bank_b)); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA, + MALI_C55_MESH_SHADING_ALPHA_R_MASK, + params->mesh_alpha_r); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA, + MALI_C55_MESH_SHADING_ALPHA_G_MASK, + MALI_C55_MESH_SHADING_ALPHA_G(params->mesh_alpha_g)); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_MESH_SHADING_ALPHA, + MALI_C55_MESH_SHADING_ALPHA_B_MASK, + MALI_C55_MESH_SHADING_ALPHA_B(params->mesh_alpha_b)); + + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_MESH_SHADING_MESH_STRENGTH, + MALI_c55_MESH_STRENGTH_MASK, + params->mesh_strength); +} + +static const mali_c55_params_handler mali_c55_params_handlers[] = { + [MALI_C55_PARAM_BLOCK_SENSOR_OFFS] = &mali_c55_params_sensor_offs, + [MALI_C55_PARAM_BLOCK_AEXP_HIST] = &mali_c55_params_aexp_hist, + [MALI_C55_PARAM_BLOCK_AEXP_IHIST] = &mali_c55_params_aexp_hist, + [MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS] = &mali_c55_params_aexp_hist_weights, + [MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS] = &mali_c55_params_aexp_hist_weights, + [MALI_C55_PARAM_BLOCK_DIGITAL_GAIN] = &mali_c55_params_digital_gain, + [MALI_C55_PARAM_BLOCK_AWB_GAINS] = &mali_c55_params_awb_gains, + [MALI_C55_PARAM_BLOCK_AWB_CONFIG] = &mali_c55_params_awb_config, + [MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP] = &mali_c55_params_awb_gains, + [MALI_C55_PARAM_MESH_SHADING_CONFIG] = &mali_c55_params_lsc_config, + [MALI_C55_PARAM_MESH_SHADING_SELECTION] = &mali_c55_params_lsc_selection, +}; + +static const struct v4l2_isp_params_block_type_info +mali_c55_params_block_types_info[] = { + [MALI_C55_PARAM_BLOCK_SENSOR_OFFS] = { + .size = sizeof(struct mali_c55_params_sensor_off_preshading), + }, + [MALI_C55_PARAM_BLOCK_AEXP_HIST] = { + .size = sizeof(struct mali_c55_params_aexp_hist), + }, + [MALI_C55_PARAM_BLOCK_AEXP_IHIST] = { + .size = sizeof(struct mali_c55_params_aexp_hist), + }, + [MALI_C55_PARAM_BLOCK_AEXP_HIST_WEIGHTS] = { + .size = sizeof(struct mali_c55_params_aexp_weights), + }, + [MALI_C55_PARAM_BLOCK_AEXP_IHIST_WEIGHTS] = { + .size = sizeof(struct mali_c55_params_aexp_weights), + }, + [MALI_C55_PARAM_BLOCK_DIGITAL_GAIN] = { + .size = sizeof(struct mali_c55_params_digital_gain), + }, + [MALI_C55_PARAM_BLOCK_AWB_GAINS] = { + .size = sizeof(struct mali_c55_params_awb_gains), + }, + [MALI_C55_PARAM_BLOCK_AWB_CONFIG] = { + .size = sizeof(struct mali_c55_params_awb_config), + }, + [MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP] = { + .size = sizeof(struct mali_c55_params_awb_gains), + }, + [MALI_C55_PARAM_MESH_SHADING_CONFIG] = { + .size = sizeof(struct mali_c55_params_mesh_shading_config), + }, + [MALI_C55_PARAM_MESH_SHADING_SELECTION] = { + .size = sizeof(struct mali_c55_params_mesh_shading_selection), + }, +}; + +static_assert(ARRAY_SIZE(mali_c55_params_handlers) == + ARRAY_SIZE(mali_c55_params_block_types_info)); + +static int mali_c55_params_enum_fmt_meta_out(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + + if (f->mbus_code && f->mbus_code != MEDIA_BUS_FMT_METADATA_FIXED) + return -EINVAL; + + f->pixelformat = V4L2_META_FMT_MALI_C55_PARAMS; + + return 0; +} + +static int mali_c55_params_g_fmt_meta_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + static const struct v4l2_meta_format mfmt = { + .dataformat = V4L2_META_FMT_MALI_C55_PARAMS, + .buffersize = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE), + }; + + f->fmt.meta = mfmt; + + return 0; +} + +static int mali_c55_params_querycap(struct file *file, + void *priv, struct v4l2_capability *cap) +{ + strscpy(cap->driver, MALI_C55_DRIVER_NAME, sizeof(cap->driver)); + strscpy(cap->card, "ARM Mali-C55 ISP", sizeof(cap->card)); + + return 0; +} + +static const struct v4l2_ioctl_ops mali_c55_params_v4l2_ioctl_ops = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_fmt_meta_out = mali_c55_params_enum_fmt_meta_out, + .vidioc_g_fmt_meta_out = mali_c55_params_g_fmt_meta_out, + .vidioc_s_fmt_meta_out = mali_c55_params_g_fmt_meta_out, + .vidioc_try_fmt_meta_out = mali_c55_params_g_fmt_meta_out, + .vidioc_querycap = mali_c55_params_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_file_operations mali_c55_params_v4l2_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +static int +mali_c55_params_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + if (*num_planes && *num_planes > 1) + return -EINVAL; + + if (sizes[0] && sizes[0] < v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)) + return -EINVAL; + + *num_planes = 1; + + if (!sizes[0]) + sizes[0] = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE); + + return 0; +} + +static int mali_c55_params_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); + + buf->config = kvmalloc(v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE), + GFP_KERNEL); + if (!buf->config) + return -ENOMEM; + + return 0; +} + +static void mali_c55_params_buf_cleanup(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); + + kvfree(buf->config); + buf->config = NULL; +} + +static int mali_c55_params_buf_prepare(struct vb2_buffer *vb) +{ + struct mali_c55_params *params = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); + struct v4l2_isp_params_buffer *config = vb2_plane_vaddr(vb, 0); + struct mali_c55 *mali_c55 = params->mali_c55; + int ret; + + if (config->version != MALI_C55_PARAM_BUFFER_V1) { + dev_dbg(mali_c55->dev, + "Unsupported extensible format version: %u\n", + config->version); + return -EINVAL; + } + + ret = v4l2_isp_params_validate_buffer_size(mali_c55->dev, vb, + v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); + if (ret) + return ret; + + /* + * Copy the parameters buffer provided by userspace to the internal + * scratch buffer. This protects against the chance of userspace making + * changed to the buffer content whilst the driver processes it. + */ + + memcpy(buf->config, config, v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); + + return v4l2_isp_params_validate_buffer(mali_c55->dev, vb, buf->config, + mali_c55_params_block_types_info, + ARRAY_SIZE(mali_c55_params_block_types_info)); +} + +static void mali_c55_params_buf_queue(struct vb2_buffer *vb) +{ + struct mali_c55_params *params = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); + + spin_lock(¶ms->buffers.lock); + list_add_tail(&buf->queue, ¶ms->buffers.queue); + spin_unlock(¶ms->buffers.lock); +} + +static void mali_c55_params_return_buffers(struct mali_c55_params *params, + enum vb2_buffer_state state) +{ + struct mali_c55_params_buf *buf, *tmp; + + guard(spinlock)(¶ms->buffers.lock); + + list_for_each_entry_safe(buf, tmp, ¶ms->buffers.queue, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } +} + +static int mali_c55_params_start_streaming(struct vb2_queue *q, + unsigned int count) +{ + struct mali_c55_params *params = vb2_get_drv_priv(q); + struct mali_c55 *mali_c55 = params->mali_c55; + int ret; + + ret = pm_runtime_resume_and_get(mali_c55->dev); + if (ret) + goto err_return_buffers; + + ret = video_device_pipeline_alloc_start(¶ms->vdev); + if (ret) + goto err_pm_put; + + if (mali_c55_pipeline_ready(mali_c55)) { + ret = v4l2_subdev_enable_streams(&mali_c55->isp.sd, + MALI_C55_ISP_PAD_SOURCE_VIDEO, + BIT(0)); + if (ret < 0) + goto err_stop_pipeline; + } + + return 0; + +err_stop_pipeline: + video_device_pipeline_stop(¶ms->vdev); +err_pm_put: + pm_runtime_put_autosuspend(mali_c55->dev); +err_return_buffers: + mali_c55_params_return_buffers(params, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void mali_c55_params_stop_streaming(struct vb2_queue *q) +{ + struct mali_c55_params *params = vb2_get_drv_priv(q); + struct mali_c55 *mali_c55 = params->mali_c55; + struct mali_c55_isp *isp = &mali_c55->isp; + + if (mali_c55_pipeline_ready(mali_c55)) { + if (v4l2_subdev_is_streaming(&isp->sd)) + v4l2_subdev_disable_streams(&isp->sd, + MALI_C55_ISP_PAD_SOURCE_VIDEO, + BIT(0)); + } + + video_device_pipeline_stop(¶ms->vdev); + mali_c55_params_return_buffers(params, VB2_BUF_STATE_ERROR); + pm_runtime_put_autosuspend(params->mali_c55->dev); +} + +static const struct vb2_ops mali_c55_params_vb2_ops = { + .queue_setup = mali_c55_params_queue_setup, + .buf_init = mali_c55_params_buf_init, + .buf_cleanup = mali_c55_params_buf_cleanup, + .buf_queue = mali_c55_params_buf_queue, + .buf_prepare = mali_c55_params_buf_prepare, + .start_streaming = mali_c55_params_start_streaming, + .stop_streaming = mali_c55_params_stop_streaming, +}; + +void mali_c55_params_write_config(struct mali_c55 *mali_c55) +{ + struct mali_c55_params *params = &mali_c55->params; + struct v4l2_isp_params_buffer *config; + struct mali_c55_params_buf *buf; + size_t block_offset = 0; + size_t max_offset; + + spin_lock(¶ms->buffers.lock); + + buf = list_first_entry_or_null(¶ms->buffers.queue, + struct mali_c55_params_buf, queue); + if (buf) + list_del(&buf->queue); + spin_unlock(¶ms->buffers.lock); + + if (!buf) + return; + + buf->vb.sequence = mali_c55->isp.frame_sequence; + config = buf->config; + + max_offset = config->data_size; + + /* + * Walk the list of parameter blocks and process them. No validation is + * done here, as the contents of the config buffer are already checked + * when the buffer is queued. + */ + while (max_offset && block_offset < max_offset) { + union mali_c55_params_block block; + mali_c55_params_handler handler; + + block.data = &config->data[block_offset]; + + /* We checked the array index already in .buf_queue() */ + handler = mali_c55_params_handlers[block.header->type]; + handler(mali_c55, block); + + block_offset += block.header->size; + } + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); +} + +void mali_c55_unregister_params(struct mali_c55 *mali_c55) +{ + struct mali_c55_params *params = &mali_c55->params; + + if (!video_is_registered(¶ms->vdev)) + return; + + vb2_video_unregister_device(¶ms->vdev); + media_entity_cleanup(¶ms->vdev.entity); + mutex_destroy(¶ms->lock); +} + +int mali_c55_register_params(struct mali_c55 *mali_c55) +{ + struct mali_c55_params *params = &mali_c55->params; + struct video_device *vdev = ¶ms->vdev; + struct vb2_queue *vb2q = ¶ms->queue; + int ret; + + mutex_init(¶ms->lock); + INIT_LIST_HEAD(¶ms->buffers.queue); + spin_lock_init(¶ms->buffers.lock); + + params->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(¶ms->vdev.entity, 1, ¶ms->pad); + if (ret) + goto err_destroy_mutex; + + vb2q->type = V4L2_BUF_TYPE_META_OUTPUT; + vb2q->io_modes = VB2_MMAP | VB2_DMABUF; + vb2q->drv_priv = params; + vb2q->mem_ops = &vb2_dma_contig_memops; + vb2q->ops = &mali_c55_params_vb2_ops; + vb2q->buf_struct_size = sizeof(struct mali_c55_params_buf); + vb2q->min_queued_buffers = 1; + vb2q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vb2q->lock = ¶ms->lock; + vb2q->dev = mali_c55->dev; + + ret = vb2_queue_init(vb2q); + if (ret) { + dev_err(mali_c55->dev, "params vb2 queue init failed\n"); + goto err_cleanup_entity; + } + + strscpy(params->vdev.name, "mali-c55 3a params", + sizeof(params->vdev.name)); + vdev->release = video_device_release_empty; + vdev->fops = &mali_c55_params_v4l2_fops; + vdev->ioctl_ops = &mali_c55_params_v4l2_ioctl_ops; + vdev->lock = ¶ms->lock; + vdev->v4l2_dev = &mali_c55->v4l2_dev; + vdev->queue = ¶ms->queue; + vdev->device_caps = V4L2_CAP_META_OUTPUT | V4L2_CAP_STREAMING | + V4L2_CAP_IO_MC; + vdev->vfl_dir = VFL_DIR_TX; + video_set_drvdata(vdev, params); + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(mali_c55->dev, + "failed to register params video device\n"); + goto err_release_vb2q; + } + + params->mali_c55 = mali_c55; + + return 0; + +err_release_vb2q: + vb2_queue_release(vb2q); +err_cleanup_entity: + media_entity_cleanup(¶ms->vdev.entity); +err_destroy_mutex: + mutex_destroy(¶ms->lock); + + return ret; +} diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-registers.h b/drivers/media/platform/arm/mali-c55/mali-c55-registers.h new file mode 100644 index 000000000000..f5a148add1c8 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/mali-c55-registers.h @@ -0,0 +1,449 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * ARM Mali-C55 ISP Driver - Register definitions + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#ifndef _MALI_C55_REGISTERS_H +#define _MALI_C55_REGISTERS_H + +#include <linux/bits.h> + +/* ISP Common 0x00000 - 0x000ff */ + +#define MALI_C55_REG_API 0x00000 +#define MALI_C55_REG_PRODUCT 0x00004 +#define MALI_C55_REG_VERSION 0x00008 +#define MALI_C55_REG_REVISION 0x0000c +#define MALI_C55_REG_PULSE_MODE 0x0003c +#define MALI_C55_REG_INPUT_MODE_REQUEST 0x0009c +#define MALI_C55_INPUT_SAFE_STOP 0x00 +#define MALI_C55_INPUT_SAFE_START 0x01 +#define MALI_C55_REG_MODE_STATUS 0x000a0 +#define MALI_C55_REG_INTERRUPT_MASK_VECTOR 0x00030 +#define MALI_C55_INTERRUPT_MASK_ALL GENMASK(31, 0) + +#define MALI_C55_REG_GLOBAL_MONITOR 0x00050 + +#define MALI_C55_REG_GEN_VIDEO 0x00080 +#define MALI_C55_REG_GEN_VIDEO_ON_MASK BIT(0) +#define MALI_C55_REG_GEN_VIDEO_MULTI_MASK BIT(1) +#define MALI_C55_REG_GEN_PREFETCH_MASK GENMASK(31, 16) + +#define MALI_C55_REG_MCU_CONFIG 0x00020 +#define MALI_C55_REG_MCU_CONFIG_OVERRIDE_MASK BIT(0) +#define MALI_C55_REG_MCU_CONFIG_WRITE_MASK BIT(1) +#define MALI_C55_MCU_CONFIG_WRITE(x) ((x) << 1) +#define MALI_C55_REG_MCU_CONFIG_WRITE_PING BIT(1) +#define MALI_C55_REG_MCU_CONFIG_WRITE_PONG 0x00 +#define MALI_C55_REG_MULTI_CONTEXT_MODE_MASK BIT(8) +#define MALI_C55_REG_PING_PONG_READ 0x00024 +#define MALI_C55_REG_PING_PONG_READ_MASK BIT(2) + +#define MALI_C55_REG_INTERRUPT_CLEAR_VECTOR 0x00034 +#define MALI_C55_REG_INTERRUPT_CLEAR 0x00040 +#define MALI_C55_REG_INTERRUPT_STATUS_VECTOR 0x00044 + +enum mali_c55_interrupts { + MALI_C55_IRQ_ISP_START, + MALI_C55_IRQ_ISP_DONE, + MALI_C55_IRQ_MCM_ERROR, + MALI_C55_IRQ_BROKEN_FRAME_ERROR, + MALI_C55_IRQ_MET_AF_DONE, + MALI_C55_IRQ_MET_AEXP_DONE, + MALI_C55_IRQ_MET_AWB_DONE, + MALI_C55_IRQ_AEXP_1024_DONE, + MALI_C55_IRQ_IRIDIX_MET_DONE, + MALI_C55_IRQ_LUT_INIT_DONE, + MALI_C55_IRQ_FR_Y_DONE, + MALI_C55_IRQ_FR_UV_DONE, + MALI_C55_IRQ_DS_Y_DONE, + MALI_C55_IRQ_DS_UV_DONE, + MALI_C55_IRQ_LINEARIZATION_DONE, + MALI_C55_IRQ_RAW_FRONTEND_DONE, + MALI_C55_IRQ_NOISE_REDUCTION_DONE, + MALI_C55_IRQ_IRIDIX_DONE, + MALI_C55_IRQ_BAYER2RGB_DONE, + MALI_C55_IRQ_WATCHDOG_TIMER, + MALI_C55_IRQ_FRAME_COLLISION, + MALI_C55_IRQ_UNUSED, + MALI_C55_IRQ_DMA_ERROR, + MALI_C55_IRQ_INPUT_STOPPED, + MALI_C55_IRQ_MET_AWB_TARGET1_HIT, + MALI_C55_IRQ_MET_AWB_TARGET2_HIT, + MALI_C55_NUM_IRQ_BITS +}; + +#define MALI_C55_INTERRUPT_BIT(x) BIT(x) + +#define MALI_C55_REG_GLOBAL_PARAMETER_STATUS 0x00068 +#define MALI_C55_GPS_PONG_FITTED BIT(0) +#define MALI_C55_GPS_WDR_FITTED BIT(1) +#define MALI_C55_GPS_COMPRESSION_FITTED BIT(2) +#define MALI_C55_GPS_TEMPER_FITTED BIT(3) +#define MALI_C55_GPS_SINTER_LITE_FITTED BIT(4) +#define MALI_C55_GPS_SINTER_FITTED BIT(5) +#define MALI_C55_GPS_IRIDIX_LTM_FITTED BIT(6) +#define MALI_C55_GPS_IRIDIX_GTM_FITTED BIT(7) +#define MALI_C55_GPS_CNR_FITTED BIT(8) +#define MALI_C55_GPS_FRSCALER_FITTED BIT(9) +#define MALI_C55_GPS_DS_PIPE_FITTED BIT(10) + +#define MALI_C55_REG_BLANKING 0x00084 +#define MALI_C55_REG_HBLANK_MASK GENMASK(15, 0) +#define MALI_C55_REG_VBLANK_MASK GENMASK(31, 16) +#define MALI_C55_VBLANK(x) ((x) << 16) + +#define MALI_C55_REG_HC_START 0x00088 +#define MALI_C55_HC_START(h) (((h) & 0xffff) << 16) +#define MALI_C55_REG_HC_SIZE 0x0008c +#define MALI_C55_HC_SIZE(h) ((h) & 0xffff) +#define MALI_C55_REG_VC_START_SIZE 0x00094 +#define MALI_C55_VC_START(v) ((v) & 0xffff) +#define MALI_C55_VC_SIZE(v) (((v) & 0xffff) << 16) + +#define MALI_C55_REG_1024BIN_HIST 0x054a8 +#define MALI_C55_1024BIN_HIST_SIZE 4096 + +/* Ping/Pong Configuration Space */ +#define MALI_C55_REG_BASE_ADDR 0x18e88 +#define MALI_C55_REG_BYPASS_0 0x18eac +#define MALI_C55_REG_BYPASS_0_VIDEO_TEST BIT(0) +#define MALI_C55_REG_BYPASS_0_INPUT_FMT BIT(1) +#define MALI_C55_REG_BYPASS_0_DECOMPANDER BIT(2) +#define MALI_C55_REG_BYPASS_0_SENSOR_OFFSET_WDR BIT(3) +#define MALI_C55_REG_BYPASS_0_GAIN_WDR BIT(4) +#define MALI_C55_REG_BYPASS_0_FRAME_STITCH BIT(5) +#define MALI_C55_REG_BYPASS_1 0x18eb0 +#define MALI_C55_REG_BYPASS_1_DIGI_GAIN BIT(0) +#define MALI_C55_REG_BYPASS_1_FE_SENSOR_OFFS BIT(1) +#define MALI_C55_REG_BYPASS_1_FE_SQRT BIT(2) +#define MALI_C55_REG_BYPASS_1_RAW_FE BIT(3) +#define MALI_C55_REG_BYPASS_2 0x18eb8 +#define MALI_C55_REG_BYPASS_2_SINTER BIT(0) +#define MALI_C55_REG_BYPASS_2_TEMPER BIT(1) +#define MALI_C55_REG_BYPASS_3 0x18ebc +#define MALI_C55_REG_BYPASS_3_SQUARE_BE BIT(0) +#define MALI_C55_REG_BYPASS_3_SENSOR_OFFSET_PRE_SH BIT(1) +#define MALI_C55_REG_BYPASS_3_MESH_SHADING BIT(3) +#define MALI_C55_REG_BYPASS_3_WHITE_BALANCE BIT(4) +#define MALI_C55_REG_BYPASS_3_IRIDIX BIT(5) +#define MALI_C55_REG_BYPASS_3_IRIDIX_GAIN BIT(6) +#define MALI_C55_REG_BYPASS_4 0x18ec0 +#define MALI_C55_REG_BYPASS_4_DEMOSAIC_RGB BIT(1) +#define MALI_C55_REG_BYPASS_4_PF_CORRECTION BIT(3) +#define MALI_C55_REG_BYPASS_4_CCM BIT(4) +#define MALI_C55_REG_BYPASS_4_CNR BIT(5) +#define MALI_C55_REG_FR_BYPASS 0x18ec4 +#define MALI_C55_REG_DS_BYPASS 0x18ec8 +#define MALI_C55_BYPASS_CROP BIT(0) +#define MALI_C55_BYPASS_SCALER BIT(1) +#define MALI_C55_BYPASS_GAMMA_RGB BIT(2) +#define MALI_C55_BYPASS_SHARPEN BIT(3) +#define MALI_C55_BYPASS_CS_CONV BIT(4) +#define MALI_C55_REG_ISP_RAW_BYPASS 0x18ecc +#define MALI_C55_ISP_RAW_BYPASS_BYPASS_MASK BIT(0) +#define MALI_C55_ISP_RAW_BYPASS_FR_BYPASS_MASK GENMASK(9, 8) +#define MALI_C55_ISP_RAW_BYPASS_RAW_FR_BYPASS (2 << 8) +#define MALI_C55_ISP_RAW_BYPASS_RGB_FR_BYPASS (1 << 8) +#define MALI_C55_ISP_RAW_BYPASS_DS_PIPE_DISABLE BIT(1) +#define MALI_C55_ISP_RAW_BYPASS_RAW_BYPASS BIT(0) + +#define MALI_C55_REG_ACTIVE_WIDTH_MASK 0xffff +#define MALI_C55_REG_ACTIVE_HEIGHT_MASK 0xffff0000 +#define MALI_C55_REG_BAYER_ORDER 0x18e8c +#define MALI_C55_BAYER_ORDER_MASK GENMASK(1, 0) +#define MALI_C55_BAYER_ORDER_RGGB 0 +#define MALI_C55_BAYER_ORDER_GRBG 1 +#define MALI_C55_BAYER_ORDER_GBRG 2 +#define MALI_C55_BAYER_ORDER_BGGR 3 + +#define MALI_C55_REG_METERING_CONFIG 0x18ed0 +#define MALI_C55_5BIN_HIST_DISABLE_MASK BIT(0) +#define MALI_C55_5BIN_HIST_SWITCH_MASK GENMASK(2, 1) +#define MALI_C55_5BIN_HIST_SWITCH(x) ((x) << 1) +#define MALI_C55_AF_DISABLE_MASK BIT(4) +#define MALI_C55_AF_SWITCH_MASK BIT(5) +#define MALI_C55_AWB_DISABLE_MASK BIT(8) +#define MALI_C55_AWB_SWITCH_MASK BIT(9) +#define MALI_C55_AWB_SWITCH(x) ((x) << 9) +#define MALI_C55_AEXP_HIST_DISABLE_MASK BIT(12) +#define MALI_C55_AEXP_HIST_DISABLE (0x01 << 12) +#define MALI_C55_AEXP_HIST_SWITCH_MASK GENMASK(14, 13) +#define MALI_C55_AEXP_HIST_SWITCH(x) ((x) << 13) +#define MALI_C55_AEXP_IHIST_DISABLE_MASK BIT(16) +#define MALI_C55_AEXP_IHIST_DISABLE (0x01 << 12) +#define MALI_C55_AEXP_SRC_MASK BIT(24) + +#define MALI_C55_REG_TPG_CH0 0x18ed8 +#define MALI_C55_TEST_PATTERN_ON_OFF BIT(0) +#define MALI_C55_TEST_PATTERN_RGB_MASK BIT(1) +#define MALI_C55_TEST_PATTERN_RGB(x) ((x) << 1) +#define MALI_C55_REG_TPG_R_BACKGROUND 0x18ee0 +#define MALI_C55_REG_TPG_G_BACKGROUND 0x18ee4 +#define MALI_C55_REG_TPG_B_BACKGROUND 0x18ee8 +#define MALI_C55_TPG_BACKGROUND_MAX 0xfffff +#define MALI_C55_REG_INPUT_WIDTH 0x18f98 +#define MALI_C55_INPUT_WIDTH_MASK GENMASK(18, 16) +#define MALI_C55_INPUT_WIDTH_8BIT (0 << 16) +#define MALI_C55_INPUT_WIDTH_10BIT (1 << 16) +#define MALI_C55_INPUT_WIDTH_12BIT (2 << 16) +#define MALI_C55_INPUT_WIDTH_14BIT (3 << 16) +#define MALI_C55_INPUT_WIDTH_16BIT (4 << 16) +#define MALI_C55_INPUT_WIDTH_20BIT (5 << 16) +#define MALI_C55_REG_SPACE_SIZE 0x4000 +#define MALI_C55_REG_CONFIG_SPACES_OFFSET 0x0ab6c +#define MALI_C55_CONFIG_SPACE_SIZE 0x1231c + +#define MALI_C55_REG_DIGITAL_GAIN 0x1926c +#define MALI_C55_DIGITAL_GAIN_MASK GENMASK(12, 0) +#define MALI_C55_REG_DIGITAL_GAIN_OFFSET 0x19270 +#define MALI_C55_DIGITAL_GAIN_OFFSET_MASK GENMASK(19, 0) + +#define MALI_C55_REG_SINTER_CONFIG 0x19348 +#define MALI_C55_SINTER_VIEW_FILTER_MASK GENMASK(1, 0) +#define MALI_C55_SINTER_SCALE_MODE_MASK GENMASK(3, 2) +#define MALI_C55_SINTER_ENABLE_MASK BIT(4) +#define MALI_C55_SINTER_FILTER_SELECT_MASK BIT(5) +#define MALI_C55_SINTER_INT_SELECT_MASK BIT(6) +#define MALI_C55_SINTER_RM_ENABLE_MASK BIT(7) + +/* Temper DMA */ +#define MALI_C55_REG_TEMPER_DMA_IO 0x1ab78 +#define MALI_C55_TEMPER_DMA_WRITE_ON BIT(0) +#define MALI_C55_TEMPER_DMA_READ_ON BIT(1) + +/* Black Level Correction Configuration */ +#define MALI_C55_REG_SENSOR_OFF_PRE_SHA_00 0x1abcc +#define MALI_C55_REG_SENSOR_OFF_PRE_SHA_01 0x1abd0 +#define MALI_C55_REG_SENSOR_OFF_PRE_SHA_10 0x1abd4 +#define MALI_C55_REG_SENSOR_OFF_PRE_SHA_11 0x1abd8 +#define MALI_C55_SENSOR_OFF_PRE_SHA_MASK 0xfffff + +/* Lens Mesh Shading Configuration */ +#define MALI_C55_REG_MESH_SHADING_TABLES 0x13074 +#define MALI_C55_REG_MESH_SHADING_CONFIG 0x1abfc +#define MALI_C55_MESH_SHADING_ENABLE_MASK BIT(0) +#define MALI_C55_MESH_SHADING_MESH_SHOW_MASK BIT(1) +#define MALI_C55_MESH_SHADING_MESH_SHOW(x) ((x) << 1) +#define MALI_C55_MESH_SHADING_SCALE_MASK GENMASK(4, 2) +#define MALI_C55_MESH_SHADING_SCALE(x) ((x) << 2) +#define MALI_C55_MESH_SHADING_PAGE_R_MASK GENMASK(9, 8) +#define MALI_C55_MESH_SHADING_PAGE_R(x) ((x) << 8) +#define MALI_C55_MESH_SHADING_PAGE_G_MASK GENMASK(11, 10) +#define MALI_C55_MESH_SHADING_PAGE_G(x) ((x) << 10) +#define MALI_C55_MESH_SHADING_PAGE_B_MASK GENMASK(13, 12) +#define MALI_C55_MESH_SHADING_PAGE_B(x) ((x) << 12) +#define MALI_C55_MESH_SHADING_MESH_WIDTH_MASK GENMASK(21, 16) +#define MALI_C55_MESH_SHADING_MESH_WIDTH(x) ((x) << 16) +#define MALI_C55_MESH_SHADING_MESH_HEIGHT_MASK GENMASK(29, 24) +#define MALI_C55_MESH_SHADING_MESH_HEIGHT(x) ((x) << 24) + +#define MALI_C55_REG_MESH_SHADING_ALPHA_BANK 0x1ac04 +#define MALI_C55_MESH_SHADING_ALPHA_BANK_R_MASK GENMASK(2, 0) +#define MALI_C55_MESH_SHADING_ALPHA_BANK_G_MASK GENMASK(5, 3) +#define MALI_C55_MESH_SHADING_ALPHA_BANK_G(x) ((x) << 3) +#define MALI_C55_MESH_SHADING_ALPHA_BANK_B_MASK GENMASK(8, 6) +#define MALI_C55_MESH_SHADING_ALPHA_BANK_B(x) ((x) << 6) +#define MALI_C55_REG_MESH_SHADING_ALPHA 0x1ac08 +#define MALI_C55_MESH_SHADING_ALPHA_R_MASK GENMASK(7, 0) +#define MALI_C55_MESH_SHADING_ALPHA_G_MASK GENMASK(15, 8) +#define MALI_C55_MESH_SHADING_ALPHA_G(x) ((x) << 8) +#define MALI_C55_MESH_SHADING_ALPHA_B_MASK GENMASK(23, 16) +#define MALI_C55_MESH_SHADING_ALPHA_B(x) ((x) << 16) +#define MALI_C55_REG_MESH_SHADING_MESH_STRENGTH 0x1ac0c +#define MALI_c55_MESH_STRENGTH_MASK GENMASK(15, 0) + +/* AWB Gains Configuration */ +#define MALI_C55_REG_AWB_GAINS1 0x1ac10 +#define MALI_C55_AWB_GAIN00_MASK GENMASK(11, 0) +#define MALI_C55_AWB_GAIN01_MASK GENMASK(27, 16) +#define MALI_C55_AWB_GAIN01(x) ((x) << 16) +#define MALI_C55_REG_AWB_GAINS2 0x1ac14 +#define MALI_C55_AWB_GAIN10_MASK GENMASK(11, 0) +#define MALI_C55_AWB_GAIN11_MASK GENMASK(27, 16) +#define MALI_C55_AWB_GAIN11(x) ((x) << 16) +#define MALI_C55_REG_AWB_GAINS1_AEXP 0x1ac18 +#define MALI_C55_REG_AWB_GAINS2_AEXP 0x1ac1c + +/* Colour Correction Matrix Configuration */ +#define MALI_C55_REG_CCM_ENABLE 0x1b07c +#define MALI_C55_CCM_ENABLE_MASK BIT(0) +#define MALI_C55_REG_CCM_COEF_R_R 0x1b080 +#define MALI_C55_REG_CCM_COEF_R_G 0x1b084 +#define MALI_C55_REG_CCM_COEF_R_B 0x1b088 +#define MALI_C55_REG_CCM_COEF_G_R 0x1b090 +#define MALI_C55_REG_CCM_COEF_G_G 0x1b094 +#define MALI_C55_REG_CCM_COEF_G_B 0x1b098 +#define MALI_C55_REG_CCM_COEF_B_R 0x1b0a0 +#define MALI_C55_REG_CCM_COEF_B_G 0x1b0a4 +#define MALI_C55_REG_CCM_COEF_B_B 0x1b0a8 +#define MALI_C55_CCM_COEF_MASK GENMASK(12, 0) +#define MALI_C55_REG_CCM_ANTIFOG_GAIN_R 0x1b0b0 +#define MALI_C55_REG_CCM_ANTIFOG_GAIN_G 0x1b0b4 +#define MALI_C55_REG_CCM_ANTIFOG_GAIN_B 0x1b0b8 +#define MALI_C55_CCM_ANTIFOG_GAIN_MASK GENMASK(11, 0) +#define MALI_C55_REG_CCM_ANTIFOG_OFFSET_R 0x1b0c0 +#define MALI_C55_REG_CCM_ANTIFOG_OFFSET_G 0x1b0c4 +#define MALI_C55_REG_CCM_ANTIFOG_OFFSET_B 0x1b0c8 +#define MALI_C55_CCM_ANTIFOG_OFFSET_MASK GENMASK(11, 0) + +/* AWB Statistics Configuration */ +#define MALI_C55_REG_AWB_STATS_MODE 0x1b29c +#define MALI_C55_AWB_STATS_MODE_MASK BIT(0) +#define MALI_C55_REG_AWB_WHITE_LEVEL 0x1b2a0 +#define MALI_C55_AWB_WHITE_LEVEL_MASK GENMASK(9, 0) +#define MALI_C55_REG_AWB_BLACK_LEVEL 0x1b2a4 +#define MALI_C55_AWB_BLACK_LEVEL_MASK GENMASK(9, 0) +#define MALI_C55_REG_AWB_CR_MAX 0x1b2a8 +#define MALI_C55_AWB_CR_MAX_MASK GENMASK(11, 0) +#define MALI_C55_REG_AWB_CR_MIN 0x1b2ac +#define MALI_C55_AWB_CR_MIN_MASK GENMASK(11, 0) +#define MALI_C55_REG_AWB_CB_MAX 0x1b2b0 +#define MALI_C55_AWB_CB_MAX_MASK GENMASK(11, 0) +#define MALI_C55_REG_AWB_CB_MIN 0x1b2b4 +#define MALI_C55_AWB_CB_MIN_MASK GENMASK(11, 0) +#define MALI_C55_REG_AWB_NODES_USED 0x1b2c4 +#define MALI_C55_AWB_NODES_USED_HORIZ_MASK GENMASK(7, 0) +#define MALI_C55_AWB_NODES_USED_VERT_MASK GENMASK(15, 8) +#define MALI_C55_AWB_NODES_USED_VERT(x) ((x) << 8) +#define MALI_C55_REG_AWB_CR_HIGH 0x1b2c8 +#define MALI_C55_AWB_CR_HIGH_MASK GENMASK(11, 0) +#define MALI_C55_REG_AWB_CR_LOW 0x1b2cc +#define MALI_C55_AWB_CR_LOW_MASK GENMASK(11, 0) +#define MALI_C55_REG_AWB_CB_HIGH 0x1b2d0 +#define MALI_C55_AWB_CB_HIGH_MASK GENMASK(11, 0) +#define MALI_C55_REG_AWB_CB_LOW 0x1b2d4 +#define MALI_C55_AWB_CB_LOW_MASK GENMASK(11, 0) + +/* AEXP Metering Histogram Configuration */ +#define MALI_C55_REG_AEXP_HIST_BASE 0x1b730 +#define MALI_C55_REG_AEXP_IHIST_BASE 0x1bbac +#define MALI_C55_AEXP_HIST_SKIP_OFFSET 0 +#define MALI_C55_AEXP_HIST_SKIP_X_MASK GENMASK(2, 0) +#define MALI_C55_AEXP_HIST_SKIP_X(x) ((x) << 0) +#define MALI_C55_AEXP_HIST_OFFSET_X_MASK BIT(3) +#define MALI_C55_AEXP_HIST_OFFSET_X(x) ((x) << 3) +#define MALI_C55_AEXP_HIST_SKIP_Y_MASK GENMASK(6, 4) +#define MALI_C55_AEXP_HIST_SKIP_Y(x) ((x) << 4) +#define MALI_C55_AEXP_HIST_OFFSET_Y_MASK BIT(7) +#define MALI_C55_AEXP_HIST_OFFSET_Y(x) ((x) << 7) +#define MALI_C55_AEXP_HIST_SCALE_OFFSET 4 +#define MALI_C55_AEXP_HIST_SCALE_BOTTOM_MASK GENMASK(3, 0) +#define MALI_C55_AEXP_HIST_SCALE_TOP_MASK GENMASK(7, 4) +#define MALI_C55_AEXP_HIST_SCALE_TOP(x) ((x) << 4) +#define MALI_C55_AEXP_HIST_PLANE_MODE_OFFSET 16 +#define MALI_C55_AEXP_HIST_PLANE_MODE_MASK GENMASK(2, 0) +#define MALI_C55_AEXP_HIST_NODES_USED_OFFSET 52 +#define MALI_C55_AEXP_HIST_NODES_USED_HORIZ_MASK GENMASK(7, 0) +#define MALI_C55_AEXP_HIST_NODES_USED_VERT_MASK GENMASK(15, 8) +#define MALI_C55_AEXP_HIST_NODES_USED_VERT(x) ((x) << 8) +#define MALI_C55_AEXP_HIST_ZONE_WEIGHTS_OFFSET 56 +#define MALI_C55_AEXP_HIST_ZONE_WEIGHT_MASK 0x0f0f0f0f + +/* + * The Mali-C55 ISP has up to two output pipes; known as full resolution and + * down scaled. The register space for these is laid out identically, but offset + * by 372 bytes. + */ +#define MALI_C55_CAP_DEV_FR_REG_OFFSET 0x0 +#define MALI_C55_CAP_DEV_DS_REG_OFFSET 0x174 + +#define MALI_C55_REG_CS_CONV_CONFIG 0x1c098 +#define MALI_C55_CS_CONV_MATRIX_MASK BIT(0) +#define MALI_C55_CS_CONV_FILTER_MASK BIT(1) +#define MALI_C55_CS_CONV_HORZ_DOWNSAMPLE_MASK BIT(2) +#define MALI_C55_CS_CONV_VERT_DOWNSAMPLE_MASK BIT(3) +#define MALI_C55_CS_CONV_FILTER_ENABLE (0x01 << 1) +#define MALI_C55_CS_CONV_HORZ_DOWNSAMPLE_ENABLE (0x01 << 2) +#define MALI_C55_CS_CONV_VERT_DOWNSAMPLE_ENABLE (0x01 << 3) +#define MALI_C55_REG_Y_WRITER_MODE 0x1c0ec +#define MALI_C55_REG_UV_WRITER_MODE 0x1c144 +#define MALI_C55_WRITER_MODE_MASK GENMASK(4, 0) +#define MALI_C55_OUTPUT_DISABLED 0 +#define MALI_C55_OUTPUT_RGB32 1 +#define MALI_C55_OUTPUT_A2R10G10B10 2 +#define MALI_C55_OUTPUT_RGB565 3 +#define MALI_C55_OUTPUT_RGB24 4 +#define MALI_C55_OUTPUT_GEN32 5 +#define MALI_C55_OUTPUT_RAW16 6 +#define MALI_C55_OUTPUT_AYUV 8 +#define MALI_C55_OUTPUT_Y410 9 +#define MALI_C55_OUTPUT_YUY2 10 +#define MALI_C55_OUTPUT_UYVY 11 +#define MALI_C55_OUTPUT_Y210 12 +#define MALI_C55_OUTPUT_NV12_21 13 +#define MALI_C55_OUTPUT_YUV_420_422 17 +#define MALI_C55_OUTPUT_P210_P010 19 +#define MALI_C55_OUTPUT_YUV422 20 +#define MALI_C55_WRITER_SUBMODE_MASK GENMASK(7, 6) +#define MALI_C55_WRITER_SUBMODE(x) ((x) << 6) +#define MALI_C55_OUTPUT_PLANE_ALT0 0 +#define MALI_C55_OUTPUT_PLANE_ALT1 1 +#define MALI_C55_OUTPUT_PLANE_ALT2 2 +#define MALI_C55_WRITER_FRAME_WRITE_MASK BIT(9) +#define MALI_C55_WRITER_FRAME_WRITE_ENABLE (0x01 << 9) +#define MALI_C55_REG_ACTIVE_OUT_Y_SIZE 0x1c0f0 +#define MALI_C55_REG_ACTIVE_OUT_UV_SIZE 0x1c148 +#define MALI_C55_REG_ACTIVE_OUT_SIZE_W(w) ((w) << 0) +#define MALI_C55_REG_ACTIVE_OUT_SIZE_H(h) ((h) << 16) +#define MALI_C55_REG_Y_WRITER_BANKS_BASE 0x1c0f4 +#define MALI_C55_REG_Y_WRITER_BANKS_CONFIG 0x1c108 +#define MALI_C55_REG_Y_WRITER_MAX_BANKS_MASK GENMASK(2, 0) +#define MALI_C55_REG_Y_WRITER_BANKS_RESTART BIT(3) +#define MALI_C55_REG_Y_WRITER_OFFSET 0x1c10c +#define MALI_C55_REG_UV_WRITER_BANKS_BASE 0x1c14c +#define MALI_C55_REG_UV_WRITER_BANKS_CONFIG 0x1c160 +#define MALI_C55_REG_UV_WRITER_MAX_BANKS_MASK GENMASK(2, 0) +#define MALI_C55_REG_UV_WRITER_BANKS_RESTART BIT(3) +#define MALI_C55_REG_UV_WRITER_OFFSET 0x1c164 + +#define MALI_C55_REG_TEST_GEN_CH0_OFF_ON +#define MALI_C55_REG_TEST_GEN_CH0_PATTERN_TYPE 0x18edc + +#define MALI_C55_REG_CROP_EN 0x1c028 +#define MALI_C55_CROP_ENABLE BIT(0) +#define MALI_C55_REG_CROP_X_START 0x1c02c +#define MALI_C55_REG_CROP_Y_START 0x1c030 +#define MALI_C55_REG_CROP_X_SIZE 0x1c034 +#define MALI_C55_REG_CROP_Y_SIZE 0x1c038 +#define MALI_C55_REG_SCALER_TIMEOUT_EN 0x1c040 +#define MALI_C55_SCALER_TIMEOUT_EN BIT(4) +#define MALI_C55_SCALER_TIMEOUT(t) ((t) << 16) +#define MALI_C55_REG_SCALER_IN_WIDTH 0x1c044 +#define MALI_C55_REG_SCALER_IN_HEIGHT 0x1c048 +#define MALI_C55_REG_SCALER_OUT_WIDTH 0x1c04c +#define MALI_C55_REG_SCALER_OUT_HEIGHT 0x1c050 +#define MALI_C55_REG_SCALER_HFILT_TINC 0x1c054 +#define MALI_C55_REG_SCALER_HFILT_COEF 0x1c058 +#define MALI_C55_REG_SCALER_VFILT_TINC 0x1c05c +#define MALI_C55_REG_SCALER_VFILT_COEF 0x1c060 + +#define MALI_C55_REG_GAMMA_RGB_ENABLE 0x1c064 +#define MALI_C55_GAMMA_ENABLE_MASK BIT(0) +#define MALI_C55_REG_GAMMA_GAINS_1 0x1c068 +#define MALI_C55_GAMMA_GAIN_R_MASK GENMASK(11, 0) +#define MALI_C55_GAMMA_GAIN_G_MASK GENMASK(27, 16) +#define MALI_C55_REG_GAMMA_GAINS_2 0x1c06c +#define MALI_C55_GAMMA_GAIN_B_MASK GENMASK(11, 0) +#define MALI_C55_REG_GAMMA_OFFSETS_1 0x1c070 +#define MALI_C55_GAMMA_OFFSET_R_MASK GENMASK(11, 0) +#define MALI_C55_GAMMA_OFFSET_G_MASK GENMASK(27, 16) +#define MALI_C55_REG_GAMMA_OFFSETS_2 0x1c074 +#define MALI_C55_GAMMA_OFFSET_B_MASK GENMASK(11, 0) + +/* + * A re-definition of an above register. These will usually be written on a per + * capture device basis and handled with mali_c55_cap_dev_write(), but on + * startup is written by core.c + */ +#define MALI_C55_REG_FR_GAMMA_RGB_ENABLE 0x1c064 +#define MALI_C55_REG_DS_GAMMA_RGB_ENABLE 0x1c1d8 + +#define MALI_C55_REG_FR_SCALER_HFILT 0x34a8 +#define MALI_C55_REG_FR_SCALER_VFILT 0x44a8 +#define MALI_C55_REG_DS_SCALER_HFILT 0x14a8 +#define MALI_C55_REG_DS_SCALER_VFILT 0x24a8 + +#endif /* _MALI_C55_REGISTERS_H */ diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c b/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c new file mode 100644 index 000000000000..a8d739af74b6 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c @@ -0,0 +1,1156 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM Mali-C55 ISP Driver - Image signal processor + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include <linux/math.h> +#include <linux/minmax.h> + +#include <media/media-entity.h> +#include <media/v4l2-subdev.h> + +#include "mali-c55-common.h" +#include "mali-c55-registers.h" + +/* Scaling factor in Q4.20 format. */ +#define MALI_C55_RSZ_SCALER_FACTOR (1U << 20) + +#define MALI_C55_RSZ_COEFS_BANKS 8 +#define MALI_C55_RSZ_COEFS_ENTRIES 64 + +static inline struct mali_c55_resizer * +sd_to_mali_c55_rsz(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mali_c55_resizer, sd); +} + +static const unsigned int +mali_c55_rsz_filter_coeffs_h[MALI_C55_RSZ_COEFS_BANKS] + [MALI_C55_RSZ_COEFS_ENTRIES] = { + { /* Bank 0 */ + 0x24fc0000, 0x0000fc24, 0x27fc0000, 0x0000fc21, + 0x28fc0000, 0x0000fd1f, 0x2cfb0000, 0x0000fd1c, + 0x2efb0000, 0x0000fd1a, 0x30fb0000, 0x0000fe17, + 0x32fb0000, 0x0000fe15, 0x35fb0000, 0x0000fe12, + 0x35fc0000, 0x0000ff10, 0x37fc0000, 0x0000ff0e, + 0x39fc0000, 0x0000ff0c, 0x3afd0000, 0x0000ff0a, + 0x3afe0000, 0x00000008, 0x3cfe0000, 0x00000006, + 0x3dff0000, 0x00000004, 0x3d000000, 0x00000003, + 0x3c020000, 0x00000002, 0x3d030000, 0x00000000, + 0x3d040000, 0x000000ff, 0x3c060000, 0x000000fe, + 0x3a080000, 0x000000fe, 0x3a0aff00, 0x000000fd, + 0x390cff00, 0x000000fc, 0x370eff00, 0x000000fc, + 0x3510ff00, 0x000000fc, 0x3512fe00, 0x000000fb, + 0x3215fe00, 0x000000fb, 0x3017fe00, 0x000000fb, + 0x2e1afd00, 0x000000fb, 0x2c1cfd00, 0x000000fb, + 0x281ffd00, 0x000000fc, 0x2721fc00, 0x000000fc, + }, + { /* Bank 1 */ + 0x25fb0000, 0x0000fb25, 0x27fb0000, 0x0000fb23, + 0x29fb0000, 0x0000fb21, 0x2afc0000, 0x0000fb1f, + 0x2cfc0000, 0x0000fb1d, 0x2efc0000, 0x0000fb1b, + 0x2ffd0000, 0x0000fb19, 0x2ffe0000, 0x0000fc17, + 0x31fe0000, 0x0000fc15, 0x32ff0000, 0x0000fc13, + 0x3400ff00, 0x0000fc11, 0x3301ff00, 0x0000fd10, + 0x3402ff00, 0x0000fd0e, 0x3503ff00, 0x0000fd0c, + 0x3505ff00, 0x0000fd0a, 0x3506fe00, 0x0000fe09, + 0x3607fe00, 0x0000fe07, 0x3509fe00, 0x0000fe06, + 0x350afd00, 0x0000ff05, 0x350cfd00, 0x0000ff03, + 0x340efd00, 0x0000ff02, 0x3310fd00, 0x0000ff01, + 0x3411fc00, 0x0000ff00, 0x3213fc00, 0x000000ff, + 0x3115fc00, 0x000000fe, 0x2f17fc00, 0x000000fe, + 0x2f19fb00, 0x000000fd, 0x2e1bfb00, 0x000000fc, + 0x2c1dfb00, 0x000000fc, 0x2a1ffb00, 0x000000fc, + 0x2921fb00, 0x000000fb, 0x2723fb00, 0x000000fb, + }, + { /* Bank 2 */ + 0x1f010000, 0x0000011f, 0x21010000, 0x0000001e, + 0x21020000, 0x0000001d, 0x22020000, 0x0000001c, + 0x23030000, 0x0000ff1b, 0x2404ff00, 0x0000ff1a, + 0x2504ff00, 0x0000ff19, 0x2505ff00, 0x0000ff18, + 0x2606ff00, 0x0000fe17, 0x2607ff00, 0x0000fe16, + 0x2708ff00, 0x0000fe14, 0x2709ff00, 0x0000fe13, + 0x270aff00, 0x0000fe12, 0x280bfe00, 0x0000fe11, + 0x280cfe00, 0x0000fe10, 0x280dfe00, 0x0000fe0f, + 0x280efe00, 0x0000fe0e, 0x280ffe00, 0x0000fe0d, + 0x2810fe00, 0x0000fe0c, 0x2811fe00, 0x0000fe0b, + 0x2712fe00, 0x0000ff0a, 0x2713fe00, 0x0000ff09, + 0x2714fe00, 0x0000ff08, 0x2616fe00, 0x0000ff07, + 0x2617fe00, 0x0000ff06, 0x2518ff00, 0x0000ff05, + 0x2519ff00, 0x0000ff04, 0x241aff00, 0x0000ff04, + 0x231bff00, 0x00000003, 0x221c0000, 0x00000002, + 0x211d0000, 0x00000002, 0x211e0000, 0x00000001, + }, + { /* Bank 3 */ + 0x1b06ff00, 0x00ff061b, 0x1b07ff00, 0x00ff061a, + 0x1c07ff00, 0x00ff051a, 0x1c08ff00, 0x00ff0519, + 0x1c09ff00, 0x00ff0419, 0x1d09ff00, 0x00ff0418, + 0x1e0aff00, 0x00ff0317, 0x1e0aff00, 0x00ff0317, + 0x1e0bff00, 0x00ff0316, 0x1f0cff00, 0x00ff0215, + 0x1e0cff00, 0x00000215, 0x1e0dff00, 0x00000214, + 0x1e0e0000, 0x00000113, 0x1e0e0000, 0x00000113, + 0x1e0f0000, 0x00000112, 0x1f100000, 0x00000011, + 0x20100000, 0x00000010, 0x1f110000, 0x00000010, + 0x1e120100, 0x0000000f, 0x1e130100, 0x0000000e, + 0x1e130100, 0x0000000e, 0x1e140200, 0x0000ff0d, + 0x1e150200, 0x0000ff0c, 0x1f1502ff, 0x0000ff0c, + 0x1e1603ff, 0x0000ff0b, 0x1e1703ff, 0x0000ff0a, + 0x1e1703ff, 0x0000ff0a, 0x1d1804ff, 0x0000ff09, + 0x1c1904ff, 0x0000ff09, 0x1c1905ff, 0x0000ff08, + 0x1c1a05ff, 0x0000ff07, 0x1b1a06ff, 0x0000ff07, + }, + { /* Bank 4 */ + 0x17090000, 0x00000917, 0x18090000, 0x00000916, + 0x170a0100, 0x00000816, 0x170a0100, 0x00000816, + 0x180b0100, 0x00000715, 0x180b0100, 0x00000715, + 0x170c0100, 0x00000715, 0x190c0100, 0x00000614, + 0x180d0100, 0x00000614, 0x190d0200, 0x00000513, + 0x180e0200, 0x00000513, 0x180e0200, 0x00000513, + 0x1a0e0200, 0x00000412, 0x190f0200, 0x00000412, + 0x190f0300, 0x00000411, 0x18100300, 0x00000411, + 0x1a100300, 0x00000310, 0x18110400, 0x00000310, + 0x19110400, 0x0000030f, 0x19120400, 0x0000020f, + 0x1a120400, 0x0000020e, 0x18130500, 0x0000020e, + 0x18130500, 0x0000020e, 0x19130500, 0x0000020d, + 0x18140600, 0x0000010d, 0x19140600, 0x0000010c, + 0x17150700, 0x0000010c, 0x18150700, 0x0000010b, + 0x18150700, 0x0000010b, 0x17160800, 0x0000010a, + 0x17160800, 0x0000010a, 0x18160900, 0x00000009, + }, + { /* Bank 5 */ + 0x120b0300, 0x00030b12, 0x120c0300, 0x00030b11, + 0x110c0400, 0x00030b11, 0x110c0400, 0x00030b11, + 0x130c0400, 0x00020a11, 0x120d0400, 0x00020a11, + 0x110d0500, 0x00020a11, 0x110d0500, 0x00020a11, + 0x130d0500, 0x00010911, 0x130e0500, 0x00010910, + 0x120e0600, 0x00010910, 0x120e0600, 0x00010910, + 0x130e0600, 0x00010810, 0x120f0600, 0x00010810, + 0x120f0700, 0x00000810, 0x130f0700, 0x0000080f, + 0x140f0700, 0x0000070f, 0x130f0800, 0x0000070f, + 0x12100800, 0x0000070f, 0x12100801, 0x0000060f, + 0x13100801, 0x0000060e, 0x12100901, 0x0000060e, + 0x12100901, 0x0000060e, 0x13100901, 0x0000050e, + 0x13110901, 0x0000050d, 0x11110a02, 0x0000050d, + 0x11110a02, 0x0000050d, 0x12110a02, 0x0000040d, + 0x13110a02, 0x0000040c, 0x11110b03, 0x0000040c, + 0x11110b03, 0x0000040c, 0x12110b03, 0x0000030c, + }, + { /* Bank 6 */ + 0x0b0a0805, 0x00080a0c, 0x0b0a0805, 0x00080a0c, + 0x0c0a0805, 0x00080a0b, 0x0c0a0805, 0x00080a0b, + 0x0d0a0805, 0x00070a0b, 0x0d0a0805, 0x00070a0b, + 0x0d0a0805, 0x00070a0b, 0x0c0a0806, 0x00070a0b, + 0x0b0b0806, 0x00070a0b, 0x0c0b0806, 0x0007090b, + 0x0b0b0906, 0x0007090b, 0x0b0b0906, 0x0007090b, + 0x0b0b0906, 0x0007090b, 0x0b0b0906, 0x0007090b, + 0x0b0b0906, 0x0007090b, 0x0c0b0906, 0x0006090b, + 0x0c0b0906, 0x0006090b, 0x0c0b0906, 0x0006090b, + 0x0b0b0907, 0x0006090b, 0x0b0b0907, 0x0006090b, + 0x0b0b0907, 0x0006090b, 0x0b0b0907, 0x0006090b, + 0x0b0b0907, 0x0006090b, 0x0c0b0907, 0x0006080b, + 0x0b0b0a07, 0x0006080b, 0x0c0b0a07, 0x0006080a, + 0x0d0b0a07, 0x0005080a, 0x0d0b0a07, 0x0005080a, + 0x0d0b0a07, 0x0005080a, 0x0c0b0a08, 0x0005080a, + 0x0c0b0a08, 0x0005080a, 0x0c0b0a08, 0x0005080a, + }, + { /* Bank 7 */ + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + 0x0909090a, 0x00090909, 0x0909090a, 0x00090909, + } +}; + +static const unsigned int +mali_c55_rsz_filter_coeffs_v[MALI_C55_RSZ_COEFS_BANKS] + [MALI_C55_RSZ_COEFS_ENTRIES] = { + { /* Bank 0 */ + 0x2424fc00, 0x000000fc, 0x2721fc00, 0x000000fc, + 0x281ffd00, 0x000000fc, 0x2c1cfd00, 0x000000fb, + 0x2e1afd00, 0x000000fb, 0x3017fe00, 0x000000fb, + 0x3215fe00, 0x000000fb, 0x3512fe00, 0x000000fb, + 0x3510ff00, 0x000000fc, 0x370eff00, 0x000000fc, + 0x390cff00, 0x000000fc, 0x3a0aff00, 0x000000fd, + 0x3a080000, 0x000000fe, 0x3c060000, 0x000000fe, + 0x3d040000, 0x000000ff, 0x3d030000, 0x00000000, + 0x3c020000, 0x00000002, 0x3d000000, 0x00000003, + 0x3dff0000, 0x00000004, 0x3cfe0000, 0x00000006, + 0x3afe0000, 0x00000008, 0x3afd0000, 0x0000ff0a, + 0x39fc0000, 0x0000ff0c, 0x37fc0000, 0x0000ff0e, + 0x35fc0000, 0x0000ff10, 0x35fb0000, 0x0000fe12, + 0x32fb0000, 0x0000fe15, 0x30fb0000, 0x0000fe17, + 0x2efb0000, 0x0000fd1a, 0x2cfb0000, 0x0000fd1c, + 0x28fc0000, 0x0000fd1f, 0x27fc0000, 0x0000fc21, + }, + { /* Bank 1 */ + 0x2525fb00, 0x000000fb, 0x2723fb00, 0x000000fb, + 0x2921fb00, 0x000000fb, 0x2a1ffb00, 0x000000fc, + 0x2c1dfb00, 0x000000fc, 0x2e1bfb00, 0x000000fc, + 0x2f19fb00, 0x000000fd, 0x2f17fc00, 0x000000fe, + 0x3115fc00, 0x000000fe, 0x3213fc00, 0x000000ff, + 0x3411fc00, 0x0000ff00, 0x3310fd00, 0x0000ff01, + 0x340efd00, 0x0000ff02, 0x350cfd00, 0x0000ff03, + 0x350afd00, 0x0000ff05, 0x3509fe00, 0x0000fe06, + 0x3607fe00, 0x0000fe07, 0x3506fe00, 0x0000fe09, + 0x3505ff00, 0x0000fd0a, 0x3503ff00, 0x0000fd0c, + 0x3402ff00, 0x0000fd0e, 0x3301ff00, 0x0000fd10, + 0x3400ff00, 0x0000fc11, 0x32ff0000, 0x0000fc13, + 0x31fe0000, 0x0000fc15, 0x2ffe0000, 0x0000fc17, + 0x2ffd0000, 0x0000fb19, 0x2efc0000, 0x0000fb1b, + 0x2cfc0000, 0x0000fb1d, 0x2afc0000, 0x0000fb1f, + 0x29fb0000, 0x0000fb21, 0x27fb0000, 0x0000fb23, + }, + { /* Bank 2 */ + 0x1f1f0100, 0x00000001, 0x211e0000, 0x00000001, + 0x211d0000, 0x00000002, 0x221c0000, 0x00000002, + 0x231bff00, 0x00000003, 0x241aff00, 0x0000ff04, + 0x2519ff00, 0x0000ff04, 0x2518ff00, 0x0000ff05, + 0x2617fe00, 0x0000ff06, 0x2616fe00, 0x0000ff07, + 0x2714fe00, 0x0000ff08, 0x2713fe00, 0x0000ff09, + 0x2712fe00, 0x0000ff0a, 0x2811fe00, 0x0000fe0b, + 0x2810fe00, 0x0000fe0c, 0x280ffe00, 0x0000fe0d, + 0x280efe00, 0x0000fe0e, 0x280dfe00, 0x0000fe0f, + 0x280cfe00, 0x0000fe10, 0x280bfe00, 0x0000fe11, + 0x270aff00, 0x0000fe12, 0x2709ff00, 0x0000fe13, + 0x2708ff00, 0x0000fe14, 0x2607ff00, 0x0000fe16, + 0x2606ff00, 0x0000fe17, 0x2505ff00, 0x0000ff18, + 0x2504ff00, 0x0000ff19, 0x2404ff00, 0x0000ff1a, + 0x23030000, 0x0000ff1b, 0x22020000, 0x0000001c, + 0x21020000, 0x0000001d, 0x21010000, 0x0000001e, + }, + { /* Bank 3 */ + 0x1b1b06ff, 0x0000ff06, 0x1b1a06ff, 0x0000ff07, + 0x1c1a05ff, 0x0000ff07, 0x1c1905ff, 0x0000ff08, + 0x1c1904ff, 0x0000ff09, 0x1d1804ff, 0x0000ff09, + 0x1e1703ff, 0x0000ff0a, 0x1e1703ff, 0x0000ff0a, + 0x1e1603ff, 0x0000ff0b, 0x1f1502ff, 0x0000ff0c, + 0x1e150200, 0x0000ff0c, 0x1e140200, 0x0000ff0d, + 0x1e130100, 0x0000000e, 0x1e130100, 0x0000000e, + 0x1e120100, 0x0000000f, 0x1f110000, 0x00000010, + 0x20100000, 0x00000010, 0x1f100000, 0x00000011, + 0x1e0f0000, 0x00000112, 0x1e0e0000, 0x00000113, + 0x1e0e0000, 0x00000113, 0x1e0dff00, 0x00000214, + 0x1e0cff00, 0x00000215, 0x1f0cff00, 0x00ff0215, + 0x1e0bff00, 0x00ff0316, 0x1e0aff00, 0x00ff0317, + 0x1e0aff00, 0x00ff0317, 0x1d09ff00, 0x00ff0418, + 0x1c09ff00, 0x00ff0419, 0x1c08ff00, 0x00ff0519, + 0x1c07ff00, 0x00ff051a, 0x1b07ff00, 0x00ff061a, + }, + { /* Bank 4 */ + 0x17170900, 0x00000009, 0x18160900, 0x00000009, + 0x17160800, 0x0000010a, 0x17160800, 0x0000010a, + 0x18150700, 0x0000010b, 0x18150700, 0x0000010b, + 0x17150700, 0x0000010c, 0x19140600, 0x0000010c, + 0x18140600, 0x0000010d, 0x19130500, 0x0000020d, + 0x18130500, 0x0000020e, 0x18130500, 0x0000020e, + 0x1a120400, 0x0000020e, 0x19120400, 0x0000020f, + 0x19110400, 0x0000030f, 0x18110400, 0x00000310, + 0x1a100300, 0x00000310, 0x18100300, 0x00000411, + 0x190f0300, 0x00000411, 0x190f0200, 0x00000412, + 0x1a0e0200, 0x00000412, 0x180e0200, 0x00000513, + 0x180e0200, 0x00000513, 0x190d0200, 0x00000513, + 0x180d0100, 0x00000614, 0x190c0100, 0x00000614, + 0x170c0100, 0x00000715, 0x180b0100, 0x00000715, + 0x180b0100, 0x00000715, 0x170a0100, 0x00000816, + 0x170a0100, 0x00000816, 0x18090000, 0x00000916, + }, + { /* Bank 5 */ + 0x12120b03, 0x0000030b, 0x12110b03, 0x0000030c, + 0x11110b03, 0x0000040c, 0x11110b03, 0x0000040c, + 0x13110a02, 0x0000040c, 0x12110a02, 0x0000040d, + 0x11110a02, 0x0000050d, 0x11110a02, 0x0000050d, + 0x13110901, 0x0000050d, 0x13100901, 0x0000050e, + 0x12100901, 0x0000060e, 0x12100901, 0x0000060e, + 0x13100801, 0x0000060e, 0x12100801, 0x0000060f, + 0x12100800, 0x0000070f, 0x130f0800, 0x0000070f, + 0x140f0700, 0x0000070f, 0x130f0700, 0x0000080f, + 0x120f0700, 0x00000810, 0x120f0600, 0x00010810, + 0x130e0600, 0x00010810, 0x120e0600, 0x00010910, + 0x120e0600, 0x00010910, 0x130e0500, 0x00010910, + 0x130d0500, 0x00010911, 0x110d0500, 0x00020a11, + 0x110d0500, 0x00020a11, 0x120d0400, 0x00020a11, + 0x130c0400, 0x00020a11, 0x110c0400, 0x00030b11, + 0x110c0400, 0x00030b11, 0x120c0300, 0x00030b11, + }, + { /* Bank 6 */ + 0x0b0c0a08, 0x0005080a, 0x0b0c0a08, 0x0005080a, + 0x0c0b0a08, 0x0005080a, 0x0c0b0a08, 0x0005080a, + 0x0d0b0a07, 0x0005080a, 0x0d0b0a07, 0x0005080a, + 0x0d0b0a07, 0x0005080a, 0x0c0b0a07, 0x0006080a, + 0x0b0b0a07, 0x0006080b, 0x0c0b0907, 0x0006080b, + 0x0b0b0907, 0x0006090b, 0x0b0b0907, 0x0006090b, + 0x0b0b0907, 0x0006090b, 0x0b0b0907, 0x0006090b, + 0x0b0b0907, 0x0006090b, 0x0c0b0906, 0x0006090b, + 0x0c0b0906, 0x0006090b, 0x0c0b0906, 0x0006090b, + 0x0b0b0906, 0x0007090b, 0x0b0b0906, 0x0007090b, + 0x0b0b0906, 0x0007090b, 0x0b0b0906, 0x0007090b, + 0x0b0b0906, 0x0007090b, 0x0c0b0806, 0x0007090b, + 0x0b0b0806, 0x00070a0b, 0x0c0a0806, 0x00070a0b, + 0x0d0a0805, 0x00070a0b, 0x0d0a0805, 0x00070a0b, + 0x0d0a0805, 0x00070a0b, 0x0c0a0805, 0x00080a0b, + 0x0c0a0805, 0x00080a0b, 0x0c0a0805, 0x00080a0b, + }, + { /* Bank 7 */ + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + 0x09090909, 0x000a0909, 0x09090909, 0x000a0909, + } +}; + +static const unsigned int mali_c55_rsz_coef_banks_range_start[] = { + 770, 600, 460, 354, 273, 210, 162, 125 +}; + +/* + * Select the right filter coefficients bank based on the scaler input and the + * scaler output sizes ratio, set by the v4l2 crop and scale selection + * rectangles respectively. + */ +static unsigned int mali_c55_rsz_calculate_bank(struct mali_c55 *mali_c55, + unsigned int rsz_in, + unsigned int rsz_out) +{ + unsigned int rsz_ratio = (rsz_out * 1000U) / rsz_in; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mali_c55_rsz_coef_banks_range_start); i++) + if (rsz_ratio >= mali_c55_rsz_coef_banks_range_start[i]) + break; + + return i; +} + +static const u32 rsz_non_bypass_src_fmts[] = { + MEDIA_BUS_FMT_RGB121212_1X36, + MEDIA_BUS_FMT_YUV10_1X30 +}; + +static void mali_c55_resizer_program_coefficients(struct mali_c55_resizer *rsz) +{ + struct mali_c55 *mali_c55 = rsz->mali_c55; + unsigned int haddr = rsz->id == MALI_C55_RSZ_FR ? + MALI_C55_REG_FR_SCALER_HFILT : + MALI_C55_REG_DS_SCALER_HFILT; + unsigned int vaddr = rsz->id == MALI_C55_RSZ_FR ? + MALI_C55_REG_FR_SCALER_VFILT : + MALI_C55_REG_DS_SCALER_VFILT; + + for (unsigned int i = 0; i < MALI_C55_RSZ_COEFS_BANKS; i++) { + for (unsigned int j = 0; j < MALI_C55_RSZ_COEFS_ENTRIES; j++) { + mali_c55_write(mali_c55, haddr, + mali_c55_rsz_filter_coeffs_h[i][j]); + mali_c55_write(mali_c55, vaddr, + mali_c55_rsz_filter_coeffs_v[i][j]); + + haddr += sizeof(u32); + vaddr += sizeof(u32); + } + } +} + +static int mali_c55_rsz_program_crop(struct mali_c55_resizer *rsz, + const struct v4l2_subdev_state *state) +{ + const struct v4l2_mbus_framefmt *fmt; + const struct v4l2_rect *crop; + + /* Verify if crop should be enabled. */ + fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SINK_PAD, 0); + crop = v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD, 0); + + if (fmt->width == crop->width && fmt->height == crop->height) + return MALI_C55_BYPASS_CROP; + + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_X_START, + crop->left); + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_Y_START, + crop->top); + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_X_SIZE, + crop->width); + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_Y_SIZE, + crop->height); + + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_CROP_EN, + MALI_C55_CROP_ENABLE); + + return 0; +} + +static int mali_c55_rsz_program_resizer(struct mali_c55_resizer *rsz, + struct v4l2_subdev_state *state) +{ + struct mali_c55 *mali_c55 = rsz->mali_c55; + const struct v4l2_rect *crop, *scale; + unsigned int h_bank, v_bank; + u64 h_scale, v_scale; + + /* Verify if scaling should be enabled. */ + crop = v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD, 0); + scale = v4l2_subdev_state_get_compose(state, MALI_C55_RSZ_SINK_PAD, 0); + + if (crop->width == scale->width && crop->height == scale->height) + return MALI_C55_BYPASS_SCALER; + + /* Program the scaler coefficients if the scaler is in use. */ + mali_c55_resizer_program_coefficients(rsz); + + /* Program the V/H scaling factor in Q4.20 format. */ + h_scale = crop->width * MALI_C55_RSZ_SCALER_FACTOR; + v_scale = crop->height * MALI_C55_RSZ_SCALER_FACTOR; + + do_div(h_scale, scale->width); + do_div(v_scale, scale->height); + + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_IN_WIDTH, + crop->width); + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_IN_HEIGHT, + crop->height); + + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_OUT_WIDTH, + scale->width); + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_OUT_HEIGHT, + scale->height); + + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_HFILT_TINC, + h_scale); + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_VFILT_TINC, + v_scale); + + /* Select the scaler coefficients bank to use. */ + h_bank = mali_c55_rsz_calculate_bank(mali_c55, crop->width, + scale->width); + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_HFILT_COEF, + h_bank); + + v_bank = mali_c55_rsz_calculate_bank(mali_c55, crop->height, + scale->height); + mali_c55_cap_dev_write(rsz->cap_dev, MALI_C55_REG_SCALER_VFILT_COEF, + v_bank); + + return 0; +} + +static void mali_c55_rsz_program(struct mali_c55_resizer *rsz, + struct v4l2_subdev_state *state) +{ + struct mali_c55 *mali_c55 = rsz->mali_c55; + u32 bypass = 0; + + /* Verify if cropping and scaling should be enabled. */ + bypass |= mali_c55_rsz_program_crop(rsz, state); + bypass |= mali_c55_rsz_program_resizer(rsz, state); + + mali_c55_ctx_update_bits(mali_c55, rsz->id == MALI_C55_RSZ_FR ? + MALI_C55_REG_FR_BYPASS : MALI_C55_REG_DS_BYPASS, + MALI_C55_BYPASS_CROP | MALI_C55_BYPASS_SCALER, + bypass); +} + +/* + * Inspect the routing table to know which of the two (mutually exclusive) + * routes is enabled and return the sink pad id of the active route. + */ +static unsigned int mali_c55_rsz_get_active_sink(struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_krouting *routing = &state->routing; + struct v4l2_subdev_route *route; + + /* A single route is enabled at a time. */ + for_each_active_route(routing, route) + return route->sink_pad; + + return MALI_C55_RSZ_SINK_PAD; +} + +/* + * When operating in bypass mode, the ISP takes input in a 20-bit format, but + * can only output 16-bit RAW bayer data (with the 4 least significant bits from + * the input being lost). Return the 16-bit version of the 20-bit input formats. + */ +static u32 mali_c55_rsz_shift_mbus_code(u32 mbus_code) +{ + const struct mali_c55_isp_format_info *fmt = + mali_c55_isp_get_mbus_config_by_code(mbus_code); + + if (!fmt) + return -EINVAL; + + return fmt->shifted_code; +} + +static int __mali_c55_rsz_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + const struct v4l2_subdev_krouting *routing) +{ + struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd); + unsigned int active_sink = UINT_MAX; + struct v4l2_mbus_framefmt *src_fmt; + struct v4l2_subdev_route *route; + unsigned int active_routes = 0; + struct v4l2_mbus_framefmt *fmt; + int ret; + + ret = v4l2_subdev_routing_validate(sd, routing, 0); + if (ret) + return ret; + + /* Only a single route can be enabled at a time. */ + for_each_active_route(routing, route) { + if (++active_routes > 1) { + dev_dbg(rsz->mali_c55->dev, + "Only one route can be active"); + return -EINVAL; + } + + active_sink = route->sink_pad; + } + if (active_sink == UINT_MAX) { + dev_dbg(rsz->mali_c55->dev, "One route has to be active"); + return -EINVAL; + } + + ret = v4l2_subdev_set_routing(sd, state, routing); + if (ret) { + dev_dbg(rsz->mali_c55->dev, "Failed to set routing\n"); + return ret; + } + + fmt = v4l2_subdev_state_get_format(state, active_sink, 0); + fmt->width = MALI_C55_DEFAULT_WIDTH; + fmt->height = MALI_C55_DEFAULT_HEIGHT; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); + fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(false, + fmt->colorspace, + fmt->ycbcr_enc); + fmt->field = V4L2_FIELD_NONE; + + if (active_sink == MALI_C55_RSZ_SINK_PAD) { + struct v4l2_rect *crop, *compose; + + fmt->code = MEDIA_BUS_FMT_RGB121212_1X36; + + crop = v4l2_subdev_state_get_crop(state, active_sink, 0); + compose = v4l2_subdev_state_get_compose(state, active_sink, 0); + + crop->left = 0; + crop->top = 0; + crop->width = MALI_C55_DEFAULT_WIDTH; + crop->height = MALI_C55_DEFAULT_HEIGHT; + + *compose = *crop; + } else { + fmt->code = MEDIA_BUS_FMT_SRGGB20_1X20; + } + + /* Propagate the format to the source pad */ + src_fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SOURCE_PAD, + 0); + *src_fmt = *fmt; + + /* In the event this is the bypass pad the mbus code needs correcting */ + if (active_sink == MALI_C55_RSZ_SINK_BYPASS_PAD) + src_fmt->code = mali_c55_rsz_shift_mbus_code(src_fmt->code); + + return 0; +} + +static int mali_c55_rsz_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct mali_c55_isp_format_info *fmt; + struct v4l2_mbus_framefmt *sink_fmt; + u32 sink_pad; + + switch (code->pad) { + case MALI_C55_RSZ_SINK_PAD: + if (code->index) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_RGB121212_1X36; + + return 0; + case MALI_C55_RSZ_SOURCE_PAD: + sink_pad = mali_c55_rsz_get_active_sink(state); + sink_fmt = v4l2_subdev_state_get_format(state, sink_pad, 0); + + /* + * If the active route is from the Bypass sink pad, then the + * source pad is a simple passthrough of the sink format, + * downshifted to 16-bits. + */ + + if (sink_pad == MALI_C55_RSZ_SINK_BYPASS_PAD) { + if (code->index) + return -EINVAL; + + code->code = mali_c55_rsz_shift_mbus_code(sink_fmt->code); + if (!code->code) + return -EINVAL; + + return 0; + } + + /* + * If the active route is from the non-bypass sink then we can + * select either RGB or conversion to YUV. + */ + + if (code->index >= ARRAY_SIZE(rsz_non_bypass_src_fmts)) + return -EINVAL; + + code->code = rsz_non_bypass_src_fmts[code->index]; + + return 0; + case MALI_C55_RSZ_SINK_BYPASS_PAD: + fmt = mali_c55_isp_get_mbus_config_by_index(code->index); + if (fmt) { + code->code = fmt->code; + return 0; + } + + break; + } + + return -EINVAL; +} + +static int mali_c55_rsz_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct mali_c55_isp_format_info *fmt; + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *compose; + u32 sink_pad; + + switch (fse->pad) { + case MALI_C55_RSZ_SINK_PAD: + if (fse->index || fse->code != MEDIA_BUS_FMT_RGB121212_1X36) + return -EINVAL; + + fse->max_width = MALI_C55_MAX_WIDTH; + fse->max_height = MALI_C55_MAX_HEIGHT; + fse->min_width = MALI_C55_MIN_WIDTH; + fse->min_height = MALI_C55_MIN_HEIGHT; + + return 0; + case MALI_C55_RSZ_SOURCE_PAD: + sink_pad = mali_c55_rsz_get_active_sink(state); + sink_fmt = v4l2_subdev_state_get_format(state, sink_pad, 0); + + if (sink_pad == MALI_C55_RSZ_SINK_BYPASS_PAD) { + if (fse->index) + return -EINVAL; + + fmt = mali_c55_isp_get_mbus_config_by_shifted_code(fse->code); + if (!fmt) + return -EINVAL; + + fse->min_width = sink_fmt->width; + fse->max_width = sink_fmt->width; + fse->min_height = sink_fmt->height; + fse->max_height = sink_fmt->height; + + return 0; + } + + if ((fse->code != MEDIA_BUS_FMT_RGB121212_1X36 && + fse->code != MEDIA_BUS_FMT_YUV10_1X30) || fse->index > 1) + return -EINVAL; + + compose = v4l2_subdev_state_get_compose(state, + MALI_C55_RSZ_SINK_PAD, + 0); + + fse->min_width = compose->width; + fse->max_width = compose->width; + fse->min_height = compose->height; + fse->max_height = compose->height; + + return 0; + case MALI_C55_RSZ_SINK_BYPASS_PAD: + fmt = mali_c55_isp_get_mbus_config_by_code(fse->code); + if (fse->index || !fmt) + return -EINVAL; + + fse->max_width = MALI_C55_MAX_WIDTH; + fse->max_height = MALI_C55_MAX_HEIGHT; + fse->min_width = MALI_C55_MIN_WIDTH; + fse->min_height = MALI_C55_MIN_HEIGHT; + + return 0; + } + + return -EINVAL; +} + +static int mali_c55_rsz_set_sink_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct v4l2_mbus_framefmt *sink_fmt; + unsigned int active_sink; + struct v4l2_rect *rect; + + sink_fmt = v4l2_subdev_state_get_format(state, format->pad, 0); + + /* + * Clamp to min/max and then reset crop and compose rectangles to the + * newly applied size. + */ + sink_fmt->width = clamp_t(unsigned int, fmt->width, + MALI_C55_MIN_WIDTH, MALI_C55_MAX_WIDTH); + sink_fmt->height = clamp_t(unsigned int, fmt->height, + MALI_C55_MIN_HEIGHT, MALI_C55_MAX_HEIGHT); + + /* + * Make sure the media bus code for the bypass pad is one of the + * supported ISP input media bus codes. Default it to SRGGB otherwise. + */ + if (format->pad == MALI_C55_RSZ_SINK_BYPASS_PAD) + sink_fmt->code = mali_c55_isp_get_mbus_config_by_code(fmt->code) ? + fmt->code : MEDIA_BUS_FMT_SRGGB20_1X20; + + *fmt = *sink_fmt; + + if (format->pad == MALI_C55_RSZ_SINK_PAD) { + rect = v4l2_subdev_state_get_crop(state, format->pad); + rect->left = 0; + rect->top = 0; + rect->width = fmt->width; + rect->height = fmt->height; + + rect = v4l2_subdev_state_get_compose(state, format->pad); + rect->left = 0; + rect->top = 0; + rect->width = fmt->width; + rect->height = fmt->height; + } + + /* If format->pad is routed to the source pad, propagate the format. */ + active_sink = mali_c55_rsz_get_active_sink(state); + if (active_sink == format->pad) { + /* If the bypass route is used, downshift the code to 16bpp. */ + if (active_sink == MALI_C55_RSZ_SINK_BYPASS_PAD) + fmt->code = mali_c55_rsz_shift_mbus_code(fmt->code); + + *v4l2_subdev_state_get_format(state, + MALI_C55_RSZ_SOURCE_PAD, 0) = *fmt; + } + + return 0; +} + +static int mali_c55_rsz_set_source_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + unsigned int active_sink; + + active_sink = mali_c55_rsz_get_active_sink(state); + sink_fmt = v4l2_subdev_state_get_format(state, active_sink, 0); + src_fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SOURCE_PAD); + + if (active_sink == MALI_C55_RSZ_SINK_PAD) { + /* + * Regular processing pipe: RGB121212 can be color-space + * converted to YUV101010. + */ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rsz_non_bypass_src_fmts); i++) { + if (fmt->code == rsz_non_bypass_src_fmts[i]) + break; + } + + src_fmt->code = i == ARRAY_SIZE(rsz_non_bypass_src_fmts) ? + MEDIA_BUS_FMT_RGB121212_1X36 : fmt->code; + } else { + /* + * Bypass pipe: the source format is the same as the bypass + * sink pad downshifted to 16bpp. + */ + fmt->code = mali_c55_rsz_shift_mbus_code(sink_fmt->code); + } + + *fmt = *src_fmt; + + return 0; +} + +static int mali_c55_rsz_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + /* + * On sink pads fmt is either fixed for the 'regular' processing + * pad or a RAW format or 20-bit wide RGB/YUV format for the FR bypass + * pad. + * + * On source pad sizes are the result of crop+compose on the sink + * pad sizes, while the format depends on the active route. + */ + + if (format->pad == MALI_C55_RSZ_SINK_PAD || + format->pad == MALI_C55_RSZ_SINK_BYPASS_PAD) + return mali_c55_rsz_set_sink_fmt(sd, state, format); + + return mali_c55_rsz_set_source_fmt(sd, state, format); +} + +static int mali_c55_rsz_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + if (sel->pad != MALI_C55_RSZ_SINK_PAD) + return -EINVAL; + + if (sel->target != V4L2_SEL_TGT_CROP && + sel->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + sel->r = sel->target == V4L2_SEL_TGT_CROP + ? *v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD) + : *v4l2_subdev_state_get_compose(state, MALI_C55_RSZ_SINK_PAD); + + return 0; +} + +static int mali_c55_rsz_set_crop(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd); + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + struct v4l2_rect *crop, *compose; + + sink_fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SINK_PAD); + crop = v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD); + compose = v4l2_subdev_state_get_compose(state, MALI_C55_RSZ_SINK_PAD); + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && + v4l2_subdev_is_streaming(sd)) { + /* + * At runtime the compose rectangle and output size cannot be + * changed so we need to clamp the crop rectangle such that the + * compose rectangle can fit within it. + */ + crop->left = clamp_t(unsigned int, sel->r.left, 0, + sink_fmt->width - compose->width); + crop->top = clamp_t(unsigned int, sel->r.top, 0, + sink_fmt->height - compose->height); + crop->width = clamp_t(unsigned int, sel->r.width, compose->width, + sink_fmt->width - crop->left); + crop->height = clamp_t(unsigned int, sel->r.height, compose->height, + sink_fmt->height - crop->top); + + mali_c55_rsz_program(rsz, state); + } else { + /* + * If we're not streaming we can utilise the ISP's full range + * and simply need to propagate the selected rectangle to the + * compose target and source pad format. + */ + crop->left = clamp_t(unsigned int, sel->r.left, 0, + sink_fmt->width); + crop->top = clamp_t(unsigned int, sel->r.top, 0, + sink_fmt->height); + crop->width = clamp_t(unsigned int, sel->r.width, + MALI_C55_MIN_WIDTH, + sink_fmt->width - crop->left); + crop->height = clamp_t(unsigned int, sel->r.height, + MALI_C55_MIN_HEIGHT, + sink_fmt->height - crop->top); + + *compose = *crop; + + src_fmt = v4l2_subdev_state_get_format(state, + MALI_C55_RSZ_SOURCE_PAD); + src_fmt->width = compose->width; + src_fmt->height = compose->height; + } + + sel->r = *crop; + return 0; +} + +static int mali_c55_rsz_set_compose(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd); + struct mali_c55 *mali_c55 = rsz->mali_c55; + struct v4l2_mbus_framefmt *src_fmt; + struct v4l2_rect *compose, *crop; + + /* + * We cannot change the compose rectangle during streaming, as that + * would require a change in the output buffer size. + */ + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && + v4l2_subdev_is_streaming(sd)) + return -EBUSY; + + /* + * In the FR pipe, the scaler is an optional component that may not be + * fitted. + */ + if (rsz->id == MALI_C55_RSZ_FR && + !(mali_c55->capabilities & MALI_C55_GPS_FRSCALER_FITTED)) + return -EINVAL; + + compose = v4l2_subdev_state_get_compose(state, MALI_C55_RSZ_SINK_PAD); + crop = v4l2_subdev_state_get_crop(state, MALI_C55_RSZ_SINK_PAD); + + compose->left = 0; + compose->top = 0; + compose->width = clamp_t(unsigned int, sel->r.width, crop->width / 8, + crop->width); + compose->height = clamp_t(unsigned int, sel->r.height, crop->height / 8, + crop->height); + + sel->r = *compose; + + /* + * We need to be sure to propagate the compose rectangle size to the + * source pad format. + */ + src_fmt = v4l2_subdev_state_get_format(state, MALI_C55_RSZ_SOURCE_PAD); + src_fmt->width = compose->width; + src_fmt->height = compose->height; + + return 0; +} + +static int mali_c55_rsz_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + if (sel->pad != MALI_C55_RSZ_SINK_PAD) + return -EINVAL; + + if (sel->target == V4L2_SEL_TGT_CROP) + return mali_c55_rsz_set_crop(sd, state, sel); + + if (sel->target == V4L2_SEL_TGT_COMPOSE) + return mali_c55_rsz_set_compose(sd, state, sel); + + return -EINVAL; +} + +static int mali_c55_rsz_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + if (which == V4L2_SUBDEV_FORMAT_ACTIVE && + media_entity_is_streaming(&sd->entity)) + return -EBUSY; + + return __mali_c55_rsz_set_routing(sd, state, routing); +} + +static int mali_c55_rsz_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd); + struct mali_c55 *mali_c55 = rsz->mali_c55; + unsigned int sink_pad; + + sink_pad = mali_c55_rsz_get_active_sink(state); + if (sink_pad == MALI_C55_RSZ_SINK_BYPASS_PAD) { + /* Bypass FR pipe processing if the bypass route is active. */ + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_ISP_RAW_BYPASS, + MALI_C55_ISP_RAW_BYPASS_FR_BYPASS_MASK, + MALI_C55_ISP_RAW_BYPASS_RAW_FR_BYPASS); + return 0; + } + + /* Disable bypass and use regular processing. */ + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_ISP_RAW_BYPASS, + MALI_C55_ISP_RAW_BYPASS_FR_BYPASS_MASK, 0); + mali_c55_rsz_program(rsz, state); + + return 0; +} + +static int mali_c55_rsz_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + return 0; +} + +static const struct v4l2_subdev_pad_ops mali_c55_resizer_pad_ops = { + .enum_mbus_code = mali_c55_rsz_enum_mbus_code, + .enum_frame_size = mali_c55_rsz_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = mali_c55_rsz_set_fmt, + .get_selection = mali_c55_rsz_get_selection, + .set_selection = mali_c55_rsz_set_selection, + .set_routing = mali_c55_rsz_set_routing, + .enable_streams = mali_c55_rsz_enable_streams, + .disable_streams = mali_c55_rsz_disable_streams, +}; + +static const struct v4l2_subdev_ops mali_c55_resizer_ops = { + .pad = &mali_c55_resizer_pad_ops, +}; + +static int mali_c55_rsz_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct mali_c55_resizer *rsz = sd_to_mali_c55_rsz(sd); + struct v4l2_subdev_route routes[2] = { + { + .sink_pad = MALI_C55_RSZ_SINK_PAD, + .source_pad = MALI_C55_RSZ_SOURCE_PAD, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, { + .sink_pad = MALI_C55_RSZ_SINK_BYPASS_PAD, + .source_pad = MALI_C55_RSZ_SOURCE_PAD, + }, + }; + struct v4l2_subdev_krouting routing = { + .num_routes = rsz->num_routes, + .routes = routes, + }; + + return __mali_c55_rsz_set_routing(sd, state, &routing); +} + +static const struct v4l2_subdev_internal_ops mali_c55_resizer_internal_ops = { + .init_state = mali_c55_rsz_init_state, +}; + +static int mali_c55_register_resizer(struct mali_c55 *mali_c55, + unsigned int index) +{ + struct mali_c55_resizer *rsz = &mali_c55->resizers[index]; + struct v4l2_subdev *sd = &rsz->sd; + unsigned int num_pads; + int ret; + + rsz->id = index; + v4l2_subdev_init(sd, &mali_c55_resizer_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; + sd->internal_ops = &mali_c55_resizer_internal_ops; + + rsz->pads[MALI_C55_RSZ_SINK_PAD].flags = MEDIA_PAD_FL_SINK; + rsz->pads[MALI_C55_RSZ_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE; + + if (rsz->id == MALI_C55_RSZ_FR) { + num_pads = MALI_C55_RSZ_NUM_PADS; + rsz->num_routes = 2; + + rsz->pads[MALI_C55_RSZ_SINK_BYPASS_PAD].flags = + MEDIA_PAD_FL_SINK; + + snprintf(sd->name, sizeof(sd->name), "%s resizer fr", + MALI_C55_DRIVER_NAME); + + } else { + num_pads = MALI_C55_RSZ_NUM_PADS - 1; + rsz->num_routes = 1; + + snprintf(sd->name, sizeof(sd->name), "%s resizer ds", + MALI_C55_DRIVER_NAME); + } + + ret = media_entity_pads_init(&sd->entity, num_pads, rsz->pads); + if (ret) + return ret; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_media_cleanup; + + ret = v4l2_device_register_subdev(&mali_c55->v4l2_dev, sd); + if (ret) + goto err_subdev_cleanup; + + rsz->cap_dev = &mali_c55->cap_devs[index]; + rsz->mali_c55 = mali_c55; + + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_media_cleanup: + media_entity_cleanup(&sd->entity); + + return ret; +} + +static void mali_c55_unregister_resizer(struct mali_c55_resizer *rsz) +{ + if (!rsz->mali_c55) + return; + + v4l2_device_unregister_subdev(&rsz->sd); + v4l2_subdev_cleanup(&rsz->sd); + media_entity_cleanup(&rsz->sd.entity); +} + +int mali_c55_register_resizers(struct mali_c55 *mali_c55) +{ + int ret; + + ret = mali_c55_register_resizer(mali_c55, MALI_C55_RSZ_FR); + if (ret) + return ret; + + if (mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED) { + ret = mali_c55_register_resizer(mali_c55, MALI_C55_RSZ_DS); + if (ret) + goto err_unregister_fr; + } + + return 0; + +err_unregister_fr: + mali_c55_unregister_resizer(&mali_c55->resizers[MALI_C55_RSZ_FR]); + + return ret; +} + +void mali_c55_unregister_resizers(struct mali_c55 *mali_c55) +{ + for (unsigned int i = 0; i < MALI_C55_NUM_RSZS; i++) + mali_c55_unregister_resizer(&mali_c55->resizers[i]); +} diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-stats.c b/drivers/media/platform/arm/mali-c55/mali-c55-stats.c new file mode 100644 index 000000000000..655e52a5f288 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/mali-c55-stats.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM Mali-C55 ISP Driver - 3A Statistics capture device + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include <linux/container_of.h> +#include <linux/dev_printk.h> +#include <linux/list.h> +#include <linux/media/arm/mali-c55-config.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/spinlock.h> +#include <linux/string.h> + +#include <media/media-entity.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "mali-c55-common.h" +#include "mali-c55-registers.h" + +static const unsigned int metering_space_addrs[] = { + [MALI_C55_CONFIG_PING] = 0x095ac, + [MALI_C55_CONFIG_PONG] = 0x2156c, +}; + +static int mali_c55_stats_enum_fmt_meta_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + + f->pixelformat = V4L2_META_FMT_MALI_C55_STATS; + + return 0; +} + +static int mali_c55_stats_g_fmt_meta_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + static const struct v4l2_meta_format mfmt = { + .dataformat = V4L2_META_FMT_MALI_C55_STATS, + .buffersize = sizeof(struct mali_c55_stats_buffer) + }; + + f->fmt.meta = mfmt; + + return 0; +} + +static int mali_c55_stats_querycap(struct file *file, + void *priv, struct v4l2_capability *cap) +{ + strscpy(cap->driver, MALI_C55_DRIVER_NAME, sizeof(cap->driver)); + strscpy(cap->card, "ARM Mali-C55 ISP", sizeof(cap->card)); + + return 0; +} + +static const struct v4l2_ioctl_ops mali_c55_stats_v4l2_ioctl_ops = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_fmt_meta_cap = mali_c55_stats_enum_fmt_meta_cap, + .vidioc_g_fmt_meta_cap = mali_c55_stats_g_fmt_meta_cap, + .vidioc_s_fmt_meta_cap = mali_c55_stats_g_fmt_meta_cap, + .vidioc_try_fmt_meta_cap = mali_c55_stats_g_fmt_meta_cap, + .vidioc_querycap = mali_c55_stats_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_file_operations mali_c55_stats_v4l2_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +static int +mali_c55_stats_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + if (*num_planes && *num_planes > 1) + return -EINVAL; + + if (sizes[0] && sizes[0] < sizeof(struct mali_c55_stats_buffer)) + return -EINVAL; + + *num_planes = 1; + + if (!sizes[0]) + sizes[0] = sizeof(struct mali_c55_stats_buffer); + + return 0; +} + +static void mali_c55_stats_buf_queue(struct vb2_buffer *vb) +{ + struct mali_c55_stats *stats = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mali_c55_stats_buf *buf = container_of(vbuf, + struct mali_c55_stats_buf, vb); + + vb2_set_plane_payload(vb, 0, sizeof(struct mali_c55_stats_buffer)); + buf->segments_remaining = 2; + buf->failed = false; + + spin_lock(&stats->buffers.lock); + list_add_tail(&buf->queue, &stats->buffers.queue); + spin_unlock(&stats->buffers.lock); +} + +static void mali_c55_stats_return_buffers(struct mali_c55_stats *stats, + enum vb2_buffer_state state) +{ + struct mali_c55_stats_buf *buf, *tmp; + + guard(spinlock)(&stats->buffers.lock); + + list_for_each_entry_safe(buf, tmp, &stats->buffers.queue, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } +} + +static int mali_c55_stats_start_streaming(struct vb2_queue *q, + unsigned int count) +{ + struct mali_c55_stats *stats = vb2_get_drv_priv(q); + struct mali_c55 *mali_c55 = stats->mali_c55; + int ret; + + ret = pm_runtime_resume_and_get(mali_c55->dev); + if (ret) + goto err_return_buffers; + + ret = video_device_pipeline_alloc_start(&stats->vdev); + if (ret) + goto err_pm_put; + + if (mali_c55_pipeline_ready(mali_c55)) { + ret = v4l2_subdev_enable_streams(&mali_c55->isp.sd, + MALI_C55_ISP_PAD_SOURCE_VIDEO, + BIT(0)); + if (ret < 0) + goto err_stop_pipeline; + } + + return 0; + +err_stop_pipeline: + video_device_pipeline_stop(&stats->vdev); +err_pm_put: + pm_runtime_put_autosuspend(mali_c55->dev); +err_return_buffers: + mali_c55_stats_return_buffers(stats, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void mali_c55_stats_stop_streaming(struct vb2_queue *q) +{ + struct mali_c55_stats *stats = vb2_get_drv_priv(q); + struct mali_c55 *mali_c55 = stats->mali_c55; + struct mali_c55_isp *isp = &mali_c55->isp; + + if (mali_c55_pipeline_ready(mali_c55)) { + if (v4l2_subdev_is_streaming(&isp->sd)) + v4l2_subdev_disable_streams(&isp->sd, + MALI_C55_ISP_PAD_SOURCE_VIDEO, + BIT(0)); + } + + video_device_pipeline_stop(&stats->vdev); + mali_c55_stats_return_buffers(stats, VB2_BUF_STATE_ERROR); + + pm_runtime_put_autosuspend(stats->mali_c55->dev); +} + +static const struct vb2_ops mali_c55_stats_vb2_ops = { + .queue_setup = mali_c55_stats_queue_setup, + .buf_queue = mali_c55_stats_buf_queue, + .start_streaming = mali_c55_stats_start_streaming, + .stop_streaming = mali_c55_stats_stop_streaming, +}; + +static void mali_c55_stats_cpu_read(struct mali_c55_stats *stats, + struct mali_c55_stats_buf *buf, + enum mali_c55_config_spaces cfg_space) +{ + struct mali_c55 *mali_c55 = stats->mali_c55; + const void __iomem *src; + size_t length; + void *dst; + + src = mali_c55->base + MALI_C55_REG_1024BIN_HIST; + dst = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + memcpy_fromio(dst, src, MALI_C55_1024BIN_HIST_SIZE); + + src = mali_c55->base + metering_space_addrs[cfg_space]; + dst += MALI_C55_1024BIN_HIST_SIZE; + length = sizeof(struct mali_c55_stats_buffer) - MALI_C55_1024BIN_HIST_SIZE; + memcpy_fromio(dst, src, length); +} + +void mali_c55_stats_fill_buffer(struct mali_c55 *mali_c55, + enum mali_c55_config_spaces cfg_space) +{ + struct mali_c55_stats *stats = &mali_c55->stats; + struct mali_c55_stats_buf *buf = NULL; + + spin_lock(&stats->buffers.lock); + if (!list_empty(&stats->buffers.queue)) { + buf = list_first_entry(&stats->buffers.queue, + struct mali_c55_stats_buf, queue); + list_del(&buf->queue); + } + spin_unlock(&stats->buffers.lock); + + if (!buf) + return; + + buf->vb.sequence = mali_c55->isp.frame_sequence; + buf->vb.vb2_buf.timestamp = ktime_get_boottime_ns(); + + mali_c55_stats_cpu_read(stats, buf, cfg_space); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); +} + +void mali_c55_unregister_stats(struct mali_c55 *mali_c55) +{ + struct mali_c55_stats *stats = &mali_c55->stats; + + if (!video_is_registered(&stats->vdev)) + return; + + vb2_video_unregister_device(&stats->vdev); + media_entity_cleanup(&stats->vdev.entity); + + mutex_destroy(&stats->lock); +} + +int mali_c55_register_stats(struct mali_c55 *mali_c55) +{ + struct mali_c55_stats *stats = &mali_c55->stats; + struct video_device *vdev = &stats->vdev; + struct vb2_queue *vb2q = &stats->queue; + int ret; + + mutex_init(&stats->lock); + INIT_LIST_HEAD(&stats->buffers.queue); + spin_lock_init(&stats->buffers.lock); + + stats->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&stats->vdev.entity, 1, &stats->pad); + if (ret) + goto err_destroy_mutex; + + vb2q->type = V4L2_BUF_TYPE_META_CAPTURE; + vb2q->io_modes = VB2_MMAP | VB2_DMABUF; + vb2q->drv_priv = stats; + vb2q->mem_ops = &vb2_dma_contig_memops; + vb2q->ops = &mali_c55_stats_vb2_ops; + vb2q->buf_struct_size = sizeof(struct mali_c55_stats_buf); + vb2q->min_queued_buffers = 1; + vb2q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vb2q->lock = &stats->lock; + vb2q->dev = mali_c55->dev; + + ret = vb2_queue_init(vb2q); + if (ret) { + dev_err(mali_c55->dev, "stats vb2 queue init failed\n"); + goto err_cleanup_entity; + } + + strscpy(stats->vdev.name, "mali-c55 3a stats", sizeof(stats->vdev.name)); + vdev->release = video_device_release_empty; + vdev->fops = &mali_c55_stats_v4l2_fops; + vdev->ioctl_ops = &mali_c55_stats_v4l2_ioctl_ops; + vdev->lock = &stats->lock; + vdev->v4l2_dev = &mali_c55->v4l2_dev; + vdev->queue = &stats->queue; + vdev->device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING; + vdev->vfl_dir = VFL_DIR_RX; + video_set_drvdata(vdev, stats); + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(mali_c55->dev, + "failed to register stats video device\n"); + goto err_release_vb2q; + } + + stats->mali_c55 = mali_c55; + + return 0; + +err_release_vb2q: + vb2_queue_release(vb2q); +err_cleanup_entity: + media_entity_cleanup(&stats->vdev.entity); +err_destroy_mutex: + + mutex_destroy(&stats->lock); + + return ret; +} diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-tpg.c b/drivers/media/platform/arm/mali-c55/mali-c55-tpg.c new file mode 100644 index 000000000000..1af5d2759a83 --- /dev/null +++ b/drivers/media/platform/arm/mali-c55/mali-c55-tpg.c @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM Mali-C55 ISP Driver - Test pattern generator + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include <linux/minmax.h> +#include <linux/pm_runtime.h> +#include <linux/string.h> + +#include <media/media-entity.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-subdev.h> + +#include "mali-c55-common.h" +#include "mali-c55-registers.h" + +#define MALI_C55_TPG_SRC_PAD 0 +#define MALI_C55_TPG_FIXED_HBLANK 0x20 +#define MALI_C55_TPG_DEFAULT_MIN_VBLANK 66 +#define MALI_C55_TPG_DEFAULT_DEF_VBLANK 626 +#define MALI_C55_TPG_MAX_VBLANK 0xffff +#define MALI_C55_TPG_PIXEL_RATE 100000000 + +static const char * const mali_c55_tpg_test_pattern_menu[] = { + "Flat field", + "Horizontal gradient", + "Vertical gradient", + "Vertical bars", + "Arbitrary rectangle", + "White frame on black field" +}; + +static const u32 mali_c55_tpg_mbus_codes[] = { + MEDIA_BUS_FMT_SRGGB20_1X20, + MEDIA_BUS_FMT_RGB202020_1X60, +}; + +static void mali_c55_tpg_update_vblank(struct mali_c55_tpg *tpg, + struct v4l2_mbus_framefmt *format) +{ + unsigned int def_vblank; + unsigned int min_vblank; + unsigned int hts; + int tgt_fps; + + hts = format->width + MALI_C55_TPG_FIXED_HBLANK; + + /* + * The ISP has minimum vertical blanking requirements that must be + * adhered to by the TPG. The minimum is a function of the Iridix blocks + * clocking requirements and the width of the image and horizontal + * blanking, but if we assume the worst case iVariance and sVariance + * values then it boils down to the below (plus one to the numerator to + * ensure the answer is rounded up). + */ + min_vblank = 15 + (120501 / hts); + + /* + * We need to set a sensible default vblank for whatever format height + * we happen to be given from set_fmt(). This function just targets + * an even multiple of 15fps. If we can't get 15fps, let's target 5fps. + * If we can't get 5fps we'll take whatever the minimum vblank gives us. + */ + tgt_fps = MALI_C55_TPG_PIXEL_RATE / hts / (format->height + min_vblank); + + if (tgt_fps < 5) + def_vblank = min_vblank; + else + def_vblank = (MALI_C55_TPG_PIXEL_RATE / hts + / max(rounddown(tgt_fps, 15), 5)) - format->height; + + def_vblank = ALIGN_DOWN(def_vblank, 2); + + __v4l2_ctrl_modify_range(tpg->ctrls.vblank, min_vblank, + MALI_C55_TPG_MAX_VBLANK, 1, def_vblank); + __v4l2_ctrl_s_ctrl(tpg->ctrls.vblank, def_vblank); +} + +static int mali_c55_tpg_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mali_c55_tpg *tpg = container_of(ctrl->handler, + struct mali_c55_tpg, + ctrls.handler); + struct mali_c55 *mali_c55 = container_of(tpg, struct mali_c55, tpg); + int ret = 0; + + if (!pm_runtime_get_if_in_use(mali_c55->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_TEST_PATTERN: + mali_c55_ctx_write(mali_c55, + MALI_C55_REG_TEST_GEN_CH0_PATTERN_TYPE, + ctrl->val); + break; + case V4L2_CID_VBLANK: + mali_c55_update_bits(mali_c55, MALI_C55_REG_BLANKING, + MALI_C55_REG_VBLANK_MASK, + MALI_C55_VBLANK(ctrl->val)); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put_autosuspend(mali_c55->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops mali_c55_tpg_ctrl_ops = { + .s_ctrl = &mali_c55_tpg_s_ctrl, +}; + +static void mali_c55_tpg_configure(struct mali_c55_tpg *tpg, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *fmt; + u32 test_pattern_format; + + /* + * hblank needs setting, but is a read-only control and thus won't be + * called during __v4l2_ctrl_handler_setup(). Do it here instead. + */ + mali_c55_update_bits(tpg->mali_c55, MALI_C55_REG_BLANKING, + MALI_C55_REG_HBLANK_MASK, + MALI_C55_TPG_FIXED_HBLANK); + mali_c55_update_bits(tpg->mali_c55, MALI_C55_REG_GEN_VIDEO, + MALI_C55_REG_GEN_VIDEO_MULTI_MASK, + MALI_C55_REG_GEN_VIDEO_MULTI_MASK); + + fmt = v4l2_subdev_state_get_format(state, MALI_C55_TPG_SRC_PAD); + + test_pattern_format = fmt->code == MEDIA_BUS_FMT_RGB202020_1X60 ? + 0x01 : 0x0; + + mali_c55_ctx_update_bits(tpg->mali_c55, MALI_C55_REG_TPG_CH0, + MALI_C55_TEST_PATTERN_RGB_MASK, + MALI_C55_TEST_PATTERN_RGB(test_pattern_format)); +} + +static int mali_c55_tpg_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(mali_c55_tpg_mbus_codes)) + return -EINVAL; + + code->code = mali_c55_tpg_mbus_codes[code->index]; + + return 0; +} + +static int mali_c55_tpg_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + unsigned int i; + + if (fse->index > 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(mali_c55_tpg_mbus_codes); i++) { + if (fse->code == mali_c55_tpg_mbus_codes[i]) + break; + } + + if (i == ARRAY_SIZE(mali_c55_tpg_mbus_codes)) + return -EINVAL; + + fse->min_width = MALI_C55_MIN_WIDTH; + fse->max_width = MALI_C55_MAX_WIDTH; + fse->min_height = MALI_C55_MIN_HEIGHT; + fse->max_height = MALI_C55_MAX_HEIGHT; + + return 0; +} + +static int mali_c55_tpg_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct mali_c55_tpg *tpg = container_of(sd, struct mali_c55_tpg, sd); + struct v4l2_mbus_framefmt *fmt; + unsigned int i; + + fmt = v4l2_subdev_state_get_format(state, MALI_C55_TPG_SRC_PAD); + fmt->code = format->format.code; + + for (i = 0; i < ARRAY_SIZE(mali_c55_tpg_mbus_codes); i++) { + if (fmt->code == mali_c55_tpg_mbus_codes[i]) + break; + } + + if (i == ARRAY_SIZE(mali_c55_tpg_mbus_codes)) + fmt->code = MEDIA_BUS_FMT_SRGGB20_1X20; + + /* + * The TPG says that the test frame timing generation logic expects a + * minimum framesize of 4x4 pixels, but given the rest of the ISP can't + * handle anything smaller than 128x128 it seems pointless to allow a + * smaller frame. + */ + fmt->width = clamp(format->format.width, MALI_C55_MIN_WIDTH, + MALI_C55_MAX_WIDTH); + fmt->height = clamp(format->format.height, MALI_C55_MIN_HEIGHT, + MALI_C55_MAX_HEIGHT); + + format->format = *fmt; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + + mali_c55_tpg_update_vblank(tpg, fmt); + + return 0; +} + +static int mali_c55_tpg_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct mali_c55_tpg *tpg = container_of(sd, struct mali_c55_tpg, sd); + struct mali_c55 *mali_c55 = container_of(tpg, struct mali_c55, tpg); + + /* + * We only have a source pad and a single stream, and v4l2-core already + * validated both so we don't need to do that. One might reasonably + * expect the framesize to be set here given it's configurable in + * .set_fmt(), but it's done in the ISP subdevice's .enable_streams() + * instead, as the same register is also used to indicate the size of + * the data coming from the sensor. + */ + mali_c55_tpg_configure(tpg, state); + __v4l2_ctrl_handler_setup(sd->ctrl_handler); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_TPG_CH0, + MALI_C55_TEST_PATTERN_ON_OFF, + MALI_C55_TEST_PATTERN_ON_OFF); + mali_c55_update_bits(mali_c55, MALI_C55_REG_GEN_VIDEO, + MALI_C55_REG_GEN_VIDEO_ON_MASK, + MALI_C55_REG_GEN_VIDEO_ON_MASK); + + return 0; +} + +static int mali_c55_tpg_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct mali_c55_tpg *tpg = container_of(sd, struct mali_c55_tpg, sd); + struct mali_c55 *mali_c55 = container_of(tpg, struct mali_c55, tpg); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_TPG_CH0, + MALI_C55_TEST_PATTERN_ON_OFF, 0x00); + mali_c55_update_bits(mali_c55, MALI_C55_REG_GEN_VIDEO, + MALI_C55_REG_GEN_VIDEO_ON_MASK, 0x00); + + return 0; +} + +static const struct v4l2_subdev_pad_ops mali_c55_tpg_pad_ops = { + .enum_mbus_code = mali_c55_tpg_enum_mbus_code, + .enum_frame_size = mali_c55_tpg_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = mali_c55_tpg_set_fmt, + .enable_streams = mali_c55_tpg_enable_streams, + .disable_streams = mali_c55_tpg_disable_streams, +}; + +static const struct v4l2_subdev_core_ops mali_c55_isp_core_ops = { + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops mali_c55_tpg_ops = { + .core = &mali_c55_isp_core_ops, + .pad = &mali_c55_tpg_pad_ops, +}; + +static int mali_c55_tpg_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *fmt = + v4l2_subdev_state_get_format(state, MALI_C55_TPG_SRC_PAD); + + fmt->width = MALI_C55_DEFAULT_WIDTH; + fmt->height = MALI_C55_DEFAULT_HEIGHT; + fmt->field = V4L2_FIELD_NONE; + fmt->code = MEDIA_BUS_FMT_SRGGB20_1X20; + fmt->colorspace = V4L2_COLORSPACE_RAW; + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace); + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); + fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(false, + fmt->colorspace, + fmt->ycbcr_enc); + + return 0; +} + +static const struct v4l2_subdev_internal_ops mali_c55_tpg_internal_ops = { + .init_state = mali_c55_tpg_init_state, +}; + +static int mali_c55_tpg_init_controls(struct mali_c55 *mali_c55) +{ + struct mali_c55_tpg_ctrls *ctrls = &mali_c55->tpg.ctrls; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *hblank; + int ret; + + ret = v4l2_ctrl_handler_init(&ctrls->handler, 4); + if (ret) + return ret; + + v4l2_ctrl_new_std_menu_items(&ctrls->handler, &mali_c55_tpg_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mali_c55_tpg_test_pattern_menu) - 1, + 0, 3, mali_c55_tpg_test_pattern_menu); + + /* + * We fix hblank at the minimum allowed value and control framerate + * solely through the vblank control. + */ + hblank = v4l2_ctrl_new_std(&ctrls->handler, &mali_c55_tpg_ctrl_ops, + V4L2_CID_HBLANK, MALI_C55_TPG_FIXED_HBLANK, + MALI_C55_TPG_FIXED_HBLANK, 1, + MALI_C55_TPG_FIXED_HBLANK); + if (hblank) + hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctrls->vblank = v4l2_ctrl_new_std(&ctrls->handler, + &mali_c55_tpg_ctrl_ops, + V4L2_CID_VBLANK, + MALI_C55_TPG_DEFAULT_MIN_VBLANK, + MALI_C55_TPG_MAX_VBLANK, 1, + MALI_C55_TPG_DEFAULT_DEF_VBLANK); + + pixel_rate = v4l2_ctrl_new_std(&ctrls->handler, &mali_c55_tpg_ctrl_ops, + V4L2_CID_PIXEL_RATE, + MALI_C55_TPG_PIXEL_RATE, + MALI_C55_TPG_PIXEL_RATE, 1, + MALI_C55_TPG_PIXEL_RATE); + if (pixel_rate) + pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + if (ctrls->handler.error) { + dev_err(mali_c55->dev, "Error during v4l2 controls init\n"); + v4l2_ctrl_handler_free(&ctrls->handler); + return ctrls->handler.error; + } + + mali_c55->tpg.sd.ctrl_handler = &ctrls->handler; + mali_c55->tpg.sd.state_lock = ctrls->handler.lock; + + return 0; +} + +int mali_c55_register_tpg(struct mali_c55 *mali_c55) +{ + struct mali_c55_tpg *tpg = &mali_c55->tpg; + struct v4l2_subdev *sd = &tpg->sd; + struct media_pad *pad = &tpg->pad; + int ret; + + v4l2_subdev_init(sd, &mali_c55_tpg_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + sd->internal_ops = &mali_c55_tpg_internal_ops; + strscpy(sd->name, MALI_C55_DRIVER_NAME " tpg", sizeof(sd->name)); + + pad->flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&sd->entity, 1, pad); + if (ret) { + dev_err(mali_c55->dev, + "Failed to initialize media entity pads\n"); + return ret; + } + + ret = mali_c55_tpg_init_controls(mali_c55); + if (ret) { + dev_err(mali_c55->dev, + "Error initialising controls\n"); + goto err_cleanup_media_entity; + } + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_free_ctrl_handler; + + ret = v4l2_device_register_subdev(&mali_c55->v4l2_dev, sd); + if (ret) { + dev_err(mali_c55->dev, "Failed to register tpg subdev\n"); + goto err_cleanup_subdev; + } + + /* + * By default the colour settings lead to a very dim image that is + * nearly indistinguishable from black on some monitor settings. Ramp + * them up a bit so the image is brighter. + */ + mali_c55_ctx_write(mali_c55, MALI_C55_REG_TPG_R_BACKGROUND, + MALI_C55_TPG_BACKGROUND_MAX); + mali_c55_ctx_write(mali_c55, MALI_C55_REG_TPG_G_BACKGROUND, + MALI_C55_TPG_BACKGROUND_MAX); + mali_c55_ctx_write(mali_c55, MALI_C55_REG_TPG_B_BACKGROUND, + MALI_C55_TPG_BACKGROUND_MAX); + + tpg->mali_c55 = mali_c55; + + return 0; + +err_cleanup_subdev: + v4l2_subdev_cleanup(sd); +err_free_ctrl_handler: + v4l2_ctrl_handler_free(&tpg->ctrls.handler); +err_cleanup_media_entity: + media_entity_cleanup(&sd->entity); + + return ret; +} + +void mali_c55_unregister_tpg(struct mali_c55 *mali_c55) +{ + struct mali_c55_tpg *tpg = &mali_c55->tpg; + + if (!tpg->mali_c55) + return; + + v4l2_device_unregister_subdev(&tpg->sd); + v4l2_ctrl_handler_free(&tpg->ctrls.handler); + v4l2_subdev_cleanup(&tpg->sd); + media_entity_cleanup(&tpg->sd.entity); +} diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c index 54cae0da9aca..b83e43245277 100644 --- a/drivers/media/platform/aspeed/aspeed-video.c +++ b/drivers/media/platform/aspeed/aspeed-video.c @@ -4,6 +4,7 @@ #include <linux/atomic.h> #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> @@ -25,6 +26,8 @@ #include <linux/workqueue.h> #include <linux/debugfs.h> #include <linux/ktime.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-dev.h> #include <media/v4l2-device.h> @@ -203,6 +206,25 @@ #define VE_MEM_RESTRICT_START 0x310 #define VE_MEM_RESTRICT_END 0x314 +/* SCU's registers */ +#define SCU_MISC_CTRL 0xC0 +#define SCU_DPLL_SOURCE BIT(20) + +/* GFX's registers */ +#define GFX_CTRL 0x60 +#define GFX_CTRL_ENABLE BIT(0) +#define GFX_CTRL_FMT GENMASK(9, 7) + +#define GFX_H_DISPLAY 0x70 +#define GFX_H_DISPLAY_DE GENMASK(28, 16) +#define GFX_H_DISPLAY_TOTAL GENMASK(12, 0) + +#define GFX_V_DISPLAY 0x78 +#define GFX_V_DISPLAY_DE GENMASK(27, 16) +#define GFX_V_DISPLAY_TOTAL GENMASK(11, 0) + +#define GFX_DISPLAY_ADDR 0x80 + /* * VIDEO_MODE_DETECT_DONE: a flag raised if signal lock * VIDEO_RES_CHANGE: a flag raised if res_change work on-going @@ -262,6 +284,7 @@ struct aspeed_video_perf { /* * struct aspeed_video - driver data * + * version: holds the version of aspeed SoC * res_work: holds the delayed_work for res-detection if unlock * buffers: holds the list of buffer queued from user * flags: holds the state of video @@ -273,6 +296,7 @@ struct aspeed_video_perf { * yuv420: a flag raised if JPEG subsampling is 420 * format: holds the video format * hq_mode: a flag raised if HQ is enabled. Only for VIDEO_FMT_ASPEED + * input: holds the video input * frame_rate: holds the frame_rate * jpeg_quality: holds jpeq's quality (0~11) * jpeg_hq_quality: holds hq's quality (1~12) only if hq_mode enabled @@ -298,6 +322,9 @@ struct aspeed_video { struct video_device vdev; struct mutex video_lock; /* v4l2 and videobuf2 lock */ + struct regmap *scu; + struct regmap *gfx; + u32 version; u32 jpeg_mode; u32 comp_size_read; @@ -316,6 +343,7 @@ struct aspeed_video { bool yuv420; enum aspeed_video_format format; bool hq_mode; + enum aspeed_video_input input; unsigned int frame_rate; unsigned int jpeg_quality; unsigned int jpeg_hq_quality; @@ -331,21 +359,25 @@ struct aspeed_video { #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev) struct aspeed_video_config { + u32 version; u32 jpeg_mode; u32 comp_size_read; }; static const struct aspeed_video_config ast2400_config = { + .version = 4, .jpeg_mode = AST2400_VE_SEQ_CTRL_JPEG_MODE, .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, }; static const struct aspeed_video_config ast2500_config = { + .version = 5, .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, }; static const struct aspeed_video_config ast2600_config = { + .version = 6, .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK, }; @@ -485,6 +517,7 @@ static const struct v4l2_dv_timings_cap aspeed_video_timings_cap = { static const char * const format_str[] = {"Standard JPEG", "Aspeed JPEG"}; +static const char * const input_str[] = {"HOST VGA", "BMC GFX"}; static unsigned int debug; @@ -609,6 +642,14 @@ static int aspeed_video_start_frame(struct aspeed_video *video) aspeed_video_free_buf(video, &video->bcd); } + if (video->input == VIDEO_INPUT_GFX) { + u32 val; + + // update input buffer address as gfx's + regmap_read(video->gfx, GFX_DISPLAY_ADDR, &val); + aspeed_video_write(video, VE_TGS_0, val); + } + spin_lock_irqsave(&video->lock, flags); buf = list_first_entry_or_null(&video->buffers, struct aspeed_video_buffer, link); @@ -1026,9 +1067,23 @@ static void aspeed_video_get_timings(struct aspeed_video *v, } } +static void aspeed_video_get_resolution_gfx(struct aspeed_video *video, + struct v4l2_bt_timings *det) +{ + u32 h_val, v_val; + + regmap_read(video->gfx, GFX_H_DISPLAY, &h_val); + regmap_read(video->gfx, GFX_V_DISPLAY, &v_val); + + det->width = FIELD_GET(GFX_H_DISPLAY_DE, h_val) + 1; + det->height = FIELD_GET(GFX_V_DISPLAY_DE, v_val) + 1; + video->v4l2_input_status = 0; +} + #define res_check(v) test_and_clear_bit(VIDEO_MODE_DETECT_DONE, &(v)->flags) -static void aspeed_video_get_resolution(struct aspeed_video *video) +static void aspeed_video_get_resolution_vga(struct aspeed_video *video, + struct v4l2_bt_timings *det) { bool invalid_resolution = true; int rc; @@ -1036,7 +1091,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) u32 mds; u32 src_lr_edge; u32 src_tb_edge; - struct v4l2_bt_timings *det = &video->detected_timings; det->width = MIN_WIDTH; det->height = MIN_HEIGHT; @@ -1113,14 +1167,20 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) aspeed_video_get_timings(video, det); - /* - * Enable mode-detect watchdog, resolution-change watchdog and - * automatic compression after frame capture. - */ + /* Enable mode-detect watchdog, resolution-change watchdog */ aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, VE_INTERRUPT_MODE_DETECT_WD); - aspeed_video_update(video, VE_SEQ_CTRL, 0, - VE_SEQ_CTRL_AUTO_COMP | VE_SEQ_CTRL_EN_WATCHDOG); + aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_EN_WATCHDOG); +} + +static void aspeed_video_get_resolution(struct aspeed_video *video) +{ + struct v4l2_bt_timings *det = &video->detected_timings; + + if (video->input == VIDEO_INPUT_GFX) + aspeed_video_get_resolution_gfx(video, det); + else + aspeed_video_get_resolution_vga(video, det); v4l2_dbg(1, debug, &video->v4l2_dev, "Got resolution: %dx%d\n", det->width, det->height); @@ -1156,7 +1216,7 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4); /* Don't use direct mode below 1024 x 768 (irqs don't fire) */ - if (size < DIRECT_FETCH_THRESHOLD) { + if (video->input == VIDEO_INPUT_VGA && size < DIRECT_FETCH_THRESHOLD) { v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Sync Mode\n"); aspeed_video_write(video, VE_TGS_0, FIELD_PREP(VE_TGS_FIRST, @@ -1171,10 +1231,20 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, VE_CTRL_INT_DE); } else { + u32 ctrl, val, bpp; + v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Direct Mode\n"); + ctrl = VE_CTRL_DIRECT_FETCH; + if (video->input == VIDEO_INPUT_GFX) { + regmap_read(video->gfx, GFX_CTRL, &val); + bpp = FIELD_GET(GFX_CTRL_FMT, val) ? 32 : 16; + if (bpp == 16) + ctrl |= VE_CTRL_INT_DE; + aspeed_video_write(video, VE_TGS_1, act->width * (bpp >> 3)); + } aspeed_video_update(video, VE_CTRL, VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, - VE_CTRL_DIRECT_FETCH); + ctrl); } size *= 4; @@ -1207,6 +1277,22 @@ err_mem: aspeed_video_free_buf(video, &video->srcs[0]); } +/* + * Update relative parameters when timing changed. + * + * @video: the struct of aspeed_video + * @timings: the new timings + */ +static void aspeed_video_update_timings(struct aspeed_video *video, struct v4l2_bt_timings *timings) +{ + video->active_timings = *timings; + aspeed_video_set_resolution(video); + + video->pix_fmt.width = timings->width; + video->pix_fmt.height = timings->height; + video->pix_fmt.sizeimage = video->max_compressed_size; +} + static void aspeed_video_update_regs(struct aspeed_video *video) { u8 jpeg_hq_quality = clamp((int)video->jpeg_hq_quality - 1, 0, @@ -1219,6 +1305,8 @@ static void aspeed_video_update_regs(struct aspeed_video *video) u32 ctrl = 0; u32 seq_ctrl = 0; + v4l2_dbg(1, debug, &video->v4l2_dev, "input(%s)\n", + input_str[video->input]); v4l2_dbg(1, debug, &video->v4l2_dev, "framerate(%d)\n", video->frame_rate); v4l2_dbg(1, debug, &video->v4l2_dev, "jpeg format(%s) subsample(%s)\n", @@ -1234,6 +1322,9 @@ static void aspeed_video_update_regs(struct aspeed_video *video) else aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0); + if (video->input == VIDEO_INPUT_VGA) + ctrl |= VE_CTRL_AUTO_OR_CURSOR; + if (video->frame_rate) ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate); @@ -1252,7 +1343,9 @@ static void aspeed_video_update_regs(struct aspeed_video *video) aspeed_video_update(video, VE_SEQ_CTRL, video->jpeg_mode | VE_SEQ_CTRL_YUV420, seq_ctrl); - aspeed_video_update(video, VE_CTRL, VE_CTRL_FRC, ctrl); + aspeed_video_update(video, VE_CTRL, + VE_CTRL_FRC | VE_CTRL_AUTO_OR_CURSOR | + VE_CTRL_SOURCE, ctrl); aspeed_video_update(video, VE_COMP_CTRL, VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR | VE_COMP_CTRL_EN_HQ | VE_COMP_CTRL_HQ_DCT_LUM | @@ -1280,6 +1373,7 @@ static void aspeed_video_init_regs(struct aspeed_video *video) aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma); /* Set control registers */ + aspeed_video_write(video, VE_SEQ_CTRL, VE_SEQ_CTRL_AUTO_COMP); aspeed_video_write(video, VE_CTRL, ctrl); aspeed_video_write(video, VE_COMP_CTRL, VE_COMP_CTRL_RSVD); @@ -1311,12 +1405,7 @@ static void aspeed_video_start(struct aspeed_video *video) aspeed_video_get_resolution(video); /* Set timings since the device is being opened for the first time */ - video->active_timings = video->detected_timings; - aspeed_video_set_resolution(video); - - video->pix_fmt.width = video->active_timings.width; - video->pix_fmt.height = video->active_timings.height; - video->pix_fmt.sizeimage = video->max_compressed_size; + aspeed_video_update_timings(video, &video->detected_timings); } static void aspeed_video_stop(struct aspeed_video *video) @@ -1401,10 +1490,10 @@ static int aspeed_video_enum_input(struct file *file, void *fh, { struct aspeed_video *video = video_drvdata(file); - if (inp->index) + if (inp->index >= VIDEO_INPUT_MAX) return -EINVAL; - strscpy(inp->name, "Host VGA capture", sizeof(inp->name)); + sprintf(inp->name, "%s capture", input_str[inp->index]); inp->type = V4L2_INPUT_TYPE_CAMERA; inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; inp->status = video->v4l2_input_status; @@ -1414,16 +1503,57 @@ static int aspeed_video_enum_input(struct file *file, void *fh, static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i) { - *i = 0; + struct aspeed_video *video = video_drvdata(file); + + *i = video->input; return 0; } static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i) { - if (i) + struct aspeed_video *video = video_drvdata(file); + + if (i >= VIDEO_INPUT_MAX) return -EINVAL; + if (i == video->input) + return 0; + + if (vb2_is_busy(&video->queue)) + return -EBUSY; + + if (IS_ERR(video->scu)) { + v4l2_dbg(1, debug, &video->v4l2_dev, + "%s: scu isn't ready for input-control\n", __func__); + return -EINVAL; + } + + if (IS_ERR(video->gfx) && i == VIDEO_INPUT_GFX) { + v4l2_dbg(1, debug, &video->v4l2_dev, + "%s: gfx isn't ready for GFX input\n", __func__); + return -EINVAL; + } + + video->input = i; + + if (video->version == 6) { + /* modify dpll source per current input */ + if (video->input == VIDEO_INPUT_VGA) + regmap_update_bits(video->scu, SCU_MISC_CTRL, + SCU_DPLL_SOURCE, 0); + else + regmap_update_bits(video->scu, SCU_MISC_CTRL, + SCU_DPLL_SOURCE, SCU_DPLL_SOURCE); + } + + aspeed_video_update_regs(video); + + /* update signal status */ + aspeed_video_get_resolution(video); + if (!video->v4l2_input_status) + aspeed_video_update_timings(video, &video->detected_timings); + return 0; } @@ -1527,13 +1657,7 @@ static int aspeed_video_set_dv_timings(struct file *file, void *fh, if (vb2_is_busy(&video->queue)) return -EBUSY; - video->active_timings = timings->bt; - - aspeed_video_set_resolution(video); - - video->pix_fmt.width = timings->bt.width; - video->pix_fmt.height = timings->bt.height; - video->pix_fmt.sizeimage = video->max_compressed_size; + aspeed_video_update_timings(video, &timings->bt); timings->type = V4L2_DV_BT_656_1120; @@ -1909,6 +2033,7 @@ static int aspeed_video_debugfs_show(struct seq_file *s, void *data) val08 = aspeed_video_read(v, VE_CTRL); if (FIELD_GET(VE_CTRL_DIRECT_FETCH, val08)) { seq_printf(s, " %-20s:\tDirect fetch\n", "Mode"); + seq_printf(s, " %-20s:\t%s\n", "Input", input_str[v->input]); seq_printf(s, " %-20s:\t%s\n", "VGA bpp mode", FIELD_GET(VE_CTRL_INT_DE, val08) ? "16" : "32"); } else { @@ -2068,12 +2193,29 @@ static int aspeed_video_setup_video(struct aspeed_video *video) return 0; } +/* + * Get regmap without checking res, such as clk/reset, that could lead to + * conflict. + */ +static struct regmap *aspeed_regmap_lookup(struct device_node *np, const char *property) +{ + struct device_node *syscon_np __free(device_node) = of_parse_phandle(np, property, 0); + + if (!syscon_np) + return ERR_PTR(-ENODEV); + + return device_node_to_regmap(syscon_np); +} + static int aspeed_video_init(struct aspeed_video *video) { int irq; int rc; struct device *dev = video->dev; + video->scu = aspeed_regmap_lookup(dev->of_node, "aspeed,scu"); + video->gfx = aspeed_regmap_lookup(dev->of_node, "aspeed,gfx"); + irq = irq_of_parse_and_map(dev->of_node, 0); if (!irq) { dev_err(dev, "Unable to find IRQ\n"); @@ -2165,6 +2307,7 @@ static int aspeed_video_probe(struct platform_device *pdev) if (!config) return -ENODEV; + video->version = config->version; video->jpeg_mode = config->jpeg_mode; video->comp_size_read = config->comp_size_read; diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 7f1ce95cdc3f..8c19f125da3e 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -5,8 +5,10 @@ * Copyright (C) 2017 Cadence Design Systems Inc. */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/export.h> #include <linux/io.h> #include <linux/iopoll.h> #include <linux/module.h> @@ -17,6 +19,7 @@ #include <linux/reset.h> #include <linux/slab.h> +#include <media/cadence/cdns-csi2rx.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -52,7 +55,9 @@ #define CSI2RX_STREAM_DATA_CFG_VC_SELECT(n) BIT((n) + 16) #define CSI2RX_STREAM_CFG_REG(n) (CSI2RX_STREAM_BASE(n) + 0x00c) -#define CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF (1 << 8) +#define CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF BIT(8) +#define CSI2RX_STREAM_CFG_NUM_PIXELS_MASK GENMASK(5, 4) +#define CSI2RX_STREAM_CFG_NUM_PIXELS(n) ((n) >> 1U) #define CSI2RX_LANES_MAX 4 #define CSI2RX_STREAMS_MAX 4 @@ -87,7 +92,10 @@ enum csi2rx_pads { struct csi2rx_fmt { u32 code; + /* width of a single pixel on CSI-2 bus */ u8 bpp; + /* max pixels per clock supported on output bus */ + u8 max_pixels; }; struct csi2rx_event { @@ -132,6 +140,7 @@ struct csi2rx_priv { struct reset_control *pixel_rst[CSI2RX_STREAMS_MAX]; struct phy *dphy; + u8 num_pixels[CSI2RX_STREAMS_MAX]; u8 lanes[CSI2RX_LANES_MAX]; u8 num_lanes; u8 max_lanes; @@ -149,22 +158,22 @@ struct csi2rx_priv { }; static const struct csi2rx_fmt formats[] = { - { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, }, - { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, }, - { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, }, - { .code = MEDIA_BUS_FMT_VYUY8_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, }, - { .code = MEDIA_BUS_FMT_Y8_1X8, .bpp = 8, }, - { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, }, - { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, }, - { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, }, - { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, }, - { .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16, }, - { .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24, }, - { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, }, + { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, .max_pixels = 2, }, + { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, .max_pixels = 2, }, + { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, .max_pixels = 2, }, + { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, .max_pixels = 2, }, + { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, .max_pixels = 4, }, + { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, .max_pixels = 4, }, + { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, .max_pixels = 4, }, + { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, .max_pixels = 4, }, + { .code = MEDIA_BUS_FMT_Y8_1X8, .bpp = 8, .max_pixels = 4, }, + { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, .max_pixels = 2, }, + { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, .max_pixels = 2, }, + { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, .max_pixels = 2, }, + { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, .max_pixels = 2, }, + { .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16, .max_pixels = 1, }, + { .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24, .max_pixels = 1, }, + { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, .max_pixels = 1, }, }; static void csi2rx_configure_error_irq_mask(void __iomem *base, @@ -370,7 +379,9 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) reset_control_deassert(csi2rx->pixel_rst[i]); - writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF, + writel(CSI2RX_STREAM_CFG_FIFO_MODE_LARGE_BUF | + FIELD_PREP(CSI2RX_STREAM_CFG_NUM_PIXELS_MASK, + csi2rx->num_pixels[i]), csi2rx->base + CSI2RX_STREAM_CFG_REG(i)); /* @@ -569,6 +580,33 @@ static int csi2rx_init_state(struct v4l2_subdev *subdev, return csi2rx_set_fmt(subdev, state, &format); } +int cdns_csi2rx_negotiate_ppc(struct v4l2_subdev *subdev, unsigned int pad, + u8 *ppc) +{ + struct csi2rx_priv *csi2rx = v4l2_subdev_to_csi2rx(subdev); + const struct csi2rx_fmt *csi_fmt; + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + + if (!ppc || pad < CSI2RX_PAD_SOURCE_STREAM0 || pad >= CSI2RX_PAD_MAX) + return -EINVAL; + + state = v4l2_subdev_lock_and_get_active_state(subdev); + fmt = v4l2_subdev_state_get_format(state, pad); + csi_fmt = csi2rx_get_fmt_by_code(fmt->code); + + /* Reduce requested PPC if it is too high */ + *ppc = min(*ppc, csi_fmt->max_pixels); + + v4l2_subdev_unlock_state(state); + + csi2rx->num_pixels[pad - CSI2RX_PAD_SOURCE_STREAM0] = + CSI2RX_STREAM_CFG_NUM_PIXELS(*ppc); + + return 0; +} +EXPORT_SYMBOL_FOR_MODULES(cdns_csi2rx_negotiate_ppc, "j721e-csi2rx"); + static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = { .enum_mbus_code = csi2rx_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, @@ -595,6 +633,7 @@ static const struct v4l2_subdev_internal_ops csi2rx_internal_ops = { static const struct media_entity_operations csi2rx_media_ops = { .link_validate = v4l2_subdev_link_validate, + .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, }; static int csi2rx_async_bound(struct v4l2_async_notifier *notifier, diff --git a/drivers/media/platform/chips-media/coda/coda-bit.c b/drivers/media/platform/chips-media/coda/coda-bit.c index 84ded154adfe..fa6b72c3bd93 100644 --- a/drivers/media/platform/chips-media/coda/coda-bit.c +++ b/drivers/media/platform/chips-media/coda/coda-bit.c @@ -1685,7 +1685,7 @@ static void coda_finish_encode(struct coda_ctx *ctx) dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c index e6e3f5ec24f6..33f712ff8556 100644 --- a/drivers/media/platform/chips-media/coda/coda-common.c +++ b/drivers/media/platform/chips-media/coda/coda-common.c @@ -56,6 +56,11 @@ #define fh_to_ctx(__fh) container_of(__fh, struct coda_ctx, fh) +static inline struct coda_ctx *file_to_ctx(struct file *filp) +{ + return fh_to_ctx(file_to_v4l2_fh(filp)); +} + int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); @@ -422,7 +427,7 @@ out: static int coda_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); strscpy(cap->driver, CODA_NAME, sizeof(cap->driver)); strscpy(cap->card, coda_product_name(ctx->dev->devtype->product), @@ -442,7 +447,7 @@ static int coda_enum_fmt(struct file *file, void *priv, { struct video_device *vdev = video_devdata(file); const struct coda_video_device *cvd = to_coda_video_device(vdev); - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); const u32 *formats; if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -492,7 +497,7 @@ static int coda_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct coda_q_data *q_data; - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); q_data = get_q_data(ctx, f->type); if (!q_data) @@ -653,7 +658,7 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, static int coda_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); const struct coda_q_data *q_data_src; const struct coda_codec *codec; struct vb2_queue *src_vq; @@ -759,7 +764,7 @@ static void coda_set_default_colorspace(struct v4l2_pix_format *fmt) static int coda_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_dev *dev = ctx->dev; const struct coda_q_data *q_data_dst; const struct coda_codec *codec; @@ -785,8 +790,6 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, struct vb2_queue *vq; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; q_data = get_q_data(ctx, f->type); if (!q_data) @@ -853,7 +856,7 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f, static int coda_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data_src; const struct coda_codec *codec; struct v4l2_rect r; @@ -905,7 +908,7 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv, static int coda_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); const struct coda_codec *codec; struct v4l2_format f_cap; struct vb2_queue *dst_vq; @@ -937,8 +940,6 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, ctx->codec = codec; dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (!dst_vq) - return -EINVAL; /* * Setting the capture queue format is not possible while the capture @@ -961,7 +962,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, static int coda_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *rb) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); int ret; ret = v4l2_m2m_reqbufs(file, ctx->fh.m2m_ctx, rb); @@ -981,7 +982,7 @@ static int coda_reqbufs(struct file *file, void *priv, static int coda_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); if (ctx->inst_type == CODA_INST_DECODER && buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -992,7 +993,7 @@ static int coda_qbuf(struct file *file, void *priv, static int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct coda_ctx *ctx = fh_to_ctx(priv); + struct coda_ctx *ctx = file_to_ctx(file); int ret; ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); @@ -1020,7 +1021,7 @@ void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, static int coda_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data; struct v4l2_rect r, *rsel; @@ -1066,7 +1067,7 @@ static int coda_g_selection(struct file *file, void *fh, static int coda_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data; switch (s->target) { @@ -1121,7 +1122,7 @@ static void coda_wake_up_capture_queue(struct coda_ctx *ctx) static int coda_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct vb2_v4l2_buffer *buf; int ret; @@ -1202,7 +1203,7 @@ static bool coda_mark_last_dst_buf(struct coda_ctx *ctx) static int coda_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_dev *dev = ctx->dev; struct vb2_v4l2_buffer *buf; struct vb2_queue *dst_vq; @@ -1281,7 +1282,7 @@ static int coda_decoder_cmd(struct file *file, void *fh, static int coda_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data_dst; const struct coda_codec *codec; @@ -1314,7 +1315,7 @@ static int coda_enum_framesizes(struct file *file, void *fh, static int coda_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *f) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct coda_q_data *q_data; const struct coda_codec *codec; @@ -1353,7 +1354,7 @@ static int coda_enum_frameintervals(struct file *file, void *fh, static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct v4l2_fract *tpf; if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -1436,7 +1437,7 @@ static uint32_t coda_timeperframe_to_frate(struct v4l2_fract *timeperframe) static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_ctx *ctx = file_to_ctx(file); struct v4l2_fract *tpf; if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -2637,8 +2638,7 @@ static int coda_open(struct file *file) if (ctx->ops->seq_end_work) INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->dev = dev; ctx->idx = idx; @@ -2721,7 +2721,7 @@ err_clk_ahb: err_clk_enable: pm_runtime_put_sync(dev->dev); err_pm_get: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); err_coda_name_init: ida_free(&dev->ida, ctx->idx); @@ -2733,7 +2733,7 @@ err_coda_max: static int coda_release(struct file *file) { struct coda_dev *dev = video_drvdata(file); - struct coda_ctx *ctx = fh_to_ctx(file->private_data); + struct coda_ctx *ctx = file_to_ctx(file); coda_dbg(1, ctx, "release instance (%p)\n", ctx); @@ -2759,7 +2759,7 @@ static int coda_release(struct file *file) clk_disable_unprepare(dev->clk_ahb); clk_disable_unprepare(dev->clk_per); pm_runtime_put_sync(dev->dev); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); ida_free(&dev->ida, ctx->idx); if (ctx->ops->release) diff --git a/drivers/media/platform/chips-media/coda/coda-jpeg.c b/drivers/media/platform/chips-media/coda/coda-jpeg.c index 5746892658b1..fb150b87c773 100644 --- a/drivers/media/platform/chips-media/coda/coda-jpeg.c +++ b/drivers/media/platform/chips-media/coda/coda-jpeg.c @@ -1245,7 +1245,7 @@ static void coda9_jpeg_finish_encode(struct coda_ctx *ctx) dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); coda_m2m_buf_done(ctx, dst_buf, err_mb ? VB2_BUF_STATE_ERROR : @@ -1472,7 +1472,7 @@ static void coda9_jpeg_finish_decode(struct coda_ctx *ctx) dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); vb2_set_plane_payload(&dst_buf->vb2_buf, 0, q_data_dst->sizeimage); diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c index 2c9d8cbca6e4..f03ad9c0de22 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.c +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c @@ -27,7 +27,7 @@ const char *state_to_str(enum vpu_instance_state state) } } -void wave5_cleanup_instance(struct vpu_instance *inst) +void wave5_cleanup_instance(struct vpu_instance *inst, struct file *filp) { int i; @@ -46,7 +46,7 @@ void wave5_cleanup_instance(struct vpu_instance *inst) wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf); v4l2_ctrl_handler_free(&inst->v4l2_ctrl_hdl); if (inst->v4l2_fh.vdev) { - v4l2_fh_del(&inst->v4l2_fh); + v4l2_fh_del(&inst->v4l2_fh, filp); v4l2_fh_exit(&inst->v4l2_fh); } list_del_init(&inst->list); @@ -59,7 +59,7 @@ int wave5_vpu_release_device(struct file *filp, int (*close_func)(struct vpu_instance *inst, u32 *fail_res), char *name) { - struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data); + struct vpu_instance *inst = file_to_vpu_inst(filp); int ret = 0; v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx); @@ -78,7 +78,7 @@ int wave5_vpu_release_device(struct file *filp, } } - wave5_cleanup_instance(inst); + wave5_cleanup_instance(inst, filp); return ret; } @@ -142,7 +142,7 @@ int wave5_vpu_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscr int wave5_vpu_g_fmt_out(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i; f->fmt.pix_mp.width = inst->src_fmt.width; diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h index 9937fce553fc..976a402e426f 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-helper.h +++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h @@ -14,7 +14,7 @@ #define MAX_FMTS 12 const char *state_to_str(enum vpu_instance_state state); -void wave5_cleanup_instance(struct vpu_instance *inst); +void wave5_cleanup_instance(struct vpu_instance *inst, struct file *filp); int wave5_vpu_release_device(struct file *filp, int (*close_func)(struct vpu_instance *inst, u32 *fail_res), char *name); 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 fd71f0c43ac3..e3038c18ca36 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -451,7 +451,6 @@ 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); } @@ -506,7 +505,7 @@ static int wave5_vpu_dec_enum_fmt_cap(struct file *file, void *fh, struct v4l2_f static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); struct dec_info *p_dec_info = &inst->codec_info->dec_info; const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; @@ -547,7 +546,7 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo static int wave5_vpu_dec_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i, ret; dev_dbg(inst->dev->dev, @@ -606,7 +605,7 @@ static int wave5_vpu_dec_s_fmt_cap(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_dec_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i; f->fmt.pix_mp.width = inst->dst_fmt.width; @@ -630,7 +629,7 @@ static int wave5_vpu_dec_g_fmt_cap(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); @@ -647,7 +646,7 @@ 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); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; int width, height; @@ -678,7 +677,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); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; int i, ret; @@ -727,7 +726,7 @@ static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target); @@ -761,7 +760,7 @@ static int wave5_vpu_dec_g_selection(struct file *file, void *fh, struct v4l2_se static int wave5_vpu_dec_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -872,7 +871,7 @@ unlock_and_return: static int wave5_vpu_dec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; int ret; @@ -1364,7 +1363,6 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count } } - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); return ret; @@ -1498,7 +1496,6 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) else streamoff_capture(q); - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); } @@ -1662,7 +1659,6 @@ 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); } @@ -1761,8 +1757,7 @@ static int wave5_vpu_open_dec(struct file *filp) return -ENOMEM; v4l2_fh_init(&inst->v4l2_fh, vdev); - filp->private_data = &inst->v4l2_fh; - v4l2_fh_add(&inst->v4l2_fh); + v4l2_fh_add(&inst->v4l2_fh, filp); INIT_LIST_HEAD(&inst->list); @@ -1840,7 +1835,7 @@ static int wave5_vpu_open_dec(struct file *filp) return 0; cleanup_inst: - wave5_cleanup_instance(inst); + wave5_cleanup_instance(inst, filp); return ret; } 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 1e5fc5f8b856..9bfaa9fb3ceb 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -360,7 +360,7 @@ static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_f static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); @@ -377,7 +377,7 @@ 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); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; int width, height; @@ -411,7 +411,7 @@ static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo static int wave5_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i, ret; dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n", @@ -445,7 +445,7 @@ static int wave5_vpu_enc_s_fmt_cap(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); int i; f->fmt.pix_mp.width = inst->dst_fmt.width; @@ -469,7 +469,7 @@ static int wave5_vpu_enc_g_fmt_cap(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; dev_dbg(inst->dev->dev, "%s: index: %u\n", __func__, f->index); @@ -486,7 +486,7 @@ 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); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct v4l2_frmsize_stepwise *frmsize; const struct vpu_format *vpu_fmt; int width, height; @@ -515,7 +515,7 @@ static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_fo 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); + struct vpu_instance *inst = file_to_vpu_inst(file); const struct vpu_format *vpu_fmt; const struct v4l2_format_info *info; int i, ret; @@ -543,7 +543,7 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form if (!info) return -EINVAL; - inst->cbcr_interleave = (info->comp_planes == 2) ? true : false; + inst->cbcr_interleave = info->comp_planes == 2; switch (inst->src_fmt.pixelformat) { case V4L2_PIX_FMT_NV21: @@ -576,7 +576,7 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); dev_dbg(inst->dev->dev, "%s: type: %u | target: %u\n", __func__, s->type, s->target); @@ -605,7 +605,7 @@ static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_se static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; @@ -628,7 +628,7 @@ static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_se static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; int ret; @@ -661,7 +661,7 @@ static int wave5_vpu_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_en static int wave5_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type); @@ -681,7 +681,7 @@ static int wave5_vpu_enc_g_parm(struct file *file, void *fh, struct v4l2_streamp static int wave5_vpu_enc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct vpu_instance *inst = wave5_to_vpu_inst(fh); + struct vpu_instance *inst = file_to_vpu_inst(file); dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, a->type); @@ -1391,12 +1391,10 @@ 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; } @@ -1465,7 +1463,6 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q) else streamoff_capture(inst, q); - pm_runtime_mark_last_busy(inst->dev->dev); pm_runtime_put_autosuspend(inst->dev->dev); } @@ -1520,7 +1517,6 @@ 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: @@ -1529,7 +1525,6 @@ 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); } @@ -1587,8 +1582,7 @@ static int wave5_vpu_open_enc(struct file *filp) return -ENOMEM; v4l2_fh_init(&inst->v4l2_fh, vdev); - filp->private_data = &inst->v4l2_fh; - v4l2_fh_add(&inst->v4l2_fh); + v4l2_fh_add(&inst->v4l2_fh, filp); INIT_LIST_HEAD(&inst->list); @@ -1784,7 +1778,7 @@ static int wave5_vpu_open_enc(struct file *filp) return 0; cleanup_inst: - wave5_cleanup_instance(inst); + wave5_cleanup_instance(inst, filp); return ret; } diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.h b/drivers/media/platform/chips-media/wave5/wave5-vpu.h index 3847332551fc..5943bdaa9c4c 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.h @@ -46,6 +46,11 @@ static inline struct vpu_instance *wave5_to_vpu_inst(struct v4l2_fh *vfh) return container_of(vfh, struct vpu_instance, v4l2_fh); } +static inline struct vpu_instance *file_to_vpu_inst(struct file *filp) +{ + return wave5_to_vpu_inst(file_to_v4l2_fh(filp)); +} + static inline struct vpu_instance *wave5_ctrl_to_vpu_inst(struct v4l2_ctrl *vctrl) { return container_of(vctrl->handler, struct vpu_instance, v4l2_ctrl_hdl); diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c index ae868d9f73e1..1c6e076033ec 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.c +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c @@ -253,7 +253,7 @@ static int e5010_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { int i, index = 0; struct e5010_fmt *fmt = NULL; - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { v4l2_err(&ctx->e5010->v4l2_dev, "ENUMFMT with Invalid type: %d\n", f->type); @@ -279,7 +279,7 @@ static int e5010_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) static int e5010_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); struct e5010_q_data *queue; int i; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; @@ -380,14 +380,14 @@ static int e5010_jpeg_try_fmt(struct v4l2_format *f, struct e5010_context *ctx) static int e5010_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); return e5010_jpeg_try_fmt(f, ctx); } static int e5010_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); struct vb2_queue *vq; int ret = 0, i = 0; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; @@ -396,8 +396,6 @@ static int e5010_s_fmt(struct file *file, void *priv, struct v4l2_format *f) struct e5010_fmt *fmt; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; if (vb2_is_busy(vq)) { v4l2_err(&ctx->e5010->v4l2_dev, "queue busy\n"); @@ -462,7 +460,7 @@ static int e5010_enum_framesizes(struct file *file, void *priv, struct v4l2_frms static int e5010_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); struct e5010_q_data *queue; if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -490,14 +488,12 @@ static int e5010_g_selection(struct file *file, void *fh, struct v4l2_selection static int e5010_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); struct e5010_q_data *queue; struct vb2_queue *vq; struct v4l2_rect base_rect; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, s->type); - if (!vq) - return -EINVAL; if (vb2_is_streaming(vq)) return -EBUSY; @@ -742,8 +738,7 @@ static int e5010_open(struct file *file) } v4l2_fh_init(&ctx->fh, vdev); - file->private_data = ctx; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->e5010 = e5010; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(e5010->m2m_dev, ctx, queue_init); @@ -770,7 +765,7 @@ static int e5010_open(struct file *file) err_ctrls_setup: v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); exit: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&e5010->mutex); free: @@ -781,13 +776,13 @@ free: static int e5010_release(struct file *file) { struct e5010_dev *e5010 = video_drvdata(file); - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); dprintk(e5010, 1, "Releasing instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx); mutex_lock(&e5010->mutex); v4l2_ctrl_handler_free(&ctx->ctrl_handler); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&e5010->mutex); @@ -1262,7 +1257,7 @@ static void e5010_buf_queue(struct vb2_buffer *vb) static int e5010_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *cmd) { - struct e5010_context *ctx = file->private_data; + struct e5010_context *ctx = to_e5010_context(file); int ret; struct vb2_queue *cap_vq; @@ -1359,7 +1354,7 @@ static void e5010_device_run(void *priv) s_vb->sequence = ctx->out_queue.sequence++; d_vb->sequence = ctx->cap_queue.sequence++; - v4l2_m2m_buf_copy_metadata(s_vb, d_vb, false); + v4l2_m2m_buf_copy_metadata(s_vb, d_vb); if (ctx != e5010->last_context_run || ctx->update_qp) { dprintk(e5010, 1, "ctx updated: 0x%p -> 0x%p, updating qp tables\n", diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.h b/drivers/media/platform/imagination/e5010-jpeg-enc.h index 71f49ead6898..da57bc1baa46 100644 --- a/drivers/media/platform/imagination/e5010-jpeg-enc.h +++ b/drivers/media/platform/imagination/e5010-jpeg-enc.h @@ -120,6 +120,11 @@ struct e5010_context { u8 chroma_qp[QP_TABLE_SIZE]; }; +static inline struct e5010_context *to_e5010_context(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct e5010_context, fh); +} + /* * Buffer structure * Contains info for all buffers diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 5188f3189096..af098874ead5 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -142,6 +142,11 @@ struct deinterlace_ctx { struct dma_interleaved_template *xt; }; +static inline struct deinterlace_ctx *file_to_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct deinterlace_ctx, fh); +} + /* * mem2mem callbacks */ @@ -480,13 +485,8 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) { - struct vb2_queue *vq; struct deinterlace_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - q_data = get_q_data(f->type); f->fmt.pix.width = q_data->width; @@ -512,13 +512,13 @@ static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) static int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file_to_ctx(file), f); } static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file_to_ctx(file), f); } static int vidioc_try_fmt(struct v4l2_format *f, struct deinterlace_fmt *fmt) @@ -539,8 +539,8 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct deinterlace_fmt *fmt) static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct deinterlace_ctx *ctx = file_to_ctx(file); struct deinterlace_fmt *fmt; - struct deinterlace_ctx *ctx = priv; fmt = find_format(f); if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) @@ -581,8 +581,6 @@ static int vidioc_s_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; q_data = get_q_data(f->type); if (!q_data) @@ -633,20 +631,20 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, ret = vidioc_try_fmt_vid_cap(file, priv, f); if (ret) return ret; - return vidioc_s_fmt(priv, f); + return vidioc_s_fmt(file_to_ctx(file), f); } static int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct deinterlace_ctx *ctx = priv; + struct deinterlace_ctx *ctx = file_to_ctx(file); int ret; ret = vidioc_try_fmt_vid_out(file, priv, f); if (ret) return ret; - ret = vidioc_s_fmt(priv, f); + ret = vidioc_s_fmt(ctx, f); if (!ret) ctx->colorspace = f->fmt.pix.colorspace; @@ -656,8 +654,8 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { + struct deinterlace_ctx *ctx = file_to_ctx(file); struct deinterlace_q_data *s_q_data, *d_q_data; - struct deinterlace_ctx *ctx = priv; s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT); d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE); @@ -842,7 +840,6 @@ static int deinterlace_open(struct file *file) return -ENOMEM; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = pcdev; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); @@ -861,7 +858,7 @@ static int deinterlace_open(struct file *file) } ctx->colorspace = V4L2_COLORSPACE_REC709; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); @@ -872,11 +869,11 @@ static int deinterlace_open(struct file *file) static int deinterlace_release(struct file *file) { struct deinterlace_dev *pcdev = video_drvdata(file); - struct deinterlace_ctx *ctx = file->private_data; + struct deinterlace_ctx *ctx = file_to_ctx(file); dprintk(pcdev, "Releasing instance %p\n", ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); kfree(ctx->xt); diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c index ef810249def6..f9796de92aa7 100644 --- a/drivers/media/platform/marvell/cafe-driver.c +++ b/drivers/media/platform/marvell/cafe-driver.c @@ -14,7 +14,7 @@ * Written by Jonathan Corbet, corbet@lwn.net. * * v4l2_device/v4l2_subdev conversion by: - * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2009 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index 7eb12449b63a..d08fe365cbb2 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -119,9 +119,9 @@ static inline struct mtk_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) return container_of(ctrl->handler, struct mtk_jpeg_ctx, ctrl_hdl); } -static inline struct mtk_jpeg_ctx *mtk_jpeg_fh_to_ctx(struct v4l2_fh *fh) +static inline struct mtk_jpeg_ctx *mtk_jpeg_file_to_ctx(struct file *filp) { - return container_of(fh, struct mtk_jpeg_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct mtk_jpeg_ctx, fh); } static inline struct mtk_jpeg_src_buf *mtk_jpeg_vb2_to_srcbuf( @@ -212,7 +212,7 @@ static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n, static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; return mtk_jpeg_enum_fmt(jpeg->variant->formats, @@ -223,7 +223,7 @@ static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, static int mtk_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; return mtk_jpeg_enum_fmt(jpeg->variant->formats, @@ -302,17 +302,12 @@ static int mtk_jpeg_try_fmt_mplane(struct v4l2_pix_format_mplane *pix_mp, static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct vb2_queue *vq; struct mtk_jpeg_q_data *q_data = NULL; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; int i; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - q_data = mtk_jpeg_get_q_data(ctx, f->type); pix_mp->width = q_data->pix_mp.width; @@ -351,7 +346,7 @@ static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv, static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; struct mtk_jpeg_fmt *fmt; @@ -380,7 +375,7 @@ static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv, static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct mtk_jpeg_dev *jpeg = ctx->jpeg; struct mtk_jpeg_fmt *fmt; @@ -416,8 +411,6 @@ static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx, int i; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; q_data = mtk_jpeg_get_q_data(ctx, f->type); @@ -470,7 +463,7 @@ static int mtk_jpeg_s_fmt_vid_out_mplane(struct file *file, void *priv, if (ret) return ret; - return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f, + return mtk_jpeg_s_fmt_mplane(mtk_jpeg_file_to_ctx(file), f, MTK_JPEG_FMT_FLAG_OUTPUT); } @@ -483,7 +476,7 @@ static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv, if (ret) return ret; - return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f, + return mtk_jpeg_s_fmt_mplane(mtk_jpeg_file_to_ctx(file), f, MTK_JPEG_FMT_FLAG_CAPTURE); } @@ -512,7 +505,7 @@ static int mtk_jpeg_subscribe_event(struct v4l2_fh *fh, static int mtk_jpeg_enc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; @@ -537,7 +530,7 @@ static int mtk_jpeg_enc_g_selection(struct file *file, void *priv, static int mtk_jpeg_dec_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -566,7 +559,7 @@ static int mtk_jpeg_dec_g_selection(struct file *file, void *priv, static int mtk_jpeg_enc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; @@ -588,8 +581,8 @@ static int mtk_jpeg_enc_s_selection(struct file *file, void *priv, static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv); + struct v4l2_fh *fh = file_to_v4l2_fh(file); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); struct vb2_queue *vq; struct vb2_buffer *vb; struct mtk_jpeg_src_buf *jpeg_src_buf; @@ -1171,8 +1164,7 @@ static int mtk_jpeg_open(struct file *file) INIT_LIST_HEAD(&ctx->dst_done_queue); spin_lock_init(&ctx->done_queue_lock); v4l2_fh_init(&ctx->fh, vfd); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->jpeg = jpeg; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, @@ -1197,7 +1189,7 @@ static int mtk_jpeg_open(struct file *file) return 0; error: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&jpeg->lock); free: @@ -1208,12 +1200,12 @@ free: static int mtk_jpeg_release(struct file *file) { struct mtk_jpeg_dev *jpeg = video_drvdata(file); - struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(file->private_data); + struct mtk_jpeg_ctx *ctx = mtk_jpeg_file_to_ctx(file); mutex_lock(&jpeg->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&jpeg->lock); @@ -1626,7 +1618,7 @@ retry_select: if (!dst_buf) goto getbuf_fail; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); mtk_jpegenc_set_hw_param(ctx, hw_id, src_buf, dst_buf); ret = pm_runtime_get_sync(comp_jpeg[hw_id]->dev); @@ -1722,7 +1714,7 @@ retry_select: if (!dst_buf) goto getbuf_fail; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf); jpeg_dst_buf = mtk_jpeg_vb2_to_srcbuf(&dst_buf->vb2_buf); 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 e78e1d11093c..32372781daf5 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c @@ -530,7 +530,7 @@ static void mtk_jpegdec_timeout_work(struct work_struct *work) src_buf = cjpeg->hw_param.src_buffer; dst_buf = cjpeg->hw_param.dst_buffer; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); mtk_jpeg_dec_reset(cjpeg->reg_base); clk_disable_unprepare(cjpeg->jdec_clk.clks->clk); @@ -560,7 +560,7 @@ static irqreturn_t mtk_jpegdec_hw_irq_handler(int irq, void *priv) ctx = jpeg->hw_param.curr_ctx; src_buf = jpeg->hw_param.src_buffer; dst_buf = jpeg->hw_param.dst_buffer; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); irq_status = mtk_jpeg_dec_get_int_status(jpeg->reg_base); dec_irq_ret = mtk_jpeg_dec_enum_result(irq_status); diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c index 9ab27aee302a..b6f5b2249f1f 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c @@ -261,7 +261,7 @@ static void mtk_jpegenc_timeout_work(struct work_struct *work) src_buf = cjpeg->hw_param.src_buffer; dst_buf = cjpeg->hw_param.dst_buffer; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); mtk_jpeg_enc_reset(cjpeg->reg_base); clk_disable_unprepare(cjpeg->venc_clk.clks->clk); @@ -289,7 +289,7 @@ static irqreturn_t mtk_jpegenc_hw_irq_handler(int irq, void *priv) ctx = jpeg->hw_param.curr_ctx; src_buf = jpeg->hw_param.src_buffer; dst_buf = jpeg->hw_param.dst_buffer; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); irq_status = readl(jpeg->reg_base + JPEG_ENC_INT_STS) & JPEG_ENC_INT_STATUS_MASK_ALLIRQ; diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c index d0fd77dcf8e2..03c07948dfdd 100644 --- a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c @@ -348,9 +348,9 @@ static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, u32 type, return 0; } -static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh) +static inline struct mtk_mdp_ctx *file_to_ctx(struct file *filp) { - return container_of(fh, struct mtk_mdp_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct mtk_mdp_ctx, fh); } static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) @@ -589,7 +589,7 @@ static const struct vb2_ops mtk_mdp_m2m_qops = { static int mtk_mdp_m2m_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_dev *mdp = ctx->mdp_dev; strscpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver)); @@ -627,7 +627,7 @@ static int mtk_mdp_m2m_enum_fmt_vid_out(struct file *file, void *priv, static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_frame *frame; struct v4l2_pix_format_mplane *pix_mp; int i; @@ -666,7 +666,7 @@ static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh, static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); if (!mtk_mdp_try_fmt_mplane(ctx, f)) return -EINVAL; @@ -676,7 +676,7 @@ static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh, static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct vb2_queue *vq; struct mtk_mdp_frame *frame; struct v4l2_pix_format_mplane *pix_mp; @@ -722,7 +722,7 @@ static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh, static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *reqbufs) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); } @@ -730,7 +730,7 @@ static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh, static int mtk_mdp_m2m_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); int ret; if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_VPU_INIT)) { @@ -768,8 +768,8 @@ static inline bool mtk_mdp_is_target_crop(u32 target) static int mtk_mdp_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_frame *frame; - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); bool valid = false; if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -835,8 +835,8 @@ static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant *var, int src_w, static int mtk_mdp_m2m_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_frame *frame; - struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); struct v4l2_rect new_r; struct mtk_mdp_variant *variant = ctx->mdp_dev->variant; int ret; @@ -1065,14 +1065,13 @@ static int mtk_mdp_m2m_open(struct file *file) mutex_init(&ctx->slock); ctx->id = mdp->id_counter++; v4l2_fh_init(&ctx->fh, vfd); - file->private_data = &ctx->fh; ret = mtk_mdp_ctrls_create(ctx); if (ret) goto error_ctrls; /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); INIT_LIST_HEAD(&ctx->list); ctx->mdp_dev = mdp; @@ -1126,7 +1125,7 @@ err_load_vpu: error_m2m_ctx: v4l2_ctrl_handler_free(&ctx->ctrl_handler); error_ctrls: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&mdp->lock); err_lock: @@ -1137,14 +1136,14 @@ err_lock: static int mtk_mdp_m2m_release(struct file *file) { - struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data); + struct mtk_mdp_ctx *ctx = file_to_ctx(file); struct mtk_mdp_dev *mdp = ctx->mdp_dev; flush_workqueue(mdp->job_wq); mutex_lock(&mdp->lock); v4l2_m2m_ctx_release(ctx->m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mtk_mdp_vpu_deinit(&ctx->vpu); mdp->ctx_num--; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index 683c066ed975..7fcb2fbdd64e 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -1530,6 +1530,9 @@ static const struct of_device_id mdp_comp_dt_ids[] __maybe_unused = { }, { .compatible = "mediatek,mt8195-mdp3-tcc", .data = (void *)MDP_COMP_TYPE_TCC, + }, { + .compatible = "mediatek,mt8188-mdp3-rdma", + .data = (void *)MDP_COMP_TYPE_RDMA, }, {} }; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index 8de2c8e4d333..6d26d4aa1eef 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -157,10 +157,18 @@ void mdp_video_device_release(struct video_device *vdev) kfree(mdp); } +static void mdp_put_device(void *_dev) +{ + struct device *dev = _dev; + + put_device(dev); +} + static int mdp_mm_subsys_deploy(struct mdp_dev *mdp, enum mdp_infra_id id) { struct platform_device *mm_pdev = NULL; struct device **dev; + int ret; int i; if (!mdp) @@ -194,6 +202,11 @@ static int mdp_mm_subsys_deploy(struct mdp_dev *mdp, enum mdp_infra_id id) if (WARN_ON(!mm_pdev)) return -ENODEV; + ret = devm_add_action_or_reset(&mdp->pdev->dev, mdp_put_device, + &mm_pdev->dev); + if (ret) + return ret; + *dev = &mm_pdev->dev; } @@ -279,10 +292,11 @@ static int mdp_probe(struct platform_device *pdev) goto err_destroy_clock_wq; } mdp->scp = platform_get_drvdata(mm_pdev); + put_device(&mm_pdev->dev); } mdp->rproc_handle = scp_get_rproc(mdp->scp); - dev_dbg(&pdev->dev, "MDP rproc_handle: %pK", mdp->rproc_handle); + dev_dbg(&pdev->dev, "MDP rproc_handle: %p", mdp->rproc_handle); mutex_init(&mdp->vpu_lock); mutex_init(&mdp->m2m_lock); diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c index 59ce5cce0698..44140987cf5f 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c @@ -10,9 +10,9 @@ #include <media/videobuf2-dma-contig.h> #include "mtk-mdp3-m2m.h" -static inline struct mdp_m2m_ctx *fh_to_ctx(struct v4l2_fh *fh) +static inline struct mdp_m2m_ctx *file_to_ctx(struct file *filp) { - return container_of(fh, struct mdp_m2m_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct mdp_m2m_ctx, fh); } static inline struct mdp_m2m_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) @@ -51,7 +51,7 @@ static void mdp_m2m_process_done(void *priv, int vb_state) ctx->curr_param.frame_no = ctx->frame_count[MDP_M2M_SRC]; src_vbuf->sequence = ctx->frame_count[MDP_M2M_SRC]++; dst_vbuf->sequence = ctx->frame_count[MDP_M2M_DST]++; - v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, true); + v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf); v4l2_m2m_buf_done(src_vbuf, vb_state); v4l2_m2m_buf_done(dst_vbuf, vb_state); @@ -285,7 +285,7 @@ static int mdp_m2m_querycap(struct file *file, void *fh, static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); return mdp_enum_fmt_mplane(ctx->mdp_dev, f); } @@ -293,7 +293,7 @@ static int mdp_m2m_enum_fmt_mplane(struct file *file, void *fh, static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_frame *frame; struct v4l2_pix_format_mplane *pix_mp; @@ -311,7 +311,7 @@ static int mdp_m2m_g_fmt_mplane(struct file *file, void *fh, static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_frame *frame = ctx_get_frame(ctx, f->type); struct mdp_frame *capture; const struct mdp_format *fmt; @@ -354,7 +354,7 @@ static int mdp_m2m_s_fmt_mplane(struct file *file, void *fh, static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); if (!mdp_try_fmt_mplane(ctx->mdp_dev, f, &ctx->curr_param, ctx->id)) return -EINVAL; @@ -365,7 +365,7 @@ static int mdp_m2m_try_fmt_mplane(struct file *file, void *fh, static int mdp_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_frame *frame; bool valid = false; @@ -417,7 +417,7 @@ static int mdp_m2m_g_selection(struct file *file, void *fh, static int mdp_m2m_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(fh); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_frame *frame = ctx_get_frame(ctx, s->type); struct mdp_frame *capture; struct v4l2_rect r; @@ -585,14 +585,13 @@ static int mdp_m2m_open(struct file *file) ctx->mdp_dev = mdp; v4l2_fh_init(&ctx->fh, vdev); - file->private_data = &ctx->fh; ret = mdp_m2m_ctrls_create(ctx); if (ret) goto err_exit_fh; /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); mutex_init(&ctx->ctx_lock); ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, mdp_m2m_queue_init); @@ -629,7 +628,7 @@ err_release_m2m_ctx: v4l2_m2m_ctx_release(ctx->m2m_ctx); err_release_handler: v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); err_exit_fh: v4l2_fh_exit(&ctx->fh); ida_free(&mdp->mdp_ida, ctx->id); @@ -643,7 +642,7 @@ err_free_ctx: static int mdp_m2m_release(struct file *file) { - struct mdp_m2m_ctx *ctx = fh_to_ctx(file->private_data); + struct mdp_m2m_ctx *ctx = file_to_ctx(file); struct mdp_dev *mdp = video_drvdata(file); struct device *dev = &mdp->pdev->dev; @@ -653,7 +652,7 @@ static int mdp_m2m_release(struct file *file) mdp_vpu_put_locked(mdp); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); ida_free(&mdp->mdp_ida, ctx->id); mutex_unlock(&mdp->m2m_lock); diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c index da3a892ad867..fae3e1ad2df7 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c @@ -221,7 +221,7 @@ int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp, } dev_dbg(&mdp->pdev->dev, - "VPU param:%pK pa:%pad sz:%zx, work:%pK pa:%pad sz:%zx, config:%pK pa:%pad sz:%zx", + "VPU param:%p pa:%pad sz:%zx, work:%p pa:%pad sz:%zx, config:%p pa:%pad sz:%zx", vpu->param, &vpu->param_addr, vpu->param_size, vpu->work, &vpu->work_addr, vpu->work_size, vpu->config, &vpu->config_addr, vpu->config_size); diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_dbgfs.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_dbgfs.c index 5ad3797836db..643d6fff088b 100644 --- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_dbgfs.c +++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_dbgfs.c @@ -183,8 +183,8 @@ static void mtk_vcodec_dbgfs_vdec_init(struct mtk_vcodec_dec_dev *vcodec_dev) vcodec_dev->dbgfs.vcodec_root = debugfs_create_dir("vcodec-dec", NULL); if (IS_ERR(vcodec_dev->dbgfs.vcodec_root)) - dev_err(&vcodec_dev->plat_dev->dev, "create vcodec dir err:%ld\n", - PTR_ERR(vcodec_dev->dbgfs.vcodec_root)); + dev_err(&vcodec_dev->plat_dev->dev, "create vcodec dir err:%pe\n", + vcodec_dev->dbgfs.vcodec_root); vcodec_root = vcodec_dev->dbgfs.vcodec_root; debugfs_create_x32("mtk_v4l2_dbg_level", 0644, vcodec_root, &mtk_v4l2_dbg_level); diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c index d7027d600208..3632037f78f5 100644 --- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c +++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_fw_vpu.c @@ -47,30 +47,32 @@ static void mtk_vcodec_vpu_reset_dec_handler(void *priv) { struct mtk_vcodec_dec_dev *dev = priv; struct mtk_vcodec_dec_ctx *ctx; + unsigned long flags; dev_err(&dev->plat_dev->dev, "Watchdog timeout!!"); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_for_each_entry(ctx, &dev->ctx_list, list) { ctx->state = MTK_STATE_ABORT; mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id); } - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); } static void mtk_vcodec_vpu_reset_enc_handler(void *priv) { struct mtk_vcodec_enc_dev *dev = priv; struct mtk_vcodec_enc_ctx *ctx; + unsigned long flags; dev_err(&dev->plat_dev->dev, "Watchdog timeout!!"); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_for_each_entry(ctx, &dev->ctx_list, list) { ctx->state = MTK_STATE_ABORT; mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id); } - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); } static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = { @@ -117,8 +119,10 @@ struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(void *priv, enum mtk_vcodec_fw_use vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_enc_handler, priv, rst_id); fw = devm_kzalloc(&plat_dev->dev, sizeof(*fw), GFP_KERNEL); - if (!fw) + if (!fw) { + put_device(&fw_pdev->dev); return ERR_PTR(-ENOMEM); + } fw->type = VPU; fw->ops = &mtk_vcodec_vpu_msg; fw->pdev = fw_pdev; diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c index 98838217b97d..1f32ba11a18c 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c @@ -87,7 +87,7 @@ static int stateful_try_decoder_cmd(struct file *file, void *priv, struct v4l2_d static int stateful_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct vb2_queue *src_vq, *dst_vq; int ret; @@ -132,7 +132,7 @@ static int stateless_try_decoder_cmd(struct file *file, void *priv, struct v4l2_ static int stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); int ret; ret = v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, cmd); @@ -158,7 +158,7 @@ static int stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_deco static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (ctx->dev->vdec_pdata->uses_stateless_api) return stateless_try_decoder_cmd(file, priv, cmd); @@ -168,7 +168,7 @@ static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_dec static int vidioc_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (ctx->dev->vdec_pdata->uses_stateless_api) return stateless_decoder_cmd(file, priv, cmd); @@ -233,7 +233,7 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_dec_ctx *ctx) static int vidioc_vdec_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (ctx->state == MTK_STATE_ABORT) { mtk_v4l2_vdec_err(ctx, "[%d] Call on QBUF after unrecoverable error", ctx->id); @@ -246,7 +246,7 @@ static int vidioc_vdec_qbuf(struct file *file, void *priv, static int vidioc_vdec_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (ctx->state == MTK_STATE_ABORT) { mtk_v4l2_vdec_err(ctx, "[%d] Call on DQBUF after unrecoverable error", ctx->id); @@ -259,7 +259,7 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv, static int vidioc_vdec_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct device *dev = &ctx->dev->plat_dev->dev; strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); @@ -354,7 +354,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { const struct mtk_video_fmt *fmt; - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; fmt = mtk_vdec_find_format(f, dec_pdata); @@ -372,7 +372,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; const struct mtk_video_fmt *fmt; - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; fmt = mtk_vdec_find_format(f, dec_pdata); @@ -393,7 +393,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, static int vidioc_vdec_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct mtk_q_data *q_data; if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -442,7 +442,7 @@ static int vidioc_vdec_g_selection(struct file *file, void *priv, static int vidioc_vdec_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -464,7 +464,7 @@ static int vidioc_vdec_s_selection(struct file *file, void *priv, static int vidioc_vdec_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct v4l2_pix_format_mplane *pix_mp; struct mtk_q_data *q_data; int ret = 0; @@ -594,7 +594,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { int i = 0; - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; if (fsize->index != 0) @@ -623,10 +623,10 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, return -EINVAL; } -static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, +static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, bool output_queue) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata; const struct mtk_video_fmt *fmt; int i, j = 0; @@ -660,29 +660,22 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, static int vidioc_vdec_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, priv, false); + return vidioc_enum_fmt(file, f, false); } static int vidioc_vdec_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - return vidioc_enum_fmt(f, priv, true); + return vidioc_enum_fmt(file, f, true); } static int vidioc_vdec_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct vb2_queue *vq; struct mtk_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (!vq) { - mtk_v4l2_vdec_err(ctx, "no vb2 queue for type=%d", f->type); - return -EINVAL; - } - q_data = mtk_vdec_get_q_data(ctx, f->type); pix_mp->field = V4L2_FIELD_NONE; 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 9247d92d431d..3b81fae9f913 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 @@ -198,6 +198,7 @@ static int fops_vcodec_open(struct file *file) struct mtk_vcodec_dec_ctx *ctx = NULL; int ret = 0, i, hw_count; struct vb2_queue *src_vq; + unsigned long flags; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -206,8 +207,7 @@ static int fops_vcodec_open(struct file *file) mutex_lock(&dev->dev_mutex); ctx->id = dev->id_counter++; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); INIT_LIST_HEAD(&ctx->list); ctx->dev = dev; if (ctx->dev->vdec_pdata->is_subdev_supported) { @@ -268,9 +268,9 @@ static int fops_vcodec_open(struct file *file) ctx->dev->vdec_pdata->init_vdec_params(ctx); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_add(&ctx->list, &dev->ctx_list); - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); mtk_vcodec_dbgfs_create(ctx); mutex_unlock(&dev->dev_mutex); @@ -283,7 +283,7 @@ err_load_fw: err_m2m_ctx_init: v4l2_ctrl_handler_free(&ctx->ctrl_hdl); err_ctrls_setup: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&dev->dev_mutex); @@ -294,7 +294,8 @@ err_ctrls_setup: static int fops_vcodec_release(struct file *file) { struct mtk_vcodec_dec_dev *dev = video_drvdata(file); - struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(file->private_data); + struct mtk_vcodec_dec_ctx *ctx = file_to_dec_ctx(file); + unsigned long flags; mtk_v4l2_vdec_dbg(0, ctx, "[%d] decoder", ctx->id); mutex_lock(&dev->dev_mutex); @@ -308,14 +309,14 @@ static int fops_vcodec_release(struct file *file) v4l2_m2m_ctx_release(ctx->m2m_ctx); mtk_vcodec_dec_release(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); mtk_vcodec_dbgfs_remove(dev, ctx->id); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_del_init(&ctx->list); - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); kfree(ctx); mutex_unlock(&dev->dev_mutex); return 0; @@ -408,7 +409,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) for (i = 0; i < MTK_VDEC_HW_MAX; i++) mutex_init(&dev->dec_mutex[i]); mutex_init(&dev->dev_mutex); - mutex_init(&dev->dev_ctx_lock); + spin_lock_init(&dev->dev_ctx_lock); spin_lock_init(&dev->irqlock); snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h index aececca7ecf8..9d68808e8f9c 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.h @@ -285,7 +285,7 @@ struct mtk_vcodec_dec_dev { /* decoder hardware mutex lock */ struct mutex dec_mutex[MTK_VDEC_HW_MAX]; struct mutex dev_mutex; - struct mutex dev_ctx_lock; + spinlock_t dev_ctx_lock; struct workqueue_struct *decode_workqueue; spinlock_t irqlock; @@ -314,6 +314,11 @@ static inline struct mtk_vcodec_dec_ctx *fh_to_dec_ctx(struct v4l2_fh *fh) return container_of(fh, struct mtk_vcodec_dec_ctx, fh); } +static inline struct mtk_vcodec_dec_ctx *file_to_dec_ctx(struct file *filp) +{ + return fh_to_dec_ctx(file_to_v4l2_fh(filp)); +} + static inline struct mtk_vcodec_dec_ctx *ctrl_to_dec_ctx(struct v4l2_ctrl *ctrl) { return container_of(ctrl->handler, struct mtk_vcodec_dec_ctx, ctrl_hdl); diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c index bf21f2467a0f..7be4b6086920 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c @@ -1073,7 +1073,7 @@ static int vdec_av1_slice_setup_lat_from_src_buf(struct vdec_av1_slice_instance lat_buf->src_buf_req = src->vb2_buf.req_obj.req; dst = &lat_buf->ts_info; - v4l2_m2m_buf_copy_metadata(src, dst, true); + v4l2_m2m_buf_copy_metadata(src, dst); vsi->frame.cur_ts = dst->vb2_buf.timestamp; return 0; @@ -1780,7 +1780,7 @@ static int vdec_av1_slice_setup_core_to_dst_buf(struct vdec_av1_slice_instance * if (!dst) return -EINVAL; - v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, dst, true); + v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, dst); return 0; } @@ -1810,8 +1810,6 @@ static int vdec_av1_slice_setup_core_buffer(struct vdec_av1_slice_instance *inst /* reference buffers */ vq = v4l2_m2m_get_vq(instance->ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (!vq) - return -EINVAL; /* get current output buffer */ vb = &v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx)->vb2_buf; diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c index 1e1b32faac77..b9a5ea7887d3 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_if.c @@ -367,7 +367,7 @@ static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb; v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, - &dst_buf_info->m2m_buf.vb, true); + &dst_buf_info->m2m_buf.vb); err = get_vdec_decode_parameters(inst); if (err) goto err_free_fb_out; diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c index 5b25e1679b51..9a9dc2f88d6e 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_h264_req_multi_if.c @@ -570,7 +570,7 @@ static int vdec_h264_slice_setup_core_buffer_ext(struct vdec_h264_slice_inst *in } vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, vb2_v4l2, true); + v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, vb2_v4l2); return 0; } @@ -674,7 +674,7 @@ static int vdec_h264_slice_core_decode(struct vdec_lat_buf *lat_buf) } vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, vb2_v4l2, true); + v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, vb2_v4l2); vdec_h264_slice_fill_decode_reflist(inst, &inst->vsi_core->h264_slice_params, share_info); @@ -768,7 +768,8 @@ static int vdec_h264_slice_lat_decode_ext(void *h_vdec, struct mtk_vcodec_mem *b src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); lat_buf->src_buf_req = src_buf_info->m2m_buf.vb.vb2_buf.req_obj.req; - v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, &lat_buf->ts_info, true); + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &lat_buf->ts_info); err = vdec_h264_slice_fill_decode_parameters(inst, share_info, &inst->vsi_ext->h264_slice_params); @@ -900,7 +901,8 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, inst->vsi->dec.nal_info = buf[nal_start_idx]; lat_buf->src_buf_req = src_buf_info->m2m_buf.vb.vb2_buf.req_obj.req; - v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, &lat_buf->ts_info, true); + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &lat_buf->ts_info); err = vdec_h264_slice_fill_decode_parameters(inst, share_info, &inst->vsi->h264_slice_params); @@ -1039,7 +1041,7 @@ static int vdec_h264_slice_single_decode_ext(void *h_vdec, struct mtk_vcodec_mem inst->vsi_ctx_ext.dec.vdec_fb_va = (u64)(uintptr_t)fb; v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, - &dst_buf_info->m2m_buf.vb, true); + &dst_buf_info->m2m_buf.vb); err = get_vdec_sig_decode_parameters(inst); if (err) goto err_free_fb_out; @@ -1135,7 +1137,7 @@ static int vdec_h264_slice_single_decode(void *h_vdec, struct mtk_vcodec_mem *bs inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb; v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, - &dst_buf_info->m2m_buf.vb, true); + &dst_buf_info->m2m_buf.vb); err = get_vdec_sig_decode_parameters(inst); if (err) goto err_free_fb_out; diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c index 2725db882e5b..88eca50c2017 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_hevc_req_multi_if.c @@ -742,7 +742,8 @@ static int vdec_hevc_slice_setup_lat_buffer(struct vdec_hevc_slice_inst *inst, src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); lat_buf->src_buf_req = src_buf_info->m2m_buf.vb.vb2_buf.req_obj.req; - v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, &lat_buf->ts_info, true); + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &lat_buf->ts_info); *res_chg = inst->resolution_changed; if (inst->resolution_changed) { @@ -847,7 +848,7 @@ static int vdec_hevc_slice_setup_core_buffer(struct vdec_hevc_slice_inst *inst, } vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, vb2_v4l2, true); + v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, vb2_v4l2); return 0; } diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c index 232ef3bd246a..e1d4960553f2 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c @@ -358,7 +358,7 @@ static int vdec_vp8_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, y_fb_dma, c_fb_dma); v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, - &dst_buf_info->m2m_buf.vb, true); + &dst_buf_info->m2m_buf.vb); err = vdec_vp8_slice_get_decode_parameters(inst); if (err) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c index 47c302745c1d..cd1935014d76 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c @@ -706,7 +706,7 @@ int vdec_vp9_slice_setup_single_from_src_to_dst(struct vdec_vp9_slice_instance * if (!dst) return -EINVAL; - v4l2_m2m_buf_copy_metadata(src, dst, true); + v4l2_m2m_buf_copy_metadata(src, dst); return 0; } @@ -724,7 +724,7 @@ static int vdec_vp9_slice_setup_lat_from_src_buf(struct vdec_vp9_slice_instance lat_buf->src_buf_req = src->vb2_buf.req_obj.req; dst = &lat_buf->ts_info; - v4l2_m2m_buf_copy_metadata(src, dst, true); + v4l2_m2m_buf_copy_metadata(src, dst); return 0; } @@ -1652,7 +1652,7 @@ static int vdec_vp9_slice_setup_core_to_dst_buf(struct vdec_vp9_slice_instance * if (!dst) return -EINVAL; - v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, dst, true); + v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, dst); return 0; } @@ -1686,8 +1686,6 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst /* reference buffers */ vq = v4l2_m2m_get_vq(instance->ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (!vq) - return -EINVAL; /* get current output buffer */ vb = &v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx)->vb2_buf; diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c index 145958206e38..40b97f114cf6 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c @@ -75,16 +75,17 @@ static void handle_get_param_msg_ack(const struct vdec_vpu_ipi_get_param_ack *ms static bool vpu_dec_check_ap_inst(struct mtk_vcodec_dec_dev *dec_dev, struct vdec_vpu_inst *vpu) { struct mtk_vcodec_dec_ctx *ctx; + unsigned long flags; int ret = false; - mutex_lock(&dec_dev->dev_ctx_lock); + spin_lock_irqsave(&dec_dev->dev_ctx_lock, flags); list_for_each_entry(ctx, &dec_dev->ctx_list, list) { if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) { ret = true; break; } } - mutex_unlock(&dec_dev->dev_ctx_lock); + spin_unlock_irqrestore(&dec_dev->dev_ctx_lock, flags); return ret; } 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 a01dc25a7699..6faf3f659e75 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c @@ -159,7 +159,7 @@ static int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { const struct mtk_video_fmt *fmt; - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(fh); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); if (fsize->index != 0) return -EINVAL; @@ -183,7 +183,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { const struct mtk_vcodec_enc_pdata *pdata = - fh_to_enc_ctx(priv)->dev->venc_pdata; + file_to_enc_ctx(file)->dev->venc_pdata; return vidioc_enum_fmt(f, pdata->capture_formats, pdata->num_capture_formats); @@ -193,15 +193,14 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { const struct mtk_vcodec_enc_pdata *pdata = - fh_to_enc_ctx(priv)->dev->venc_pdata; + file_to_enc_ctx(file)->dev->venc_pdata; return vidioc_enum_fmt(f, pdata->output_formats, pdata->num_output_formats); } -static int mtk_vcodec_enc_get_chip_name(void *priv) +static int mtk_vcodec_enc_get_chip_name(struct mtk_vcodec_enc_ctx *ctx) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); struct device *dev = &ctx->dev->plat_dev->dev; if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-enc")) @@ -221,9 +220,9 @@ static int mtk_vcodec_enc_get_chip_name(void *priv) static int vidioc_venc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct device *dev = &ctx->dev->plat_dev->dev; - int platform_name = mtk_vcodec_enc_get_chip_name(priv); + int platform_name = mtk_vcodec_enc_get_chip_name(ctx); strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); snprintf(cap->card, sizeof(cap->card), "MT%d video encoder", platform_name); @@ -234,7 +233,7 @@ static int vidioc_venc_querycap(struct file *file, void *priv, static int vidioc_venc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct v4l2_fract *timeperframe = &a->parm.output.timeperframe; if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) @@ -257,7 +256,7 @@ static int vidioc_venc_s_parm(struct file *file, void *priv, static int vidioc_venc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return -EINVAL; @@ -414,7 +413,7 @@ static void mtk_venc_set_param(struct mtk_vcodec_enc_ctx *ctx, static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; struct vb2_queue *vq; struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type); @@ -422,10 +421,6 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, const struct mtk_video_fmt *fmt; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (!vq) { - mtk_v4l2_venc_err(ctx, "fail to get vq"); - return -EINVAL; - } if (vb2_is_busy(vq)) { mtk_v4l2_venc_err(ctx, "queue busy"); @@ -469,7 +464,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, static int vidioc_venc_s_fmt_out(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; struct vb2_queue *vq; struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type); @@ -477,10 +472,6 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv, const struct mtk_video_fmt *fmt; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (!vq) { - mtk_v4l2_venc_err(ctx, "fail to get vq"); - return -EINVAL; - } if (vb2_is_busy(vq)) { mtk_v4l2_venc_err(ctx, "queue busy"); @@ -524,16 +515,10 @@ static int vidioc_venc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); - struct vb2_queue *vq; + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, f->type); int i; - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - pix->width = q_data->coded_width; pix->height = q_data->coded_height; pix->pixelformat = q_data->fmt->fourcc; @@ -557,7 +542,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { const struct mtk_video_fmt *fmt; - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); @@ -579,7 +564,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { const struct mtk_video_fmt *fmt; - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata; fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata); @@ -600,7 +585,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, static int vidioc_venc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -630,7 +615,7 @@ static int vidioc_venc_g_selection(struct file *file, void *priv, static int vidioc_venc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct mtk_q_data *q_data = mtk_venc_get_q_data(ctx, s->type); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -655,7 +640,7 @@ static int vidioc_venc_s_selection(struct file *file, void *priv, static int vidioc_venc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); if (ctx->state == MTK_STATE_ABORT) { mtk_v4l2_venc_err(ctx, "[%d] Call on QBUF after unrecoverable error", @@ -669,7 +654,7 @@ static int vidioc_venc_qbuf(struct file *file, void *priv, static int vidioc_venc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); int ret; if (ctx->state == MTK_STATE_ABORT) { @@ -707,7 +692,7 @@ static int vidioc_venc_dqbuf(struct file *file, void *priv, static int vidioc_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *cmd) { - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(priv); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); struct vb2_queue *src_vq, *dst_vq; int ret; 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 a1e4483abcdb..82b8ff38e8f1 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 @@ -117,6 +117,7 @@ static int fops_vcodec_open(struct file *file) struct mtk_vcodec_enc_ctx *ctx = NULL; int ret = 0; struct vb2_queue *src_vq; + unsigned long flags; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -129,8 +130,7 @@ static int fops_vcodec_open(struct file *file) */ ctx->id = dev->id_counter++; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); INIT_LIST_HEAD(&ctx->list); ctx->dev = dev; init_waitqueue_head(&ctx->queue[0]); @@ -177,9 +177,9 @@ static int fops_vcodec_open(struct file *file) mtk_v4l2_venc_dbg(2, ctx, "Create instance [%d]@%p m2m_ctx=%p ", ctx->id, ctx, ctx->m2m_ctx); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_add(&ctx->list, &dev->ctx_list); - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); mutex_unlock(&dev->dev_mutex); mtk_v4l2_venc_dbg(0, ctx, "%s encoder [%d]", dev_name(&dev->plat_dev->dev), @@ -192,7 +192,7 @@ err_load_fw: err_m2m_ctx_init: v4l2_ctrl_handler_free(&ctx->ctrl_hdl); err_ctrls_setup: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&dev->dev_mutex); @@ -203,20 +203,21 @@ err_ctrls_setup: static int fops_vcodec_release(struct file *file) { struct mtk_vcodec_enc_dev *dev = video_drvdata(file); - struct mtk_vcodec_enc_ctx *ctx = fh_to_enc_ctx(file->private_data); + struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); + unsigned long flags; mtk_v4l2_venc_dbg(1, ctx, "[%d] encoder", ctx->id); mutex_lock(&dev->dev_mutex); v4l2_m2m_ctx_release(ctx->m2m_ctx); mtk_vcodec_enc_release(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); - mutex_lock(&dev->dev_ctx_lock); + spin_lock_irqsave(&dev->dev_ctx_lock, flags); list_del_init(&ctx->list); - mutex_unlock(&dev->dev_ctx_lock); + spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); kfree(ctx); mutex_unlock(&dev->dev_mutex); return 0; @@ -298,7 +299,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) mutex_init(&dev->enc_mutex); mutex_init(&dev->dev_mutex); - mutex_init(&dev->dev_ctx_lock); + spin_lock_init(&dev->dev_ctx_lock); spin_lock_init(&dev->irqlock); snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h index 0bd85d0fb379..0cddfa13594f 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.h @@ -206,7 +206,7 @@ struct mtk_vcodec_enc_dev { /* encoder hardware mutex lock */ struct mutex enc_mutex; struct mutex dev_mutex; - struct mutex dev_ctx_lock; + spinlock_t dev_ctx_lock; struct workqueue_struct *encode_workqueue; int enc_irq; @@ -217,9 +217,9 @@ struct mtk_vcodec_enc_dev { struct mtk_vcodec_dbgfs dbgfs; }; -static inline struct mtk_vcodec_enc_ctx *fh_to_enc_ctx(struct v4l2_fh *fh) +static inline struct mtk_vcodec_enc_ctx *file_to_enc_ctx(struct file *filp) { - return container_of(fh, struct mtk_vcodec_enc_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct mtk_vcodec_enc_ctx, fh); } static inline struct mtk_vcodec_enc_ctx *ctrl_to_enc_ctx(struct v4l2_ctrl *ctrl) diff --git a/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c b/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c index 51bb7ee141b9..3c229b1f6b21 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/encoder/venc_vpu_if.c @@ -45,16 +45,17 @@ static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data) static bool vpu_enc_check_ap_inst(struct mtk_vcodec_enc_dev *enc_dev, struct venc_vpu_inst *vpu) { struct mtk_vcodec_enc_ctx *ctx; + unsigned long flags; int ret = false; - mutex_lock(&enc_dev->dev_ctx_lock); + spin_lock_irqsave(&enc_dev->dev_ctx_lock, flags); list_for_each_entry(ctx, &enc_dev->ctx_list, list) { if (!IS_ERR_OR_NULL(ctx) && ctx->vpu_inst == vpu) { ret = true; break; } } - mutex_unlock(&enc_dev->dev_ctx_lock); + spin_unlock_irqrestore(&enc_dev->dev_ctx_lock, flags); return ret; } diff --git a/drivers/media/platform/nvidia/tegra-vde/h264.c b/drivers/media/platform/nvidia/tegra-vde/h264.c index 0e56a4331b0d..2a2211671fd9 100644 --- a/drivers/media/platform/nvidia/tegra-vde/h264.c +++ b/drivers/media/platform/nvidia/tegra-vde/h264.c @@ -585,7 +585,6 @@ static int tegra_vde_decode_begin(struct tegra_vde *vde, return 0; put_runtime_pm: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); unlock: @@ -612,7 +611,6 @@ static void tegra_vde_decode_abort(struct tegra_vde *vde) if (err) dev_err(dev, "DEC end: Failed to assert HW reset: %d\n", err); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); mutex_unlock(&vde->lock); @@ -778,7 +776,7 @@ static int tegra_vde_h264_setup_frames(struct tegra_ctx *ctx, * If userspace doesn't tell us frame's type, then we will try decode * as-is. */ - v4l2_m2m_buf_copy_metadata(src, dst, true); + v4l2_m2m_buf_copy_metadata(src, dst); if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) tb->b_frame = true; diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c index e3726cab0c82..d94978ae2baf 100644 --- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c +++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c @@ -46,9 +46,9 @@ static const struct v4l2_ctrl_config ctrl_cfgs[] = { }, }; -static inline struct tegra_ctx *fh_to_tegra_ctx(struct v4l2_fh *fh) +static inline struct tegra_ctx *file_to_tegra_ctx(struct file *file) { - return container_of(fh, struct tegra_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct tegra_ctx, fh); } static void tegra_set_control_data(struct tegra_ctx *ctx, void *data, u32 id) @@ -506,7 +506,7 @@ static int tegra_querycap(struct file *file, void *priv, static int tegra_enum_decoded_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); if (WARN_ON(!ctx->coded_fmt_desc)) return -EINVAL; @@ -522,7 +522,7 @@ static int tegra_enum_decoded_fmt(struct file *file, void *priv, static int tegra_g_decoded_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); *f = ctx->decoded_fmt; return 0; @@ -531,8 +531,8 @@ static int tegra_g_decoded_fmt(struct file *file, void *priv, static int tegra_try_decoded_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct tegra_ctx *ctx = file_to_tegra_ctx(file); struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); const struct tegra_coded_fmt_desc *coded_desc; unsigned int i; @@ -571,7 +571,7 @@ static int tegra_try_decoded_fmt(struct file *file, void *priv, static int tegra_s_decoded_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); struct vb2_queue *vq; int err; @@ -593,7 +593,7 @@ static int tegra_s_decoded_fmt(struct file *file, void *priv, static int tegra_enum_coded_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); const struct tegra_vde_soc *soc = ctx->vde->soc; if (f->index >= soc->num_coded_fmts) @@ -607,7 +607,7 @@ static int tegra_enum_coded_fmt(struct file *file, void *priv, static int tegra_g_coded_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); *f = ctx->coded_fmt; return 0; @@ -631,7 +631,7 @@ static int tegra_try_coded_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); const struct tegra_vde_soc *soc = ctx->vde->soc; int size = pix_mp->plane_fmt[0].sizeimage; const struct tegra_coded_fmt_desc *desc; @@ -656,7 +656,7 @@ static int tegra_try_coded_fmt(struct file *file, void *priv, static int tegra_s_coded_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; const struct tegra_coded_fmt_desc *desc; struct vb2_queue *peer_vq, *vq; @@ -718,7 +718,7 @@ static int tegra_s_coded_fmt(struct file *file, void *priv, static int tegra_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); const struct tegra_coded_fmt_desc *fmt; if (fsize->index) @@ -832,14 +832,13 @@ static int tegra_open(struct file *file) goto free_ctrls; } - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); tegra_reset_coded_fmt(ctx); - tegra_try_coded_fmt(file, file->private_data, &ctx->coded_fmt); + tegra_try_coded_fmt(file, &ctx->fh, &ctx->coded_fmt); tegra_reset_decoded_fmt(ctx); - tegra_try_decoded_fmt(file, file->private_data, &ctx->decoded_fmt); + tegra_try_decoded_fmt(file, &ctx->fh, &ctx->decoded_fmt); return 0; @@ -853,11 +852,11 @@ free_ctx: static int tegra_release(struct file *file) { - struct v4l2_fh *fh = file->private_data; - struct tegra_ctx *ctx = fh_to_tegra_ctx(fh); + struct tegra_ctx *ctx = file_to_tegra_ctx(file); + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct tegra_vde *vde = ctx->vde; - v4l2_fh_del(fh); + v4l2_fh_del(fh, file); v4l2_m2m_ctx_release(fh->m2m_ctx); v4l2_ctrl_handler_free(&ctx->hdl); v4l2_fh_exit(fh); diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c index 3d1db1121bf9..4aaf9c3fff53 100644 --- a/drivers/media/platform/nxp/dw100/dw100.c +++ b/drivers/media/platform/nxp/dw100/dw100.c @@ -266,7 +266,7 @@ static inline int dw100_dump_regs(struct seq_file *m) static inline struct dw100_ctx *dw100_file2ctx(struct file *file) { - return container_of(file->private_data, struct dw100_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct dw100_ctx, fh); } static struct dw100_q_data *dw100_get_q_data(struct dw100_ctx *ctx, @@ -607,7 +607,6 @@ static int dw100_open(struct file *file) mutex_init(&ctx->vq_mutex); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dw_dev = dw_dev; ctx->q_data[DW100_QUEUE_SRC].fmt = &formats[0]; @@ -651,7 +650,7 @@ static int dw100_open(struct file *file) goto err; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); return 0; @@ -668,7 +667,7 @@ static int dw100_release(struct file *file) { struct dw100_ctx *ctx = dw100_file2ctx(file); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); @@ -736,13 +735,8 @@ static int dw100_enum_framesizes(struct file *file, void *priv, static int dw100_g_fmt_vid(struct file *file, void *priv, struct v4l2_format *f) { struct dw100_ctx *ctx = dw100_file2ctx(file); - struct vb2_queue *vq; struct dw100_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - q_data = dw100_get_q_data(ctx, f->type); f->fmt.pix_mp = q_data->pix_fmt; @@ -804,8 +798,6 @@ static int dw100_s_fmt(struct dw100_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; q_data = dw100_get_q_data(ctx, f->type); if (!q_data) @@ -1438,7 +1430,7 @@ static void dw100_start(struct dw100_ctx *ctx, struct vb2_v4l2_buffer *in_vb, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE), in_vb->sequence, out_vb->sequence); - v4l2_m2m_buf_copy_metadata(in_vb, out_vb, true); + v4l2_m2m_buf_copy_metadata(in_vb, out_vb); /* Now, let's deal with hardware ... */ dw100_hw_master_bus_disable(dw_dev); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 8681dd193033..9e4a813489c0 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -644,9 +644,9 @@ static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf, } } -static inline struct mxc_jpeg_ctx *mxc_jpeg_fh_to_ctx(struct v4l2_fh *fh) +static inline struct mxc_jpeg_ctx *mxc_jpeg_file_to_ctx(struct file *filp) { - return container_of(fh, struct mxc_jpeg_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct mxc_jpeg_ctx, fh); } static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n, @@ -1537,7 +1537,7 @@ static void mxc_jpeg_device_run(void *priv) src_buf->sequence = q_data_out->sequence++; dst_buf->sequence = q_data_cap->sequence++; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); jpeg_src_buf = vb2_to_mxc_buf(&src_buf->vb2_buf); if (q_data_cap->fmt->mem_planes != dst_buf->vb2_buf.num_planes) { @@ -1604,8 +1604,8 @@ end: static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct v4l2_fh *fh = file->private_data; - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct v4l2_fh *fh = file_to_v4l2_fh(file); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); unsigned long flags; int ret; @@ -1637,8 +1637,8 @@ static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, static int mxc_jpeg_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *cmd) { - struct v4l2_fh *fh = file->private_data; - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct v4l2_fh *fh = file_to_v4l2_fh(file); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); unsigned long flags; int ret; @@ -2200,8 +2200,7 @@ static int mxc_jpeg_open(struct file *file) } v4l2_fh_init(&ctx->fh, mxc_vfd); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->mxc_jpeg = mxc_jpeg; @@ -2234,7 +2233,7 @@ static int mxc_jpeg_open(struct file *file) err_ctrls_setup: v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); error: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&mxc_jpeg->lock); free: @@ -2256,7 +2255,7 @@ static int mxc_jpeg_querycap(struct file *file, void *priv, static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type); if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) { @@ -2296,7 +2295,7 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); u32 type = ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? MXC_JPEG_FMT_TYPE_ENC : MXC_JPEG_FMT_TYPE_RAW; int ret; @@ -2437,7 +2436,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; struct device *dev = jpeg->dev; struct mxc_jpeg_q_data tmp_q; @@ -2456,7 +2455,7 @@ static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv, static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; struct device *dev = jpeg->dev; struct mxc_jpeg_q_data tmp_q; @@ -2492,8 +2491,6 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx, struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; if (vb2_is_busy(vq)) { v4l2_err(&jpeg->v4l2_dev, "queue busy\n"); @@ -2508,20 +2505,20 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx, static int mxc_jpeg_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); + return mxc_jpeg_s_fmt(mxc_jpeg_file_to_ctx(file), f); } static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { int ret; - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct vb2_queue *dst_vq; struct mxc_jpeg_q_data *q_data_cap; enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; struct v4l2_format fc; - ret = mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); + ret = mxc_jpeg_s_fmt(ctx, f); if (ret) return ret; @@ -2529,8 +2526,6 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv, return 0; dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, cap_type); - if (!dst_vq) - return -EINVAL; if (vb2_is_busy(dst_vq)) return 0; @@ -2550,7 +2545,7 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv, static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, struct v4l2_format *f) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; struct device *dev = jpeg->dev; struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; @@ -2588,7 +2583,7 @@ static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, static int mxc_jpeg_dec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_q_data *q_data_cap; if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -2617,7 +2612,7 @@ static int mxc_jpeg_dec_g_selection(struct file *file, void *fh, struct v4l2_sel static int mxc_jpeg_enc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_q_data *q_data_out; if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) @@ -2645,7 +2640,7 @@ static int mxc_jpeg_enc_g_selection(struct file *file, void *fh, struct v4l2_sel static int mxc_jpeg_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) return mxc_jpeg_dec_g_selection(file, fh, s); @@ -2655,7 +2650,7 @@ static int mxc_jpeg_g_selection(struct file *file, void *fh, struct v4l2_selecti static int mxc_jpeg_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct mxc_jpeg_q_data *q_data_out; if (ctx->mxc_jpeg->mode != MXC_JPEG_ENCODE) @@ -2735,7 +2730,7 @@ static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = { static int mxc_jpeg_release(struct file *file) { struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file); - struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(file->private_data); + struct mxc_jpeg_ctx *ctx = mxc_jpeg_file_to_ctx(file); struct device *dev = mxc_jpeg->dev; mutex_lock(&mxc_jpeg->lock); @@ -2747,7 +2742,7 @@ static int mxc_jpeg_release(struct file *file) ctx->slot); v4l2_ctrl_handler_free(&ctx->ctrl_handler); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&mxc_jpeg->lock); diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 2beb5f43c2c0..088b2945aee3 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -54,23 +54,19 @@ /* CSIS common control */ #define MIPI_CSIS_CMN_CTRL 0x04 -#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW BIT(16) -#define MIPI_CSIS_CMN_CTRL_INTER_MODE BIT(10) +#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW(n) BIT((n) + 16) +#define MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_DT BIT(10) +#define MIPI_CSIS_CMN_CTRL_LANE_NUMBER(n) ((n) << 8) +#define MIPI_CSIS_CMN_CTRL_LANE_NUMBER_MASK GENMASK(9, 8) #define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL BIT(2) -#define MIPI_CSIS_CMN_CTRL_RESET BIT(1) -#define MIPI_CSIS_CMN_CTRL_ENABLE BIT(0) - -#define MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET 8 -#define MIPI_CSIS_CMN_CTRL_LANE_NR_MASK (3 << 8) +#define MIPI_CSIS_CMN_CTRL_SW_RESET BIT(1) +#define MIPI_CSIS_CMN_CTRL_CSI_EN BIT(0) /* CSIS clock control */ #define MIPI_CSIS_CLK_CTRL 0x08 -#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH3(x) ((x) << 28) -#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH2(x) ((x) << 24) -#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH1(x) ((x) << 20) -#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(x) ((x) << 16) -#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK (0xf << 4) -#define MIPI_CSIS_CLK_CTRL_WCLK_SRC BIT(0) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(n, x) ((x) << ((n) * 4 + 16)) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MASK GENMASK(7, 4) +#define MIPI_CSIS_CLK_CTRL_WCLK_SRC(n) BIT(n) /* CSIS Interrupt mask */ #define MIPI_CSIS_INT_MSK 0x10 @@ -87,7 +83,7 @@ #define MIPI_CSIS_INT_MSK_ERR_WRONG_CFG BIT(3) #define MIPI_CSIS_INT_MSK_ERR_ECC BIT(2) #define MIPI_CSIS_INT_MSK_ERR_CRC BIT(1) -#define MIPI_CSIS_INT_MSK_ERR_UNKNOWN BIT(0) +#define MIPI_CSIS_INT_MSK_ERR_ID BIT(0) /* CSIS Interrupt source */ #define MIPI_CSIS_INT_SRC 0x14 @@ -98,16 +94,16 @@ #define MIPI_CSIS_INT_SRC_ODD_AFTER BIT(28) #define MIPI_CSIS_INT_SRC_ODD (0x3 << 28) #define MIPI_CSIS_INT_SRC_NON_IMAGE_DATA (0xf << 28) -#define MIPI_CSIS_INT_SRC_FRAME_START BIT(24) -#define MIPI_CSIS_INT_SRC_FRAME_END BIT(20) -#define MIPI_CSIS_INT_SRC_ERR_SOT_HS BIT(16) -#define MIPI_CSIS_INT_SRC_ERR_LOST_FS BIT(12) -#define MIPI_CSIS_INT_SRC_ERR_LOST_FE BIT(8) -#define MIPI_CSIS_INT_SRC_ERR_OVER BIT(4) +#define MIPI_CSIS_INT_SRC_FRAME_START(n) BIT((n) + 24) +#define MIPI_CSIS_INT_SRC_FRAME_END(n) BIT((n) + 20) +#define MIPI_CSIS_INT_SRC_ERR_SOT_HS(n) BIT((n) + 16) +#define MIPI_CSIS_INT_SRC_ERR_LOST_FS(n) BIT((n) + 12) +#define MIPI_CSIS_INT_SRC_ERR_LOST_FE(n) BIT((n) + 8) +#define MIPI_CSIS_INT_SRC_ERR_OVER(n) BIT((n) + 4) #define MIPI_CSIS_INT_SRC_ERR_WRONG_CFG BIT(3) #define MIPI_CSIS_INT_SRC_ERR_ECC BIT(2) #define MIPI_CSIS_INT_SRC_ERR_CRC BIT(1) -#define MIPI_CSIS_INT_SRC_ERR_UNKNOWN BIT(0) +#define MIPI_CSIS_INT_SRC_ERR_ID BIT(0) #define MIPI_CSIS_INT_SRC_ERRORS 0xfffff /* D-PHY status control */ @@ -123,8 +119,8 @@ #define MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE_MASK GENMASK(31, 24) #define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(n) ((n) << 22) #define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE_MASK GENMASK(23, 22) -#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_CLK BIT(6) -#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_DAT BIT(5) +#define MIPI_CSIS_DPHY_CMN_CTRL_S_DPDN_SWAP_CLK BIT(6) +#define MIPI_CSIS_DPHY_CMN_CTRL_S_DPDN_SWAP_DAT BIT(5) #define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_DAT BIT(1) #define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_CLK BIT(0) #define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE (0x1f << 0) @@ -174,26 +170,28 @@ /* ISP Configuration register */ #define MIPI_CSIS_ISP_CONFIG_CH(n) (0x40 + (n) * 0x10) -#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK (0xff << 24) +#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MASK GENMASK(31, 24) #define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x) ((x) << 24) #define MIPI_CSIS_ISPCFG_PIXEL_MODE_SINGLE (0 << 12) #define MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL (1 << 12) #define MIPI_CSIS_ISPCFG_PIXEL_MODE_QUAD (2 << 12) /* i.MX8M[MNP] only */ -#define MIPI_CSIS_ISPCFG_PIXEL_MASK (3 << 12) -#define MIPI_CSIS_ISPCFG_ALIGN_32BIT BIT(11) -#define MIPI_CSIS_ISPCFG_FMT(fmt) ((fmt) << 2) -#define MIPI_CSIS_ISPCFG_FMT_MASK (0x3f << 2) +#define MIPI_CSIS_ISPCFG_PIXEL_MODE_MASK GENMASK(13, 12) +#define MIPI_CSIS_ISPCFG_PARALLEL BIT(11) +#define MIPI_CSIS_ISPCFG_DATAFORMAT(fmt) ((fmt) << 2) +#define MIPI_CSIS_ISPCFG_DATAFORMAT_MASK GENMASK(7, 2) /* ISP Image Resolution register */ #define MIPI_CSIS_ISP_RESOL_CH(n) (0x44 + (n) * 0x10) +#define MIPI_CSIS_ISP_RESOL_VRESOL(n) ((n) << 16) +#define MIPI_CSIS_ISP_RESOL_HRESOL(n) ((n) << 0) #define CSIS_MAX_PIX_WIDTH 0xffff #define CSIS_MAX_PIX_HEIGHT 0xffff /* ISP SYNC register */ #define MIPI_CSIS_ISP_SYNC_CH(n) (0x48 + (n) * 0x10) -#define MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET 18 -#define MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET 12 -#define MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET 0 +#define MIPI_CSIS_ISP_SYNC_HSYNC_LINTV(n) ((n) << 18) +#define MIPI_CSIS_ISP_SYNC_VSYNC_SINTV(n) ((n) << 12) +#define MIPI_CSIS_ISP_SYNC_VSYNC_EINTV(n) ((n) << 0) /* ISP shadow registers */ #define MIPI_CSIS_SDW_CONFIG_CH(n) (0x80 + (n) * 0x10) @@ -203,23 +201,23 @@ /* Debug control register */ #define MIPI_CSIS_DBG_CTRL 0xc0 #define MIPI_CSIS_DBG_INTR_MSK 0xc4 -#define MIPI_CSIS_DBG_INTR_MSK_DT_NOT_SUPPORT BIT(25) -#define MIPI_CSIS_DBG_INTR_MSK_DT_IGNORE BIT(24) -#define MIPI_CSIS_DBG_INTR_MSK_ERR_FRAME_SIZE BIT(20) -#define MIPI_CSIS_DBG_INTR_MSK_TRUNCATED_FRAME BIT(16) -#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FE BIT(12) -#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FS BIT(8) -#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_FALL BIT(4) -#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_RISE BIT(0) +#define MIPI_CSIS_DBG_INTR_MSK_DT_NOT_SUPPORT BIT(25) +#define MIPI_CSIS_DBG_INTR_MSK_DT_IGNORE BIT(24) +#define MIPI_CSIS_DBG_INTR_MSK_ERR_FRAME_SIZE(n) BIT((n) + 20) +#define MIPI_CSIS_DBG_INTR_MSK_TRUNCATED_FRAME(n) BIT((n) + 16) +#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FE(n) BIT((n) + 12) +#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FS(n) BIT((n) + 8) +#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_FALL(n) BIT((n) + 4) +#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_RISE(n) BIT((n) + 0) #define MIPI_CSIS_DBG_INTR_SRC 0xc8 -#define MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT BIT(25) -#define MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE BIT(24) -#define MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE BIT(20) -#define MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME BIT(16) -#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FE BIT(12) -#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FS BIT(8) -#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL BIT(4) -#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE BIT(0) +#define MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT BIT(25) +#define MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE BIT(24) +#define MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(n) BIT((n) + 20) +#define MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(n) BIT((n) + 16) +#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(n) BIT((n) + 12) +#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(n) BIT((n) + 8) +#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(n) BIT((n) + 4) +#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(n) BIT((n) + 0) #define MIPI_CSIS_FRAME_COUNTER_CH(n) (0x0100 + (n) * 4) @@ -228,10 +226,11 @@ #define MIPI_CSIS_PKTDATA_EVEN 0x3000 #define MIPI_CSIS_PKTDATA_SIZE SZ_4K -#define DEFAULT_SCLK_CSIS_FREQ 166000000UL +#define MIPI_CSIS_MAX_CHANNELS 4 struct mipi_csis_event { bool debug; + unsigned int channel; u32 mask; const char * const name; unsigned int counter; @@ -239,33 +238,70 @@ struct mipi_csis_event { static const struct mipi_csis_event mipi_csis_events[] = { /* Errors */ - { false, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" }, - { true, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" }, - { true, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" }, - { true, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error" }, - { true, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame" }, - { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End" }, - { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_SOT_HS(0), "SOT 0 Error" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_SOT_HS(1), "SOT 1 Error" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_SOT_HS(2), "SOT 2 Error" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_SOT_HS(3), "SOT 3 Error" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_LOST_FS(0), "Lost Frame Start Error 0" }, + { false, 1, MIPI_CSIS_INT_SRC_ERR_LOST_FS(1), "Lost Frame Start Error 1" }, + { false, 2, MIPI_CSIS_INT_SRC_ERR_LOST_FS(2), "Lost Frame Start Error 2" }, + { false, 3, MIPI_CSIS_INT_SRC_ERR_LOST_FS(3), "Lost Frame Start Error 3" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_LOST_FE(0), "Lost Frame End Error 0" }, + { false, 1, MIPI_CSIS_INT_SRC_ERR_LOST_FE(1), "Lost Frame End Error 1" }, + { false, 2, MIPI_CSIS_INT_SRC_ERR_LOST_FE(2), "Lost Frame End Error 2" }, + { false, 3, MIPI_CSIS_INT_SRC_ERR_LOST_FE(3), "Lost Frame End Error 3" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_OVER(0), "FIFO Overflow Error 0" }, + { false, 1, MIPI_CSIS_INT_SRC_ERR_OVER(1), "FIFO Overflow Error 1" }, + { false, 2, MIPI_CSIS_INT_SRC_ERR_OVER(2), "FIFO Overflow Error 2" }, + { false, 3, MIPI_CSIS_INT_SRC_ERR_OVER(3), "FIFO Overflow Error 3" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" }, + { false, 0, MIPI_CSIS_INT_SRC_ERR_ID, "Unknown ID Error" }, + { true, 0, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" }, + { true, 0, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" }, + { true, 0, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(0), "Frame Size Error 0" }, + { true, 1, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(1), "Frame Size Error 1" }, + { true, 2, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(2), "Frame Size Error 2" }, + { true, 3, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE(3), "Frame Size Error 3" }, + { true, 0, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(0), "Truncated Frame 0" }, + { true, 1, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(1), "Truncated Frame 1" }, + { true, 2, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(2), "Truncated Frame 2" }, + { true, 3, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME(3), "Truncated Frame 3" }, + { true, 0, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(0), "Early Frame End 0" }, + { true, 1, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(1), "Early Frame End 1" }, + { true, 2, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(2), "Early Frame End 2" }, + { true, 3, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE(3), "Early Frame End 3" }, + { true, 0, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(0), "Early Frame Start 0" }, + { true, 1, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(1), "Early Frame Start 1" }, + { true, 2, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(2), "Early Frame Start 2" }, + { true, 3, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS(3), "Early Frame Start 3" }, /* Non-image data receive events */ - { false, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" }, - { false, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" }, - { false, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" }, - { false, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" }, + { false, 0, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" }, + { false, 0, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" }, + { false, 0, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" }, + { false, 0, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" }, /* Frame start/end */ - { false, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" }, - { false, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" }, - { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge" }, - { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge" }, + { false, 0, MIPI_CSIS_INT_SRC_FRAME_START(0), "Frame Start 0" }, + { false, 1, MIPI_CSIS_INT_SRC_FRAME_START(1), "Frame Start 1" }, + { false, 2, MIPI_CSIS_INT_SRC_FRAME_START(2), "Frame Start 2" }, + { false, 3, MIPI_CSIS_INT_SRC_FRAME_START(3), "Frame Start 3" }, + { false, 0, MIPI_CSIS_INT_SRC_FRAME_END(0), "Frame End 0" }, + { false, 1, MIPI_CSIS_INT_SRC_FRAME_END(1), "Frame End 1" }, + { false, 2, MIPI_CSIS_INT_SRC_FRAME_END(2), "Frame End 2" }, + { false, 3, MIPI_CSIS_INT_SRC_FRAME_END(3), "Frame End 3" }, + { true, 0, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(0), "VSYNC Falling Edge 0" }, + { true, 1, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(1), "VSYNC Falling Edge 1" }, + { true, 2, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(2), "VSYNC Falling Edge 2" }, + { true, 3, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL(3), "VSYNC Falling Edge 3" }, + { true, 0, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(0), "VSYNC Rising Edge 0" }, + { true, 1, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(1), "VSYNC Rising Edge 1" }, + { true, 2, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(2), "VSYNC Rising Edge 2" }, + { true, 3, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE(3), "VSYNC Rising Edge 3" }, }; -#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events) +#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events) +#define MIPI_CSIS_NUM_ERROR_EVENTS 38 enum mipi_csis_clk { MIPI_CSIS_CLK_PCLK, @@ -297,7 +333,9 @@ struct mipi_csis_device { struct clk_bulk_data *clks; struct reset_control *mrst; struct regulator *mipi_phy_regulator; + const struct mipi_csis_info *info; + unsigned int num_channels; struct v4l2_subdev sd; struct media_pad pads[CSIS_PADS_NUM]; @@ -313,6 +351,8 @@ struct mipi_csis_device { u32 hs_settle; u32 clk_settle; + unsigned int num_data_lanes; + spinlock_t slock; /* Protect events */ struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; struct dentry *debugfs_root; @@ -517,7 +557,7 @@ static void mipi_csis_sw_reset(struct mipi_csis_device *csis) u32 val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, - val | MIPI_CSIS_CMN_CTRL_RESET); + val | MIPI_CSIS_CMN_CTRL_SW_RESET); usleep_range(10, 20); } @@ -527,15 +567,15 @@ static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on) val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); if (on) - val |= MIPI_CSIS_CMN_CTRL_ENABLE; + val |= MIPI_CSIS_CMN_CTRL_CSI_EN; else - val &= ~MIPI_CSIS_CMN_CTRL_ENABLE; + val &= ~MIPI_CSIS_CMN_CTRL_CSI_EN; mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val); val = mipi_csis_read(csis, MIPI_CSIS_DPHY_CMN_CTRL); val &= ~MIPI_CSIS_DPHY_CMN_CTRL_ENABLE; if (on) { - mask = (1 << (csis->bus.num_data_lanes + 1)) - 1; + mask = (1 << (csis->num_data_lanes + 1)) - 1; val |= (mask & MIPI_CSIS_DPHY_CMN_CTRL_ENABLE); } mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val); @@ -549,8 +589,8 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis, /* Color format */ val = mipi_csis_read(csis, MIPI_CSIS_ISP_CONFIG_CH(0)); - val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK - | MIPI_CSIS_ISPCFG_PIXEL_MASK); + val &= ~(MIPI_CSIS_ISPCFG_PARALLEL | MIPI_CSIS_ISPCFG_PIXEL_MODE_MASK | + MIPI_CSIS_ISPCFG_DATAFORMAT_MASK); /* * YUV 4:2:2 can be transferred with 8 or 16 bits per clock sample @@ -568,25 +608,24 @@ static void __mipi_csis_set_format(struct mipi_csis_device *csis, if (csis_fmt->data_type == MIPI_CSI2_DT_YUV422_8B) val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; - val |= MIPI_CSIS_ISPCFG_FMT(csis_fmt->data_type); + val |= MIPI_CSIS_ISPCFG_DATAFORMAT(csis_fmt->data_type); mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val); /* Pixel resolution */ - val = format->width | (format->height << 16); - mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val); + mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), + MIPI_CSIS_ISP_RESOL_VRESOL(format->height) | + MIPI_CSIS_ISP_RESOL_HRESOL(format->width)); } static int mipi_csis_calculate_params(struct mipi_csis_device *csis, const struct csis_pix_format *csis_fmt) { - struct media_pad *src_pad = - &csis->source.sd->entity.pads[csis->source.pad->index]; s64 link_freq; u32 lane_rate; /* Calculate the line rate from the pixel rate. */ - link_freq = v4l2_get_link_freq(src_pad, csis_fmt->width, - csis->bus.num_data_lanes * 2); + link_freq = v4l2_get_link_freq(csis->source.pad, csis_fmt->width, + csis->num_data_lanes * 2); if (link_freq < 0) { dev_err(csis->dev, "Unable to obtain link frequency: %d\n", (int)link_freq); @@ -631,14 +670,14 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis, const struct v4l2_mbus_framefmt *format, const struct csis_pix_format *csis_fmt) { - int lanes = csis->bus.num_data_lanes; + int lanes = csis->num_data_lanes; u32 val; val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); - val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK; - val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET; + val &= ~MIPI_CSIS_CMN_CTRL_LANE_NUMBER_MASK; + val |= MIPI_CSIS_CMN_CTRL_LANE_NUMBER(lanes - 1); if (csis->info->version == MIPI_CSIS_V3_3) - val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; + val |= MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_DT; mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val); __mipi_csis_set_format(csis, format, csis_fmt); @@ -647,15 +686,15 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis, MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) | MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(csis->clk_settle)); - val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET) - | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET) - | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET); - mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(0), val); + mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(0), + MIPI_CSIS_ISP_SYNC_HSYNC_LINTV(0) | + MIPI_CSIS_ISP_SYNC_VSYNC_SINTV(0) | + MIPI_CSIS_ISP_SYNC_VSYNC_EINTV(0)); val = mipi_csis_read(csis, MIPI_CSIS_CLK_CTRL); - val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC; - val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15); - val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK; + val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC(0); + val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(0, 15); + val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MASK; mipi_csis_write(csis, MIPI_CSIS_CLK_CTRL, val); mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_L, @@ -671,7 +710,7 @@ static void mipi_csis_set_params(struct mipi_csis_device *csis, /* Update the shadow register. */ val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, - val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW | + val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW(0) | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL); } @@ -704,12 +743,17 @@ static int mipi_csis_clk_get(struct mipi_csis_device *csis) if (ret < 0) return ret; - /* Set clock rate */ - ret = clk_set_rate(csis->clks[MIPI_CSIS_CLK_WRAP].clk, - csis->clk_frequency); - if (ret < 0) - dev_err(csis->dev, "set rate=%d failed: %d\n", - csis->clk_frequency, ret); + if (csis->clk_frequency) { + /* + * Set the clock rate. This is deprecated, for backward + * compatibility with old device trees. + */ + ret = clk_set_rate(csis->clks[MIPI_CSIS_CLK_WRAP].clk, + csis->clk_frequency); + if (ret < 0) + dev_err(csis->dev, "set rate=%d failed: %d\n", + csis->clk_frequency, ret); + } return ret; } @@ -757,16 +801,19 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) /* Update the event/error counters */ if ((status & MIPI_CSIS_INT_SRC_ERRORS) || csis->debug.enable) { - for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) { + for (i = 0; i < ARRAY_SIZE(csis->events); i++) { struct mipi_csis_event *event = &csis->events[i]; + if (event->channel >= csis->num_channels) + continue; + if ((!event->debug && (status & event->mask)) || (event->debug && (dbg_status & event->mask))) event->counter++; } } - if (status & MIPI_CSIS_INT_SRC_FRAME_START) + if (status & MIPI_CSIS_INT_SRC_FRAME_START(0)) mipi_csis_queue_event_sof(csis); spin_unlock_irqrestore(&csis->slock, flags); @@ -843,7 +890,7 @@ static void mipi_csis_clear_counters(struct mipi_csis_device *csis) static void mipi_csis_log_counters(struct mipi_csis_device *csis, bool non_errors) { unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS - : MIPI_CSIS_NUM_EVENTS - 8; + : MIPI_CSIS_NUM_ERROR_EVENTS; unsigned int counters[MIPI_CSIS_NUM_EVENTS]; unsigned long flags; unsigned int i; @@ -854,45 +901,67 @@ static void mipi_csis_log_counters(struct mipi_csis_device *csis, bool non_error spin_unlock_irqrestore(&csis->slock, flags); for (i = 0; i < num_events; ++i) { + const struct mipi_csis_event *event = &csis->events[i]; + + if (event->channel >= csis->num_channels) + continue; + if (counters[i] > 0 || csis->debug.enable) dev_info(csis->dev, "%s events: %d\n", - csis->events[i].name, - counters[i]); + event->name, counters[i]); } } +struct mipi_csis_reg_info { + u32 addr; + unsigned int offset; + const char * const name; +}; + +static void mipi_csis_dump_channel_reg(struct mipi_csis_device *csis, + const struct mipi_csis_reg_info *reg, + unsigned int channel) +{ + dev_info(csis->dev, "%16s%u: 0x%08x\n", reg->name, channel, + mipi_csis_read(csis, reg->addr + channel * reg->offset)); +} + static int mipi_csis_dump_regs(struct mipi_csis_device *csis) { - static const struct { - u32 offset; - const char * const name; - } registers[] = { - { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" }, - { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" }, - { MIPI_CSIS_INT_MSK, "INT_MSK" }, - { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" }, - { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" }, - { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" }, - { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" }, - { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" }, - { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" }, - { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" }, - { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" }, - { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" }, - { MIPI_CSIS_FRAME_COUNTER_CH(0), "FRAME_COUNTER_CH0" }, + static const struct mipi_csis_reg_info common_registers[] = { + { MIPI_CSIS_CMN_CTRL, 0, "CMN_CTRL" }, + { MIPI_CSIS_CLK_CTRL, 0, "CLK_CTRL" }, + { MIPI_CSIS_INT_MSK, 0, "INT_MSK" }, + { MIPI_CSIS_DPHY_STATUS, 0, "DPHY_STATUS" }, + { MIPI_CSIS_DPHY_CMN_CTRL, 0, "DPHY_CMN_CTRL" }, + { MIPI_CSIS_DPHY_SCTRL_L, 0, "DPHY_SCTRL_L" }, + { MIPI_CSIS_DPHY_SCTRL_H, 0, "DPHY_SCTRL_H" }, + { MIPI_CSIS_DBG_CTRL, 0, "DBG_CTRL" }, + }; + static const struct mipi_csis_reg_info channel_registers[] = { + { MIPI_CSIS_ISP_CONFIG_CH(0), 0x10, "ISP_CONFIG_CH" }, + { MIPI_CSIS_ISP_RESOL_CH(0), 0x10, "ISP_RESOL_CH" }, + { MIPI_CSIS_SDW_CONFIG_CH(0), 0x10, "SDW_CONFIG_CH" }, + { MIPI_CSIS_SDW_RESOL_CH(0), 0x10, "SDW_RESOL_CH" }, + { MIPI_CSIS_FRAME_COUNTER_CH(0), 4, "FRAME_COUNTER_CH" }, }; - - unsigned int i; - u32 cfg; if (!pm_runtime_get_if_in_use(csis->dev)) return 0; dev_info(csis->dev, "--- REGISTERS ---\n"); - for (i = 0; i < ARRAY_SIZE(registers); i++) { - cfg = mipi_csis_read(csis, registers[i].offset); - dev_info(csis->dev, "%14s: 0x%08x\n", registers[i].name, cfg); + for (unsigned int i = 0; i < ARRAY_SIZE(common_registers); i++) { + const struct mipi_csis_reg_info *reg = &common_registers[i]; + + dev_info(csis->dev, "%17s: 0x%08x\n", reg->name, + mipi_csis_read(csis, reg->addr)); + } + + for (unsigned int chan = 0; chan < csis->num_channels; chan++) { + for (unsigned int i = 0; i < ARRAY_SIZE(channel_registers); ++i) + mipi_csis_dump_channel_reg(csis, &channel_registers[i], + chan); } pm_runtime_put(csis->dev); @@ -965,6 +1034,12 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) format = v4l2_subdev_state_get_format(state, CSIS_PAD_SINK); csis_fmt = find_csis_format(format->code); + ret = v4l2_get_active_data_lanes(csis->source.pad, csis->bus.num_data_lanes); + if (ret < 0) + goto err_unlock; + + csis->num_data_lanes = ret; + ret = mipi_csis_calculate_params(csis, csis_fmt); if (ret < 0) goto err_unlock; @@ -998,7 +1073,7 @@ err_unlock: } static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_mbus_code_enum *code) { /* @@ -1011,7 +1086,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - fmt = v4l2_subdev_state_get_format(sd_state, code->pad); + fmt = v4l2_subdev_state_get_format(state, code->pad); code->code = fmt->code; return 0; } @@ -1028,10 +1103,10 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, } static int mipi_csis_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_state *state, struct v4l2_subdev_format *sdformat) { - struct csis_pix_format const *csis_fmt; + const struct csis_pix_format *csis_fmt; struct v4l2_mbus_framefmt *fmt; unsigned int align; @@ -1040,7 +1115,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, * modified. */ if (sdformat->pad == CSIS_PAD_SOURCE) - return v4l2_subdev_get_fmt(sd, sd_state, sdformat); + return v4l2_subdev_get_fmt(sd, state, sdformat); if (sdformat->pad != CSIS_PAD_SINK) return -EINVAL; @@ -1078,7 +1153,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, &sdformat->format.height, 1, CSIS_MAX_PIX_HEIGHT, 0, 0); - fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad); + fmt = v4l2_subdev_state_get_format(state, sdformat->pad); fmt->code = csis_fmt->code; fmt->width = sdformat->format.width; @@ -1092,7 +1167,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, sdformat->format = *fmt; /* Propagate the format from sink to source. */ - fmt = v4l2_subdev_state_get_format(sd_state, CSIS_PAD_SOURCE); + fmt = v4l2_subdev_state_get_format(state, CSIS_PAD_SOURCE); *fmt = sdformat->format; /* The format on the source pad might change due to unpacking. */ @@ -1132,7 +1207,7 @@ static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, } static int mipi_csis_init_state(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) + struct v4l2_subdev_state *state) { struct v4l2_subdev_format fmt = { .pad = CSIS_PAD_SINK, @@ -1149,7 +1224,7 @@ static int mipi_csis_init_state(struct v4l2_subdev *sd, V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt.format.colorspace, fmt.format.ycbcr_enc); - return mipi_csis_set_fmt(sd, sd_state, &fmt); + return mipi_csis_set_fmt(sd, state, &fmt); } static int mipi_csis_log_status(struct v4l2_subdev *sd) @@ -1299,8 +1374,9 @@ static int mipi_csis_async_register(struct mipi_csis_device *csis) } csis->bus = vep.bus.mipi_csi2; + csis->num_data_lanes = csis->bus.num_data_lanes; - dev_dbg(csis->dev, "data lanes: %d\n", csis->bus.num_data_lanes); + dev_dbg(csis->dev, "max data lanes: %d\n", csis->bus.num_data_lanes); dev_dbg(csis->dev, "flags: 0x%08x\n", csis->bus.flags); asd = v4l2_async_nf_add_fwnode_remote(&csis->notifier, ep, @@ -1413,9 +1489,14 @@ static int mipi_csis_parse_dt(struct mipi_csis_device *csis) { struct device_node *node = csis->dev->of_node; - if (of_property_read_u32(node, "clock-frequency", - &csis->clk_frequency)) - csis->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + of_property_read_u32(node, "clock-frequency", &csis->clk_frequency); + dev_dbg(csis->dev, "clock frequency: %u\n", csis->clk_frequency); + + csis->num_channels = 1; + of_property_read_u32(node, "fsl,num-channels", &csis->num_channels); + if (csis->num_channels < 1 || csis->num_channels > MIPI_CSIS_MAX_CHANNELS) + return dev_err_probe(csis->dev, -EINVAL, + "Invalid fsl,num-channels value\n"); return 0; } @@ -1440,10 +1521,8 @@ static int mipi_csis_probe(struct platform_device *pdev) /* Parse DT properties. */ ret = mipi_csis_parse_dt(csis); - if (ret < 0) { - dev_err(dev, "Failed to parse device tree: %d\n", ret); + if (ret < 0) return ret; - } /* Acquire resources. */ csis->regs = devm_platform_ioremap_resource(pdev, 0); @@ -1497,9 +1576,6 @@ static int mipi_csis_probe(struct platform_device *pdev) goto err_unregister_all; } - dev_info(dev, "lanes: %d, freq: %u\n", - csis->bus.num_data_lanes, csis->clk_frequency); - return 0; err_unregister_all: @@ -1565,4 +1641,3 @@ module_platform_driver(mipi_csis_driver); MODULE_DESCRIPTION("i.MX7 & i.MX8 MIPI CSI-2 receiver driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:imx-mipi-csi2"); diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c index 7f8ffbac582f..3f9a67a6bd4d 100644 --- a/drivers/media/platform/nxp/imx-pxp.c +++ b/drivers/media/platform/nxp/imx-pxp.c @@ -248,7 +248,7 @@ struct pxp_ctx { static inline struct pxp_ctx *file2ctx(struct file *file) { - return container_of(file->private_data, struct pxp_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct pxp_ctx, fh); } static struct pxp_q_data *get_q_data(struct pxp_ctx *ctx, @@ -1180,13 +1180,8 @@ static int pxp_enum_fmt_vid_out(struct file *file, void *priv, static int pxp_g_fmt(struct pxp_ctx *ctx, struct v4l2_format *f) { - struct vb2_queue *vq; struct pxp_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - q_data = get_q_data(ctx, f->type); f->fmt.pix.width = q_data->width; @@ -1329,8 +1324,6 @@ static int pxp_s_fmt(struct pxp_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; q_data = get_q_data(ctx, f->type); if (!q_data) @@ -1660,7 +1653,6 @@ static int pxp_open(struct file *file) } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 4); @@ -1699,7 +1691,7 @@ static int pxp_open(struct file *file) goto open_unlock; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); atomic_inc(&dev->num_inst); dprintk(dev, "Created instance: %p, m2m_ctx: %p\n", @@ -1717,7 +1709,7 @@ static int pxp_release(struct file *file) dprintk(dev, "Releasing instance %p\n", ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(&dev->dev_mutex); diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c index 34a92642bbfe..933a5f39f9f4 100644 --- a/drivers/media/platform/nxp/imx7-media-csi.c +++ b/drivers/media/platform/nxp/imx7-media-csi.c @@ -2290,4 +2290,3 @@ module_platform_driver(imx7_csi_driver); MODULE_DESCRIPTION("i.MX7 CSI subdev driver"); MODULE_AUTHOR("Rui Miguel Silva <rui.silva@linaro.org>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform: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 981648a03113..c3d411ddf492 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -314,6 +314,28 @@ static const struct mxc_isi_plat_data mxc_imx8mp_data = { .has_36bit_dma = true, }; +static const struct mxc_isi_plat_data mxc_imx8qm_data = { + .model = MXC_ISI_IMX8QM, + .num_ports = 5, + .num_channels = 8, + .reg_offset = 0x10000, + .ier_reg = &mxc_imx8_isi_ier_qm, + .set_thd = &mxc_imx8_isi_thd_v1, + .buf_active_reverse = true, + .has_36bit_dma = false, +}; + +static const struct mxc_isi_plat_data mxc_imx8qxp_data = { + .model = MXC_ISI_IMX8QXP, + .num_ports = 5, + .num_channels = 6, + .reg_offset = 0x10000, + .ier_reg = &mxc_imx8_isi_ier_v2, + .set_thd = &mxc_imx8_isi_thd_v1, + .buf_active_reverse = true, + .has_36bit_dma = false, +}; + static const struct mxc_isi_plat_data mxc_imx8ulp_data = { .model = MXC_ISI_IMX8ULP, .num_ports = 1, @@ -325,37 +347,26 @@ static const struct mxc_isi_plat_data mxc_imx8ulp_data = { .has_36bit_dma = false, }; -static const struct mxc_isi_plat_data mxc_imx93_data = { - .model = MXC_ISI_IMX93, +static const struct mxc_isi_plat_data mxc_imx91_data = { + .model = MXC_ISI_IMX91, .num_ports = 1, .num_channels = 1, .reg_offset = 0, .ier_reg = &mxc_imx8_isi_ier_v2, .set_thd = &mxc_imx8_isi_thd_v1, .buf_active_reverse = true, - .gasket_ops = &mxc_imx93_gasket_ops, .has_36bit_dma = false, }; -static const struct mxc_isi_plat_data mxc_imx8qm_data = { - .model = MXC_ISI_IMX8QM, - .num_ports = 5, - .num_channels = 8, - .reg_offset = 0x10000, - .ier_reg = &mxc_imx8_isi_ier_qm, - .set_thd = &mxc_imx8_isi_thd_v1, - .buf_active_reverse = true, - .has_36bit_dma = false, -}; - -static const struct mxc_isi_plat_data mxc_imx8qxp_data = { - .model = MXC_ISI_IMX8QXP, - .num_ports = 5, - .num_channels = 6, - .reg_offset = 0x10000, +static const struct mxc_isi_plat_data mxc_imx93_data = { + .model = MXC_ISI_IMX93, + .num_ports = 1, + .num_channels = 1, + .reg_offset = 0, .ier_reg = &mxc_imx8_isi_ier_v2, .set_thd = &mxc_imx8_isi_thd_v1, .buf_active_reverse = true, + .gasket_ops = &mxc_imx93_gasket_ops, .has_36bit_dma = false, }; @@ -374,6 +385,8 @@ static int mxc_isi_pm_suspend(struct device *dev) mxc_isi_video_suspend(pipe); } + mxc_isi_m2m_suspend(&isi->m2m); + return pm_runtime_force_suspend(dev); } @@ -403,6 +416,12 @@ static int mxc_isi_pm_resume(struct device *dev) } } + ret = mxc_isi_m2m_resume(&isi->m2m); + if (ret) { + dev_err(dev, "Failed to resume ISI (%d) for m2m\n", ret); + err = ret; + } + return err; } @@ -539,6 +558,7 @@ static const struct of_device_id mxc_isi_of_match[] = { { .compatible = "fsl,imx8qm-isi", .data = &mxc_imx8qm_data }, { .compatible = "fsl,imx8qxp-isi", .data = &mxc_imx8qxp_data }, { .compatible = "fsl,imx8ulp-isi", .data = &mxc_imx8ulp_data }, + { .compatible = "fsl,imx91-isi", .data = &mxc_imx91_data }, { .compatible = "fsl,imx93-isi", .data = &mxc_imx93_data }, { /* sentinel */ }, }; diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h index 206995bedca4..3cbd35305af0 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h @@ -160,6 +160,7 @@ enum model { MXC_ISI_IMX8QM, MXC_ISI_IMX8QXP, MXC_ISI_IMX8ULP, + MXC_ISI_IMX91, MXC_ISI_IMX93, }; @@ -202,9 +203,8 @@ struct mxc_isi_video { struct video_device vdev; struct media_pad pad; - /* Protects is_streaming, and the vdev and vb2_q operations */ + /* Protects the vdev and vb2_q operations */ struct mutex lock; - bool is_streaming; struct v4l2_pix_format_mplane pix; const struct mxc_isi_format_info *fmtinfo; @@ -343,6 +343,8 @@ int mxc_isi_video_buffer_prepare(struct mxc_isi_dev *isi, struct vb2_buffer *vb2 #ifdef CONFIG_VIDEO_IMX8_ISI_M2M int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev); int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi); +void mxc_isi_m2m_suspend(struct mxc_isi_m2m *m2m); +int mxc_isi_m2m_resume(struct mxc_isi_m2m *m2m); #else static inline int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev) @@ -353,6 +355,13 @@ static inline int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi) { return 0; } +static inline void mxc_isi_m2m_suspend(struct mxc_isi_m2m *m2m) +{ +} +static inline int mxc_isi_m2m_resume(struct mxc_isi_m2m *m2m) +{ + return 0; +} #endif int mxc_isi_channel_acquire(struct mxc_isi_pipe *pipe, @@ -362,7 +371,7 @@ void mxc_isi_channel_get(struct mxc_isi_pipe *pipe); void mxc_isi_channel_put(struct mxc_isi_pipe *pipe); void mxc_isi_channel_enable(struct mxc_isi_pipe *pipe); void mxc_isi_channel_disable(struct mxc_isi_pipe *pipe); -int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe, bool bypass); +int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe); void mxc_isi_channel_unchain(struct mxc_isi_pipe *pipe); void mxc_isi_channel_config(struct mxc_isi_pipe *pipe, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-gasket.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-gasket.c index f69c3b5d4782..58ec7eddcd3d 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-gasket.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-gasket.c @@ -3,6 +3,8 @@ * Copyright 2019-2023 NXP */ +#include <linux/bitfield.h> +#include <linux/bits.h> #include <linux/regmap.h> #include <media/mipi-csi2.h> @@ -16,8 +18,7 @@ #define GASKET_BASE(n) (0x0060 + (n) * 0x30) #define GASKET_CTRL 0x0000 -#define GASKET_CTRL_DATA_TYPE(dt) ((dt) << 8) -#define GASKET_CTRL_DATA_TYPE_MASK (0x3f << 8) +#define GASKET_CTRL_DATA_TYPE(dt) FIELD_PREP(GENMASK(13, 8), dt) #define GASKET_CTRL_DUAL_COMP_ENABLE BIT(1) #define GASKET_CTRL_ENABLE BIT(0) @@ -57,9 +58,10 @@ const struct mxc_gasket_ops mxc_imx8_gasket_ops = { * i.MX93 gasket */ -#define DISP_MIX_CAMERA_MUX 0x30 -#define DISP_MIX_CAMERA_MUX_DATA_TYPE(x) (((x) & 0x3f) << 3) -#define DISP_MIX_CAMERA_MUX_GASKET_ENABLE BIT(16) +#define DISP_MIX_CAMERA_MUX 0x30 +#define DISP_MIX_CAMERA_MUX_DATA_TYPE(x) FIELD_PREP(GENMASK(8, 3), x) +#define DISP_MIX_CAMERA_MUX_GASKET_ENABLE BIT(16) +#define DISP_MIX_CAMERA_MUX_GASKET_SOURCE_TYPE BIT(17) static void mxc_imx93_gasket_enable(struct mxc_isi_dev *isi, const struct v4l2_mbus_frame_desc *fd, @@ -70,6 +72,16 @@ static void mxc_imx93_gasket_enable(struct mxc_isi_dev *isi, val = DISP_MIX_CAMERA_MUX_DATA_TYPE(fd->entry[0].bus.csi2.dt); val |= DISP_MIX_CAMERA_MUX_GASKET_ENABLE; + + /* + * CAMERA MUX + * - [17]: Selects source input to gasket + * 0: Data from MIPI CSI + * 1: Data from parallel camera + */ + if (fd->type == V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL) + val |= DISP_MIX_CAMERA_MUX_GASKET_SOURCE_TYPE; + regmap_write(isi->gasket, DISP_MIX_CAMERA_MUX, val); } diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c index 5623914f95e6..9225a7ac1c3e 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c @@ -587,7 +587,7 @@ void mxc_isi_channel_release(struct mxc_isi_pipe *pipe) * * TODO: Support secondary line buffer for downscaling YUV420 images. */ -int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe, bool bypass) +int mxc_isi_channel_chain(struct mxc_isi_pipe *pipe) { /* Channel chaining requires both line and output buffer. */ const u8 resources = MXC_ISI_CHANNEL_RES_OUTPUT_BUF 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 22e49d3a1287..f425ac786854 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c @@ -43,7 +43,6 @@ struct mxc_isi_m2m_ctx_queue_data { struct v4l2_pix_format_mplane format; const struct mxc_isi_format_info *info; u32 sequence; - bool streaming; }; struct mxc_isi_m2m_ctx { @@ -74,9 +73,9 @@ to_isi_m2m_buffer(struct vb2_v4l2_buffer *buf) return container_of(buf, struct mxc_isi_m2m_buffer, buf.vb); } -static inline struct mxc_isi_m2m_ctx *to_isi_m2m_ctx(struct v4l2_fh *fh) +static inline struct mxc_isi_m2m_ctx *file_to_isi_m2m_ctx(struct file *filp) { - return container_of(fh, struct mxc_isi_m2m_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct mxc_isi_m2m_ctx, fh); } static inline struct mxc_isi_m2m_ctx_queue_data * @@ -108,7 +107,7 @@ static void mxc_isi_m2m_frame_write_done(struct mxc_isi_pipe *pipe, u32 status) src_vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); dst_vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, false); + v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf); src_vbuf->sequence = ctx->queues.out.sequence++; dst_vbuf->sequence = ctx->queues.cap.sequence++; @@ -236,6 +235,70 @@ static void mxc_isi_m2m_vb2_buffer_queue(struct vb2_buffer *vb2) v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } +static int mxc_isi_m2m_vb2_prepare_streaming(struct vb2_queue *q) +{ + struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q); + const struct v4l2_pix_format_mplane *out_pix = &ctx->queues.out.format; + const struct v4l2_pix_format_mplane *cap_pix = &ctx->queues.cap.format; + const struct mxc_isi_format_info *cap_info = ctx->queues.cap.info; + const struct mxc_isi_format_info *out_info = ctx->queues.out.info; + struct mxc_isi_m2m *m2m = ctx->m2m; + int ret; + + guard(mutex)(&m2m->lock); + + if (m2m->usage_count == INT_MAX) + return -EOVERFLOW; + + ret = pm_runtime_resume_and_get(m2m->isi->dev); + if (ret) + return ret; + + /* + * Acquire the pipe and initialize the channel with the first user of + * the M2M device. + */ + if (m2m->usage_count == 0) { + bool bypass = cap_pix->width == out_pix->width && + cap_pix->height == out_pix->height && + cap_info->encoding == out_info->encoding; + + ret = mxc_isi_channel_acquire(m2m->pipe, + &mxc_isi_m2m_frame_write_done, + bypass); + if (ret) + goto err_pm; + + mxc_isi_channel_get(m2m->pipe); + } + + m2m->usage_count++; + + /* + * Allocate resources for the channel, counting how many users require + * buffer chaining. + */ + if (!ctx->chained && out_pix->width > MXC_ISI_MAX_WIDTH_UNCHAINED) { + ret = mxc_isi_channel_chain(m2m->pipe); + if (ret) + goto err_deinit; + + m2m->chained_count++; + ctx->chained = true; + } + + return 0; + +err_deinit: + if (--m2m->usage_count == 0) { + mxc_isi_channel_put(m2m->pipe); + mxc_isi_channel_release(m2m->pipe); + } +err_pm: + pm_runtime_put(m2m->isi->dev); + return ret; +} + static int mxc_isi_m2m_vb2_start_streaming(struct vb2_queue *q, unsigned int count) { @@ -265,13 +328,46 @@ static void mxc_isi_m2m_vb2_stop_streaming(struct vb2_queue *q) } } +static void mxc_isi_m2m_vb2_unprepare_streaming(struct vb2_queue *q) +{ + struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q); + struct mxc_isi_m2m *m2m = ctx->m2m; + + guard(mutex)(&m2m->lock); + + /* + * If the last context is this one, reset it to make sure the device + * will be reconfigured when streaming is restarted. + */ + if (m2m->last_ctx == ctx) + m2m->last_ctx = NULL; + + /* Free the channel resources if this is the last chained context. */ + if (ctx->chained && --m2m->chained_count == 0) + mxc_isi_channel_unchain(m2m->pipe); + ctx->chained = false; + + /* Turn off the light with the last user. */ + if (--m2m->usage_count == 0) { + mxc_isi_channel_disable(m2m->pipe); + mxc_isi_channel_put(m2m->pipe); + mxc_isi_channel_release(m2m->pipe); + } + + WARN_ON(m2m->usage_count < 0); + + pm_runtime_put(m2m->isi->dev); +} + static const struct vb2_ops mxc_isi_m2m_vb2_qops = { .queue_setup = mxc_isi_m2m_vb2_queue_setup, .buf_init = mxc_isi_m2m_vb2_buffer_init, .buf_prepare = mxc_isi_m2m_vb2_buffer_prepare, .buf_queue = mxc_isi_m2m_vb2_buffer_queue, + .prepare_streaming = mxc_isi_m2m_vb2_prepare_streaming, .start_streaming = mxc_isi_m2m_vb2_start_streaming, .stop_streaming = mxc_isi_m2m_vb2_stop_streaming, + .unprepare_streaming = mxc_isi_m2m_vb2_unprepare_streaming, }; static int mxc_isi_m2m_queue_init(void *priv, struct vb2_queue *src_vq, @@ -427,7 +523,7 @@ static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh, const enum mxc_isi_video_type type = f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP; - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); __mxc_isi_m2m_try_fmt_vid(ctx, &f->fmt.pix_mp, type); @@ -437,7 +533,7 @@ static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh, static int mxc_isi_m2m_g_fmt_vid(struct file *file, void *fh, struct v4l2_format *f) { - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); const struct mxc_isi_m2m_ctx_queue_data *qdata = mxc_isi_m2m_ctx_qdata(ctx, f->type); @@ -452,14 +548,12 @@ static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh, const enum mxc_isi_video_type type = f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP; - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; const struct mxc_isi_format_info *info; struct vb2_queue *vq; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; if (vb2_is_busy(vq)) return -EBUSY; @@ -481,136 +575,6 @@ static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh, return 0; } -static int mxc_isi_m2m_streamon(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); - struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type); - const struct v4l2_pix_format_mplane *out_pix = &ctx->queues.out.format; - const struct v4l2_pix_format_mplane *cap_pix = &ctx->queues.cap.format; - const struct mxc_isi_format_info *cap_info = ctx->queues.cap.info; - const struct mxc_isi_format_info *out_info = ctx->queues.out.info; - struct mxc_isi_m2m *m2m = ctx->m2m; - bool bypass; - int ret; - - if (q->streaming) - return 0; - - mutex_lock(&m2m->lock); - - if (m2m->usage_count == INT_MAX) { - ret = -EOVERFLOW; - goto unlock; - } - - bypass = cap_pix->width == out_pix->width && - cap_pix->height == out_pix->height && - cap_info->encoding == out_info->encoding; - - /* - * Acquire the pipe and initialize the channel with the first user of - * the M2M device. - */ - if (m2m->usage_count == 0) { - ret = mxc_isi_channel_acquire(m2m->pipe, - &mxc_isi_m2m_frame_write_done, - bypass); - if (ret) - goto unlock; - - mxc_isi_channel_get(m2m->pipe); - } - - m2m->usage_count++; - - /* - * Allocate resources for the channel, counting how many users require - * buffer chaining. - */ - if (!ctx->chained && out_pix->width > MXC_ISI_MAX_WIDTH_UNCHAINED) { - ret = mxc_isi_channel_chain(m2m->pipe, bypass); - if (ret) - goto deinit; - - m2m->chained_count++; - ctx->chained = true; - } - - /* - * Drop the lock to start the stream, as the .device_run() operation - * needs to acquire it. - */ - mutex_unlock(&m2m->lock); - ret = v4l2_m2m_ioctl_streamon(file, fh, type); - if (ret) { - /* Reacquire the lock for the cleanup path. */ - mutex_lock(&m2m->lock); - goto unchain; - } - - q->streaming = true; - - return 0; - -unchain: - if (ctx->chained && --m2m->chained_count == 0) - mxc_isi_channel_unchain(m2m->pipe); - ctx->chained = false; - -deinit: - if (--m2m->usage_count == 0) { - mxc_isi_channel_put(m2m->pipe); - mxc_isi_channel_release(m2m->pipe); - } - -unlock: - mutex_unlock(&m2m->lock); - return ret; -} - -static int mxc_isi_m2m_streamoff(struct file *file, void *fh, - enum v4l2_buf_type type) -{ - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh); - struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type); - struct mxc_isi_m2m *m2m = ctx->m2m; - - v4l2_m2m_ioctl_streamoff(file, fh, type); - - if (!q->streaming) - return 0; - - mutex_lock(&m2m->lock); - - /* - * If the last context is this one, reset it to make sure the device - * will be reconfigured when streaming is restarted. - */ - if (m2m->last_ctx == ctx) - m2m->last_ctx = NULL; - - /* Free the channel resources if this is the last chained context. */ - if (ctx->chained && --m2m->chained_count == 0) - mxc_isi_channel_unchain(m2m->pipe); - ctx->chained = false; - - /* Turn off the light with the last user. */ - if (--m2m->usage_count == 0) { - mxc_isi_channel_disable(m2m->pipe); - mxc_isi_channel_put(m2m->pipe); - mxc_isi_channel_release(m2m->pipe); - } - - WARN_ON(m2m->usage_count < 0); - - mutex_unlock(&m2m->lock); - - q->streaming = false; - - return 0; -} - static const struct v4l2_ioctl_ops mxc_isi_m2m_ioctl_ops = { .vidioc_querycap = mxc_isi_m2m_querycap, @@ -631,8 +595,8 @@ static const struct v4l2_ioctl_ops mxc_isi_m2m_ioctl_ops = { .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_streamon = mxc_isi_m2m_streamon, - .vidioc_streamoff = mxc_isi_m2m_streamoff, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, @@ -668,7 +632,6 @@ static int mxc_isi_m2m_open(struct file *file) mutex_init(&ctx->vb2_lock); v4l2_fh_init(&ctx->fh, vdev); - file->private_data = &ctx->fh; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(m2m->m2m_dev, ctx, &mxc_isi_m2m_queue_init); @@ -685,16 +648,10 @@ static int mxc_isi_m2m_open(struct file *file) if (ret) goto err_ctx; - ret = pm_runtime_resume_and_get(m2m->isi->dev); - if (ret) - goto err_ctrls; - - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); return 0; -err_ctrls: - mxc_isi_m2m_ctx_ctrls_delete(ctx); err_ctx: v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); err_fh: @@ -706,20 +663,17 @@ err_fh: static int mxc_isi_m2m_release(struct file *file) { - struct mxc_isi_m2m *m2m = video_drvdata(file); - struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(file->private_data); + struct mxc_isi_m2m_ctx *ctx = file_to_isi_m2m_ctx(file); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mxc_isi_m2m_ctx_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_destroy(&ctx->vb2_lock); kfree(ctx); - pm_runtime_put(m2m->isi->dev); - return 0; } @@ -733,6 +687,40 @@ static const struct v4l2_file_operations mxc_isi_m2m_fops = { }; /* ----------------------------------------------------------------------------- + * Suspend & resume + */ + +void mxc_isi_m2m_suspend(struct mxc_isi_m2m *m2m) +{ + if (m2m->usage_count == 0) + return; + + v4l2_m2m_suspend(m2m->m2m_dev); + + if (m2m->chained_count > 0) + mxc_isi_channel_unchain(m2m->pipe); + + mxc_isi_channel_disable(m2m->pipe); + mxc_isi_channel_put(m2m->pipe); +} + +int mxc_isi_m2m_resume(struct mxc_isi_m2m *m2m) +{ + if (m2m->usage_count == 0) + return 0; + + mxc_isi_channel_get(m2m->pipe); + + if (m2m->chained_count > 0) + mxc_isi_channel_chain(m2m->pipe); + + m2m->last_ctx = NULL; + v4l2_m2m_resume(m2m->m2m_dev); + + return 0; +} + +/* ----------------------------------------------------------------------------- * Registration */ diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c index d76eb58deb09..a41c51dd9ce0 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c @@ -855,7 +855,7 @@ int mxc_isi_pipe_acquire(struct mxc_isi_pipe *pipe, /* Chain the channel if needed for wide resolutions. */ if (sink_fmt->width > MXC_ISI_MAX_WIDTH_UNCHAINED) { - ret = mxc_isi_channel_chain(pipe, bypass); + ret = mxc_isi_channel_chain(pipe); if (ret) mxc_isi_channel_release(pipe); } 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 8654150728a8..13682bf6e9f8 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c @@ -937,6 +937,47 @@ static void mxc_isi_video_init_channel(struct mxc_isi_video *video) mxc_isi_channel_set_output_format(pipe, video->fmtinfo, &video->pix); } +static int mxc_isi_vb2_prepare_streaming(struct vb2_queue *q) +{ + struct mxc_isi_video *video = vb2_get_drv_priv(q); + struct media_device *mdev = &video->pipe->isi->media_dev; + struct media_pipeline *pipe; + int ret; + + /* Get a pipeline for the video node and start it. */ + scoped_guard(mutex, &mdev->graph_mutex) { + ret = mxc_isi_pipe_acquire(video->pipe, + &mxc_isi_video_frame_write_done); + if (ret) + return ret; + + pipe = media_entity_pipeline(&video->vdev.entity) + ? : &video->pipe->pipe; + + ret = __video_device_pipeline_start(&video->vdev, pipe); + if (ret) + goto err_release; + } + + /* Verify that the video format matches the output of the subdev. */ + ret = mxc_isi_video_validate_format(video); + if (ret) + goto err_stop; + + /* Allocate buffers for discard operation. */ + ret = mxc_isi_video_alloc_discard_buffers(video); + if (ret) + goto err_stop; + + return 0; + +err_stop: + video_device_pipeline_stop(&video->vdev); +err_release: + mxc_isi_pipe_release(video->pipe); + return ret; +} + static int mxc_isi_vb2_start_streaming(struct vb2_queue *q, unsigned int count) { struct mxc_isi_video *video = vb2_get_drv_priv(q); @@ -985,13 +1026,24 @@ static void mxc_isi_vb2_stop_streaming(struct vb2_queue *q) mxc_isi_video_return_buffers(video, VB2_BUF_STATE_ERROR); } +static void mxc_isi_vb2_unprepare_streaming(struct vb2_queue *q) +{ + struct mxc_isi_video *video = vb2_get_drv_priv(q); + + mxc_isi_video_free_discard_buffers(video); + video_device_pipeline_stop(&video->vdev); + mxc_isi_pipe_release(video->pipe); +} + static const struct vb2_ops mxc_isi_vb2_qops = { .queue_setup = mxc_isi_vb2_queue_setup, .buf_init = mxc_isi_vb2_buffer_init, .buf_prepare = mxc_isi_vb2_buffer_prepare, .buf_queue = mxc_isi_vb2_buffer_queue, + .prepare_streaming = mxc_isi_vb2_prepare_streaming, .start_streaming = mxc_isi_vb2_start_streaming, .stop_streaming = mxc_isi_vb2_stop_streaming, + .unprepare_streaming = mxc_isi_vb2_unprepare_streaming, }; /* ----------------------------------------------------------------------------- @@ -1145,97 +1197,6 @@ static int mxc_isi_video_s_fmt(struct file *file, void *priv, return 0; } -static int mxc_isi_video_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct mxc_isi_video *video = video_drvdata(file); - struct media_device *mdev = &video->pipe->isi->media_dev; - struct media_pipeline *pipe; - int ret; - - if (vb2_queue_is_busy(&video->vb2_q, file)) - return -EBUSY; - - /* - * Get a pipeline for the video node and start it. This must be done - * here and not in the queue .start_streaming() handler, so that - * pipeline start errors can be reported from VIDIOC_STREAMON and not - * delayed until subsequent VIDIOC_QBUF calls. - */ - mutex_lock(&mdev->graph_mutex); - - ret = mxc_isi_pipe_acquire(video->pipe, &mxc_isi_video_frame_write_done); - if (ret) { - mutex_unlock(&mdev->graph_mutex); - return ret; - } - - pipe = media_entity_pipeline(&video->vdev.entity) ? : &video->pipe->pipe; - - ret = __video_device_pipeline_start(&video->vdev, pipe); - if (ret) { - mutex_unlock(&mdev->graph_mutex); - goto err_release; - } - - mutex_unlock(&mdev->graph_mutex); - - /* Verify that the video format matches the output of the subdev. */ - ret = mxc_isi_video_validate_format(video); - if (ret) - goto err_stop; - - /* Allocate buffers for discard operation. */ - ret = mxc_isi_video_alloc_discard_buffers(video); - if (ret) - goto err_stop; - - ret = vb2_streamon(&video->vb2_q, type); - if (ret) - goto err_free; - - video->is_streaming = true; - - return 0; - -err_free: - mxc_isi_video_free_discard_buffers(video); -err_stop: - video_device_pipeline_stop(&video->vdev); -err_release: - mxc_isi_pipe_release(video->pipe); - return ret; -} - -static void mxc_isi_video_cleanup_streaming(struct mxc_isi_video *video) -{ - lockdep_assert_held(&video->lock); - - if (!video->is_streaming) - return; - - mxc_isi_video_free_discard_buffers(video); - video_device_pipeline_stop(&video->vdev); - mxc_isi_pipe_release(video->pipe); - - video->is_streaming = false; -} - -static int mxc_isi_video_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct mxc_isi_video *video = video_drvdata(file); - int ret; - - ret = vb2_ioctl_streamoff(file, priv, type); - if (ret) - return ret; - - mxc_isi_video_cleanup_streaming(video); - - return 0; -} - static int mxc_isi_video_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { @@ -1291,9 +1252,8 @@ static const struct v4l2_ioctl_ops mxc_isi_video_ioctl_ops = { .vidioc_expbuf = vb2_ioctl_expbuf, .vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_create_bufs = vb2_ioctl_create_bufs, - - .vidioc_streamon = mxc_isi_video_streamon, - .vidioc_streamoff = mxc_isi_video_streamoff, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_enum_framesizes = mxc_isi_video_enum_framesizes, @@ -1332,10 +1292,6 @@ static int mxc_isi_video_release(struct file *file) if (ret) dev_err(video->pipe->isi->dev, "%s fail\n", __func__); - mutex_lock(&video->lock); - mxc_isi_video_cleanup_streaming(video); - mutex_unlock(&video->lock); - pm_runtime_put(video->pipe->isi->dev); return ret; } @@ -1357,7 +1313,7 @@ void mxc_isi_video_suspend(struct mxc_isi_pipe *pipe) { struct mxc_isi_video *video = &pipe->video; - if (!video->is_streaming) + if (!vb2_is_streaming(&video->vb2_q)) return; mxc_isi_pipe_disable(pipe); @@ -1388,7 +1344,7 @@ int mxc_isi_video_resume(struct mxc_isi_pipe *pipe) { struct mxc_isi_video *video = &pipe->video; - if (!video->is_streaming) + if (!vb2_is_streaming(&video->vb2_q)) return 0; mxc_isi_video_init_channel(video); diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c index 3a4645f59a44..371b4e81328c 100644 --- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c +++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c @@ -418,8 +418,8 @@ static int imx8mq_mipi_csi_calc_hs_settle(struct csi_state *state, src_pad = media_entity_remote_source_pad_unique(&sd_state->sd->entity); if (IS_ERR(src_pad)) { - dev_err(state->dev, "can't get source pad of %s (%ld)\n", - sd_state->sd->name, PTR_ERR(src_pad)); + dev_err(state->dev, "can't get source pad of %s (%pe)\n", + sd_state->sd->name, src_pad); return PTR_ERR(src_pad); } @@ -1114,4 +1114,3 @@ module_platform_driver(imx8mq_mipi_csi_driver); MODULE_DESCRIPTION("i.MX8MQ MIPI CSI-2 receiver driver"); MODULE_AUTHOR("Martin Kepplinger <martin.kepplinger@puri.sm>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:imx8mq-mipi-csi2"); diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c index 0c6cc120fd2a..02d57229b9b3 100644 --- a/drivers/media/platform/nxp/mx2_emmaprp.c +++ b/drivers/media/platform/nxp/mx2_emmaprp.c @@ -214,6 +214,11 @@ struct emmaprp_ctx { struct emmaprp_q_data q_data[2]; }; +static inline struct emmaprp_ctx *file_to_emmaprp_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct emmaprp_ctx, fh); +} + static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx, enum v4l2_buf_type type) { @@ -426,13 +431,8 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) { - struct vb2_queue *vq; struct emmaprp_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - q_data = get_q_data(ctx, f->type); f->fmt.pix.width = q_data->width; @@ -451,13 +451,13 @@ static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) static int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file_to_emmaprp_ctx(file), f); } static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - return vidioc_g_fmt(priv, f); + return vidioc_g_fmt(file_to_emmaprp_ctx(file), f); } static int vidioc_try_fmt(struct v4l2_format *f) @@ -497,8 +497,8 @@ static int vidioc_try_fmt(struct v4l2_format *f) static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { + struct emmaprp_ctx *ctx = file_to_emmaprp_ctx(file); struct emmaprp_fmt *fmt; - struct emmaprp_ctx *ctx = priv; fmt = find_format(f); if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) { @@ -514,8 +514,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { + struct emmaprp_ctx *ctx = file_to_emmaprp_ctx(file); struct emmaprp_fmt *fmt; - struct emmaprp_ctx *ctx = priv; fmt = find_format(f); if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) { @@ -535,8 +535,6 @@ static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f) int ret; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; q_data = get_q_data(ctx, f->type); if (!q_data) @@ -575,7 +573,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (ret) return ret; - return vidioc_s_fmt(priv, f); + return vidioc_s_fmt(file_to_emmaprp_ctx(file), f); } static int vidioc_s_fmt_vid_out(struct file *file, void *priv, @@ -587,7 +585,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, if (ret) return ret; - return vidioc_s_fmt(priv, f); + return vidioc_s_fmt(file_to_emmaprp_ctx(file), f); } static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { @@ -725,7 +723,6 @@ static int emmaprp_open(struct file *file) return -ENOMEM; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = pcdev; if (mutex_lock_interruptible(&pcdev->dev_mutex)) { @@ -747,7 +744,7 @@ static int emmaprp_open(struct file *file) clk_prepare_enable(pcdev->clk_emma_ahb); ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1]; ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); mutex_unlock(&pcdev->dev_mutex); dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); @@ -758,14 +755,14 @@ static int emmaprp_open(struct file *file) static int emmaprp_release(struct file *file) { struct emmaprp_dev *pcdev = video_drvdata(file); - struct emmaprp_ctx *ctx = file->private_data; + struct emmaprp_ctx *ctx = file_to_emmaprp_ctx(file); dprintk(pcdev, "Releasing instance %p\n", ctx); mutex_lock(&pcdev->dev_mutex); clk_disable_unprepare(pcdev->clk_emma_ahb); clk_disable_unprepare(pcdev->clk_emma_ipg); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(&pcdev->dev_mutex); diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile index d26a9c24a430..5e349b491513 100644 --- a/drivers/media/platform/qcom/camss/Makefile +++ b/drivers/media/platform/qcom/camss/Makefile @@ -6,9 +6,10 @@ qcom-camss-objs += \ camss-csid.o \ camss-csid-4-1.o \ camss-csid-4-7.o \ + camss-csid-340.o \ camss-csid-680.o \ camss-csid-gen2.o \ - camss-csid-780.o \ + camss-csid-gen3.o \ camss-csiphy-2ph-1-0.o \ camss-csiphy-3ph-1-0.o \ camss-csiphy.o \ @@ -17,10 +18,12 @@ qcom-camss-objs += \ camss-vfe-4-7.o \ camss-vfe-4-8.o \ camss-vfe-17x.o \ + camss-vfe-340.o \ camss-vfe-480.o \ camss-vfe-680.o \ - camss-vfe-780.o \ + camss-vfe-gen3.o \ camss-vfe-gen1.o \ + camss-vfe-vbif.o \ camss-vfe.o \ camss-video.o \ camss-format.o \ diff --git a/drivers/media/platform/qcom/camss/camss-csid-340.c b/drivers/media/platform/qcom/camss/camss-csid-340.c new file mode 100644 index 000000000000..22a30510fb79 --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-csid-340.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module 340 + * + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/completion.h> +#include <linux/bitfield.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> + +#include "camss.h" +#include "camss-csid.h" +#include "camss-csid-gen2.h" + +#define CSID_RST_STROBES (0x010) +#define CSID_RST_SW_REGS BIT(0) +#define CSID_RST_IRQ BIT(1) +#define CSID_RST_IFE_CLK BIT(2) +#define CSID_RST_PHY_CLK BIT(3) +#define CSID_RST_CSID_CLK BIT(4) + +#define CSID_IRQ_STATUS (0x070) +#define CSID_IRQ_MASK (0x074) +#define CSID_IRQ_MASK_RST_DONE BIT(0) +#define CSID_IRQ_CLEAR (0x078) +#define CSID_IRQ_CMD (0x080) +#define CSID_IRQ_CMD_CLEAR BIT(0) + +#define CSID_CSI2_RX_CFG0 (0x100) +#define CSI2_RX_CFG0_NUM_ACTIVE_LANES_MASK GENMASK(1, 0) +#define CSI2_RX_CFG0_DLX_INPUT_SEL_MASK GENMASK(17, 4) +#define CSI2_RX_CFG0_PHY_NUM_SEL_MASK GENMASK(21, 20) +#define CSI2_RX_CFG0_PHY_NUM_SEL_BASE_IDX 1 +#define CSI2_RX_CFG0_PHY_TYPE_SEL BIT(24) + +#define CSID_CSI2_RX_CFG1 (0x104) +#define CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN BIT(0) +#define CSI2_RX_CFG1_MISR_EN BIT(6) +#define CSI2_RX_CFG1_CGC_MODE BIT(7) + +#define CSID_RDI_CFG0(rdi) (0x300 + 0x100 * (rdi)) +#define CSID_RDI_CFG0_BYTE_CNTR_EN BIT(0) +#define CSID_RDI_CFG0_TIMESTAMP_EN BIT(1) +#define CSID_RDI_CFG0_DECODE_FORMAT_MASK GENMASK(15, 12) +#define CSID_RDI_CFG0_DECODE_FORMAT_NOP CSID_RDI_CFG0_DECODE_FORMAT_MASK +#define CSID_RDI_CFG0_DT_MASK GENMASK(21, 16) +#define CSID_RDI_CFG0_VC_MASK GENMASK(23, 22) +#define CSID_RDI_CFG0_DTID_MASK GENMASK(28, 27) +#define CSID_RDI_CFG0_ENABLE BIT(31) + +#define CSID_RDI_CTRL(rdi) (0x308 + 0x100 * (rdi)) +#define CSID_RDI_CTRL_HALT_AT_FRAME_BOUNDARY 0 +#define CSID_RDI_CTRL_RESUME_AT_FRAME_BOUNDARY 1 + +static void __csid_configure_rx(struct csid_device *csid, + struct csid_phy_config *phy, int vc) +{ + u32 val; + + val = FIELD_PREP(CSI2_RX_CFG0_NUM_ACTIVE_LANES_MASK, phy->lane_cnt - 1); + val |= FIELD_PREP(CSI2_RX_CFG0_DLX_INPUT_SEL_MASK, phy->lane_assign); + val |= FIELD_PREP(CSI2_RX_CFG0_PHY_NUM_SEL_MASK, + phy->csiphy_id + CSI2_RX_CFG0_PHY_NUM_SEL_BASE_IDX); + writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0); + + val = CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN; + writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); +} + +static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi) +{ + writel_relaxed(!!enable, csid->base + CSID_RDI_CTRL(rdi)); +} + +static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) +{ + struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, + csid->res->formats->nformats, + input_format->code); + u8 lane_cnt = csid->phy.lane_cnt; + u8 dt_id; + u32 val; + + if (!lane_cnt) + lane_cnt = 4; + + /* + * DT_ID is a two bit bitfield that is concatenated with + * the four least significant bits of the five bit VC + * bitfield to generate an internal CID value. + * + * CSID_RDI_CFG0(vc) + * DT_ID : 28:27 + * VC : 26:22 + * DT : 21:16 + * + * CID : VC 3:0 << 2 | DT_ID 1:0 + */ + dt_id = vc & 0x03; + + val = CSID_RDI_CFG0_DECODE_FORMAT_NOP; /* only for RDI path */ + val |= FIELD_PREP(CSID_RDI_CFG0_DT_MASK, format->data_type); + val |= FIELD_PREP(CSID_RDI_CFG0_VC_MASK, vc); + val |= FIELD_PREP(CSID_RDI_CFG0_DTID_MASK, dt_id); + + if (enable) + val |= CSID_RDI_CFG0_ENABLE; + + dev_dbg(csid->camss->dev, "CSID%u: Stream %s (dt:0x%x vc=%u)\n", + csid->id, enable ? "enable" : "disable", format->data_type, vc); + + writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); +} + +static void csid_configure_stream(struct csid_device *csid, u8 enable) +{ + int i; + + for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) { + if (csid->phy.en_vc & BIT(i)) { + __csid_configure_rdi_stream(csid, enable, i); + __csid_configure_rx(csid, &csid->phy, i); + __csid_ctrl_rdi(csid, enable, i); + } + } +} + +static int csid_reset(struct csid_device *csid) +{ + unsigned long time; + + writel_relaxed(CSID_IRQ_MASK_RST_DONE, csid->base + CSID_IRQ_MASK); + writel_relaxed(CSID_IRQ_MASK_RST_DONE, csid->base + CSID_IRQ_CLEAR); + writel_relaxed(CSID_IRQ_CMD_CLEAR, csid->base + CSID_IRQ_CMD); + + reinit_completion(&csid->reset_complete); + + /* Reset with registers preserved */ + writel(CSID_RST_IRQ | CSID_RST_IFE_CLK | CSID_RST_PHY_CLK | CSID_RST_CSID_CLK, + csid->base + CSID_RST_STROBES); + + time = wait_for_completion_timeout(&csid->reset_complete, + msecs_to_jiffies(CSID_RESET_TIMEOUT_MS)); + if (!time) { + dev_err(csid->camss->dev, "CSID%u: reset timeout\n", csid->id); + return -EIO; + } + + dev_dbg(csid->camss->dev, "CSID%u: reset done\n", csid->id); + + return 0; +} + +static irqreturn_t csid_isr(int irq, void *dev) +{ + struct csid_device *csid = dev; + u32 val; + + val = readl_relaxed(csid->base + CSID_IRQ_STATUS); + writel_relaxed(val, csid->base + CSID_IRQ_CLEAR); + writel_relaxed(CSID_IRQ_CMD_CLEAR, csid->base + CSID_IRQ_CMD); + + if (val & CSID_IRQ_MASK_RST_DONE) + complete(&csid->reset_complete); + else + dev_warn_ratelimited(csid->camss->dev, "Spurious CSID interrupt\n"); + + return IRQ_HANDLED; +} + +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val) +{ + return -EOPNOTSUPP; /* Not part of CSID */ +} + +static void csid_subdev_init(struct csid_device *csid) {} + +const struct csid_hw_ops csid_ops_340 = { + .configure_testgen_pattern = csid_configure_testgen_pattern, + .configure_stream = csid_configure_stream, + .hw_version = csid_hw_version, + .isr = csid_isr, + .reset = csid_reset, + .src_pad_code = csid_src_pad_code, + .subdev_init = csid_subdev_init, +}; diff --git a/drivers/media/platform/qcom/camss/camss-csid-780.c b/drivers/media/platform/qcom/camss/camss-csid-gen3.c index 4c720d177731..664245cf6eb0 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-780.c +++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.c @@ -13,7 +13,7 @@ #include "camss.h" #include "camss-csid.h" -#include "camss-csid-780.h" +#include "camss-csid-gen3.h" #define CSID_IO_PATH_CFG0(csid) (0x4 * (csid)) #define OUTPUT_IFE_EN 0x100 @@ -45,8 +45,12 @@ #define CSID_CSI2_RX_IRQ_CLEAR 0xA4 #define CSID_CSI2_RX_IRQ_SET 0xA8 +#define IS_CSID_690(csid) ((csid->camss->res->version == CAMSS_8775P) \ + || (csid->camss->res->version == CAMSS_8300)) #define CSID_BUF_DONE_IRQ_STATUS 0x8C -#define BUF_DONE_IRQ_STATUS_RDI_OFFSET (csid_is_lite(csid) ? 1 : 14) +#define BUF_DONE_IRQ_STATUS_RDI_OFFSET (csid_is_lite(csid) ?\ + 1 : (IS_CSID_690(csid) ?\ + 13 : 14)) #define CSID_BUF_DONE_IRQ_MASK 0x90 #define CSID_BUF_DONE_IRQ_CLEAR 0x94 #define CSID_BUF_DONE_IRQ_SET 0x98 @@ -59,6 +63,7 @@ #define CSID_CSI2_RX_CFG0 0x200 #define CSI2_RX_CFG0_NUM_ACTIVE_LANES 0 +#define CSI2_RX_CFG0_VC_MODE 3 #define CSI2_RX_CFG0_DL0_INPUT_SEL 4 #define CSI2_RX_CFG0_PHY_NUM_SEL 20 @@ -66,7 +71,9 @@ #define CSI2_RX_CFG1_ECC_CORRECTION_EN BIT(0) #define CSI2_RX_CFG1_VC_MODE BIT(2) -#define CSID_RDI_CFG0(rdi) (0x500 + 0x100 * (rdi)) +#define CSID_RDI_CFG0(rdi) (csid_is_lite(csid) && IS_CSID_690(csid) ?\ + (0x300 + 0x100 * (rdi)) :\ + (0x500 + 0x100 * (rdi))) #define RDI_CFG0_TIMESTAMP_EN BIT(6) #define RDI_CFG0_TIMESTAMP_STB_SEL BIT(8) #define RDI_CFG0_DECODE_FORMAT 12 @@ -75,10 +82,14 @@ #define RDI_CFG0_DT_ID 27 #define RDI_CFG0_EN BIT(31) -#define CSID_RDI_CTRL(rdi) (0x504 + 0x100 * (rdi)) +#define CSID_RDI_CTRL(rdi) (csid_is_lite(csid) && IS_CSID_690(csid) ?\ + (0x304 + 0x100 * (rdi)) :\ + (0x504 + 0x100 * (rdi))) #define RDI_CTRL_START_CMD BIT(0) -#define CSID_RDI_CFG1(rdi) (0x510 + 0x100 * (rdi)) +#define CSID_RDI_CFG1(rdi) (csid_is_lite(csid) && IS_CSID_690(csid) ?\ + (0x310 + 0x100 * (rdi)) :\ + (0x510 + 0x100 * (rdi))) #define RDI_CFG1_DROP_H_EN BIT(5) #define RDI_CFG1_DROP_V_EN BIT(6) #define RDI_CFG1_CROP_H_EN BIT(7) @@ -86,9 +97,12 @@ #define RDI_CFG1_PIX_STORE BIT(10) #define RDI_CFG1_PACKING_FORMAT_MIPI BIT(15) -#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) (0x548 + 0x100 * (rdi)) -#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) (0x54C + 0x100 * (rdi)) - +#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) (csid_is_lite(csid) && IS_CSID_690(csid) ?\ + (0x348 + 0x100 * (rdi)) :\ + (0x548 + 0x100 * (rdi))) +#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) (csid_is_lite(csid) && IS_CSID_690(csid) ?\ + (0x34C + 0x100 * (rdi)) :\ + (0x54C + 0x100 * (rdi))) #define CSI2_RX_CFG0_PHY_SEL_BASE_IDX 1 static void __csid_configure_rx(struct csid_device *csid, @@ -259,7 +273,7 @@ static irqreturn_t csid_isr(int irq, void *dev) if (buf_done_val & BIT(BUF_DONE_IRQ_STATUS_RDI_OFFSET + i)) { /* - * For Titan 780, bus done and RUP IRQ have been moved to + * For Titan Gen3, bus done and RUP IRQ have been moved to * CSID from VFE. Once CSID received bus done, need notify * VFE of this event. Trigger VFE to handle bus done process. */ @@ -325,7 +339,7 @@ static void csid_subdev_init(struct csid_device *csid) csid->testgen.nmodes = CSID_PAYLOAD_MODE_DISABLED; } -const struct csid_hw_ops csid_ops_780 = { +const struct csid_hw_ops csid_ops_gen3 = { .configure_stream = csid_configure_stream, .configure_testgen_pattern = csid_configure_testgen_pattern, .hw_version = csid_hw_version, diff --git a/drivers/media/platform/qcom/camss/camss-csid-780.h b/drivers/media/platform/qcom/camss/camss-csid-gen3.h index a990c66a60ff..6ee62da770c1 100644 --- a/drivers/media/platform/qcom/camss/camss-csid-780.h +++ b/drivers/media/platform/qcom/camss/camss-csid-gen3.h @@ -1,13 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * camss-csid-780.h + * camss-csid-gen3.h * * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module Generation 3 * * Copyright (c) 2024 Qualcomm Technologies, Inc. */ -#ifndef __QC_MSM_CAMSS_CSID_780_H__ -#define __QC_MSM_CAMSS_CSID_780_H__ +#ifndef __QC_MSM_CAMSS_CSID_GEN3_H__ +#define __QC_MSM_CAMSS_CSID_GEN3_H__ #define DECODE_FORMAT_UNCOMPRESSED_8_BIT 0x1 #define DECODE_FORMAT_UNCOMPRESSED_10_BIT 0x2 @@ -22,4 +22,4 @@ #define PLAIN_FORMAT_PLAIN16 0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */ #define PLAIN_FORMAT_PLAIN32 0x2 /* supports UNCOMPRESSED_20_BIT */ -#endif /* __QC_MSM_CAMSS_CSID_780_H__ */ +#endif /* __QC_MSM_CAMSS_CSID_GEN3_H__ */ diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h index 9dc826d8c8f6..aedc96ed84b2 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.h +++ b/drivers/media/platform/qcom/camss/camss-csid.h @@ -213,9 +213,10 @@ extern const struct csid_formats csid_formats_gen2; extern const struct csid_hw_ops csid_ops_4_1; extern const struct csid_hw_ops csid_ops_4_7; +extern const struct csid_hw_ops csid_ops_340; extern const struct csid_hw_ops csid_ops_680; extern const struct csid_hw_ops csid_ops_gen2; -extern const struct csid_hw_ops csid_ops_780; +extern const struct csid_hw_ops csid_ops_gen3; /* * csid_is_lite - Check if CSID is CSID lite. diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c index 88c0ba495c32..619abbf60781 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-3ph-1-0.c @@ -64,6 +64,85 @@ struct csiphy_lane_regs { u32 csiphy_param_type; }; +/* 5nm 2PH v 1.3.0 2p5Gbps 4 lane DPHY mode */ +static const struct +csiphy_lane_regs lane_regs_sa8775p[] = { + {0x0724, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x070C, 0xFF, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0024, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0224, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0424, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0624, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x8D, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x10, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x005C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0xFD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x025C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0xFD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x045C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0xFD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x065C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0xFD, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + /* GEN2 1.0 2PH */ static const struct csiphy_lane_regs lane_regs_sdm845[] = { @@ -319,6 +398,90 @@ csiphy_lane_regs lane_regs_sm8250[] = { {0x0884, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, }; +/* 14nm 2PH v 2.0.1 2p5Gbps 4 lane DPHY mode */ +static const struct +csiphy_lane_regs lane_regs_qcm2290[] = { + {0x0030, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0028, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x003c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0xd7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0xff, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x3f, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0730, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0xc0, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0704, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0720, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x3f, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0230, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x023c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0xd7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0204, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0220, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020c, 0xff, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x3f, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0430, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0428, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x043c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0xd7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0xff, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x3f, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0630, 0x02, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x04, 0x00, CSIPHY_DNP_PARAMS}, + {0x063c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0xd7, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0604, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0620, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x04, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0xff, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x50, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x3f, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + /* GEN2 2.1.2 2PH DPHY mode */ static const struct csiphy_lane_regs lane_regs_sm8550[] = { @@ -424,6 +587,102 @@ csiphy_lane_regs lane_regs_sm8550[] = { {0x0C64, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, }; +/* GEN2 2.2.0 2PH 4 lane DPHY mode */ +static const struct +csiphy_lane_regs lane_regs_sm8650[] = { + {0x0e94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0ea0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e90, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e98, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e94, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0e30, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e28, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e00, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e0c, 0xff, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e38, 0x1f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e2c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e34, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e1c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e14, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e3c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e04, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e20, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0e08, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0e10, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0094, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x00a0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0090, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0098, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0094, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0030, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x8e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xfe, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x002c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0034, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x001c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0014, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x003c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0004, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0020, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0494, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x04a0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0490, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0498, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0494, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0430, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x8e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xfe, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x042c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0434, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x041c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0414, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x043c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0404, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0420, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0894, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x08a0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0890, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0898, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0894, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0830, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x8e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0838, 0xfe, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x082c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0834, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x081c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0814, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x083c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0804, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0820, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0808, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0810, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + + {0x0c94, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0ca0, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c90, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c98, 0x08, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c94, 0x07, 0xd1, CSIPHY_DEFAULT_PARAMS}, + {0x0c30, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c00, 0x8e, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c38, 0xfe, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c2c, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c34, 0x0f, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c1c, 0x0a, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c14, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c3c, 0xb8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c04, 0x0c, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c20, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0c08, 0x19, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x0c10, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, +}; + /* 4nm 2PH v 2.1.2 2p5Gbps 4 lane DPHY mode */ static const struct csiphy_lane_regs lane_regs_x1e80100[] = { @@ -744,11 +1003,15 @@ static bool csiphy_is_gen2(u32 version) bool ret = false; switch (version) { + case CAMSS_2290: case CAMSS_7280: case CAMSS_8250: case CAMSS_8280XP: + case CAMSS_8300: case CAMSS_845: case CAMSS_8550: + case CAMSS_8650: + case CAMSS_8775P: case CAMSS_X1E80100: ret = true; break; @@ -829,6 +1092,10 @@ static int csiphy_init(struct csiphy_device *csiphy) regs->lane_regs = &lane_regs_sdm845[0]; regs->lane_array_size = ARRAY_SIZE(lane_regs_sdm845); break; + case CAMSS_2290: + regs->lane_regs = &lane_regs_qcm2290[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_qcm2290); + break; case CAMSS_7280: case CAMSS_8250: regs->lane_regs = &lane_regs_sm8250[0]; @@ -848,6 +1115,16 @@ static int csiphy_init(struct csiphy_device *csiphy) regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8550); regs->offset = 0x1000; break; + case CAMSS_8650: + regs->lane_regs = &lane_regs_sm8650[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sm8650); + regs->offset = 0x1000; + break; + case CAMSS_8300: + case CAMSS_8775P: + regs->lane_regs = &lane_regs_sa8775p[0]; + regs->lane_array_size = ARRAY_SIZE(lane_regs_sa8775p); + break; default: break; } diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 2de97f58f9ae..a734fb7dde0a 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -600,6 +600,7 @@ int msm_csiphy_subdev_init(struct camss *camss, return PTR_ERR(csiphy->base); if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x39 || camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_8x96) { csiphy->base_clk_mux = diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index 2dc585c6123d..aaf3caa42d33 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -1112,6 +1112,8 @@ int msm_ispif_subdev_init(struct camss *camss, /* Number of ISPIF lines - same as number of CSID hardware modules */ if (camss->res->version == CAMSS_8x16) ispif->line_num = 2; + else if (camss->res->version == CAMSS_8x39) + ispif->line_num = 3; else if (camss->res->version == CAMSS_8x96 || camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_660) @@ -1128,7 +1130,8 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->line[i].ispif = ispif; ispif->line[i].id = i; - if (camss->res->version == CAMSS_8x16) { + if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x39) { ispif->line[i].formats = ispif_formats_8x16; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x16); @@ -1162,7 +1165,8 @@ int msm_ispif_subdev_init(struct camss *camss, ispif->irq = ret; snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s", dev_name(dev), MSM_ISPIF_NAME); - if (camss->res->version == CAMSS_8x16) + if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x39) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); else if (camss->res->version == CAMSS_8x96 || diff --git a/drivers/media/platform/qcom/camss/camss-vfe-340.c b/drivers/media/platform/qcom/camss/camss-vfe-340.c new file mode 100644 index 000000000000..30d7630b3e8b --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-340.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module 340 (TFE) + * + * Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <linux/delay.h> +#include <linux/bitfield.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> + +#include "camss.h" +#include "camss-vfe.h" + +#define TFE_GLOBAL_RESET_CMD (0x014) +#define TFE_GLOBAL_RESET_CMD_CORE BIT(0) + +#define TFE_REG_UPDATE_CMD (0x02c) + +#define TFE_IRQ_CMD (0x030) +#define TFE_IRQ_CMD_CLEAR BIT(0) +#define TFE_IRQ_MASK_0 (0x034) +#define TFE_IRQ_MASK_0_RST_DONE BIT(0) +#define TFE_IRQ_MASK_0_BUS_WR BIT(1) +#define TFE_IRQ_MASK_1 (0x038) +#define TFE_IRQ_MASK_2 (0x03c) +#define TFE_IRQ_CLEAR_0 (0x040) + +#define TFE_IRQ_STATUS_0 (0x04c) + +#define BUS_REG(a) (0xa00 + (a)) + +#define TFE_BUS_IRQ_MASK_0 BUS_REG(0x18) +#define TFE_BUS_IRQ_MASK_RUP_DONE_MASK GENMASK(3, 0) +#define TFE_BUS_IRQ_MASK_RUP_DONE(sc) FIELD_PREP(TFE_BUS_IRQ_MASK_RUP_DONE_MASK, BIT(sc)) +#define TFE_BUS_IRQ_MASK_BUF_DONE_MASK GENMASK(15, 8) +#define TFE_BUS_IRQ_MASK_BUF_DONE(sg) FIELD_PREP(TFE_BUS_IRQ_MASK_BUF_DONE_MASK, BIT(sg)) +#define TFE_BUS_IRQ_MASK_0_CONS_VIOL BIT(28) +#define TFE_BUS_IRQ_MASK_0_VIOL BIT(30) +#define TFE_BUS_IRQ_MASK_0_IMG_VIOL BIT(31) + +#define TFE_BUS_IRQ_MASK_1 BUS_REG(0x1c) +#define TFE_BUS_IRQ_CLEAR_0 BUS_REG(0x20) +#define TFE_BUS_IRQ_STATUS_0 BUS_REG(0x28) +#define TFE_BUS_IRQ_CMD BUS_REG(0x30) +#define TFE_BUS_IRQ_CMD_CLEAR BIT(0) + +#define TFE_BUS_STATUS_CLEAR BUS_REG(0x60) +#define TFE_BUS_VIOLATION_STATUS BUS_REG(0x64) +#define TFE_BUS_OVERFLOW_STATUS BUS_REG(0x68) +#define TFE_BUS_IMAGE_SZ_VIOLATION_STATUS BUS_REG(0x70) + +#define TFE_BUS_CLIENT_CFG(c) BUS_REG(0x200 + (c) * 0x100) +#define TFE_BUS_CLIENT_CFG_EN BIT(0) +#define TFE_BUS_CLIENT_CFG_MODE_FRAME BIT(16) +#define TFE_BUS_IMAGE_ADDR(c) BUS_REG(0x204 + (c) * 0x100) +#define TFE_BUS_FRAME_INCR(c) BUS_REG(0x208 + (c) * 0x100) +#define TFE_BUS_IMAGE_CFG_0(c) BUS_REG(0x20c + (c) * 0x100) +#define TFE_BUS_IMAGE_CFG_0_DEFAULT 0xffff +#define TFE_BUS_IMAGE_CFG_1(c) BUS_REG(0x210 + (c) * 0x100) +#define TFE_BUS_IMAGE_CFG_2(c) BUS_REG(0x214 + (c) * 0x100) +#define TFE_BUS_IMAGE_CFG_2_DEFAULT 0xffff +#define TFE_BUS_PACKER_CFG(c) BUS_REG(0x218 + (c) * 0x100) +#define TFE_BUS_PACKER_CFG_FMT_PLAIN64 0xa +#define TFE_BUS_IRQ_SUBSAMPLE_CFG_0(c) BUS_REG(0x230 + (c) * 0x100) +#define TFE_BUS_IRQ_SUBSAMPLE_CFG_1(c) BUS_REG(0x234 + (c) * 0x100) +#define TFE_BUS_FRAMEDROP_CFG_0(c) BUS_REG(0x238 + (c) * 0x100) +#define TFE_BUS_FRAMEDROP_CFG_1(c) BUS_REG(0x23c + (c) * 0x100) + +/* + * TODO: differentiate the port id based on requested type of RDI, BHIST etc + * + * TFE write master IDs (clients) + * + * BAYER 0 + * IDEAL_RAW 1 + * STATS_TINTLESS_BG 2 + * STATS_BHIST 3 + * STATS_AWB_BG 4 + * STATS_AEC_BG 5 + * STATS_BAF 6 + * RDI0 7 + * RDI1 8 + * RDI2 9 + */ +#define RDI_WM(n) (7 + (n)) +#define TFE_WM_NUM 10 + +enum tfe_iface { + TFE_IFACE_PIX, + TFE_IFACE_RDI0, + TFE_IFACE_RDI1, + TFE_IFACE_RDI2, + TFE_IFACE_NUM +}; + +enum tfe_subgroups { + TFE_SUBGROUP_BAYER, + TFE_SUBGROUP_IDEAL_RAW, + TFE_SUBGROUP_HDR, + TFE_SUBGROUP_BG, + TFE_SUBGROUP_BAF, + TFE_SUBGROUP_RDI0, + TFE_SUBGROUP_RDI1, + TFE_SUBGROUP_RDI2, + TFE_SUBGROUP_NUM +}; + +static enum tfe_iface tfe_line_iface_map[VFE_LINE_NUM_MAX] = { + [VFE_LINE_RDI0] = TFE_IFACE_RDI0, + [VFE_LINE_RDI1] = TFE_IFACE_RDI1, + [VFE_LINE_RDI2] = TFE_IFACE_RDI2, + [VFE_LINE_PIX] = TFE_IFACE_PIX, +}; + +static enum vfe_line_id tfe_subgroup_line_map[TFE_SUBGROUP_NUM] = { + [TFE_SUBGROUP_BAYER] = VFE_LINE_PIX, + [TFE_SUBGROUP_IDEAL_RAW] = VFE_LINE_PIX, + [TFE_SUBGROUP_HDR] = VFE_LINE_PIX, + [TFE_SUBGROUP_BG] = VFE_LINE_PIX, + [TFE_SUBGROUP_BAF] = VFE_LINE_PIX, + [TFE_SUBGROUP_RDI0] = VFE_LINE_RDI0, + [TFE_SUBGROUP_RDI1] = VFE_LINE_RDI1, + [TFE_SUBGROUP_RDI2] = VFE_LINE_RDI2, +}; + +static inline enum tfe_iface __line_to_iface(enum vfe_line_id line_id) +{ + if (line_id <= VFE_LINE_NONE || line_id >= VFE_LINE_NUM_MAX) { + pr_warn("VFE: Invalid line %d\n", line_id); + return TFE_IFACE_RDI0; + } + + return tfe_line_iface_map[line_id]; +} + +static inline enum vfe_line_id __iface_to_line(unsigned int iface) +{ + int i; + + for (i = 0; i < VFE_LINE_NUM_MAX; i++) { + if (tfe_line_iface_map[i] == iface) + return i; + } + + return VFE_LINE_NONE; +} + +static inline enum vfe_line_id __subgroup_to_line(enum tfe_subgroups sg) +{ + if (sg >= TFE_SUBGROUP_NUM) + return VFE_LINE_NONE; + + return tfe_subgroup_line_map[sg]; +} + +static void vfe_global_reset(struct vfe_device *vfe) +{ + writel(TFE_IRQ_MASK_0_RST_DONE, vfe->base + TFE_IRQ_MASK_0); + writel(TFE_GLOBAL_RESET_CMD_CORE, vfe->base + TFE_GLOBAL_RESET_CMD); +} + +static irqreturn_t vfe_isr(int irq, void *dev) +{ + struct vfe_device *vfe = dev; + u32 status; + int i; + + status = readl_relaxed(vfe->base + TFE_IRQ_STATUS_0); + writel_relaxed(status, vfe->base + TFE_IRQ_CLEAR_0); + writel_relaxed(TFE_IRQ_CMD_CLEAR, vfe->base + TFE_IRQ_CMD); + + if (status & TFE_IRQ_MASK_0_RST_DONE) { + dev_dbg(vfe->camss->dev, "VFE%u: Reset done!", vfe->id); + vfe_isr_reset_ack(vfe); + } + + if (status & TFE_IRQ_MASK_0_BUS_WR) { + u32 bus_status = readl_relaxed(vfe->base + TFE_BUS_IRQ_STATUS_0); + + writel_relaxed(bus_status, vfe->base + TFE_BUS_IRQ_CLEAR_0); + writel_relaxed(TFE_BUS_IRQ_CMD_CLEAR, vfe->base + TFE_BUS_IRQ_CMD); + + for (i = 0; i < TFE_IFACE_NUM; i++) { + if (bus_status & TFE_BUS_IRQ_MASK_RUP_DONE(i)) + vfe->res->hw_ops->reg_update_clear(vfe, __iface_to_line(i)); + } + + for (i = 0; i < TFE_SUBGROUP_NUM; i++) { + if (bus_status & TFE_BUS_IRQ_MASK_BUF_DONE(i)) + vfe_buf_done(vfe, __subgroup_to_line(i)); + } + + if (bus_status & TFE_BUS_IRQ_MASK_0_CONS_VIOL) + dev_err_ratelimited(vfe->camss->dev, "VFE%u: Bad config violation", + vfe->id); + + if (bus_status & TFE_BUS_IRQ_MASK_0_VIOL) + dev_err_ratelimited(vfe->camss->dev, "VFE%u: Input data violation", + vfe->id); + + if (bus_status & TFE_BUS_IRQ_MASK_0_IMG_VIOL) + dev_err_ratelimited(vfe->camss->dev, "VFE%u: Image size violation", + vfe->id); + } + + status = readl_relaxed(vfe->base + TFE_BUS_OVERFLOW_STATUS); + if (status) { + writel_relaxed(status, vfe->base + TFE_BUS_STATUS_CLEAR); + for (i = 0; i < TFE_WM_NUM; i++) { + if (status & BIT(i)) + dev_err_ratelimited(vfe->camss->dev, + "VFE%u: bus overflow for wm %u\n", + vfe->id, i); + } + } + + return IRQ_HANDLED; +} + +static int vfe_halt(struct vfe_device *vfe) +{ + /* rely on vfe_disable_output() to stop the VFE */ + return 0; +} + +static void vfe_enable_irq(struct vfe_device *vfe) +{ + writel(TFE_IRQ_MASK_0_RST_DONE | TFE_IRQ_MASK_0_BUS_WR, + vfe->base + TFE_IRQ_MASK_0); + writel(TFE_BUS_IRQ_MASK_RUP_DONE_MASK | TFE_BUS_IRQ_MASK_BUF_DONE_MASK | + TFE_BUS_IRQ_MASK_0_CONS_VIOL | TFE_BUS_IRQ_MASK_0_VIOL | + TFE_BUS_IRQ_MASK_0_IMG_VIOL, vfe->base + TFE_BUS_IRQ_MASK_0); +} + +static void vfe_wm_update(struct vfe_device *vfe, u8 rdi, u32 addr, + struct vfe_line *line) +{ + u8 wm = RDI_WM(rdi); + + writel_relaxed(addr, vfe->base + TFE_BUS_IMAGE_ADDR(wm)); +} + +static void vfe_wm_start(struct vfe_device *vfe, u8 rdi, struct vfe_line *line) +{ + struct v4l2_pix_format_mplane *pix = &line->video_out.active_fmt.fmt.pix_mp; + u32 stride = pix->plane_fmt[0].bytesperline; + u8 wm = RDI_WM(rdi); + + /* Configuration for plain RDI frames */ + writel_relaxed(TFE_BUS_IMAGE_CFG_0_DEFAULT, vfe->base + TFE_BUS_IMAGE_CFG_0(wm)); + writel_relaxed(0u, vfe->base + TFE_BUS_IMAGE_CFG_1(wm)); + writel_relaxed(TFE_BUS_IMAGE_CFG_2_DEFAULT, vfe->base + TFE_BUS_IMAGE_CFG_2(wm)); + writel_relaxed(stride * pix->height, vfe->base + TFE_BUS_FRAME_INCR(wm)); + writel_relaxed(TFE_BUS_PACKER_CFG_FMT_PLAIN64, vfe->base + TFE_BUS_PACKER_CFG(wm)); + + /* No dropped frames, one irq per frame */ + writel_relaxed(0, vfe->base + TFE_BUS_FRAMEDROP_CFG_0(wm)); + writel_relaxed(1, vfe->base + TFE_BUS_FRAMEDROP_CFG_1(wm)); + writel_relaxed(0, vfe->base + TFE_BUS_IRQ_SUBSAMPLE_CFG_0(wm)); + writel_relaxed(1, vfe->base + TFE_BUS_IRQ_SUBSAMPLE_CFG_1(wm)); + + vfe_enable_irq(vfe); + + writel(TFE_BUS_CLIENT_CFG_EN | TFE_BUS_CLIENT_CFG_MODE_FRAME, + vfe->base + TFE_BUS_CLIENT_CFG(wm)); + + dev_dbg(vfe->camss->dev, "VFE%u: Started RDI%u width %u height %u stride %u\n", + vfe->id, rdi, pix->width, pix->height, stride); +} + +static void vfe_wm_stop(struct vfe_device *vfe, u8 rdi) +{ + u8 wm = RDI_WM(rdi); + + writel(0, vfe->base + TFE_BUS_CLIENT_CFG(wm)); + + dev_dbg(vfe->camss->dev, "VFE%u: Stopped RDI%u\n", vfe->id, rdi); +} + +static const struct camss_video_ops vfe_video_ops_520 = { + .queue_buffer = vfe_queue_buffer_v2, + .flush_buffers = vfe_flush_buffers, +}; + +static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) +{ + vfe->video_ops = vfe_video_ops_520; +} + +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + vfe->reg_update |= BIT(__line_to_iface(line_id)); + writel_relaxed(vfe->reg_update, vfe->base + TFE_REG_UPDATE_CMD); +} + +static void vfe_reg_update_clear(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + vfe->reg_update &= ~BIT(__line_to_iface(line_id)); +} + +const struct vfe_hw_ops vfe_ops_340 = { + .global_reset = vfe_global_reset, + .hw_version = vfe_hw_version, + .isr = vfe_isr, + .pm_domain_off = vfe_pm_domain_off, + .pm_domain_on = vfe_pm_domain_on, + .subdev_init = vfe_subdev_init, + .vfe_disable = vfe_disable, + .vfe_enable = vfe_enable_v2, + .vfe_halt = vfe_halt, + .vfe_wm_start = vfe_wm_start, + .vfe_wm_stop = vfe_wm_stop, + .vfe_buf_done = vfe_buf_done, + .vfe_wm_update = vfe_wm_update, + .reg_update = vfe_reg_update, + .reg_update_clear = vfe_reg_update_clear, +}; 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 901677293d97..9cf1ccdb2fe7 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -15,6 +15,7 @@ #include "camss.h" #include "camss-vfe.h" #include "camss-vfe-gen1.h" +#include "camss-vfe-vbif.h" #define VFE_0_HW_VERSION 0x000 @@ -733,6 +734,7 @@ static void vfe_set_qos(struct vfe_device *vfe) { u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG; u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG; + int ret; writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0); writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1); @@ -742,6 +744,16 @@ static void vfe_set_qos(struct vfe_device *vfe) writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5); writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6); writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7); + + /* SoC-specific VBIF settings */ + if (vfe->res->has_vbif) { + ret = vfe_vbif_apply_settings(vfe); + if (ret < 0) { + dev_err_ratelimited(vfe->camss->dev, + "VFE: VBIF error %d\n", + ret); + } + } } static void vfe_set_ds(struct vfe_device *vfe) diff --git a/drivers/media/platform/qcom/camss/camss-vfe-780.c b/drivers/media/platform/qcom/camss/camss-vfe-gen3.c index b9812d70f91b..22579617def7 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-780.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-gen3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v780 (SM8550) + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module gen3 * * Copyright (c) 2024 Qualcomm Technologies, Inc. */ @@ -12,13 +12,44 @@ #include "camss.h" #include "camss-vfe.h" -#define BUS_REG_BASE (vfe_is_lite(vfe) ? 0x200 : 0xC00) +#define IS_VFE_690(vfe) \ + ((vfe->camss->res->version == CAMSS_8775P) \ + || (vfe->camss->res->version == CAMSS_8300)) + +#define BUS_REG_BASE_690 \ + (vfe_is_lite(vfe) ? 0x480 : 0x400) +#define BUS_REG_BASE_780 \ + (vfe_is_lite(vfe) ? 0x200 : 0xC00) +#define BUS_REG_BASE \ + (IS_VFE_690(vfe) ? BUS_REG_BASE_690 : BUS_REG_BASE_780) + +#define VFE_TOP_CORE_CFG (0x24) +#define VFE_DISABLE_DSCALING_DS4 BIT(21) +#define VFE_DISABLE_DSCALING_DS16 BIT(22) + +#define VFE_BUS_WM_TEST_BUS_CTRL_690 (BUS_REG_BASE + 0xFC) +#define VFE_BUS_WM_TEST_BUS_CTRL_780 (BUS_REG_BASE + 0xDC) +#define VFE_BUS_WM_TEST_BUS_CTRL \ + (IS_VFE_690(vfe) ? VFE_BUS_WM_TEST_BUS_CTRL_690 \ + : VFE_BUS_WM_TEST_BUS_CTRL_780) +/* + * Bus client mapping: + * + * Full VFE: + * VFE_690: 16 = RDI0, 17 = RDI1, 18 = RDI2 + * VFE_780: 23 = RDI0, 24 = RDI1, 25 = RDI2 + * + * VFE LITE: + * VFE_690 : 0 = RDI0, 1 = RDI1, 2 = RDI2, 3 = RDI3, 4 = RDI4, 5 = RDI5 + * VFE_780 : 0 = RDI0, 1 = RDI1, 2 = RDI2, 3 = RDI3, 4 = RDI4 + */ +#define RDI_WM_690(n) ((vfe_is_lite(vfe) ? 0x0 : 0x10) + (n)) +#define RDI_WM_780(n) ((vfe_is_lite(vfe) ? 0x0 : 0x17) + (n)) +#define RDI_WM(n) (IS_VFE_690(vfe) ? RDI_WM_690(n) : RDI_WM_780(n)) #define VFE_BUS_WM_CGC_OVERRIDE (BUS_REG_BASE + 0x08) #define WM_CGC_OVERRIDE_ALL (0x7FFFFFF) -#define VFE_BUS_WM_TEST_BUS_CTRL (BUS_REG_BASE + 0xDC) - #define VFE_BUS_WM_CFG(n) (BUS_REG_BASE + 0x200 + (n) * 0x100) #define WM_CFG_EN BIT(0) #define WM_VIR_FRM_EN BIT(1) @@ -39,17 +70,6 @@ #define VFE_BUS_WM_MMU_PREFETCH_CFG(n) (BUS_REG_BASE + 0x260 + (n) * 0x100) #define VFE_BUS_WM_MMU_PREFETCH_MAX_OFFSET(n) (BUS_REG_BASE + 0x264 + (n) * 0x100) -/* - * Bus client mapping: - * - * Full VFE: - * 23 = RDI0, 24 = RDI1, 25 = RDI2 - * - * VFE LITE: - * 0 = RDI0, 1 = RDI1, 2 = RDI3, 4 = RDI4 - */ -#define RDI_WM(n) ((vfe_is_lite(vfe) ? 0x0 : 0x17) + (n)) - static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line) { struct v4l2_pix_format_mplane *pix = @@ -62,14 +82,24 @@ static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line) writel(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL); - writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height >> 8, - vfe->base + VFE_BUS_WM_FRAME_INCR(wm)); + if (IS_VFE_690(vfe)) + writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height, + vfe->base + VFE_BUS_WM_FRAME_INCR(wm)); + else + writel(ALIGN(pix->plane_fmt[0].bytesperline, 16) * pix->height >> 8, + vfe->base + VFE_BUS_WM_FRAME_INCR(wm)); + writel((WM_IMAGE_CFG_0_DEFAULT_WIDTH & 0xFFFF), vfe->base + VFE_BUS_WM_IMAGE_CFG_0(wm)); writel(WM_IMAGE_CFG_2_DEFAULT_STRIDE, vfe->base + VFE_BUS_WM_IMAGE_CFG_2(wm)); writel(0, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); + /* TOP CORE CFG */ + if (IS_VFE_690(vfe)) + writel(VFE_DISABLE_DSCALING_DS4 | VFE_DISABLE_DSCALING_DS16, + vfe->base + VFE_TOP_CORE_CFG); + /* no dropped frames, one irq per frame */ writel(0, vfe->base + VFE_BUS_WM_FRAMEDROP_PERIOD(wm)); writel(1, vfe->base + VFE_BUS_WM_FRAMEDROP_PATTERN(wm)); @@ -92,7 +122,11 @@ static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr, struct vfe_line *line) { wm = RDI_WM(wm); - writel((addr >> 8) & 0xFFFFFFFF, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm)); + + if (IS_VFE_690(vfe)) + writel(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm)); + else + writel((addr >> 8), vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm)); dev_dbg(vfe->camss->dev, "wm:%d, image buf addr:0x%x\n", wm, addr); @@ -113,14 +147,14 @@ static inline void vfe_reg_update_clear(struct vfe_device *vfe, camss_reg_update(vfe->camss, vfe->id, port_id, true); } -static const struct camss_video_ops vfe_video_ops_780 = { +static const struct camss_video_ops vfe_video_ops_gen3 = { .queue_buffer = vfe_queue_buffer_v2, .flush_buffers = vfe_flush_buffers, }; static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) { - vfe->video_ops = vfe_video_ops_780; + vfe->video_ops = vfe_video_ops_gen3; } static void vfe_global_reset(struct vfe_device *vfe) @@ -140,7 +174,7 @@ static int vfe_halt(struct vfe_device *vfe) return 0; } -const struct vfe_hw_ops vfe_ops_780 = { +const struct vfe_hw_ops vfe_ops_gen3 = { .global_reset = vfe_global_reset, .hw_version = vfe_hw_version, .isr = vfe_isr, diff --git a/drivers/media/platform/qcom/camss/camss-vfe-vbif.c b/drivers/media/platform/qcom/camss/camss-vfe-vbif.c new file mode 100644 index 000000000000..911f8da02f1f --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-vbif.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * camss-vfe-vbif.c + * + * Qualcomm MSM Camera Subsystem - VFE VBIF Module + * + * Copyright (c) 2025, The Linux Foundation. All rights reserved. + * + */ + +#include <linux/io.h> + +#include "camss.h" +#include "camss-vfe.h" +#include "camss-vfe-vbif.h" + +#define VBIF_FIXED_SORT_EN 0x30 +#define VBIF_FIXED_SORT_SEL0 0x34 + +void vfe_vbif_write_reg(struct vfe_device *vfe, u32 reg, u32 val) +{ + writel_relaxed(val, vfe->vbif_base + reg); +} + +int vfe_vbif_apply_settings(struct vfe_device *vfe) +{ + vfe_vbif_write_reg(vfe, VBIF_FIXED_SORT_EN, 0xfff); + vfe_vbif_write_reg(vfe, VBIF_FIXED_SORT_SEL0, 0x555000); + + return 0; +} diff --git a/drivers/media/platform/qcom/camss/camss-vfe-vbif.h b/drivers/media/platform/qcom/camss/camss-vfe-vbif.h new file mode 100644 index 000000000000..502db629e961 --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-vbif.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * camss-vfe-vbif.h + * + * Qualcomm MSM Camera Subsystem - VFE VBIF Module + * + * Copyright (c) 2025, The Linux Foundation. All rights reserved. + * + */ +#ifndef QC_MSM_CAMSS_VFE_VBIF_H +#define QC_MSM_CAMSS_VFE_VBIF_H + +#include "camss-vfe.h" + +void vfe_vbif_write_reg(struct vfe_device *vfe, u32 reg, u32 val); + +int vfe_vbif_apply_settings(struct vfe_device *vfe); + +#endif /* QC_MSM_CAMSS_VFE_VBIF_H */ diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index 4bca6c3abaff..9c7ad8aa4058 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -290,6 +290,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, switch (vfe->camss->res->version) { case CAMSS_8x16: + case CAMSS_8x39: case CAMSS_8x53: switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: @@ -340,12 +341,16 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, } break; case CAMSS_660: + case CAMSS_2290: case CAMSS_7280: case CAMSS_8x96: case CAMSS_8250: case CAMSS_8280XP: + case CAMSS_8300: case CAMSS_845: case CAMSS_8550: + case CAMSS_8650: + case CAMSS_8775P: case CAMSS_X1E80100: switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_1X16: @@ -538,7 +543,7 @@ int vfe_enable_output_v2(struct vfe_line *line) ops->vfe_wm_start(vfe, output->wm_idx[0], line); - for (i = 0; i < 2; i++) { + for (i = 0; i < CAMSS_INIT_BUF_COUNT; i++) { output->buf[i] = vfe_buf_get_pending(output); if (!output->buf[i]) break; @@ -910,7 +915,25 @@ static int vfe_match_clock_names(struct vfe_device *vfe, return (!strcmp(clock->name, vfe_name) || !strcmp(clock->name, vfe_lite_name) || - !strcmp(clock->name, "vfe_lite")); + !strcmp(clock->name, "vfe_lite") || + !strcmp(clock->name, "camnoc_axi") || + !strcmp(clock->name, "camnoc_rt_axi")); +} + +/* + * vfe_check_clock_levels - Calculate and set clock rates on VFE module + * @clock: clocks data + * + * Return false if there is no non-zero clock level and true otherwise. + */ +static bool vfe_check_clock_levels(struct camss_clock *clock) +{ + int i; + + for (i = 0; i < clock->nfreqs; i++) + if (clock->freq[i]) + return true; + return false; } /* @@ -936,7 +959,7 @@ static int vfe_set_clock_rates(struct vfe_device *vfe) for (i = 0; i < vfe->nclocks; i++) { struct camss_clock *clock = &vfe->clock[i]; - if (vfe_match_clock_names(vfe, clock)) { + if (vfe_match_clock_names(vfe, clock) && vfe_check_clock_levels(clock)) { u64 min_rate = 0; long rate; @@ -1017,7 +1040,7 @@ static int vfe_check_clock_rates(struct vfe_device *vfe) for (i = 0; i < vfe->nclocks; i++) { struct camss_clock *clock = &vfe->clock[i]; - if (vfe_match_clock_names(vfe, clock)) { + if (vfe_match_clock_names(vfe, clock) && vfe_check_clock_levels(clock)) { u64 min_rate = 0; unsigned long rate; @@ -1807,6 +1830,15 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, return PTR_ERR(vfe->base); } + if (vfe->res->has_vbif) { + vfe->vbif_base = devm_platform_ioremap_resource_byname(pdev, + vfe->res->vbif_name); + if (IS_ERR(vfe->vbif_base)) { + dev_err(dev, "could not map vbif memory\n"); + return PTR_ERR(vfe->vbif_base); + } + } + /* Interrupt */ ret = platform_get_irq_byname(pdev, res->interrupt[0]); @@ -1972,8 +2004,11 @@ static int vfe_bpl_align(struct vfe_device *vfe) case CAMSS_7280: case CAMSS_8250: case CAMSS_8280XP: + case CAMSS_8300: case CAMSS_845: case CAMSS_8550: + case CAMSS_8650: + case CAMSS_8775P: case CAMSS_X1E80100: ret = 16; break; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index a23f666be753..ae9dad353a37 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -136,6 +136,8 @@ struct vfe_subdev_resources { u8 line_num; bool has_pd; char *pd_name; + bool has_vbif; + char *vbif_name; const struct vfe_hw_ops *hw_ops; const struct camss_formats *formats_rdi; const struct camss_formats *formats_pix; @@ -145,6 +147,7 @@ struct vfe_device { struct camss *camss; u8 id; void __iomem *base; + void __iomem *vbif_base; u32 irq; char irq_name[30]; struct camss_clock *clock; @@ -242,9 +245,10 @@ extern const struct vfe_hw_ops vfe_ops_4_1; extern const struct vfe_hw_ops vfe_ops_4_7; extern const struct vfe_hw_ops vfe_ops_4_8; extern const struct vfe_hw_ops vfe_ops_170; +extern const struct vfe_hw_ops vfe_ops_340; extern const struct vfe_hw_ops vfe_ops_480; extern const struct vfe_hw_ops vfe_ops_680; -extern const struct vfe_hw_ops vfe_ops_780; +extern const struct vfe_hw_ops vfe_ops_gen3; int vfe_get(struct vfe_device *vfe); void vfe_put(struct vfe_device *vfe); diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 8d05802d1735..831486e14754 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -604,50 +604,11 @@ static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { * V4L2 file operations */ -static int video_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct camss_video *video = video_drvdata(file); - struct v4l2_fh *vfh; - int ret; - - mutex_lock(&video->lock); - - vfh = kzalloc(sizeof(*vfh), GFP_KERNEL); - if (vfh == NULL) { - ret = -ENOMEM; - goto error_alloc; - } - - v4l2_fh_init(vfh, vdev); - v4l2_fh_add(vfh); - - file->private_data = vfh; - - mutex_unlock(&video->lock); - - return 0; - -error_alloc: - mutex_unlock(&video->lock); - - return ret; -} - -static int video_release(struct file *file) -{ - vb2_fop_release(file); - - file->private_data = NULL; - - return 0; -} - static const struct v4l2_file_operations msm_vid_fops = { .owner = THIS_MODULE, .unlocked_ioctl = video_ioctl2, - .open = video_open, - .release = video_release, + .open = v4l2_fh_open, + .release = vb2_fop_release, .poll = vb2_fop_poll, .mmap = vb2_fop_mmap, .read = vb2_fop_read, diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index e08e70b93824..fcc2b2c3cba0 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -154,6 +154,149 @@ static const struct camss_subdev_resources vfe_res_8x16[] = { } }; +static const struct camss_subdev_resources csiphy_res_8x39[] = { + /* CSIPHY0 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy0_timer" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 100000000, 200000000 } }, + .reg = { "csiphy0", "csiphy0_clk_mux" }, + .interrupt = { "csiphy0" }, + .csiphy = { + .id = 0, + .hw_ops = &csiphy_ops_2ph_1_0, + .formats = &csiphy_formats_8x16 + } + }, + + /* CSIPHY1 */ + { + .regulators = { "vdda" }, + .clock = { "top_ahb", "ispif_ahb", "ahb", "csiphy1_timer" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 100000000, 200000000 } }, + .reg = { "csiphy1", "csiphy1_clk_mux" }, + .interrupt = { "csiphy1" }, + .csiphy = { + .id = 1, + .hw_ops = &csiphy_ops_2ph_1_0, + .formats = &csiphy_formats_8x16 + } + } +}; + +static const struct camss_subdev_resources csid_res_8x39[] = { + /* CSID0 */ + { + .regulators = {}, + .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb", + "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 0 }, + { 100000000, 200000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .hw_ops = &csid_ops_4_1, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_1 + } + }, + + /* CSID1 */ + { + .regulators = {}, + .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb", + "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 0 }, + { 100000000, 200000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .hw_ops = &csid_ops_4_1, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_1 + } + }, + + /* CSID2 */ + { + .regulators = {}, + .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb", + "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 0 }, + { 0 }, + { 100000000, 200000000 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" }, + .csid = { + .hw_ops = &csid_ops_4_1, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_4_1 + } + }, +}; + +static const struct camss_subdev_resources ispif_res_8x39 = { + /* ISPIF */ + .clock = { "top_ahb", "ispif_ahb", "ahb", + "csi0", "csi0_pix", "csi0_rdi", + "csi1", "csi1_pix", "csi1_rdi", + "csi2", "csi2_pix", "csi2_rdi" }, + .clock_for_reset = { "vfe0", "csi_vfe0" }, + .reg = { "ispif", "csi_clk_mux" }, + .interrupt = { "ispif" }, +}; + +static const struct camss_subdev_resources vfe_res_8x39[] = { + /* VFE0 */ + { + .regulators = {}, + .clock = { "top_ahb", "ispif_ahb", "vfe0", "csi_vfe0", + "vfe_ahb", "vfe_axi", "ahb" }, + .clock_rate = { { 0 }, + { 40000000, 80000000 }, + { 50000000, 80000000, 100000000, 160000000, + 177780000, 200000000, 266670000, 320000000, + 400000000, 465000000, 480000000, 600000000 }, + { 0 }, + { 0 }, + { 0 }, + { 0 } }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 3, + .has_vbif = true, + .vbif_name = "vfe0_vbif", + .hw_ops = &vfe_ops_4_1, + .formats_rdi = &vfe_formats_rdi_8x16, + .formats_pix = &vfe_formats_pix_8x16 + } + } +}; + static const struct camss_subdev_resources csid_res_8x53[] = { /* CSID0 */ { @@ -515,6 +658,140 @@ static const struct camss_subdev_resources vfe_res_8x96[] = { } }; +static const struct camss_subdev_resources csiphy_res_2290[] = { + /* CSIPHY0 */ + { + .regulators = { "vdd-csiphy-1p2", "vdd-csiphy-1p8" }, + .clock = { "top_ahb", "ahb", "csiphy0", "csiphy0_timer" }, + .clock_rate = { { 0 }, + { 0 }, + { 240000000, 341330000, 384000000 }, + { 100000000, 200000000, 268800000 } }, + .reg = { "csiphy0" }, + .interrupt = { "csiphy0" }, + .csiphy = { + .id = 0, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + } + }, + + /* CSIPHY1 */ + { + .regulators = { "vdd-csiphy-1p2", "vdd-csiphy-1p8" }, + .clock = { "top_ahb", "ahb", "csiphy1", "csiphy1_timer" }, + .clock_rate = { { 0 }, + { 0 }, + { 240000000, 341330000, 384000000 }, + { 100000000, 200000000, 268800000 } }, + .reg = { "csiphy1" }, + .interrupt = { "csiphy1" }, + .csiphy = { + .id = 1, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + } + } +}; + +static const struct camss_subdev_resources csid_res_2290[] = { + /* CSID0 */ + { + .regulators = {}, + .clock = { "top_ahb", "ahb", "csi0", "vfe0_cphy_rx", "vfe0" }, + .clock_rate = { { 0 }, + { 0 }, + { 192000000, 240000000, 384000000, 426400000 }, + { 0 }, + { 0 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .hw_ops = &csid_ops_340, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + + /* CSID1 */ + { + .regulators = {}, + .clock = { "top_ahb", "ahb", "csi1", "vfe1_cphy_rx", "vfe1" }, + .clock_rate = { { 0 }, + { 0 }, + { 192000000, 240000000, 384000000, 426400000 }, + { 0 }, + { 0 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .hw_ops = &csid_ops_340, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + } +}; + +static const struct camss_subdev_resources vfe_res_2290[] = { + /* VFE0 */ + { + .regulators = {}, + .clock = { "top_ahb", "ahb", "axi", "vfe0", "camnoc_rt_axi", "camnoc_nrt_axi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 19200000, 153600000, 192000000, 256000000, 384000000, 460800000 }, + { 0 }, + { 0 }, }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 4, + .hw_ops = &vfe_ops_340, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, + + /* VFE1 */ + { + .regulators = {}, + .clock = { "top_ahb", "ahb", "axi", "vfe1", "camnoc_rt_axi", "camnoc_nrt_axi" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 19200000, 153600000, 192000000, 256000000, 384000000, 460800000 }, + { 0 }, + { 0 }, }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .vfe = { + .line_num = 4, + .hw_ops = &vfe_ops_340, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, +}; + +static const struct resources_icc icc_res_2290[] = { + { + .name = "ahb", + .icc_bw_tbl.avg = 150000, + .icc_bw_tbl.peak = 300000, + }, + { + .name = "hf_mnoc", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 3000000, + }, + { + .name = "sf_mnoc", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 3000000, + }, +}; + static const struct camss_subdev_resources csiphy_res_660[] = { /* CSIPHY0 */ { @@ -2285,7 +2562,7 @@ static const struct camss_subdev_resources csid_res_8550[] = { .csid = { .is_lite = false, .parent_dev_ops = &vfe_parent_dev_ops, - .hw_ops = &csid_ops_780, + .hw_ops = &csid_ops_gen3, .formats = &csid_formats_gen2 } }, @@ -2300,7 +2577,7 @@ static const struct camss_subdev_resources csid_res_8550[] = { .csid = { .is_lite = false, .parent_dev_ops = &vfe_parent_dev_ops, - .hw_ops = &csid_ops_780, + .hw_ops = &csid_ops_gen3, .formats = &csid_formats_gen2 } }, @@ -2315,7 +2592,7 @@ static const struct camss_subdev_resources csid_res_8550[] = { .csid = { .is_lite = false, .parent_dev_ops = &vfe_parent_dev_ops, - .hw_ops = &csid_ops_780, + .hw_ops = &csid_ops_gen3, .formats = &csid_formats_gen2 } }, @@ -2330,7 +2607,7 @@ static const struct camss_subdev_resources csid_res_8550[] = { .csid = { .is_lite = true, .parent_dev_ops = &vfe_parent_dev_ops, - .hw_ops = &csid_ops_780, + .hw_ops = &csid_ops_gen3, .formats = &csid_formats_gen2 } }, @@ -2345,7 +2622,7 @@ static const struct camss_subdev_resources csid_res_8550[] = { .csid = { .is_lite = true, .parent_dev_ops = &vfe_parent_dev_ops, - .hw_ops = &csid_ops_780, + .hw_ops = &csid_ops_gen3, .formats = &csid_formats_gen2 } } @@ -2371,7 +2648,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = { .is_lite = false, .has_pd = true, .pd_name = "ife0", - .hw_ops = &vfe_ops_780, + .hw_ops = &vfe_ops_gen3, .formats_rdi = &vfe_formats_rdi_845, .formats_pix = &vfe_formats_pix_845 } @@ -2395,7 +2672,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = { .is_lite = false, .has_pd = true, .pd_name = "ife1", - .hw_ops = &vfe_ops_780, + .hw_ops = &vfe_ops_gen3, .formats_rdi = &vfe_formats_rdi_845, .formats_pix = &vfe_formats_pix_845 } @@ -2419,7 +2696,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = { .is_lite = false, .has_pd = true, .pd_name = "ife2", - .hw_ops = &vfe_ops_780, + .hw_ops = &vfe_ops_gen3, .formats_rdi = &vfe_formats_rdi_845, .formats_pix = &vfe_formats_pix_845 } @@ -2441,7 +2718,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = { .vfe = { .line_num = 4, .is_lite = true, - .hw_ops = &vfe_ops_780, + .hw_ops = &vfe_ops_gen3, .formats_rdi = &vfe_formats_rdi_845, .formats_pix = &vfe_formats_pix_845 } @@ -2463,7 +2740,7 @@ static const struct camss_subdev_resources vfe_res_8550[] = { .vfe = { .line_num = 4, .is_lite = true, - .hw_ops = &vfe_ops_780, + .hw_ops = &vfe_ops_gen3, .formats_rdi = &vfe_formats_rdi_845, .formats_pix = &vfe_formats_pix_845 } @@ -2483,6 +2760,778 @@ static const struct resources_icc icc_res_sm8550[] = { }, }; +static const struct camss_subdev_resources csiphy_res_sm8650[] = { + /* CSIPHY0 */ + { + .regulators = { "vdd-csiphy01-0p9", "vdd-csiphy01-1p2", }, + .clock = { "csiphy0", "csiphy0_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy0" }, + .interrupt = { "csiphy0" }, + .csiphy = { + .id = 0, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY1 */ + { + .regulators = { "vdd-csiphy01-0p9", "vdd-csiphy01-1p2", }, + .clock = { "csiphy1", "csiphy1_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy1" }, + .interrupt = { "csiphy1" }, + .csiphy = { + .id = 1, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY2 */ + { + .regulators = { "vdd-csiphy24-0p9", "vdd-csiphy24-1p2", }, + .clock = { "csiphy2", "csiphy2_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy2" }, + .interrupt = { "csiphy2" }, + .csiphy = { + .id = 2, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY3 */ + { + .regulators = { "vdd-csiphy35-0p9", "vdd-csiphy35-1p2", }, + .clock = { "csiphy3", "csiphy3_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy3" }, + .interrupt = { "csiphy3" }, + .csiphy = { + .id = 3, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY4 */ + { + .regulators = { "vdd-csiphy24-0p9", "vdd-csiphy24-1p2", }, + .clock = { "csiphy4", "csiphy4_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy4" }, + .interrupt = { "csiphy4" }, + .csiphy = { + .id = 4, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, + /* CSIPHY5 */ + { + .regulators = { "vdd-csiphy35-0p9", "vdd-csiphy35-1p2", }, + .clock = { "csiphy5", "csiphy5_timer" }, + .clock_rate = { { 400000000 }, + { 400000000 } }, + .reg = { "csiphy5" }, + .interrupt = { "csiphy5" }, + .csiphy = { + .id = 5, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + }, + }, +}; + +static const struct camss_subdev_resources csid_res_sm8650[] = { + /* CSID0 */ + { + .regulators = { }, + .clock = { "csid", "csiphy_rx" }, + .clock_rate = { { 400000000 }, + { 400000000, 480000000 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, + /* CSID1 */ + { + .regulators = { }, + .clock = { "csid", "csiphy_rx" }, + .clock_rate = { { 400000000 }, + { 400000000, 480000000 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, + /* CSID2 */ + { + .regulators = { }, + .clock = { "csid", "csiphy_rx" }, + .clock_rate = { { 400000000 }, + { 400000000, 480000000 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" }, + .csid = { + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, + /* CSID3 lite */ + { + .regulators = { }, + .clock = { "vfe_lite_ahb", "vfe_lite_csid", "vfe_lite_cphy_rx" }, + .clock_rate = { { 0 }, + { 400000000, 480000000 }, + { 0 } }, + .reg = { "csid_lite0" }, + .interrupt = { "csid_lite0" }, + .csid = { + .is_lite = true, + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, + /* CSID4 lite */ + { + .regulators = { }, + .clock = { "vfe_lite_ahb", "vfe_lite_csid", "vfe_lite_cphy_rx" }, + .clock_rate = { { 0 }, + { 400000000, 480000000 }, + { 0 } }, + .reg = { "csid_lite1" }, + .interrupt = { "csid_lite1" }, + .csid = { + .is_lite = true, + .parent_dev_ops = &vfe_parent_dev_ops, + .hw_ops = &csid_ops_gen3, + .formats = &csid_formats_gen2, + }, + }, +}; + +static const struct camss_subdev_resources vfe_res_sm8650[] = { + /* VFE0 */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb", + "camnoc_axi", "vfe0_fast_ahb", "vfe0", "cpas_vfe0", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 300000000, 400000000 }, + { 0 }, + { 466000000, 594000000, 675000000, 785000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "ife0", + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* VFE1 */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb", + "camnoc_axi", "vfe1_fast_ahb", "vfe1", "cpas_vfe1", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 300000000, 400000000 }, + { 0 }, + { 466000000, 594000000, 675000000, 785000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "ife1", + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* VFE2 */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "cpas_fast_ahb", + "camnoc_axi", "vfe2_fast_ahb", "vfe2", "cpas_vfe2", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 300000000, 400000000 }, + { 0 }, + { 466000000, 594000000, 675000000, 785000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe2" }, + .interrupt = { "vfe2" }, + .vfe = { + .line_num = 3, + .has_pd = true, + .pd_name = "ife2", + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* VFE3 lite */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "camnoc_axi", + "vfe_lite_ahb", "vfe_lite", "cpas_vfe_lite", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 0 }, + { 400000000, 480000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe_lite0" }, + .interrupt = { "vfe_lite0" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, + /* VFE4 lite */ + { + .regulators = { }, + .clock = { "gcc_axi_hf", "cpas_ahb", "camnoc_axi", + "vfe_lite_ahb", "vfe_lite", "cpas_vfe_lite", + "qdss_debug_xo", + }, + .clock_rate = { { 0 }, + { 80000000 }, + { 300000000, 400000000 }, + { 0 }, + { 400000000, 480000000 }, + { 0 }, + { 0 }, + }, + .reg = { "vfe_lite1" }, + .interrupt = { "vfe_lite1" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + }, + }, +}; + +static const struct resources_icc icc_res_sm8650[] = { + { + .name = "ahb", + .icc_bw_tbl.avg = 38400, + .icc_bw_tbl.peak = 76800, + }, + { + .name = "hf_mnoc", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 2097152, + }, +}; + +static const struct camss_subdev_resources csiphy_res_8300[] = { + /* CSIPHY0 */ + { + .regulators = { "vdda-phy", "vdda-pll" }, + + .clock = { "csiphy_rx", "csiphy0", "csiphy0_timer" }, + .clock_rate = { + { 400000000 }, + { 0 }, + { 400000000 }, + }, + .reg = { "csiphy0" }, + .interrupt = { "csiphy0" }, + .csiphy = { + .id = 0, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + } + }, + /* CSIPHY1 */ + { + .regulators = { "vdda-phy", "vdda-pll" }, + + .clock = { "csiphy_rx", "csiphy1", "csiphy1_timer" }, + .clock_rate = { + { 400000000 }, + { 0 }, + { 400000000 }, + }, + .reg = { "csiphy1" }, + .interrupt = { "csiphy1" }, + .csiphy = { + .id = 1, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + } + }, + /* CSIPHY2 */ + { + .regulators = { "vdda-phy", "vdda-pll" }, + + .clock = { "csiphy_rx", "csiphy2", "csiphy2_timer" }, + .clock_rate = { + { 400000000 }, + { 0 }, + { 400000000 }, + }, + .reg = { "csiphy2" }, + .interrupt = { "csiphy2" }, + .csiphy = { + .id = 2, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845, + } + }, +}; + +static const struct camss_subdev_resources csiphy_res_8775p[] = { + /* CSIPHY0 */ + { + .regulators = { "vdda-phy", "vdda-pll" }, + .clock = { "csiphy_rx", "csiphy0", "csiphy0_timer"}, + .clock_rate = { + { 400000000 }, + { 0 }, + { 400000000 }, + }, + .reg = { "csiphy0" }, + .interrupt = { "csiphy0" }, + .csiphy = { + .id = 0, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + } + }, + /* CSIPHY1 */ + { + .regulators = { "vdda-phy", "vdda-pll" }, + .clock = { "csiphy_rx", "csiphy1", "csiphy1_timer"}, + .clock_rate = { + { 400000000 }, + { 0 }, + { 400000000 }, + }, + .reg = { "csiphy1" }, + .interrupt = { "csiphy1" }, + .csiphy = { + .id = 1, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + } + }, + /* CSIPHY2 */ + { + .regulators = { "vdda-phy", "vdda-pll" }, + .clock = { "csiphy_rx", "csiphy2", "csiphy2_timer"}, + .clock_rate = { + { 400000000 }, + { 0 }, + { 400000000 }, + }, + .reg = { "csiphy2" }, + .interrupt = { "csiphy2" }, + .csiphy = { + .id = 2, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + } + }, + /* CSIPHY3 */ + { + .regulators = { "vdda-phy", "vdda-pll" }, + .clock = { "csiphy_rx", "csiphy3", "csiphy3_timer"}, + .clock_rate = { + { 400000000 }, + { 0 }, + { 400000000 }, + }, + .reg = { "csiphy3" }, + .interrupt = { "csiphy3" }, + .csiphy = { + .id = 3, + .hw_ops = &csiphy_ops_3ph_1_0, + .formats = &csiphy_formats_sdm845 + } + }, +}; + +static const struct camss_subdev_resources csid_res_8775p[] = { + /* CSID0 */ + { + .regulators = {}, + .clock = { "csid", "csiphy_rx"}, + .clock_rate = { + { 400000000, 400000000}, + { 400000000, 400000000} + }, + .reg = { "csid0" }, + .interrupt = { "csid0" }, + .csid = { + .is_lite = false, + .hw_ops = &csid_ops_gen3, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + /* CSID1 */ + { + .regulators = {}, + .clock = { "csid", "csiphy_rx"}, + .clock_rate = { + { 400000000, 400000000}, + { 400000000, 400000000} + }, + .reg = { "csid1" }, + .interrupt = { "csid1" }, + .csid = { + .is_lite = false, + .hw_ops = &csid_ops_gen3, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + + /* CSID2 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 400000000, 400000000, 0}, + { 0, 0, 400000000, 480000000, 0} + }, + .reg = { "csid_lite0" }, + .interrupt = { "csid_lite0" }, + .csid = { + .is_lite = true, + .hw_ops = &csid_ops_gen3, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + /* CSID3 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 400000000, 400000000, 0}, + { 0, 0, 400000000, 480000000, 0} + }, + .reg = { "csid_lite1" }, + .interrupt = { "csid_lite1" }, + .csid = { + .is_lite = true, + .hw_ops = &csid_ops_gen3, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + /* CSID4 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 400000000, 400000000, 0}, + { 0, 0, 400000000, 480000000, 0} + }, + .reg = { "csid_lite2" }, + .interrupt = { "csid_lite2" }, + .csid = { + .is_lite = true, + .hw_ops = &csid_ops_gen3, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + /* CSID5 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 400000000, 400000000, 0}, + { 0, 0, 400000000, 480000000, 0} + }, + .reg = { "csid_lite3" }, + .interrupt = { "csid_lite3" }, + .csid = { + .is_lite = true, + .hw_ops = &csid_ops_gen3, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, + /* CSID6 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 400000000, 400000000, 0}, + { 0, 0, 400000000, 480000000, 0} + }, + .reg = { "csid_lite4" }, + .interrupt = { "csid_lite4" }, + .csid = { + .is_lite = true, + .hw_ops = &csid_ops_gen3, + .parent_dev_ops = &vfe_parent_dev_ops, + .formats = &csid_formats_gen2 + } + }, +}; + +static const struct camss_subdev_resources vfe_res_8775p[] = { + /* VFE0 */ + { + .regulators = {}, + .clock = { "cpas_vfe0", "vfe0", "vfe0_fast_ahb", + "cpas_ahb", "gcc_axi_hf", + "cpas_fast_ahb_clk", + "camnoc_axi"}, + .clock_rate = { + { 0 }, + { 480000000 }, + { 300000000, 400000000 }, + { 300000000, 400000000 }, + { 0 }, + { 300000000, 400000000 }, + { 400000000 }, + }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" }, + .vfe = { + .line_num = 3, + .is_lite = false, + .has_pd = false, + .pd_name = NULL, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, + /* VFE1 */ + { + .regulators = {}, + .clock = { "cpas_vfe1", "vfe1", "vfe1_fast_ahb", + "cpas_ahb", "gcc_axi_hf", + "cpas_fast_ahb_clk", + "camnoc_axi"}, + .clock_rate = { + { 0 }, + { 480000000 }, + { 300000000, 400000000 }, + { 300000000, 400000000 }, + { 0 }, + { 300000000, 400000000 }, + { 400000000 }, + }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" }, + .vfe = { + .line_num = 3, + .is_lite = false, + .has_pd = false, + .pd_name = NULL, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, + /* VFE2 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 0, 0 }, + { 300000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 480000000, 600000000, 600000000, 600000000 }, + }, + .reg = { "vfe_lite0" }, + .interrupt = { "vfe_lite0" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, + /* VFE3 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 0, 0 }, + { 300000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 480000000, 600000000, 600000000, 600000000 }, + }, + .reg = { "vfe_lite1" }, + .interrupt = { "vfe_lite1" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, + /* VFE4 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 0, 0 }, + { 300000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 480000000, 600000000, 600000000, 600000000 }, + }, + .reg = { "vfe_lite2" }, + .interrupt = { "vfe_lite2" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, + /* VFE5 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 0, 0 }, + { 300000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 480000000, 600000000, 600000000, 600000000 }, + }, + .reg = { "vfe_lite3" }, + .interrupt = { "vfe_lite3" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, + /* VFE6 (lite) */ + { + .regulators = {}, + .clock = { "cpas_vfe_lite", "vfe_lite_ahb", + "vfe_lite_csid", "vfe_lite_cphy_rx", + "vfe_lite"}, + .clock_rate = { + { 0, 0, 0, 0 }, + { 300000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 400000000, 400000000, 400000000, 400000000 }, + { 480000000, 600000000, 600000000, 600000000 }, + }, + .reg = { "vfe_lite4" }, + .interrupt = { "vfe_lite4" }, + .vfe = { + .line_num = 4, + .is_lite = true, + .hw_ops = &vfe_ops_gen3, + .formats_rdi = &vfe_formats_rdi_845, + .formats_pix = &vfe_formats_pix_845 + } + }, +}; + +static const struct resources_icc icc_res_qcs8300[] = { + { + .name = "ahb", + .icc_bw_tbl.avg = 38400, + .icc_bw_tbl.peak = 76800, + }, + { + .name = "hf_0", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 2097152, + }, +}; + +static const struct resources_icc icc_res_sa8775p[] = { + { + .name = "ahb", + .icc_bw_tbl.avg = 38400, + .icc_bw_tbl.peak = 76800, + }, + { + .name = "hf_0", + .icc_bw_tbl.avg = 2097152, + .icc_bw_tbl.peak = 2097152, + }, +}; + static const struct camss_subdev_resources csiphy_res_x1e80100[] = { /* CSIPHY0 */ { @@ -3041,9 +4090,6 @@ static int camss_of_parse_ports(struct camss *camss) for_each_endpoint_of_node(dev->of_node, node) { struct camss_async_subdev *csd; - if (!of_device_is_available(node)) - continue; - remote = of_graph_get_remote_port_parent(node); if (!remote) { dev_err(dev, "Cannot get remote parent\n"); @@ -3143,7 +4189,6 @@ static int camss_init_subdevices(struct camss *camss) } /* - * camss_link_entities - Register subdev nodes and create links * camss_link_err - print error in case link creation fails * @src_name: name for source of the link * @sink_name: name for sink of the link @@ -3557,7 +4602,6 @@ static int camss_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct camss *camss; - int num_subdevs; int ret; camss = devm_kzalloc(dev, sizeof(*camss), GFP_KERNEL); @@ -3581,6 +4625,7 @@ static int camss_probe(struct platform_device *pdev) return -ENOMEM; if (camss->res->version == CAMSS_8x16 || + camss->res->version == CAMSS_8x39 || camss->res->version == CAMSS_8x53 || camss->res->version == CAMSS_8x96) { camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); @@ -3628,17 +4673,15 @@ static int camss_probe(struct platform_device *pdev) pm_runtime_enable(dev); - num_subdevs = camss_of_parse_ports(camss); - if (num_subdevs < 0) { - ret = num_subdevs; + ret = camss_of_parse_ports(camss); + if (ret < 0) goto err_v4l2_device_unregister; - } ret = camss_register_entities(camss); if (ret < 0) goto err_v4l2_device_unregister; - ret = camss->res->link_entities(camss); + ret = camss_link_entities(camss); if (ret < 0) goto err_register_subdevs; @@ -3648,23 +4691,12 @@ static int camss_probe(struct platform_device *pdev) goto err_register_subdevs; } - if (num_subdevs) { - camss->notifier.ops = &camss_subdev_notifier_ops; - - ret = v4l2_async_nf_register(&camss->notifier); - if (ret) { - dev_err(dev, - "Failed to register async subdev nodes: %d\n", - ret); - goto err_media_device_unregister; - } - } else { - ret = v4l2_device_register_subdev_nodes(&camss->v4l2_dev); - if (ret < 0) { - dev_err(dev, "Failed to register subdev nodes: %d\n", - ret); - goto err_media_device_unregister; - } + camss->notifier.ops = &camss_subdev_notifier_ops; + ret = v4l2_async_nf_register(&camss->notifier); + if (ret) { + dev_err(dev, + "Failed to register async subdev nodes: %d\n", ret); + goto err_media_device_unregister; } return 0; @@ -3723,7 +4755,17 @@ static const struct camss_resources msm8916_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_8x16), .csid_num = ARRAY_SIZE(csid_res_8x16), .vfe_num = ARRAY_SIZE(vfe_res_8x16), - .link_entities = camss_link_entities +}; + +static const struct camss_resources msm8939_resources = { + .version = CAMSS_8x39, + .csiphy_res = csiphy_res_8x39, + .csid_res = csid_res_8x39, + .ispif_res = &ispif_res_8x39, + .vfe_res = vfe_res_8x39, + .csiphy_num = ARRAY_SIZE(csiphy_res_8x39), + .csid_num = ARRAY_SIZE(csid_res_8x39), + .vfe_num = ARRAY_SIZE(vfe_res_8x39), }; static const struct camss_resources msm8953_resources = { @@ -3737,7 +4779,6 @@ static const struct camss_resources msm8953_resources = { .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 = { @@ -3749,7 +4790,46 @@ static const struct camss_resources msm8996_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_8x96), .csid_num = ARRAY_SIZE(csid_res_8x96), .vfe_num = ARRAY_SIZE(vfe_res_8x96), - .link_entities = camss_link_entities +}; + +static const struct camss_resources qcm2290_resources = { + .version = CAMSS_2290, + .csiphy_res = csiphy_res_2290, + .csid_res = csid_res_2290, + .vfe_res = vfe_res_2290, + .icc_res = icc_res_2290, + .icc_path_num = ARRAY_SIZE(icc_res_2290), + .csiphy_num = ARRAY_SIZE(csiphy_res_2290), + .csid_num = ARRAY_SIZE(csid_res_2290), + .vfe_num = ARRAY_SIZE(vfe_res_2290), +}; + +static const struct camss_resources qcs8300_resources = { + .version = CAMSS_8300, + .pd_name = "top", + .csiphy_res = csiphy_res_8300, + .csid_res = csid_res_8775p, + .csid_wrapper_res = &csid_wrapper_res_sm8550, + .vfe_res = vfe_res_8775p, + .icc_res = icc_res_qcs8300, + .csiphy_num = ARRAY_SIZE(csiphy_res_8300), + .csid_num = ARRAY_SIZE(csid_res_8775p), + .vfe_num = ARRAY_SIZE(vfe_res_8775p), + .icc_path_num = ARRAY_SIZE(icc_res_qcs8300), +}; + +static const struct camss_resources sa8775p_resources = { + .version = CAMSS_8775P, + .pd_name = "top", + .csiphy_res = csiphy_res_8775p, + .csid_res = csid_res_8775p, + .csid_wrapper_res = &csid_wrapper_res_sm8550, + .vfe_res = vfe_res_8775p, + .icc_res = icc_res_sa8775p, + .csiphy_num = ARRAY_SIZE(csiphy_res_8775p), + .csid_num = ARRAY_SIZE(csid_res_8775p), + .vfe_num = ARRAY_SIZE(vfe_res_8775p), + .icc_path_num = ARRAY_SIZE(icc_res_sa8775p), }; static const struct camss_resources sdm660_resources = { @@ -3761,7 +4841,6 @@ static const struct camss_resources sdm660_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_660), .csid_num = ARRAY_SIZE(csid_res_660), .vfe_num = ARRAY_SIZE(vfe_res_660), - .link_entities = camss_link_entities }; static const struct camss_resources sdm670_resources = { @@ -3772,7 +4851,6 @@ static const struct camss_resources sdm670_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_670), .csid_num = ARRAY_SIZE(csid_res_670), .vfe_num = ARRAY_SIZE(vfe_res_670), - .link_entities = camss_link_entities }; static const struct camss_resources sdm845_resources = { @@ -3784,7 +4862,6 @@ static const struct camss_resources sdm845_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_845), .csid_num = ARRAY_SIZE(csid_res_845), .vfe_num = ARRAY_SIZE(vfe_res_845), - .link_entities = camss_link_entities }; static const struct camss_resources sm8250_resources = { @@ -3798,7 +4875,6 @@ static const struct camss_resources sm8250_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_8250), .csid_num = ARRAY_SIZE(csid_res_8250), .vfe_num = ARRAY_SIZE(vfe_res_8250), - .link_entities = camss_link_entities }; static const struct camss_resources sc8280xp_resources = { @@ -3813,7 +4889,6 @@ static const struct camss_resources sc8280xp_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_sc8280xp), .csid_num = ARRAY_SIZE(csid_res_sc8280xp), .vfe_num = ARRAY_SIZE(vfe_res_sc8280xp), - .link_entities = camss_link_entities }; static const struct camss_resources sc7280_resources = { @@ -3827,7 +4902,6 @@ static const struct camss_resources sc7280_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_7280), .csid_num = ARRAY_SIZE(csid_res_7280), .vfe_num = ARRAY_SIZE(vfe_res_7280), - .link_entities = camss_link_entities }; static const struct camss_resources sm8550_resources = { @@ -3842,7 +4916,20 @@ static const struct camss_resources sm8550_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_8550), .csid_num = ARRAY_SIZE(csid_res_8550), .vfe_num = ARRAY_SIZE(vfe_res_8550), - .link_entities = camss_link_entities +}; + +static const struct camss_resources sm8650_resources = { + .version = CAMSS_8650, + .pd_name = "top", + .csiphy_res = csiphy_res_sm8650, + .csid_res = csid_res_sm8650, + .csid_wrapper_res = &csid_wrapper_res_sm8550, + .vfe_res = vfe_res_sm8650, + .icc_res = icc_res_sm8650, + .icc_path_num = ARRAY_SIZE(icc_res_sm8650), + .csiphy_num = ARRAY_SIZE(csiphy_res_sm8650), + .csid_num = ARRAY_SIZE(csid_res_sm8650), + .vfe_num = ARRAY_SIZE(vfe_res_sm8650), }; static const struct camss_resources x1e80100_resources = { @@ -3857,13 +4944,16 @@ static const struct camss_resources x1e80100_resources = { .csiphy_num = ARRAY_SIZE(csiphy_res_x1e80100), .csid_num = ARRAY_SIZE(csid_res_x1e80100), .vfe_num = ARRAY_SIZE(vfe_res_x1e80100), - .link_entities = camss_link_entities }; static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,msm8916-camss", .data = &msm8916_resources }, + { .compatible = "qcom,msm8939-camss", .data = &msm8939_resources }, { .compatible = "qcom,msm8953-camss", .data = &msm8953_resources }, { .compatible = "qcom,msm8996-camss", .data = &msm8996_resources }, + { .compatible = "qcom,qcm2290-camss", .data = &qcm2290_resources }, + { .compatible = "qcom,qcs8300-camss", .data = &qcs8300_resources }, + { .compatible = "qcom,sa8775p-camss", .data = &sa8775p_resources }, { .compatible = "qcom,sc7280-camss", .data = &sc7280_resources }, { .compatible = "qcom,sc8280xp-camss", .data = &sc8280xp_resources }, { .compatible = "qcom,sdm660-camss", .data = &sdm660_resources }, @@ -3871,6 +4961,7 @@ static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,sdm845-camss", .data = &sdm845_resources }, { .compatible = "qcom,sm8250-camss", .data = &sm8250_resources }, { .compatible = "qcom,sm8550-camss", .data = &sm8550_resources }, + { .compatible = "qcom,sm8650-camss", .data = &sm8650_resources }, { .compatible = "qcom,x1e80100-camss", .data = &x1e80100_resources }, { } }; @@ -3928,7 +5019,6 @@ static struct platform_driver qcom_camss_driver = { module_platform_driver(qcom_camss_driver); -MODULE_ALIAS("platform:qcom-camss"); MODULE_DESCRIPTION("Qualcomm Camera Subsystem driver"); MODULE_AUTHOR("Todor Tomov <todor.tomov@linaro.org>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 63c0afee154a..9d9a62640e25 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -41,6 +41,7 @@ (to_camss_index(ptr_module, index)->dev) #define CAMSS_RES_MAX 17 +#define CAMSS_INIT_BUF_COUNT 2 struct camss_subdev_resources { char *regulators[CAMSS_RES_MAX]; @@ -78,14 +79,19 @@ enum pm_domain { enum camss_version { CAMSS_660, + CAMSS_2290, CAMSS_7280, CAMSS_8x16, + CAMSS_8x39, CAMSS_8x53, CAMSS_8x96, CAMSS_8250, CAMSS_8280XP, + CAMSS_8300, CAMSS_845, CAMSS_8550, + CAMSS_8650, + CAMSS_8775P, CAMSS_X1E80100, }; @@ -107,7 +113,6 @@ struct camss_resources { const unsigned int csiphy_num; const unsigned int csid_num; const unsigned int vfe_num; - int (*link_entities)(struct camss *camss); }; struct camss { diff --git a/drivers/media/platform/qcom/iris/Makefile b/drivers/media/platform/qcom/iris/Makefile index e86d00ee6f15..fad3be044e5f 100644 --- a/drivers/media/platform/qcom/iris/Makefile +++ b/drivers/media/platform/qcom/iris/Makefile @@ -1,5 +1,5 @@ -qcom-iris-objs += \ - iris_buffer.o \ +qcom-iris-objs += iris_buffer.o \ + iris_common.o \ iris_core.o \ iris_ctrls.o \ iris_firmware.o \ @@ -19,13 +19,14 @@ qcom-iris-objs += \ iris_vidc.o \ iris_vb2.o \ iris_vdec.o \ + iris_venc.o \ iris_vpu2.o \ iris_vpu3x.o \ iris_vpu_buffer.o \ iris_vpu_common.o \ ifeq ($(CONFIG_VIDEO_QCOM_VENUS),) -qcom-iris-objs += iris_platform_sm8250.o +qcom-iris-objs += iris_platform_gen1.o endif obj-$(CONFIG_VIDEO_QCOM_IRIS) += qcom-iris.o diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c index 6425e4919e3b..b89b1ee06cce 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_buffer.c @@ -63,7 +63,12 @@ static u32 iris_yuv_buffer_size_nv12(struct iris_inst *inst) { u32 y_plane, uv_plane, y_stride, uv_stride, y_scanlines, uv_scanlines; - struct v4l2_format *f = inst->fmt_dst; + struct v4l2_format *f; + + if (inst->domain == DECODER) + f = inst->fmt_dst; + else + f = inst->fmt_src; y_stride = ALIGN(f->fmt.pix_mp.width, Y_STRIDE_ALIGN); uv_stride = ALIGN(f->fmt.pix_mp.width, UV_STRIDE_ALIGN); @@ -166,9 +171,14 @@ static u32 iris_yuv_buffer_size_nv12(struct iris_inst *inst) static u32 iris_yuv_buffer_size_qc08c(struct iris_inst *inst) { u32 y_plane, uv_plane, y_stride, uv_stride; - struct v4l2_format *f = inst->fmt_dst; u32 uv_meta_stride, uv_meta_plane; u32 y_meta_stride, y_meta_plane; + struct v4l2_format *f = NULL; + + if (inst->domain == DECODER) + f = inst->fmt_dst; + else + f = inst->fmt_src; y_meta_stride = ALIGN(DIV_ROUND_UP(f->fmt.pix_mp.width, META_STRIDE_ALIGNED >> 1), META_STRIDE_ALIGNED); @@ -194,7 +204,7 @@ static u32 iris_yuv_buffer_size_qc08c(struct iris_inst *inst) return ALIGN(y_meta_plane + y_plane + uv_meta_plane + uv_plane, PIXELS_4K); } -static u32 iris_bitstream_buffer_size(struct iris_inst *inst) +static u32 iris_dec_bitstream_buffer_size(struct iris_inst *inst) { struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; u32 base_res_mbs = NUM_MBS_4K; @@ -219,18 +229,64 @@ static u32 iris_bitstream_buffer_size(struct iris_inst *inst) return ALIGN(frame_size, PIXELS_4K); } +static u32 iris_enc_bitstream_buffer_size(struct iris_inst *inst) +{ + u32 aligned_width, aligned_height, bitstream_size, yuv_size; + int bitrate_mode, frame_rc; + struct v4l2_format *f; + + f = inst->fmt_dst; + + bitrate_mode = inst->fw_caps[BITRATE_MODE].value; + frame_rc = inst->fw_caps[FRAME_RC_ENABLE].value; + + aligned_width = ALIGN(f->fmt.pix_mp.width, 32); + aligned_height = ALIGN(f->fmt.pix_mp.height, 32); + bitstream_size = aligned_width * aligned_height * 3; + yuv_size = (aligned_width * aligned_height * 3) >> 1; + if (aligned_width * aligned_height > (4096 * 2176)) + /* bitstream_size = 0.25 * yuv_size; */ + bitstream_size = (bitstream_size >> 3); + else if (aligned_width * aligned_height > (1280 * 720)) + /* bitstream_size = 0.5 * yuv_size; */ + bitstream_size = (bitstream_size >> 2); + + if ((!frame_rc || bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) && + bitstream_size < yuv_size) + bitstream_size = (bitstream_size << 1); + + return ALIGN(bitstream_size, 4096); +} + int iris_get_buffer_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) { - switch (buffer_type) { - case BUF_INPUT: - return iris_bitstream_buffer_size(inst); - case BUF_OUTPUT: - return iris_yuv_buffer_size_nv12(inst); - case BUF_DPB: - return iris_yuv_buffer_size_qc08c(inst); - default: - return 0; + if (inst->domain == DECODER) { + switch (buffer_type) { + case BUF_INPUT: + return iris_dec_bitstream_buffer_size(inst); + case BUF_OUTPUT: + if (inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C) + return iris_yuv_buffer_size_qc08c(inst); + else + return iris_yuv_buffer_size_nv12(inst); + case BUF_DPB: + return iris_yuv_buffer_size_qc08c(inst); + default: + return 0; + } + } else { + switch (buffer_type) { + case BUF_INPUT: + if (inst->fmt_src->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C) + return iris_yuv_buffer_size_qc08c(inst); + else + return iris_yuv_buffer_size_nv12(inst); + case BUF_OUTPUT: + return iris_enc_bitstream_buffer_size(inst); + default: + return 0; + } } } @@ -239,7 +295,7 @@ static void iris_fill_internal_buf_info(struct iris_inst *inst, { struct iris_buffers *buffers = &inst->buffers[buffer_type]; - buffers->size = iris_vpu_buf_size(inst, buffer_type); + buffers->size = inst->core->iris_platform_data->get_vpu_buffer_size(inst, buffer_type); buffers->min_count = iris_vpu_buf_count(inst, buffer_type); } @@ -249,16 +305,30 @@ void iris_get_internal_buffers(struct iris_inst *inst, u32 plane) const u32 *internal_buf_type; u32 internal_buffer_count, i; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); + } else { + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); + } } else { - internal_buf_type = platform_data->dec_op_int_buf_tbl; - internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); + } else { + internal_buf_type = platform_data->enc_op_int_buf_tbl; + internal_buffer_count = platform_data->enc_op_int_buf_tbl_size; + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); + } } } @@ -299,12 +369,22 @@ int iris_create_internal_buffers(struct iris_inst *inst, u32 plane) const u32 *internal_buf_type; int ret; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + } } else { - internal_buf_type = platform_data->dec_op_int_buf_tbl; - internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->enc_op_int_buf_tbl; + internal_buffer_count = platform_data->enc_op_int_buf_tbl_size; + } } for (i = 0; i < internal_buffer_count; i++) { @@ -334,6 +414,29 @@ int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf) return 0; } +int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buffer_type) +{ + struct iris_buffer *buffer, *next; + struct iris_buffers *buffers; + int ret = 0; + + buffers = &inst->buffers[buffer_type]; + list_for_each_entry_safe(buffer, next, &buffers->list, list) { + if (buffer->attr & BUF_ATTR_PENDING_RELEASE) + continue; + if (buffer->attr & BUF_ATTR_QUEUED) + continue; + + if (buffer->attr & BUF_ATTR_DEFERRED) { + ret = iris_queue_buffer(inst, buffer); + if (ret) + return ret; + } + } + + return ret; +} + int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) { const struct iris_platform_data *platform_data = inst->core->iris_platform_data; @@ -343,12 +446,22 @@ int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) u32 internal_buffer_count, i; int ret; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->dec_op_int_buf_tbl; + internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + } } else { - internal_buf_type = platform_data->dec_op_int_buf_tbl; - internal_buffer_count = platform_data->dec_op_int_buf_tbl_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->enc_op_int_buf_tbl; + internal_buffer_count = platform_data->enc_op_int_buf_tbl_size; + } } for (i = 0; i < internal_buffer_count; i++) { @@ -358,6 +471,10 @@ int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) continue; if (buffer->attr & BUF_ATTR_QUEUED) continue; + if (buffer->type == BUF_DPB && inst->state != IRIS_INST_STREAMING) { + buffer->attr |= BUF_ATTR_DEFERRED; + continue; + } ret = iris_queue_buffer(inst, buffer); if (ret) return ret; @@ -388,12 +505,22 @@ static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool u32 i, len; int ret; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - len = platform_data->dec_ip_int_buf_tbl_size; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + len = platform_data->dec_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->dec_op_int_buf_tbl; + len = platform_data->dec_op_int_buf_tbl_size; + } } else { - internal_buf_type = platform_data->dec_op_int_buf_tbl; - len = platform_data->dec_op_int_buf_tbl_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + len = platform_data->enc_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->enc_op_int_buf_tbl; + len = platform_data->enc_op_int_buf_tbl_size; + } } for (i = 0; i < len; i++) { @@ -413,6 +540,19 @@ static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool } } + if (force) { + if (inst->domain == DECODER) + buffers = &inst->buffers[BUF_PERSIST]; + else + buffers = &inst->buffers[BUF_ARP]; + + list_for_each_entry_safe(buf, next, &buffers->list, list) { + ret = iris_destroy_internal_buffer(inst, buf); + if (ret) + return ret; + } + } + return 0; } @@ -455,8 +595,13 @@ static int iris_release_input_internal_buffers(struct iris_inst *inst) u32 internal_buffer_count, i; int ret; - internal_buf_type = platform_data->dec_ip_int_buf_tbl; - internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + if (inst->domain == DECODER) { + internal_buf_type = platform_data->dec_ip_int_buf_tbl; + internal_buffer_count = platform_data->dec_ip_int_buf_tbl_size; + } else { + internal_buf_type = platform_data->enc_ip_int_buf_tbl; + internal_buffer_count = platform_data->enc_ip_int_buf_tbl_size; + } for (i = 0; i < internal_buffer_count; i++) { ret = iris_release_internal_buffers(inst, internal_buf_type[i]); @@ -467,9 +612,9 @@ static int iris_release_input_internal_buffers(struct iris_inst *inst) return 0; } -int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst) +int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst, enum iris_buffer_type buffer_type) { - struct iris_buffers *buffers = &inst->buffers[BUF_PERSIST]; + struct iris_buffers *buffers = &inst->buffers[buffer_type]; struct iris_buffer *buffer, *next; int ret; u32 i; @@ -477,10 +622,10 @@ int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst) if (!list_empty(&buffers->list)) return 0; - iris_fill_internal_buf_info(inst, BUF_PERSIST); + iris_fill_internal_buf_info(inst, buffer_type); for (i = 0; i < buffers->min_count; i++) { - ret = iris_create_internal_buffer(inst, BUF_PERSIST, i); + ret = iris_create_internal_buffer(inst, buffer_type, i); if (ret) return ret; } @@ -614,6 +759,8 @@ int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) vb2 = &vbuf->vb2_buf; + vbuf->flags |= buf->flags; + if (buf->flags & V4L2_BUF_FLAG_ERROR) { state = VB2_BUF_STATE_ERROR; vb2_set_plane_payload(vb2, 0, 0); @@ -622,8 +769,6 @@ int iris_vb2_buffer_done(struct iris_inst *inst, struct iris_buffer *buf) return 0; } - vbuf->flags |= buf->flags; - if (V4L2_TYPE_IS_CAPTURE(type)) { vb2_set_plane_payload(vb2, 0, buf->data_size); vbuf->sequence = inst->sequence_cap++; diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h index 00825ad2dc3a..325d30fce5c9 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.h +++ b/drivers/media/platform/qcom/iris/iris_buffer.h @@ -25,6 +25,8 @@ struct iris_inst; * @BUF_DPB: buffer to store display picture buffers for reference * @BUF_PERSIST: buffer to store session context data * @BUF_SCRATCH_1: buffer to store decoding/encoding context data for HW + * @BUF_SCRATCH_2: buffer to store encoding context data for HW + * @BUF_VPSS: buffer to store VPSS context data for HW * @BUF_TYPE_MAX: max buffer types */ enum iris_buffer_type { @@ -38,6 +40,8 @@ enum iris_buffer_type { BUF_DPB, BUF_PERSIST, BUF_SCRATCH_1, + BUF_SCRATCH_2, + BUF_VPSS, BUF_TYPE_MAX, }; @@ -105,10 +109,11 @@ int iris_get_buffer_size(struct iris_inst *inst, enum iris_buffer_type buffer_ty void iris_get_internal_buffers(struct iris_inst *inst, u32 plane); int iris_create_internal_buffers(struct iris_inst *inst, u32 plane); int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane); +int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buffer_type); int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer); int iris_destroy_all_internal_buffers(struct iris_inst *inst, u32 plane); int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane); -int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst); +int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst, enum iris_buffer_type buf_type); int iris_alloc_and_queue_input_int_bufs(struct iris_inst *inst); int iris_queue_buffer(struct iris_inst *inst, struct iris_buffer *buf); int iris_queue_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buf_type); diff --git a/drivers/media/platform/qcom/iris/iris_common.c b/drivers/media/platform/qcom/iris/iris_common.c new file mode 100644 index 000000000000..7f1c7fe144f7 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_common.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <media/v4l2-mem2mem.h> + +#include "iris_common.h" +#include "iris_ctrls.h" +#include "iris_instance.h" +#include "iris_power.h" + +int iris_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); + + buf->type = iris_v4l2_type_to_driver(vb2->type); + buf->index = vb2->index; + buf->fd = vb2->planes[0].m.fd; + buf->buffer_size = vb2->planes[0].length; + buf->data_offset = vb2->planes[0].data_offset; + buf->data_size = vb2->planes[0].bytesused - vb2->planes[0].data_offset; + buf->flags = vbuf->flags; + buf->timestamp = vb2->timestamp; + buf->attr = 0; + + return 0; +} + +void iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) +{ + u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + struct vb2_buffer *vb = &vbuf->vb2_buf; + u64 ts_us = vb->timestamp; + + if (inst->metadata_idx >= ARRAY_SIZE(inst->tss)) + inst->metadata_idx = 0; + + do_div(ts_us, NSEC_PER_USEC); + + inst->tss[inst->metadata_idx].flags = vbuf->flags & mask; + inst->tss[inst->metadata_idx].tc = vbuf->timecode; + inst->tss[inst->metadata_idx].ts_us = ts_us; + inst->tss[inst->metadata_idx].ts_ns = vb->timestamp; + + inst->metadata_idx++; +} + +int iris_process_streamon_input(struct iris_inst *inst) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + enum iris_inst_sub_state set_sub_state = 0; + int ret; + + iris_scale_power(inst); + + ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { + ret = iris_inst_change_sub_state(inst, IRIS_INST_SUB_INPUT_PAUSE, 0); + if (ret) + return ret; + } + + if (inst->domain == DECODER && + (inst->sub_state & IRIS_INST_SUB_DRC || + inst->sub_state & IRIS_INST_SUB_DRAIN || + inst->sub_state & IRIS_INST_SUB_FIRST_IPSC)) { + if (!(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE)) { + if (hfi_ops->session_pause) { + ret = hfi_ops->session_pause(inst, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + } + set_sub_state = IRIS_INST_SUB_INPUT_PAUSE; + } + } + + ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + inst->last_buffer_dequeued = false; + + return iris_inst_change_sub_state(inst, 0, set_sub_state); +} + +int iris_process_streamon_output(struct iris_inst *inst) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + enum iris_inst_sub_state clear_sub_state = 0; + bool drain_active, drc_active, first_ipsc; + int ret = 0; + + iris_scale_power(inst); + + first_ipsc = inst->sub_state & IRIS_INST_SUB_FIRST_IPSC; + + drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN && + inst->sub_state & IRIS_INST_SUB_DRAIN_LAST; + + drc_active = inst->sub_state & IRIS_INST_SUB_DRC && + inst->sub_state & IRIS_INST_SUB_DRC_LAST; + + if (drc_active) + clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST; + else if (drain_active) + clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; + + /* Input internal buffer reconfiguration required in case of resolution change */ + if (first_ipsc || drc_active) { + ret = iris_alloc_and_queue_input_int_bufs(inst); + if (ret) + return ret; + ret = iris_set_stage(inst, STAGE); + if (ret) + return ret; + ret = iris_set_pipe(inst, PIPE); + if (ret) + return ret; + } + + if (inst->state == IRIS_INST_INPUT_STREAMING && + inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { + if (!drain_active) + ret = hfi_ops->session_resume_drc(inst, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + else if (hfi_ops->session_resume_drain) + ret = hfi_ops->session_resume_drain(inst, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE; + } + + if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC) + clear_sub_state |= IRIS_INST_SUB_FIRST_IPSC; + + ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + return ret; + + if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) + clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE; + + ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + return ret; + + inst->last_buffer_dequeued = false; + + return iris_inst_change_sub_state(inst, clear_sub_state, 0); +} + +static void iris_flush_deferred_buffers(struct iris_inst *inst, + enum iris_buffer_type type) +{ + struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; + struct v4l2_m2m_buffer *buffer, *n; + struct iris_buffer *buf; + + if (type == BUF_INPUT) { + v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) { + buf = to_iris_buffer(&buffer->vb); + if (buf->attr & BUF_ATTR_DEFERRED) { + if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { + buf->attr |= BUF_ATTR_BUFFER_DONE; + buf->data_size = 0; + iris_vb2_buffer_done(inst, buf); + } + } + } + } else { + v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { + buf = to_iris_buffer(&buffer->vb); + if (buf->attr & BUF_ATTR_DEFERRED) { + if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { + buf->attr |= BUF_ATTR_BUFFER_DONE; + buf->data_size = 0; + iris_vb2_buffer_done(inst, buf); + } + } + } + } +} + +static void iris_kill_session(struct iris_inst *inst) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + + if (!inst->session_id) + return; + + hfi_ops->session_close(inst); + iris_inst_change_state(inst, IRIS_INST_ERROR); +} + +int iris_session_streamoff(struct iris_inst *inst, u32 plane) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + enum iris_buffer_type buffer_type; + int ret; + + switch (plane) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + buffer_type = BUF_INPUT; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + buffer_type = BUF_OUTPUT; + break; + default: + return -EINVAL; + } + + ret = hfi_ops->session_stop(inst, plane); + if (ret) + goto error; + + ret = iris_inst_state_change_streamoff(inst, plane); + if (ret) + goto error; + + iris_flush_deferred_buffers(inst, buffer_type); + + return 0; + +error: + iris_kill_session(inst); + iris_flush_deferred_buffers(inst, buffer_type); + + return ret; +} diff --git a/drivers/media/platform/qcom/iris/iris_common.h b/drivers/media/platform/qcom/iris/iris_common.h new file mode 100644 index 000000000000..b2a27b781c9a --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_common.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __IRIS_COMMON_H__ +#define __IRIS_COMMON_H__ + +struct iris_inst; +struct iris_buffer; + +int iris_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf); +void iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); +int iris_process_streamon_input(struct iris_inst *inst); +int iris_process_streamon_output(struct iris_inst *inst); +int iris_session_streamoff(struct iris_inst *inst, u32 plane); + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c index 0fa0a3b549a2..8406c48d635b 100644 --- a/drivers/media/platform/qcom/iris/iris_core.c +++ b/drivers/media/platform/qcom/iris/iris_core.c @@ -15,10 +15,12 @@ void iris_core_deinit(struct iris_core *core) pm_runtime_resume_and_get(core->dev); mutex_lock(&core->lock); - iris_fw_unload(core); - iris_vpu_power_off(core); - iris_hfi_queues_deinit(core); - core->state = IRIS_CORE_DEINIT; + if (core->state != IRIS_CORE_DEINIT) { + iris_fw_unload(core); + iris_vpu_power_off(core); + iris_hfi_queues_deinit(core); + core->state = IRIS_CORE_DEINIT; + } mutex_unlock(&core->lock); pm_runtime_put_sync(core->dev); diff --git a/drivers/media/platform/qcom/iris/iris_core.h b/drivers/media/platform/qcom/iris/iris_core.h index aeeac32a1f6d..fb194c967ad4 100644 --- a/drivers/media/platform/qcom/iris/iris_core.h +++ b/drivers/media/platform/qcom/iris/iris_core.h @@ -25,6 +25,11 @@ struct icc_info { #define IRIS_FW_VERSION_LENGTH 128 #define IFACEQ_CORE_PKT_SIZE (1024 * 4) +enum domain_type { + ENCODER = BIT(0), + DECODER = BIT(1), +}; + /** * struct iris_core - holds core parameters valid for all instances * @@ -33,8 +38,10 @@ struct icc_info { * @irq: iris irq * @v4l2_dev: a holder for v4l2 device structure * @vdev_dec: iris video device structure for decoder + * @vdev_enc: iris video device structure for encoder * @iris_v4l2_file_ops: iris v4l2 file ops - * @iris_v4l2_ioctl_ops: iris v4l2 ioctl ops + * @iris_v4l2_ioctl_ops_dec: iris v4l2 ioctl ops for decoder + * @iris_v4l2_ioctl_ops_enc: iris v4l2 ioctl ops for encoder * @iris_vb2_ops: iris vb2 ops * @icc_tbl: table of iris interconnects * @icc_count: count of iris interconnects @@ -64,7 +71,8 @@ struct icc_info { * @intr_status: interrupt status * @sys_error_handler: a delayed work for handling system fatal error * @instances: a list_head of all instances - * @inst_fw_caps: an array of supported instance capabilities + * @inst_fw_caps_dec: an array of supported instance capabilities by decoder + * @inst_fw_caps_enc: an array of supported instance capabilities by encoder */ struct iris_core { @@ -73,8 +81,10 @@ struct iris_core { int irq; struct v4l2_device v4l2_dev; struct video_device *vdev_dec; + struct video_device *vdev_enc; const struct v4l2_file_operations *iris_v4l2_file_ops; - const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops; + const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops_dec; + const struct v4l2_ioctl_ops *iris_v4l2_ioctl_ops_enc; const struct vb2_ops *iris_vb2_ops; struct icc_bulk_data *icc_tbl; u32 icc_count; @@ -104,7 +114,9 @@ struct iris_core { u32 intr_status; struct delayed_work sys_error_handler; struct list_head instances; - struct platform_inst_fw_cap inst_fw_caps[INST_FW_CAP_MAX]; + /* encoder and decoder have overlapping caps, so two different arrays are required */ + struct platform_inst_fw_cap inst_fw_caps_dec[INST_FW_CAP_MAX]; + struct platform_inst_fw_cap inst_fw_caps_enc[INST_FW_CAP_MAX]; }; int iris_core_init(struct iris_core *core); diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c index 9136b723c0f2..c0b3a09ad3e3 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.c +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c @@ -7,8 +7,13 @@ #include <media/v4l2-mem2mem.h> #include "iris_ctrls.h" +#include "iris_hfi_gen1_defines.h" +#include "iris_hfi_gen2_defines.h" #include "iris_instance.h" +#define CABAC_MAX_BITRATE 160000000 +#define CAVLC_MAX_BITRATE 220000000 + static inline bool iris_valid_cap_id(enum platform_inst_fw_cap_type cap_id) { return cap_id >= 1 && cap_id < INST_FW_CAP_MAX; @@ -31,6 +36,68 @@ static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) return LEVEL_VP9; case V4L2_CID_MPEG_VIDEO_HEVC_TIER: return TIER; + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + return HEADER_MODE; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + return PREPEND_SPSPPS_TO_IDR; + case V4L2_CID_MPEG_VIDEO_BITRATE: + return BITRATE; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + return BITRATE_PEAK; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + return BITRATE_MODE; + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: + return FRAME_SKIP_MODE; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + return FRAME_RC_ENABLE; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + return GOP_SIZE; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + return ENTROPY_MODE; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + return MIN_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + return MIN_FRAME_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + return MAX_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + return MAX_FRAME_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP: + return I_FRAME_MIN_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP: + return I_FRAME_MIN_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: + return P_FRAME_MIN_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP: + return P_FRAME_MIN_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP: + return B_FRAME_MIN_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP: + return B_FRAME_MIN_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: + return I_FRAME_MAX_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP: + return I_FRAME_MAX_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: + return P_FRAME_MAX_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP: + return P_FRAME_MAX_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP: + return B_FRAME_MAX_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP: + return B_FRAME_MAX_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: + return I_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + return I_FRAME_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: + return P_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: + return P_FRAME_QP_HEVC; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: + return B_FRAME_QP_H264; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: + return B_FRAME_QP_HEVC; default: return INST_FW_CAP_MAX; } @@ -56,12 +123,74 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) return V4L2_CID_MPEG_VIDEO_VP9_LEVEL; case TIER: return V4L2_CID_MPEG_VIDEO_HEVC_TIER; + case HEADER_MODE: + return V4L2_CID_MPEG_VIDEO_HEADER_MODE; + case PREPEND_SPSPPS_TO_IDR: + return V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR; + case BITRATE: + return V4L2_CID_MPEG_VIDEO_BITRATE; + case BITRATE_PEAK: + return V4L2_CID_MPEG_VIDEO_BITRATE_PEAK; + case BITRATE_MODE: + return V4L2_CID_MPEG_VIDEO_BITRATE_MODE; + case FRAME_SKIP_MODE: + return V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE; + case FRAME_RC_ENABLE: + return V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE; + case GOP_SIZE: + return V4L2_CID_MPEG_VIDEO_GOP_SIZE; + case ENTROPY_MODE: + return V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE; + case MIN_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_MIN_QP; + case MIN_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP; + case MAX_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_MAX_QP; + case MAX_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP; + case I_FRAME_MIN_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP; + case I_FRAME_MIN_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP; + case P_FRAME_MIN_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP; + case P_FRAME_MIN_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP; + case B_FRAME_MIN_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP; + case B_FRAME_MIN_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP; + case I_FRAME_MAX_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP; + case I_FRAME_MAX_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP; + case P_FRAME_MAX_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP; + case P_FRAME_MAX_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP; + case B_FRAME_MAX_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP; + case B_FRAME_MAX_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP; + case I_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP; + case I_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP; + case P_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP; + case P_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP; + case B_FRAME_QP_H264: + return V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP; + case B_FRAME_QP_HEVC: + return V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP; default: return 0; } } -static int iris_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) +static int iris_op_s_ctrl(struct v4l2_ctrl *ctrl) { struct iris_inst *inst = container_of(ctrl->handler, struct iris_inst, ctrl_handler); enum platform_inst_fw_cap_type cap_id; @@ -82,11 +211,16 @@ static int iris_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) inst->fw_caps[cap_id].value = ctrl->val; + if (vb2_is_streaming(q)) { + if (cap[cap_id].set) + cap[cap_id].set(inst, cap_id); + } + return 0; } static const struct v4l2_ctrl_ops iris_ctrl_ops = { - .s_ctrl = iris_vdec_op_s_ctrl, + .s_ctrl = iris_op_s_ctrl, }; int iris_ctrls_init(struct iris_inst *inst) @@ -101,7 +235,10 @@ int iris_ctrls_init(struct iris_inst *inst) num_ctrls++; } - /* Adding 1 to num_ctrls to include V4L2_CID_MIN_BUFFERS_FOR_CAPTURE */ + /* Adding 1 to num_ctrls to include + * V4L2_CID_MIN_BUFFERS_FOR_CAPTURE for decoder and + * V4L2_CID_MIN_BUFFERS_FOR_OUTPUT for encoder + */ ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls + 1); if (ret) @@ -143,8 +280,13 @@ int iris_ctrls_init(struct iris_inst *inst) ctrl_idx++; } - v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, - V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 4); + if (inst->domain == DECODER) { + v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 4); + } else { + v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 4); + } ret = inst->ctrl_handler.error; if (ret) @@ -159,35 +301,70 @@ error: void iris_session_init_caps(struct iris_core *core) { - struct platform_inst_fw_cap *caps; + const struct platform_inst_fw_cap *caps; u32 i, num_cap, cap_id; - caps = core->iris_platform_data->inst_fw_caps; - num_cap = core->iris_platform_data->inst_fw_caps_size; + caps = core->iris_platform_data->inst_fw_caps_dec; + num_cap = core->iris_platform_data->inst_fw_caps_dec_size; for (i = 0; i < num_cap; i++) { cap_id = caps[i].cap_id; if (!iris_valid_cap_id(cap_id)) continue; - core->inst_fw_caps[cap_id].cap_id = caps[i].cap_id; - core->inst_fw_caps[cap_id].min = caps[i].min; - core->inst_fw_caps[cap_id].max = caps[i].max; - core->inst_fw_caps[cap_id].step_or_mask = caps[i].step_or_mask; - core->inst_fw_caps[cap_id].value = caps[i].value; - core->inst_fw_caps[cap_id].flags = caps[i].flags; - core->inst_fw_caps[cap_id].hfi_id = caps[i].hfi_id; - core->inst_fw_caps[cap_id].set = caps[i].set; + core->inst_fw_caps_dec[cap_id].cap_id = caps[i].cap_id; + core->inst_fw_caps_dec[cap_id].step_or_mask = caps[i].step_or_mask; + core->inst_fw_caps_dec[cap_id].flags = caps[i].flags; + core->inst_fw_caps_dec[cap_id].hfi_id = caps[i].hfi_id; + core->inst_fw_caps_dec[cap_id].set = caps[i].set; + + if (cap_id == PIPE) { + core->inst_fw_caps_dec[cap_id].value = + core->iris_platform_data->num_vpp_pipe; + core->inst_fw_caps_dec[cap_id].min = + core->iris_platform_data->num_vpp_pipe; + core->inst_fw_caps_dec[cap_id].max = + core->iris_platform_data->num_vpp_pipe; + } else { + core->inst_fw_caps_dec[cap_id].min = caps[i].min; + core->inst_fw_caps_dec[cap_id].max = caps[i].max; + core->inst_fw_caps_dec[cap_id].value = caps[i].value; + } + } + + caps = core->iris_platform_data->inst_fw_caps_enc; + num_cap = core->iris_platform_data->inst_fw_caps_enc_size; + + for (i = 0; i < num_cap; i++) { + cap_id = caps[i].cap_id; + if (!iris_valid_cap_id(cap_id)) + continue; + + core->inst_fw_caps_enc[cap_id].cap_id = caps[i].cap_id; + core->inst_fw_caps_enc[cap_id].min = caps[i].min; + core->inst_fw_caps_enc[cap_id].max = caps[i].max; + core->inst_fw_caps_enc[cap_id].step_or_mask = caps[i].step_or_mask; + core->inst_fw_caps_enc[cap_id].value = caps[i].value; + core->inst_fw_caps_enc[cap_id].flags = caps[i].flags; + core->inst_fw_caps_enc[cap_id].hfi_id = caps[i].hfi_id; + core->inst_fw_caps_enc[cap_id].set = caps[i].set; } } static u32 iris_get_port_info(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { - if (inst->fw_caps[cap_id].flags & CAP_FLAG_INPUT_PORT) - return HFI_PORT_BITSTREAM; - else if (inst->fw_caps[cap_id].flags & CAP_FLAG_OUTPUT_PORT) - return HFI_PORT_RAW; + if (inst->domain == DECODER) { + if (inst->fw_caps[cap_id].flags & CAP_FLAG_INPUT_PORT) + return HFI_PORT_BITSTREAM; + else if (inst->fw_caps[cap_id].flags & CAP_FLAG_OUTPUT_PORT) + return HFI_PORT_RAW; + } else { + if (inst->fw_caps[cap_id].flags & CAP_FLAG_INPUT_PORT) + return HFI_PORT_RAW; + else if (inst->fw_caps[cap_id].flags & CAP_FLAG_OUTPUT_PORT) + return HFI_PORT_BITSTREAM; + } return HFI_PORT_NONE; } @@ -227,8 +404,10 @@ int iris_set_stage(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id u32 width = inp_f->fmt.pix_mp.width; u32 work_mode = STAGE_2; - if (iris_res_is_less_than(width, height, 1280, 720)) - work_mode = STAGE_1; + if (inst->domain == DECODER) { + if (iris_res_is_less_than(width, height, 1280, 720)) + work_mode = STAGE_1; + } return hfi_ops->session_set_property(inst, hfi_id, HFI_HOST_FLAGS_NONE, @@ -250,6 +429,470 @@ int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) &work_route, sizeof(u32)); } +int iris_set_profile(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 hfi_id, hfi_value; + + if (inst->codec == V4L2_PIX_FMT_H264) { + hfi_id = inst->fw_caps[PROFILE_H264].hfi_id; + hfi_value = inst->fw_caps[PROFILE_H264].value; + } else { + hfi_id = inst->fw_caps[PROFILE_HEVC].hfi_id; + hfi_value = inst->fw_caps[PROFILE_HEVC].value; + } + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32)); +} + +int iris_set_level(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 hfi_id, hfi_value; + + if (inst->codec == V4L2_PIX_FMT_H264) { + hfi_id = inst->fw_caps[LEVEL_H264].hfi_id; + hfi_value = inst->fw_caps[LEVEL_H264].value; + } else { + hfi_id = inst->fw_caps[LEVEL_HEVC].hfi_id; + hfi_value = inst->fw_caps[LEVEL_HEVC].value; + } + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32)); +} + +int iris_set_profile_level_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + struct hfi_profile_level pl; + + if (inst->codec == V4L2_PIX_FMT_H264) { + pl.profile = inst->fw_caps[PROFILE_H264].value; + pl.level = inst->fw_caps[LEVEL_H264].value; + } else { + pl.profile = inst->fw_caps[PROFILE_HEVC].value; + pl.level = inst->fw_caps[LEVEL_HEVC].value; + } + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &pl, sizeof(u32)); +} + +int iris_set_header_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 header_mode = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (header_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) + hfi_val = 0; + else + hfi_val = 1; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &hfi_val, sizeof(u32)); +} + +int iris_set_header_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 prepend_sps_pps = inst->fw_caps[PREPEND_SPSPPS_TO_IDR].value; + u32 header_mode = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (prepend_sps_pps) + hfi_val = HFI_SEQ_HEADER_PREFIX_WITH_SYNC_FRAME; + else if (header_mode == V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME) + hfi_val = HFI_SEQ_HEADER_JOINED_WITH_1ST_FRAME; + else + hfi_val = HFI_SEQ_HEADER_SEPERATE_FRAME; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &hfi_val, sizeof(u32)); +} + +int iris_set_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 entropy_mode = inst->fw_caps[ENTROPY_MODE].value; + u32 bitrate = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 max_bitrate; + + if (inst->codec == V4L2_PIX_FMT_HEVC) + max_bitrate = CABAC_MAX_BITRATE; + + if (entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) + max_bitrate = CABAC_MAX_BITRATE; + else + max_bitrate = CAVLC_MAX_BITRATE; + + bitrate = min(bitrate, max_bitrate); + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &bitrate, sizeof(u32)); +} + +int iris_set_peak_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 rc_mode = inst->fw_caps[BITRATE_MODE].value; + u32 peak_bitrate = inst->fw_caps[cap_id].value; + u32 bitrate = inst->fw_caps[BITRATE].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + + if (rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + return 0; + + if (inst->fw_caps[cap_id].flags & CAP_FLAG_CLIENT_SET) { + if (peak_bitrate < bitrate) + peak_bitrate = bitrate; + } else { + peak_bitrate = bitrate; + } + + inst->fw_caps[cap_id].value = peak_bitrate; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &peak_bitrate, sizeof(u32)); +} + +int iris_set_bitrate_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 bitrate_mode = inst->fw_caps[BITRATE_MODE].value; + u32 frame_rc = inst->fw_caps[FRAME_RC_ENABLE].value; + u32 frame_skip = inst->fw_caps[FRAME_SKIP_MODE].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 rc_mode = 0; + + if (!frame_rc) + rc_mode = HFI_RATE_CONTROL_OFF; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + rc_mode = frame_skip ? HFI_RATE_CONTROL_VBR_VFR : HFI_RATE_CONTROL_VBR_CFR; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + rc_mode = frame_skip ? HFI_RATE_CONTROL_CBR_VFR : HFI_RATE_CONTROL_CBR_CFR; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + rc_mode = HFI_RATE_CONTROL_CQ; + + inst->hfi_rc_type = rc_mode; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &rc_mode, sizeof(u32)); +} + +int iris_set_bitrate_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 bitrate_mode = inst->fw_caps[BITRATE_MODE].value; + u32 frame_rc = inst->fw_caps[FRAME_RC_ENABLE].value; + u32 frame_skip = inst->fw_caps[FRAME_SKIP_MODE].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 rc_mode = 0; + + if (!frame_rc) + rc_mode = HFI_RC_OFF; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) + rc_mode = HFI_RC_VBR_CFR; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) + rc_mode = frame_skip ? HFI_RC_CBR_VFR : HFI_RC_CBR_CFR; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + rc_mode = HFI_RC_CQ; + + inst->hfi_rc_type = rc_mode; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &rc_mode, sizeof(u32)); +} + +int iris_set_entropy_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 entropy_mode = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (inst->codec != V4L2_PIX_FMT_H264) + return 0; + + hfi_val = (entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) ? + HFI_H264_ENTROPY_CAVLC : HFI_H264_ENTROPY_CABAC; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &hfi_val, sizeof(u32)); +} + +int iris_set_entropy_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 entropy_mode = inst->fw_caps[cap_id].value; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 profile; + + if (inst->codec != V4L2_PIX_FMT_H264) + return 0; + + profile = inst->fw_caps[PROFILE_H264].value; + + if (profile == V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE || + profile == V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) + entropy_mode = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC; + + inst->fw_caps[cap_id].value = entropy_mode; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &entropy_mode, sizeof(u32)); +} + +int iris_set_min_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0; + u32 i_frame_qp = 0, p_frame_qp = 0, b_frame_qp = 0; + u32 min_qp_enable = 0, client_qp_enable = 0; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (inst->codec == V4L2_PIX_FMT_H264) { + if (inst->fw_caps[MIN_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + min_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[I_FRAME_MIN_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[P_FRAME_MIN_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[B_FRAME_MIN_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + } else { + if (inst->fw_caps[MIN_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + min_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[I_FRAME_MIN_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[P_FRAME_MIN_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (min_qp_enable || + (inst->fw_caps[B_FRAME_MIN_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + } + + client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2; + if (!client_qp_enable) + return 0; + + if (inst->codec == V4L2_PIX_FMT_H264) { + i_frame_qp = max(inst->fw_caps[I_FRAME_MIN_QP_H264].value, + inst->fw_caps[MIN_FRAME_QP_H264].value); + p_frame_qp = max(inst->fw_caps[P_FRAME_MIN_QP_H264].value, + inst->fw_caps[MIN_FRAME_QP_H264].value); + b_frame_qp = max(inst->fw_caps[B_FRAME_MIN_QP_H264].value, + inst->fw_caps[MIN_FRAME_QP_H264].value); + } else { + i_frame_qp = max(inst->fw_caps[I_FRAME_MIN_QP_HEVC].value, + inst->fw_caps[MIN_FRAME_QP_HEVC].value); + p_frame_qp = max(inst->fw_caps[P_FRAME_MIN_QP_HEVC].value, + inst->fw_caps[MIN_FRAME_QP_HEVC].value); + b_frame_qp = max(inst->fw_caps[B_FRAME_MIN_QP_HEVC].value, + inst->fw_caps[MIN_FRAME_QP_HEVC].value); + } + + hfi_val = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 | client_qp_enable << 24; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_32_PACKED, + &hfi_val, sizeof(u32)); +} + +int iris_set_max_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0; + u32 max_qp_enable = 0, client_qp_enable; + u32 i_frame_qp, p_frame_qp, b_frame_qp; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val; + + if (inst->codec == V4L2_PIX_FMT_H264) { + if (inst->fw_caps[MAX_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + max_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[I_FRAME_MAX_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[P_FRAME_MAX_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[B_FRAME_MAX_QP_H264].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + } else { + if (inst->fw_caps[MAX_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + max_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[I_FRAME_MAX_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[P_FRAME_MAX_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (max_qp_enable || + (inst->fw_caps[B_FRAME_MAX_QP_HEVC].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + } + + client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2; + if (!client_qp_enable) + return 0; + + if (inst->codec == V4L2_PIX_FMT_H264) { + i_frame_qp = min(inst->fw_caps[I_FRAME_MAX_QP_H264].value, + inst->fw_caps[MAX_FRAME_QP_H264].value); + p_frame_qp = min(inst->fw_caps[P_FRAME_MAX_QP_H264].value, + inst->fw_caps[MAX_FRAME_QP_H264].value); + b_frame_qp = min(inst->fw_caps[B_FRAME_MAX_QP_H264].value, + inst->fw_caps[MAX_FRAME_QP_H264].value); + } else { + i_frame_qp = min(inst->fw_caps[I_FRAME_MAX_QP_HEVC].value, + inst->fw_caps[MAX_FRAME_QP_HEVC].value); + p_frame_qp = min(inst->fw_caps[P_FRAME_MAX_QP_HEVC].value, + inst->fw_caps[MAX_FRAME_QP_HEVC].value); + b_frame_qp = min(inst->fw_caps[B_FRAME_MAX_QP_HEVC].value, + inst->fw_caps[MAX_FRAME_QP_HEVC].value); + } + + hfi_val = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 | + client_qp_enable << 24; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_32_PACKED, + &hfi_val, sizeof(u32)); +} + +int iris_set_frame_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0, client_qp_enable; + u32 i_frame_qp, p_frame_qp, b_frame_qp; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + struct vb2_queue *q; + u32 hfi_val; + + q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + if (vb2_is_streaming(q)) { + if (inst->hfi_rc_type != HFI_RC_OFF) + return 0; + } + + if (inst->hfi_rc_type == HFI_RC_OFF) { + i_qp_enable = 1; + p_qp_enable = 1; + b_qp_enable = 1; + } else { + if (inst->codec == V4L2_PIX_FMT_H264) { + if (inst->fw_caps[I_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + i_qp_enable = 1; + if (inst->fw_caps[P_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + p_qp_enable = 1; + if (inst->fw_caps[B_FRAME_QP_H264].flags & CAP_FLAG_CLIENT_SET) + b_qp_enable = 1; + } else { + if (inst->fw_caps[I_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + i_qp_enable = 1; + if (inst->fw_caps[P_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + p_qp_enable = 1; + if (inst->fw_caps[B_FRAME_QP_HEVC].flags & CAP_FLAG_CLIENT_SET) + b_qp_enable = 1; + } + } + + client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2; + if (!client_qp_enable) + return 0; + + if (inst->codec == V4L2_PIX_FMT_H264) { + i_frame_qp = inst->fw_caps[I_FRAME_QP_H264].value; + p_frame_qp = inst->fw_caps[P_FRAME_QP_H264].value; + b_frame_qp = inst->fw_caps[B_FRAME_QP_H264].value; + } else { + i_frame_qp = inst->fw_caps[I_FRAME_QP_HEVC].value; + p_frame_qp = inst->fw_caps[P_FRAME_QP_HEVC].value; + b_frame_qp = inst->fw_caps[B_FRAME_QP_HEVC].value; + } + + hfi_val = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 | + client_qp_enable << 24; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_32_PACKED, + &hfi_val, sizeof(u32)); +} + +int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + struct hfi_quantization_range_v2 range; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + range.min_qp.qp_packed = inst->fw_caps[MIN_FRAME_QP_HEVC].value; + range.max_qp.qp_packed = inst->fw_caps[MAX_FRAME_QP_HEVC].value; + } else { + range.min_qp.qp_packed = inst->fw_caps[MIN_FRAME_QP_H264].value; + range.max_qp.qp_packed = inst->fw_caps[MAX_FRAME_QP_H264].value; + } + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_32_PACKED, + &range, sizeof(range)); +} + int iris_set_properties(struct iris_inst *inst, u32 plane) { const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h index 9b5741868933..30af333cc494 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.h +++ b/drivers/media/platform/qcom/iris/iris_ctrls.h @@ -17,6 +17,21 @@ int iris_set_u32_enum(struct iris_inst *inst, enum platform_inst_fw_cap_type cap int iris_set_stage(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_pipe(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_u32(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_profile(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_level(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_profile_level_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_header_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_header_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_peak_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_bitrate_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_bitrate_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_entropy_mode_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_entropy_mode_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_min_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_max_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_frame_qp(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_qp_range(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_properties(struct iris_inst *inst, u32 plane); #endif diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index f1b5cd56db32..679444327ed7 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -19,8 +19,7 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) u32 pas_id = core->iris_platform_data->pas_id; const struct firmware *firmware = NULL; struct device *dev = core->dev; - struct reserved_mem *rmem; - struct device_node *node; + struct resource res; phys_addr_t mem_phys; size_t res_size; ssize_t fw_size; @@ -30,17 +29,12 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4) return -EINVAL; - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!node) - return -EINVAL; - - rmem = of_reserved_mem_lookup(node); - of_node_put(node); - if (!rmem) - return -EINVAL; + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); + if (ret) + return ret; - mem_phys = rmem->base; - res_size = rmem->size; + mem_phys = res.start; + res_size = resource_size(&res); ret = request_firmware(&firmware, fw_name, dev); if (ret) @@ -60,16 +54,7 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) ret = qcom_mdt_load(dev, firmware, fw_name, pas_id, mem_virt, mem_phys, res_size, NULL); - if (ret) - goto err_mem_unmap; - ret = qcom_scm_pas_auth_and_reset(pas_id); - if (ret) - goto err_mem_unmap; - - return ret; - -err_mem_unmap: memunmap(mem_virt); err_release_fw: release_firmware(firmware); @@ -94,6 +79,12 @@ int iris_fw_load(struct iris_core *core) return -ENOMEM; } + ret = qcom_scm_pas_auth_and_reset(core->iris_platform_data->pas_id); + if (ret) { + dev_err(core->dev, "auth and reset failed: %d\n", ret); + return ret; + } + ret = qcom_scm_mem_protect_video_var(cp_config->cp_start, cp_config->cp_size, cp_config->cp_nonpixel_start, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_common.h b/drivers/media/platform/qcom/iris/iris_hfi_common.h index 9e6aadb83783..b51471fb32c7 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_common.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_common.h @@ -102,7 +102,7 @@ enum hfi_matrix_coefficients { struct iris_hfi_prop_type_handle { u32 type; - int (*handle)(struct iris_inst *inst); + int (*handle)(struct iris_inst *inst, u32 plane); }; struct iris_hfi_command_ops { diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c index 5fc30d54af4d..52da7ef7bab0 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c @@ -21,6 +21,10 @@ static u32 iris_hfi_gen1_buf_type_from_driver(enum iris_buffer_type buffer_type) return HFI_BUFFER_INTERNAL_SCRATCH; case BUF_SCRATCH_1: return HFI_BUFFER_INTERNAL_SCRATCH_1; + case BUF_SCRATCH_2: + return HFI_BUFFER_INTERNAL_SCRATCH_2; + case BUF_ARP: + return HFI_BUFFER_INTERNAL_PERSIST; default: return -EINVAL; } @@ -109,7 +113,12 @@ static int iris_hfi_gen1_session_open(struct iris_inst *inst) packet.shdr.hdr.size = sizeof(struct hfi_session_open_pkt); packet.shdr.hdr.pkt_type = HFI_CMD_SYS_SESSION_INIT; packet.shdr.session_id = inst->session_id; - packet.session_domain = HFI_SESSION_TYPE_DEC; + + if (inst->domain == DECODER) + packet.session_domain = HFI_SESSION_TYPE_DEC; + else + packet.session_domain = HFI_SESSION_TYPE_ENC; + packet.session_codec = codec; reinit_completion(&inst->completion); @@ -184,47 +193,70 @@ static int iris_hfi_gen1_session_stop(struct iris_inst *inst, u32 plane) u32 flush_type = 0; int ret = 0; - if ((V4L2_TYPE_IS_OUTPUT(plane) && - inst->state == IRIS_INST_INPUT_STREAMING) || - (V4L2_TYPE_IS_CAPTURE(plane) && - inst->state == IRIS_INST_OUTPUT_STREAMING) || - inst->state == IRIS_INST_ERROR) { - reinit_completion(&inst->completion); - iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_STOP); - ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); - if (!ret) - ret = iris_wait_for_session_response(inst, false); - - reinit_completion(&inst->completion); - iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_RELEASE_RESOURCES); - ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); - if (!ret) - ret = iris_wait_for_session_response(inst, false); - - iris_inst_change_sub_state(inst, IRIS_INST_SUB_LOAD_RESOURCES, 0); + if (inst->domain == DECODER) { + if (inst->state == IRIS_INST_STREAMING) { + if (V4L2_TYPE_IS_OUTPUT(plane)) + flush_type = HFI_FLUSH_ALL; + else if (V4L2_TYPE_IS_CAPTURE(plane)) + flush_type = HFI_FLUSH_OUTPUT; + + reinit_completion(&inst->flush_completion); + + flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt); + flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; + flush_pkt.shdr.session_id = inst->session_id; + flush_pkt.flush_type = flush_type; + + ret = iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size); + if (!ret) { + inst->flush_responses_pending++; + ret = iris_wait_for_session_response(inst, true); + } + } else if (inst->sub_state & IRIS_INST_SUB_LOAD_RESOURCES) { + reinit_completion(&inst->completion); + iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_STOP); + ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); + if (!ret) + ret = iris_wait_for_session_response(inst, false); + + reinit_completion(&inst->completion); + iris_hfi_gen1_packet_session_cmd(inst, &pkt, + HFI_CMD_SESSION_RELEASE_RESOURCES); + ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); + if (!ret) + ret = iris_wait_for_session_response(inst, false); + + iris_inst_change_sub_state(inst, IRIS_INST_SUB_LOAD_RESOURCES, 0); + + iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + VB2_BUF_STATE_ERROR); + iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + VB2_BUF_STATE_ERROR); + } + } else { + if (inst->state == IRIS_INST_STREAMING || + inst->state == IRIS_INST_INPUT_STREAMING || + inst->state == IRIS_INST_ERROR) { + reinit_completion(&inst->completion); + iris_hfi_gen1_packet_session_cmd(inst, &pkt, HFI_CMD_SESSION_STOP); + ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); + if (!ret) + ret = iris_wait_for_session_response(inst, false); + + reinit_completion(&inst->completion); + iris_hfi_gen1_packet_session_cmd(inst, &pkt, + HFI_CMD_SESSION_RELEASE_RESOURCES); + ret = iris_hfi_queue_cmd_write(core, &pkt, pkt.shdr.hdr.size); + if (!ret) + ret = iris_wait_for_session_response(inst, false); + + iris_inst_change_sub_state(inst, IRIS_INST_SUB_LOAD_RESOURCES, 0); + } iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, VB2_BUF_STATE_ERROR); iris_helper_buffers_done(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, VB2_BUF_STATE_ERROR); - } else if (inst->state == IRIS_INST_STREAMING) { - if (V4L2_TYPE_IS_OUTPUT(plane)) - flush_type = HFI_FLUSH_ALL; - else if (V4L2_TYPE_IS_CAPTURE(plane)) - flush_type = HFI_FLUSH_OUTPUT; - - reinit_completion(&inst->flush_completion); - - flush_pkt.shdr.hdr.size = sizeof(struct hfi_session_flush_pkt); - flush_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_FLUSH; - flush_pkt.shdr.session_id = inst->session_id; - flush_pkt.flush_type = flush_type; - - ret = iris_hfi_queue_cmd_write(core, &flush_pkt, flush_pkt.shdr.hdr.size); - if (!ret) { - inst->flush_responses_pending++; - ret = iris_wait_for_session_response(inst, true); - } } return ret; @@ -241,23 +273,44 @@ static int iris_hfi_gen1_session_continue(struct iris_inst *inst, u32 plane) static int iris_hfi_gen1_queue_input_buffer(struct iris_inst *inst, struct iris_buffer *buf) { - struct hfi_session_empty_buffer_compressed_pkt ip_pkt; - - ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt); - ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; - ip_pkt.shdr.session_id = inst->session_id; - ip_pkt.time_stamp_hi = upper_32_bits(buf->timestamp); - ip_pkt.time_stamp_lo = lower_32_bits(buf->timestamp); - ip_pkt.flags = buf->flags; - ip_pkt.mark_target = 0; - ip_pkt.mark_data = 0; - ip_pkt.offset = buf->data_offset; - ip_pkt.alloc_len = buf->buffer_size; - ip_pkt.filled_len = buf->data_size; - ip_pkt.input_tag = buf->index; - ip_pkt.packet_buffer = buf->device_addr; - - return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); + struct hfi_session_empty_buffer_compressed_pkt com_ip_pkt; + struct hfi_session_empty_buffer_uncompressed_pkt uncom_ip_pkt; + + if (inst->domain == DECODER) { + com_ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt); + com_ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; + com_ip_pkt.shdr.session_id = inst->session_id; + com_ip_pkt.time_stamp_hi = upper_32_bits(buf->timestamp); + com_ip_pkt.time_stamp_lo = lower_32_bits(buf->timestamp); + com_ip_pkt.flags = buf->flags; + com_ip_pkt.mark_target = 0; + com_ip_pkt.mark_data = 0; + com_ip_pkt.offset = buf->data_offset; + com_ip_pkt.alloc_len = buf->buffer_size; + com_ip_pkt.filled_len = buf->data_size; + com_ip_pkt.input_tag = buf->index; + com_ip_pkt.packet_buffer = buf->device_addr; + return iris_hfi_queue_cmd_write(inst->core, &com_ip_pkt, + com_ip_pkt.shdr.hdr.size); + } else { + uncom_ip_pkt.shdr.hdr.size = + sizeof(struct hfi_session_empty_buffer_uncompressed_pkt); + uncom_ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; + uncom_ip_pkt.shdr.session_id = inst->session_id; + uncom_ip_pkt.time_stamp_hi = upper_32_bits(buf->timestamp); + uncom_ip_pkt.time_stamp_lo = lower_32_bits(buf->timestamp); + uncom_ip_pkt.view_id = 0; + uncom_ip_pkt.flags = buf->flags; + uncom_ip_pkt.mark_target = 0; + uncom_ip_pkt.mark_data = 0; + uncom_ip_pkt.offset = buf->data_offset; + uncom_ip_pkt.alloc_len = buf->buffer_size; + uncom_ip_pkt.filled_len = buf->data_size; + uncom_ip_pkt.input_tag = buf->index; + uncom_ip_pkt.packet_buffer = buf->device_addr; + return iris_hfi_queue_cmd_write(inst->core, &uncom_ip_pkt, + uncom_ip_pkt.shdr.hdr.size); + } } static int iris_hfi_gen1_queue_output_buffer(struct iris_inst *inst, struct iris_buffer *buf) @@ -330,6 +383,8 @@ static int iris_hfi_gen1_session_queue_buffer(struct iris_inst *inst, struct iri case BUF_PERSIST: case BUF_BIN: case BUF_SCRATCH_1: + case BUF_SCRATCH_2: + case BUF_ARP: return iris_hfi_gen1_queue_internal_buffer(inst, buf); default: return -EINVAL; @@ -395,16 +450,31 @@ exit: static int iris_hfi_gen1_session_drain(struct iris_inst *inst, u32 plane) { - struct hfi_session_empty_buffer_compressed_pkt ip_pkt = {0}; + if (inst->domain == DECODER) { + struct hfi_session_empty_buffer_compressed_pkt ip_pkt = {0}; + + ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt); + ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; + ip_pkt.shdr.session_id = inst->session_id; + ip_pkt.flags = HFI_BUFFERFLAG_EOS; + ip_pkt.packet_buffer = 0xdeadb000; + + return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); + } + + if (inst->domain == ENCODER) { + struct hfi_session_empty_buffer_uncompressed_pkt ip_pkt = {0}; - ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_compressed_pkt); - ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; - ip_pkt.shdr.session_id = inst->session_id; - ip_pkt.flags = HFI_BUFFERFLAG_EOS; - if (inst->codec == V4L2_PIX_FMT_VP9) + ip_pkt.shdr.hdr.size = sizeof(struct hfi_session_empty_buffer_uncompressed_pkt); + ip_pkt.shdr.hdr.pkt_type = HFI_CMD_SESSION_EMPTY_BUFFER; + ip_pkt.shdr.session_id = inst->session_id; + ip_pkt.flags = HFI_BUFFERFLAG_EOS; ip_pkt.packet_buffer = 0xdeadb000; - return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); + return iris_hfi_queue_cmd_write(inst->core, &ip_pkt, ip_pkt.shdr.hdr.size); + } + + return -EINVAL; } static int @@ -507,6 +577,114 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p packet->shdr.hdr.size += sizeof(u32) + sizeof(*wm); break; } + case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: { + struct hfi_profile_level *in = pdata, *pl = prop_data; + + pl->level = in->level; + pl->profile = in->profile; + if (pl->profile <= 0) + /* Profile not supported, falling back to high */ + pl->profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + + if (!pl->level) + /* Level not supported, falling back to 1 */ + pl->level = 1; + + packet->shdr.hdr.size += sizeof(u32) + sizeof(*pl); + break; + } + case HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER: { + struct hfi_enable *en = prop_data; + u32 *in = pdata; + + en->enable = *in; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*en); + break; + } + case HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE: { + struct hfi_bitrate *brate = prop_data; + u32 *in = pdata; + + brate->bitrate = *in; + brate->layer_id = 0; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*brate); + break; + } + case HFI_PROPERTY_PARAM_VENC_RATE_CONTROL: { + u32 *in = pdata; + + switch (*in) { + case HFI_RATE_CONTROL_OFF: + case HFI_RATE_CONTROL_CBR_CFR: + case HFI_RATE_CONTROL_CBR_VFR: + case HFI_RATE_CONTROL_VBR_CFR: + case HFI_RATE_CONTROL_VBR_VFR: + case HFI_RATE_CONTROL_CQ: + break; + default: + return -EINVAL; + } + + packet->data[1] = *in; + packet->shdr.hdr.size += sizeof(u32) * 2; + break; + } + case HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL: { + struct hfi_h264_entropy_control *entropy = prop_data; + u32 *in = pdata; + + entropy->entropy_mode = *in; + if (entropy->entropy_mode == HFI_H264_ENTROPY_CABAC) + entropy->cabac_model = HFI_H264_CABAC_MODEL_0; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*entropy); + break; + } + case HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2: { + struct hfi_quantization_range_v2 *range = prop_data; + struct hfi_quantization_range_v2 *in = pdata; + u32 min_qp, max_qp; + + min_qp = in->min_qp.qp_packed; + max_qp = in->max_qp.qp_packed; + + /* We'll be packing in the qp, so make sure we + * won't be losing data when masking + */ + if (min_qp > 0xff || max_qp > 0xff) + return -ERANGE; + + range->min_qp.layer_id = 0xFF; + range->max_qp.layer_id = 0xFF; + range->min_qp.qp_packed = (min_qp & 0xFF) | ((min_qp & 0xFF) << 8) | + ((min_qp & 0xFF) << 16); + range->max_qp.qp_packed = (max_qp & 0xFF) | ((max_qp & 0xFF) << 8) | + ((max_qp & 0xFF) << 16); + range->min_qp.enable = 7; + range->max_qp.enable = 7; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*range); + break; + } + case HFI_PROPERTY_CONFIG_FRAME_RATE: { + struct hfi_framerate *frate = prop_data; + struct hfi_framerate *in = pdata; + + frate->buffer_type = in->buffer_type; + frate->framerate = in->framerate; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*frate); + break; + } + case HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO: { + struct hfi_uncompressed_plane_actual_info *plane_actual_info = prop_data; + struct hfi_uncompressed_plane_actual_info *in = pdata; + + plane_actual_info->buffer_type = in->buffer_type; + plane_actual_info->num_planes = in->num_planes; + plane_actual_info->plane_format[0] = in->plane_format[0]; + if (in->num_planes > 1) + plane_actual_info->plane_format[1] = in->plane_format[1]; + packet->shdr.hdr.size += sizeof(u32) + sizeof(*plane_actual_info); + break; + } default: return -EINVAL; } @@ -549,7 +727,7 @@ static int iris_hfi_gen1_session_set_property(struct iris_inst *inst, u32 packet return hfi_gen1_set_property(inst, packet_type, payload, payload_size); } -static int iris_hfi_gen1_set_resolution(struct iris_inst *inst) +static int iris_hfi_gen1_set_resolution(struct iris_inst *inst, u32 plane) { u32 ptype = HFI_PROPERTY_PARAM_FRAME_SIZE; struct hfi_framesize fs; @@ -564,14 +742,18 @@ static int iris_hfi_gen1_set_resolution(struct iris_inst *inst) if (ret) return ret; } - fs.buffer_type = HFI_BUFFER_OUTPUT2; + if (inst->domain == DECODER) + fs.buffer_type = HFI_BUFFER_OUTPUT2; + else + fs.buffer_type = HFI_BUFFER_OUTPUT; + fs.width = inst->fmt_dst->fmt.pix_mp.width; fs.height = inst->fmt_dst->fmt.pix_mp.height; return hfi_gen1_set_property(inst, ptype, &fs, sizeof(fs)); } -static int iris_hfi_gen1_decide_core(struct iris_inst *inst) +static int iris_hfi_gen1_decide_core(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; struct hfi_videocores_usage_type cu; @@ -581,40 +763,54 @@ static int iris_hfi_gen1_decide_core(struct iris_inst *inst) return hfi_gen1_set_property(inst, ptype, &cu, sizeof(cu)); } -static int iris_hfi_gen1_set_raw_format(struct iris_inst *inst) +static int iris_hfi_gen1_set_raw_format(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT; - u32 pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; struct hfi_uncompressed_format_select fmt; + u32 pixelformat; int ret; - if (iris_split_mode_enabled(inst)) { - fmt.buffer_type = HFI_BUFFER_OUTPUT; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12_UBWC : 0; + if (inst->domain == DECODER) { + pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; + if (iris_split_mode_enabled(inst)) { + fmt.buffer_type = HFI_BUFFER_OUTPUT; + fmt.format = HFI_COLOR_FORMAT_NV12_UBWC; - ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); - if (ret) - return ret; + ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); + if (ret) + return ret; - fmt.buffer_type = HFI_BUFFER_OUTPUT2; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; + fmt.buffer_type = HFI_BUFFER_OUTPUT2; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FORMAT_NV12 : HFI_COLOR_FORMAT_NV12_UBWC; - ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); - } else { - fmt.buffer_type = HFI_BUFFER_OUTPUT; - fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FORMAT_NV12 : 0; + ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); + } else { + fmt.buffer_type = HFI_BUFFER_OUTPUT; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FORMAT_NV12 : HFI_COLOR_FORMAT_NV12_UBWC; + ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); + } + } else { + pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; + fmt.buffer_type = HFI_BUFFER_INPUT; + fmt.format = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FORMAT_NV12 : HFI_COLOR_FORMAT_NV12_UBWC; ret = hfi_gen1_set_property(inst, ptype, &fmt, sizeof(fmt)); } return ret; } -static int iris_hfi_gen1_set_format_constraints(struct iris_inst *inst) +static int iris_hfi_gen1_set_format_constraints(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO; struct hfi_uncompressed_plane_actual_constraints_info pconstraint; + if (inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C) + return 0; + pconstraint.buffer_type = HFI_BUFFER_OUTPUT2; pconstraint.num_planes = 2; pconstraint.plane_format[0].stride_multiples = 128; @@ -630,7 +826,7 @@ static int iris_hfi_gen1_set_format_constraints(struct iris_inst *inst) return hfi_gen1_set_property(inst, ptype, &pconstraint, sizeof(pconstraint)); } -static int iris_hfi_gen1_set_num_bufs(struct iris_inst *inst) +static int iris_hfi_gen1_set_num_bufs(struct iris_inst *inst, u32 plane) { u32 ptype = HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL; struct hfi_buffer_count_actual buf_count; @@ -644,20 +840,28 @@ static int iris_hfi_gen1_set_num_bufs(struct iris_inst *inst) if (ret) return ret; - if (iris_split_mode_enabled(inst)) { - buf_count.type = HFI_BUFFER_OUTPUT; - buf_count.count_actual = VIDEO_MAX_FRAME; - buf_count.count_min_host = VIDEO_MAX_FRAME; + if (inst->domain == DECODER) { + if (iris_split_mode_enabled(inst)) { + buf_count.type = HFI_BUFFER_OUTPUT; + buf_count.count_actual = VIDEO_MAX_FRAME; + buf_count.count_min_host = VIDEO_MAX_FRAME; - ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); - if (ret) - return ret; + ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); + if (ret) + return ret; - buf_count.type = HFI_BUFFER_OUTPUT2; - buf_count.count_actual = iris_vpu_buf_count(inst, BUF_DPB); - buf_count.count_min_host = iris_vpu_buf_count(inst, BUF_DPB); + buf_count.type = HFI_BUFFER_OUTPUT2; + buf_count.count_actual = iris_vpu_buf_count(inst, BUF_DPB); + buf_count.count_min_host = iris_vpu_buf_count(inst, BUF_DPB); - ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); + ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); + } else { + buf_count.type = HFI_BUFFER_OUTPUT; + buf_count.count_actual = VIDEO_MAX_FRAME; + buf_count.count_min_host = VIDEO_MAX_FRAME; + + ret = hfi_gen1_set_property(inst, ptype, &buf_count, sizeof(buf_count)); + } } else { buf_count.type = HFI_BUFFER_OUTPUT; buf_count.count_actual = VIDEO_MAX_FRAME; @@ -669,7 +873,7 @@ static int iris_hfi_gen1_set_num_bufs(struct iris_inst *inst) return ret; } -static int iris_hfi_gen1_set_multistream(struct iris_inst *inst) +static int iris_hfi_gen1_set_multistream(struct iris_inst *inst, u32 plane) { u32 ptype = HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM; struct hfi_multi_stream multi = {0}; @@ -704,7 +908,7 @@ static int iris_hfi_gen1_set_multistream(struct iris_inst *inst) return ret; } -static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst) +static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst, u32 plane) { const u32 ptype = HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL; struct hfi_buffer_size_actual bufsz; @@ -712,7 +916,7 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst) if (iris_split_mode_enabled(inst)) { bufsz.type = HFI_BUFFER_OUTPUT; - bufsz.size = iris_vpu_buf_size(inst, BUF_DPB); + bufsz.size = inst->core->iris_platform_data->get_vpu_buffer_size(inst, BUF_DPB); ret = hfi_gen1_set_property(inst, ptype, &bufsz, sizeof(bufsz)); if (ret) @@ -739,14 +943,49 @@ static int iris_hfi_gen1_set_bufsize(struct iris_inst *inst) return ret; } +static int iris_hfi_gen1_set_frame_rate(struct iris_inst *inst, u32 plane) +{ + const u32 ptype = HFI_PROPERTY_CONFIG_FRAME_RATE; + struct hfi_framerate frate; + + if (V4L2_TYPE_IS_OUTPUT(plane)) + return 0; + + frate.buffer_type = HFI_BUFFER_OUTPUT; + frate.framerate = inst->frame_rate << 16; + + return hfi_gen1_set_property(inst, ptype, &frate, sizeof(frate)); +} + +static int iris_hfi_gen1_set_stride(struct iris_inst *inst, u32 plane) +{ + const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO; + struct hfi_uncompressed_plane_actual_info plane_actual_info; + + plane_actual_info.buffer_type = HFI_BUFFER_INPUT; + plane_actual_info.num_planes = 2; + plane_actual_info.plane_format[0].actual_stride = + ALIGN(inst->fmt_src->fmt.pix_mp.width, 128); + plane_actual_info.plane_format[0].actual_plane_buffer_height = + ALIGN(inst->fmt_src->fmt.pix_mp.height, 32); + plane_actual_info.plane_format[1].actual_stride = + ALIGN(inst->fmt_src->fmt.pix_mp.width, 128); + plane_actual_info.plane_format[1].actual_plane_buffer_height = + (ALIGN(inst->fmt_src->fmt.pix_mp.height, 32)) / 2; + + return hfi_gen1_set_property(inst, ptype, &plane_actual_info, sizeof(plane_actual_info)); +} + static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 plane) { + struct iris_hfi_prop_type_handle const *handler = NULL; + u32 handler_size = 0; struct iris_core *core = inst->core; u32 config_params_size, i, j; const u32 *config_params; int ret; - static const struct iris_hfi_prop_type_handle prop_type_handle_inp_arr[] = { + static const struct iris_hfi_prop_type_handle vdec_prop_type_handle_inp_arr[] = { {HFI_PROPERTY_PARAM_FRAME_SIZE, iris_hfi_gen1_set_resolution}, {HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE, @@ -763,7 +1002,7 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p iris_hfi_gen1_set_bufsize}, }; - static const struct iris_hfi_prop_type_handle prop_type_handle_out_arr[] = { + static const struct iris_hfi_prop_type_handle vdec_prop_type_handle_out_arr[] = { {HFI_PROPERTY_PARAM_FRAME_SIZE, iris_hfi_gen1_set_resolution}, {HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, @@ -778,29 +1017,43 @@ static int iris_hfi_gen1_session_set_config_params(struct iris_inst *inst, u32 p iris_hfi_gen1_set_bufsize}, }; - config_params = core->iris_platform_data->input_config_params_default; - config_params_size = core->iris_platform_data->input_config_params_default_size; - - if (V4L2_TYPE_IS_OUTPUT(plane)) { - for (i = 0; i < config_params_size; i++) { - for (j = 0; j < ARRAY_SIZE(prop_type_handle_inp_arr); j++) { - if (prop_type_handle_inp_arr[j].type == config_params[i]) { - ret = prop_type_handle_inp_arr[j].handle(inst); - if (ret) - return ret; - break; - } - } + static const struct iris_hfi_prop_type_handle venc_prop_type_handle_inp_arr[] = { + {HFI_PROPERTY_CONFIG_FRAME_RATE, + iris_hfi_gen1_set_frame_rate}, + {HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO, + iris_hfi_gen1_set_stride}, + {HFI_PROPERTY_PARAM_FRAME_SIZE, + iris_hfi_gen1_set_resolution}, + {HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, + iris_hfi_gen1_set_raw_format}, + {HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL, + iris_hfi_gen1_set_num_bufs}, + }; + + if (inst->domain == DECODER) { + config_params = core->iris_platform_data->dec_input_config_params_default; + config_params_size = core->iris_platform_data->dec_input_config_params_default_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + handler = vdec_prop_type_handle_inp_arr; + handler_size = ARRAY_SIZE(vdec_prop_type_handle_inp_arr); + } else if (V4L2_TYPE_IS_CAPTURE(plane)) { + handler = vdec_prop_type_handle_out_arr; + handler_size = ARRAY_SIZE(vdec_prop_type_handle_out_arr); } - } else if (V4L2_TYPE_IS_CAPTURE(plane)) { - for (i = 0; i < config_params_size; i++) { - for (j = 0; j < ARRAY_SIZE(prop_type_handle_out_arr); j++) { - if (prop_type_handle_out_arr[j].type == config_params[i]) { - ret = prop_type_handle_out_arr[j].handle(inst); - if (ret) - return ret; - break; - } + } else { + config_params = core->iris_platform_data->enc_input_config_params; + config_params_size = core->iris_platform_data->enc_input_config_params_size; + handler = venc_prop_type_handle_inp_arr; + handler_size = ARRAY_SIZE(venc_prop_type_handle_inp_arr); + } + + for (i = 0; i < config_params_size; i++) { + for (j = 0; j < handler_size; j++) { + if (handler[j].type == config_params[i]) { + ret = handler[j].handle(inst, plane); + if (ret) + return ret; + break; } } } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h index d4d119ca98b0..42226ccee3d9 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h @@ -10,6 +10,7 @@ #define HFI_VIDEO_ARCH_OX 0x1 +#define HFI_SESSION_TYPE_ENC 1 #define HFI_SESSION_TYPE_DEC 2 #define HFI_VIDEO_CODEC_H264 0x00000002 @@ -73,18 +74,22 @@ #define HFI_BUFFER_INPUT 0x1 #define HFI_BUFFER_OUTPUT 0x2 #define HFI_BUFFER_OUTPUT2 0x3 +#define HFI_BUFFER_INTERNAL_PERSIST 0x4 #define HFI_BUFFER_INTERNAL_PERSIST_1 0x5 #define HFI_BUFFER_INTERNAL_SCRATCH 0x6 #define HFI_BUFFER_INTERNAL_SCRATCH_1 0x7 +#define HFI_BUFFER_INTERNAL_SCRATCH_2 0x8 #define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL 0x5 #define HFI_PROPERTY_SYS_IMAGE_VERSION 0x6 #define HFI_PROPERTY_PARAM_FRAME_SIZE 0x1001 +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO 0x1002 #define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT 0x1003 #define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT 0x1005 #define HFI_PROPERTY_PARAM_WORK_MODE 0x1015 #define HFI_PROPERTY_PARAM_WORK_ROUTE 0x1017 +#define HFI_PROPERTY_CONFIG_FRAME_RATE 0x2001 #define HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE 0x2002 #define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM 0x1003001 @@ -111,15 +116,32 @@ #define HFI_MSG_SESSION_RELEASE_RESOURCES 0x22100a #define HFI_MSG_SESSION_RELEASE_BUFFERS 0x22100c -#define HFI_PICTURE_I 0x00000001 -#define HFI_PICTURE_P 0x00000002 -#define HFI_PICTURE_B 0x00000004 -#define HFI_PICTURE_IDR 0x00000008 +#define HFI_GEN1_PICTURE_I 0x00000001 +#define HFI_GEN1_PICTURE_P 0x00000002 +#define HFI_GEN1_PICTURE_B 0x00000004 +#define HFI_GEN1_PICTURE_IDR 0x00000008 #define HFI_FRAME_NOTCODED 0x7f002000 #define HFI_FRAME_YUV 0x7f004000 #define HFI_UNUSED_PICT 0x10000000 -#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008 -#define HFI_BUFFERFLAG_DROP_FRAME 0x20000000 +#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008 +#define HFI_BUFFERFLAG_DROP_FRAME 0x20000000 +#define HFI_RATE_CONTROL_OFF 0x1000001 +#define HFI_RATE_CONTROL_VBR_VFR 0x1000002 +#define HFI_RATE_CONTROL_VBR_CFR 0x1000003 +#define HFI_RATE_CONTROL_CBR_VFR 0x1000004 +#define HFI_RATE_CONTROL_CBR_CFR 0x1000005 +#define HFI_RATE_CONTROL_CQ 0x1000008 + +#define HFI_H264_ENTROPY_CAVLC 0x1 +#define HFI_H264_ENTROPY_CABAC 0x2 + +#define HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL 0x2005002 +#define HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL 0x2005003 +#define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL 0x2005004 +#define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2 0x2005009 +#define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES 0x2005020 +#define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE 0x2006001 +#define HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER 0x2006008 struct hfi_pkt_hdr { u32 size; @@ -194,6 +216,23 @@ struct hfi_session_empty_buffer_compressed_pkt { u32 data; }; +struct hfi_session_empty_buffer_uncompressed_pkt { + struct hfi_session_hdr_pkt shdr; + u32 view_id; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 flags; + u32 mark_target; + u32 mark_data; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 input_tag; + u32 packet_buffer; + u32 extradata_buffer; + u32 data; +}; + struct hfi_session_fill_buffer_pkt { struct hfi_session_hdr_pkt shdr; u32 stream_id; @@ -340,6 +379,17 @@ struct hfi_uncompressed_plane_actual_constraints_info { struct hfi_uncompressed_plane_constraints plane_format[2]; }; +struct hfi_uncompressed_plane_actual { + int actual_stride; + u32 actual_plane_buffer_height; +}; + +struct hfi_uncompressed_plane_actual_info { + u32 buffer_type; + u32 num_planes; + struct hfi_uncompressed_plane_actual plane_format[2]; +}; + struct hfi_buffer_count_actual { u32 type; u32 count_actual; @@ -367,6 +417,36 @@ struct hfi_buffer_requirements { u32 alignment; }; +struct hfi_bitrate { + u32 bitrate; + u32 layer_id; +}; + +#define HFI_H264_CABAC_MODEL_0 0x1 + +struct hfi_h264_entropy_control { + u32 entropy_mode; + u32 cabac_model; +}; + +struct hfi_quantization_v2 { + u32 qp_packed; + u32 layer_id; + u32 enable; + u32 reserved[3]; +}; + +struct hfi_quantization_range_v2 { + struct hfi_quantization_v2 min_qp; + struct hfi_quantization_v2 max_qp; + u32 reserved[4]; +}; + +struct hfi_framerate { + u32 buffer_type; + u32 framerate; +}; + struct hfi_event_data { u32 error; u32 height; @@ -398,6 +478,26 @@ struct hfi_msg_session_empty_buffer_done_pkt { u32 data[]; }; +struct hfi_msg_session_fbd_compressed_pkt { + struct hfi_session_hdr_pkt shdr; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 error_type; + u32 flags; + u32 mark_target; + u32 mark_data; + u32 stats; + u32 offset; + u32 alloc_len; + u32 filled_len; + u32 input_tag; + u32 output_tag; + u32 picture_type; + u32 packet_buffer; + u32 extradata_buffer; + u32 data[]; +}; + struct hfi_msg_session_fbd_uncompressed_plane0_pkt { struct hfi_session_hdr_pkt shdr; u32 stream_id; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c index 8d1ce8a19a45..8e864c239e29 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_response.c @@ -387,24 +387,43 @@ error: static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) { - struct hfi_msg_session_fbd_uncompressed_plane0_pkt *pkt = packet; + struct hfi_msg_session_fbd_uncompressed_plane0_pkt *uncom_pkt = packet; + struct hfi_msg_session_fbd_compressed_pkt *com_pkt = packet; struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; struct v4l2_m2m_buffer *m2m_buffer, *n; struct hfi_session_flush_pkt flush_pkt; - u32 timestamp_hi = pkt->time_stamp_hi; - u32 timestamp_lo = pkt->time_stamp_lo; + u32 timestamp_hi; + u32 timestamp_lo; struct iris_core *core = inst->core; - u32 filled_len = pkt->filled_len; - u32 pic_type = pkt->picture_type; - u32 output_tag = pkt->output_tag; + u32 filled_len; + u32 pic_type; + u32 output_tag; struct iris_buffer *buf, *iter; struct iris_buffers *buffers; - u32 hfi_flags = pkt->flags; - u32 offset = pkt->offset; + u32 hfi_flags; + u32 offset; u64 timestamp_us = 0; bool found = false; u32 flags = 0; + if (inst->domain == DECODER) { + timestamp_hi = uncom_pkt->time_stamp_hi; + timestamp_lo = uncom_pkt->time_stamp_lo; + filled_len = uncom_pkt->filled_len; + pic_type = uncom_pkt->picture_type; + output_tag = uncom_pkt->output_tag; + hfi_flags = uncom_pkt->flags; + offset = uncom_pkt->offset; + } else { + timestamp_hi = com_pkt->time_stamp_hi; + timestamp_lo = com_pkt->time_stamp_lo; + filled_len = com_pkt->filled_len; + pic_type = com_pkt->picture_type; + output_tag = com_pkt->output_tag; + hfi_flags = com_pkt->flags; + offset = com_pkt->offset; + } + if ((hfi_flags & HFI_BUFFERFLAG_EOS) && !filled_len) { reinit_completion(&inst->flush_completion); @@ -416,11 +435,10 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) inst->flush_responses_pending++; iris_inst_sub_state_change_drain_last(inst); - - return; } - if (iris_split_mode_enabled(inst) && pkt->stream_id == 0) { + if (iris_split_mode_enabled(inst) && inst->domain == DECODER && + uncom_pkt->stream_id == 0) { buffers = &inst->buffers[BUF_DPB]; if (!buffers) goto error; @@ -461,8 +479,14 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) timestamp_us = timestamp_hi; timestamp_us = (timestamp_us << 32) | timestamp_lo; } else { - if (pkt->stream_id == 1 && !inst->last_buffer_dequeued) { - if (iris_drc_pending(inst)) { + if (inst->domain == DECODER && uncom_pkt->stream_id == 1 && + !inst->last_buffer_dequeued) { + if (iris_drc_pending(inst) || iris_drain_pending(inst)) { + flags |= V4L2_BUF_FLAG_LAST; + inst->last_buffer_dequeued = true; + } + } else if (inst->domain == ENCODER) { + if (!inst->last_buffer_dequeued && iris_drain_pending(inst)) { flags |= V4L2_BUF_FLAG_LAST; inst->last_buffer_dequeued = true; } @@ -471,14 +495,14 @@ static void iris_hfi_gen1_session_ftb_done(struct iris_inst *inst, void *packet) buf->timestamp = timestamp_us; switch (pic_type) { - case HFI_PICTURE_IDR: - case HFI_PICTURE_I: + case HFI_GEN1_PICTURE_IDR: + case HFI_GEN1_PICTURE_I: flags |= V4L2_BUF_FLAG_KEYFRAME; break; - case HFI_PICTURE_P: + case HFI_GEN1_PICTURE_P: flags |= V4L2_BUF_FLAG_PFRAME; break; - case HFI_PICTURE_B: + case HFI_GEN1_PICTURE_B: flags |= V4L2_BUF_FLAG_BFRAME; break; case HFI_FRAME_NOTCODED: @@ -553,7 +577,7 @@ static const struct iris_hfi_gen1_response_pkt_info pkt_infos[] = { }, { .pkt = HFI_MSG_SESSION_FILL_BUFFER, - .pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt), + .pkt_sz = sizeof(struct hfi_msg_session_fbd_compressed_pkt), }, { .pkt = HFI_MSG_SESSION_FLUSH, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index 7ca5ae13d62b..f91295532099 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -88,33 +88,63 @@ static int iris_hfi_gen2_sys_pc_prep(struct iris_core *core) return ret; } -static u32 iris_hfi_gen2_get_port(u32 plane) +static u32 iris_hfi_gen2_get_port(struct iris_inst *inst, u32 plane) { - switch (plane) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return HFI_PORT_BITSTREAM; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - return HFI_PORT_RAW; - default: - return HFI_PORT_NONE; + if (inst->domain == DECODER) { + switch (plane) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return HFI_PORT_BITSTREAM; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return HFI_PORT_RAW; + default: + return HFI_PORT_NONE; + } + } else { + switch (plane) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return HFI_PORT_RAW; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return HFI_PORT_BITSTREAM; + default: + return HFI_PORT_NONE; + } } } -static u32 iris_hfi_gen2_get_port_from_buf_type(enum iris_buffer_type buffer_type) +static u32 iris_hfi_gen2_get_port_from_buf_type(struct iris_inst *inst, + enum iris_buffer_type buffer_type) { - switch (buffer_type) { - case BUF_INPUT: - case BUF_BIN: - case BUF_COMV: - case BUF_NON_COMV: - case BUF_LINE: - return HFI_PORT_BITSTREAM; - case BUF_OUTPUT: - case BUF_DPB: - return HFI_PORT_RAW; - case BUF_PERSIST: - default: - return HFI_PORT_NONE; + if (inst->domain == DECODER) { + switch (buffer_type) { + case BUF_INPUT: + case BUF_BIN: + case BUF_COMV: + case BUF_NON_COMV: + case BUF_LINE: + return HFI_PORT_BITSTREAM; + case BUF_OUTPUT: + case BUF_DPB: + return HFI_PORT_RAW; + case BUF_PERSIST: + default: + return HFI_PORT_NONE; + } + } else { + switch (buffer_type) { + case BUF_INPUT: + case BUF_VPSS: + return HFI_PORT_RAW; + case BUF_OUTPUT: + case BUF_BIN: + case BUF_COMV: + case BUF_NON_COMV: + case BUF_LINE: + case BUF_SCRATCH_2: + return HFI_PORT_BITSTREAM; + case BUF_ARP: + default: + return HFI_PORT_NONE; + } } } @@ -136,34 +166,77 @@ static int iris_hfi_gen2_session_set_property(struct iris_inst *inst, u32 packet inst_hfi_gen2->packet->size); } -static int iris_hfi_gen2_set_bitstream_resolution(struct iris_inst *inst) +static int iris_hfi_gen2_set_raw_resolution(struct iris_inst *inst, u32 plane) { - struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); u32 resolution = inst->fmt_src->fmt.pix_mp.width << 16 | inst->fmt_src->fmt.pix_mp.height; + u32 port = iris_hfi_gen2_get_port(inst, plane); - inst_hfi_gen2->src_subcr_params.bitstream_resolution = resolution; + return iris_hfi_gen2_session_set_property(inst, + HFI_PROP_RAW_RESOLUTION, + HFI_HOST_FLAGS_NONE, + port, + HFI_PAYLOAD_32_PACKED, + &resolution, + sizeof(u32)); +} + +static int iris_hfi_gen2_set_bitstream_resolution(struct iris_inst *inst, u32 plane) +{ + struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); + u32 port = iris_hfi_gen2_get_port(inst, plane); + enum hfi_packet_payload_info payload_type; + u32 resolution, codec_align; + + if (inst->domain == DECODER) { + resolution = inst->fmt_src->fmt.pix_mp.width << 16 | + inst->fmt_src->fmt.pix_mp.height; + inst_hfi_gen2->src_subcr_params.bitstream_resolution = resolution; + payload_type = HFI_PAYLOAD_U32; + } else { + codec_align = inst->codec == V4L2_PIX_FMT_HEVC ? 32 : 16; + resolution = ALIGN(inst->fmt_dst->fmt.pix_mp.width, codec_align) << 16 | + ALIGN(inst->fmt_dst->fmt.pix_mp.height, codec_align); + inst_hfi_gen2->dst_subcr_params.bitstream_resolution = resolution; + payload_type = HFI_PAYLOAD_32_PACKED; + } return iris_hfi_gen2_session_set_property(inst, HFI_PROP_BITSTREAM_RESOLUTION, HFI_HOST_FLAGS_NONE, port, - HFI_PAYLOAD_U32, + payload_type, &resolution, sizeof(u32)); } -static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst) +static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst, u32 plane) { - u32 bottom_offset = (inst->fmt_src->fmt.pix_mp.height - inst->crop.height); - u32 right_offset = (inst->fmt_src->fmt.pix_mp.width - inst->crop.width); struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - u32 left_offset = inst->crop.left; - u32 top_offset = inst->crop.top; + u32 port = iris_hfi_gen2_get_port(inst, plane); + u32 bottom_offset, right_offset; + u32 left_offset, top_offset; u32 payload[2]; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + bottom_offset = (inst->fmt_src->fmt.pix_mp.height - inst->crop.height); + right_offset = (inst->fmt_src->fmt.pix_mp.width - inst->crop.width); + left_offset = inst->crop.left; + top_offset = inst->crop.top; + } else { + bottom_offset = (inst->fmt_dst->fmt.pix_mp.height - inst->compose.height); + right_offset = (inst->fmt_dst->fmt.pix_mp.width - inst->compose.width); + left_offset = inst->compose.left; + top_offset = inst->compose.top; + } + } else { + bottom_offset = (inst->fmt_src->fmt.pix_mp.height - inst->crop.height); + right_offset = (inst->fmt_src->fmt.pix_mp.width - inst->crop.width); + left_offset = inst->crop.left; + top_offset = inst->crop.top; + } + payload[0] = FIELD_PREP(GENMASK(31, 16), left_offset) | top_offset; payload[1] = FIELD_PREP(GENMASK(31, 16), right_offset) | bottom_offset; inst_hfi_gen2->src_subcr_params.crop_offsets[0] = payload[0]; @@ -178,10 +251,10 @@ static int iris_hfi_gen2_set_crop_offsets(struct iris_inst *inst) sizeof(u64)); } -static int iris_hfi_gen2_set_bit_depth(struct iris_inst *inst) +static int iris_hfi_gen2_set_bit_depth(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 bitdepth = BIT_DEPTH_8; inst_hfi_gen2->src_subcr_params.bit_depth = bitdepth; @@ -195,10 +268,10 @@ static int iris_hfi_gen2_set_bit_depth(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_coded_frames(struct iris_inst *inst) +static int iris_hfi_gen2_set_coded_frames(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 coded_frames = 0; if (inst->fw_caps[CODED_FRAMES].value == CODED_FRAMES_PROGRESSIVE) @@ -214,11 +287,11 @@ static int iris_hfi_gen2_set_coded_frames(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_min_output_count(struct iris_inst *inst) +static int iris_hfi_gen2_set_min_output_count(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); u32 min_output = inst->buffers[BUF_OUTPUT].min_count; + u32 port = iris_hfi_gen2_get_port(inst, plane); inst_hfi_gen2->src_subcr_params.fw_min_count = min_output; @@ -231,10 +304,10 @@ static int iris_hfi_gen2_set_min_output_count(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_picture_order_count(struct iris_inst *inst) +static int iris_hfi_gen2_set_picture_order_count(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 poc = 0; inst_hfi_gen2->src_subcr_params.pic_order_cnt = poc; @@ -248,16 +321,16 @@ static int iris_hfi_gen2_set_picture_order_count(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_colorspace(struct iris_inst *inst) +static int iris_hfi_gen2_set_colorspace(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); struct v4l2_pix_format_mplane *pixmp = &inst->fmt_src->fmt.pix_mp; u32 video_signal_type_present_flag = 0, color_info; u32 matrix_coeff = HFI_MATRIX_COEFF_RESERVED; u32 video_format = UNSPECIFIED_COLOR_FORMAT; u32 full_range = V4L2_QUANTIZATION_DEFAULT; u32 transfer_char = HFI_TRANSFER_RESERVED; + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 colour_description_present_flag = 0; u32 primaries = HFI_PRIMARIES_RESERVED; @@ -291,10 +364,10 @@ static int iris_hfi_gen2_set_colorspace(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_profile(struct iris_inst *inst) +static int iris_hfi_gen2_set_profile(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); u32 profile = 0; switch (inst->codec) { @@ -320,10 +393,10 @@ static int iris_hfi_gen2_set_profile(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_level(struct iris_inst *inst) +static int iris_hfi_gen2_set_level(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); u32 level = 0; switch (inst->codec) { @@ -349,33 +422,63 @@ static int iris_hfi_gen2_set_level(struct iris_inst *inst) sizeof(u32)); } -static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst) +static int iris_hfi_gen2_set_opb_enable(struct iris_inst *inst, u32 plane) { - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, plane); + u32 opb_enable = iris_split_mode_enabled(inst); + + return iris_hfi_gen2_session_set_property(inst, + HFI_PROP_OPB_ENABLE, + HFI_HOST_FLAGS_NONE, + port, + HFI_PAYLOAD_U32, + &opb_enable, + sizeof(u32)); +} + +static int iris_hfi_gen2_set_colorformat(struct iris_inst *inst, u32 plane) +{ + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 hfi_colorformat, pixelformat; - pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; - hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? HFI_COLOR_FMT_NV12 : 0; + if (inst->domain == DECODER) { + pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; + hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FMT_NV12 : HFI_COLOR_FMT_NV12_UBWC; + } else { + pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; + hfi_colorformat = pixelformat == V4L2_PIX_FMT_NV12 ? + HFI_COLOR_FMT_NV12 : HFI_COLOR_FMT_NV12_UBWC; + } return iris_hfi_gen2_session_set_property(inst, HFI_PROP_COLOR_FORMAT, HFI_HOST_FLAGS_NONE, port, - HFI_PAYLOAD_U32, + HFI_PAYLOAD_U32_ENUM, &hfi_colorformat, sizeof(u32)); } -static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst) +static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst, u32 plane) { - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - u32 pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; - u32 scanline_y = inst->fmt_dst->fmt.pix_mp.height; - u32 stride_y = inst->fmt_dst->fmt.pix_mp.width; - u32 scanline_uv = scanline_y / 2; - u32 stride_uv = stride_y; + u32 pixelformat, stride_y, stride_uv, scanline_y, scanline_uv; + u32 port = iris_hfi_gen2_get_port(inst, plane); u32 payload[2]; + if (inst->domain == DECODER) { + pixelformat = inst->fmt_dst->fmt.pix_mp.pixelformat; + stride_y = inst->fmt_dst->fmt.pix_mp.width; + scanline_y = inst->fmt_dst->fmt.pix_mp.height; + } else { + pixelformat = inst->fmt_src->fmt.pix_mp.pixelformat; + stride_y = ALIGN(inst->fmt_src->fmt.pix_mp.width, 128); + scanline_y = ALIGN(inst->fmt_src->fmt.pix_mp.height, 32); + } + + stride_uv = stride_y; + scanline_uv = scanline_y / 2; + if (pixelformat != V4L2_PIX_FMT_NV12) return 0; @@ -386,15 +489,15 @@ static int iris_hfi_gen2_set_linear_stride_scanline(struct iris_inst *inst) HFI_PROP_LINEAR_STRIDE_SCANLINE, HFI_HOST_FLAGS_NONE, port, - HFI_PAYLOAD_U64, + HFI_PAYLOAD_64_PACKED, &payload, sizeof(u64)); } -static int iris_hfi_gen2_set_tier(struct iris_inst *inst) +static int iris_hfi_gen2_set_tier(struct iris_inst *inst, u32 plane) { struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); u32 tier = inst->fw_caps[TIER].value; inst_hfi_gen2->src_subcr_params.tier = tier; @@ -408,14 +511,29 @@ static int iris_hfi_gen2_set_tier(struct iris_inst *inst) sizeof(u32)); } +static int iris_hfi_gen2_set_frame_rate(struct iris_inst *inst, u32 plane) +{ + u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + u32 frame_rate = inst->frame_rate << 16; + + return iris_hfi_gen2_session_set_property(inst, + HFI_PROP_FRAME_RATE, + HFI_HOST_FLAGS_NONE, + port, + HFI_PAYLOAD_Q16, + &frame_rate, + sizeof(u32)); +} + static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 plane) { - struct iris_core *core = inst->core; + const struct iris_platform_data *pdata = inst->core->iris_platform_data; u32 config_params_size = 0, i, j; const u32 *config_params = NULL; int ret; static const struct iris_hfi_prop_type_handle prop_type_handle_arr[] = { + {HFI_PROP_RAW_RESOLUTION, iris_hfi_gen2_set_raw_resolution }, {HFI_PROP_BITSTREAM_RESOLUTION, iris_hfi_gen2_set_bitstream_resolution }, {HFI_PROP_CROP_OFFSETS, iris_hfi_gen2_set_crop_offsets }, {HFI_PROP_CODED_FRAMES, iris_hfi_gen2_set_coded_frames }, @@ -425,32 +543,39 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p {HFI_PROP_SIGNAL_COLOR_INFO, iris_hfi_gen2_set_colorspace }, {HFI_PROP_PROFILE, iris_hfi_gen2_set_profile }, {HFI_PROP_LEVEL, iris_hfi_gen2_set_level }, + {HFI_PROP_OPB_ENABLE, iris_hfi_gen2_set_opb_enable }, {HFI_PROP_COLOR_FORMAT, iris_hfi_gen2_set_colorformat }, {HFI_PROP_LINEAR_STRIDE_SCANLINE, iris_hfi_gen2_set_linear_stride_scanline }, {HFI_PROP_TIER, iris_hfi_gen2_set_tier }, + {HFI_PROP_FRAME_RATE, iris_hfi_gen2_set_frame_rate }, }; - if (V4L2_TYPE_IS_OUTPUT(plane)) { - switch (inst->codec) { - case V4L2_PIX_FMT_H264: - config_params = core->iris_platform_data->input_config_params_default; - config_params_size = - core->iris_platform_data->input_config_params_default_size; - break; - case V4L2_PIX_FMT_HEVC: - config_params = core->iris_platform_data->input_config_params_hevc; - config_params_size = - core->iris_platform_data->input_config_params_hevc_size; - break; - case V4L2_PIX_FMT_VP9: - config_params = core->iris_platform_data->input_config_params_vp9; - config_params_size = - core->iris_platform_data->input_config_params_vp9_size; - break; + if (inst->domain == DECODER) { + if (V4L2_TYPE_IS_OUTPUT(plane)) { + if (inst->codec == V4L2_PIX_FMT_H264) { + config_params = pdata->dec_input_config_params_default; + config_params_size = pdata->dec_input_config_params_default_size; + } else if (inst->codec == V4L2_PIX_FMT_HEVC) { + config_params = pdata->dec_input_config_params_hevc; + config_params_size = pdata->dec_input_config_params_hevc_size; + } else if (inst->codec == V4L2_PIX_FMT_VP9) { + config_params = pdata->dec_input_config_params_vp9; + config_params_size = pdata->dec_input_config_params_vp9_size; + } else { + return -EINVAL; + } + } else { + config_params = pdata->dec_output_config_params; + config_params_size = pdata->dec_output_config_params_size; } } else { - config_params = core->iris_platform_data->output_config_params; - config_params_size = core->iris_platform_data->output_config_params_size; + if (V4L2_TYPE_IS_OUTPUT(plane)) { + config_params = pdata->enc_input_config_params; + config_params_size = pdata->enc_input_config_params_size; + } else { + config_params = pdata->enc_output_config_params; + config_params_size = pdata->enc_output_config_params_size; + } } if (!config_params || !config_params_size) @@ -459,7 +584,7 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p for (i = 0; i < config_params_size; i++) { for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) { if (prop_type_handle_arr[j].type == config_params[i]) { - ret = prop_type_handle_arr[j].handle(inst); + ret = prop_type_handle_arr[j].handle(inst, plane); if (ret) return ret; break; @@ -477,14 +602,19 @@ static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst) switch (inst->codec) { case V4L2_PIX_FMT_H264: - codec = HFI_CODEC_DECODE_AVC; + if (inst->domain == ENCODER) + codec = HFI_CODEC_ENCODE_AVC; + else + codec = HFI_CODEC_DECODE_AVC; break; case V4L2_PIX_FMT_HEVC: - codec = HFI_CODEC_DECODE_HEVC; + if (inst->domain == ENCODER) + codec = HFI_CODEC_ENCODE_HEVC; + else + codec = HFI_CODEC_DECODE_HEVC; break; case V4L2_PIX_FMT_VP9: codec = HFI_CODEC_DECODE_VP9; - break; } iris_hfi_gen2_packet_session_property(inst, @@ -550,9 +680,11 @@ static int iris_hfi_gen2_session_open(struct iris_inst *inst) if (ret) goto fail_free_packet; - ret = iris_hfi_gen2_session_set_default_header(inst); - if (ret) - goto fail_free_packet; + if (inst->domain == DECODER) { + ret = iris_hfi_gen2_session_set_default_header(inst); + if (ret) + goto fail_free_packet; + } return 0; @@ -601,7 +733,7 @@ static int iris_hfi_gen2_session_subscribe_mode(struct iris_inst *inst, cmd, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, payload_type, payload, @@ -623,6 +755,9 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan u32 hfi_port = 0, i; int ret; + if (inst->domain == ENCODER) + return 0; + if ((V4L2_TYPE_IS_OUTPUT(plane) && inst_hfi_gen2->ipsc_properties_set) || (V4L2_TYPE_IS_CAPTURE(plane) && inst_hfi_gen2->opsc_properties_set)) { dev_err(core->dev, "invalid plane\n"); @@ -631,19 +766,19 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan switch (inst->codec) { case V4L2_PIX_FMT_H264: - change_param = core->iris_platform_data->input_config_params_default; + change_param = core->iris_platform_data->dec_input_config_params_default; change_param_size = - core->iris_platform_data->input_config_params_default_size; + core->iris_platform_data->dec_input_config_params_default_size; break; case V4L2_PIX_FMT_HEVC: - change_param = core->iris_platform_data->input_config_params_hevc; + change_param = core->iris_platform_data->dec_input_config_params_hevc; change_param_size = - core->iris_platform_data->input_config_params_hevc_size; + core->iris_platform_data->dec_input_config_params_hevc_size; break; case V4L2_PIX_FMT_VP9: - change_param = core->iris_platform_data->input_config_params_vp9; + change_param = core->iris_platform_data->dec_input_config_params_vp9; change_param_size = - core->iris_platform_data->input_config_params_vp9_size; + core->iris_platform_data->dec_input_config_params_vp9_size; break; } @@ -664,7 +799,7 @@ static int iris_hfi_gen2_subscribe_change_param(struct iris_inst *inst, u32 plan if (V4L2_TYPE_IS_OUTPUT(plane)) { inst_hfi_gen2->ipsc_properties_set = true; } else { - hfi_port = iris_hfi_gen2_get_port(V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + hfi_port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); memcpy(&inst_hfi_gen2->dst_subcr_params, &inst_hfi_gen2->src_subcr_params, sizeof(inst_hfi_gen2->src_subcr_params)); @@ -759,6 +894,9 @@ static int iris_hfi_gen2_subscribe_property(struct iris_inst *inst, u32 plane) payload[0] = HFI_MODE_PROPERTY; + if (inst->domain == ENCODER) + return 0; + if (V4L2_TYPE_IS_OUTPUT(plane)) { subscribe_prop_size = core->iris_platform_data->dec_input_prop_size; subcribe_prop = core->iris_platform_data->dec_input_prop; @@ -810,7 +948,7 @@ static int iris_hfi_gen2_session_start(struct iris_inst *inst, u32 plane) HFI_CMD_START, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_NONE, NULL, @@ -832,7 +970,7 @@ static int iris_hfi_gen2_session_stop(struct iris_inst *inst, u32 plane) (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED | HFI_HOST_FLAGS_NON_DISCARDABLE), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_NONE, NULL, @@ -854,7 +992,7 @@ static int iris_hfi_gen2_session_pause(struct iris_inst *inst, u32 plane) HFI_CMD_PAUSE, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_NONE, NULL, @@ -873,7 +1011,7 @@ static int iris_hfi_gen2_session_resume_drc(struct iris_inst *inst, u32 plane) HFI_CMD_RESUME, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_U32, &payload, @@ -892,7 +1030,7 @@ static int iris_hfi_gen2_session_resume_drain(struct iris_inst *inst, u32 plane) HFI_CMD_RESUME, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_U32, &payload, @@ -914,7 +1052,7 @@ static int iris_hfi_gen2_session_drain(struct iris_inst *inst, u32 plane) (HFI_HOST_FLAGS_RESPONSE_REQUIRED | HFI_HOST_FLAGS_INTR_REQUIRED | HFI_HOST_FLAGS_NON_DISCARDABLE), - iris_hfi_gen2_get_port(plane), + iris_hfi_gen2_get_port(inst, plane), inst->session_id, HFI_PAYLOAD_NONE, NULL, @@ -924,13 +1062,19 @@ static int iris_hfi_gen2_session_drain(struct iris_inst *inst, u32 plane) inst_hfi_gen2->packet->size); } -static u32 iris_hfi_gen2_buf_type_from_driver(enum iris_buffer_type buffer_type) +static u32 iris_hfi_gen2_buf_type_from_driver(u32 domain, enum iris_buffer_type buffer_type) { switch (buffer_type) { case BUF_INPUT: - return HFI_BUFFER_BITSTREAM; + if (domain == DECODER) + return HFI_BUFFER_BITSTREAM; + else + return HFI_BUFFER_RAW; case BUF_OUTPUT: - return HFI_BUFFER_RAW; + if (domain == DECODER) + return HFI_BUFFER_RAW; + else + return HFI_BUFFER_BITSTREAM; case BUF_BIN: return HFI_BUFFER_BIN; case BUF_COMV: @@ -940,9 +1084,14 @@ static u32 iris_hfi_gen2_buf_type_from_driver(enum iris_buffer_type buffer_type) case BUF_LINE: return HFI_BUFFER_LINE; case BUF_DPB: + case BUF_SCRATCH_2: return HFI_BUFFER_DPB; case BUF_PERSIST: return HFI_BUFFER_PERSIST; + case BUF_ARP: + return HFI_BUFFER_ARP; + case BUF_VPSS: + return HFI_BUFFER_VPSS; default: return 0; } @@ -965,16 +1114,17 @@ static int iris_set_num_comv(struct iris_inst *inst) &num_comv, sizeof(u32)); } -static void iris_hfi_gen2_get_buffer(struct iris_buffer *buffer, struct iris_hfi_buffer *buf) +static void iris_hfi_gen2_get_buffer(u32 domain, struct iris_buffer *buffer, + struct iris_hfi_buffer *buf) { memset(buf, 0, sizeof(*buf)); - buf->type = iris_hfi_gen2_buf_type_from_driver(buffer->type); + buf->type = iris_hfi_gen2_buf_type_from_driver(domain, buffer->type); buf->index = buffer->index; buf->base_address = buffer->device_addr; buf->addr_offset = 0; buf->buffer_size = buffer->buffer_size; - if (buffer->type == BUF_INPUT) + if (domain == DECODER && buffer->type == BUF_INPUT) buf->buffer_size = ALIGN(buffer->buffer_size, 256); buf->data_offset = buffer->data_offset; buf->data_size = buffer->data_size; @@ -991,14 +1141,14 @@ static int iris_hfi_gen2_session_queue_buffer(struct iris_inst *inst, struct iri u32 port; int ret; - iris_hfi_gen2_get_buffer(buffer, &hfi_buffer); + iris_hfi_gen2_get_buffer(inst->domain, buffer, &hfi_buffer); if (buffer->type == BUF_COMV) { ret = iris_set_num_comv(inst); if (ret) return ret; } - port = iris_hfi_gen2_get_port_from_buf_type(buffer->type); + port = iris_hfi_gen2_get_port_from_buf_type(inst, buffer->type); iris_hfi_gen2_packet_session_command(inst, HFI_CMD_BUFFER, HFI_HOST_FLAGS_INTR_REQUIRED, @@ -1018,9 +1168,9 @@ static int iris_hfi_gen2_session_release_buffer(struct iris_inst *inst, struct i struct iris_hfi_buffer hfi_buffer; u32 port; - iris_hfi_gen2_get_buffer(buffer, &hfi_buffer); + iris_hfi_gen2_get_buffer(inst->domain, buffer, &hfi_buffer); hfi_buffer.flags |= HFI_BUF_HOST_FLAG_RELEASE; - port = iris_hfi_gen2_get_port_from_buf_type(buffer->type); + port = iris_hfi_gen2_get_port_from_buf_type(inst, buffer->type); iris_hfi_gen2_packet_session_command(inst, HFI_CMD_BUFFER, @@ -1062,5 +1212,5 @@ void iris_hfi_gen2_command_ops_init(struct iris_core *core) struct iris_inst *iris_hfi_gen2_get_instance(void) { - return kzalloc(sizeof(struct iris_inst_hfi_gen2), GFP_KERNEL); + return (struct iris_inst *)kzalloc(sizeof(struct iris_inst_hfi_gen2), GFP_KERNEL); } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index 5f13dc11bea5..1b6a4dbac828 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -49,18 +49,49 @@ #define HFI_PROP_TIER 0x03000109 #define HFI_PROP_STAGE 0x0300010a #define HFI_PROP_PIPE 0x0300010b +#define HFI_PROP_FRAME_RATE 0x0300010c #define HFI_PROP_LUMA_CHROMA_BIT_DEPTH 0x0300010f #define HFI_PROP_CODED_FRAMES 0x03000120 #define HFI_PROP_CABAC_SESSION 0x03000121 #define HFI_PROP_BUFFER_HOST_MAX_COUNT 0x03000123 #define HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT 0x03000124 #define HFI_PROP_PIC_ORDER_CNT_TYPE 0x03000128 + +enum hfi_rate_control { + HFI_RC_VBR_CFR = 0x00000000, + HFI_RC_CBR_CFR = 0x00000001, + HFI_RC_CQ = 0x00000002, + HFI_RC_OFF = 0x00000003, + HFI_RC_CBR_VFR = 0x00000004, + HFI_RC_LOSSLESS = 0x00000005, +}; + +#define HFI_PROP_RATE_CONTROL 0x0300012a +#define HFI_PROP_QP_PACKED 0x0300012e +#define HFI_PROP_MIN_QP_PACKED 0x0300012f +#define HFI_PROP_MAX_QP_PACKED 0x03000130 +#define HFI_PROP_TOTAL_BITRATE 0x0300013b +#define HFI_PROP_MAX_GOP_FRAMES 0x03000146 +#define HFI_PROP_MAX_B_FRAMES 0x03000147 #define HFI_PROP_QUALITY_MODE 0x03000148 + +enum hfi_seq_header_mode { + HFI_SEQ_HEADER_SEPERATE_FRAME = 0x00000001, + HFI_SEQ_HEADER_JOINED_WITH_1ST_FRAME = 0x00000002, + HFI_SEQ_HEADER_PREFIX_WITH_SYNC_FRAME = 0x00000004, + HFI_SEQ_HEADER_METADATA = 0x00000008, +}; + +#define HFI_PROP_SEQ_HEADER_MODE 0x03000149 #define HFI_PROP_SIGNAL_COLOR_INFO 0x03000155 #define HFI_PROP_PICTURE_TYPE 0x03000162 #define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168 #define HFI_PROP_DEC_START_FROM_RAP_FRAME 0x03000169 #define HFI_PROP_NO_OUTPUT 0x0300016a +#define HFI_PROP_BUFFER_MARK 0x0300016c +#define HFI_PROP_RAW_RESOLUTION 0x03000178 +#define HFI_PROP_TOTAL_PEAK_BITRATE 0x0300017C +#define HFI_PROP_OPB_ENABLE 0x03000184 #define HFI_PROP_COMV_BUFFER_COUNT 0x03000193 #define HFI_PROP_END 0x03FFFFFF @@ -111,13 +142,13 @@ enum hfi_codec_type { }; enum hfi_picture_type { - HFI_PICTURE_IDR = 0x00000001, - HFI_PICTURE_P = 0x00000002, - HFI_PICTURE_B = 0x00000004, - HFI_PICTURE_I = 0x00000008, - HFI_PICTURE_CRA = 0x00000010, - HFI_PICTURE_BLA = 0x00000020, - HFI_PICTURE_NOSHOW = 0x00000040, + HFI_GEN2_PICTURE_IDR = 0x00000001, + HFI_GEN2_PICTURE_P = 0x00000002, + HFI_GEN2_PICTURE_B = 0x00000004, + HFI_GEN2_PICTURE_I = 0x00000008, + HFI_GEN2_PICTURE_CRA = 0x00000010, + HFI_GEN2_PICTURE_BLA = 0x00000020, + HFI_GEN2_PICTURE_NOSHOW = 0x00000040, }; enum hfi_buffer_type { diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c index a8c30fc5c0d0..2f1f118eae4f 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c @@ -29,7 +29,8 @@ struct iris_hfi_gen2_packet_handle { int (*handle)(struct iris_inst *inst, struct iris_hfi_packet *pkt); }; -static u32 iris_hfi_gen2_buf_type_to_driver(enum hfi_buffer_type buf_type) +static u32 iris_hfi_gen2_buf_type_to_driver(struct iris_inst *inst, + enum hfi_buffer_type buf_type) { switch (buf_type) { case HFI_BUFFER_BITSTREAM: @@ -47,7 +48,10 @@ static u32 iris_hfi_gen2_buf_type_to_driver(enum hfi_buffer_type buf_type) case HFI_BUFFER_LINE: return BUF_LINE; case HFI_BUFFER_DPB: - return BUF_DPB; + if (inst->domain == DECODER) + return BUF_DPB; + else + return BUF_SCRATCH_2; case HFI_BUFFER_PERSIST: return BUF_PERSIST; default: @@ -87,17 +91,18 @@ static bool iris_hfi_gen2_is_valid_hfi_port(u32 port, u32 buffer_type) static int iris_hfi_gen2_get_driver_buffer_flags(struct iris_inst *inst, u32 hfi_flags) { - u32 keyframe = HFI_PICTURE_IDR | HFI_PICTURE_I | HFI_PICTURE_CRA | HFI_PICTURE_BLA; struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); + u32 keyframe = HFI_GEN2_PICTURE_IDR | HFI_GEN2_PICTURE_I | + HFI_GEN2_PICTURE_CRA | HFI_GEN2_PICTURE_BLA; u32 driver_flags = 0; - if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_NOSHOW) + if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_GEN2_PICTURE_NOSHOW) driver_flags |= V4L2_BUF_FLAG_ERROR; else if (inst_hfi_gen2->hfi_frame_info.picture_type & keyframe) driver_flags |= V4L2_BUF_FLAG_KEYFRAME; - else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_P) + else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_GEN2_PICTURE_P) driver_flags |= V4L2_BUF_FLAG_PFRAME; - else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_PICTURE_B) + else if (inst_hfi_gen2->hfi_frame_info.picture_type & HFI_GEN2_PICTURE_B) driver_flags |= V4L2_BUF_FLAG_BFRAME; if (inst_hfi_gen2->hfi_frame_info.data_corrupt || inst_hfi_gen2->hfi_frame_info.overflow) @@ -420,11 +425,10 @@ static void iris_hfi_gen2_handle_dequeue_buffers(struct iris_inst *inst) static int iris_hfi_gen2_handle_release_internal_buffer(struct iris_inst *inst, struct iris_hfi_buffer *buffer) { - u32 buf_type = iris_hfi_gen2_buf_type_to_driver(buffer->type); + u32 buf_type = iris_hfi_gen2_buf_type_to_driver(inst, buffer->type); struct iris_buffers *buffers = &inst->buffers[buf_type]; struct iris_buffer *buf, *iter; bool found = false; - int ret = 0; list_for_each_entry(iter, &buffers->list, list) { if (iter->device_addr == buffer->base_address) { @@ -437,10 +441,8 @@ static int iris_hfi_gen2_handle_release_internal_buffer(struct iris_inst *inst, return -EINVAL; buf->attr &= ~BUF_ATTR_QUEUED; - if (buf->attr & BUF_ATTR_PENDING_RELEASE) - ret = iris_destroy_internal_buffer(inst, buf); - return ret; + return iris_destroy_internal_buffer(inst, buf); } static int iris_hfi_gen2_handle_session_stop(struct iris_inst *inst, @@ -478,12 +480,22 @@ static int iris_hfi_gen2_handle_session_buffer(struct iris_inst *inst, if (!iris_hfi_gen2_is_valid_hfi_port(pkt->port, buffer->type)) return 0; - if (buffer->type == HFI_BUFFER_BITSTREAM) - return iris_hfi_gen2_handle_input_buffer(inst, buffer); - else if (buffer->type == HFI_BUFFER_RAW) - return iris_hfi_gen2_handle_output_buffer(inst, buffer); - else - return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer); + if (inst->domain == DECODER) { + if (buffer->type == HFI_BUFFER_BITSTREAM) + return iris_hfi_gen2_handle_input_buffer(inst, buffer); + else if (buffer->type == HFI_BUFFER_RAW) + return iris_hfi_gen2_handle_output_buffer(inst, buffer); + else + return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer); + } else { + if (buffer->type == HFI_BUFFER_RAW) + return iris_hfi_gen2_handle_input_buffer(inst, buffer); + else if (buffer->type == HFI_BUFFER_BITSTREAM) + return iris_hfi_gen2_handle_output_buffer(inst, buffer); + else + return iris_hfi_gen2_handle_release_internal_buffer(inst, buffer); + } + return 0; } static int iris_hfi_gen2_handle_session_drain(struct iris_inst *inst, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_queue.c b/drivers/media/platform/qcom/iris/iris_hfi_queue.c index 221dcd09e1e1..b3ed06297953 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_queue.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_queue.c @@ -142,7 +142,6 @@ int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size) } mutex_unlock(&core->lock); - pm_runtime_mark_last_busy(core->dev); pm_runtime_put_autosuspend(core->dev); return 0; diff --git a/drivers/media/platform/qcom/iris/iris_instance.h b/drivers/media/platform/qcom/iris/iris_instance.h index 0e1f5799b72d..62fbb30691ff 100644 --- a/drivers/media/platform/qcom/iris/iris_instance.h +++ b/drivers/media/platform/qcom/iris/iris_instance.h @@ -12,6 +12,25 @@ #include "iris_core.h" #include "iris_utils.h" +#define DEFAULT_WIDTH 320 +#define DEFAULT_HEIGHT 240 + +enum iris_fmt_type_out { + IRIS_FMT_H264, + IRIS_FMT_HEVC, + IRIS_FMT_VP9, +}; + +enum iris_fmt_type_cap { + IRIS_FMT_NV12, + IRIS_FMT_QC08C, +}; + +struct iris_fmt { + u32 pixfmt; + u32 type; +}; + /** * struct iris_inst - holds per video instance parameters * @@ -24,7 +43,9 @@ * @fmt_src: structure of v4l2_format for source * @fmt_dst: structure of v4l2_format for destination * @ctrl_handler: reference of v4l2 ctrl handler + * @domain: domain type: encoder or decoder * @crop: structure of crop info + * @compose: structure of compose info * @completion: structure of signal completions * @flush_completion: structure of signal completions for flush cmd * @flush_responses_pending: counter to track number of pending flush responses @@ -45,6 +66,9 @@ * @metadata_idx: index for metadata buffer * @codec: codec type * @last_buffer_dequeued: a flag to indicate that last buffer is sent by driver + * @frame_rate: frame rate of current instance + * @operating_rate: operating rate of current instance + * @hfi_rc_type: rate control type */ struct iris_inst { @@ -57,7 +81,9 @@ struct iris_inst { struct v4l2_format *fmt_src; struct v4l2_format *fmt_dst; struct v4l2_ctrl_handler ctrl_handler; + enum domain_type domain; struct iris_hfi_rect_desc crop; + struct iris_hfi_rect_desc compose; struct completion completion; struct completion flush_completion; u32 flush_responses_pending; @@ -78,6 +104,9 @@ struct iris_inst { u32 metadata_idx; u32 codec; bool last_buffer_dequeued; + u32 frame_rate; + u32 operating_rate; + u32 hfi_rc_type; }; #endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index adafdce8a856..8d8cdb56a3c7 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -7,6 +7,7 @@ #define __IRIS_PLATFORM_COMMON_H__ #include <linux/bits.h> +#include "iris_buffer.h" struct iris_core; struct iris_inst; @@ -21,7 +22,13 @@ struct iris_inst; #define DEFAULT_MAX_HOST_BUF_COUNT 64 #define DEFAULT_MAX_HOST_BURST_BUF_COUNT 256 #define DEFAULT_FPS 30 -#define NUM_MBS_8K ((8192 * 4352) / 256) +#define MAXIMUM_FPS 480 +#define NUM_MBS_8K ((8192 * 4352) / 256) +#define MIN_QP_8BIT 1 +#define MAX_QP 51 +#define MAX_QP_HEVC 63 +#define DEFAULT_QP 20 +#define BITRATE_DEFAULT 20000000 enum stage_type { STAGE_1 = 1, @@ -34,15 +41,22 @@ enum pipe_type { PIPE_4 = 4, }; -extern struct iris_platform_data qcs8300_data; -extern struct iris_platform_data sm8250_data; -extern struct iris_platform_data sm8550_data; -extern struct iris_platform_data sm8650_data; +extern const struct iris_platform_data qcs8300_data; +extern const struct iris_platform_data sc7280_data; +extern const struct iris_platform_data sm8250_data; +extern const struct iris_platform_data sm8550_data; +extern const struct iris_platform_data sm8650_data; +extern const struct iris_platform_data sm8750_data; enum platform_clk_type { - IRIS_AXI_CLK, + IRIS_AXI_CLK, /* AXI0 in case of platforms with multiple AXI clocks */ IRIS_CTRL_CLK, + IRIS_AHB_CLK, IRIS_HW_CLK, + IRIS_HW_AHB_CLK, + IRIS_AXI1_CLK, + IRIS_CTRL_FREERUN_CLK, + IRIS_HW_FREERUN_CLK, }; struct platform_clk_data { @@ -78,6 +92,8 @@ struct platform_inst_caps { u32 mb_cycles_fw; u32 mb_cycles_fw_vpp; u32 num_comv; + u32 max_frame_rate; + u32 max_operating_rate; }; enum platform_inst_fw_cap_type { @@ -88,6 +104,7 @@ enum platform_inst_fw_cap_type { LEVEL_HEVC, LEVEL_VP9, INPUT_BUF_HOST_MAX_COUNT, + OUTPUT_BUF_HOST_MAX_COUNT, STAGE, PIPE, POC, @@ -95,6 +112,37 @@ enum platform_inst_fw_cap_type { BIT_DEPTH, RAP_FRAME, TIER, + HEADER_MODE, + PREPEND_SPSPPS_TO_IDR, + BITRATE, + BITRATE_PEAK, + BITRATE_MODE, + FRAME_SKIP_MODE, + FRAME_RC_ENABLE, + GOP_SIZE, + ENTROPY_MODE, + MIN_FRAME_QP_H264, + MIN_FRAME_QP_HEVC, + MAX_FRAME_QP_H264, + MAX_FRAME_QP_HEVC, + I_FRAME_MIN_QP_H264, + I_FRAME_MIN_QP_HEVC, + P_FRAME_MIN_QP_H264, + P_FRAME_MIN_QP_HEVC, + B_FRAME_MIN_QP_H264, + B_FRAME_MIN_QP_HEVC, + I_FRAME_MAX_QP_H264, + I_FRAME_MAX_QP_HEVC, + P_FRAME_MAX_QP_H264, + P_FRAME_MAX_QP_HEVC, + B_FRAME_MAX_QP_H264, + B_FRAME_MAX_QP_HEVC, + I_FRAME_QP_H264, + I_FRAME_QP_HEVC, + P_FRAME_QP_H264, + P_FRAME_QP_HEVC, + B_FRAME_QP_H264, + B_FRAME_QP_HEVC, INST_FW_CAP_MAX, }; @@ -149,6 +197,7 @@ struct iris_platform_data { void (*init_hfi_command_ops)(struct iris_core *core); void (*init_hfi_response_ops)(struct iris_core *core); struct iris_inst *(*get_instance)(void); + u32 (*get_vpu_buffer_size)(struct iris_inst *inst, enum iris_buffer_type buffer_type); const struct vpu_ops *vpu_ops; void (*set_preset_registers)(struct iris_core *core); const struct icc_info *icc_tbl; @@ -169,24 +218,33 @@ struct iris_platform_data { const char *fwname; u32 pas_id; struct platform_inst_caps *inst_caps; - struct platform_inst_fw_cap *inst_fw_caps; - u32 inst_fw_caps_size; + const struct platform_inst_fw_cap *inst_fw_caps_dec; + u32 inst_fw_caps_dec_size; + const struct platform_inst_fw_cap *inst_fw_caps_enc; + u32 inst_fw_caps_enc_size; struct tz_cp_config *tz_cp_config_data; u32 core_arch; u32 hw_response_timeout; struct ubwc_config_data *ubwc_config; u32 num_vpp_pipe; + bool no_aon; u32 max_session_count; /* max number of macroblocks per frame supported */ u32 max_core_mbpf; - const u32 *input_config_params_default; - unsigned int input_config_params_default_size; - const u32 *input_config_params_hevc; - unsigned int input_config_params_hevc_size; - const u32 *input_config_params_vp9; - unsigned int input_config_params_vp9_size; - const u32 *output_config_params; - unsigned int output_config_params_size; + /* max number of macroblocks per second supported */ + u32 max_core_mbps; + const u32 *dec_input_config_params_default; + unsigned int dec_input_config_params_default_size; + const u32 *dec_input_config_params_hevc; + unsigned int dec_input_config_params_hevc_size; + const u32 *dec_input_config_params_vp9; + unsigned int dec_input_config_params_vp9_size; + const u32 *dec_output_config_params; + unsigned int dec_output_config_params_size; + const u32 *enc_input_config_params; + unsigned int enc_input_config_params_size; + const u32 *enc_output_config_params; + unsigned int enc_output_config_params_size; const u32 *dec_input_prop; unsigned int dec_input_prop_size; const u32 *dec_output_prop_avc; @@ -199,6 +257,10 @@ struct iris_platform_data { unsigned int dec_ip_int_buf_tbl_size; const u32 *dec_op_int_buf_tbl; unsigned int dec_op_int_buf_tbl_size; + const u32 *enc_ip_int_buf_tbl; + unsigned int enc_ip_int_buf_tbl_size; + const u32 *enc_op_int_buf_tbl; + unsigned int enc_op_int_buf_tbl_size; }; #endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen1.c b/drivers/media/platform/qcom/iris/iris_platform_gen1.c new file mode 100644 index 000000000000..34cbeb8f52e2 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_gen1.c @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "iris_core.h" +#include "iris_ctrls.h" +#include "iris_platform_common.h" +#include "iris_resources.h" +#include "iris_hfi_gen1.h" +#include "iris_hfi_gen1_defines.h" +#include "iris_vpu_buffer.h" +#include "iris_vpu_common.h" + +#include "iris_platform_sc7280.h" + +#define BITRATE_MIN 32000 +#define BITRATE_MAX 160000000 +#define BITRATE_PEAK_DEFAULT (BITRATE_DEFAULT * 2) +#define BITRATE_STEP 100 + +static const struct platform_inst_fw_cap inst_fw_cap_sm8250_dec[] = { + { + .cap_id = PIPE, + /* .max, .min and .value are set via platform data */ + .step_or_mask = 1, + .hfi_id = HFI_PROPERTY_PARAM_WORK_ROUTE, + .set = iris_set_pipe, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, + .set = iris_set_stage, + }, +}; + +static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, + .set = iris_set_stage, + }, + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .hfi_id = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile_level_gen1, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_header_mode_gen1, + }, + { + .cap_id = BITRATE, + .min = BITRATE_MIN, + .max = BITRATE_MAX, + .step_or_mask = BITRATE_STEP, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_bitrate, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROPERTY_PARAM_VENC_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_bitrate_mode_gen1, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_RC_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = (1 << 16) - 1, + .step_or_mask = 1, + .value = 30, + .set = iris_set_u32 + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .hfi_id = HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_entropy_mode_gen1, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP_HEVC, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP_HEVC, + .step_or_mask = 1, + .value = MAX_QP_HEVC, + .hfi_id = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_qp_range, + }, +}; + +static struct platform_inst_caps platform_inst_cap_sm8250 = { + .min_frame_width = 128, + .max_frame_width = 8192, + .min_frame_height = 128, + .max_frame_height = 8192, + .max_mbpf = 138240, + .mb_cycles_vsp = 25, + .mb_cycles_vpp = 200, + .max_frame_rate = MAXIMUM_FPS, + .max_operating_rate = MAXIMUM_FPS, +}; + +static void iris_set_sm8250_preset_registers(struct iris_core *core) +{ + writel(0x0, core->reg_base + 0xB0088); +} + +static const struct icc_info sm8250_icc_table[] = { + { "cpu-cfg", 1000, 1000 }, + { "video-mem", 1000, 15000000 }, +}; + +static const char * const sm8250_clk_reset_table[] = { "bus", "core" }; + +static const struct bw_info sm8250_bw_table_dec[] = { + { ((4096 * 2160) / 256) * 60, 2403000 }, + { ((4096 * 2160) / 256) * 30, 1224000 }, + { ((1920 * 1080) / 256) * 60, 812000 }, + { ((1920 * 1080) / 256) * 30, 416000 }, +}; + +static const char * const sm8250_pmdomain_table[] = { "venus", "vcodec0" }; + +static const char * const sm8250_opp_pd_table[] = { "mx" }; + +static const struct platform_clk_data sm8250_clk_table[] = { + {IRIS_AXI_CLK, "iface" }, + {IRIS_CTRL_CLK, "core" }, + {IRIS_HW_CLK, "vcodec0_core" }, +}; + +static struct tz_cp_config tz_cp_config_sm8250 = { + .cp_start = 0, + .cp_size = 0x25800000, + .cp_nonpixel_start = 0x01000000, + .cp_nonpixel_size = 0x24800000, +}; + +static const u32 sm8250_vdec_input_config_param_default[] = { + HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE, + HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, + HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO, + HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL, + HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM, + HFI_PROPERTY_PARAM_FRAME_SIZE, + HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL, + HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE, +}; + +static const u32 sm8250_venc_input_config_param[] = { + HFI_PROPERTY_CONFIG_FRAME_RATE, + HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO, + HFI_PROPERTY_PARAM_FRAME_SIZE, + HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, + HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL, +}; + +static const u32 sm8250_dec_ip_int_buf_tbl[] = { + BUF_BIN, + BUF_SCRATCH_1, +}; + +static const u32 sm8250_dec_op_int_buf_tbl[] = { + BUF_DPB, +}; + +static const u32 sm8250_enc_ip_int_buf_tbl[] = { + BUF_BIN, + BUF_SCRATCH_1, + BUF_SCRATCH_2, +}; + +const struct iris_platform_data sm8250_data = { + .get_instance = iris_hfi_gen1_get_instance, + .init_hfi_command_ops = &iris_hfi_gen1_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen1_response_ops_init, + .get_vpu_buffer_size = iris_vpu_buf_size, + .vpu_ops = &iris_vpu2_ops, + .set_preset_registers = iris_set_sm8250_preset_registers, + .icc_tbl = sm8250_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8250_icc_table), + .clk_rst_tbl = sm8250_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8250_clk_reset_table), + .bw_tbl_dec = sm8250_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8250_bw_table_dec), + .pmdomain_tbl = sm8250_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8250_pmdomain_table), + .opp_pd_tbl = sm8250_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8250_opp_pd_table), + .clk_tbl = sm8250_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8250_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu-1.0/venus.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8250, + .inst_fw_caps_dec = inst_fw_cap_sm8250_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8250_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8250_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8250_enc), + .tz_cp_config_data = &tz_cp_config_sm8250, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .num_vpp_pipe = 4, + .max_session_count = 16, + .max_core_mbpf = NUM_MBS_8K, + .max_core_mbps = ((7680 * 4320) / 256) * 60, + .dec_input_config_params_default = + sm8250_vdec_input_config_param_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8250_vdec_input_config_param_default), + .enc_input_config_params = sm8250_venc_input_config_param, + .enc_input_config_params_size = + ARRAY_SIZE(sm8250_venc_input_config_param), + + .dec_ip_int_buf_tbl = sm8250_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8250_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_op_int_buf_tbl), + + .enc_ip_int_buf_tbl = sm8250_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_enc_ip_int_buf_tbl), +}; + +const struct iris_platform_data sc7280_data = { + .get_instance = iris_hfi_gen1_get_instance, + .init_hfi_command_ops = &iris_hfi_gen1_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen1_response_ops_init, + .get_vpu_buffer_size = iris_vpu_buf_size, + .vpu_ops = &iris_vpu2_ops, + .set_preset_registers = iris_set_sm8250_preset_registers, + .icc_tbl = sm8250_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8250_icc_table), + .bw_tbl_dec = sc7280_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sc7280_bw_table_dec), + .pmdomain_tbl = sm8250_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8250_pmdomain_table), + .opp_pd_tbl = sc7280_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sc7280_opp_pd_table), + .clk_tbl = sc7280_clk_table, + .clk_tbl_size = ARRAY_SIZE(sc7280_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu/vpu20_p1.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8250, + .inst_fw_caps_dec = inst_fw_cap_sm8250_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8250_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8250_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8250_enc), + .tz_cp_config_data = &tz_cp_config_sm8250, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .num_vpp_pipe = 1, + .no_aon = true, + .max_session_count = 16, + .max_core_mbpf = 4096 * 2176 / 256 * 2 + 1920 * 1088 / 256, + /* max spec for SC7280 is 4096x2176@60fps */ + .max_core_mbps = 4096 * 2176 / 256 * 60, + .dec_input_config_params_default = + sm8250_vdec_input_config_param_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8250_vdec_input_config_param_default), + .enc_input_config_params = sm8250_venc_input_config_param, + .enc_input_config_params_size = + ARRAY_SIZE(sm8250_venc_input_config_param), + + .dec_ip_int_buf_tbl = sm8250_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8250_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_op_int_buf_tbl), + + .enc_ip_int_buf_tbl = sm8250_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_enc_ip_int_buf_tbl), +}; diff --git a/drivers/media/platform/qcom/iris/iris_platform_gen2.c b/drivers/media/platform/qcom/iris/iris_platform_gen2.c index d3026b2bcb70..c1989240c248 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_gen2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2025 Linaro Ltd */ #include "iris_core.h" @@ -8,14 +9,17 @@ #include "iris_hfi_gen2.h" #include "iris_hfi_gen2_defines.h" #include "iris_platform_common.h" +#include "iris_vpu_buffer.h" #include "iris_vpu_common.h" #include "iris_platform_qcs8300.h" #include "iris_platform_sm8650.h" +#include "iris_platform_sm8750.h" #define VIDEO_ARCH_LX 1 +#define BITRATE_MAX 245000000 -static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { +static const struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = { { .cap_id = PROFILE_H264, .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, @@ -156,10 +160,8 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { }, { .cap_id = PIPE, - .min = PIPE_1, - .max = PIPE_4, + /* .max, .min and .value are set via platform data */ .step_or_mask = 1, - .value = PIPE_4, .hfi_id = HFI_PROP_PIPE, .set = iris_set_pipe, }, @@ -199,6 +201,393 @@ static struct platform_inst_fw_cap inst_fw_cap_sm8550[] = { }, }; +static const struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROP_SEQ_HEADER_MODE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_header_mode_gen2, + }, + { + .cap_id = PREPEND_SPSPPS_TO_IDR, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + }, + { + .cap_id = BITRATE, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_bitrate, + }, + { + .cap_id = BITRATE_PEAK, + .min = 1, + .max = BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_PEAK_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_peak_bitrate, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROP_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_bitrate_mode_gen2, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_RC_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 2 * DEFAULT_FPS - 1, + .hfi_id = HFI_PROP_MAX_GOP_FRAMES, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_u32, + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .hfi_id = HFI_PROP_CABAC_SESSION, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_entropy_mode_gen2, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = I_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = I_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = OUTPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_u32, + }, +}; + static struct platform_inst_caps platform_inst_cap_sm8550 = { .min_frame_width = 96, .max_frame_width = 8192, @@ -209,6 +598,8 @@ static struct platform_inst_caps platform_inst_cap_sm8550 = { .mb_cycles_fw = 489583, .mb_cycles_fw_vpp = 66234, .num_comv = 0, + .max_frame_rate = MAXIMUM_FPS, + .max_operating_rate = MAXIMUM_FPS, }; static void iris_set_sm8550_preset_registers(struct iris_core *core) @@ -289,11 +680,26 @@ static const u32 sm8550_vdec_input_config_param_vp9[] = { HFI_PROP_LEVEL, }; +static const u32 sm8550_venc_input_config_params[] = { + HFI_PROP_COLOR_FORMAT, + HFI_PROP_RAW_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LINEAR_STRIDE_SCANLINE, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + static const u32 sm8550_vdec_output_config_params[] = { + HFI_PROP_OPB_ENABLE, HFI_PROP_COLOR_FORMAT, HFI_PROP_LINEAR_STRIDE_SCANLINE, }; +static const u32 sm8550_venc_output_config_params[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_FRAME_RATE, +}; + static const u32 sm8550_vdec_subscribe_input_properties[] = { HFI_PROP_NO_OUTPUT, }; @@ -322,10 +728,19 @@ static const u32 sm8550_dec_op_int_buf_tbl[] = { BUF_DPB, }; -struct iris_platform_data sm8550_data = { +static const u32 sm8550_enc_op_int_buf_tbl[] = { + BUF_BIN, + BUF_COMV, + BUF_NON_COMV, + BUF_LINE, + BUF_SCRATCH_2, +}; + +const struct iris_platform_data sm8550_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .get_vpu_buffer_size = iris_vpu_buf_size, .vpu_ops = &iris_vpu3_ops, .set_preset_registers = iris_set_sm8550_preset_registers, .icc_tbl = sm8550_icc_table, @@ -345,8 +760,10 @@ struct iris_platform_data sm8550_data = { .fwname = "qcom/vpu/vpu30_p4.mbn", .pas_id = IRIS_PAS_ID, .inst_caps = &platform_inst_cap_sm8550, - .inst_fw_caps = inst_fw_cap_sm8550, - .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8550), + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), .tz_cp_config_data = &tz_cp_config_sm8550, .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, @@ -354,22 +771,33 @@ struct iris_platform_data sm8550_data = { .num_vpp_pipe = 4, .max_session_count = 16, .max_core_mbpf = NUM_MBS_8K * 2, - .input_config_params_default = + .max_core_mbps = ((7680 * 4320) / 256) * 60, + .dec_input_config_params_default = sm8550_vdec_input_config_params_default, - .input_config_params_default_size = + .dec_input_config_params_default_size = ARRAY_SIZE(sm8550_vdec_input_config_params_default), - .input_config_params_hevc = + .dec_input_config_params_hevc = sm8550_vdec_input_config_param_hevc, - .input_config_params_hevc_size = + .dec_input_config_params_hevc_size = ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), - .input_config_params_vp9 = + .dec_input_config_params_vp9 = sm8550_vdec_input_config_param_vp9, - .input_config_params_vp9_size = + .dec_input_config_params_vp9_size = ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), - .output_config_params = + .dec_output_config_params = sm8550_vdec_output_config_params, - .output_config_params_size = + .dec_output_config_params_size = ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + .dec_input_prop = sm8550_vdec_subscribe_input_properties, .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, @@ -386,6 +814,9 @@ struct iris_platform_data sm8550_data = { .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; /* @@ -395,10 +826,11 @@ struct iris_platform_data sm8550_data = { * - controller_rst_tbl to sm8650_controller_reset_table * - fwname to "qcom/vpu/vpu33_p4.mbn" */ -struct iris_platform_data sm8650_data = { +const struct iris_platform_data sm8650_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .get_vpu_buffer_size = iris_vpu33_buf_size, .vpu_ops = &iris_vpu33_ops, .set_preset_registers = iris_set_sm8550_preset_registers, .icc_tbl = sm8550_icc_table, @@ -420,8 +852,10 @@ struct iris_platform_data sm8650_data = { .fwname = "qcom/vpu/vpu33_p4.mbn", .pas_id = IRIS_PAS_ID, .inst_caps = &platform_inst_cap_sm8550, - .inst_fw_caps = inst_fw_cap_sm8550, - .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8550), + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), .tz_cp_config_data = &tz_cp_config_sm8550, .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, @@ -429,22 +863,33 @@ struct iris_platform_data sm8650_data = { .num_vpp_pipe = 4, .max_session_count = 16, .max_core_mbpf = NUM_MBS_8K * 2, - .input_config_params_default = + .max_core_mbps = ((7680 * 4320) / 256) * 60, + .dec_input_config_params_default = sm8550_vdec_input_config_params_default, - .input_config_params_default_size = + .dec_input_config_params_default_size = ARRAY_SIZE(sm8550_vdec_input_config_params_default), - .input_config_params_hevc = + .dec_input_config_params_hevc = sm8550_vdec_input_config_param_hevc, - .input_config_params_hevc_size = + .dec_input_config_params_hevc_size = ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), - .input_config_params_vp9 = + .dec_input_config_params_vp9 = sm8550_vdec_input_config_param_vp9, - .input_config_params_vp9_size = + .dec_input_config_params_vp9_size = ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), - .output_config_params = + .dec_output_config_params = sm8550_vdec_output_config_params, - .output_config_params_size = + .dec_output_config_params_size = ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + .dec_input_prop = sm8550_vdec_subscribe_input_properties, .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, @@ -461,17 +906,101 @@ struct iris_platform_data sm8650_data = { .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), +}; + +const struct iris_platform_data sm8750_data = { + .get_instance = iris_hfi_gen2_get_instance, + .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, + .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .vpu_ops = &iris_vpu35_ops, + .set_preset_registers = iris_set_sm8550_preset_registers, + .icc_tbl = sm8550_icc_table, + .icc_tbl_size = ARRAY_SIZE(sm8550_icc_table), + .clk_rst_tbl = sm8750_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(sm8750_clk_reset_table), + .bw_tbl_dec = sm8550_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8550_bw_table_dec), + .pmdomain_tbl = sm8550_pmdomain_table, + .pmdomain_tbl_size = ARRAY_SIZE(sm8550_pmdomain_table), + .opp_pd_tbl = sm8550_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(sm8550_opp_pd_table), + .clk_tbl = sm8750_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8750_clk_table), + /* Upper bound of DMA address range */ + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu/vpu35_p4.mbn", + .pas_id = IRIS_PAS_ID, + .inst_caps = &platform_inst_cap_sm8550, + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), + .tz_cp_config_data = &tz_cp_config_sm8550, + .core_arch = VIDEO_ARCH_LX, + .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, + .ubwc_config = &ubwc_config_sm8550, + .num_vpp_pipe = 4, + .max_session_count = 16, + .max_core_mbpf = NUM_MBS_8K * 2, + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = + sm8550_vdec_output_config_params, + .dec_output_config_params_size = + ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + + .dec_input_prop = sm8550_vdec_subscribe_input_properties, + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), + + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; /* * Shares most of SM8550 data except: * - inst_caps to platform_inst_cap_qcs8300 - * - inst_fw_caps to inst_fw_cap_qcs8300 */ -struct iris_platform_data qcs8300_data = { +const struct iris_platform_data qcs8300_data = { .get_instance = iris_hfi_gen2_get_instance, .init_hfi_command_ops = iris_hfi_gen2_command_ops_init, .init_hfi_response_ops = iris_hfi_gen2_response_ops_init, + .get_vpu_buffer_size = iris_vpu_buf_size, .vpu_ops = &iris_vpu3_ops, .set_preset_registers = iris_set_sm8550_preset_registers, .icc_tbl = sm8550_icc_table, @@ -491,8 +1020,10 @@ struct iris_platform_data qcs8300_data = { .fwname = "qcom/vpu/vpu30_p4_s6.mbn", .pas_id = IRIS_PAS_ID, .inst_caps = &platform_inst_cap_qcs8300, - .inst_fw_caps = inst_fw_cap_qcs8300, - .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_qcs8300), + .inst_fw_caps_dec = inst_fw_cap_sm8550_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_sm8550_dec), + .inst_fw_caps_enc = inst_fw_cap_sm8550_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_sm8550_enc), .tz_cp_config_data = &tz_cp_config_sm8550, .core_arch = VIDEO_ARCH_LX, .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, @@ -500,22 +1031,33 @@ struct iris_platform_data qcs8300_data = { .num_vpp_pipe = 2, .max_session_count = 16, .max_core_mbpf = ((4096 * 2176) / 256) * 4, - .input_config_params_default = + .max_core_mbps = (((3840 * 2176) / 256) * 120), + .dec_input_config_params_default = sm8550_vdec_input_config_params_default, - .input_config_params_default_size = + .dec_input_config_params_default_size = ARRAY_SIZE(sm8550_vdec_input_config_params_default), - .input_config_params_hevc = + .dec_input_config_params_hevc = sm8550_vdec_input_config_param_hevc, - .input_config_params_hevc_size = + .dec_input_config_params_hevc_size = ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), - .input_config_params_vp9 = + .dec_input_config_params_vp9 = sm8550_vdec_input_config_param_vp9, - .input_config_params_vp9_size = + .dec_input_config_params_vp9_size = ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), - .output_config_params = + .dec_output_config_params = sm8550_vdec_output_config_params, - .output_config_params_size = + .dec_output_config_params_size = ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + .dec_input_prop = sm8550_vdec_subscribe_input_properties, .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, @@ -532,4 +1074,7 @@ struct iris_platform_data qcs8300_data = { .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; diff --git a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h index a8d66ed388a3..61025f1e965b 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h +++ b/drivers/media/platform/qcom/iris/iris_platform_qcs8300.h @@ -3,189 +3,8 @@ * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. */ -static struct platform_inst_fw_cap inst_fw_cap_qcs8300[] = { - { - .cap_id = PROFILE_H264, - .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, - .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH), - .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, - .hfi_id = HFI_PROP_PROFILE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = PROFILE_HEVC, - .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, - .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | - BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE), - .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, - .hfi_id = HFI_PROP_PROFILE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = PROFILE_VP9, - .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, - .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | - BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), - .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, - .hfi_id = HFI_PROP_PROFILE, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = LEVEL_H264, - .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, - .max = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), - .value = V4L2_MPEG_VIDEO_H264_LEVEL_6_1, - .hfi_id = HFI_PROP_LEVEL, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = LEVEL_HEVC, - .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, - .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | - BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), - .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, - .hfi_id = HFI_PROP_LEVEL, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = LEVEL_VP9, - .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, - .max = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | - BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), - .value = V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, - .hfi_id = HFI_PROP_LEVEL, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = TIER, - .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, - .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, - .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | - BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), - .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, - .hfi_id = HFI_PROP_TIER, - .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, - .set = iris_set_u32_enum, - }, - { - .cap_id = INPUT_BUF_HOST_MAX_COUNT, - .min = DEFAULT_MAX_HOST_BUF_COUNT, - .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, - .step_or_mask = 1, - .value = DEFAULT_MAX_HOST_BUF_COUNT, - .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, - .flags = CAP_FLAG_INPUT_PORT, - .set = iris_set_u32, - }, - { - .cap_id = STAGE, - .min = STAGE_1, - .max = STAGE_2, - .step_or_mask = 1, - .value = STAGE_2, - .hfi_id = HFI_PROP_STAGE, - .set = iris_set_stage, - }, - { - .cap_id = PIPE, - .min = PIPE_1, - .max = PIPE_2, - .step_or_mask = 1, - .value = PIPE_2, - .hfi_id = HFI_PROP_PIPE, - .set = iris_set_pipe, - }, - { - .cap_id = POC, - .min = 0, - .max = 2, - .step_or_mask = 1, - .value = 1, - .hfi_id = HFI_PROP_PIC_ORDER_CNT_TYPE, - }, - { - .cap_id = CODED_FRAMES, - .min = CODED_FRAMES_PROGRESSIVE, - .max = CODED_FRAMES_PROGRESSIVE, - .step_or_mask = 0, - .value = CODED_FRAMES_PROGRESSIVE, - .hfi_id = HFI_PROP_CODED_FRAMES, - }, - { - .cap_id = BIT_DEPTH, - .min = BIT_DEPTH_8, - .max = BIT_DEPTH_8, - .step_or_mask = 1, - .value = BIT_DEPTH_8, - .hfi_id = HFI_PROP_LUMA_CHROMA_BIT_DEPTH, - }, - { - .cap_id = RAP_FRAME, - .min = 0, - .max = 1, - .step_or_mask = 1, - .value = 1, - .hfi_id = HFI_PROP_DEC_START_FROM_RAP_FRAME, - .flags = CAP_FLAG_INPUT_PORT, - .set = iris_set_u32, - }, -}; +#ifndef __IRIS_PLATFORM_QCS8300_H__ +#define __IRIS_PLATFORM_QCS8300_H__ static struct platform_inst_caps platform_inst_cap_qcs8300 = { .min_frame_width = 96, @@ -197,4 +16,8 @@ static struct platform_inst_caps platform_inst_cap_qcs8300 = { .mb_cycles_fw = 326389, .mb_cycles_fw_vpp = 44156, .num_comv = 0, + .max_frame_rate = MAXIMUM_FPS, + .max_operating_rate = MAXIMUM_FPS, }; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_sc7280.h b/drivers/media/platform/qcom/iris/iris_platform_sc7280.h new file mode 100644 index 000000000000..f1bef4d4bcfe --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_sc7280.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + */ + +#ifndef __IRIS_PLATFORM_SC7280_H__ +#define __IRIS_PLATFORM_SC7280_H__ + +static const struct bw_info sc7280_bw_table_dec[] = { + { ((3840 * 2160) / 256) * 60, 1896000, }, + { ((3840 * 2160) / 256) * 30, 968000, }, + { ((1920 * 1080) / 256) * 60, 618000, }, + { ((1920 * 1080) / 256) * 30, 318000, }, +}; + +static const char * const sc7280_opp_pd_table[] = { "cx" }; + +static const struct platform_clk_data sc7280_clk_table[] = { + {IRIS_CTRL_CLK, "core" }, + {IRIS_AXI_CLK, "iface" }, + {IRIS_AHB_CLK, "bus" }, + {IRIS_HW_CLK, "vcodec_core" }, + {IRIS_HW_AHB_CLK, "vcodec_bus" }, +}; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c b/drivers/media/platform/qcom/iris/iris_platform_sm8250.c deleted file mode 100644 index 8d0816a67ae0..000000000000 --- a/drivers/media/platform/qcom/iris/iris_platform_sm8250.c +++ /dev/null @@ -1,140 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. - */ - -#include "iris_core.h" -#include "iris_ctrls.h" -#include "iris_platform_common.h" -#include "iris_resources.h" -#include "iris_hfi_gen1.h" -#include "iris_hfi_gen1_defines.h" -#include "iris_vpu_common.h" - -static struct platform_inst_fw_cap inst_fw_cap_sm8250[] = { - { - .cap_id = PIPE, - .min = PIPE_1, - .max = PIPE_4, - .step_or_mask = 1, - .value = PIPE_4, - .hfi_id = HFI_PROPERTY_PARAM_WORK_ROUTE, - .set = iris_set_pipe, - }, - { - .cap_id = STAGE, - .min = STAGE_1, - .max = STAGE_2, - .step_or_mask = 1, - .value = STAGE_2, - .hfi_id = HFI_PROPERTY_PARAM_WORK_MODE, - .set = iris_set_stage, - }, -}; - -static struct platform_inst_caps platform_inst_cap_sm8250 = { - .min_frame_width = 128, - .max_frame_width = 8192, - .min_frame_height = 128, - .max_frame_height = 8192, - .max_mbpf = 138240, - .mb_cycles_vsp = 25, - .mb_cycles_vpp = 200, -}; - -static void iris_set_sm8250_preset_registers(struct iris_core *core) -{ - writel(0x0, core->reg_base + 0xB0088); -} - -static const struct icc_info sm8250_icc_table[] = { - { "cpu-cfg", 1000, 1000 }, - { "video-mem", 1000, 15000000 }, -}; - -static const char * const sm8250_clk_reset_table[] = { "bus", "core" }; - -static const struct bw_info sm8250_bw_table_dec[] = { - { ((4096 * 2160) / 256) * 60, 2403000 }, - { ((4096 * 2160) / 256) * 30, 1224000 }, - { ((1920 * 1080) / 256) * 60, 812000 }, - { ((1920 * 1080) / 256) * 30, 416000 }, -}; - -static const char * const sm8250_pmdomain_table[] = { "venus", "vcodec0" }; - -static const char * const sm8250_opp_pd_table[] = { "mx" }; - -static const struct platform_clk_data sm8250_clk_table[] = { - {IRIS_AXI_CLK, "iface" }, - {IRIS_CTRL_CLK, "core" }, - {IRIS_HW_CLK, "vcodec0_core" }, -}; - -static struct tz_cp_config tz_cp_config_sm8250 = { - .cp_start = 0, - .cp_size = 0x25800000, - .cp_nonpixel_start = 0x01000000, - .cp_nonpixel_size = 0x24800000, -}; - -static const u32 sm8250_vdec_input_config_param_default[] = { - HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE, - HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT, - HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO, - HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL, - HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM, - HFI_PROPERTY_PARAM_FRAME_SIZE, - HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL, - HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE, -}; - -static const u32 sm8250_dec_ip_int_buf_tbl[] = { - BUF_BIN, - BUF_SCRATCH_1, -}; - -static const u32 sm8250_dec_op_int_buf_tbl[] = { - BUF_DPB, -}; - -struct iris_platform_data sm8250_data = { - .get_instance = iris_hfi_gen1_get_instance, - .init_hfi_command_ops = &iris_hfi_gen1_command_ops_init, - .init_hfi_response_ops = iris_hfi_gen1_response_ops_init, - .vpu_ops = &iris_vpu2_ops, - .set_preset_registers = iris_set_sm8250_preset_registers, - .icc_tbl = sm8250_icc_table, - .icc_tbl_size = ARRAY_SIZE(sm8250_icc_table), - .clk_rst_tbl = sm8250_clk_reset_table, - .clk_rst_tbl_size = ARRAY_SIZE(sm8250_clk_reset_table), - .bw_tbl_dec = sm8250_bw_table_dec, - .bw_tbl_dec_size = ARRAY_SIZE(sm8250_bw_table_dec), - .pmdomain_tbl = sm8250_pmdomain_table, - .pmdomain_tbl_size = ARRAY_SIZE(sm8250_pmdomain_table), - .opp_pd_tbl = sm8250_opp_pd_table, - .opp_pd_tbl_size = ARRAY_SIZE(sm8250_opp_pd_table), - .clk_tbl = sm8250_clk_table, - .clk_tbl_size = ARRAY_SIZE(sm8250_clk_table), - /* Upper bound of DMA address range */ - .dma_mask = 0xe0000000 - 1, - .fwname = "qcom/vpu-1.0/venus.mbn", - .pas_id = IRIS_PAS_ID, - .inst_caps = &platform_inst_cap_sm8250, - .inst_fw_caps = inst_fw_cap_sm8250, - .inst_fw_caps_size = ARRAY_SIZE(inst_fw_cap_sm8250), - .tz_cp_config_data = &tz_cp_config_sm8250, - .hw_response_timeout = HW_RESPONSE_TIMEOUT_VALUE, - .num_vpp_pipe = 4, - .max_session_count = 16, - .max_core_mbpf = NUM_MBS_8K, - .input_config_params_default = - sm8250_vdec_input_config_param_default, - .input_config_params_default_size = - ARRAY_SIZE(sm8250_vdec_input_config_param_default), - - .dec_ip_int_buf_tbl = sm8250_dec_ip_int_buf_tbl, - .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_ip_int_buf_tbl), - .dec_op_int_buf_tbl = sm8250_dec_op_int_buf_tbl, - .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8250_dec_op_int_buf_tbl), -}; diff --git a/drivers/media/platform/qcom/iris/iris_platform_sm8750.h b/drivers/media/platform/qcom/iris/iris_platform_sm8750.h new file mode 100644 index 000000000000..719056656a5b --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_sm8750.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2025 Linaro Ltd + */ + +#ifndef __MEDIA_IRIS_PLATFORM_SM8750_H__ +#define __MEDIA_IRIS_PLATFORM_SM8750_H__ + +static const char * const sm8750_clk_reset_table[] = { + "bus0", "bus1", "core", "vcodec0_core" +}; + +static const struct platform_clk_data sm8750_clk_table[] = { + {IRIS_AXI_CLK, "iface" }, + {IRIS_CTRL_CLK, "core" }, + {IRIS_HW_CLK, "vcodec0_core" }, + {IRIS_AXI1_CLK, "iface1" }, + {IRIS_CTRL_FREERUN_CLK, "core_freerun" }, + {IRIS_HW_FREERUN_CLK, "vcodec0_core_freerun" }, +}; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index 4e6e92357968..9bc9b34c2576 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -146,7 +146,7 @@ static int iris_init_resources(struct iris_core *core) return iris_init_resets(core); } -static int iris_register_video_device(struct iris_core *core) +static int iris_register_video_device(struct iris_core *core, enum domain_type type) { struct video_device *vdev; int ret; @@ -155,19 +155,29 @@ static int iris_register_video_device(struct iris_core *core) if (!vdev) return -ENOMEM; - strscpy(vdev->name, "qcom-iris-decoder", sizeof(vdev->name)); vdev->release = video_device_release; vdev->fops = core->iris_v4l2_file_ops; - vdev->ioctl_ops = core->iris_v4l2_ioctl_ops; vdev->vfl_dir = VFL_DIR_M2M; vdev->v4l2_dev = &core->v4l2_dev; vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + if (type == DECODER) { + strscpy(vdev->name, "qcom-iris-decoder", sizeof(vdev->name)); + vdev->ioctl_ops = core->iris_v4l2_ioctl_ops_dec; + core->vdev_dec = vdev; + } else if (type == ENCODER) { + strscpy(vdev->name, "qcom-iris-encoder", sizeof(vdev->name)); + vdev->ioctl_ops = core->iris_v4l2_ioctl_ops_enc; + core->vdev_enc = vdev; + } else { + ret = -EINVAL; + goto err_vdev_release; + } + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret) goto err_vdev_release; - core->vdev_dec = vdev; video_set_drvdata(vdev, core); return 0; @@ -189,6 +199,7 @@ static void iris_remove(struct platform_device *pdev) iris_core_deinit(core); video_unregister_device(core->vdev_dec); + video_unregister_device(core->vdev_enc); v4l2_device_unregister(&core->v4l2_dev); @@ -258,17 +269,21 @@ static int iris_probe(struct platform_device *pdev) if (ret) return ret; - ret = iris_register_video_device(core); + ret = iris_register_video_device(core, DECODER); if (ret) goto err_v4l2_unreg; + ret = iris_register_video_device(core, ENCODER); + if (ret) + goto err_vdev_unreg_dec; + platform_set_drvdata(pdev, core); dma_mask = core->iris_platform_data->dma_mask; ret = dma_set_mask_and_coherent(dev, dma_mask); if (ret) - goto err_vdev_unreg; + goto err_vdev_unreg_enc; dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); dma_set_seg_boundary(&pdev->dev, DMA_BIT_MASK(32)); @@ -277,11 +292,13 @@ static int iris_probe(struct platform_device *pdev) pm_runtime_use_autosuspend(core->dev); ret = devm_pm_runtime_enable(core->dev); if (ret) - goto err_vdev_unreg; + goto err_vdev_unreg_enc; return 0; -err_vdev_unreg: +err_vdev_unreg_enc: + video_unregister_device(core->vdev_enc); +err_vdev_unreg_dec: video_unregister_device(core->vdev_dec); err_v4l2_unreg: v4l2_device_unregister(&core->v4l2_dev); @@ -341,6 +358,10 @@ static const struct of_device_id iris_dt_match[] = { }, #if (!IS_ENABLED(CONFIG_VIDEO_QCOM_VENUS)) { + .compatible = "qcom,sc7280-venus", + .data = &sc7280_data, + }, + { .compatible = "qcom,sm8250-venus", .data = &sm8250_data, }, @@ -353,6 +374,10 @@ static const struct of_device_id iris_dt_match[] = { .compatible = "qcom,sm8650-iris", .data = &sm8650_data, }, + { + .compatible = "qcom,sm8750-iris", + .data = &sm8750_data, + }, { }, }; MODULE_DEVICE_TABLE(of, iris_dt_match); diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c index cf32f268b703..164490c49c95 100644 --- a/drivers/media/platform/qcom/iris/iris_resources.c +++ b/drivers/media/platform/qcom/iris/iris_resources.c @@ -112,7 +112,7 @@ int iris_prepare_enable_clock(struct iris_core *core, enum platform_clk_type clk clock = iris_get_clk_by_type(core, clk_type); if (!clock) - return -EINVAL; + return -ENOENT; return clk_prepare_enable(clock); } diff --git a/drivers/media/platform/qcom/iris/iris_state.c b/drivers/media/platform/qcom/iris/iris_state.c index 104e1687ad39..d14472414750 100644 --- a/drivers/media/platform/qcom/iris/iris_state.c +++ b/drivers/media/platform/qcom/iris/iris_state.c @@ -122,7 +122,8 @@ static bool iris_inst_allow_sub_state(struct iris_inst *inst, enum iris_inst_sub return false; case IRIS_INST_OUTPUT_STREAMING: if (sub_state & (IRIS_INST_SUB_DRC_LAST | - IRIS_INST_SUB_DRAIN_LAST | IRIS_INST_SUB_OUTPUT_PAUSE)) + IRIS_INST_SUB_DRAIN_LAST | IRIS_INST_SUB_OUTPUT_PAUSE | + IRIS_INST_SUB_LOAD_RESOURCES)) return true; return false; case IRIS_INST_STREAMING: @@ -251,7 +252,7 @@ bool iris_drc_pending(struct iris_inst *inst) inst->sub_state & IRIS_INST_SUB_DRC_LAST; } -static inline bool iris_drain_pending(struct iris_inst *inst) +bool iris_drain_pending(struct iris_inst *inst) { return inst->sub_state & IRIS_INST_SUB_DRAIN && inst->sub_state & IRIS_INST_SUB_DRAIN_LAST; @@ -262,11 +263,11 @@ bool iris_allow_cmd(struct iris_inst *inst, u32 cmd) struct vb2_queue *src_q = v4l2_m2m_get_src_vq(inst->m2m_ctx); struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); - if (cmd == V4L2_DEC_CMD_START) { + if (cmd == V4L2_DEC_CMD_START || cmd == V4L2_ENC_CMD_START) { if (vb2_is_streaming(src_q) || vb2_is_streaming(dst_q)) if (iris_drc_pending(inst) || iris_drain_pending(inst)) return true; - } else if (cmd == V4L2_DEC_CMD_STOP) { + } else if (cmd == V4L2_DEC_CMD_STOP || cmd == V4L2_ENC_CMD_STOP) { if (vb2_is_streaming(src_q)) if (inst->sub_state != IRIS_INST_SUB_DRAIN) return true; diff --git a/drivers/media/platform/qcom/iris/iris_state.h b/drivers/media/platform/qcom/iris/iris_state.h index e718386dbe04..b09fa54cf17e 100644 --- a/drivers/media/platform/qcom/iris/iris_state.h +++ b/drivers/media/platform/qcom/iris/iris_state.h @@ -141,5 +141,6 @@ int iris_inst_sub_state_change_drc_last(struct iris_inst *inst); int iris_inst_sub_state_change_pause(struct iris_inst *inst, u32 plane); bool iris_allow_cmd(struct iris_inst *inst, u32 cmd); bool iris_drc_pending(struct iris_inst *inst); +bool iris_drain_pending(struct iris_inst *inst); #endif diff --git a/drivers/media/platform/qcom/iris/iris_utils.c b/drivers/media/platform/qcom/iris/iris_utils.c index 83c70d6a2d90..e2f1131de431 100644 --- a/drivers/media/platform/qcom/iris/iris_utils.c +++ b/drivers/media/platform/qcom/iris/iris_utils.c @@ -34,7 +34,8 @@ int iris_get_mbpf(struct iris_inst *inst) bool iris_split_mode_enabled(struct iris_inst *inst) { - return inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12; + return inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_NV12 || + inst->fmt_dst->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_QC08C; } void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, @@ -88,3 +89,39 @@ struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id) mutex_unlock(&core->lock); return NULL; } + +int iris_check_core_mbpf(struct iris_inst *inst) +{ + struct iris_core *core = inst->core; + struct iris_inst *instance; + u32 total_mbpf = 0; + + mutex_lock(&core->lock); + list_for_each_entry(instance, &core->instances, list) + total_mbpf += iris_get_mbpf(instance); + mutex_unlock(&core->lock); + + if (total_mbpf > core->iris_platform_data->max_core_mbpf) + return -ENOMEM; + + return 0; +} + +int iris_check_core_mbps(struct iris_inst *inst) +{ + struct iris_core *core = inst->core; + struct iris_inst *instance; + u32 total_mbps = 0, fps = 0; + + mutex_lock(&core->lock); + list_for_each_entry(instance, &core->instances, list) { + fps = max(instance->frame_rate, instance->operating_rate); + total_mbps += iris_get_mbpf(instance) * fps; + } + mutex_unlock(&core->lock); + + if (total_mbps > core->iris_platform_data->max_core_mbps) + return -ENOMEM; + + return 0; +} diff --git a/drivers/media/platform/qcom/iris/iris_utils.h b/drivers/media/platform/qcom/iris/iris_utils.h index 49869cf7a376..75740181122f 100644 --- a/drivers/media/platform/qcom/iris/iris_utils.h +++ b/drivers/media/platform/qcom/iris/iris_utils.h @@ -49,5 +49,7 @@ struct iris_inst *iris_get_instance(struct iris_core *core, u32 session_id); void iris_helper_buffers_done(struct iris_inst *inst, unsigned int type, enum vb2_buffer_state state); int iris_wait_for_session_response(struct iris_inst *inst, bool is_flush); +int iris_check_core_mbpf(struct iris_inst *inst); +int iris_check_core_mbps(struct iris_inst *inst); #endif diff --git a/drivers/media/platform/qcom/iris/iris_vb2.c b/drivers/media/platform/qcom/iris/iris_vb2.c index 8b17c7c39487..db8768d8a8f6 100644 --- a/drivers/media/platform/qcom/iris/iris_vb2.c +++ b/drivers/media/platform/qcom/iris/iris_vb2.c @@ -7,28 +7,13 @@ #include <media/v4l2-event.h> #include <media/v4l2-mem2mem.h> +#include "iris_common.h" #include "iris_instance.h" #include "iris_vb2.h" #include "iris_vdec.h" +#include "iris_venc.h" #include "iris_power.h" -static int iris_check_core_mbpf(struct iris_inst *inst) -{ - struct iris_core *core = inst->core; - struct iris_inst *instance; - u32 total_mbpf = 0; - - mutex_lock(&core->lock); - list_for_each_entry(instance, &core->instances, list) - total_mbpf += iris_get_mbpf(instance); - mutex_unlock(&core->lock); - - if (total_mbpf > core->iris_platform_data->max_core_mbpf) - return -ENOMEM; - - return 0; -} - static int iris_check_inst_mbpf(struct iris_inst *inst) { struct platform_inst_caps *caps; @@ -173,9 +158,6 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) inst = vb2_get_drv_priv(q); - if (V4L2_TYPE_IS_CAPTURE(q->type) && inst->state == IRIS_INST_INIT) - return 0; - mutex_lock(&inst->lock); if (inst->state == IRIS_INST_ERROR) { ret = -EBUSY; @@ -194,16 +176,35 @@ int iris_vb2_start_streaming(struct vb2_queue *q, unsigned int count) if (ret) goto error; - if (V4L2_TYPE_IS_OUTPUT(q->type)) - ret = iris_vdec_streamon_input(inst); - else if (V4L2_TYPE_IS_CAPTURE(q->type)) - ret = iris_vdec_streamon_output(inst); + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + if (inst->domain == DECODER) + ret = iris_vdec_streamon_input(inst); + else + ret = iris_venc_streamon_input(inst); + } else if (V4L2_TYPE_IS_CAPTURE(q->type)) { + if (inst->domain == DECODER) + ret = iris_vdec_streamon_output(inst); + else + ret = iris_venc_streamon_output(inst); + } if (ret) goto error; buf_type = iris_v4l2_type_to_driver(q->type); - ret = iris_queue_deferred_buffers(inst, buf_type); + if (inst->domain == DECODER) { + if (inst->state == IRIS_INST_STREAMING) + ret = iris_queue_internal_deferred_buffers(inst, BUF_DPB); + if (!ret) + ret = iris_queue_deferred_buffers(inst, buf_type); + } else { + if (inst->state == IRIS_INST_STREAMING) { + ret = iris_queue_deferred_buffers(inst, BUF_INPUT); + if (!ret) + ret = iris_queue_deferred_buffers(inst, BUF_OUTPUT); + } + } + if (ret) goto error; @@ -230,20 +231,22 @@ void iris_vb2_stop_streaming(struct vb2_queue *q) return; mutex_lock(&inst->lock); + if (inst->state == IRIS_INST_ERROR) + goto exit; if (!V4L2_TYPE_IS_OUTPUT(q->type) && !V4L2_TYPE_IS_CAPTURE(q->type)) goto exit; - ret = iris_vdec_session_streamoff(inst, q->type); + ret = iris_session_streamoff(inst, q->type); if (ret) goto exit; exit: - iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); - if (ret) + if (ret) { + iris_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); iris_inst_change_state(inst, IRIS_INST_ERROR); - + } mutex_unlock(&inst->lock); } @@ -326,7 +329,10 @@ void iris_vb2_buf_queue(struct vb2_buffer *vb2) v4l2_m2m_buf_queue(m2m_ctx, vbuf); - ret = iris_vdec_qbuf(inst, vbuf); + if (inst->domain == DECODER) + ret = iris_vdec_qbuf(inst, vbuf); + else + ret = iris_venc_qbuf(inst, vbuf); exit: if (ret) { diff --git a/drivers/media/platform/qcom/iris/iris_vdec.c b/drivers/media/platform/qcom/iris/iris_vdec.c index d670b51c5839..69ffe52590d3 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.c +++ b/drivers/media/platform/qcom/iris/iris_vdec.c @@ -7,14 +7,13 @@ #include <media/v4l2-mem2mem.h> #include "iris_buffer.h" +#include "iris_common.h" #include "iris_ctrls.h" #include "iris_instance.h" #include "iris_power.h" #include "iris_vdec.h" #include "iris_vpu_buffer.h" -#define DEFAULT_WIDTH 320 -#define DEFAULT_HEIGHT 240 #define DEFAULT_CODEC_ALIGNMENT 16 int iris_vdec_inst_init(struct iris_inst *inst) @@ -56,7 +55,7 @@ int iris_vdec_inst_init(struct iris_inst *inst) inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); inst->buffers[BUF_OUTPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; - memcpy(&inst->fw_caps[0], &core->inst_fw_caps[0], + memcpy(&inst->fw_caps[0], &core->inst_fw_caps_dec[0], INST_FW_CAP_MAX * sizeof(struct platform_inst_fw_cap)); return iris_ctrls_init(inst); @@ -68,7 +67,7 @@ void iris_vdec_inst_deinit(struct iris_inst *inst) kfree(inst->fmt_src); } -static const struct iris_fmt iris_vdec_formats[] = { +static const struct iris_fmt iris_vdec_formats_out[] = { [IRIS_FMT_H264] = { .pixfmt = V4L2_PIX_FMT_H264, .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, @@ -83,12 +82,35 @@ static const struct iris_fmt iris_vdec_formats[] = { }, }; +static const struct iris_fmt iris_vdec_formats_cap[] = { + [IRIS_FMT_NV12] = { + .pixfmt = V4L2_PIX_FMT_NV12, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + [IRIS_FMT_QC08C] = { + .pixfmt = V4L2_PIX_FMT_QC08C, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, +}; + static const struct iris_fmt * find_format(struct iris_inst *inst, u32 pixfmt, u32 type) { - unsigned int size = ARRAY_SIZE(iris_vdec_formats); - const struct iris_fmt *fmt = iris_vdec_formats; + const struct iris_fmt *fmt = NULL; + unsigned int size = 0; unsigned int i; + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + fmt = iris_vdec_formats_out; + size = ARRAY_SIZE(iris_vdec_formats_out); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + fmt = iris_vdec_formats_cap; + size = ARRAY_SIZE(iris_vdec_formats_cap); + break; + default: + return NULL; + } for (i = 0; i < size; i++) { if (fmt[i].pixfmt == pixfmt) @@ -104,8 +126,21 @@ find_format(struct iris_inst *inst, u32 pixfmt, u32 type) static const struct iris_fmt * find_format_by_index(struct iris_inst *inst, u32 index, u32 type) { - const struct iris_fmt *fmt = iris_vdec_formats; - unsigned int size = ARRAY_SIZE(iris_vdec_formats); + const struct iris_fmt *fmt = NULL; + unsigned int size = 0; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + fmt = iris_vdec_formats_out; + size = ARRAY_SIZE(iris_vdec_formats_out); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + fmt = iris_vdec_formats_cap; + size = ARRAY_SIZE(iris_vdec_formats_cap); + break; + default: + return NULL; + } if (index >= size || fmt[index].type != type) return NULL; @@ -127,9 +162,10 @@ int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) f->flags = V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_DYN_RESOLUTION; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (f->index) + fmt = find_format_by_index(inst, f->index, f->type); + if (!fmt) return -EINVAL; - f->pixelformat = V4L2_PIX_FMT_NV12; + f->pixelformat = fmt->pixfmt; break; default: return -EINVAL; @@ -191,8 +227,6 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) u32 codec_align; q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); - if (!q) - return -EINVAL; if (vb2_is_busy(q)) return -EBUSY; @@ -239,10 +273,11 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) inst->crop.height = f->fmt.pix_mp.height; break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) + return -EINVAL; + fmt = inst->fmt_dst; fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - if (fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV12) - return -EINVAL; fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); @@ -265,6 +300,20 @@ int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f) return 0; } +int iris_vdec_validate_format(struct iris_inst *inst, u32 pixelformat) +{ + const struct iris_fmt *fmt = NULL; + + fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (!fmt) { + fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (!fmt) + return -EINVAL; + } + + return 0; +} + int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub) { int ret = 0; @@ -301,125 +350,6 @@ void iris_vdec_src_change(struct iris_inst *inst) v4l2_event_queue_fh(&inst->fh, &event); } - -static void iris_vdec_flush_deferred_buffers(struct iris_inst *inst, - enum iris_buffer_type type) -{ - struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx; - struct v4l2_m2m_buffer *buffer, *n; - struct iris_buffer *buf; - - if (type == BUF_INPUT) { - v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buffer, n) { - buf = to_iris_buffer(&buffer->vb); - if (buf->attr & BUF_ATTR_DEFERRED) { - if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { - buf->attr |= BUF_ATTR_BUFFER_DONE; - buf->data_size = 0; - iris_vb2_buffer_done(inst, buf); - } - } - } - } else { - v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buffer, n) { - buf = to_iris_buffer(&buffer->vb); - if (buf->attr & BUF_ATTR_DEFERRED) { - if (!(buf->attr & BUF_ATTR_BUFFER_DONE)) { - buf->attr |= BUF_ATTR_BUFFER_DONE; - buf->data_size = 0; - iris_vb2_buffer_done(inst, buf); - } - } - } - } -} - -static void iris_vdec_kill_session(struct iris_inst *inst) -{ - const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - - if (!inst->session_id) - return; - - hfi_ops->session_close(inst); - iris_inst_change_state(inst, IRIS_INST_ERROR); -} - -int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane) -{ - const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - enum iris_buffer_type buffer_type; - int ret; - - switch (plane) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - buffer_type = BUF_INPUT; - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - buffer_type = BUF_OUTPUT; - break; - default: - return -EINVAL; - } - - ret = hfi_ops->session_stop(inst, plane); - if (ret) - goto error; - - ret = iris_inst_state_change_streamoff(inst, plane); - if (ret) - goto error; - - iris_vdec_flush_deferred_buffers(inst, buffer_type); - - return 0; - -error: - iris_vdec_kill_session(inst); - iris_vdec_flush_deferred_buffers(inst, buffer_type); - - return ret; -} - -static int iris_vdec_process_streamon_input(struct iris_inst *inst) -{ - const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - enum iris_inst_sub_state set_sub_state = 0; - int ret; - - iris_scale_power(inst); - - ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) - return ret; - - if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { - ret = iris_inst_change_sub_state(inst, IRIS_INST_SUB_INPUT_PAUSE, 0); - if (ret) - return ret; - } - - if (inst->sub_state & IRIS_INST_SUB_DRC || - inst->sub_state & IRIS_INST_SUB_DRAIN || - inst->sub_state & IRIS_INST_SUB_FIRST_IPSC) { - if (!(inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE)) { - if (hfi_ops->session_pause) { - ret = hfi_ops->session_pause(inst, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) - return ret; - } - set_sub_state = IRIS_INST_SUB_INPUT_PAUSE; - } - } - - ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) - return ret; - - return iris_inst_change_sub_state(inst, 0, set_sub_state); -} - int iris_vdec_streamon_input(struct iris_inst *inst) { int ret; @@ -428,7 +358,7 @@ int iris_vdec_streamon_input(struct iris_inst *inst) if (ret) return ret; - ret = iris_alloc_and_queue_persist_bufs(inst); + ret = iris_alloc_and_queue_persist_bufs(inst, BUF_PERSIST); if (ret) return ret; @@ -446,71 +376,7 @@ int iris_vdec_streamon_input(struct iris_inst *inst) if (ret) return ret; - return iris_vdec_process_streamon_input(inst); -} - -static int iris_vdec_process_streamon_output(struct iris_inst *inst) -{ - const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; - bool drain_active = false, drc_active = false; - enum iris_inst_sub_state clear_sub_state = 0; - int ret = 0; - - iris_scale_power(inst); - - drain_active = inst->sub_state & IRIS_INST_SUB_DRAIN && - inst->sub_state & IRIS_INST_SUB_DRAIN_LAST; - - drc_active = inst->sub_state & IRIS_INST_SUB_DRC && - inst->sub_state & IRIS_INST_SUB_DRC_LAST; - - if (drc_active) - clear_sub_state = IRIS_INST_SUB_DRC | IRIS_INST_SUB_DRC_LAST; - else if (drain_active) - clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; - - if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { - ret = iris_alloc_and_queue_input_int_bufs(inst); - if (ret) - return ret; - ret = iris_set_stage(inst, STAGE); - if (ret) - return ret; - ret = iris_set_pipe(inst, PIPE); - if (ret) - return ret; - } - - if (inst->state == IRIS_INST_INPUT_STREAMING && - inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { - if (!drain_active) - ret = hfi_ops->session_resume_drc(inst, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - else if (hfi_ops->session_resume_drain) - ret = hfi_ops->session_resume_drain(inst, - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (ret) - return ret; - clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE; - } - - if (inst->sub_state & IRIS_INST_SUB_FIRST_IPSC) - clear_sub_state |= IRIS_INST_SUB_FIRST_IPSC; - - ret = hfi_ops->session_start(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (ret) - return ret; - - if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) - clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE; - - ret = iris_inst_state_change_streamon(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (ret) - return ret; - - inst->last_buffer_dequeued = false; - - return iris_inst_change_sub_state(inst, clear_sub_state, 0); + return iris_process_streamon_input(inst); } int iris_vdec_streamon_output(struct iris_inst *inst) @@ -532,7 +398,7 @@ int iris_vdec_streamon_output(struct iris_inst *inst) if (ret) return ret; - ret = iris_vdec_process_streamon_output(inst); + ret = iris_process_streamon_output(inst); if (ret) goto error; @@ -543,49 +409,11 @@ int iris_vdec_streamon_output(struct iris_inst *inst) return ret; error: - iris_vdec_session_streamoff(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + iris_session_streamoff(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); return ret; } -static int -iris_vdec_vb2_buffer_to_driver(struct vb2_buffer *vb2, struct iris_buffer *buf) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2); - - buf->type = iris_v4l2_type_to_driver(vb2->type); - buf->index = vb2->index; - buf->fd = vb2->planes[0].m.fd; - buf->buffer_size = vb2->planes[0].length; - buf->data_offset = vb2->planes[0].data_offset; - buf->data_size = vb2->planes[0].bytesused - vb2->planes[0].data_offset; - buf->flags = vbuf->flags; - buf->timestamp = vb2->timestamp; - buf->attr = 0; - - return 0; -} - -static void -iris_set_ts_metadata(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) -{ - u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - struct vb2_buffer *vb = &vbuf->vb2_buf; - u64 ts_us = vb->timestamp; - - if (inst->metadata_idx >= ARRAY_SIZE(inst->tss)) - inst->metadata_idx = 0; - - do_div(ts_us, NSEC_PER_USEC); - - inst->tss[inst->metadata_idx].flags = vbuf->flags & mask; - inst->tss[inst->metadata_idx].tc = vbuf->timecode; - inst->tss[inst->metadata_idx].ts_us = ts_us; - inst->tss[inst->metadata_idx].ts_ns = vb->timestamp; - - inst->metadata_idx++; -} - int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) { struct iris_buffer *buf = to_iris_buffer(vbuf); @@ -593,7 +421,7 @@ int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) struct vb2_queue *q; int ret; - ret = iris_vdec_vb2_buffer_to_driver(vb2, buf); + ret = iris_vb2_buffer_to_driver(vb2, buf); if (ret) return ret; diff --git a/drivers/media/platform/qcom/iris/iris_vdec.h b/drivers/media/platform/qcom/iris/iris_vdec.h index cd7aab66dc7c..ec1ce55d1375 100644 --- a/drivers/media/platform/qcom/iris/iris_vdec.h +++ b/drivers/media/platform/qcom/iris/iris_vdec.h @@ -8,22 +8,12 @@ struct iris_inst; -enum iris_fmt_type { - IRIS_FMT_H264, - IRIS_FMT_HEVC, - IRIS_FMT_VP9, -}; - -struct iris_fmt { - u32 pixfmt; - u32 type; -}; - int iris_vdec_inst_init(struct iris_inst *inst); void iris_vdec_inst_deinit(struct iris_inst *inst); int iris_vdec_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); int iris_vdec_try_fmt(struct iris_inst *inst, struct v4l2_format *f); int iris_vdec_s_fmt(struct iris_inst *inst, struct v4l2_format *f); +int iris_vdec_validate_format(struct iris_inst *inst, u32 pixelformat); int iris_vdec_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub); void iris_vdec_src_change(struct iris_inst *inst); int iris_vdec_streamon_input(struct iris_inst *inst); @@ -31,6 +21,5 @@ int iris_vdec_streamon_output(struct iris_inst *inst); int iris_vdec_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); int iris_vdec_start_cmd(struct iris_inst *inst); int iris_vdec_stop_cmd(struct iris_inst *inst); -int iris_vdec_session_streamoff(struct iris_inst *inst, u32 plane); #endif diff --git a/drivers/media/platform/qcom/iris/iris_venc.c b/drivers/media/platform/qcom/iris/iris_venc.c new file mode 100644 index 000000000000..5830eba93c68 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_venc.c @@ -0,0 +1,616 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <media/v4l2-event.h> +#include <media/v4l2-mem2mem.h> + +#include "iris_buffer.h" +#include "iris_common.h" +#include "iris_ctrls.h" +#include "iris_instance.h" +#include "iris_power.h" +#include "iris_venc.h" +#include "iris_vpu_buffer.h" + +int iris_venc_inst_init(struct iris_inst *inst) +{ + struct iris_core *core = inst->core; + struct v4l2_format *f; + + inst->fmt_src = kzalloc(sizeof(*inst->fmt_src), GFP_KERNEL); + inst->fmt_dst = kzalloc(sizeof(*inst->fmt_dst), GFP_KERNEL); + if (!inst->fmt_src || !inst->fmt_dst) { + kfree(inst->fmt_src); + kfree(inst->fmt_dst); + return -ENOMEM; + } + + f = inst->fmt_dst; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + f->fmt.pix_mp.width = DEFAULT_WIDTH; + f->fmt.pix_mp.height = DEFAULT_HEIGHT; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; + inst->codec = f->fmt.pix_mp.pixelformat; + f->fmt.pix_mp.num_planes = 1; + f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; + f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); + inst->buffers[BUF_OUTPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + + f = inst->fmt_src; + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12; + f->fmt.pix_mp.width = ALIGN(DEFAULT_WIDTH, 128); + f->fmt.pix_mp.height = ALIGN(DEFAULT_HEIGHT, 32); + f->fmt.pix_mp.num_planes = 1; + f->fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(DEFAULT_WIDTH, 128); + f->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT); + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + inst->buffers[BUF_INPUT].min_count = iris_vpu_buf_count(inst, BUF_INPUT); + inst->buffers[BUF_INPUT].size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + + inst->crop.left = 0; + inst->crop.top = 0; + inst->crop.width = f->fmt.pix_mp.width; + inst->crop.height = f->fmt.pix_mp.height; + + inst->operating_rate = DEFAULT_FPS; + inst->frame_rate = DEFAULT_FPS; + + memcpy(&inst->fw_caps[0], &core->inst_fw_caps_enc[0], + INST_FW_CAP_MAX * sizeof(struct platform_inst_fw_cap)); + + return iris_ctrls_init(inst); +} + +void iris_venc_inst_deinit(struct iris_inst *inst) +{ + kfree(inst->fmt_dst); + kfree(inst->fmt_src); +} + +static const struct iris_fmt iris_venc_formats_cap[] = { + [IRIS_FMT_H264] = { + .pixfmt = V4L2_PIX_FMT_H264, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + [IRIS_FMT_HEVC] = { + .pixfmt = V4L2_PIX_FMT_HEVC, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, +}; + +static const struct iris_fmt iris_venc_formats_out[] = { + [IRIS_FMT_NV12] = { + .pixfmt = V4L2_PIX_FMT_NV12, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + [IRIS_FMT_QC08C] = { + .pixfmt = V4L2_PIX_FMT_QC08C, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, +}; + +static const struct iris_fmt * +find_format(struct iris_inst *inst, u32 pixfmt, u32 type) +{ + const struct iris_fmt *fmt = NULL; + unsigned int size = 0; + unsigned int i; + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + fmt = iris_venc_formats_out; + size = ARRAY_SIZE(iris_venc_formats_out); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + fmt = iris_venc_formats_cap; + size = ARRAY_SIZE(iris_venc_formats_cap); + break; + default: + return NULL; + } + + for (i = 0; i < size; i++) { + if (fmt[i].pixfmt == pixfmt) + break; + } + + if (i == size || fmt[i].type != type) + return NULL; + + return &fmt[i]; +} + +static const struct iris_fmt * +find_format_by_index(struct iris_inst *inst, u32 index, u32 type) +{ + const struct iris_fmt *fmt = NULL; + unsigned int size = 0; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + fmt = iris_venc_formats_out; + size = ARRAY_SIZE(iris_venc_formats_out); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + fmt = iris_venc_formats_cap; + size = ARRAY_SIZE(iris_venc_formats_cap); + break; + default: + return NULL; + } + + if (index >= size || fmt[index].type != type) + return NULL; + + return &fmt[index]; +} + +int iris_venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f) +{ + const struct iris_fmt *fmt; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + fmt = find_format_by_index(inst, f->index, f->type); + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->pixfmt; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + fmt = find_format_by_index(inst, f->index, f->type); + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->pixfmt; + f->flags = V4L2_FMT_FLAG_COMPRESSED | V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL; + break; + default: + return -EINVAL; + } + + return 0; +} + +int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + const struct iris_fmt *fmt; + struct v4l2_format *f_inst; + + memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); + fmt = find_format(inst, pixmp->pixelformat, f->type); + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (!fmt) { + f_inst = inst->fmt_src; + f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; + f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat = f_inst->fmt.pix_mp.pixelformat; + } + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (!fmt) { + f_inst = inst->fmt_dst; + f->fmt.pix_mp.width = f_inst->fmt.pix_mp.width; + f->fmt.pix_mp.height = f_inst->fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat = f_inst->fmt.pix_mp.pixelformat; + } + break; + default: + return -EINVAL; + } + + if (pixmp->field == V4L2_FIELD_ANY) + pixmp->field = V4L2_FIELD_NONE; + + pixmp->num_planes = 1; + + return 0; +} + +static int iris_venc_s_fmt_output(struct iris_inst *inst, struct v4l2_format *f) +{ + struct v4l2_format *fmt; + + iris_venc_try_fmt(inst, f); + + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) + return -EINVAL; + + fmt = inst->fmt_dst; + fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + fmt->fmt.pix_mp.num_planes = 1; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_OUTPUT); + + if (f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_DEFAULT && + f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_REC709) + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + + inst->buffers[BUF_OUTPUT].min_count = iris_vpu_buf_count(inst, BUF_OUTPUT); + inst->buffers[BUF_OUTPUT].size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; + inst->codec = f->fmt.pix_mp.pixelformat; + memcpy(f, fmt, sizeof(struct v4l2_format)); + + return 0; +} + +static int iris_venc_s_fmt_input(struct iris_inst *inst, struct v4l2_format *f) +{ + struct v4l2_format *fmt, *output_fmt; + + iris_venc_try_fmt(inst, f); + + if (!(find_format(inst, f->fmt.pix_mp.pixelformat, f->type))) + return -EINVAL; + + fmt = inst->fmt_src; + fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, 128); + fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, 32); + fmt->fmt.pix_mp.num_planes = 1; + fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline = ALIGN(f->fmt.pix_mp.width, 128); + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = iris_get_buffer_size(inst, BUF_INPUT); + + fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + + output_fmt = inst->fmt_dst; + output_fmt->fmt.pix_mp.width = fmt->fmt.pix_mp.width; + output_fmt->fmt.pix_mp.height = fmt->fmt.pix_mp.height; + output_fmt->fmt.pix_mp.colorspace = fmt->fmt.pix_mp.colorspace; + output_fmt->fmt.pix_mp.xfer_func = fmt->fmt.pix_mp.xfer_func; + output_fmt->fmt.pix_mp.ycbcr_enc = fmt->fmt.pix_mp.ycbcr_enc; + output_fmt->fmt.pix_mp.quantization = fmt->fmt.pix_mp.quantization; + + inst->buffers[BUF_INPUT].min_count = iris_vpu_buf_count(inst, BUF_INPUT); + inst->buffers[BUF_INPUT].size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + + if (f->fmt.pix_mp.width != inst->crop.width || + f->fmt.pix_mp.height != inst->crop.height) { + inst->crop.top = 0; + inst->crop.left = 0; + inst->crop.width = fmt->fmt.pix_mp.width; + inst->crop.height = fmt->fmt.pix_mp.height; + + iris_venc_s_fmt_output(inst, output_fmt); + } + + memcpy(f, fmt, sizeof(struct v4l2_format)); + + return 0; +} + +int iris_venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f) +{ + struct vb2_queue *q; + + q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); + + if (vb2_is_busy(q)) + return -EBUSY; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return iris_venc_s_fmt_input(inst, f); + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return iris_venc_s_fmt_output(inst, f); + default: + return -EINVAL; + } +} + +int iris_venc_validate_format(struct iris_inst *inst, u32 pixelformat) +{ + const struct iris_fmt *fmt = NULL; + + fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (!fmt) { + fmt = find_format(inst, pixelformat, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (!fmt) + return -EINVAL; + } + + return 0; +} + +int iris_venc_subscribe_event(struct iris_inst *inst, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(&inst->fh, sub, 0, NULL); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subscribe_event(&inst->fh, sub); + default: + return -EINVAL; + } +} + +int iris_venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s) +{ + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + + if (s->r.width > inst->fmt_src->fmt.pix_mp.width || + s->r.height > inst->fmt_src->fmt.pix_mp.height) + return -EINVAL; + + inst->crop.left = s->r.left; + inst->crop.top = s->r.top; + inst->crop.width = s->r.width; + inst->crop.height = s->r.height; + inst->fmt_dst->fmt.pix_mp.width = inst->crop.width; + inst->fmt_dst->fmt.pix_mp.height = inst->crop.height; + return iris_venc_s_fmt_output(inst, inst->fmt_dst); + default: + return -EINVAL; + } +} + +int iris_venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm) +{ + struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; + struct vb2_queue *src_q = v4l2_m2m_get_src_vq(inst->m2m_ctx); + struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + struct v4l2_fract *timeperframe = NULL; + u32 default_rate = DEFAULT_FPS; + bool is_frame_rate = false; + u64 us_per_frame, fps; + u32 max_rate; + + int ret = 0; + + if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + timeperframe = &s_parm->parm.output.timeperframe; + max_rate = caps->max_operating_rate; + s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + } else { + timeperframe = &s_parm->parm.capture.timeperframe; + is_frame_rate = true; + max_rate = caps->max_frame_rate; + s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + } + + if (!timeperframe->denominator || !timeperframe->numerator) { + if (!timeperframe->numerator) + timeperframe->numerator = 1; + if (!timeperframe->denominator) + timeperframe->denominator = default_rate; + } + + us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; + do_div(us_per_frame, timeperframe->denominator); + + if (!us_per_frame) + return -EINVAL; + + fps = (u64)USEC_PER_SEC; + do_div(fps, us_per_frame); + if (fps > max_rate) { + ret = -ENOMEM; + goto reset_rate; + } + + if (is_frame_rate) + inst->frame_rate = (u32)fps; + else + inst->operating_rate = (u32)fps; + + if ((s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && vb2_is_streaming(src_q)) || + (s_parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && vb2_is_streaming(dst_q))) { + ret = iris_check_core_mbpf(inst); + if (ret) + goto reset_rate; + ret = iris_check_core_mbps(inst); + if (ret) + goto reset_rate; + } + + return 0; + +reset_rate: + if (ret) { + if (is_frame_rate) + inst->frame_rate = default_rate; + else + inst->operating_rate = default_rate; + } + + return ret; +} + +int iris_venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm) +{ + struct v4l2_fract *timeperframe = NULL; + + if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + timeperframe = &s_parm->parm.output.timeperframe; + timeperframe->numerator = 1; + timeperframe->denominator = inst->operating_rate; + s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + } else { + timeperframe = &s_parm->parm.capture.timeperframe; + timeperframe->numerator = 1; + timeperframe->denominator = inst->frame_rate; + s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + } + + return 0; +} + +int iris_venc_streamon_input(struct iris_inst *inst) +{ + int ret; + + ret = iris_set_properties(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + ret = iris_alloc_and_queue_persist_bufs(inst, BUF_ARP); + if (ret) + return ret; + + iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + ret = iris_destroy_dequeued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + ret = iris_create_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + ret = iris_queue_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + return iris_process_streamon_input(inst); +} + +int iris_venc_streamon_output(struct iris_inst *inst) +{ + int ret; + + ret = iris_set_properties(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + goto error; + + ret = iris_alloc_and_queue_persist_bufs(inst, BUF_ARP); + if (ret) + return ret; + + iris_get_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + ret = iris_destroy_dequeued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + goto error; + + ret = iris_create_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + goto error; + + ret = iris_queue_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + goto error; + + ret = iris_process_streamon_output(inst); + if (ret) + goto error; + + return ret; + +error: + iris_session_streamoff(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + return ret; +} + +int iris_venc_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf) +{ + struct iris_buffer *buf = to_iris_buffer(vbuf); + struct vb2_buffer *vb2 = &vbuf->vb2_buf; + struct vb2_queue *q; + int ret; + + ret = iris_vb2_buffer_to_driver(vb2, buf); + if (ret) + return ret; + + if (buf->type == BUF_INPUT) + iris_set_ts_metadata(inst, vbuf); + + q = v4l2_m2m_get_vq(inst->m2m_ctx, vb2->type); + if (!vb2_is_streaming(q)) { + buf->attr |= BUF_ATTR_DEFERRED; + return 0; + } + + iris_scale_power(inst); + + return iris_queue_buffer(inst, buf); +} + +int iris_venc_start_cmd(struct iris_inst *inst) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + enum iris_inst_sub_state clear_sub_state = 0; + struct vb2_queue *dst_vq; + int ret; + + dst_vq = v4l2_m2m_get_dst_vq(inst->m2m_ctx); + + if (inst->sub_state & IRIS_INST_SUB_DRAIN && + inst->sub_state & IRIS_INST_SUB_DRAIN_LAST) { + vb2_clear_last_buffer_dequeued(dst_vq); + clear_sub_state = IRIS_INST_SUB_DRAIN | IRIS_INST_SUB_DRAIN_LAST; + if (inst->sub_state & IRIS_INST_SUB_INPUT_PAUSE) { + if (hfi_ops->session_resume_drain) { + ret = hfi_ops->session_resume_drain(inst, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + } + clear_sub_state |= IRIS_INST_SUB_INPUT_PAUSE; + } + if (inst->sub_state & IRIS_INST_SUB_OUTPUT_PAUSE) { + if (hfi_ops->session_resume_drain) { + ret = hfi_ops->session_resume_drain(inst, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (ret) + return ret; + } + clear_sub_state |= IRIS_INST_SUB_OUTPUT_PAUSE; + } + } else { + dev_err(inst->core->dev, "start called before receiving last_flag\n"); + iris_inst_change_state(inst, IRIS_INST_ERROR); + return -EBUSY; + } + + inst->last_buffer_dequeued = false; + + return iris_inst_change_sub_state(inst, clear_sub_state, 0); +} + +int iris_venc_stop_cmd(struct iris_inst *inst) +{ + const struct iris_hfi_command_ops *hfi_ops = inst->core->hfi_ops; + int ret; + + ret = hfi_ops->session_drain(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (ret) + return ret; + + ret = iris_inst_change_sub_state(inst, 0, IRIS_INST_SUB_DRAIN); + + iris_scale_power(inst); + + return ret; +} diff --git a/drivers/media/platform/qcom/iris/iris_venc.h b/drivers/media/platform/qcom/iris/iris_venc.h new file mode 100644 index 000000000000..c4db7433da53 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_venc.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _IRIS_VENC_H_ +#define _IRIS_VENC_H_ + +struct iris_inst; + +int iris_venc_inst_init(struct iris_inst *inst); +void iris_venc_inst_deinit(struct iris_inst *inst); +int iris_venc_enum_fmt(struct iris_inst *inst, struct v4l2_fmtdesc *f); +int iris_venc_try_fmt(struct iris_inst *inst, struct v4l2_format *f); +int iris_venc_s_fmt(struct iris_inst *inst, struct v4l2_format *f); +int iris_venc_validate_format(struct iris_inst *inst, u32 pixelformat); +int iris_venc_subscribe_event(struct iris_inst *inst, const struct v4l2_event_subscription *sub); +int iris_venc_s_selection(struct iris_inst *inst, struct v4l2_selection *s); +int iris_venc_g_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm); +int iris_venc_s_param(struct iris_inst *inst, struct v4l2_streamparm *s_parm); +int iris_venc_streamon_input(struct iris_inst *inst); +int iris_venc_streamon_output(struct iris_inst *inst); +int iris_venc_qbuf(struct iris_inst *inst, struct vb2_v4l2_buffer *vbuf); +int iris_venc_start_cmd(struct iris_inst *inst); +int iris_venc_stop_cmd(struct iris_inst *inst); + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index c417e8c31f80..c9b881923ef1 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -12,6 +12,7 @@ #include "iris_vidc.h" #include "iris_instance.h" #include "iris_vdec.h" +#include "iris_venc.h" #include "iris_vb2.h" #include "iris_vpu_buffer.h" #include "iris_platform_common.h" @@ -21,16 +22,19 @@ #define STEP_WIDTH 1 #define STEP_HEIGHT 1 -static void iris_v4l2_fh_init(struct iris_inst *inst) +static void iris_v4l2_fh_init(struct iris_inst *inst, struct file *filp) { - v4l2_fh_init(&inst->fh, inst->core->vdev_dec); + if (inst->domain == ENCODER) + v4l2_fh_init(&inst->fh, inst->core->vdev_enc); + else if (inst->domain == DECODER) + v4l2_fh_init(&inst->fh, inst->core->vdev_dec); inst->fh.ctrl_handler = &inst->ctrl_handler; - v4l2_fh_add(&inst->fh); + v4l2_fh_add(&inst->fh, filp); } -static void iris_v4l2_fh_deinit(struct iris_inst *inst) +static void iris_v4l2_fh_deinit(struct iris_inst *inst, struct file *filp) { - v4l2_fh_del(&inst->fh); + v4l2_fh_del(&inst->fh, filp); inst->fh.ctrl_handler = NULL; v4l2_fh_exit(&inst->fh); } @@ -67,9 +71,9 @@ static void iris_remove_session(struct iris_inst *inst) mutex_unlock(&core->lock); } -static inline struct iris_inst *iris_get_inst(struct file *filp, void *fh) +static inline struct iris_inst *iris_get_inst(struct file *filp) { - return container_of(filp->private_data, struct iris_inst, fh); + return container_of(file_to_v4l2_fh(filp), struct iris_inst, fh); } static void iris_m2m_device_run(void *priv) @@ -126,9 +130,19 @@ iris_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_ int iris_open(struct file *filp) { struct iris_core *core = video_drvdata(filp); + struct video_device *vdev; struct iris_inst *inst; + u32 session_type; int ret; + vdev = video_devdata(filp); + if (strcmp(vdev->name, "qcom-iris-decoder") == 0) + session_type = DECODER; + else if (strcmp(vdev->name, "qcom-iris-encoder") == 0) + session_type = ENCODER; + else + return -EINVAL; + ret = pm_runtime_resume_and_get(core->dev); if (ret < 0) return ret; @@ -147,6 +161,7 @@ int iris_open(struct file *filp) return -ENOMEM; inst->core = core; + inst->domain = session_type; inst->session_id = hash32_ptr(inst); inst->state = IRIS_INST_DEINIT; @@ -161,10 +176,12 @@ int iris_open(struct file *filp) INIT_LIST_HEAD(&inst->buffers[BUF_DPB].list); INIT_LIST_HEAD(&inst->buffers[BUF_PERSIST].list); INIT_LIST_HEAD(&inst->buffers[BUF_SCRATCH_1].list); + INIT_LIST_HEAD(&inst->buffers[BUF_SCRATCH_2].list); + INIT_LIST_HEAD(&inst->buffers[BUF_VPSS].list); init_completion(&inst->completion); init_completion(&inst->flush_completion); - iris_v4l2_fh_init(inst); + iris_v4l2_fh_init(inst, filp); inst->m2m_dev = v4l2_m2m_init(&iris_m2m_ops); if (IS_ERR_OR_NULL(inst->m2m_dev)) { @@ -178,14 +195,16 @@ int iris_open(struct file *filp) goto fail_m2m_release; } - ret = iris_vdec_inst_init(inst); + if (inst->domain == DECODER) + ret = iris_vdec_inst_init(inst); + else if (inst->domain == ENCODER) + ret = iris_venc_inst_init(inst); if (ret) goto fail_m2m_ctx_release; iris_add_session(inst); inst->fh.m2m_ctx = inst->m2m_ctx; - filp->private_data = &inst->fh; return 0; @@ -194,7 +213,7 @@ fail_m2m_ctx_release: fail_m2m_release: v4l2_m2m_release(inst->m2m_dev); fail_v4l2_fh_deinit: - iris_v4l2_fh_deinit(inst); + iris_v4l2_fh_deinit(inst, filp); mutex_destroy(&inst->ctx_q_lock); mutex_destroy(&inst->lock); kfree(inst); @@ -240,26 +259,42 @@ static void iris_check_num_queued_internal_buffers(struct iris_inst *inst, u32 p for (i = 0; i < internal_buffer_count; i++) { buffers = &inst->buffers[internal_buf_type[i]]; + count = 0; list_for_each_entry_safe(buf, next, &buffers->list, list) count++; if (count) dev_err(inst->core->dev, "%d buffer of type %d not released", count, internal_buf_type[i]); } + + if (inst->domain == DECODER) + buffers = &inst->buffers[BUF_PERSIST]; + else + buffers = &inst->buffers[BUF_ARP]; + + count = 0; + list_for_each_entry_safe(buf, next, &buffers->list, list) + count++; + if (count) + dev_err(inst->core->dev, "%d buffer of type %d not released", + count, inst->domain == DECODER ? BUF_PERSIST : BUF_ARP); } int iris_close(struct file *filp) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); v4l2_ctrl_handler_free(&inst->ctrl_handler); v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); mutex_lock(&inst->lock); - iris_vdec_inst_deinit(inst); + if (inst->domain == DECODER) + iris_vdec_inst_deinit(inst); + else if (inst->domain == ENCODER) + iris_venc_inst_deinit(inst); iris_session_close(inst); iris_inst_change_state(inst, IRIS_INST_DEINIT); - iris_v4l2_fh_deinit(inst); + iris_v4l2_fh_deinit(inst, filp); iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); iris_destroy_all_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); iris_check_num_queued_internal_buffers(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); @@ -269,25 +304,34 @@ int iris_close(struct file *filp) mutex_destroy(&inst->ctx_q_lock); mutex_destroy(&inst->lock); kfree(inst); - filp->private_data = NULL; return 0; } static int iris_enum_fmt(struct file *filp, void *fh, struct v4l2_fmtdesc *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); - return iris_vdec_enum_fmt(inst, f); + if (inst->domain == DECODER) + return iris_vdec_enum_fmt(inst, f); + else if (inst->domain == ENCODER) + return iris_venc_enum_fmt(inst, f); + else + return -EINVAL; } static int iris_try_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); - int ret; + struct iris_inst *inst = iris_get_inst(filp); + int ret = 0; mutex_lock(&inst->lock); - ret = iris_vdec_try_fmt(inst, f); + + if (inst->domain == DECODER) + ret = iris_vdec_try_fmt(inst, f); + else if (inst->domain == ENCODER) + ret = iris_venc_try_fmt(inst, f); + mutex_unlock(&inst->lock); return ret; @@ -295,11 +339,16 @@ static int iris_try_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_form static int iris_s_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); - int ret; + struct iris_inst *inst = iris_get_inst(filp); + int ret = 0; mutex_lock(&inst->lock); - ret = iris_vdec_s_fmt(inst, f); + + if (inst->domain == DECODER) + ret = iris_vdec_s_fmt(inst, f); + else if (inst->domain == ENCODER) + ret = iris_venc_s_fmt(inst, f); + mutex_unlock(&inst->lock); return ret; @@ -307,7 +356,7 @@ static int iris_s_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format *f) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); int ret = 0; mutex_lock(&inst->lock); @@ -326,15 +375,20 @@ static int iris_g_fmt_vid_mplane(struct file *filp, void *fh, struct v4l2_format static int iris_enum_framesizes(struct file *filp, void *fh, struct v4l2_frmsizeenum *fsize) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); struct platform_inst_caps *caps; + int ret = 0; if (fsize->index) return -EINVAL; - if (fsize->pixel_format != V4L2_PIX_FMT_H264 && - fsize->pixel_format != V4L2_PIX_FMT_NV12) - return -EINVAL; + if (inst->domain == DECODER) + ret = iris_vdec_validate_format(inst, fsize->pixel_format); + else + ret = iris_venc_validate_format(inst, fsize->pixel_format); + + if (ret) + return ret; caps = inst->core->iris_platform_data->inst_caps; @@ -346,55 +400,174 @@ static int iris_enum_framesizes(struct file *filp, void *fh, fsize->stepwise.max_height = caps->max_frame_height; fsize->stepwise.step_height = STEP_HEIGHT; + return ret; +} + +static int iris_enum_frameintervals(struct file *filp, void *fh, + struct v4l2_frmivalenum *fival) + +{ + struct iris_inst *inst = iris_get_inst(filp); + struct iris_core *core = inst->core; + struct platform_inst_caps *caps; + u32 fps, mbpf; + int ret = 0; + + if (inst->domain == DECODER) + return -ENOTTY; + + if (fival->index) + return -EINVAL; + + ret = iris_venc_validate_format(inst, fival->pixel_format); + if (ret) + return ret; + + if (!fival->width || !fival->height) + return -EINVAL; + + caps = inst->core->iris_platform_data->inst_caps; + if (fival->width > caps->max_frame_width || + fival->width < caps->min_frame_width || + fival->height > caps->max_frame_height || + fival->height < caps->min_frame_height) + return -EINVAL; + + mbpf = NUM_MBS_PER_FRAME(fival->height, fival->width); + fps = DIV_ROUND_UP(core->iris_platform_data->max_core_mbps, mbpf); + + fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; + fival->stepwise.min.numerator = 1; + fival->stepwise.min.denominator = + min_t(u32, fps, MAXIMUM_FPS); + fival->stepwise.max.numerator = 1; + fival->stepwise.max.denominator = 1; + fival->stepwise.step.numerator = 1; + fival->stepwise.step.denominator = MAXIMUM_FPS; + return 0; } static int iris_querycap(struct file *filp, void *fh, struct v4l2_capability *cap) { + struct iris_inst *inst = iris_get_inst(filp); + strscpy(cap->driver, IRIS_DRV_NAME, sizeof(cap->driver)); - strscpy(cap->card, "Iris Decoder", sizeof(cap->card)); + + if (inst->domain == DECODER) + strscpy(cap->card, "Iris Decoder", sizeof(cap->card)); + else + strscpy(cap->card, "Iris Encoder", sizeof(cap->card)); return 0; } static int iris_g_selection(struct file *filp, void *fh, struct v4l2_selection *s) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + inst->domain == DECODER) return -EINVAL; - switch (s->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - case V4L2_SEL_TGT_COMPOSE_PADDED: - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && + inst->domain == ENCODER) + return -EINVAL; + + if (inst->domain == DECODER) { + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE: + s->r.left = inst->crop.left; + s->r.top = inst->crop.top; + s->r.width = inst->crop.width; + s->r.height = inst->crop.height; + break; + default: + return -EINVAL; + } + } else if (inst->domain == ENCODER) { + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + s->r.width = inst->fmt_src->fmt.pix_mp.width; + s->r.height = inst->fmt_src->fmt.pix_mp.height; + break; + case V4L2_SEL_TGT_CROP: + s->r.width = inst->crop.width; + s->r.height = inst->crop.height; + break; + default: + return -EINVAL; + } s->r.left = inst->crop.left; s->r.top = inst->crop.top; - s->r.width = inst->crop.width; - s->r.height = inst->crop.height; - break; - default: - return -EINVAL; } return 0; } +static int iris_s_selection(struct file *filp, void *fh, struct v4l2_selection *s) +{ + struct iris_inst *inst = iris_get_inst(filp); + + if (inst->domain == DECODER) + return -EINVAL; + else if (inst->domain == ENCODER) + return iris_venc_s_selection(inst, s); + + return -EINVAL; +} + static int iris_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { struct iris_inst *inst = container_of(fh, struct iris_inst, fh); - return iris_vdec_subscribe_event(inst, sub); + if (inst->domain == DECODER) + return iris_vdec_subscribe_event(inst, sub); + else if (inst->domain == ENCODER) + return iris_venc_subscribe_event(inst, sub); + + return -EINVAL; +} + +static int iris_s_parm(struct file *filp, void *fh, struct v4l2_streamparm *a) +{ + struct iris_inst *inst = iris_get_inst(filp); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + if (inst->domain == ENCODER) + return iris_venc_s_param(inst, a); + else + return -EINVAL; +} + +static int iris_g_parm(struct file *filp, void *fh, struct v4l2_streamparm *a) +{ + struct iris_inst *inst = iris_get_inst(filp); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + if (inst->domain == ENCODER) + return iris_venc_g_param(inst, a); + else + return -EINVAL; } static int iris_dec_cmd(struct file *filp, void *fh, struct v4l2_decoder_cmd *dec) { - struct iris_inst *inst = iris_get_inst(filp, NULL); + struct iris_inst *inst = iris_get_inst(filp); int ret = 0; mutex_lock(&inst->lock); @@ -424,7 +597,40 @@ unlock: return ret; } -static struct v4l2_file_operations iris_v4l2_file_ops = { +static int iris_enc_cmd(struct file *filp, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct iris_inst *inst = iris_get_inst(filp); + int ret = 0; + + mutex_lock(&inst->lock); + + ret = v4l2_m2m_ioctl_encoder_cmd(filp, fh, enc); + if (ret) + goto unlock; + + if (inst->state == IRIS_INST_DEINIT) + goto unlock; + + if (!iris_allow_cmd(inst, enc->cmd)) { + ret = -EBUSY; + goto unlock; + } + + if (enc->cmd == V4L2_ENC_CMD_START) + ret = iris_venc_start_cmd(inst); + else if (enc->cmd == V4L2_ENC_CMD_STOP) + ret = iris_venc_stop_cmd(inst); + else + ret = -EINVAL; + +unlock: + mutex_unlock(&inst->lock); + + return ret; +} + +static const struct v4l2_file_operations iris_v4l2_file_ops = { .owner = THIS_MODULE, .open = iris_open, .release = iris_close, @@ -443,7 +649,7 @@ static const struct vb2_ops iris_vb2_ops = { .buf_queue = iris_vb2_buf_queue, }; -static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { +static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops_dec = { .vidioc_enum_fmt_vid_cap = iris_enum_fmt, .vidioc_enum_fmt_vid_out = iris_enum_fmt, .vidioc_try_fmt_vid_cap_mplane = iris_try_fmt_vid_mplane, @@ -471,9 +677,42 @@ static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops = { .vidioc_decoder_cmd = iris_dec_cmd, }; +static const struct v4l2_ioctl_ops iris_v4l2_ioctl_ops_enc = { + .vidioc_enum_fmt_vid_cap = iris_enum_fmt, + .vidioc_enum_fmt_vid_out = iris_enum_fmt, + .vidioc_try_fmt_vid_cap_mplane = iris_try_fmt_vid_mplane, + .vidioc_try_fmt_vid_out_mplane = iris_try_fmt_vid_mplane, + .vidioc_s_fmt_vid_cap_mplane = iris_s_fmt_vid_mplane, + .vidioc_s_fmt_vid_out_mplane = iris_s_fmt_vid_mplane, + .vidioc_g_fmt_vid_cap_mplane = iris_g_fmt_vid_mplane, + .vidioc_g_fmt_vid_out_mplane = iris_g_fmt_vid_mplane, + .vidioc_enum_framesizes = iris_enum_framesizes, + .vidioc_enum_frameintervals = iris_enum_frameintervals, + .vidioc_querycap = iris_querycap, + .vidioc_subscribe_event = iris_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_selection = iris_g_selection, + .vidioc_s_selection = iris_s_selection, + .vidioc_s_parm = iris_s_parm, + .vidioc_g_parm = iris_g_parm, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_remove_bufs = v4l2_m2m_ioctl_remove_bufs, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = iris_enc_cmd, +}; + void iris_init_ops(struct iris_core *core) { core->iris_v4l2_file_ops = &iris_v4l2_file_ops; core->iris_vb2_ops = &iris_vb2_ops; - core->iris_v4l2_ioctl_ops = &iris_v4l2_ioctl_ops; + core->iris_v4l2_ioctl_ops_dec = &iris_v4l2_ioctl_ops_dec; + core->iris_v4l2_ioctl_ops_enc = &iris_v4l2_ioctl_ops_enc; } diff --git a/drivers/media/platform/qcom/iris/iris_vpu2.c b/drivers/media/platform/qcom/iris/iris_vpu2.c index 7cf1bfc352d3..9c103a2e4e4e 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu2.c +++ b/drivers/media/platform/qcom/iris/iris_vpu2.c @@ -3,9 +3,15 @@ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ +#include <linux/bits.h> +#include <linux/iopoll.h> +#include <linux/reset.h> + #include "iris_instance.h" #include "iris_vpu_common.h" +#include "iris_vpu_register_defines.h" + static u64 iris_vpu2_calc_freq(struct iris_inst *inst, size_t data_size) { struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; @@ -34,6 +40,8 @@ static u64 iris_vpu2_calc_freq(struct iris_inst *inst, size_t data_size) const struct vpu_ops iris_vpu2_ops = { .power_off_hw = iris_vpu_power_off_hw, + .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu_power_off_controller, + .power_on_controller = iris_vpu_power_on_controller, .calc_freq = iris_vpu2_calc_freq, }; diff --git a/drivers/media/platform/qcom/iris/iris_vpu3x.c b/drivers/media/platform/qcom/iris/iris_vpu3x.c index 9b7c9a1495ee..339776a0b467 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu3x.c +++ b/drivers/media/platform/qcom/iris/iris_vpu3x.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2025 Linaro Ltd */ #include <linux/iopoll.h> @@ -19,8 +20,13 @@ #define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS + 0x5C) #define REQ_POWER_DOWN_PREP BIT(0) #define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS + 0x60) +#define NOC_LPI_STATUS_DONE BIT(0) /* Indicates the NOC handshake is complete */ +#define NOC_LPI_STATUS_DENY BIT(1) /* Indicates the NOC handshake is denied */ +#define NOC_LPI_STATUS_ACTIVE BIT(2) /* Indicates the NOC is active */ #define WRAPPER_CORE_CLOCK_CONFIG (WRAPPER_BASE_OFFS + 0x88) #define CORE_CLK_RUN 0x0 +/* VPU v3.5 */ +#define WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0 (WRAPPER_BASE_OFFS + 0x78) #define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) #define CTL_AXI_CLK_HALT BIT(0) @@ -52,6 +58,8 @@ #define AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL (AON_BASE_OFFS + 0x20) #define NOC_HALT BIT(0) #define AON_WRAPPER_SPARE (AON_BASE_OFFS + 0x28) +#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL (AON_BASE_OFFS + 0x2C) +#define AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS (AON_BASE_OFFS + 0x30) static bool iris_vpu3x_hw_power_collapsed(struct iris_core *core) { @@ -109,7 +117,9 @@ disable_power: static void iris_vpu33_power_off_hardware(struct iris_core *core) { + bool handshake_done = false, handshake_busy = false; u32 reg_val = 0, value, i; + u32 count = 0; int ret; if (iris_vpu3x_hw_power_collapsed(core)) @@ -128,13 +138,36 @@ static void iris_vpu33_power_off_hardware(struct iris_core *core) goto disable_power; } + /* Retry up to 1000 times as recommended by hardware documentation */ + do { + /* set MNoC to low power */ + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + + udelay(15); + + value = readl(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS); + + handshake_done = value & NOC_LPI_STATUS_DONE; + handshake_busy = value & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); + + if (handshake_done || !handshake_busy) + break; + + writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + + udelay(15); + + } while (++count < 1000); + + if (!handshake_done && handshake_busy) + dev_err(core->dev, "LPI handshake timeout\n"); + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, reg_val, reg_val & BIT(0), 200, 2000); if (ret) goto disable_power; - /* set MNoC to low power, set PD_NOC_QREQ (bit 0) */ - writel(BIT(0), core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + writel(0, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); writel(CORE_BRIDGE_SW_RESET | CORE_BRIDGE_HW_RESET_DISABLE, core->reg_base + CPU_CS_AHB_BRIDGE_SYNC_RESET); @@ -225,6 +258,158 @@ disable_power: return 0; } +static int iris_vpu35_power_on_hw(struct iris_core *core) +{ + int ret; + + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + if (ret) + return ret; + + ret = iris_prepare_enable_clock(core, IRIS_AXI_CLK); + if (ret) + goto err_disable_power; + + ret = iris_prepare_enable_clock(core, IRIS_HW_FREERUN_CLK); + if (ret) + goto err_disable_axi_clk; + + ret = iris_prepare_enable_clock(core, IRIS_HW_CLK); + if (ret) + goto err_disable_hw_free_clk; + + ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], true); + if (ret) + goto err_disable_hw_clk; + + return 0; + +err_disable_hw_clk: + iris_disable_unprepare_clock(core, IRIS_HW_CLK); +err_disable_hw_free_clk: + iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK); +err_disable_axi_clk: + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); +err_disable_power: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + + return ret; +} + +static void iris_vpu35_power_off_hw(struct iris_core *core) +{ + iris_vpu33_power_off_hardware(core); + + iris_disable_unprepare_clock(core, IRIS_HW_FREERUN_CLK); + iris_disable_unprepare_clock(core, IRIS_AXI_CLK); +} + +static int iris_vpu35_power_off_controller(struct iris_core *core) +{ + u32 clk_rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; + unsigned int count = 0; + u32 val = 0; + bool handshake_done, handshake_busy; + int ret; + + writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); + + writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); + + /* Retry up to 1000 times as recommended by hardware documentation */ + do { + /* set MNoC to low power */ + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + + udelay(15); + + val = readl(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS); + + handshake_done = val & NOC_LPI_STATUS_DONE; + handshake_busy = val & (NOC_LPI_STATUS_DENY | NOC_LPI_STATUS_ACTIVE); + + if (handshake_done || !handshake_busy) + break; + + writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + + udelay(15); + + } while (++count < 1000); + + if (!handshake_done && handshake_busy) + dev_err(core->dev, "LPI handshake timeout\n"); + + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + + writel(0, core->reg_base + AON_WRAPPER_MVP_VIDEO_CTL_NOC_LPI_CONTROL); + + writel(0, core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL); + + ret = readl_poll_timeout(core->reg_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS, + val, val == 0, 200, 2000); + if (ret) + goto disable_power; + +disable_power: + iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); + iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); + iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); + + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + + reset_control_bulk_reset(clk_rst_tbl_size, core->resets); + + return 0; +} + +static int iris_vpu35_power_on_controller(struct iris_core *core) +{ + int ret; + + ret = iris_enable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + if (ret) + return ret; + + ret = iris_prepare_enable_clock(core, IRIS_AXI1_CLK); + if (ret) + goto err_disable_power; + + ret = iris_prepare_enable_clock(core, IRIS_CTRL_FREERUN_CLK); + if (ret) + goto err_disable_axi1_clk; + + ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); + if (ret) + goto err_disable_ctrl_free_clk; + + return 0; + +err_disable_ctrl_free_clk: + iris_disable_unprepare_clock(core, IRIS_CTRL_FREERUN_CLK); +err_disable_axi1_clk: + iris_disable_unprepare_clock(core, IRIS_AXI1_CLK); +err_disable_power: + iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); + + return ret; +} + +static void iris_vpu35_program_bootup_registers(struct iris_core *core) +{ + writel(0x1, core->reg_base + WRAPPER_IRIS_VCODEC_VPU_WRAPPER_SPARE_0); +} + static u64 iris_vpu3x_calculate_frequency(struct iris_inst *inst, size_t data_size) { struct platform_inst_caps *caps = inst->core->iris_platform_data->inst_caps; @@ -264,12 +449,25 @@ static u64 iris_vpu3x_calculate_frequency(struct iris_inst *inst, size_t data_si const struct vpu_ops iris_vpu3_ops = { .power_off_hw = iris_vpu3_power_off_hardware, + .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu_power_off_controller, + .power_on_controller = iris_vpu_power_on_controller, .calc_freq = iris_vpu3x_calculate_frequency, }; const struct vpu_ops iris_vpu33_ops = { .power_off_hw = iris_vpu33_power_off_hardware, + .power_on_hw = iris_vpu_power_on_hw, .power_off_controller = iris_vpu33_power_off_controller, + .power_on_controller = iris_vpu_power_on_controller, + .calc_freq = iris_vpu3x_calculate_frequency, +}; + +const struct vpu_ops iris_vpu35_ops = { + .power_off_hw = iris_vpu35_power_off_hw, + .power_on_hw = iris_vpu35_power_on_hw, + .power_off_controller = iris_vpu35_power_off_controller, + .power_on_controller = iris_vpu35_power_on_controller, + .program_bootup_registers = iris_vpu35_program_bootup_registers, .calc_freq = iris_vpu3x_calculate_frequency, }; diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c index f92fd39fe310..4463be05ce16 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c @@ -5,6 +5,14 @@ #include "iris_instance.h" #include "iris_vpu_buffer.h" +#include "iris_hfi_gen1_defines.h" +#include "iris_hfi_gen2_defines.h" + +#define HFI_MAX_COL_FRAME 6 + +#ifndef SYSTEM_LAL_TILE10 +#define SYSTEM_LAL_TILE10 192 +#endif static u32 size_h264d_hw_bin_buffer(u32 frame_width, u32 frame_height, u32 num_vpp_pipes) { @@ -548,6 +556,858 @@ static u32 iris_vpu_dec_scratch1_size(struct iris_inst *inst) iris_vpu_dec_line_size(inst); } +static inline u32 size_bin_bitstream_enc(u32 width, u32 height, + u32 rc_type) +{ + u32 aligned_height = ALIGN(height, 32); + u32 aligned_width = ALIGN(width, 32); + u32 frame_size = width * height * 3; + u32 mbs_per_frame; + + /* + * Encoder output size calculation: 32 Align width/height + * For resolution < 720p : YUVsize * 4 + * For resolution > 720p & <= 4K : YUVsize / 2 + * For resolution > 4k : YUVsize / 4 + * Initially frame_size = YUVsize * 2; + */ + + mbs_per_frame = (ALIGN(aligned_height, 16) * ALIGN(aligned_width, 16)) / 256; + + if (mbs_per_frame < NUM_MBS_720P) + frame_size = frame_size << 1; + else if (mbs_per_frame <= NUM_MBS_4K) + frame_size = frame_size >> 2; + else + frame_size = frame_size >> 3; + + if (rc_type == HFI_RATE_CONTROL_OFF || rc_type == HFI_RATE_CONTROL_CQ || + rc_type == HFI_RC_OFF || rc_type == HFI_RC_CQ) + frame_size = frame_size << 1; + + /* + * In case of opaque color format bitdepth will be known + * with first ETB, buffers allocated already with 8 bit + * won't be sufficient for 10 bit + * calculate size considering 10-bit by default + * For 10-bit cases size = size * 1.25 + */ + frame_size *= 5; + frame_size /= 4; + + return ALIGN(frame_size, SZ_4K); +} + +static inline u32 hfi_buffer_bin_enc(u32 width, u32 height, + u32 work_mode, u32 lcu_size, + u32 num_vpp_pipes, u32 rc_type) +{ + u32 sao_bin_buffer_size, padded_bin_size, bitstream_size; + u32 total_bitbin_buffers, size_single_pipe, bitbin_size; + u32 aligned_height = ALIGN(height, lcu_size); + u32 aligned_width = ALIGN(width, lcu_size); + + bitstream_size = size_bin_bitstream_enc(width, height, rc_type); + bitstream_size = ALIGN(bitstream_size, 256); + + if (work_mode == STAGE_2) { + total_bitbin_buffers = 3; + bitbin_size = bitstream_size * 17 / 10; + bitbin_size = ALIGN(bitbin_size, 256); + } else { + total_bitbin_buffers = 1; + bitstream_size = aligned_width * aligned_height * 3; + bitbin_size = ALIGN(bitstream_size, 256); + } + + if (num_vpp_pipes > 2) + size_single_pipe = bitbin_size / 2; + else + size_single_pipe = bitbin_size; + + size_single_pipe = ALIGN(size_single_pipe, 256); + sao_bin_buffer_size = (64 * (((width + 32) * (height + 32)) >> 10)) + 384; + padded_bin_size = ALIGN(size_single_pipe, 256); + size_single_pipe = sao_bin_buffer_size + padded_bin_size; + size_single_pipe = ALIGN(size_single_pipe, 256); + bitbin_size = size_single_pipe * num_vpp_pipes; + + return ALIGN(bitbin_size, 256) * total_bitbin_buffers + 512; +} + +static u32 iris_vpu_enc_bin_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + u32 stage = inst->fw_caps[STAGE].value; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 lcu_size; + + if (inst->codec == V4L2_PIX_FMT_HEVC) + lcu_size = 32; + else + lcu_size = 16; + + return hfi_buffer_bin_enc(width, height, stage, lcu_size, + num_vpp_pipes, inst->hfi_rc_type); +} + +static inline +u32 hfi_buffer_comv_enc(u32 frame_width, u32 frame_height, u32 lcu_size, + u32 num_recon, u32 standard) +{ + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 num_lcu_in_frame = width_in_lcus * height_in_lcus; + u32 mb_height = ((frame_height) + 15) >> 4; + u32 mb_width = ((frame_width) + 15) >> 4; + u32 size_colloc_mv, size_colloc_rc; + + size_colloc_mv = (standard == HFI_CODEC_ENCODE_HEVC) ? + (16 * ((num_lcu_in_frame << 2) + 32)) : + (3 * 16 * (width_in_lcus * height_in_lcus + 32)); + size_colloc_mv = ALIGN(size_colloc_mv, 256) * num_recon; + size_colloc_rc = (((mb_width + 7) >> 3) * 16 * 2 * mb_height); + size_colloc_rc = ALIGN(size_colloc_rc, 256) * HFI_MAX_COL_FRAME; + + return size_colloc_mv + size_colloc_rc; +} + +static u32 iris_vpu_enc_comv_size(struct iris_inst *inst) +{ + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 num_recon = 1; + u32 lcu_size = 16; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + return hfi_buffer_comv_enc(width, height, lcu_size, + num_recon + 1, HFI_CODEC_ENCODE_HEVC); + } + + return hfi_buffer_comv_enc(width, height, lcu_size, + num_recon + 1, HFI_CODEC_ENCODE_AVC); +} + +static inline +u32 size_frame_rc_buf_size(u32 standard, u32 frame_height_coded, + u32 num_vpp_pipes_enc) +{ + u32 size = 0; + + size = (standard == HFI_CODEC_ENCODE_HEVC) ? + (256 + 16 * (14 + ((((frame_height_coded) >> 5) + 7) >> 3))) : + (256 + 16 * (14 + ((((frame_height_coded) >> 4) + 7) >> 3))); + size *= 11; + + if (num_vpp_pipes_enc > 1) + size = ALIGN(size, 256) * num_vpp_pipes_enc; + + return ALIGN(size, 512) * HFI_MAX_COL_FRAME; +} + +static inline +u32 size_enc_slice_info_buf(u32 num_lcu_in_frame) +{ + return ALIGN((256 + (num_lcu_in_frame << 4)), 256); +} + +static inline u32 enc_bitcnt_buf_size(u32 num_lcu_in_frame) +{ + return ALIGN((256 + (4 * (num_lcu_in_frame))), 256); +} + +static inline u32 enc_bitmap_buf_size(u32 num_lcu_in_frame) +{ + return ALIGN((256 + ((num_lcu_in_frame) >> 3)), 256); +} + +static inline u32 size_override_buf(u32 num_lcumb) +{ + return ALIGN(((16 * (((num_lcumb) + 7) >> 3))), 256) * 2; +} + +static inline u32 size_ir_buf(u32 num_lcu_in_frame) +{ + return ALIGN((((((num_lcu_in_frame) << 1) + 7) & (~7)) * 3), 256); +} + +static inline +u32 size_linebuff_data(bool is_ten_bit, u32 frame_width_coded) +{ + return is_ten_bit ? + (((((10 * (frame_width_coded) + 1024) + (256 - 1)) & + (~(256 - 1))) * 1) + + (((((10 * (frame_width_coded) + 1024) >> 1) + (256 - 1)) & + (~(256 - 1))) * 2)) : + (((((8 * (frame_width_coded) + 1024) + (256 - 1)) & + (~(256 - 1))) * 1) + + (((((8 * (frame_width_coded) + 1024) >> 1) + (256 - 1)) & + (~(256 - 1))) * 2)); +} + +static inline +u32 size_left_linebuff_ctrl(u32 standard, u32 frame_height_coded, + u32 num_vpp_pipes_enc) +{ + u32 size = 0; + + size = standard == HFI_CODEC_ENCODE_HEVC ? + (((frame_height_coded) + + (32)) / 32 * 4 * 16) : + (((frame_height_coded) + 15) / 16 * 5 * 16); + + if ((num_vpp_pipes_enc) > 1) { + size += 512; + size = ALIGN(size, 512) * + num_vpp_pipes_enc; + } + + return ALIGN(size, 256); +} + +static inline +u32 size_left_linebuff_recon_pix(bool is_ten_bit, u32 frame_height_coded, + u32 num_vpp_pipes_enc) +{ + return (((is_ten_bit + 1) * 2 * (frame_height_coded) + 256) + + (256 << (num_vpp_pipes_enc - 1)) - 1) & + (~((256 << (num_vpp_pipes_enc - 1)) - 1)) * 1; +} + +static inline +u32 size_top_linebuff_ctrl_fe(u32 frame_width_coded, u32 standard) +{ + return standard == HFI_CODEC_ENCODE_HEVC ? + ALIGN((64 * ((frame_width_coded) >> 5)), 256) : + ALIGN((256 + 16 * ((frame_width_coded) >> 4)), 256); +} + +static inline +u32 size_left_linebuff_ctrl_fe(u32 frame_height_coded, u32 num_vpp_pipes_enc) +{ + return (((256 + 64 * ((frame_height_coded) >> 4)) + + (256 << (num_vpp_pipes_enc - 1)) - 1) & + (~((256 << (num_vpp_pipes_enc - 1)) - 1)) * 1) * + num_vpp_pipes_enc; +} + +static inline +u32 size_left_linebuff_metadata_recon_y(u32 frame_height_coded, + bool is_ten_bit, + u32 num_vpp_pipes_enc) +{ + return ALIGN(((256 + 64 * ((frame_height_coded) / + (8 * (is_ten_bit ? 4 : 8))))), 256) * num_vpp_pipes_enc; +} + +static inline +u32 size_left_linebuff_metadata_recon_uv(u32 frame_height_coded, + bool is_ten_bit, + u32 num_vpp_pipes_enc) +{ + return ALIGN(((256 + 64 * ((frame_height_coded) / + (4 * (is_ten_bit ? 4 : 8))))), 256) * num_vpp_pipes_enc; +} + +static inline +u32 size_linebuff_recon_pix(bool is_ten_bit, u32 frame_width_coded) +{ + return ALIGN(((is_ten_bit ? 3 : 2) * (frame_width_coded)), 256); +} + +static inline +u32 size_line_buf_ctrl(u32 frame_width_coded) +{ + return ALIGN(frame_width_coded, 256); +} + +static inline +u32 size_line_buf_ctrl_id2(u32 frame_width_coded) +{ + return ALIGN(frame_width_coded, 256); +} + +static inline u32 size_line_buf_sde(u32 frame_width_coded) +{ + return ALIGN((256 + (16 * ((frame_width_coded) >> 4))), 256); +} + +static inline +u32 size_vpss_line_buf(u32 num_vpp_pipes_enc, u32 frame_height_coded, + u32 frame_width_coded) +{ + return ALIGN(((((((8192) >> 2) << 5) * (num_vpp_pipes_enc)) + 64) + + (((((max_t(u32, (frame_width_coded), + (frame_height_coded)) + 3) >> 2) << 5) + 256) * 16)), 256); +} +static inline +u32 size_vpss_line_buf_vpu33(u32 num_vpp_pipes_enc, u32 frame_height_coded, + u32 frame_width_coded) +{ + u32 vpss_4tap_top, vpss_4tap_left, vpss_div2_top; + u32 vpss_div2_left, vpss_top_lb, vpss_left_lb; + u32 size_left, size_top; + u32 max_width_height; + + max_width_height = max_t(u32, frame_width_coded, frame_height_coded); + vpss_4tap_top = ((((max_width_height * 2) + 3) >> 2) << 4) + 256; + vpss_4tap_left = (((8192 + 3) >> 2) << 5) + 64; + vpss_div2_top = (((max_width_height + 3) >> 2) << 4) + 256; + vpss_div2_left = ((((max_width_height * 2) + 3) >> 2) << 5) + 64; + vpss_top_lb = (frame_width_coded + 1) << 3; + vpss_left_lb = (frame_height_coded << 3) * num_vpp_pipes_enc; + size_left = (vpss_4tap_left + vpss_div2_left) * 2 * num_vpp_pipes_enc; + size_top = (vpss_4tap_top + vpss_div2_top) * 2; + + return ALIGN(size_left + size_top + vpss_top_lb + vpss_left_lb, DMA_ALIGNMENT); +} + +static inline +u32 size_top_line_buf_first_stg_sao(u32 frame_width_coded) +{ + return ALIGN((16 * ((frame_width_coded) >> 5)), 256); +} + +static inline +u32 size_enc_ref_buffer(u32 frame_width, u32 frame_height) +{ + u32 u_chroma_buffer_height = ALIGN(frame_height >> 1, 32); + u32 u_buffer_height = ALIGN(frame_height, 32); + u32 u_buffer_width = ALIGN(frame_width, 32); + + return (u_buffer_height + u_chroma_buffer_height) * u_buffer_width; +} + +static inline +u32 size_enc_ten_bit_ref_buffer(u32 frame_width, u32 frame_height) +{ + u32 ref_luma_stride_in_bytes = ((frame_width + SYSTEM_LAL_TILE10 - 1) / SYSTEM_LAL_TILE10) * + SYSTEM_LAL_TILE10; + u32 ref_buf_height = (frame_height + (32 - 1)) & (~(32 - 1)); + u32 u_ref_stride, luma_size; + u32 ref_chrm_height_in_bytes; + u32 chroma_size; + + u_ref_stride = 4 * (ref_luma_stride_in_bytes / 3); + u_ref_stride = (u_ref_stride + (128 - 1)) & (~(128 - 1)); + luma_size = ref_buf_height * u_ref_stride; + luma_size = (luma_size + (4096 - 1)) & (~(4096 - 1)); + + ref_chrm_height_in_bytes = (((frame_height + 1) >> 1) + (32 - 1)) & (~(32 - 1)); + chroma_size = u_ref_stride * ref_chrm_height_in_bytes; + chroma_size = (chroma_size + (4096 - 1)) & (~(4096 - 1)); + + return luma_size + chroma_size; +} + +static inline +u32 hfi_ubwc_calc_metadata_plane_stride(u32 frame_width, + u32 metadata_stride_multiple, + u32 tile_width_in_pels) +{ + return ALIGN(((frame_width + (tile_width_in_pels - 1)) / tile_width_in_pels), + metadata_stride_multiple); +} + +static inline +u32 hfi_ubwc_metadata_plane_bufheight(u32 frame_height, + u32 metadata_height_multiple, + u32 tile_height_in_pels) +{ + return ALIGN(((frame_height + (tile_height_in_pels - 1)) / tile_height_in_pels), + metadata_height_multiple); +} + +static inline +u32 hfi_ubwc_metadata_plane_buffer_size(u32 _metadata_tride, u32 _metadata_buf_height) +{ + return ALIGN(_metadata_tride * _metadata_buf_height, 4096); +} + +static inline +u32 hfi_buffer_non_comv_enc(u32 frame_width, u32 frame_height, + u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) +{ + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 num_lcu_in_frame = width_in_lcus * height_in_lcus; + u32 frame_height_coded = height_in_lcus * (lcu_size); + u32 frame_width_coded = width_in_lcus * (lcu_size); + u32 num_lcumb, frame_rc_buf_size; + + num_lcumb = (frame_height_coded / lcu_size) * + ((frame_width_coded + lcu_size * 8) / lcu_size); + frame_rc_buf_size = size_frame_rc_buf_size(standard, frame_height_coded, + num_vpp_pipes_enc); + return size_enc_slice_info_buf(num_lcu_in_frame) + + SIZE_SLICE_CMD_BUFFER + + SIZE_SPS_PPS_SLICE_HDR + + frame_rc_buf_size + + enc_bitcnt_buf_size(num_lcu_in_frame) + + enc_bitmap_buf_size(num_lcu_in_frame) + + SIZE_BSE_SLICE_CMD_BUF + + SIZE_LAMBDA_LUT + + size_override_buf(num_lcumb) + + size_ir_buf(num_lcu_in_frame); +} + +static u32 iris_vpu_enc_non_comv_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 lcu_size = 16; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + return hfi_buffer_non_comv_enc(width, height, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_HEVC) + + SIZE_ONE_SLICE_BUF; + } + + return hfi_buffer_non_comv_enc(width, height, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_AVC); +} + +static inline +u32 hfi_buffer_line_enc_base(u32 frame_width, u32 frame_height, bool is_ten_bit, + u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) +{ + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 frame_height_coded = height_in_lcus * (lcu_size); + u32 frame_width_coded = width_in_lcus * (lcu_size); + u32 line_buff_data_size, left_line_buff_ctrl_size; + u32 left_line_buff_metadata_recon__uv__size; + u32 left_line_buff_metadata_recon__y__size; + u32 left_line_buff_recon_pix_size; + u32 top_line_buff_ctrl_fe_size; + u32 line_buff_recon_pix_size; + + line_buff_data_size = size_linebuff_data(is_ten_bit, frame_width_coded); + left_line_buff_ctrl_size = + size_left_linebuff_ctrl(standard, frame_height_coded, num_vpp_pipes_enc); + left_line_buff_recon_pix_size = + size_left_linebuff_recon_pix(is_ten_bit, frame_height_coded, + num_vpp_pipes_enc); + top_line_buff_ctrl_fe_size = + size_top_linebuff_ctrl_fe(frame_width_coded, standard); + left_line_buff_metadata_recon__y__size = + size_left_linebuff_metadata_recon_y(frame_height_coded, is_ten_bit, + num_vpp_pipes_enc); + left_line_buff_metadata_recon__uv__size = + size_left_linebuff_metadata_recon_uv(frame_height_coded, is_ten_bit, + num_vpp_pipes_enc); + line_buff_recon_pix_size = size_linebuff_recon_pix(is_ten_bit, frame_width_coded); + + return size_line_buf_ctrl(frame_width_coded) + + size_line_buf_ctrl_id2(frame_width_coded) + + line_buff_data_size + + left_line_buff_ctrl_size + + left_line_buff_recon_pix_size + + top_line_buff_ctrl_fe_size + + left_line_buff_metadata_recon__y__size + + left_line_buff_metadata_recon__uv__size + + line_buff_recon_pix_size + + size_left_linebuff_ctrl_fe(frame_height_coded, num_vpp_pipes_enc) + + size_line_buf_sde(frame_width_coded) + + size_top_line_buf_first_stg_sao(frame_width_coded); +} + +static inline +u32 hfi_buffer_line_enc(u32 frame_width, u32 frame_height, bool is_ten_bit, + u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) +{ + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 frame_height_coded = height_in_lcus * (lcu_size); + u32 frame_width_coded = width_in_lcus * (lcu_size); + + return hfi_buffer_line_enc_base(frame_width, frame_height, is_ten_bit, + num_vpp_pipes_enc, lcu_size, standard) + + size_vpss_line_buf(num_vpp_pipes_enc, frame_height_coded, frame_width_coded); +} + +static inline +u32 hfi_buffer_line_enc_vpu33(u32 frame_width, u32 frame_height, bool is_ten_bit, + u32 num_vpp_pipes_enc, u32 lcu_size, u32 standard) +{ + u32 width_in_lcus = ((frame_width) + (lcu_size) - 1) / (lcu_size); + u32 height_in_lcus = ((frame_height) + (lcu_size) - 1) / (lcu_size); + u32 frame_height_coded = height_in_lcus * (lcu_size); + u32 frame_width_coded = width_in_lcus * (lcu_size); + + return hfi_buffer_line_enc_base(frame_width, frame_height, is_ten_bit, + num_vpp_pipes_enc, lcu_size, standard) + + size_vpss_line_buf_vpu33(num_vpp_pipes_enc, frame_height_coded, + frame_width_coded); +} + +static u32 iris_vpu_enc_line_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 lcu_size = 16; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + return hfi_buffer_line_enc(width, height, 0, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_HEVC); + } + + return hfi_buffer_line_enc(width, height, 0, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_AVC); +} + +static u32 iris_vpu33_enc_line_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + u32 lcu_size = 16; + + if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + return hfi_buffer_line_enc_vpu33(width, height, 0, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_HEVC); + } + + return hfi_buffer_line_enc_vpu33(width, height, 0, num_vpp_pipes, + lcu_size, HFI_CODEC_ENCODE_AVC); +} + +static inline +u32 hfi_buffer_dpb_enc(u32 frame_width, u32 frame_height, bool is_ten_bit) +{ + u32 metadata_stride, metadata_buf_height, meta_size_y, meta_size_c; + u32 ten_bit_ref_buf_size = 0, ref_buf_size = 0; + u32 size; + + if (!is_ten_bit) { + ref_buf_size = size_enc_ref_buffer(frame_width, frame_height); + metadata_stride = + hfi_ubwc_calc_metadata_plane_stride(frame_width, 64, + HFI_COL_FMT_NV12C_Y_TILE_WIDTH); + metadata_buf_height = + hfi_ubwc_metadata_plane_bufheight(frame_height, 16, + HFI_COL_FMT_NV12C_Y_TILE_HEIGHT); + meta_size_y = + hfi_ubwc_metadata_plane_buffer_size(metadata_stride, metadata_buf_height); + meta_size_c = + hfi_ubwc_metadata_plane_buffer_size(metadata_stride, metadata_buf_height); + size = ref_buf_size + meta_size_y + meta_size_c; + } else { + ten_bit_ref_buf_size = size_enc_ten_bit_ref_buffer(frame_width, frame_height); + metadata_stride = + hfi_ubwc_calc_metadata_plane_stride(frame_width, + IRIS_METADATA_STRIDE_MULTIPLE, + HFI_COL_FMT_TP10C_Y_TILE_WIDTH); + metadata_buf_height = + hfi_ubwc_metadata_plane_bufheight(frame_height, + IRIS_METADATA_HEIGHT_MULTIPLE, + HFI_COL_FMT_TP10C_Y_TILE_HEIGHT); + meta_size_y = + hfi_ubwc_metadata_plane_buffer_size(metadata_stride, metadata_buf_height); + meta_size_c = + hfi_ubwc_metadata_plane_buffer_size(metadata_stride, metadata_buf_height); + size = ten_bit_ref_buf_size + meta_size_y + meta_size_c; + } + + return size; +} + +static u32 iris_vpu_enc_arp_size(struct iris_inst *inst) +{ + return HFI_BUFFER_ARP_ENC; +} + +inline bool is_scaling_enabled(struct iris_inst *inst) +{ + return inst->crop.left != inst->compose.left || + inst->crop.top != inst->compose.top || + inst->crop.width != inst->compose.width || + inst->crop.height != inst->compose.height; +} + +static inline +u32 hfi_buffer_vpss_enc(u32 dswidth, u32 dsheight, bool ds_enable, + u32 blur, bool is_ten_bit) +{ + if (ds_enable || blur) + return hfi_buffer_dpb_enc(dswidth, dsheight, is_ten_bit); + + return 0; +} + +static inline u32 hfi_buffer_scratch1_enc(u32 frame_width, u32 frame_height, + u32 lcu_size, u32 num_ref, + bool ten_bit, u32 num_vpp_pipes, + bool is_h265) +{ + u32 line_buf_ctrl_size, line_buf_data_size, leftline_buf_ctrl_size; + u32 line_buf_sde_size, sps_pps_slice_hdr, topline_buf_ctrl_size_FE; + u32 leftline_buf_ctrl_size_FE, line_buf_recon_pix_size; + u32 leftline_buf_recon_pix_size, lambda_lut_size, override_buffer_size; + u32 col_mv_buf_size, vpp_reg_buffer_size, ir_buffer_size; + u32 vpss_line_buf, leftline_buf_meta_recony, h265e_colrcbuf_size; + u32 h265e_framerc_bufsize, h265e_lcubitcnt_bufsize; + u32 h265e_lcubitmap_bufsize, se_stats_bufsize; + u32 bse_reg_buffer_size, bse_slice_cmd_buffer_size, slice_info_bufsize; + u32 line_buf_ctrl_size_buffid2, slice_cmd_buffer_size; + u32 width_lcu_num, height_lcu_num, width_coded, height_coded; + u32 frame_num_lcu, linebuf_meta_recon_uv, topline_bufsize_fe_1stg_sao; + u32 vpss_line_buffer_size_1; + u32 bit_depth, num_lcu_mb; + + width_lcu_num = (frame_width + lcu_size - 1) / lcu_size; + height_lcu_num = (frame_height + lcu_size - 1) / lcu_size; + frame_num_lcu = width_lcu_num * height_lcu_num; + width_coded = width_lcu_num * lcu_size; + height_coded = height_lcu_num * lcu_size; + num_lcu_mb = (height_coded / lcu_size) * + ((width_coded + lcu_size * 8) / lcu_size); + slice_info_bufsize = 256 + (frame_num_lcu << 4); + slice_info_bufsize = ALIGN(slice_info_bufsize, 256); + line_buf_ctrl_size = ALIGN(width_coded, 256); + line_buf_ctrl_size_buffid2 = ALIGN(width_coded, 256); + + bit_depth = ten_bit ? 10 : 8; + line_buf_data_size = + (((((bit_depth * width_coded + 1024) + (256 - 1)) & + (~(256 - 1))) * 1) + + (((((bit_depth * width_coded + 1024) >> 1) + (256 - 1)) & + (~(256 - 1))) * 2)); + + leftline_buf_ctrl_size = is_h265 ? ((height_coded + 32) / 32 * 4 * 16) : + ((height_coded + 15) / 16 * 5 * 16); + + if (num_vpp_pipes > 1) { + leftline_buf_ctrl_size += 512; + leftline_buf_ctrl_size = + ALIGN(leftline_buf_ctrl_size, 512) * num_vpp_pipes; + } + + leftline_buf_ctrl_size = ALIGN(leftline_buf_ctrl_size, 256); + leftline_buf_recon_pix_size = + (((ten_bit + 1) * 2 * (height_coded) + 256) + + (256 << (num_vpp_pipes - 1)) - 1) & + (~((256 << (num_vpp_pipes - 1)) - 1)) * 1; + + topline_buf_ctrl_size_FE = is_h265 ? (64 * (width_coded >> 5)) : + (256 + 16 * (width_coded >> 4)); + topline_buf_ctrl_size_FE = ALIGN(topline_buf_ctrl_size_FE, 256); + leftline_buf_ctrl_size_FE = + (((256 + 64 * (height_coded >> 4)) + + (256 << (num_vpp_pipes - 1)) - 1) & + (~((256 << (num_vpp_pipes - 1)) - 1)) * 1) * + num_vpp_pipes; + leftline_buf_meta_recony = + (256 + 64 * ((height_coded) / (8 * (ten_bit ? 4 : 8)))); + leftline_buf_meta_recony = ALIGN(leftline_buf_meta_recony, 256); + leftline_buf_meta_recony = leftline_buf_meta_recony * num_vpp_pipes; + linebuf_meta_recon_uv = + (256 + 64 * ((height_coded) / (4 * (ten_bit ? 4 : 8)))); + linebuf_meta_recon_uv = ALIGN(linebuf_meta_recon_uv, 256); + linebuf_meta_recon_uv = linebuf_meta_recon_uv * num_vpp_pipes; + line_buf_recon_pix_size = ((ten_bit ? 3 : 2) * width_coded); + line_buf_recon_pix_size = ALIGN(line_buf_recon_pix_size, 256); + slice_cmd_buffer_size = ALIGN(20480, 256); + sps_pps_slice_hdr = 2048 + 4096; + col_mv_buf_size = + is_h265 ? (16 * ((frame_num_lcu << 2) + 32)) : + (3 * 16 * (width_lcu_num * height_lcu_num + 32)); + col_mv_buf_size = ALIGN(col_mv_buf_size, 256) * (num_ref + 1); + h265e_colrcbuf_size = + (((width_lcu_num + 7) >> 3) * 16 * 2 * height_lcu_num); + if (num_vpp_pipes > 1) + h265e_colrcbuf_size = + ALIGN(h265e_colrcbuf_size, 256) * num_vpp_pipes; + + h265e_colrcbuf_size = + ALIGN(h265e_colrcbuf_size, 256) * HFI_MAX_COL_FRAME; + h265e_framerc_bufsize = + (is_h265) ? + (256 + 16 * (14 + (((height_coded >> 5) + 7) >> 3))) : + (256 + 16 * (14 + (((height_coded >> 4) + 7) >> 3))); + h265e_framerc_bufsize *= 6; + if (num_vpp_pipes > 1) + h265e_framerc_bufsize = + ALIGN(h265e_framerc_bufsize, 256) * num_vpp_pipes; + + h265e_framerc_bufsize = + ALIGN(h265e_framerc_bufsize, 512) * HFI_MAX_COL_FRAME; + h265e_lcubitcnt_bufsize = 256 + 4 * frame_num_lcu; + h265e_lcubitcnt_bufsize = ALIGN(h265e_lcubitcnt_bufsize, 256); + h265e_lcubitmap_bufsize = 256 + (frame_num_lcu >> 3); + h265e_lcubitmap_bufsize = ALIGN(h265e_lcubitmap_bufsize, 256); + line_buf_sde_size = 256 + 16 * (width_coded >> 4); + line_buf_sde_size = ALIGN(line_buf_sde_size, 256); + if ((width_coded * height_coded) > (4096 * 2160)) + se_stats_bufsize = 0; + else if ((width_coded * height_coded) > (1920 * 1088)) + se_stats_bufsize = (40 * 4 * frame_num_lcu + 256 + 256); + else + se_stats_bufsize = (1024 * frame_num_lcu + 256 + 256); + + se_stats_bufsize = ALIGN(se_stats_bufsize, 256) * 2; + bse_slice_cmd_buffer_size = (((8192 << 2) + 7) & (~7)) * 6; + bse_reg_buffer_size = (((512 << 3) + 7) & (~7)) * 4; + vpp_reg_buffer_size = (((2048 << 3) + 31) & (~31)) * 10; + lambda_lut_size = 256 * 11; + override_buffer_size = 16 * ((num_lcu_mb + 7) >> 3); + override_buffer_size = ALIGN(override_buffer_size, 256) * 2; + ir_buffer_size = (((frame_num_lcu << 1) + 7) & (~7)) * 3; + vpss_line_buffer_size_1 = (((8192 >> 2) << 5) * num_vpp_pipes) + 64; + vpss_line_buf = + (((((max(width_coded, height_coded) + 3) >> 2) << 5) + 256) * + 16) + + vpss_line_buffer_size_1; + topline_bufsize_fe_1stg_sao = 16 * (width_coded >> 5); + topline_bufsize_fe_1stg_sao = ALIGN(topline_bufsize_fe_1stg_sao, 256); + + return line_buf_ctrl_size + line_buf_data_size + + line_buf_ctrl_size_buffid2 + leftline_buf_ctrl_size + + vpss_line_buf + col_mv_buf_size + topline_buf_ctrl_size_FE + + leftline_buf_ctrl_size_FE + line_buf_recon_pix_size + + leftline_buf_recon_pix_size + leftline_buf_meta_recony + + linebuf_meta_recon_uv + h265e_colrcbuf_size + + h265e_framerc_bufsize + h265e_lcubitcnt_bufsize + + h265e_lcubitmap_bufsize + line_buf_sde_size + + topline_bufsize_fe_1stg_sao + override_buffer_size + + bse_reg_buffer_size + vpp_reg_buffer_size + sps_pps_slice_hdr + + slice_cmd_buffer_size + bse_slice_cmd_buffer_size + + ir_buffer_size + slice_info_bufsize + lambda_lut_size + + se_stats_bufsize + 1024; +} + +static u32 iris_vpu_enc_scratch1_size(struct iris_inst *inst) +{ + u32 num_vpp_pipes = inst->core->iris_platform_data->num_vpp_pipe; + struct v4l2_format *f = inst->fmt_dst; + u32 frame_height = f->fmt.pix_mp.height; + u32 frame_width = f->fmt.pix_mp.width; + u32 num_ref = 1; + u32 lcu_size; + bool is_h265; + + if (inst->codec == V4L2_PIX_FMT_H264) { + lcu_size = 16; + is_h265 = false; + } else if (inst->codec == V4L2_PIX_FMT_HEVC) { + lcu_size = 32; + is_h265 = true; + } else { + return 0; + } + + return hfi_buffer_scratch1_enc(frame_width, frame_height, lcu_size, + num_ref, false, num_vpp_pipes, is_h265); +} + +static inline u32 ubwc_metadata_plane_stride(u32 width, + u32 metadata_stride_multi, + u32 tile_width_pels) +{ + return ALIGN(((width + (tile_width_pels - 1)) / tile_width_pels), + metadata_stride_multi); +} + +static inline u32 ubwc_metadata_plane_bufheight(u32 height, + u32 metadata_height_multi, + u32 tile_height_pels) +{ + return ALIGN(((height + (tile_height_pels - 1)) / tile_height_pels), + metadata_height_multi); +} + +static inline u32 ubwc_metadata_plane_buffer_size(u32 metadata_stride, + u32 metadata_buf_height) +{ + return ALIGN(metadata_stride * metadata_buf_height, SZ_4K); +} + +static inline u32 hfi_buffer_scratch2_enc(u32 frame_width, u32 frame_height, + u32 num_ref, bool ten_bit) +{ + u32 aligned_width, aligned_height, chroma_height, ref_buf_height; + u32 metadata_stride, meta_buf_height, meta_size_y, meta_size_c; + u32 ref_luma_stride_bytes, ref_chroma_height_bytes; + u32 ref_buf_size, ref_stride; + u32 luma_size, chroma_size; + u32 size; + + if (!ten_bit) { + aligned_height = ALIGN(frame_height, 32); + chroma_height = frame_height >> 1; + chroma_height = ALIGN(chroma_height, 32); + aligned_width = ALIGN(frame_width, 128); + metadata_stride = + ubwc_metadata_plane_stride(frame_width, 64, 32); + meta_buf_height = + ubwc_metadata_plane_bufheight(frame_height, 16, 8); + meta_size_y = ubwc_metadata_plane_buffer_size(metadata_stride, + meta_buf_height); + meta_size_c = ubwc_metadata_plane_buffer_size(metadata_stride, + meta_buf_height); + size = (aligned_height + chroma_height) * aligned_width + + meta_size_y + meta_size_c; + size = (size * (num_ref + 3)) + 4096; + } else { + ref_buf_height = (frame_height + (32 - 1)) & (~(32 - 1)); + ref_luma_stride_bytes = ((frame_width + 192 - 1) / 192) * 192; + ref_stride = 4 * (ref_luma_stride_bytes / 3); + ref_stride = (ref_stride + (128 - 1)) & (~(128 - 1)); + luma_size = ref_buf_height * ref_stride; + ref_chroma_height_bytes = + (((frame_height + 1) >> 1) + (32 - 1)) & (~(32 - 1)); + chroma_size = ref_stride * ref_chroma_height_bytes; + luma_size = (luma_size + (SZ_4K - 1)) & (~(SZ_4K - 1)); + chroma_size = (chroma_size + (SZ_4K - 1)) & (~(SZ_4K - 1)); + ref_buf_size = luma_size + chroma_size; + metadata_stride = + ubwc_metadata_plane_stride(frame_width, 64, 48); + meta_buf_height = + ubwc_metadata_plane_bufheight(frame_height, 16, 4); + meta_size_y = ubwc_metadata_plane_buffer_size(metadata_stride, + meta_buf_height); + meta_size_c = ubwc_metadata_plane_buffer_size(metadata_stride, + meta_buf_height); + size = ref_buf_size + meta_size_y + meta_size_c; + size = (size * (num_ref + 3)) + 4096; + } + + return size; +} + +static u32 iris_vpu_enc_scratch2_size(struct iris_inst *inst) +{ + struct v4l2_format *f = inst->fmt_dst; + u32 frame_width = f->fmt.pix_mp.width; + u32 frame_height = f->fmt.pix_mp.height; + u32 num_ref = 1; + + return hfi_buffer_scratch2_enc(frame_width, frame_height, num_ref, + false); +} + +static u32 iris_vpu_enc_vpss_size(struct iris_inst *inst) +{ + u32 ds_enable = is_scaling_enabled(inst); + struct v4l2_format *f = inst->fmt_dst; + u32 height = f->fmt.pix_mp.height; + u32 width = f->fmt.pix_mp.width; + + return hfi_buffer_vpss_enc(width, height, ds_enable, 0, 0); +} + static int output_min_count(struct iris_inst *inst) { int output_min_count = 4; @@ -571,10 +1431,10 @@ struct iris_vpu_buf_type_handle { u32 (*handle)(struct iris_inst *inst); }; -int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) +u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) { - const struct iris_vpu_buf_type_handle *buf_type_handle_arr; - u32 size = 0, buf_type_handle_size, i; + const struct iris_vpu_buf_type_handle *buf_type_handle_arr = NULL; + u32 size = 0, buf_type_handle_size = 0, i; static const struct iris_vpu_buf_type_handle dec_internal_buf_type_handle[] = { {BUF_BIN, iris_vpu_dec_bin_size }, @@ -586,8 +1446,24 @@ int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) {BUF_SCRATCH_1, iris_vpu_dec_scratch1_size }, }; - buf_type_handle_size = ARRAY_SIZE(dec_internal_buf_type_handle); - buf_type_handle_arr = dec_internal_buf_type_handle; + static const struct iris_vpu_buf_type_handle enc_internal_buf_type_handle[] = { + {BUF_BIN, iris_vpu_enc_bin_size }, + {BUF_COMV, iris_vpu_enc_comv_size }, + {BUF_NON_COMV, iris_vpu_enc_non_comv_size }, + {BUF_LINE, iris_vpu_enc_line_size }, + {BUF_ARP, iris_vpu_enc_arp_size }, + {BUF_VPSS, iris_vpu_enc_vpss_size }, + {BUF_SCRATCH_1, iris_vpu_enc_scratch1_size }, + {BUF_SCRATCH_2, iris_vpu_enc_scratch2_size }, + }; + + if (inst->domain == DECODER) { + buf_type_handle_size = ARRAY_SIZE(dec_internal_buf_type_handle); + buf_type_handle_arr = dec_internal_buf_type_handle; + } else if (inst->domain == ENCODER) { + buf_type_handle_size = ARRAY_SIZE(enc_internal_buf_type_handle); + buf_type_handle_arr = enc_internal_buf_type_handle; + } for (i = 0; i < buf_type_handle_size; i++) { if (buf_type_handle_arr[i].type == buffer_type) { @@ -599,6 +1475,34 @@ int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) return size; } +u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type) +{ + u32 size = 0, i; + + static const struct iris_vpu_buf_type_handle enc_internal_buf_type_handle[] = { + {BUF_BIN, iris_vpu_enc_bin_size }, + {BUF_COMV, iris_vpu_enc_comv_size }, + {BUF_NON_COMV, iris_vpu_enc_non_comv_size }, + {BUF_LINE, iris_vpu33_enc_line_size }, + {BUF_ARP, iris_vpu_enc_arp_size }, + {BUF_VPSS, iris_vpu_enc_vpss_size }, + {BUF_SCRATCH_1, iris_vpu_enc_scratch1_size }, + {BUF_SCRATCH_2, iris_vpu_enc_scratch2_size }, + }; + + if (inst->domain == DECODER) + return iris_vpu_buf_size(inst, buffer_type); + + for (i = 0; i < ARRAY_SIZE(enc_internal_buf_type_handle); i++) { + if (enc_internal_buf_type_handle[i].type == buffer_type) { + size = enc_internal_buf_type_handle[i].handle(inst); + break; + } + } + + return size; +} + static u32 internal_buffer_count(struct iris_inst *inst, enum iris_buffer_type buffer_type) { @@ -628,7 +1532,10 @@ int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type case BUF_INPUT: return MIN_BUFFERS; case BUF_OUTPUT: - return output_min_count(inst); + if (inst->domain == ENCODER) + return MIN_BUFFERS; + else + return output_min_count(inst); case BUF_BIN: case BUF_COMV: case BUF_NON_COMV: @@ -636,6 +1543,9 @@ int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type case BUF_PERSIST: return internal_buffer_count(inst, buffer_type); case BUF_SCRATCH_1: + case BUF_SCRATCH_2: + case BUF_VPSS: + case BUF_ARP: return 1; /* internal buffer count needed by firmware is 1 */ case BUF_DPB: return iris_vpu_dpb_count(inst); diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h index ee95fd20b794..04f0b7400a1e 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.h @@ -41,6 +41,7 @@ struct iris_inst; #define SIZE_SLIST_BUF_H265 (BIT(10)) #define H265_DISPLAY_BUF_SIZE (3072) #define H265_NUM_FRM_INFO (48) +#define SIZE_ONE_SLICE_BUF 256 #define VP9_NUM_FRAME_INFO_BUF 32 #define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) @@ -80,6 +81,26 @@ struct iris_inst; #define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE 384 #define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE 640 +#define SIZE_SLICE_CMD_BUFFER (ALIGN(20480, 256)) +#define SIZE_SPS_PPS_SLICE_HDR (2048 + 4096) +#define SIZE_BSE_SLICE_CMD_BUF ((((8192 << 2) + 7) & (~7)) * 3) +#define SIZE_LAMBDA_LUT (256 * 11) + +#define HFI_COL_FMT_NV12C_Y_TILE_HEIGHT (8) +#define HFI_COL_FMT_NV12C_Y_TILE_WIDTH (32) +#define HFI_COL_FMT_TP10C_Y_TILE_HEIGHT (4) +#define HFI_COL_FMT_TP10C_Y_TILE_WIDTH (48) + +#define IRIS_METADATA_STRIDE_MULTIPLE 64 +#define IRIS_METADATA_HEIGHT_MULTIPLE 16 + +#define HFI_BUFFER_ARP_ENC 204800 + +#define MAX_WIDTH 4096 +#define MAX_HEIGHT 2304 +#define NUM_MBS_4K (DIV_ROUND_UP(MAX_WIDTH, 16) * DIV_ROUND_UP(MAX_HEIGHT, 16)) +#define NUM_MBS_720P (((ALIGN(1280, 16)) >> 4) * ((ALIGN(736, 16)) >> 4)) + static inline u32 size_h264d_lb_fe_top_data(u32 frame_width) { return MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * ALIGN(frame_width, 16) * 3; @@ -125,7 +146,8 @@ static inline u32 size_h264d_qp(u32 frame_width, u32 frame_height) return DIV_ROUND_UP(frame_width, 64) * DIV_ROUND_UP(frame_height, 64) * 128; } -int iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); +u32 iris_vpu_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); +u32 iris_vpu33_buf_size(struct iris_inst *inst, enum iris_buffer_type buffer_type); int iris_vpu_buf_count(struct iris_inst *inst, enum iris_buffer_type buffer_type); #endif diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index 268e45acaa7c..515dd55a3377 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -84,6 +84,7 @@ static void iris_vpu_interrupt_init(struct iris_core *core) static void iris_vpu_setup_ucregion_memory_map(struct iris_core *core) { u32 queue_size, value; + const struct vpu_ops *vpu_ops = core->iris_platform_data->vpu_ops; /* Iris hardware requires 4K queue alignment */ queue_size = ALIGN(sizeof(struct iris_hfi_queue_table_header) + @@ -105,6 +106,9 @@ static void iris_vpu_setup_ucregion_memory_map(struct iris_core *core) value = (u32)core->sfr_daddr + core->iris_platform_data->core_arch; writel(value, core->reg_base + SFR_ADDR); } + + if (vpu_ops->program_bootup_registers) + vpu_ops->program_bootup_registers(core); } int iris_vpu_boot_firmware(struct iris_core *core) @@ -218,12 +222,14 @@ int iris_vpu_power_off_controller(struct iris_core *core) writel(MSK_SIGNAL_FROM_TENSILICA | MSK_CORE_POWER_ON, core->reg_base + CPU_CS_X2RPMH); - writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + if (!core->iris_platform_data->no_aon) { + writel(REQ_POWER_DOWN_PREP, core->reg_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); - ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, - val, val & BIT(0), 200, 2000); - if (ret) - goto disable_power; + ret = readl_poll_timeout(core->reg_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, + val, val & BIT(0), 200, 2000); + if (ret) + goto disable_power; + } writel(REQ_POWER_DOWN_PREP, core->reg_base + WRAPPER_IRIS_CPU_NOC_LPI_CONTROL); @@ -246,6 +252,7 @@ int iris_vpu_power_off_controller(struct iris_core *core) writel(0x0, core->reg_base + WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG); disable_power: + iris_disable_unprepare_clock(core, IRIS_AHB_CLK); iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); iris_disable_unprepare_clock(core, IRIS_AXI_CLK); iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); @@ -257,6 +264,7 @@ void iris_vpu_power_off_hw(struct iris_core *core) { dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], false); iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); + iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK); iris_disable_unprepare_clock(core, IRIS_HW_CLK); } @@ -271,7 +279,7 @@ void iris_vpu_power_off(struct iris_core *core) disable_irq_nosync(core->irq); } -static int iris_vpu_power_on_controller(struct iris_core *core) +int iris_vpu_power_on_controller(struct iris_core *core) { u32 rst_tbl_size = core->iris_platform_data->clk_rst_tbl_size; int ret; @@ -290,11 +298,17 @@ static int iris_vpu_power_on_controller(struct iris_core *core) ret = iris_prepare_enable_clock(core, IRIS_CTRL_CLK); if (ret) - goto err_disable_clock; + goto err_disable_axi_clock; + + ret = iris_prepare_enable_clock(core, IRIS_AHB_CLK); + if (ret && ret != -ENOENT) + goto err_disable_ctrl_clock; return 0; -err_disable_clock: +err_disable_ctrl_clock: + iris_disable_unprepare_clock(core, IRIS_CTRL_CLK); +err_disable_axi_clock: iris_disable_unprepare_clock(core, IRIS_AXI_CLK); err_disable_power: iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_CTRL_POWER_DOMAIN]); @@ -302,7 +316,7 @@ err_disable_power: return ret; } -static int iris_vpu_power_on_hw(struct iris_core *core) +int iris_vpu_power_on_hw(struct iris_core *core) { int ret; @@ -314,13 +328,19 @@ static int iris_vpu_power_on_hw(struct iris_core *core) if (ret) goto err_disable_power; + ret = iris_prepare_enable_clock(core, IRIS_HW_AHB_CLK); + if (ret && ret != -ENOENT) + goto err_disable_hw_clock; + ret = dev_pm_genpd_set_hwmode(core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN], true); if (ret) - goto err_disable_clock; + goto err_disable_hw_ahb_clock; return 0; -err_disable_clock: +err_disable_hw_ahb_clock: + iris_disable_unprepare_clock(core, IRIS_HW_AHB_CLK); +err_disable_hw_clock: iris_disable_unprepare_clock(core, IRIS_HW_CLK); err_disable_power: iris_disable_power_domains(core, core->pmdomain_tbl->pd_devs[IRIS_HW_POWER_DOMAIN]); @@ -337,11 +357,11 @@ int iris_vpu_power_on(struct iris_core *core) if (ret) goto err; - ret = iris_vpu_power_on_controller(core); + ret = core->iris_platform_data->vpu_ops->power_on_controller(core); if (ret) goto err_unvote_icc; - ret = iris_vpu_power_on_hw(core); + ret = core->iris_platform_data->vpu_ops->power_on_hw(core); if (ret) goto err_power_off_ctrl; @@ -359,7 +379,7 @@ int iris_vpu_power_on(struct iris_core *core) return 0; err_power_off_ctrl: - iris_vpu_power_off_controller(core); + core->iris_platform_data->vpu_ops->power_off_controller(core); err_unvote_icc: iris_unset_icc_bw(core); err: diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.h b/drivers/media/platform/qcom/iris/iris_vpu_common.h index 93b7fa27be3b..d636e287457a 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.h +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.h @@ -11,10 +11,14 @@ struct iris_core; extern const struct vpu_ops iris_vpu2_ops; extern const struct vpu_ops iris_vpu3_ops; extern const struct vpu_ops iris_vpu33_ops; +extern const struct vpu_ops iris_vpu35_ops; struct vpu_ops { void (*power_off_hw)(struct iris_core *core); + int (*power_on_hw)(struct iris_core *core); int (*power_off_controller)(struct iris_core *core); + int (*power_on_controller)(struct iris_core *core); + void (*program_bootup_registers)(struct iris_core *core); u64 (*calc_freq)(struct iris_inst *inst, size_t data_size); }; @@ -23,6 +27,8 @@ void iris_vpu_raise_interrupt(struct iris_core *core); void iris_vpu_clear_interrupt(struct iris_core *core); int iris_vpu_watchdog(struct iris_core *core, u32 intr_status); int iris_vpu_prepare_pc(struct iris_core *core); +int iris_vpu_power_on_controller(struct iris_core *core); +int iris_vpu_power_on_hw(struct iris_core *core); int iris_vpu_power_on(struct iris_core *core); int iris_vpu_power_off_controller(struct iris_core *core); void iris_vpu_power_off_hw(struct iris_core *core); diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 4c049c694d9c..24d2b2fd0340 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -254,14 +254,19 @@ err: static void venus_assign_register_offsets(struct venus_core *core) { - if (IS_IRIS2(core) || IS_IRIS2_1(core)) { - core->vbif_base = core->base + VBIF_BASE; + if (IS_IRIS2(core) || IS_IRIS2_1(core) || IS_AR50_LITE(core)) { core->cpu_base = core->base + CPU_BASE_V6; core->cpu_cs_base = core->base + CPU_CS_BASE_V6; core->cpu_ic_base = core->base + CPU_IC_BASE_V6; core->wrapper_base = core->base + WRAPPER_BASE_V6; core->wrapper_tz_base = core->base + WRAPPER_TZ_BASE_V6; - core->aon_base = core->base + AON_BASE_V6; + if (IS_AR50_LITE(core)) { + core->vbif_base = NULL; + core->aon_base = NULL; + } else { + core->vbif_base = core->base + VBIF_BASE; + core->aon_base = core->base + AON_BASE_V6; + } } else { core->vbif_base = core->base + VBIF_BASE; core->cpu_base = core->base + CPU_BASE; @@ -448,24 +453,18 @@ static int venus_probe(struct platform_device *pdev) if (ret < 0) goto err_runtime_disable; - if (core->res->dec_nodename || core->res->enc_nodename) { - ret = venus_add_dynamic_nodes(core); - if (ret) - goto err_runtime_disable; - } - - ret = of_platform_populate(dev->of_node, NULL, NULL, dev); - if (ret) - goto err_remove_dynamic_nodes; - ret = venus_firmware_init(core); if (ret) - goto err_of_depopulate; + goto err_runtime_disable; ret = venus_boot(core); if (ret) goto err_firmware_deinit; + ret = venus_firmware_cfg(core); + if (ret) + goto err_venus_shutdown; + ret = hfi_core_resume(core, true); if (ret) goto err_venus_shutdown; @@ -474,34 +473,48 @@ static int venus_probe(struct platform_device *pdev) if (ret) goto err_venus_shutdown; - ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC); + ret = venus_firmware_check(core); if (ret) goto err_core_deinit; + if (core->res->dec_nodename || core->res->enc_nodename) { + ret = venus_add_dynamic_nodes(core); + if (ret) + goto err_core_deinit; + } + + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret) + goto err_remove_dynamic_nodes; + + ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_DEC); + if (ret) + goto err_of_depopulate; + ret = venus_enumerate_codecs(core, VIDC_SESSION_TYPE_ENC); if (ret) - goto err_core_deinit; + goto err_of_depopulate; ret = pm_runtime_put_sync(dev); if (ret) { pm_runtime_get_noresume(dev); - goto err_core_deinit; + goto err_of_depopulate; } venus_dbgfs_init(core); return 0; +err_of_depopulate: + of_platform_depopulate(dev); +err_remove_dynamic_nodes: + venus_remove_dynamic_nodes(core); err_core_deinit: hfi_core_deinit(core, false); err_venus_shutdown: venus_shutdown(core); err_firmware_deinit: venus_firmware_deinit(core); -err_of_depopulate: - of_platform_depopulate(dev); -err_remove_dynamic_nodes: - venus_remove_dynamic_nodes(core); err_runtime_disable: pm_runtime_put_noidle(dev); pm_runtime_disable(dev); @@ -596,7 +609,7 @@ err_cpucfg_path: return ret; } -void venus_close_common(struct venus_inst *inst) +void venus_close_common(struct venus_inst *inst, struct file *filp) { /* * Make sure we don't have IRQ/IRQ-thread currently running @@ -607,7 +620,7 @@ void venus_close_common(struct venus_inst *inst) v4l2_m2m_ctx_release(inst->m2m_ctx); v4l2_m2m_release(inst->m2m_dev); hfi_session_destroy(inst); - v4l2_fh_del(&inst->fh); + v4l2_fh_del(&inst->fh, filp); v4l2_fh_exit(&inst->fh); v4l2_ctrl_handler_free(&inst->ctrl_handler); @@ -1057,15 +1070,65 @@ static const struct venus_resources sc7280_res = { .enc_nodename = "video-encoder", }; +static const struct bw_tbl qcm2290_bw_table_dec[] = { + { 352800, 597000, 0, 746000, 0 }, /* 1080p@30 + 720p@30 */ + { 244800, 413000, 0, 516000, 0 }, /* 1080p@30 */ + { 216000, 364000, 0, 454000, 0 }, /* 720p@60 */ + { 108000, 182000, 0, 227000, 0 }, /* 720p@30 */ +}; + +static const struct bw_tbl qcm2290_bw_table_enc[] = { + { 352800, 396000, 0, 0, 0 }, /* 1080p@30 + 720p@30 */ + { 244800, 275000, 0, 0, 0 }, /* 1080p@30 */ + { 216000, 242000, 0, 0, 0 }, /* 720p@60 */ + { 108000, 121000, 0, 0, 0 }, /* 720p@30 */ +}; + +static const struct firmware_version min_fw = { + .major = 6, .minor = 0, .rev = 55, +}; + +static const struct venus_resources qcm2290_res = { + .bw_tbl_dec = qcm2290_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(qcm2290_bw_table_dec), + .bw_tbl_enc = qcm2290_bw_table_enc, + .bw_tbl_enc_size = ARRAY_SIZE(qcm2290_bw_table_enc), + .clks = { "core", "iface", "bus", "throttle" }, + .clks_num = 4, + .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, + .vcodec_clks_num = 2, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, + .vcodec_pmdomains_num = 2, + .opp_pmdomain = (const char *[]) { "cx" }, + .vcodec_num = 1, + .hfi_version = HFI_VERSION_4XX, + .vpu_version = VPU_VERSION_AR50_LITE, + .max_load = 352800, + .num_vpp_pipes = 1, + .vmem_id = VIDC_RESOURCE_NONE, + .vmem_size = 0, + .vmem_addr = 0, + .cp_start = 0, + .cp_size = 0x70800000, + .cp_nonpixel_start = 0x1000000, + .cp_nonpixel_size = 0x24800000, + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/venus-6.0/venus.mbn", + .dec_nodename = "video-decoder", + .enc_nodename = "video-encoder", + .min_fw = &min_fw, +}; + static const struct of_device_id venus_dt_match[] = { { .compatible = "qcom,msm8916-venus", .data = &msm8916_res, }, { .compatible = "qcom,msm8996-venus", .data = &msm8996_res, }, { .compatible = "qcom,msm8998-venus", .data = &msm8998_res, }, + { .compatible = "qcom,qcm2290-venus", .data = &qcm2290_res, }, + { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, + { .compatible = "qcom,sc7280-venus", .data = &sc7280_res, }, { .compatible = "qcom,sdm660-venus", .data = &sdm660_res, }, { .compatible = "qcom,sdm845-venus", .data = &sdm845_res, }, { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, }, - { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, - { .compatible = "qcom,sc7280-venus", .data = &sc7280_res, }, { .compatible = "qcom,sm8250-venus", .data = &sm8250_res, }, { } }; @@ -1083,6 +1146,5 @@ static struct platform_driver qcom_venus_driver = { }; module_platform_driver(qcom_venus_driver); -MODULE_ALIAS("platform:qcom-venus"); MODULE_DESCRIPTION("Qualcomm Venus video encoder and decoder driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 5b1ba1c69adb..7506f5d0f609 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -58,6 +58,12 @@ enum vpu_version { VPU_VERSION_IRIS2_1, }; +struct firmware_version { + u32 major; + u32 minor; + u32 rev; +}; + struct venus_resources { u64 dma_mask; const struct freq_tbl *freq_tbl; @@ -94,6 +100,7 @@ struct venus_resources { const char *fwname; const char *enc_nodename; const char *dec_nodename; + const struct firmware_version *min_fw; }; enum venus_fmt { @@ -231,11 +238,7 @@ struct venus_core { unsigned int core0_usage_count; unsigned int core1_usage_count; struct dentry *root; - struct venus_img_version { - u32 major; - u32 minor; - u32 rev; - } venus_ver; + struct firmware_version venus_ver; unsigned long dump_core; struct of_changeset *ocs; bool hwmode_dev; @@ -530,12 +533,17 @@ struct venus_inst { #define IS_IRIS2(core) ((core)->res->vpu_version == VPU_VERSION_IRIS2) #define IS_IRIS2_1(core) ((core)->res->vpu_version == VPU_VERSION_IRIS2_1) +static inline bool is_lite(struct venus_core *core) +{ + return IS_AR50_LITE(core); +} + #define ctrl_to_inst(ctrl) \ container_of((ctrl)->handler, struct venus_inst, ctrl_handler) static inline struct venus_inst *to_inst(struct file *filp) { - return container_of(filp->private_data, struct venus_inst, fh); + return container_of(file_to_v4l2_fh(filp), struct venus_inst, fh); } static inline void *to_hfi_priv(struct venus_core *core) @@ -573,5 +581,5 @@ is_fw_rev_or_older(struct venus_core *core, u32 vmajor, u32 vminor, u32 vrev) (core)->venus_ver.rev <= vrev); } -void venus_close_common(struct venus_inst *inst); +void venus_close_common(struct venus_inst *inst, struct file *filp); #endif diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 66a18830e66d..1de7436713ed 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -9,7 +9,6 @@ #include <linux/iommu.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_address.h> #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> #include <linux/of_device.h> @@ -30,7 +29,7 @@ static void venus_reset_cpu(struct venus_core *core) u32 fw_size = core->fw.mapped_mem_size; void __iomem *wrapper_base; - if (IS_IRIS2_1(core)) + if (IS_IRIS2(core) || IS_IRIS2_1(core)) wrapper_base = core->wrapper_tz_base; else wrapper_base = core->wrapper_base; @@ -42,7 +41,7 @@ static void venus_reset_cpu(struct venus_core *core) writel(fw_size, wrapper_base + WRAPPER_NONPIX_START_ADDR); writel(fw_size, wrapper_base + WRAPPER_NONPIX_END_ADDR); - if (IS_IRIS2_1(core)) { + if (IS_IRIS2(core) || IS_IRIS2_1(core)) { /* Bring XTSS out of reset */ writel(0, wrapper_base + WRAPPER_TZ_XTSS_SW_RESET); } else { @@ -68,7 +67,7 @@ int venus_set_hw_state(struct venus_core *core, bool resume) if (resume) { venus_reset_cpu(core); } else { - if (IS_IRIS2_1(core)) + if (IS_IRIS2(core) || IS_IRIS2_1(core)) writel(WRAPPER_XTSS_SW_RESET_BIT, core->wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET); else @@ -83,8 +82,7 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, phys_addr_t *mem_phys, size_t *mem_size) { const struct firmware *mdt; - struct reserved_mem *rmem; - struct device_node *node; + struct resource res; struct device *dev; ssize_t fw_size; void *mem_va; @@ -94,15 +92,8 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, *mem_size = 0; dev = core->dev; - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!node) { - dev_err(dev, "no memory-region specified\n"); - return -EINVAL; - } - - rmem = of_reserved_mem_lookup(node); - of_node_put(node); - if (!rmem) { + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); + if (ret) { dev_err(dev, "failed to lookup reserved memory-region\n"); return -EINVAL; } @@ -117,8 +108,8 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, goto err_release_fw; } - *mem_phys = rmem->base; - *mem_size = rmem->size; + *mem_phys = res.start; + *mem_size = resource_size(&res); if (*mem_size < fw_size || fw_size > VENUS_FW_MEM_SIZE) { ret = -EINVAL; @@ -136,8 +127,8 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, *mem_phys, *mem_size, NULL); else - ret = qcom_mdt_load_no_init(dev, mdt, fwname, VENUS_PAS_ID, - mem_va, *mem_phys, *mem_size, NULL); + ret = qcom_mdt_load_no_init(dev, mdt, fwname, mem_va, + *mem_phys, *mem_size, NULL); memunmap(mem_va); err_release_fw: @@ -181,7 +172,7 @@ static int venus_shutdown_no_tz(struct venus_core *core) void __iomem *wrapper_base = core->wrapper_base; void __iomem *wrapper_tz_base = core->wrapper_tz_base; - if (IS_IRIS2_1(core)) { + if (IS_IRIS2(core) || IS_IRIS2_1(core)) { /* Assert the reset to XTSS */ reg = readl(wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET); reg |= WRAPPER_XTSS_SW_RESET_BIT; @@ -207,6 +198,16 @@ static int venus_shutdown_no_tz(struct venus_core *core) return 0; } +int venus_firmware_cfg(struct venus_core *core) +{ + void __iomem *cpu_cs_base = core->cpu_cs_base; + + if (IS_AR50_LITE(core)) + writel(CPU_CS_VCICMD_ARP_OFF, cpu_cs_base + CPU_CS_VCICMD); + + return 0; +} + int venus_boot(struct venus_core *core) { struct device *dev = core->dev; @@ -280,6 +281,26 @@ int venus_shutdown(struct venus_core *core) return ret; } +int venus_firmware_check(struct venus_core *core) +{ + const struct firmware_version *req = core->res->min_fw; + const struct firmware_version *run = &core->venus_ver; + + if (!req) + return 0; + + if (!is_fw_rev_or_newer(core, req->major, req->minor, req->rev)) + goto error; + + return 0; +error: + dev_err(core->dev, "Firmware v%d.%d.%d < v%d.%d.%d\n", + run->major, run->minor, run->rev, + req->major, req->minor, req->rev); + + return -EINVAL; +} + int venus_firmware_init(struct venus_core *core) { struct platform_device_info info; diff --git a/drivers/media/platform/qcom/venus/firmware.h b/drivers/media/platform/qcom/venus/firmware.h index aaccd847fa30..87e1d922b369 100644 --- a/drivers/media/platform/qcom/venus/firmware.h +++ b/drivers/media/platform/qcom/venus/firmware.h @@ -9,6 +9,8 @@ struct device; int venus_firmware_init(struct venus_core *core); void venus_firmware_deinit(struct venus_core *core); +int venus_firmware_check(struct venus_core *core); +int venus_firmware_cfg(struct venus_core *core); int venus_boot(struct venus_core *core); int venus_shutdown(struct venus_core *core); int venus_set_hw_state(struct venus_core *core, bool suspend); diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 8295542e1a7c..2e4363f82231 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -1715,11 +1715,17 @@ int venus_helper_session_init(struct venus_inst *inst) if (ret) return ret; - inst->clk_data.vpp_freq = hfi_platform_get_codec_vpp_freq(version, codec, + inst->clk_data.vpp_freq = hfi_platform_get_codec_vpp_freq(inst->core, + version, + codec, session_type); - inst->clk_data.vsp_freq = hfi_platform_get_codec_vsp_freq(version, codec, + inst->clk_data.vsp_freq = hfi_platform_get_codec_vsp_freq(inst->core, + version, + codec, session_type); - inst->clk_data.low_power_freq = hfi_platform_get_codec_lp_freq(version, codec, + inst->clk_data.low_power_freq = hfi_platform_get_codec_lp_freq(inst->core, + version, + codec, session_type); return 0; diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index cf0d97cbc463..47b99d5b5af7 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -277,7 +277,12 @@ static void hfi_sys_init_done(struct venus_core *core, struct venus_inst *inst, done: core->error = error; - complete(&core->done); + /* + * Since core_init could ask for the firmware version to be validated, + * completion might have to wait until the version is retrieved. + */ + if (!core->res->min_fw) + complete(&core->done); } static void @@ -328,6 +333,10 @@ done: if (!IS_ERR(smem_tbl_ptr) && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ) memcpy(smem_tbl_ptr + SMEM_IMG_OFFSET_VENUS, img_ver, VER_STR_SZ); + + /* core_init could have had to wait for a version check */ + if (core->res->min_fw) + complete(&core->done); } static void hfi_sys_property_info(struct venus_core *core, diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c index 1b3db2caa99f..92765f9c8873 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.c +++ b/drivers/media/platform/qcom/venus/hfi_parser.c @@ -282,7 +282,7 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst) return ret; if (plat->capabilities) - caps = plat->capabilities(&entries); + caps = plat->capabilities(core, &entries); if (!caps || !entries || !count) return -EINVAL; diff --git a/drivers/media/platform/qcom/venus/hfi_platform.c b/drivers/media/platform/qcom/venus/hfi_platform.c index 643e5aa138f5..cde7f93045ac 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform.c +++ b/drivers/media/platform/qcom/venus/hfi_platform.c @@ -21,7 +21,9 @@ const struct hfi_platform *hfi_platform_get(enum hfi_version version) } unsigned long -hfi_platform_get_codec_vpp_freq(enum hfi_version version, u32 codec, u32 session_type) +hfi_platform_get_codec_vpp_freq(struct venus_core *core, + enum hfi_version version, u32 codec, + u32 session_type) { const struct hfi_platform *plat; unsigned long freq = 0; @@ -31,13 +33,15 @@ hfi_platform_get_codec_vpp_freq(enum hfi_version version, u32 codec, u32 session return 0; if (plat->codec_vpp_freq) - freq = plat->codec_vpp_freq(session_type, codec); + freq = plat->codec_vpp_freq(core, session_type, codec); return freq; } unsigned long -hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec, u32 session_type) +hfi_platform_get_codec_vsp_freq(struct venus_core *core, + enum hfi_version version, u32 codec, + u32 session_type) { const struct hfi_platform *plat; unsigned long freq = 0; @@ -47,13 +51,15 @@ hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec, u32 session return 0; if (plat->codec_vpp_freq) - freq = plat->codec_vsp_freq(session_type, codec); + freq = plat->codec_vsp_freq(core, session_type, codec); return freq; } unsigned long -hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_type) +hfi_platform_get_codec_lp_freq(struct venus_core *core, + enum hfi_version version, u32 codec, + u32 session_type) { const struct hfi_platform *plat; unsigned long freq = 0; @@ -63,13 +69,14 @@ hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_ return 0; if (plat->codec_lp_freq) - freq = plat->codec_lp_freq(session_type, codec); + freq = plat->codec_lp_freq(core, session_type, codec); return freq; } int -hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, u32 *dec_codecs, u32 *count) +hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, + u32 *dec_codecs, u32 *count) { const struct hfi_platform *plat; @@ -78,7 +85,7 @@ hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, u32 *dec_codec return -EINVAL; if (plat->codecs) - plat->codecs(enc_codecs, dec_codecs, count); + plat->codecs(core, enc_codecs, dec_codecs, count); if (IS_IRIS2_1(core)) { *enc_codecs &= ~HFI_VIDEO_CODEC_VP8; diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h index ec89a90a8129..5e4f8013a6b1 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform.h +++ b/drivers/media/platform/qcom/venus/hfi_platform.h @@ -47,11 +47,16 @@ struct hfi_platform_codec_freq_data { }; struct hfi_platform { - unsigned long (*codec_vpp_freq)(u32 session_type, u32 codec); - unsigned long (*codec_vsp_freq)(u32 session_type, u32 codec); - unsigned long (*codec_lp_freq)(u32 session_type, u32 codec); - void (*codecs)(u32 *enc_codecs, u32 *dec_codecs, u32 *count); - const struct hfi_plat_caps *(*capabilities)(unsigned int *entries); + unsigned long (*codec_vpp_freq)(struct venus_core *core, + u32 session_type, u32 codec); + unsigned long (*codec_vsp_freq)(struct venus_core *core, + u32 session_type, u32 codec); + unsigned long (*codec_lp_freq)(struct venus_core *core, + u32 session_type, u32 codec); + void (*codecs)(struct venus_core *core, u32 *enc_codecs, + u32 *dec_codecs, u32 *count); + const struct hfi_plat_caps *(*capabilities)(struct venus_core *core, + unsigned int *entries); int (*bufreq)(struct hfi_plat_buffers_params *params, u32 session_type, u32 buftype, struct hfi_buffer_requirements *bufreq); }; @@ -60,12 +65,15 @@ extern const struct hfi_platform hfi_plat_v4; extern const struct hfi_platform hfi_plat_v6; const struct hfi_platform *hfi_platform_get(enum hfi_version version); -unsigned long hfi_platform_get_codec_vpp_freq(enum hfi_version version, u32 codec, - u32 session_type); -unsigned long hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 codec, - u32 session_type); -unsigned long hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, - u32 session_type); -int hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, u32 *dec_codecs, - u32 *count); +unsigned long hfi_platform_get_codec_vpp_freq(struct venus_core *core, + enum hfi_version version, + u32 codec, u32 session_type); +unsigned long hfi_platform_get_codec_vsp_freq(struct venus_core *core, + enum hfi_version version, + u32 codec, u32 session_type); +unsigned long hfi_platform_get_codec_lp_freq(struct venus_core *core, + enum hfi_version version, + u32 codec, u32 session_type); +int hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, + u32 *dec_codecs, u32 *count); #endif diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v4.c b/drivers/media/platform/qcom/venus/hfi_platform_v4.c index e3f0a90a567b..cda888b56b5d 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform_v4.c +++ b/drivers/media/platform/qcom/venus/hfi_platform_v4.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +#include "core.h" #include "hfi_platform.h" static const struct hfi_plat_caps caps[] = { @@ -245,20 +246,150 @@ static const struct hfi_plat_caps caps[] = { .num_fmts = 4, } }; -static const struct hfi_plat_caps *get_capabilities(unsigned int *entries) +static const struct hfi_plat_caps caps_lite[] = { { - *entries = ARRAY_SIZE(caps); - return caps; + .codec = HFI_VIDEO_CODEC_H264, + .domain = VIDC_SESSION_TYPE_DEC, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 }, + .caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1}, + .caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1}, + .caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, + .num_caps = 7, + .pl[0] = { HFI_H264_PROFILE_BASELINE, HFI_H264_LEVEL_5}, + .pl[1] = {HFI_H264_PROFILE_MAIN, HFI_H264_LEVEL_5}, + .pl[2] = {HFI_H264_PROFILE_HIGH, HFI_H264_LEVEL_5}, + .pl[3] = {HFI_H264_PROFILE_CONSTRAINED_BASE, HFI_H264_LEVEL_5}, + .pl[4] = {HFI_H264_PROFILE_CONSTRAINED_HIGH, HFI_H264_LEVEL_5}, + .num_pl = 5, + .fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC}, + .fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC}, + .fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, + .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, + .num_fmts = 4, +}, { + .codec = HFI_VIDEO_CODEC_HEVC, + .domain = VIDC_SESSION_TYPE_DEC, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 }, + .caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1}, + .caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1}, + .caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, + .num_caps = 7, + .pl[0] = {HFI_HEVC_PROFILE_MAIN, HFI_HEVC_LEVEL_5 | HFI_HEVC_TIER_HIGH0 << 28 }, + .pl[1] = {HFI_HEVC_PROFILE_MAIN10, HFI_HEVC_LEVEL_5 | HFI_HEVC_TIER_HIGH0 << 28 }, + .num_pl = 2, + .fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC}, + .fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC}, + .fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, + .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, + .num_fmts = 4, +}, { + .codec = HFI_VIDEO_CODEC_VP9, + .domain = VIDC_SESSION_TYPE_DEC, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 }, + .caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1}, + .caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1}, + .caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, + .num_caps = 7, + .pl[0] = {HFI_VP9_PROFILE_P0, 200}, + .pl[1] = {HFI_VP9_PROFILE_P2_10B, 200}, + .num_pl = 2, + .fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC}, + .fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC}, + .fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, + .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, + .num_fmts = 4, +}, { + .codec = HFI_VIDEO_CODEC_H264, + .domain = VIDC_SESSION_TYPE_ENC, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 }, + .caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1}, + .caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1}, + .caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, + .caps[7] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 6, 1}, + .caps[8] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 4, 1}, + .caps[9] = {HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE, 0, 244800, 1}, + .caps[10] = {HFI_CAPABILITY_I_FRAME_QP, 0, 51, 1}, + .caps[11] = {HFI_CAPABILITY_P_FRAME_QP, 0, 51, 1}, + .caps[12] = {HFI_CAPABILITY_B_FRAME_QP, 0, 51, 1}, + .caps[13] = {HFI_CAPABILITY_SLICE_BYTE, 1, 10, 1}, + .caps[14] = {HFI_CAPABILITY_SLICE_MB, 1, 10, 1}, + .num_caps = 15, + .pl[0] = {HFI_H264_PROFILE_BASELINE, HFI_H264_LEVEL_5}, + .pl[1] = {HFI_H264_PROFILE_MAIN, HFI_H264_LEVEL_5}, + .pl[2] = {HFI_H264_PROFILE_HIGH, HFI_H264_LEVEL_5}, + .pl[3] = {HFI_H264_PROFILE_CONSTRAINED_BASE, HFI_H264_LEVEL_5}, + .pl[4] = {HFI_H264_PROFILE_CONSTRAINED_HIGH, HFI_H264_LEVEL_5}, + .num_pl = 5, + .fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12}, + .fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC}, + .num_fmts = 2, +}, { + .codec = HFI_VIDEO_CODEC_HEVC, + .domain = VIDC_SESSION_TYPE_ENC, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 }, + .caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1}, + .caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1}, + .caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, + .caps[7] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 6, 1}, + .caps[8] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 4, 1}, + .caps[9] = {HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE, 0, 244800, 1}, + .caps[10] = {HFI_CAPABILITY_I_FRAME_QP, 0, 51, 1}, + .caps[11] = {HFI_CAPABILITY_P_FRAME_QP, 0, 51, 1}, + .caps[12] = {HFI_CAPABILITY_B_FRAME_QP, 0, 51, 1}, + .caps[13] = {HFI_CAPABILITY_SLICE_BYTE, 1, 10, 1}, + .caps[14] = {HFI_CAPABILITY_SLICE_MB, 1, 10, 1}, + .num_caps = 15, + .pl[0] = {HFI_HEVC_PROFILE_MAIN, HFI_HEVC_LEVEL_5 | HFI_HEVC_TIER_HIGH0}, + .pl[1] = {HFI_HEVC_PROFILE_MAIN10, HFI_HEVC_LEVEL_5 | HFI_HEVC_TIER_HIGH0}, + .num_pl = 2, + .fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12}, + .fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC}, + .num_fmts = 2, +} }; + +static const struct hfi_plat_caps *get_capabilities(struct venus_core *core, + unsigned int *entries) +{ + *entries = is_lite(core) ? ARRAY_SIZE(caps_lite) : ARRAY_SIZE(caps); + + return is_lite(core) ? caps_lite : caps; } -static void get_codecs(u32 *enc_codecs, u32 *dec_codecs, u32 *count) +static void get_codecs(struct venus_core *core, + u32 *enc_codecs, u32 *dec_codecs, u32 *count) { - *enc_codecs = HFI_VIDEO_CODEC_H264 | HFI_VIDEO_CODEC_HEVC | - HFI_VIDEO_CODEC_VP8; - *dec_codecs = HFI_VIDEO_CODEC_H264 | HFI_VIDEO_CODEC_HEVC | - HFI_VIDEO_CODEC_VP8 | HFI_VIDEO_CODEC_VP9 | - HFI_VIDEO_CODEC_MPEG2; - *count = 8; + const struct hfi_plat_caps *caps; + unsigned int num; + size_t i; + + *enc_codecs = 0; + *dec_codecs = 0; + + caps = get_capabilities(core, &num); + + for (i = 0; i < num; caps++, i++) { + if (caps->domain == VIDC_SESSION_TYPE_ENC) + *enc_codecs |= caps->codec; + else + *dec_codecs |= caps->codec; + } + + *count = num; } static const struct hfi_platform_codec_freq_data codec_freq_data[] = { @@ -272,13 +403,29 @@ static const struct hfi_platform_codec_freq_data codec_freq_data[] = { { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10, 200 }, }; +static const struct hfi_platform_codec_freq_data codec_freq_data_lite[] = { + { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 440, 0, 440 }, + { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 440, 0, 440 }, + { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 440, 0, 440 }, + { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 0, 675 }, + { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 0, 675 }, +}; + static const struct hfi_platform_codec_freq_data * -get_codec_freq_data(u32 session_type, u32 pixfmt) +get_codec_freq_data(struct venus_core *core, u32 session_type, u32 pixfmt) { - const struct hfi_platform_codec_freq_data *data = codec_freq_data; - unsigned int i, data_size = ARRAY_SIZE(codec_freq_data); + const struct hfi_platform_codec_freq_data *data; + unsigned int i, data_size; const struct hfi_platform_codec_freq_data *found = NULL; + if (is_lite(core)) { + data = codec_freq_data_lite; + data_size = ARRAY_SIZE(codec_freq_data_lite); + } else { + data = codec_freq_data; + data_size = ARRAY_SIZE(codec_freq_data); + } + for (i = 0; i < data_size; i++) { if (data[i].pixfmt == pixfmt && data[i].session_type == session_type) { found = &data[i]; @@ -289,33 +436,36 @@ get_codec_freq_data(u32 session_type, u32 pixfmt) return found; } -static unsigned long codec_vpp_freq(u32 session_type, u32 codec) +static unsigned long codec_vpp_freq(struct venus_core *core, + u32 session_type, u32 codec) { const struct hfi_platform_codec_freq_data *data; - data = get_codec_freq_data(session_type, codec); + data = get_codec_freq_data(core, session_type, codec); if (data) return data->vpp_freq; return 0; } -static unsigned long codec_vsp_freq(u32 session_type, u32 codec) +static unsigned long codec_vsp_freq(struct venus_core *core, + u32 session_type, u32 codec) { const struct hfi_platform_codec_freq_data *data; - data = get_codec_freq_data(session_type, codec); + data = get_codec_freq_data(core, session_type, codec); if (data) return data->vsp_freq; return 0; } -static unsigned long codec_lp_freq(u32 session_type, u32 codec) +static unsigned long codec_lp_freq(struct venus_core *core, + u32 session_type, u32 codec) { const struct hfi_platform_codec_freq_data *data; - data = get_codec_freq_data(session_type, codec); + data = get_codec_freq_data(core, session_type, codec); if (data) return data->low_power_freq; diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v6.c b/drivers/media/platform/qcom/venus/hfi_platform_v6.c index 4e8af645f8b9..d8568c08cc36 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform_v6.c +++ b/drivers/media/platform/qcom/venus/hfi_platform_v6.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ +#include "core.h" #include "hfi_platform.h" static const struct hfi_plat_caps caps[] = { @@ -245,14 +246,22 @@ static const struct hfi_plat_caps caps[] = { .num_fmts = 4, } }; -static const struct hfi_plat_caps *get_capabilities(unsigned int *entries) +static const struct hfi_plat_caps *get_capabilities(struct venus_core *core, + unsigned int *entries) { + if (is_lite(core)) + return NULL; + *entries = ARRAY_SIZE(caps); return caps; } -static void get_codecs(u32 *enc_codecs, u32 *dec_codecs, u32 *count) +static void get_codecs(struct venus_core *core, u32 *enc_codecs, + u32 *dec_codecs, u32 *count) { + if (is_lite(core)) + return; + *enc_codecs = HFI_VIDEO_CODEC_H264 | HFI_VIDEO_CODEC_HEVC | HFI_VIDEO_CODEC_VP8; *dec_codecs = HFI_VIDEO_CODEC_H264 | HFI_VIDEO_CODEC_HEVC | @@ -273,12 +282,15 @@ static const struct hfi_platform_codec_freq_data codec_freq_data[] = { }; static const struct hfi_platform_codec_freq_data * -get_codec_freq_data(u32 session_type, u32 pixfmt) +get_codec_freq_data(struct venus_core *core, u32 session_type, u32 pixfmt) { const struct hfi_platform_codec_freq_data *data = codec_freq_data; unsigned int i, data_size = ARRAY_SIZE(codec_freq_data); const struct hfi_platform_codec_freq_data *found = NULL; + if (is_lite(core)) + return NULL; + for (i = 0; i < data_size; i++) { if (data[i].pixfmt == pixfmt && data[i].session_type == session_type) { found = &data[i]; @@ -289,33 +301,36 @@ get_codec_freq_data(u32 session_type, u32 pixfmt) return found; } -static unsigned long codec_vpp_freq(u32 session_type, u32 codec) +static unsigned long codec_vpp_freq(struct venus_core *core, u32 session_type, + u32 codec) { const struct hfi_platform_codec_freq_data *data; - data = get_codec_freq_data(session_type, codec); + data = get_codec_freq_data(core, session_type, codec); if (data) return data->vpp_freq; return 0; } -static unsigned long codec_vsp_freq(u32 session_type, u32 codec) +static unsigned long codec_vsp_freq(struct venus_core *core, u32 session_type, + u32 codec) { const struct hfi_platform_codec_freq_data *data; - data = get_codec_freq_data(session_type, codec); + data = get_codec_freq_data(core, session_type, codec); if (data) return data->vsp_freq; return 0; } -static unsigned long codec_lp_freq(u32 session_type, u32 codec) +static unsigned long codec_lp_freq(struct venus_core *core, u32 session_type, + u32 codec) { const struct hfi_platform_codec_freq_data *data; - data = get_codec_freq_data(session_type, codec); + data = get_codec_freq_data(core, session_type, codec); if (data) return data->low_power_freq; diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index cec7f5964d3d..d3da35f67fd5 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -380,7 +380,7 @@ static void venus_soft_int(struct venus_hfi_device *hdev) void __iomem *cpu_ic_base = hdev->core->cpu_ic_base; u32 clear_bit; - if (IS_V6(hdev->core)) + if (IS_V6(hdev->core) || (IS_V4(hdev->core) && is_lite(hdev->core))) clear_bit = BIT(CPU_IC_SOFTINT_H2A_SHIFT_V6); else clear_bit = BIT(CPU_IC_SOFTINT_H2A_SHIFT); @@ -501,9 +501,11 @@ static int venus_boot_core(struct venus_hfi_device *hdev) if (count >= max_tries) ret = -ETIMEDOUT; - if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core)) { + if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core) || IS_AR50_LITE(hdev->core)) { writel(0x1, cpu_cs_base + CPU_CS_H2XSOFTINTEN_V6); - writel(0x0, cpu_cs_base + CPU_CS_X2RPMH_V6); + + if (!IS_AR50_LITE(hdev->core)) + writel(0x0, cpu_cs_base + CPU_CS_X2RPMH_V6); } return ret; @@ -569,6 +571,9 @@ static int venus_halt_axi(struct venus_hfi_device *hdev) u32 mask_val; int ret; + if (IS_AR50_LITE(hdev->core)) + return 0; + if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core)) { writel(0x3, cpu_cs_base + CPU_CS_X2RPMH_V6); @@ -1138,7 +1143,13 @@ static irqreturn_t venus_isr(struct venus_core *core) wrapper_base = hdev->core->wrapper_base; status = readl(wrapper_base + WRAPPER_INTR_STATUS); - if (IS_IRIS2(core) || IS_IRIS2_1(core)) { + + if (IS_AR50_LITE(core)) { + if (status & WRAPPER_INTR_STATUS_A2H_MASK || + status & WRAPPER_INTR_STATUS_A2HWD_MASK_V4_LITE || + status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK) + hdev->irq_status = status; + } else if (IS_IRIS2(core) || IS_IRIS2_1(core)) { if (status & WRAPPER_INTR_STATUS_A2H_MASK || status & WRAPPER_INTR_STATUS_A2HWD_MASK_V6 || status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK) @@ -1150,7 +1161,7 @@ static irqreturn_t venus_isr(struct venus_core *core) hdev->irq_status = status; } writel(1, cpu_cs_base + CPU_CS_A2HSOFTINTCLR); - if (!(IS_IRIS2(core) || IS_IRIS2_1(core))) + if (!(IS_IRIS2(core) || IS_IRIS2_1(core) || IS_AR50_LITE(core))) writel(status, wrapper_base + WRAPPER_INTR_CLEAR); return IRQ_WAKE_THREAD; @@ -1535,7 +1546,7 @@ static bool venus_cpu_and_video_core_idle(struct venus_hfi_device *hdev) void __iomem *cpu_cs_base = hdev->core->cpu_cs_base; u32 ctrl_status, cpu_status; - if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core)) + if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core) || IS_AR50_LITE(hdev->core)) cpu_status = readl(wrapper_tz_base + WRAPPER_TZ_CPU_STATUS_V6); else cpu_status = readl(wrapper_base + WRAPPER_CPU_STATUS); @@ -1555,7 +1566,7 @@ static bool venus_cpu_idle_and_pc_ready(struct venus_hfi_device *hdev) void __iomem *cpu_cs_base = hdev->core->cpu_cs_base; u32 ctrl_status, cpu_status; - if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core)) + if (IS_IRIS2(hdev->core) || IS_IRIS2_1(hdev->core) || IS_AR50_LITE(hdev->core)) cpu_status = readl(wrapper_tz_base + WRAPPER_TZ_CPU_STATUS_V6); else cpu_status = readl(wrapper_base + WRAPPER_CPU_STATUS); diff --git a/drivers/media/platform/qcom/venus/hfi_venus_io.h b/drivers/media/platform/qcom/venus/hfi_venus_io.h index 9735a246ce36..f2c3064c44ae 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus_io.h +++ b/drivers/media/platform/qcom/venus/hfi_venus_io.h @@ -51,6 +51,9 @@ /* Venus cpu */ #define CPU_CS_SCIACMDARG3 0x58 +#define CPU_CS_VCICMD 0x20 +#define CPU_CS_VCICMD_ARP_OFF BIT(0) + #define SFR_ADDR 0x5c #define MMAP_ADDR 0x60 #define UC_REGION_ADDR 0x64 @@ -100,6 +103,7 @@ #define WRAPPER_INTR_MASK_A2HCPU_MASK 0x4 #define WRAPPER_INTR_MASK_A2HCPU_SHIFT 0x2 +#define WRAPPER_INTR_STATUS_A2HWD_MASK_V4_LITE 0x10 #define WRAPPER_INTR_STATUS_A2HWD_MASK_V6 0x8 #define WRAPPER_INTR_MASK_A2HWD_BASK_V6 0x8 diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index e32f8862a9f9..f0269524ac70 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -40,6 +40,8 @@ static int core_clks_get(struct venus_core *core) static int core_clks_enable(struct venus_core *core) { + const struct freq_tbl *freq_tbl = core->res->freq_tbl; + unsigned int freq_tbl_size = core->res->freq_tbl_size; const struct venus_resources *res = core->res; struct device *dev = core->dev; unsigned long freq = 0; @@ -48,11 +50,16 @@ static int core_clks_enable(struct venus_core *core) int ret; opp = dev_pm_opp_find_freq_ceil(dev, &freq); - if (!IS_ERR(opp)) + if (IS_ERR(opp)) { + if (!freq_tbl) + return -ENODEV; + freq = freq_tbl[freq_tbl_size - 1].freq; + } else { dev_pm_opp_put(opp); + } for (i = 0; i < res->clks_num; i++) { - if (IS_V6(core)) { + if (IS_V6(core) || (IS_V4(core) && is_lite(core))) { ret = clk_set_rate(core->clks[i], freq); if (ret) goto err; diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 29b0d6a5303d..4a6641fdffcf 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -329,8 +329,6 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) struct vb2_queue *q; q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); - if (!q) - return -EINVAL; if (vb2_is_busy(q)) return -EBUSY; @@ -1732,9 +1730,8 @@ static int vdec_open(struct file *file) v4l2_fh_init(&inst->fh, core->vdev_dec); inst->fh.ctrl_handler = &inst->ctrl_handler; - v4l2_fh_add(&inst->fh); + v4l2_fh_add(&inst->fh, file); inst->fh.m2m_ctx = inst->m2m_ctx; - file->private_data = &inst->fh; return 0; @@ -1755,7 +1752,7 @@ static int vdec_close(struct file *file) vdec_pm_get(inst); cancel_work_sync(&inst->delayed_process_work); - venus_close_common(inst); + venus_close_common(inst, file); ida_destroy(&inst->dpb_ids); vdec_pm_put(inst, false); @@ -1779,12 +1776,9 @@ static int vdec_probe(struct platform_device *pdev) struct venus_core *core; int ret; - if (!dev->parent) - return -EPROBE_DEFER; - core = dev_get_drvdata(dev->parent); if (!core) - return -EPROBE_DEFER; + return -EINVAL; platform_set_drvdata(pdev, core); @@ -1883,6 +1877,5 @@ static struct platform_driver qcom_venus_dec_driver = { }; module_platform_driver(qcom_venus_dec_driver); -MODULE_ALIAS("platform:qcom-venus-decoder"); MODULE_DESCRIPTION("Qualcomm Venus video decoder driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index c0a0ccdded80..b478b982a80d 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -241,8 +241,6 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) struct vb2_queue *q; q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); - if (!q) - return -EINVAL; if (vb2_is_busy(q)) return -EBUSY; @@ -1515,9 +1513,8 @@ static int venc_open(struct file *file) v4l2_fh_init(&inst->fh, core->vdev_enc); inst->fh.ctrl_handler = &inst->ctrl_handler; - v4l2_fh_add(&inst->fh); + v4l2_fh_add(&inst->fh, file); inst->fh.m2m_ctx = inst->m2m_ctx; - file->private_data = &inst->fh; return 0; @@ -1537,7 +1534,7 @@ static int venc_close(struct file *file) struct venus_inst *inst = to_inst(file); venc_pm_get(inst); - venus_close_common(inst); + venus_close_common(inst, file); inst->enc_state = VENUS_ENC_STATE_DEINIT; venc_pm_put(inst, false); @@ -1561,12 +1558,9 @@ static int venc_probe(struct platform_device *pdev) struct venus_core *core; int ret; - if (!dev->parent) - return -EPROBE_DEFER; - core = dev_get_drvdata(dev->parent); if (!core) - return -EPROBE_DEFER; + return -EINVAL; platform_set_drvdata(pdev, core); @@ -1665,6 +1659,5 @@ static struct platform_driver qcom_venus_enc_driver = { }; module_platform_driver(qcom_venus_enc_driver); -MODULE_ALIAS("platform:qcom-venus-encoder"); MODULE_DESCRIPTION("Qualcomm Venus video encoder driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c index b30891718d8d..d60d92d2ffa1 100644 --- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c +++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c @@ -950,7 +950,6 @@ static void pispbe_node_stop_streaming(struct vb2_queue *q) kfree(job); } - pm_runtime_mark_last_busy(pispbe->dev); pm_runtime_put_autosuspend(pispbe->dev); dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n", @@ -1742,7 +1741,6 @@ static int pispbe_probe(struct platform_device *pdev) if (ret) goto disable_devs_err; - pm_runtime_mark_last_busy(pispbe->dev); pm_runtime_put_autosuspend(pispbe->dev); return 0; diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c index 35c2ab1e2cd4..2c5b4d24b4e6 100644 --- a/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c +++ b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c @@ -525,7 +525,7 @@ static const struct v4l2_subdev_internal_ops csi2_internal_ops = { int csi2_init(struct csi2_device *csi2, struct dentry *debugfs) { - unsigned int ret; + int ret; spin_lock_init(&csi2->errors_lock); diff --git a/drivers/media/platform/renesas/Kconfig b/drivers/media/platform/renesas/Kconfig index 27a54fa79083..bd8247c0b8aa 100644 --- a/drivers/media/platform/renesas/Kconfig +++ b/drivers/media/platform/renesas/Kconfig @@ -42,6 +42,7 @@ config VIDEO_SH_VOU source "drivers/media/platform/renesas/rcar-isp/Kconfig" source "drivers/media/platform/renesas/rcar-vin/Kconfig" source "drivers/media/platform/renesas/rzg2l-cru/Kconfig" +source "drivers/media/platform/renesas/rzv2h-ivc/Kconfig" # Mem2mem drivers diff --git a/drivers/media/platform/renesas/Makefile b/drivers/media/platform/renesas/Makefile index 1127259c09d6..b6b4abf01db2 100644 --- a/drivers/media/platform/renesas/Makefile +++ b/drivers/media/platform/renesas/Makefile @@ -6,6 +6,7 @@ obj-y += rcar-isp/ obj-y += rcar-vin/ obj-y += rzg2l-cru/ +obj-y += rzv2h-ivc/ obj-y += vsp1/ obj-$(CONFIG_VIDEO_RCAR_CSI2) += rcar-csi2.o diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index f73729f59671..100105b620e3 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -849,7 +849,7 @@ static int rvin_isp_init(struct rvin_dev *vin) * Suspend / Resume */ -static int __maybe_unused rvin_suspend(struct device *dev) +static int rvin_suspend(struct device *dev) { struct rvin_dev *vin = dev_get_drvdata(dev); @@ -861,7 +861,7 @@ static int __maybe_unused rvin_suspend(struct device *dev) return 0; } -static int __maybe_unused rvin_resume(struct device *dev) +static int rvin_resume(struct device *dev) { struct rvin_dev *vin = dev_get_drvdata(dev); @@ -1276,13 +1276,13 @@ static void rcar_vin_remove(struct platform_device *pdev) rvin_dma_unregister(vin); } -static SIMPLE_DEV_PM_OPS(rvin_pm_ops, rvin_suspend, rvin_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(rvin_pm_ops, rvin_suspend, rvin_resume); static struct platform_driver rcar_vin_driver = { .driver = { .name = "rcar-vin", .suppress_bind_attrs = true, - .pm = &rvin_pm_ops, + .pm = pm_sleep_ptr(&rvin_pm_ops), .of_match_table = rvin_of_id_table, }, .probe = rcar_vin_probe, diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c index 62eddf3a35fc..079dbaf016c2 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c @@ -588,8 +588,6 @@ static int rvin_open(struct file *file) if (ret) goto err_pm; - file->private_data = vin; - ret = v4l2_fh_open(file); if (ret) goto err_unlock; diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c index fc8b6bbef793..0844934f7aa6 100644 --- a/drivers/media/platform/renesas/rcar_drif.c +++ b/drivers/media/platform/renesas/rcar_drif.c @@ -1246,6 +1246,7 @@ static struct device_node *rcar_drif_bond_enabled(struct platform_device *p) if (np && of_device_is_available(np)) return np; + of_node_put(np); return NULL; } @@ -1446,18 +1447,18 @@ static void rcar_drif_remove(struct platform_device *pdev) } /* FIXME: Implement suspend/resume support */ -static int __maybe_unused rcar_drif_suspend(struct device *dev) +static int rcar_drif_suspend(struct device *dev) { return 0; } -static int __maybe_unused rcar_drif_resume(struct device *dev) +static int rcar_drif_resume(struct device *dev) { return 0; } -static SIMPLE_DEV_PM_OPS(rcar_drif_pm_ops, rcar_drif_suspend, - rcar_drif_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(rcar_drif_pm_ops, rcar_drif_suspend, + rcar_drif_resume); static const struct of_device_id rcar_drif_of_table[] = { { .compatible = "renesas,rcar-gen3-drif" }, @@ -1470,8 +1471,8 @@ static struct platform_driver rcar_drif_driver = { .driver = { .name = RCAR_DRIF_DRV_NAME, .of_match_table = rcar_drif_of_table, - .pm = &rcar_drif_pm_ops, - }, + .pm = pm_sleep_ptr(&rcar_drif_pm_ops), + }, .probe = rcar_drif_probe, .remove = rcar_drif_remove, }; diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c index 5d453a7a8988..672869815f63 100644 --- a/drivers/media/platform/renesas/rcar_fdp1.c +++ b/drivers/media/platform/renesas/rcar_fdp1.c @@ -630,9 +630,9 @@ struct fdp1_ctx { struct fdp1_field_buffer *previous; }; -static inline struct fdp1_ctx *fh_to_ctx(struct v4l2_fh *fh) +static inline struct fdp1_ctx *file_to_ctx(struct file *filp) { - return container_of(fh, struct fdp1_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct fdp1_ctx, fh); } static struct fdp1_q_data *get_q_data(struct fdp1_ctx *ctx, @@ -1406,11 +1406,8 @@ static int fdp1_enum_fmt_vid_out(struct file *file, void *priv, static int fdp1_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct fdp1_ctx *ctx = file_to_ctx(file); struct fdp1_q_data *q_data; - struct fdp1_ctx *ctx = fh_to_ctx(priv); - - if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type)) - return -EINVAL; q_data = get_q_data(ctx, f->type); f->fmt.pix_mp = q_data->format; @@ -1584,7 +1581,7 @@ static void fdp1_try_fmt_capture(struct fdp1_ctx *ctx, static int fdp1_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct fdp1_ctx *ctx = fh_to_ctx(priv); + struct fdp1_ctx *ctx = file_to_ctx(file); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) fdp1_try_fmt_output(ctx, NULL, &f->fmt.pix_mp); @@ -1655,7 +1652,7 @@ static void fdp1_set_format(struct fdp1_ctx *ctx, static int fdp1_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct fdp1_ctx *ctx = fh_to_ctx(priv); + struct fdp1_ctx *ctx = file_to_ctx(file); struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; struct vb2_queue *vq = v4l2_m2m_get_vq(m2m_ctx, f->type); @@ -2088,7 +2085,6 @@ static int fdp1_open(struct file *file) } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->fdp1 = fdp1; /* Initialise Queues */ @@ -2137,7 +2133,7 @@ static int fdp1_open(struct file *file) if (ret < 0) goto error_pm; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); dprintk(fdp1, "Created instance: %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); @@ -2158,11 +2154,11 @@ done: static int fdp1_release(struct file *file) { struct fdp1_dev *fdp1 = video_drvdata(file); - struct fdp1_ctx *ctx = fh_to_ctx(file->private_data); + struct fdp1_ctx *ctx = file_to_ctx(file); dprintk(fdp1, "Releasing instance %p\n", ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(&fdp1->dev_mutex); @@ -2303,8 +2299,7 @@ static int fdp1_probe(struct platform_device *pdev) fdp1->fcp = rcar_fcp_get(fcp_node); of_node_put(fcp_node); if (IS_ERR(fdp1->fcp)) { - dev_dbg(&pdev->dev, "FCP not found (%ld)\n", - PTR_ERR(fdp1->fcp)); + dev_dbg(&pdev->dev, "FCP not found (%pe)\n", fdp1->fcp); return PTR_ERR(fdp1->fcp); } } @@ -2409,7 +2404,7 @@ static void fdp1_remove(struct platform_device *pdev) rcar_fcp_put(fdp1->fcp); } -static int __maybe_unused fdp1_pm_runtime_suspend(struct device *dev) +static int fdp1_pm_runtime_suspend(struct device *dev) { struct fdp1_dev *fdp1 = dev_get_drvdata(dev); @@ -2418,7 +2413,7 @@ static int __maybe_unused fdp1_pm_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused fdp1_pm_runtime_resume(struct device *dev) +static int fdp1_pm_runtime_resume(struct device *dev) { struct fdp1_dev *fdp1 = dev_get_drvdata(dev); @@ -2429,9 +2424,7 @@ static int __maybe_unused fdp1_pm_runtime_resume(struct device *dev) } static const struct dev_pm_ops fdp1_pm_ops = { - SET_RUNTIME_PM_OPS(fdp1_pm_runtime_suspend, - fdp1_pm_runtime_resume, - NULL) + RUNTIME_PM_OPS(fdp1_pm_runtime_suspend, fdp1_pm_runtime_resume, NULL) }; static const struct of_device_id fdp1_dt_ids[] = { @@ -2446,7 +2439,7 @@ static struct platform_driver fdp1_pdrv = { .driver = { .name = DRIVER_NAME, .of_match_table = fdp1_dt_ids, - .pm = &fdp1_pm_ops, + .pm = pm_ptr(&fdp1_pm_ops), }, }; diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c index 81038df71bb5..a6d26b446494 100644 --- a/drivers/media/platform/renesas/rcar_jpu.c +++ b/drivers/media/platform/renesas/rcar_jpu.c @@ -480,9 +480,9 @@ static struct jpu_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) return container_of(c->handler, struct jpu_ctx, ctrl_handler); } -static struct jpu_ctx *fh_to_ctx(struct v4l2_fh *fh) +static struct jpu_ctx *file_to_ctx(struct file *filp) { - return container_of(fh, struct jpu_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct jpu_ctx, fh); } static void jpu_set_tbl(struct jpu *jpu, u32 reg, const unsigned int *tbl, @@ -656,7 +656,7 @@ static u8 jpu_parse_hdr(void *buffer, unsigned long size, unsigned int *width, static int jpu_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct jpu_ctx *ctx = fh_to_ctx(priv); + struct jpu_ctx *ctx = file_to_ctx(file); if (ctx->encoder) strscpy(cap->card, DRV_NAME " encoder", sizeof(cap->card)); @@ -714,7 +714,7 @@ static int jpu_enum_fmt(struct v4l2_fmtdesc *f, u32 type) static int jpu_enum_fmt_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct jpu_ctx *ctx = fh_to_ctx(priv); + struct jpu_ctx *ctx = file_to_ctx(file); return jpu_enum_fmt(f, ctx->encoder ? JPU_ENC_CAPTURE : JPU_DEC_CAPTURE); @@ -723,7 +723,7 @@ static int jpu_enum_fmt_cap(struct file *file, void *priv, static int jpu_enum_fmt_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct jpu_ctx *ctx = fh_to_ctx(priv); + struct jpu_ctx *ctx = file_to_ctx(file); return jpu_enum_fmt(f, ctx->encoder ? JPU_ENC_OUTPUT : JPU_DEC_OUTPUT); } @@ -823,10 +823,7 @@ static int __jpu_try_fmt(struct jpu_ctx *ctx, struct jpu_fmt **fmtinfo, static int jpu_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct jpu_ctx *ctx = fh_to_ctx(priv); - - if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type)) - return -EINVAL; + struct jpu_ctx *ctx = file_to_ctx(file); return __jpu_try_fmt(ctx, NULL, &f->fmt.pix_mp, f->type); } @@ -834,15 +831,13 @@ static int jpu_try_fmt(struct file *file, void *priv, struct v4l2_format *f) static int jpu_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct vb2_queue *vq; - struct jpu_ctx *ctx = fh_to_ctx(priv); + struct jpu_ctx *ctx = file_to_ctx(file); struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; struct jpu_fmt *fmtinfo; struct jpu_q_data *q_data; int ret; vq = v4l2_m2m_get_vq(m2m_ctx, f->type); - if (!vq) - return -EINVAL; if (vb2_is_busy(vq)) { v4l2_err(&ctx->jpu->v4l2_dev, "%s queue busy\n", __func__); @@ -863,11 +858,8 @@ static int jpu_s_fmt(struct file *file, void *priv, struct v4l2_format *f) static int jpu_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct jpu_ctx *ctx = file_to_ctx(file); struct jpu_q_data *q_data; - struct jpu_ctx *ctx = fh_to_ctx(priv); - - if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type)) - return -EINVAL; q_data = jpu_get_q_data(ctx, f->type); f->fmt.pix_mp = q_data->format; @@ -897,8 +889,8 @@ static const struct v4l2_ctrl_ops jpu_ctrl_ops = { static int jpu_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct jpu_ctx *ctx = fh_to_ctx(priv); struct jpu_q_data *src_q_data, *dst_q_data, *orig, adj, *ref; + struct jpu_ctx *ctx = file_to_ctx(file); enum v4l2_buf_type adj_type; src_q_data = jpu_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); @@ -1226,8 +1218,7 @@ static int jpu_open(struct file *file) v4l2_fh_init(&ctx->fh, vfd); ctx->fh.ctrl_handler = &ctx->ctrl_handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->jpu = jpu; ctx->encoder = vfd == &jpu->vfd_encoder; @@ -1272,7 +1263,7 @@ jpu_reset_rollback: device_prepare_rollback: mutex_unlock(&jpu->mutex); v4l_prepare_rollback: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); return ret; @@ -1280,12 +1271,12 @@ v4l_prepare_rollback: static int jpu_release(struct file *file) { + struct jpu_ctx *ctx = file_to_ctx(file); struct jpu *jpu = video_drvdata(file); - struct jpu_ctx *ctx = fh_to_ctx(file->private_data); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); @@ -1702,7 +1693,6 @@ static void jpu_remove(struct platform_device *pdev) v4l2_device_unregister(&jpu->v4l2_dev); } -#ifdef CONFIG_PM_SLEEP static int jpu_suspend(struct device *dev) { struct jpu *jpu = dev_get_drvdata(dev); @@ -1726,11 +1716,8 @@ static int jpu_resume(struct device *dev) return 0; } -#endif -static const struct dev_pm_ops jpu_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(jpu_suspend, jpu_resume) -}; +static DEFINE_SIMPLE_DEV_PM_OPS(jpu_pm_ops, jpu_suspend, jpu_resume); static struct platform_driver jpu_driver = { .probe = jpu_probe, @@ -1738,13 +1725,13 @@ static struct platform_driver jpu_driver = { .driver = { .of_match_table = jpu_dt_ids, .name = DRV_NAME, - .pm = &jpu_pm_ops, + .pm = pm_sleep_ptr(&jpu_pm_ops), }, }; module_platform_driver(jpu_driver); MODULE_ALIAS("platform:" DRV_NAME); -MODULE_AUTHOR("Mikhail Ulianov <mikhail.ulyanov@cogentembedded.com>"); +MODULE_AUTHOR("Mikhail Ulianov"); MODULE_DESCRIPTION("Renesas R-Car JPEG processing unit driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c index 8cceafe491b1..deed49d0fb10 100644 --- a/drivers/media/platform/renesas/renesas-ceu.c +++ b/drivers/media/platform/renesas/renesas-ceu.c @@ -1048,7 +1048,7 @@ static int ceu_init_mbus_fmt(struct ceu_device *ceudev) /* * ceu_runtime_resume() - soft-reset the interface and turn sensor power on. */ -static int __maybe_unused ceu_runtime_resume(struct device *dev) +static int ceu_runtime_resume(struct device *dev) { struct ceu_device *ceudev = dev_get_drvdata(dev); struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; @@ -1064,7 +1064,7 @@ static int __maybe_unused ceu_runtime_resume(struct device *dev) * ceu_runtime_suspend() - disable capture and interrupts and soft-reset. * Turn sensor power off. */ -static int __maybe_unused ceu_runtime_suspend(struct device *dev) +static int ceu_runtime_suspend(struct device *dev) { struct ceu_device *ceudev = dev_get_drvdata(dev); struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; @@ -1709,15 +1709,13 @@ static void ceu_remove(struct platform_device *pdev) } static const struct dev_pm_ops ceu_pm_ops = { - SET_RUNTIME_PM_OPS(ceu_runtime_suspend, - ceu_runtime_resume, - NULL) + RUNTIME_PM_OPS(ceu_runtime_suspend, ceu_runtime_resume, NULL) }; static struct platform_driver ceu_driver = { .driver = { .name = DRIVER_NAME, - .pm = &ceu_pm_ops, + .pm = pm_ptr(&ceu_pm_ops), .of_match_table = of_match_ptr(ceu_of_match), }, .probe = ceu_probe, diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c index 806acc8f9728..3c5fbd857371 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c @@ -367,7 +367,6 @@ static const struct rzg2l_cru_info rzg3e_cru_info = { .enable_interrupts = rzg3e_cru_enable_interrupts, .disable_interrupts = rzg3e_cru_disable_interrupts, .fifo_empty = rzg3e_fifo_empty, - .csi_setup = rzg3e_cru_csi2_setup, }; static const u16 rzg2l_cru_regs[] = { @@ -412,7 +411,6 @@ static const struct rzg2l_cru_info rzg2l_cru_info = { .enable_interrupts = rzg2l_cru_enable_interrupts, .disable_interrupts = rzg2l_cru_disable_interrupts, .fifo_empty = rzg2l_fifo_empty, - .csi_setup = rzg2l_cru_csi2_setup, }; static const struct of_device_id rzg2l_cru_of_id_table[] = { diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h index be95b41c37df..3a200db15730 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h @@ -92,9 +92,6 @@ struct rzg2l_cru_info { void (*enable_interrupts)(struct rzg2l_cru_dev *cru); void (*disable_interrupts)(struct rzg2l_cru_dev *cru); bool (*fifo_empty)(struct rzg2l_cru_dev *cru); - void (*csi_setup)(struct rzg2l_cru_dev *cru, - const struct rzg2l_cru_ip_format *ip_fmt, - u8 csi_vc); }; /** @@ -204,11 +201,5 @@ void rzg3e_cru_disable_interrupts(struct rzg2l_cru_dev *cru); bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru); bool rzg3e_fifo_empty(struct rzg2l_cru_dev *cru); -void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, - const struct rzg2l_cru_ip_format *ip_fmt, - u8 csi_vc); -void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru, - const struct rzg2l_cru_ip_format *ip_fmt, - u8 csi_vc); #endif diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c index 1520211e7418..0fbdae280fdc 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c @@ -303,8 +303,8 @@ static int rzg2l_csi2_calc_mbps(struct rzg2l_csi2 *csi2) 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)); + dev_err(csi2->dev, "can't get source pad of %s (%pe)\n", + csi2->remote_source->name, remote_pad); return PTR_ERR(remote_pad); } @@ -722,8 +722,8 @@ static int rzg2l_csi2_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, 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)); + dev_err(csi2->dev, "can't get source pad of %s (%pe)\n", + csi2->remote_source->name, remote_pad); return PTR_ERR(remote_pad); } return v4l2_subdev_call(csi2->remote_source, pad, get_frame_desc, diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c index a8817a7066b2..162e2ace6931 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c @@ -257,30 +257,18 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru) rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr); } -void rzg3e_cru_csi2_setup(struct rzg2l_cru_dev *cru, - const struct rzg2l_cru_ip_format *ip_fmt, - u8 csi_vc) +static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, + const struct rzg2l_cru_ip_format *ip_fmt, + u8 csi_vc) { const struct rzg2l_cru_info *info = cru->info; u32 icnmc = ICnMC_INF(ip_fmt->datatype); - icnmc |= rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK; - - /* Set virtual channel CSI2 */ - icnmc |= ICnMC_VCSEL(csi_vc); - - rzg2l_cru_write(cru, ICnSVCNUM, csi_vc); - rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) | - ICnSVC_SVC2(2) | ICnSVC_SVC3(3)); - rzg2l_cru_write(cru, info->image_conv, icnmc); -} - -void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, - const struct rzg2l_cru_ip_format *ip_fmt, - u8 csi_vc) -{ - const struct rzg2l_cru_info *info = cru->info; - u32 icnmc = ICnMC_INF(ip_fmt->datatype); + if (cru->info->regs[ICnSVC]) { + rzg2l_cru_write(cru, ICnSVCNUM, csi_vc); + rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) | + ICnSVC_SVC2(2) | ICnSVC_SVC3(3)); + } icnmc |= rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK; @@ -299,7 +287,7 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru, const struct rzg2l_cru_ip_format *cru_ip_fmt; cru_ip_fmt = rzg2l_cru_ip_code_to_fmt(ip_sd_fmt->code); - info->csi_setup(cru, cru_ip_fmt, csi_vc); + rzg2l_cru_csi2_setup(cru, cru_ip_fmt, csi_vc); /* Output format */ cru_video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat); @@ -1078,7 +1066,6 @@ static int rzg2l_cru_open(struct file *file) if (ret) return ret; - file->private_data = cru; ret = v4l2_fh_open(file); if (ret) goto err_unlock; diff --git a/drivers/media/platform/renesas/rzv2h-ivc/Kconfig b/drivers/media/platform/renesas/rzv2h-ivc/Kconfig new file mode 100644 index 000000000000..eb6c6ce1caba --- /dev/null +++ b/drivers/media/platform/renesas/rzv2h-ivc/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config VIDEO_RZV2H_IVC + tristate "Renesas RZ/V2H(P) Input Video Control block driver" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV + depends on ARCH_RENESAS || COMPILE_TEST + depends on OF + depends on PM + select VIDEOBUF2_DMA_CONTIG + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + help + Support for the Renesas RZ/V2H(P) Input Video Control Block + (IVC). + + To compile this driver as a module, choose M here: the + module will be called rzv2h-ivc. diff --git a/drivers/media/platform/renesas/rzv2h-ivc/Makefile b/drivers/media/platform/renesas/rzv2h-ivc/Makefile new file mode 100644 index 000000000000..080ee3570f09 --- /dev/null +++ b/drivers/media/platform/renesas/rzv2h-ivc/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + +rzv2h-ivc-y := rzv2h-ivc-dev.o rzv2h-ivc-subdev.o rzv2h-ivc-video.o + +obj-$(CONFIG_VIDEO_RZV2H_IVC) += rzv2h-ivc.o diff --git a/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-dev.c b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-dev.c new file mode 100644 index 000000000000..e9857eb5b51a --- /dev/null +++ b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-dev.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/V2H(P) Input Video Control Block driver + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include "rzv2h-ivc.h" + +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +void rzv2h_ivc_write(struct rzv2h_ivc *ivc, u32 addr, u32 val) +{ + writel(val, ivc->base + addr); +} + +void rzv2h_ivc_update_bits(struct rzv2h_ivc *ivc, unsigned int addr, + u32 mask, u32 val) +{ + u32 orig, new; + + orig = readl(ivc->base + addr); + + new = orig & ~mask; + new |= val & mask; + + if (new != orig) + writel(new, ivc->base + addr); +} + +static int rzv2h_ivc_get_hardware_resources(struct rzv2h_ivc *ivc, + struct platform_device *pdev) +{ + static const char * const resource_names[RZV2H_IVC_NUM_HW_RESOURCES] = { + "reg", + "axi", + "isp", + }; + struct resource *res; + int ret; + + ivc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(ivc->base)) + return dev_err_probe(ivc->dev, PTR_ERR(ivc->base), + "failed to map IO memory\n"); + + for (unsigned int i = 0; i < ARRAY_SIZE(resource_names); i++) + ivc->clks[i].id = resource_names[i]; + + ret = devm_clk_bulk_get(ivc->dev, ARRAY_SIZE(resource_names), ivc->clks); + if (ret) + return dev_err_probe(ivc->dev, ret, "failed to acquire clks\n"); + + for (unsigned int i = 0; i < ARRAY_SIZE(resource_names); i++) + ivc->resets[i].id = resource_names[i]; + + ret = devm_reset_control_bulk_get_optional_shared(ivc->dev, + ARRAY_SIZE(resource_names), + ivc->resets); + if (ret) + return dev_err_probe(ivc->dev, ret, "failed to acquire resets\n"); + + return 0; +} + +static void rzv2h_ivc_global_config(struct rzv2h_ivc *ivc) +{ + /* Currently we only support single-exposure input */ + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_AXIRX_PLNUM, RZV2H_IVC_ONE_EXPOSURE); + + /* + * Datasheet says we should disable the interrupts before changing mode + * to avoid spurious IFP interrupt. + */ + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_FM_INT_EN, 0x0); + + /* + * RZ/V2H(P) documentation says software controlled single context mode + * is not supported, and currently the driver does not support the + * multi-context mode. That being so we just set single context sw-hw + * mode. + */ + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_FM_CONTEXT, + RZV2H_IVC_SINGLE_CONTEXT_SW_HW_CFG); + + /* + * We enable the frame end interrupt so that we know when we should send + * follow-up frames. + */ + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_FM_INT_EN, RZV2H_IVC_VVAL_IFPE); +} + +static irqreturn_t rzv2h_ivc_isr(int irq, void *context) +{ + struct device *dev = context; + struct rzv2h_ivc *ivc = dev_get_drvdata(dev); + + guard(spinlock)(&ivc->spinlock); + + /* IRQ should never be triggered before vvalid_ifp has been reset to 2 */ + if (WARN_ON(!ivc->vvalid_ifp)) + return IRQ_HANDLED; + + /* + * The first interrupt indicates that the buffer transfer has been + * completed. + */ + if (--ivc->vvalid_ifp) { + rzv2h_ivc_buffer_done(ivc); + return IRQ_HANDLED; + } + + /* + * The second interrupt indicates that the post-frame transfer VBLANK + * has completed, we can now schedule a new frame transfer, if any. + */ + queue_work(ivc->buffers.async_wq, &ivc->buffers.work); + + return IRQ_HANDLED; +} + +static int rzv2h_ivc_runtime_resume(struct device *dev) +{ + struct rzv2h_ivc *ivc = dev_get_drvdata(dev); + int ret; + + ret = clk_bulk_prepare_enable(ARRAY_SIZE(ivc->clks), ivc->clks); + if (ret) { + dev_err(ivc->dev, "failed to enable clocks\n"); + return ret; + } + + ret = reset_control_bulk_deassert(ARRAY_SIZE(ivc->resets), ivc->resets); + if (ret) { + dev_err(ivc->dev, "failed to deassert resets\n"); + goto err_disable_clks; + } + + rzv2h_ivc_global_config(ivc); + + ret = request_irq(ivc->irqnum, rzv2h_ivc_isr, 0, dev_driver_string(dev), + dev); + if (ret) { + dev_err(dev, "failed to request irq\n"); + goto err_assert_resets; + } + + return 0; + +err_assert_resets: + reset_control_bulk_assert(ARRAY_SIZE(ivc->resets), ivc->resets); +err_disable_clks: + clk_bulk_disable_unprepare(ARRAY_SIZE(ivc->clks), ivc->clks); + + return ret; +} + +static int rzv2h_ivc_runtime_suspend(struct device *dev) +{ + struct rzv2h_ivc *ivc = dev_get_drvdata(dev); + + reset_control_bulk_assert(ARRAY_SIZE(ivc->resets), ivc->resets); + clk_bulk_disable_unprepare(ARRAY_SIZE(ivc->clks), ivc->clks); + free_irq(ivc->irqnum, dev); + + return 0; +} + +static const struct dev_pm_ops rzv2h_ivc_pm_ops = { + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + RUNTIME_PM_OPS(rzv2h_ivc_runtime_suspend, rzv2h_ivc_runtime_resume, + NULL) +}; + +static int rzv2h_ivc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rzv2h_ivc *ivc; + int ret; + + ivc = devm_kzalloc(dev, sizeof(*ivc), GFP_KERNEL); + if (!ivc) + return -ENOMEM; + + ivc->dev = dev; + platform_set_drvdata(pdev, ivc); + + ret = devm_mutex_init(dev, &ivc->lock); + if (ret) + return ret; + + spin_lock_init(&ivc->spinlock); + + ret = rzv2h_ivc_get_hardware_resources(ivc, pdev); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(dev, 2000); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + + ivc->irqnum = platform_get_irq(pdev, 0); + if (ivc->irqnum < 0) + return ivc->irqnum; + + ret = rzv2h_ivc_initialise_subdevice(ivc); + if (ret) + goto err_disable_pm_runtime; + + return 0; + +err_disable_pm_runtime: + pm_runtime_disable(dev); + + return ret; +} + +static void rzv2h_ivc_remove(struct platform_device *pdev) +{ + struct rzv2h_ivc *ivc = platform_get_drvdata(pdev); + + rzv2h_deinit_video_dev_and_queue(ivc); + rzv2h_ivc_deinit_subdevice(ivc); +} + +static const struct of_device_id rzv2h_ivc_of_match[] = { + { .compatible = "renesas,r9a09g057-ivc", }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rzv2h_ivc_of_match); + +static struct platform_driver rzv2h_ivc_driver = { + .driver = { + .name = "rzv2h-ivc", + .of_match_table = rzv2h_ivc_of_match, + .pm = &rzv2h_ivc_pm_ops, + }, + .probe = rzv2h_ivc_probe, + .remove = rzv2h_ivc_remove, +}; + +module_platform_driver(rzv2h_ivc_driver); + +MODULE_AUTHOR("Daniel Scally <dan.scally@ideasonboard.com>"); +MODULE_DESCRIPTION("Renesas RZ/V2H(P) Input Video Control Block driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-subdev.c b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-subdev.c new file mode 100644 index 000000000000..b1659544eaa0 --- /dev/null +++ b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-subdev.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/V2H(P) Input Video Control Block driver + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include "rzv2h-ivc.h" + +#include <linux/media.h> +#include <linux/media-bus-format.h> +#include <linux/v4l2-mediabus.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-event.h> + +#define RZV2H_IVC_N_INPUTS_PER_OUTPUT 6 + +/* + * We support 8/10/12/14/16/20 bit input in any bayer order, but the output + * format is fixed at 20-bits with the same order as the input. + */ +static const struct { + u32 inputs[RZV2H_IVC_N_INPUTS_PER_OUTPUT]; + u32 output; +} rzv2h_ivc_formats[] = { + { + .inputs = { + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SBGGR14_1X14, + MEDIA_BUS_FMT_SBGGR16_1X16, + MEDIA_BUS_FMT_SBGGR20_1X20, + }, + .output = MEDIA_BUS_FMT_SBGGR20_1X20 + }, + { + .inputs = { + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGBRG14_1X14, + MEDIA_BUS_FMT_SGBRG16_1X16, + MEDIA_BUS_FMT_SGBRG20_1X20, + }, + .output = MEDIA_BUS_FMT_SGBRG20_1X20 + }, + { + .inputs = { + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SGRBG14_1X14, + MEDIA_BUS_FMT_SGRBG16_1X16, + MEDIA_BUS_FMT_SGRBG20_1X20, + }, + .output = MEDIA_BUS_FMT_SGRBG20_1X20 + }, + { + .inputs = { + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_SRGGB14_1X14, + MEDIA_BUS_FMT_SRGGB16_1X16, + MEDIA_BUS_FMT_SRGGB20_1X20, + }, + .output = MEDIA_BUS_FMT_SRGGB20_1X20 + }, +}; + +static u32 rzv2h_ivc_get_mbus_output_from_input(u32 mbus_code) +{ + unsigned int i, j; + + for (i = 0; i < ARRAY_SIZE(rzv2h_ivc_formats); i++) { + for (j = 0; j < RZV2H_IVC_N_INPUTS_PER_OUTPUT; j++) { + if (rzv2h_ivc_formats[i].inputs[j] == mbus_code) + return rzv2h_ivc_formats[i].output; + } + } + + return 0; +} + +static int rzv2h_ivc_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct v4l2_mbus_framefmt *fmt; + unsigned int order_index; + unsigned int index; + + /* + * On the source pad, only the 20-bit format corresponding to the sink + * pad format's bayer order is supported. + */ + if (code->pad == RZV2H_IVC_SUBDEV_SOURCE_PAD) { + if (code->index) + return -EINVAL; + + fmt = v4l2_subdev_state_get_format(state, + RZV2H_IVC_SUBDEV_SINK_PAD); + code->code = rzv2h_ivc_get_mbus_output_from_input(fmt->code); + + return 0; + } + + if (code->index >= ARRAY_SIZE(rzv2h_ivc_formats) * + RZV2H_IVC_N_INPUTS_PER_OUTPUT) + return -EINVAL; + + order_index = code->index / RZV2H_IVC_N_INPUTS_PER_OUTPUT; + index = code->index % RZV2H_IVC_N_INPUTS_PER_OUTPUT; + + code->code = rzv2h_ivc_formats[order_index].inputs[index]; + + return 0; +} + +static int rzv2h_ivc_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct v4l2_mbus_framefmt *fmt; + + if (fse->index > 0) + return -EINVAL; + + if (fse->pad == RZV2H_IVC_SUBDEV_SOURCE_PAD) { + fmt = v4l2_subdev_state_get_format(state, + RZV2H_IVC_SUBDEV_SINK_PAD); + + if (fse->code != rzv2h_ivc_get_mbus_output_from_input(fmt->code)) + return -EINVAL; + + fse->min_width = fmt->width; + fse->max_width = fmt->width; + fse->min_height = fmt->height; + fse->max_height = fmt->height; + + return 0; + } + + if (!rzv2h_ivc_get_mbus_output_from_input(fse->code)) + return -EINVAL; + + fse->min_width = RZV2H_IVC_MIN_WIDTH; + fse->max_width = RZV2H_IVC_MAX_WIDTH; + fse->min_height = RZV2H_IVC_MIN_HEIGHT; + fse->max_height = RZV2H_IVC_MAX_HEIGHT; + + return 0; +} + +static int rzv2h_ivc_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; + + if (format->pad == RZV2H_IVC_SUBDEV_SOURCE_PAD) + return v4l2_subdev_get_fmt(sd, state, format); + + sink_fmt = v4l2_subdev_state_get_format(state, + RZV2H_IVC_SUBDEV_SINK_PAD); + + sink_fmt->code = rzv2h_ivc_get_mbus_output_from_input(fmt->code) ? + fmt->code : rzv2h_ivc_formats[0].inputs[0]; + + sink_fmt->width = clamp(fmt->width, RZV2H_IVC_MIN_WIDTH, + RZV2H_IVC_MAX_WIDTH); + sink_fmt->height = clamp(fmt->height, RZV2H_IVC_MIN_HEIGHT, + RZV2H_IVC_MAX_HEIGHT); + + *fmt = *sink_fmt; + + src_fmt = v4l2_subdev_state_get_format(state, + RZV2H_IVC_SUBDEV_SOURCE_PAD); + *src_fmt = *sink_fmt; + src_fmt->code = rzv2h_ivc_get_mbus_output_from_input(sink_fmt->code); + + return 0; +} + +static int rzv2h_ivc_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + /* + * We have a single source pad, which has a single stream. V4L2 core has + * already validated those things. The actual power-on and programming + * of registers will be done through the video device's .vidioc_streamon + * so there's nothing to actually do here... + */ + + return 0; +} + +static int rzv2h_ivc_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + return 0; +} + +static const struct v4l2_subdev_pad_ops rzv2h_ivc_pad_ops = { + .enum_mbus_code = rzv2h_ivc_enum_mbus_code, + .enum_frame_size = rzv2h_ivc_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = rzv2h_ivc_set_fmt, + .enable_streams = rzv2h_ivc_enable_streams, + .disable_streams = rzv2h_ivc_disable_streams, +}; + +static const struct v4l2_subdev_core_ops rzv2h_ivc_core_ops = { + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_ops rzv2h_ivc_subdev_ops = { + .core = &rzv2h_ivc_core_ops, + .pad = &rzv2h_ivc_pad_ops, +}; + +static int rzv2h_ivc_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *sink_fmt, *src_fmt; + + sink_fmt = v4l2_subdev_state_get_format(state, + RZV2H_IVC_SUBDEV_SINK_PAD); + sink_fmt->width = RZV2H_IVC_DEFAULT_WIDTH; + sink_fmt->height = RZV2H_IVC_DEFAULT_HEIGHT; + sink_fmt->field = V4L2_FIELD_NONE; + sink_fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16; + sink_fmt->colorspace = V4L2_COLORSPACE_RAW; + sink_fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(sink_fmt->colorspace); + sink_fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(sink_fmt->colorspace); + sink_fmt->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, + sink_fmt->colorspace, + sink_fmt->ycbcr_enc); + + src_fmt = v4l2_subdev_state_get_format(state, + RZV2H_IVC_SUBDEV_SOURCE_PAD); + + *src_fmt = *sink_fmt; + src_fmt->code = MEDIA_BUS_FMT_SRGGB20_1X20; + + return 0; +} + +static int rzv2h_ivc_registered(struct v4l2_subdev *sd) +{ + struct rzv2h_ivc *ivc = container_of(sd, struct rzv2h_ivc, subdev.sd); + + return rzv2h_ivc_init_vdev(ivc, sd->v4l2_dev); +} + +static const struct v4l2_subdev_internal_ops rzv2h_ivc_subdev_internal_ops = { + .init_state = rzv2h_ivc_init_state, + .registered = rzv2h_ivc_registered, +}; + +static int rzv2h_ivc_link_validate(struct media_link *link) +{ + struct video_device *vdev = + media_entity_to_video_device(link->source->entity); + struct rzv2h_ivc *ivc = video_get_drvdata(vdev); + struct v4l2_subdev *sd = + media_entity_to_v4l2_subdev(link->sink->entity); + const struct rzv2h_ivc_format *fmt; + const struct v4l2_pix_format_mplane *pix; + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *mf; + unsigned int i; + int ret = 0; + + state = v4l2_subdev_lock_and_get_active_state(sd); + mf = v4l2_subdev_state_get_format(state, link->sink->index); + + pix = &ivc->format.pix; + fmt = ivc->format.fmt; + + if (mf->width != pix->width || mf->height != pix->height) { + dev_dbg(ivc->dev, + "link '%s':%u -> '%s':%u not valid: %ux%u != %ux%u\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index, + mf->width, mf->height, pix->width, pix->height); + ret = -EPIPE; + } + + for (i = 0; i < ARRAY_SIZE(fmt->mbus_codes); i++) + if (mf->code == fmt->mbus_codes[i]) + break; + + if (i == ARRAY_SIZE(fmt->mbus_codes)) { + dev_dbg(ivc->dev, + "link '%s':%u -> '%s':%u not valid: pixel format %p4cc cannot produce mbus_code 0x%04x\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index, + &pix->pixelformat, mf->code); + ret = -EPIPE; + } + + v4l2_subdev_unlock_state(state); + + return ret; +} + +static const struct media_entity_operations rzv2h_ivc_media_ops = { + .link_validate = rzv2h_ivc_link_validate, +}; + +int rzv2h_ivc_initialise_subdevice(struct rzv2h_ivc *ivc) +{ + struct v4l2_subdev *sd; + int ret; + + /* Initialise subdevice */ + sd = &ivc->subdev.sd; + sd->dev = ivc->dev; + v4l2_subdev_init(sd, &rzv2h_ivc_subdev_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; + sd->internal_ops = &rzv2h_ivc_subdev_internal_ops; + sd->entity.ops = &rzv2h_ivc_media_ops; + + ivc->subdev.pads[RZV2H_IVC_SUBDEV_SINK_PAD].flags = MEDIA_PAD_FL_SINK; + ivc->subdev.pads[RZV2H_IVC_SUBDEV_SOURCE_PAD].flags = MEDIA_PAD_FL_SOURCE; + + snprintf(sd->name, sizeof(sd->name), "rzv2h ivc block"); + + ret = media_entity_pads_init(&sd->entity, RZV2H_IVC_NUM_SUBDEV_PADS, + ivc->subdev.pads); + if (ret) { + dev_err(ivc->dev, "failed to initialise media entity\n"); + return ret; + } + + ret = v4l2_subdev_init_finalize(sd); + if (ret) { + dev_err(ivc->dev, "failed to finalize subdev init\n"); + goto err_cleanup_subdev_entity; + } + + ret = v4l2_async_register_subdev(sd); + if (ret) { + dev_err(ivc->dev, "failed to register subdevice\n"); + goto err_cleanup_subdev; + } + + return 0; + +err_cleanup_subdev: + v4l2_subdev_cleanup(sd); +err_cleanup_subdev_entity: + media_entity_cleanup(&sd->entity); + + return ret; +} + +void rzv2h_ivc_deinit_subdevice(struct rzv2h_ivc *ivc) +{ + struct v4l2_subdev *sd = &ivc->subdev.sd; + + v4l2_subdev_cleanup(sd); + media_entity_remove_links(&sd->entity); + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); +} diff --git a/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-video.c b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-video.c new file mode 100644 index 000000000000..799453250b85 --- /dev/null +++ b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-video.c @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas RZ/V2H(P) Input Video Control Block driver + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include "rzv2h-ivc.h" + +#include <linux/cleanup.h> +#include <linux/iopoll.h> +#include <linux/lockdep.h> +#include <linux/media-bus-format.h> +#include <linux/minmax.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> + +#include <media/mipi-csi2.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-contig.h> + +#define RZV2H_IVC_FIXED_HBLANK 0x20 +#define RZV2H_IVC_MIN_VBLANK(hts) max(0x1b, 15 + (120501 / (hts))) + +struct rzv2h_ivc_buf { + struct vb2_v4l2_buffer vb; + struct list_head queue; + dma_addr_t addr; +}; + +#define to_rzv2h_ivc_buf(vbuf) \ + container_of(vbuf, struct rzv2h_ivc_buf, vb) + +static const struct rzv2h_ivc_format rzv2h_ivc_formats[] = { + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .mbus_codes = { + MEDIA_BUS_FMT_SBGGR8_1X8, + }, + .dtype = MIPI_CSI2_DT_RAW8, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .mbus_codes = { + MEDIA_BUS_FMT_SGBRG8_1X8, + }, + .dtype = MIPI_CSI2_DT_RAW8, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .mbus_codes = { + MEDIA_BUS_FMT_SGRBG8_1X8, + }, + .dtype = MIPI_CSI2_DT_RAW8, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .mbus_codes = { + MEDIA_BUS_FMT_SRGGB8_1X8, + }, + .dtype = MIPI_CSI2_DT_RAW8, + }, + { + .fourcc = V4L2_PIX_FMT_RAW_CRU10, + .mbus_codes = { + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10 + }, + .dtype = MIPI_CSI2_DT_RAW10, + }, + { + .fourcc = V4L2_PIX_FMT_RAW_CRU12, + .mbus_codes = { + MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SRGGB12_1X12 + }, + .dtype = MIPI_CSI2_DT_RAW12, + }, + { + .fourcc = V4L2_PIX_FMT_RAW_CRU14, + .mbus_codes = { + MEDIA_BUS_FMT_SBGGR14_1X14, + MEDIA_BUS_FMT_SGBRG14_1X14, + MEDIA_BUS_FMT_SGRBG14_1X14, + MEDIA_BUS_FMT_SRGGB14_1X14 + }, + .dtype = MIPI_CSI2_DT_RAW14, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .mbus_codes = { + MEDIA_BUS_FMT_SBGGR16_1X16, + }, + .dtype = MIPI_CSI2_DT_RAW16, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG16, + .mbus_codes = { + MEDIA_BUS_FMT_SGBRG16_1X16, + }, + .dtype = MIPI_CSI2_DT_RAW16, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG16, + .mbus_codes = { + MEDIA_BUS_FMT_SGRBG16_1X16, + }, + .dtype = MIPI_CSI2_DT_RAW16, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB16, + .mbus_codes = { + MEDIA_BUS_FMT_SRGGB16_1X16, + }, + .dtype = MIPI_CSI2_DT_RAW16, + }, +}; + +void rzv2h_ivc_buffer_done(struct rzv2h_ivc *ivc) +{ + struct rzv2h_ivc_buf *buf; + + lockdep_assert_in_irq(); + + scoped_guard(spinlock, &ivc->buffers.lock) { + if (!ivc->buffers.curr) + return; + + buf = ivc->buffers.curr; + ivc->buffers.curr = NULL; + } + + buf->vb.sequence = ivc->buffers.sequence++; + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); +} + +static void rzv2h_ivc_transfer_buffer(struct work_struct *work) +{ + struct rzv2h_ivc *ivc = container_of(work, struct rzv2h_ivc, + buffers.work); + struct rzv2h_ivc_buf *buf; + + /* Setup buffers */ + scoped_guard(spinlock_irqsave, &ivc->buffers.lock) { + buf = list_first_entry_or_null(&ivc->buffers.queue, + struct rzv2h_ivc_buf, queue); + } + + if (!buf) + return; + + list_del(&buf->queue); + + ivc->buffers.curr = buf; + buf->addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_AXIRX_SADDL_P0, buf->addr); + + scoped_guard(spinlock_irqsave, &ivc->spinlock) { + ivc->vvalid_ifp = 2; + } + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_FM_FRCON, 0x1); +} + +static int rzv2h_ivc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct rzv2h_ivc *ivc = vb2_get_drv_priv(q); + + if (*num_planes && *num_planes > 1) + return -EINVAL; + + if (sizes[0] && sizes[0] < ivc->format.pix.plane_fmt[0].sizeimage) + return -EINVAL; + + *num_planes = 1; + + if (!sizes[0]) + sizes[0] = ivc->format.pix.plane_fmt[0].sizeimage; + + return 0; +} + +static void rzv2h_ivc_buf_queue(struct vb2_buffer *vb) +{ + struct rzv2h_ivc *ivc = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rzv2h_ivc_buf *buf = to_rzv2h_ivc_buf(vbuf); + + scoped_guard(spinlock_irq, &ivc->buffers.lock) { + list_add_tail(&buf->queue, &ivc->buffers.queue); + } + + scoped_guard(spinlock_irq, &ivc->spinlock) { + if (vb2_is_streaming(vb->vb2_queue) && !ivc->vvalid_ifp) + queue_work(ivc->buffers.async_wq, &ivc->buffers.work); + } +} + +static void rzv2h_ivc_format_configure(struct rzv2h_ivc *ivc) +{ + const struct rzv2h_ivc_format *fmt = ivc->format.fmt; + struct v4l2_pix_format_mplane *pix = &ivc->format.pix; + unsigned int vblank; + unsigned int hts; + + /* Currently only CRU packed pixel formats are supported */ + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_AXIRX_PXFMT, + RZV2H_IVC_INPUT_FMT_CRU_PACKED); + + rzv2h_ivc_update_bits(ivc, RZV2H_IVC_REG_AXIRX_PXFMT, + RZV2H_IVC_PXFMT_DTYPE, fmt->dtype); + + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_AXIRX_HSIZE, pix->width); + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_AXIRX_VSIZE, pix->height); + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_AXIRX_STRD, + pix->plane_fmt[0].bytesperline); + + /* + * The ISP has minimum vertical blanking requirements that must be + * adhered to by the IVC. The minimum is a function of the Iridix blocks + * clocking requirements and the width of the image and horizontal + * blanking, but if we assume the worst case then it boils down to the + * below (plus one to the numerator to ensure the answer is rounded up) + */ + + hts = pix->width + RZV2H_IVC_FIXED_HBLANK; + vblank = RZV2H_IVC_MIN_VBLANK(hts); + + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_AXIRX_BLANK, + RZV2H_IVC_VBLANK(vblank)); +} + +static void rzv2h_ivc_return_buffers(struct rzv2h_ivc *ivc, + enum vb2_buffer_state state) +{ + struct rzv2h_ivc_buf *buf, *tmp; + + guard(spinlock_irqsave)(&ivc->buffers.lock); + + if (ivc->buffers.curr) { + vb2_buffer_done(&ivc->buffers.curr->vb.vb2_buf, state); + ivc->buffers.curr = NULL; + } + + list_for_each_entry_safe(buf, tmp, &ivc->buffers.queue, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vb.vb2_buf, state); + } +} + +static int rzv2h_ivc_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct rzv2h_ivc *ivc = vb2_get_drv_priv(q); + int ret; + + ivc->buffers.sequence = 0; + ivc->vvalid_ifp = 0; + + ret = pm_runtime_resume_and_get(ivc->dev); + if (ret) + goto err_return_buffers; + + ret = video_device_pipeline_alloc_start(&ivc->vdev.dev); + if (ret) { + dev_err(ivc->dev, "failed to start media pipeline\n"); + goto err_pm_runtime_put; + } + + rzv2h_ivc_format_configure(ivc); + + queue_work(ivc->buffers.async_wq, &ivc->buffers.work); + + return 0; + +err_pm_runtime_put: + pm_runtime_put(ivc->dev); +err_return_buffers: + rzv2h_ivc_return_buffers(ivc, VB2_BUF_STATE_QUEUED); + + return ret; +} + +static void rzv2h_ivc_stop_streaming(struct vb2_queue *q) +{ + struct rzv2h_ivc *ivc = vb2_get_drv_priv(q); + u32 val = 0; + + rzv2h_ivc_write(ivc, RZV2H_IVC_REG_FM_STOP, 0x1); + readl_poll_timeout(ivc->base + RZV2H_IVC_REG_FM_STOP, + val, !val, 10 * USEC_PER_MSEC, 250 * USEC_PER_MSEC); + + rzv2h_ivc_return_buffers(ivc, VB2_BUF_STATE_ERROR); + video_device_pipeline_stop(&ivc->vdev.dev); + pm_runtime_put_autosuspend(ivc->dev); +} + +static const struct vb2_ops rzv2h_ivc_vb2_ops = { + .queue_setup = &rzv2h_ivc_queue_setup, + .buf_queue = &rzv2h_ivc_buf_queue, + .start_streaming = &rzv2h_ivc_start_streaming, + .stop_streaming = &rzv2h_ivc_stop_streaming, +}; + +static const struct rzv2h_ivc_format * +rzv2h_ivc_format_from_pixelformat(u32 fourcc) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(rzv2h_ivc_formats); i++) + if (fourcc == rzv2h_ivc_formats[i].fourcc) + return &rzv2h_ivc_formats[i]; + + return &rzv2h_ivc_formats[0]; +} + +static int rzv2h_ivc_enum_fmt_vid_out(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index >= ARRAY_SIZE(rzv2h_ivc_formats)) + return -EINVAL; + + f->pixelformat = rzv2h_ivc_formats[f->index].fourcc; + return 0; +} + +static int rzv2h_ivc_g_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rzv2h_ivc *ivc = video_drvdata(file); + + f->fmt.pix_mp = ivc->format.pix; + + return 0; +} + +static void rzv2h_ivc_try_fmt(struct v4l2_pix_format_mplane *pix, + const struct rzv2h_ivc_format *fmt) +{ + pix->pixelformat = fmt->fourcc; + + pix->width = clamp(pix->width, RZV2H_IVC_MIN_WIDTH, + RZV2H_IVC_MAX_WIDTH); + pix->height = clamp(pix->height, RZV2H_IVC_MIN_HEIGHT, + RZV2H_IVC_MAX_HEIGHT); + + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_RAW; + pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace); + pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, + pix->colorspace, + pix->ycbcr_enc); + + v4l2_fill_pixfmt_mp(pix, pix->pixelformat, pix->width, pix->height); +} + +static void rzv2h_ivc_set_format(struct rzv2h_ivc *ivc, + struct v4l2_pix_format_mplane *pix) +{ + const struct rzv2h_ivc_format *fmt; + + fmt = rzv2h_ivc_format_from_pixelformat(pix->pixelformat); + + rzv2h_ivc_try_fmt(pix, fmt); + ivc->format.pix = *pix; + ivc->format.fmt = fmt; +} + +static int rzv2h_ivc_s_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rzv2h_ivc *ivc = video_drvdata(file); + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + + if (vb2_is_busy(&ivc->vdev.vb2q)) + return -EBUSY; + + rzv2h_ivc_set_format(ivc, pix); + + return 0; +} + +static int rzv2h_ivc_try_fmt_vid_out(struct file *file, void *fh, + struct v4l2_format *f) +{ + const struct rzv2h_ivc_format *fmt; + + fmt = rzv2h_ivc_format_from_pixelformat(f->fmt.pix.pixelformat); + rzv2h_ivc_try_fmt(&f->fmt.pix_mp, fmt); + + return 0; +} + +static int rzv2h_ivc_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, "rzv2h-ivc", sizeof(cap->driver)); + strscpy(cap->card, "Renesas Input Video Control", sizeof(cap->card)); + + return 0; +} + +static const struct v4l2_ioctl_ops rzv2h_ivc_v4l2_ioctl_ops = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_enum_fmt_vid_out = rzv2h_ivc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out_mplane = rzv2h_ivc_g_fmt_vid_out, + .vidioc_s_fmt_vid_out_mplane = rzv2h_ivc_s_fmt_vid_out, + .vidioc_try_fmt_vid_out_mplane = rzv2h_ivc_try_fmt_vid_out, + .vidioc_querycap = rzv2h_ivc_querycap, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_file_operations rzv2h_ivc_v4l2_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +int rzv2h_ivc_init_vdev(struct rzv2h_ivc *ivc, struct v4l2_device *v4l2_dev) +{ + struct v4l2_pix_format_mplane pix = { }; + struct video_device *vdev; + struct vb2_queue *vb2q; + int ret; + + spin_lock_init(&ivc->buffers.lock); + INIT_LIST_HEAD(&ivc->buffers.queue); + INIT_WORK(&ivc->buffers.work, rzv2h_ivc_transfer_buffer); + + ivc->buffers.async_wq = alloc_workqueue("rzv2h-ivc", 0, 0); + if (!ivc->buffers.async_wq) + return -EINVAL; + + /* Initialise vb2 queue */ + vb2q = &ivc->vdev.vb2q; + vb2q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + vb2q->io_modes = VB2_MMAP | VB2_DMABUF; + vb2q->drv_priv = ivc; + vb2q->mem_ops = &vb2_dma_contig_memops; + vb2q->ops = &rzv2h_ivc_vb2_ops; + vb2q->buf_struct_size = sizeof(struct rzv2h_ivc_buf); + vb2q->min_queued_buffers = 0; + vb2q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vb2q->lock = &ivc->lock; + vb2q->dev = ivc->dev; + + ret = vb2_queue_init(vb2q); + if (ret) { + dev_err(ivc->dev, "vb2 queue init failed\n"); + goto err_destroy_workqueue; + } + + /* Initialise Video Device */ + vdev = &ivc->vdev.dev; + strscpy(vdev->name, "rzv2h-ivc", sizeof(vdev->name)); + vdev->release = video_device_release_empty; + vdev->fops = &rzv2h_ivc_v4l2_fops; + vdev->ioctl_ops = &rzv2h_ivc_v4l2_ioctl_ops; + vdev->lock = &ivc->lock; + vdev->v4l2_dev = v4l2_dev; + vdev->queue = vb2q; + vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING; + vdev->vfl_dir = VFL_DIR_TX; + video_set_drvdata(vdev, ivc); + + pix.pixelformat = V4L2_PIX_FMT_SRGGB16; + pix.width = RZV2H_IVC_DEFAULT_WIDTH; + pix.height = RZV2H_IVC_DEFAULT_HEIGHT; + rzv2h_ivc_set_format(ivc, &pix); + + ivc->vdev.pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&ivc->vdev.dev.entity, 1, &ivc->vdev.pad); + if (ret) + goto err_release_vb2q; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(ivc->dev, "failed to register IVC video device\n"); + goto err_cleanup_vdev_entity; + } + + ret = media_create_pad_link(&vdev->entity, 0, &ivc->subdev.sd.entity, + RZV2H_IVC_SUBDEV_SINK_PAD, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(ivc->dev, "failed to create media link\n"); + goto err_unregister_vdev; + } + + return 0; + +err_unregister_vdev: + video_unregister_device(vdev); +err_cleanup_vdev_entity: + media_entity_cleanup(&vdev->entity); +err_release_vb2q: + vb2_queue_release(vb2q); +err_destroy_workqueue: + destroy_workqueue(ivc->buffers.async_wq); + + return ret; +} + +void rzv2h_deinit_video_dev_and_queue(struct rzv2h_ivc *ivc) +{ + struct video_device *vdev = &ivc->vdev.dev; + struct vb2_queue *vb2q = &ivc->vdev.vb2q; + + vb2_video_unregister_device(vdev); + media_entity_cleanup(&vdev->entity); + vb2_queue_release(vb2q); +} diff --git a/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc.h b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc.h new file mode 100644 index 000000000000..3bcaab990b0f --- /dev/null +++ b/drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc.h @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Renesas RZ/V2H(P) Input Video Control Block driver + * + * Copyright (C) 2025 Ideas on Board Oy + */ + +#include <linux/clk.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/reset.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/videodev2.h> +#include <linux/workqueue.h> + +#include <media/media-entity.h> +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-v4l2.h> + +#define RZV2H_IVC_REG_AXIRX_PLNUM 0x0000 +#define RZV2H_IVC_ONE_EXPOSURE 0x00 +#define RZV2H_IVC_TWO_EXPOSURE 0x01 +#define RZV2H_IVC_REG_AXIRX_PXFMT 0x0004 +#define RZV2H_IVC_INPUT_FMT_MIPI (0 << 16) +#define RZV2H_IVC_INPUT_FMT_CRU_PACKED BIT(16) +#define RZV2H_IVC_PXFMT_DTYPE GENMASK(7, 0) +#define RZV2H_IVC_REG_AXIRX_SADDL_P0 0x0010 +#define RZV2H_IVC_REG_AXIRX_SADDH_P0 0x0014 +#define RZV2H_IVC_REG_AXIRX_SADDL_P1 0x0018 +#define RZV2H_IVC_REG_AXIRX_SADDH_P1 0x001c +#define RZV2H_IVC_REG_AXIRX_HSIZE 0x0020 +#define RZV2H_IVC_REG_AXIRX_VSIZE 0x0024 +#define RZV2H_IVC_REG_AXIRX_BLANK 0x0028 +#define RZV2H_IVC_VBLANK(x) ((x) << 16) +#define RZV2H_IVC_REG_AXIRX_STRD 0x0030 +#define RZV2H_IVC_REG_AXIRX_ISSU 0x0040 +#define RZV2H_IVC_REG_AXIRX_ERACT 0x0048 +#define RZV2H_IVC_REG_FM_CONTEXT 0x0100 +#define RZV2H_IVC_SOFTWARE_CFG 0x00 +#define RZV2H_IVC_SINGLE_CONTEXT_SW_HW_CFG BIT(0) +#define RZV2H_IVC_MULTI_CONTEXT_SW_HW_CFG BIT(1) +#define RZV2H_IVC_REG_FM_MCON 0x0104 +#define RZV2H_IVC_REG_FM_FRCON 0x0108 +#define RZV2H_IVC_REG_FM_STOP 0x010c +#define RZV2H_IVC_REG_FM_INT_EN 0x0120 +#define RZV2H_IVC_VVAL_IFPE BIT(0) +#define RZV2H_IVC_REG_FM_INT_STA 0x0124 +#define RZV2H_IVC_REG_AXIRX_FIFOCAP0 0x0208 +#define RZV2H_IVC_REG_CORE_CAPCON 0x020c +#define RZV2H_IVC_REG_CORE_FIFOCAP0 0x0228 +#define RZV2H_IVC_REG_CORE_FIFOCAP1 0x022c + +#define RZV2H_IVC_MIN_WIDTH 640 +#define RZV2H_IVC_MAX_WIDTH 4096 +#define RZV2H_IVC_MIN_HEIGHT 480 +#define RZV2H_IVC_MAX_HEIGHT 4096 +#define RZV2H_IVC_DEFAULT_WIDTH 1920 +#define RZV2H_IVC_DEFAULT_HEIGHT 1080 + +#define RZV2H_IVC_NUM_HW_RESOURCES 3 + +struct device; + +enum rzv2h_ivc_subdev_pads { + RZV2H_IVC_SUBDEV_SINK_PAD, + RZV2H_IVC_SUBDEV_SOURCE_PAD, + RZV2H_IVC_NUM_SUBDEV_PADS +}; + +struct rzv2h_ivc_format { + u32 fourcc; + /* + * The CRU packed pixel formats are bayer-order agnostic, so each could + * support any one of the 4 possible media bus formats. + */ + u32 mbus_codes[4]; + u8 dtype; +}; + +struct rzv2h_ivc { + struct device *dev; + void __iomem *base; + struct clk_bulk_data clks[RZV2H_IVC_NUM_HW_RESOURCES]; + struct reset_control_bulk_data resets[RZV2H_IVC_NUM_HW_RESOURCES]; + int irqnum; + u8 vvalid_ifp; + + struct { + struct video_device dev; + struct vb2_queue vb2q; + struct media_pad pad; + } vdev; + + struct { + struct v4l2_subdev sd; + struct media_pad pads[RZV2H_IVC_NUM_SUBDEV_PADS]; + } subdev; + + struct { + /* Spinlock to guard buffer queue */ + spinlock_t lock; + struct workqueue_struct *async_wq; + struct work_struct work; + struct list_head queue; + struct rzv2h_ivc_buf *curr; + unsigned int sequence; + } buffers; + + struct { + struct v4l2_pix_format_mplane pix; + const struct rzv2h_ivc_format *fmt; + } format; + + /* Mutex to provide to vb2 */ + struct mutex lock; + /* Lock to protect the interrupt counter */ + spinlock_t spinlock; +}; + +int rzv2h_ivc_init_vdev(struct rzv2h_ivc *ivc, struct v4l2_device *v4l2_dev); +void rzv2h_deinit_video_dev_and_queue(struct rzv2h_ivc *ivc); +void rzv2h_ivc_buffer_done(struct rzv2h_ivc *ivc); +int rzv2h_ivc_initialise_subdevice(struct rzv2h_ivc *ivc); +void rzv2h_ivc_deinit_subdevice(struct rzv2h_ivc *ivc); +void rzv2h_ivc_write(struct rzv2h_ivc *ivc, u32 addr, u32 val); +void rzv2h_ivc_update_bits(struct rzv2h_ivc *ivc, unsigned int addr, + u32 mask, u32 val); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c index b8d06e88c475..2de515c497eb 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c @@ -618,7 +618,7 @@ void vsp1_device_put(struct vsp1_device *vsp1) * Power Management */ -static int __maybe_unused vsp1_pm_suspend(struct device *dev) +static int vsp1_pm_suspend(struct device *dev) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); @@ -634,7 +634,7 @@ static int __maybe_unused vsp1_pm_suspend(struct device *dev) return 0; } -static int __maybe_unused vsp1_pm_resume(struct device *dev) +static int vsp1_pm_resume(struct device *dev) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); @@ -650,7 +650,7 @@ static int __maybe_unused vsp1_pm_resume(struct device *dev) return 0; } -static int __maybe_unused vsp1_pm_runtime_suspend(struct device *dev) +static int vsp1_pm_runtime_suspend(struct device *dev) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); @@ -660,7 +660,7 @@ static int __maybe_unused vsp1_pm_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused vsp1_pm_runtime_resume(struct device *dev) +static int vsp1_pm_runtime_resume(struct device *dev) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); int ret; @@ -693,8 +693,8 @@ done: } static const struct dev_pm_ops vsp1_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume) - SET_RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(vsp1_pm_suspend, vsp1_pm_resume) + RUNTIME_PM_OPS(vsp1_pm_runtime_suspend, vsp1_pm_runtime_resume, NULL) }; /* ----------------------------------------------------------------------------- @@ -954,8 +954,7 @@ static int vsp1_probe(struct platform_device *pdev) vsp1->fcp = rcar_fcp_get(fcp_node); of_node_put(fcp_node); if (IS_ERR(vsp1->fcp)) { - dev_dbg(&pdev->dev, "FCP not found (%ld)\n", - PTR_ERR(vsp1->fcp)); + dev_dbg(&pdev->dev, "FCP not found (%pe)\n", vsp1->fcp); return PTR_ERR(vsp1->fcp); } @@ -1042,7 +1041,7 @@ static struct platform_driver vsp1_platform_driver = { .remove = vsp1_remove, .driver = { .name = "vsp1", - .pm = &vsp1_pm_ops, + .pm = pm_ptr(&vsp1_pm_ops), .of_match_table = vsp1_of_match, }, }; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c index c762202877ba..390ea50f1595 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c @@ -392,7 +392,7 @@ static const struct v4l2_subdev_ops histo_ops = { static int histo_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_histogram *histo = vdev_to_histo(vfh->vdev); cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING @@ -409,7 +409,7 @@ static int histo_v4l2_querycap(struct file *file, void *fh, static int histo_v4l2_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_histogram *histo = vdev_to_histo(vfh->vdev); if (f->index > 0 || f->type != histo->queue.type) @@ -423,7 +423,7 @@ static int histo_v4l2_enum_format(struct file *file, void *fh, static int histo_v4l2_get_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_histogram *histo = vdev_to_histo(vfh->vdev); struct v4l2_meta_format *meta = &format->fmt.meta; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index bc66fbdde3cc..75f9a1a85d55 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -896,7 +896,7 @@ static const struct vb2_ops vsp1_video_queue_qops = { static int vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING @@ -912,7 +912,7 @@ vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) static int vsp1_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); const struct vsp1_format_info *info; @@ -933,7 +933,7 @@ static int vsp1_video_enum_format(struct file *file, void *fh, static int vsp1_video_get_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); if (format->type != video->queue.type) @@ -949,7 +949,7 @@ vsp1_video_get_format(struct file *file, void *fh, struct v4l2_format *format) static int vsp1_video_try_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); if (format->type != video->queue.type) @@ -961,7 +961,7 @@ vsp1_video_try_format(struct file *file, void *fh, struct v4l2_format *format) static int vsp1_video_set_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); const struct vsp1_format_info *info; int ret; @@ -991,7 +991,7 @@ done: static int vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct vsp1_video *video = to_vsp1_video(vfh->vdev); struct media_device *mdev = &video->vsp1->media_dev; struct vsp1_pipeline *pipe; @@ -1079,13 +1079,11 @@ static int vsp1_video_open(struct file *file) return -ENOMEM; v4l2_fh_init(vfh, &video->video); - v4l2_fh_add(vfh); - - file->private_data = vfh; + v4l2_fh_add(vfh, file); ret = vsp1_device_get(video->vsp1); if (ret < 0) { - v4l2_fh_del(vfh); + v4l2_fh_del(vfh, file); v4l2_fh_exit(vfh); kfree(vfh); } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_vspx.c b/drivers/media/platform/renesas/vsp1/vsp1_vspx.c index a754b92232bd..1673479be0ff 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_vspx.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_vspx.c @@ -286,6 +286,7 @@ void vsp1_isp_free_buffer(struct device *dev, dma_free_coherent(bus_master, buffer_desc->size, buffer_desc->cpu_addr, buffer_desc->dma_addr); } +EXPORT_SYMBOL_GPL(vsp1_isp_free_buffer); /** * vsp1_isp_start_streaming - Start processing VSPX jobs diff --git a/drivers/media/platform/rockchip/Kconfig b/drivers/media/platform/rockchip/Kconfig index 9bbeec4996aa..ba401d32f01b 100644 --- a/drivers/media/platform/rockchip/Kconfig +++ b/drivers/media/platform/rockchip/Kconfig @@ -3,5 +3,6 @@ comment "Rockchip media platform drivers" source "drivers/media/platform/rockchip/rga/Kconfig" +source "drivers/media/platform/rockchip/rkcif/Kconfig" source "drivers/media/platform/rockchip/rkisp1/Kconfig" source "drivers/media/platform/rockchip/rkvdec/Kconfig" diff --git a/drivers/media/platform/rockchip/Makefile b/drivers/media/platform/rockchip/Makefile index 286dc5c53f7e..0e0b2cbbd4bd 100644 --- a/drivers/media/platform/rockchip/Makefile +++ b/drivers/media/platform/rockchip/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += rga/ +obj-y += rkcif/ obj-y += rkisp1/ obj-y += rkvdec/ diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 3dccab5fa4a1..43f6a8d99381 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -75,7 +75,7 @@ static irqreturn_t rga_isr(int irq, void *prv) WARN_ON(!src); WARN_ON(!dst); - v4l2_m2m_buf_copy_metadata(src, dst, true); + v4l2_m2m_buf_copy_metadata(src, dst); dst->sequence = ctx->csequence++; @@ -395,8 +395,7 @@ static int rga_open(struct file *file) return ret; } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); rga_setup_ctrls(ctx); @@ -411,8 +410,7 @@ static int rga_open(struct file *file) static int rga_release(struct file *file) { - struct rga_ctx *ctx = - container_of(file->private_data, struct rga_ctx, fh); + struct rga_ctx *ctx = file_to_rga_ctx(file); struct rockchip_rga *rga = ctx->rga; mutex_lock(&rga->mutex); @@ -420,7 +418,7 @@ static int rga_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); @@ -448,7 +446,7 @@ vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) return 0; } -static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct rga_fmt *fmt; @@ -461,16 +459,12 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) return 0; } -static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; - struct rga_ctx *ctx = prv; - struct vb2_queue *vq; + struct rga_ctx *ctx = file_to_rga_ctx(file); struct rga_frame *frm; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; frm = rga_get_frame(ctx, f->type); if (IS_ERR(frm)) return PTR_ERR(frm); @@ -483,7 +477,7 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; struct rga_fmt *fmt; @@ -503,10 +497,10 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt = &f->fmt.pix_mp; - struct rga_ctx *ctx = prv; + struct rga_ctx *ctx = file_to_rga_ctx(file); struct rockchip_rga *rga = ctx->rga; struct vb2_queue *vq; struct rga_frame *frm; @@ -516,7 +510,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) /* Adjust all values accordingly to the hardware capabilities * and chosen format. */ - ret = vidioc_try_fmt(file, prv, f); + ret = vidioc_try_fmt(file, priv, f); if (ret) return ret; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); @@ -560,10 +554,10 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_g_selection(struct file *file, void *prv, +static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct rga_ctx *ctx = prv; + struct rga_ctx *ctx = file_to_rga_ctx(file); struct rga_frame *f; bool use_frame = false; @@ -608,10 +602,10 @@ static int vidioc_g_selection(struct file *file, void *prv, return 0; } -static int vidioc_s_selection(struct file *file, void *prv, +static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct rga_ctx *ctx = prv; + struct rga_ctx *ctx = file_to_rga_ctx(file); struct rockchip_rga *rga = ctx->rga; struct rga_frame *f; int ret = 0; diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h index 530e12de73c4..72a28b120fab 100644 --- a/drivers/media/platform/rockchip/rga/rga.h +++ b/drivers/media/platform/rockchip/rga/rga.h @@ -68,6 +68,11 @@ struct rga_ctx { u32 fill_color; }; +static inline struct rga_ctx *file_to_rga_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct rga_ctx, fh); +} + struct rockchip_rga { struct v4l2_device v4l2_dev; struct v4l2_m2m_dev *m2m_dev; diff --git a/drivers/media/platform/rockchip/rkcif/Kconfig b/drivers/media/platform/rockchip/rkcif/Kconfig new file mode 100644 index 000000000000..efd82ac35bd8 --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/Kconfig @@ -0,0 +1,18 @@ +config VIDEO_ROCKCHIP_CIF + tristate "Rockchip Camera Interface (CIF)" + depends on VIDEO_DEV + depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on V4L_PLATFORM_DRIVERS + depends on PM && COMMON_CLK + select MEDIA_CONTROLLER + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + select VIDEO_V4L2_SUBDEV_API + help + This is a driver for Rockchip Camera Interface (CIF). It is featured + in many Rockchips SoCs in different variations, such as the PX30 + Video Input Processor (VIP, one Digital Video Port (DVP)) or the + RK3568 Video Capture (VICAP, one DVP, one MIPI CSI-2 receiver) unit. + + To compile this driver as a module, choose M here: the module + will be called rockchip-cif. diff --git a/drivers/media/platform/rockchip/rkcif/Makefile b/drivers/media/platform/rockchip/rkcif/Makefile new file mode 100644 index 000000000000..dca2bf45159f --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_ROCKCHIP_CIF) += rockchip-cif.o + +rockchip-cif-objs += rkcif-capture-dvp.o +rockchip-cif-objs += rkcif-capture-mipi.o +rockchip-cif-objs += rkcif-dev.o +rockchip-cif-objs += rkcif-interface.o +rockchip-cif-objs += rkcif-stream.o diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-capture-dvp.c b/drivers/media/platform/rockchip/rkcif/rkcif-capture-dvp.c new file mode 100644 index 000000000000..dbaf7636aeeb --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-capture-dvp.c @@ -0,0 +1,865 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2020 Maxime Chevallier <maxime.chevallier@bootlin.com> + * Copyright (C) 2023 Mehdi Djait <mehdi.djait@bootlin.com> + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#include <media/v4l2-common.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mc.h> +#include <media/v4l2-subdev.h> + +#include "rkcif-capture-dvp.h" +#include "rkcif-common.h" +#include "rkcif-interface.h" +#include "rkcif-regs.h" +#include "rkcif-stream.h" + +static const struct rkcif_output_fmt dvp_out_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV16, + .dvp_fmt_val = RKCIF_FORMAT_YUV_OUTPUT_422 | + RKCIF_FORMAT_UV_STORAGE_ORDER_UVUV, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV16M, + .dvp_fmt_val = RKCIF_FORMAT_YUV_OUTPUT_422 | + RKCIF_FORMAT_UV_STORAGE_ORDER_UVUV, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV61, + .dvp_fmt_val = RKCIF_FORMAT_YUV_OUTPUT_422 | + RKCIF_FORMAT_UV_STORAGE_ORDER_VUVU, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV61M, + .dvp_fmt_val = RKCIF_FORMAT_YUV_OUTPUT_422 | + RKCIF_FORMAT_UV_STORAGE_ORDER_VUVU, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .dvp_fmt_val = RKCIF_FORMAT_YUV_OUTPUT_420 | + RKCIF_FORMAT_UV_STORAGE_ORDER_UVUV, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .dvp_fmt_val = RKCIF_FORMAT_YUV_OUTPUT_420 | + RKCIF_FORMAT_UV_STORAGE_ORDER_UVUV, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .dvp_fmt_val = RKCIF_FORMAT_YUV_OUTPUT_420 | + RKCIF_FORMAT_UV_STORAGE_ORDER_VUVU, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .dvp_fmt_val = RKCIF_FORMAT_YUV_OUTPUT_420 | + RKCIF_FORMAT_UV_STORAGE_ORDER_VUVU, + .cplanes = 2, + }, + { + .fourcc = V4L2_PIX_FMT_RGB24, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGR666, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR16, + .cplanes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_Y16, + .cplanes = 1, + }, +}; + +static const struct rkcif_input_fmt px30_dvp_in_fmts[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YUYV, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YUYV, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YVYU, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YVYU, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_UYVY, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_UYVY, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_VYUY, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_VYUY, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_Y8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_Y10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_Y12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + } +}; + +const struct rkcif_dvp_match_data rkcif_px30_vip_dvp_match_data = { + .in_fmts = px30_dvp_in_fmts, + .in_fmts_num = ARRAY_SIZE(px30_dvp_in_fmts), + .out_fmts = dvp_out_fmts, + .out_fmts_num = ARRAY_SIZE(dvp_out_fmts), + .has_scaler = true, + .regs = { + [RKCIF_DVP_CTRL] = 0x00, + [RKCIF_DVP_INTEN] = 0x04, + [RKCIF_DVP_INTSTAT] = 0x08, + [RKCIF_DVP_FOR] = 0x0c, + [RKCIF_DVP_LINE_NUM_ADDR] = 0x10, + [RKCIF_DVP_FRM0_ADDR_Y] = 0x14, + [RKCIF_DVP_FRM0_ADDR_UV] = 0x18, + [RKCIF_DVP_FRM1_ADDR_Y] = 0x1c, + [RKCIF_DVP_FRM1_ADDR_UV] = 0x20, + [RKCIF_DVP_VIR_LINE_WIDTH] = 0x24, + [RKCIF_DVP_SET_SIZE] = 0x28, + [RKCIF_DVP_SCL_CTRL] = 0x48, + [RKCIF_DVP_FRAME_STATUS] = 0x60, + [RKCIF_DVP_LAST_LINE] = 0x68, + [RKCIF_DVP_LAST_PIX] = 0x6c, + }, +}; + +static const struct rkcif_input_fmt rk3568_dvp_in_fmts[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YUYV, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YUYV, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YVYU, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YVYU, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_UYVY, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_UYVY, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_VYUY, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_VYUY, + .fmt_type = RKCIF_FMT_TYPE_YUV, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YUYV | + RKCIF_FORMAT_INPUT_MODE_BT1120 | + RKCIF_FORMAT_BT1120_TRANSMIT_PROGRESS, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YUYV | + RKCIF_FORMAT_INPUT_MODE_BT1120, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YVYU | + RKCIF_FORMAT_INPUT_MODE_BT1120 | + RKCIF_FORMAT_BT1120_TRANSMIT_PROGRESS, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YVYU | + RKCIF_FORMAT_INPUT_MODE_BT1120, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YUYV | + RKCIF_FORMAT_INPUT_MODE_BT1120 | + RKCIF_FORMAT_BT1120_YC_SWAP | + RKCIF_FORMAT_BT1120_TRANSMIT_PROGRESS, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YUYV | + RKCIF_FORMAT_BT1120_YC_SWAP | + RKCIF_FORMAT_INPUT_MODE_BT1120, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YVYU | + RKCIF_FORMAT_INPUT_MODE_BT1120 | + RKCIF_FORMAT_BT1120_YC_SWAP | + RKCIF_FORMAT_BT1120_TRANSMIT_PROGRESS, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + .dvp_fmt_val = RKCIF_FORMAT_YUV_INPUT_422 | + RKCIF_FORMAT_YUV_INPUT_ORDER_YVYU | + RKCIF_FORMAT_BT1120_YC_SWAP | + RKCIF_FORMAT_INPUT_MODE_BT1120, + .field = V4L2_FIELD_INTERLACED, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_Y8_1X8, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_8, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_Y10_1X10, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_10, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, + { + .mbus_code = MEDIA_BUS_FMT_Y12_1X12, + .dvp_fmt_val = RKCIF_FORMAT_INPUT_MODE_RAW | + RKCIF_FORMAT_RAW_DATA_WIDTH_12, + .fmt_type = RKCIF_FMT_TYPE_RAW, + .field = V4L2_FIELD_NONE, + }, +}; + +static void rk3568_dvp_grf_setup(struct rkcif_device *rkcif) +{ + u32 con1 = RK3568_GRF_WRITE_ENABLE(RK3568_GRF_VI_CON1_CIF_DATAPATH | + RK3568_GRF_VI_CON1_CIF_CLK_DELAYNUM); + + if (!rkcif->grf) + return; + + con1 |= rkcif->interfaces[RKCIF_DVP].dvp.dvp_clk_delay & + RK3568_GRF_VI_CON1_CIF_CLK_DELAYNUM; + + if (rkcif->interfaces[RKCIF_DVP].vep.bus.parallel.flags & + V4L2_MBUS_PCLK_SAMPLE_DUALEDGE) + con1 |= RK3568_GRF_VI_CON1_CIF_DATAPATH; + + regmap_write(rkcif->grf, RK3568_GRF_VI_CON1, con1); +} + +const struct rkcif_dvp_match_data rkcif_rk3568_vicap_dvp_match_data = { + .in_fmts = rk3568_dvp_in_fmts, + .in_fmts_num = ARRAY_SIZE(rk3568_dvp_in_fmts), + .out_fmts = dvp_out_fmts, + .out_fmts_num = ARRAY_SIZE(dvp_out_fmts), + .setup = rk3568_dvp_grf_setup, + .has_scaler = false, + .regs = { + [RKCIF_DVP_CTRL] = 0x00, + [RKCIF_DVP_INTEN] = 0x04, + [RKCIF_DVP_INTSTAT] = 0x08, + [RKCIF_DVP_FOR] = 0x0c, + [RKCIF_DVP_LINE_NUM_ADDR] = 0x2c, + [RKCIF_DVP_FRM0_ADDR_Y] = 0x14, + [RKCIF_DVP_FRM0_ADDR_UV] = 0x18, + [RKCIF_DVP_FRM1_ADDR_Y] = 0x1c, + [RKCIF_DVP_FRM1_ADDR_UV] = 0x20, + [RKCIF_DVP_VIR_LINE_WIDTH] = 0x24, + [RKCIF_DVP_SET_SIZE] = 0x28, + [RKCIF_DVP_CROP] = 0x34, + [RKCIF_DVP_FRAME_STATUS] = 0x3c, + [RKCIF_DVP_LAST_LINE] = 0x44, + [RKCIF_DVP_LAST_PIX] = 0x48, + }, +}; + +static inline unsigned int rkcif_dvp_get_addr(struct rkcif_device *rkcif, + unsigned int index) +{ + if (WARN_ON_ONCE(index >= RKCIF_DVP_REGISTER_MAX)) + return RKCIF_REGISTER_NOTSUPPORTED; + + return rkcif->match_data->dvp->regs[index]; +} + +static inline __maybe_unused void rkcif_dvp_write(struct rkcif_device *rkcif, + unsigned int index, u32 val) +{ + unsigned int addr = rkcif_dvp_get_addr(rkcif, index); + + if (addr == RKCIF_REGISTER_NOTSUPPORTED) + return; + + writel(val, rkcif->base_addr + addr); +} + +static inline __maybe_unused u32 rkcif_dvp_read(struct rkcif_device *rkcif, + unsigned int index) +{ + unsigned int addr = rkcif_dvp_get_addr(rkcif, index); + + if (addr == RKCIF_REGISTER_NOTSUPPORTED) + return 0; + + return readl(rkcif->base_addr + addr); +} + +static void rkcif_dvp_queue_buffer(struct rkcif_stream *stream, + unsigned int index) +{ + struct rkcif_device *rkcif = stream->rkcif; + struct rkcif_buffer *buffer = stream->buffers[index]; + u32 frm_addr_y, frm_addr_uv; + + frm_addr_y = index ? RKCIF_DVP_FRM1_ADDR_Y : RKCIF_DVP_FRM0_ADDR_Y; + frm_addr_uv = index ? RKCIF_DVP_FRM1_ADDR_UV : RKCIF_DVP_FRM0_ADDR_UV; + + rkcif_dvp_write(rkcif, frm_addr_y, buffer->buff_addr[RKCIF_PLANE_Y]); + rkcif_dvp_write(rkcif, frm_addr_uv, buffer->buff_addr[RKCIF_PLANE_UV]); +} + +static int rkcif_dvp_start_streaming(struct rkcif_stream *stream) +{ + struct rkcif_device *rkcif = stream->rkcif; + struct rkcif_interface *interface = stream->interface; + struct v4l2_mbus_config_parallel *parallel; + struct v4l2_mbus_framefmt *source_fmt; + struct v4l2_subdev_state *state; + const struct rkcif_input_fmt *active_in_fmt; + const struct rkcif_output_fmt *active_out_fmt; + u32 val = 0; + int ret = -EINVAL; + + state = v4l2_subdev_lock_and_get_active_state(&interface->sd); + source_fmt = v4l2_subdev_state_get_format(state, RKCIF_IF_PAD_SRC, + stream->id); + if (!source_fmt) + goto out; + + active_in_fmt = rkcif_interface_find_input_fmt(interface, false, + source_fmt->code); + active_out_fmt = rkcif_stream_find_output_fmt(stream, false, + stream->pix.pixelformat); + if (!active_in_fmt || !active_out_fmt) + goto out; + + parallel = &interface->vep.bus.parallel; + if (parallel->bus_width == 16 && + (parallel->flags & V4L2_MBUS_PCLK_SAMPLE_DUALEDGE)) + val |= RKCIF_FORMAT_BT1120_CLOCK_DOUBLE_EDGES; + val |= active_in_fmt->dvp_fmt_val; + val |= active_out_fmt->dvp_fmt_val; + rkcif_dvp_write(rkcif, RKCIF_DVP_FOR, val); + + val = stream->pix.width; + if (active_in_fmt->fmt_type == RKCIF_FMT_TYPE_RAW) + val = stream->pix.width * 2; + rkcif_dvp_write(rkcif, RKCIF_DVP_VIR_LINE_WIDTH, val); + + val = RKCIF_XY_COORD(stream->pix.width, stream->pix.height); + rkcif_dvp_write(rkcif, RKCIF_DVP_SET_SIZE, val); + + rkcif_dvp_write(rkcif, RKCIF_DVP_FRAME_STATUS, RKCIF_FRAME_STAT_CLS); + rkcif_dvp_write(rkcif, RKCIF_DVP_INTSTAT, RKCIF_INTSTAT_CLS); + if (rkcif->match_data->dvp->has_scaler) { + val = active_in_fmt->fmt_type == RKCIF_FMT_TYPE_YUV ? + RKCIF_SCL_CTRL_ENABLE_YUV_16BIT_BYPASS : + RKCIF_SCL_CTRL_ENABLE_RAW_16BIT_BYPASS; + rkcif_dvp_write(rkcif, RKCIF_DVP_SCL_CTRL, val); + } + + rkcif_dvp_write(rkcif, RKCIF_DVP_INTEN, + RKCIF_INTEN_FRAME_END_EN | + RKCIF_INTEN_PST_INF_FRAME_END_EN); + + rkcif_dvp_write(rkcif, RKCIF_DVP_CTRL, + RKCIF_CTRL_AXI_BURST_16 | RKCIF_CTRL_MODE_PINGPONG | + RKCIF_CTRL_ENABLE_CAPTURE); + + ret = 0; + +out: + v4l2_subdev_unlock_state(state); + return ret; +} + +static void rkcif_dvp_stop_streaming(struct rkcif_stream *stream) +{ + struct rkcif_device *rkcif = stream->rkcif; + u32 val; + + val = rkcif_dvp_read(rkcif, RKCIF_DVP_CTRL); + rkcif_dvp_write(rkcif, RKCIF_DVP_CTRL, + val & (~RKCIF_CTRL_ENABLE_CAPTURE)); + rkcif_dvp_write(rkcif, RKCIF_DVP_INTEN, 0x0); + rkcif_dvp_write(rkcif, RKCIF_DVP_INTSTAT, 0x3ff); + rkcif_dvp_write(rkcif, RKCIF_DVP_FRAME_STATUS, 0x0); + + stream->stopping = false; +} + +static void rkcif_dvp_reset_stream(struct rkcif_device *rkcif) +{ + u32 ctl = rkcif_dvp_read(rkcif, RKCIF_DVP_CTRL); + + rkcif_dvp_write(rkcif, RKCIF_DVP_CTRL, + ctl & (~RKCIF_CTRL_ENABLE_CAPTURE)); + rkcif_dvp_write(rkcif, RKCIF_DVP_CTRL, ctl | RKCIF_CTRL_ENABLE_CAPTURE); +} + +static void rkcif_dvp_set_crop(struct rkcif_stream *stream, u16 left, u16 top) +{ + struct rkcif_device *rkcif = stream->rkcif; + u32 val; + + val = RKCIF_XY_COORD(left, top); + rkcif_dvp_write(rkcif, RKCIF_DVP_CROP, val); +} + +irqreturn_t rkcif_dvp_isr(int irq, void *ctx) +{ + struct device *dev = ctx; + struct rkcif_device *rkcif = dev_get_drvdata(dev); + struct rkcif_stream *stream; + u32 intstat, lastline, lastpix, cif_frmst; + irqreturn_t ret = IRQ_NONE; + + if (!rkcif->match_data->dvp) + return ret; + + intstat = rkcif_dvp_read(rkcif, RKCIF_DVP_INTSTAT); + cif_frmst = rkcif_dvp_read(rkcif, RKCIF_DVP_FRAME_STATUS); + lastline = RKCIF_FETCH_Y(rkcif_dvp_read(rkcif, RKCIF_DVP_LAST_LINE)); + lastpix = RKCIF_FETCH_Y(rkcif_dvp_read(rkcif, RKCIF_DVP_LAST_PIX)); + + if (intstat & RKCIF_INTSTAT_FRAME_END) { + rkcif_dvp_write(rkcif, RKCIF_DVP_INTSTAT, + RKCIF_INTSTAT_FRAME_END_CLR | + RKCIF_INTSTAT_LINE_END_CLR); + + stream = &rkcif->interfaces[RKCIF_DVP].streams[RKCIF_ID0]; + + if (stream->stopping) { + rkcif_dvp_stop_streaming(stream); + wake_up(&stream->wq_stopped); + ret = IRQ_HANDLED; + goto out; + } + + if (lastline != stream->pix.height) { + v4l2_err(&rkcif->v4l2_dev, + "bad frame, irq:%#x frmst:%#x size:%dx%d\n", + intstat, cif_frmst, lastpix, lastline); + + rkcif_dvp_reset_stream(rkcif); + } + + rkcif_stream_pingpong(stream); + + ret = IRQ_HANDLED; + } +out: + return ret; +} + +int rkcif_dvp_register(struct rkcif_device *rkcif) +{ + struct rkcif_interface *interface; + unsigned int streams_num; + int ret; + + if (!rkcif->match_data->dvp) + return 0; + + interface = &rkcif->interfaces[RKCIF_DVP]; + interface->index = RKCIF_DVP; + interface->type = RKCIF_IF_DVP; + interface->in_fmts = rkcif->match_data->dvp->in_fmts; + interface->in_fmts_num = rkcif->match_data->dvp->in_fmts_num; + interface->set_crop = rkcif_dvp_set_crop; + ret = rkcif_interface_register(rkcif, interface); + if (ret) + return ret; + + if (rkcif->match_data->dvp->setup) + rkcif->match_data->dvp->setup(rkcif); + + streams_num = rkcif->match_data->dvp->has_ids ? 4 : 1; + for (unsigned int i = 0; i < streams_num; i++) { + struct rkcif_stream *stream = &interface->streams[i]; + + stream->id = i; + stream->interface = interface; + stream->out_fmts = rkcif->match_data->dvp->out_fmts; + stream->out_fmts_num = rkcif->match_data->dvp->out_fmts_num; + stream->queue_buffer = rkcif_dvp_queue_buffer; + stream->start_streaming = rkcif_dvp_start_streaming; + stream->stop_streaming = rkcif_dvp_stop_streaming; + + ret = rkcif_stream_register(rkcif, stream); + if (ret) + goto err_streams_unregister; + + interface->streams_num++; + } + + return 0; + +err_streams_unregister: + for (unsigned int i = 0; i < interface->streams_num; i++) + rkcif_stream_unregister(&interface->streams[i]); + + rkcif_interface_unregister(interface); + + return ret; +} + +void rkcif_dvp_unregister(struct rkcif_device *rkcif) +{ + struct rkcif_interface *interface; + + if (!rkcif->match_data->dvp) + return; + + interface = &rkcif->interfaces[RKCIF_DVP]; + + for (unsigned int i = 0; i < interface->streams_num; i++) + rkcif_stream_unregister(&interface->streams[i]); + + rkcif_interface_unregister(interface); +} diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-capture-dvp.h b/drivers/media/platform/rockchip/rkcif/rkcif-capture-dvp.h new file mode 100644 index 000000000000..a4ed37833bd6 --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-capture-dvp.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2023 Mehdi Djait <mehdi.djait@bootlin.com> + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#ifndef _RKCIF_CAPTURE_DVP_H +#define _RKCIF_CAPTURE_DVP_H + +#include "rkcif-common.h" + +extern const struct rkcif_dvp_match_data rkcif_px30_vip_dvp_match_data; +extern const struct rkcif_dvp_match_data rkcif_rk3568_vicap_dvp_match_data; + +int rkcif_dvp_register(struct rkcif_device *rkcif); + +void rkcif_dvp_unregister(struct rkcif_device *rkcif); + +irqreturn_t rkcif_dvp_isr(int irq, void *ctx); + +#endif diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.c b/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.c new file mode 100644 index 000000000000..1b81bcc067ef --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.c @@ -0,0 +1,777 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#include <linux/interrupt.h> + +#include <media/mipi-csi2.h> +#include <media/v4l2-common.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mc.h> +#include <media/v4l2-subdev.h> + +#include "rkcif-capture-mipi.h" +#include "rkcif-common.h" +#include "rkcif-interface.h" +#include "rkcif-regs.h" +#include "rkcif-stream.h" + +#define RK3568_MIPI_CTRL0_HIGH_ALIGN BIT(31) +#define RK3568_MIPI_CTRL0_UV_SWAP_EN BIT(7) +#define RK3568_MIPI_CTRL0_COMPACT_EN BIT(6) +#define RK3568_MIPI_CTRL0_CROP_EN BIT(5) +#define RK3568_MIPI_CTRL0_WRDDR(type) ((type) << 1) + +#define RKCIF_MIPI_CTRL0_DT_ID(id) ((id) << 10) +#define RKCIF_MIPI_CTRL0_VC_ID(id) ((id) << 8) +#define RKCIF_MIPI_CTRL0_CAP_EN BIT(0) + +#define RKCIF_MIPI_INT_FRAME0_END(id) BIT(8 + (id) * 2 + 0) +#define RKCIF_MIPI_INT_FRAME1_END(id) BIT(8 + (id) * 2 + 1) + +static const struct rkcif_output_fmt mipi_out_fmts[] = { + /* YUV formats */ + { + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + .depth = 16, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_YUV422_8B, + .type = RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + .depth = 16, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_YUV422_8B, + .type = RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc = V4L2_PIX_FMT_YVYU, + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + .depth = 16, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_YUV422_8B, + .type = RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc = V4L2_PIX_FMT_VYUY, + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + .depth = 16, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_YUV422_8B, + .type = RKCIF_MIPI_TYPE_RAW8, + }, + }, + /* RGB formats */ + { + .fourcc = V4L2_PIX_FMT_RGB24, + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .depth = 24, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RGB888, + .type = RKCIF_MIPI_TYPE_RGB888, + }, + }, + { + .fourcc = V4L2_PIX_FMT_BGR24, + .mbus_code = MEDIA_BUS_FMT_BGR888_1X24, + .depth = 24, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RGB888, + .type = RKCIF_MIPI_TYPE_RGB888, + }, + }, + /* Bayer formats */ + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .depth = 8, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW8, + .type = RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .depth = 8, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW8, + .type = RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .depth = 8, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW8, + .type = RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .depth = 8, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW8, + .type = RKCIF_MIPI_TYPE_RAW8, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .depth = 10, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW10, + .type = RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10P, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .depth = 10, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW10, + .compact = true, + .type = RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .depth = 10, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW10, + .type = RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10P, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .depth = 10, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW10, + .compact = true, + .type = RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .depth = 10, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW10, + .type = RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10P, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .depth = 10, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW10, + .compact = true, + .type = RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .depth = 10, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW10, + .type = RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10P, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .depth = 10, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW10, + .compact = true, + .type = RKCIF_MIPI_TYPE_RAW10, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .depth = 12, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW12, + .type = RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12P, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .depth = 12, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW12, + .compact = true, + .type = RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .depth = 12, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW12, + .type = RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12P, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .depth = 12, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW12, + .compact = true, + .type = RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .depth = 12, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW12, + .type = RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12P, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .depth = 12, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW12, + .compact = true, + .type = RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .depth = 12, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW12, + .type = RKCIF_MIPI_TYPE_RAW12, + }, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12P, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .depth = 12, + .cplanes = 1, + .mipi = { + .dt = MIPI_CSI2_DT_RAW12, + .compact = true, + .type = RKCIF_MIPI_TYPE_RAW12, + }, + }, +}; + +static const struct rkcif_input_fmt mipi_in_fmts[] = { + /* YUV formats */ + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, + }, + { + .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, + }, + { + .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, + }, + { + .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, + }, + /* RGB formats */ + { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + }, + { + .mbus_code = MEDIA_BUS_FMT_BGR888_1X24, + }, + /* Bayer formats */ + { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + }, + { + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + }, + { + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + }, +}; + +static u32 +rkcif_rk3568_mipi_ctrl0(struct rkcif_stream *stream, + const struct rkcif_output_fmt *active_out_fmt) +{ + u32 ctrl0 = 0; + + ctrl0 |= RKCIF_MIPI_CTRL0_DT_ID(active_out_fmt->mipi.dt); + ctrl0 |= RKCIF_MIPI_CTRL0_CAP_EN; + ctrl0 |= RK3568_MIPI_CTRL0_CROP_EN; + + if (active_out_fmt->mipi.compact) + ctrl0 |= RK3568_MIPI_CTRL0_COMPACT_EN; + + switch (active_out_fmt->mipi.type) { + case RKCIF_MIPI_TYPE_RAW8: + break; + case RKCIF_MIPI_TYPE_RAW10: + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x1); + break; + case RKCIF_MIPI_TYPE_RAW12: + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x2); + break; + case RKCIF_MIPI_TYPE_RGB888: + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x3); + break; + case RKCIF_MIPI_TYPE_YUV422SP: + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x4); + break; + case RKCIF_MIPI_TYPE_YUV420SP: + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x5); + break; + case RKCIF_MIPI_TYPE_YUV400: + ctrl0 |= RK3568_MIPI_CTRL0_WRDDR(0x6); + break; + default: + break; + } + + return ctrl0; +} + +const struct rkcif_mipi_match_data rkcif_rk3568_vicap_mipi_match_data = { + .mipi_num = 1, + .mipi_ctrl0 = rkcif_rk3568_mipi_ctrl0, + .regs = { + [RKCIF_MIPI_CTRL] = 0x20, + [RKCIF_MIPI_INTEN] = 0xa4, + [RKCIF_MIPI_INTSTAT] = 0xa8, + }, + .regs_id = { + [RKCIF_ID0] = { + [RKCIF_MIPI_CTRL0] = 0x00, + [RKCIF_MIPI_CTRL1] = 0x04, + [RKCIF_MIPI_FRAME0_ADDR_Y] = 0x24, + [RKCIF_MIPI_FRAME0_ADDR_UV] = 0x2c, + [RKCIF_MIPI_FRAME0_VLW_Y] = 0x34, + [RKCIF_MIPI_FRAME0_VLW_UV] = 0x3c, + [RKCIF_MIPI_FRAME1_ADDR_Y] = 0x28, + [RKCIF_MIPI_FRAME1_ADDR_UV] = 0x30, + [RKCIF_MIPI_FRAME1_VLW_Y] = 0x38, + [RKCIF_MIPI_FRAME1_VLW_UV] = 0x40, + [RKCIF_MIPI_CROP_START] = 0xbc, + }, + [RKCIF_ID1] = { + [RKCIF_MIPI_CTRL0] = 0x08, + [RKCIF_MIPI_CTRL1] = 0x0c, + [RKCIF_MIPI_FRAME0_ADDR_Y] = 0x44, + [RKCIF_MIPI_FRAME0_ADDR_UV] = 0x4c, + [RKCIF_MIPI_FRAME0_VLW_Y] = 0x54, + [RKCIF_MIPI_FRAME0_VLW_UV] = 0x5c, + [RKCIF_MIPI_FRAME1_ADDR_Y] = 0x48, + [RKCIF_MIPI_FRAME1_ADDR_UV] = 0x50, + [RKCIF_MIPI_FRAME1_VLW_Y] = 0x58, + [RKCIF_MIPI_FRAME1_VLW_UV] = 0x60, + [RKCIF_MIPI_CROP_START] = 0xc0, + }, + [RKCIF_ID2] = { + [RKCIF_MIPI_CTRL0] = 0x10, + [RKCIF_MIPI_CTRL1] = 0x14, + [RKCIF_MIPI_FRAME0_ADDR_Y] = 0x64, + [RKCIF_MIPI_FRAME0_ADDR_UV] = 0x6c, + [RKCIF_MIPI_FRAME0_VLW_Y] = 0x74, + [RKCIF_MIPI_FRAME0_VLW_UV] = 0x7c, + [RKCIF_MIPI_FRAME1_ADDR_Y] = 0x68, + [RKCIF_MIPI_FRAME1_ADDR_UV] = 0x70, + [RKCIF_MIPI_FRAME1_VLW_Y] = 0x78, + [RKCIF_MIPI_FRAME1_VLW_UV] = 0x80, + [RKCIF_MIPI_CROP_START] = 0xc4, + }, + [RKCIF_ID3] = { + [RKCIF_MIPI_CTRL0] = 0x18, + [RKCIF_MIPI_CTRL1] = 0x1c, + [RKCIF_MIPI_FRAME0_ADDR_Y] = 0x84, + [RKCIF_MIPI_FRAME0_ADDR_UV] = 0x8c, + [RKCIF_MIPI_FRAME0_VLW_Y] = 0x94, + [RKCIF_MIPI_FRAME0_VLW_UV] = 0x9c, + [RKCIF_MIPI_FRAME1_ADDR_Y] = 0x88, + [RKCIF_MIPI_FRAME1_ADDR_UV] = 0x90, + [RKCIF_MIPI_FRAME1_VLW_Y] = 0x98, + [RKCIF_MIPI_FRAME1_VLW_UV] = 0xa0, + [RKCIF_MIPI_CROP_START] = 0xc8, + }, + }, + .blocks = { + { + .offset = 0x80, + }, + }, +}; + +static inline unsigned int rkcif_mipi_get_reg(struct rkcif_interface *interface, + unsigned int index) +{ + struct rkcif_device *rkcif = interface->rkcif; + unsigned int block, offset, reg; + + block = interface->index - RKCIF_MIPI_BASE; + + if (WARN_ON_ONCE(block > RKCIF_MIPI_MAX - RKCIF_MIPI_BASE) || + WARN_ON_ONCE(index > RKCIF_MIPI_REGISTER_MAX)) + return RKCIF_REGISTER_NOTSUPPORTED; + + offset = rkcif->match_data->mipi->blocks[block].offset; + reg = rkcif->match_data->mipi->regs[index]; + if (reg == RKCIF_REGISTER_NOTSUPPORTED) + return reg; + + return offset + reg; +} + +static inline unsigned int rkcif_mipi_id_get_reg(struct rkcif_stream *stream, + unsigned int index) +{ + struct rkcif_device *rkcif = stream->rkcif; + unsigned int block, id, offset, reg; + + block = stream->interface->index - RKCIF_MIPI_BASE; + id = stream->id; + + if (WARN_ON_ONCE(block > RKCIF_MIPI_MAX - RKCIF_MIPI_BASE) || + WARN_ON_ONCE(id > RKCIF_ID_MAX) || + WARN_ON_ONCE(index > RKCIF_MIPI_ID_REGISTER_MAX)) + return RKCIF_REGISTER_NOTSUPPORTED; + + offset = rkcif->match_data->mipi->blocks[block].offset; + reg = rkcif->match_data->mipi->regs_id[id][index]; + if (reg == RKCIF_REGISTER_NOTSUPPORTED) + return reg; + + return offset + reg; +} + +static inline __maybe_unused void +rkcif_mipi_write(struct rkcif_interface *interface, unsigned int index, u32 val) +{ + unsigned int addr = rkcif_mipi_get_reg(interface, index); + + if (addr == RKCIF_REGISTER_NOTSUPPORTED) + return; + + writel(val, interface->rkcif->base_addr + addr); +} + +static inline __maybe_unused void +rkcif_mipi_stream_write(struct rkcif_stream *stream, unsigned int index, + u32 val) +{ + unsigned int addr = rkcif_mipi_id_get_reg(stream, index); + + if (addr == RKCIF_REGISTER_NOTSUPPORTED) + return; + + writel(val, stream->rkcif->base_addr + addr); +} + +static inline __maybe_unused u32 +rkcif_mipi_read(struct rkcif_interface *interface, unsigned int index) +{ + unsigned int addr = rkcif_mipi_get_reg(interface, index); + + if (addr == RKCIF_REGISTER_NOTSUPPORTED) + return 0; + + return readl(interface->rkcif->base_addr + addr); +} + +static inline __maybe_unused u32 +rkcif_mipi_stream_read(struct rkcif_stream *stream, unsigned int index) +{ + unsigned int addr = rkcif_mipi_id_get_reg(stream, index); + + if (addr == RKCIF_REGISTER_NOTSUPPORTED) + return 0; + + return readl(stream->rkcif->base_addr + addr); +} + +static void rkcif_mipi_queue_buffer(struct rkcif_stream *stream, + unsigned int index) +{ + struct rkcif_buffer *buffer = stream->buffers[index]; + u32 frm_addr_y, frm_addr_uv; + + frm_addr_y = index ? RKCIF_MIPI_FRAME1_ADDR_Y : + RKCIF_MIPI_FRAME0_ADDR_Y; + frm_addr_uv = index ? RKCIF_MIPI_FRAME1_ADDR_UV : + RKCIF_MIPI_FRAME0_ADDR_UV; + + rkcif_mipi_stream_write(stream, frm_addr_y, + buffer->buff_addr[RKCIF_PLANE_Y]); + rkcif_mipi_stream_write(stream, frm_addr_uv, + buffer->buff_addr[RKCIF_PLANE_UV]); +} + +static int rkcif_mipi_start_streaming(struct rkcif_stream *stream) +{ + struct rkcif_interface *interface = stream->interface; + const struct rkcif_output_fmt *active_out_fmt; + const struct rkcif_mipi_match_data *match_data; + struct v4l2_subdev_state *state; + u32 ctrl0 = 0, ctrl1 = 0, int_temp = 0, int_mask = 0, vlw = 0; + u16 height, width; + int ret = -EINVAL; + + state = v4l2_subdev_lock_and_get_active_state(&interface->sd); + + active_out_fmt = rkcif_stream_find_output_fmt(stream, false, + stream->pix.pixelformat); + if (!active_out_fmt) + goto out; + + height = stream->pix.height; + width = stream->pix.width; + vlw = stream->pix.plane_fmt[0].bytesperline; + + match_data = stream->rkcif->match_data->mipi; + if (match_data->mipi_ctrl0) + ctrl0 = match_data->mipi_ctrl0(stream, active_out_fmt); + + ctrl1 = RKCIF_XY_COORD(width, height); + + int_mask |= RKCIF_MIPI_INT_FRAME0_END(stream->id); + int_mask |= RKCIF_MIPI_INT_FRAME1_END(stream->id); + + int_temp = rkcif_mipi_read(interface, RKCIF_MIPI_INTEN); + int_temp |= int_mask; + rkcif_mipi_write(interface, RKCIF_MIPI_INTEN, int_temp); + + int_temp = rkcif_mipi_read(interface, RKCIF_MIPI_INTSTAT); + int_temp &= ~int_mask; + rkcif_mipi_write(interface, RKCIF_MIPI_INTSTAT, int_temp); + + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME0_VLW_Y, vlw); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME1_VLW_Y, vlw); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME0_VLW_UV, vlw); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_FRAME1_VLW_UV, vlw); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CROP_START, 0x0); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CTRL1, ctrl1); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CTRL0, ctrl0); + + ret = 0; + +out: + v4l2_subdev_unlock_state(state); + return ret; +} + +static void rkcif_mipi_stop_streaming(struct rkcif_stream *stream) +{ + struct rkcif_interface *interface = stream->interface; + struct v4l2_subdev_state *state; + u32 int_temp = 0, int_mask = 0; + + state = v4l2_subdev_lock_and_get_active_state(&interface->sd); + + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CTRL0, 0); + + int_mask |= RKCIF_MIPI_INT_FRAME0_END(stream->id); + int_mask |= RKCIF_MIPI_INT_FRAME1_END(stream->id); + + int_temp = rkcif_mipi_read(interface, RKCIF_MIPI_INTEN); + int_temp &= ~int_mask; + rkcif_mipi_write(interface, RKCIF_MIPI_INTEN, int_temp); + + int_temp = rkcif_mipi_read(interface, RKCIF_MIPI_INTSTAT); + int_temp &= ~int_mask; + rkcif_mipi_write(interface, RKCIF_MIPI_INTSTAT, int_temp); + + stream->stopping = false; + + v4l2_subdev_unlock_state(state); +} + +static void rkcif_mipi_set_crop(struct rkcif_stream *stream, u16 left, u16 top) +{ + u32 val; + + val = RKCIF_XY_COORD(left, top); + rkcif_mipi_stream_write(stream, RKCIF_MIPI_CROP_START, val); +} + +irqreturn_t rkcif_mipi_isr(int irq, void *ctx) +{ + struct device *dev = ctx; + struct rkcif_device *rkcif = dev_get_drvdata(dev); + irqreturn_t ret = IRQ_NONE; + u32 intstat; + + for (unsigned int i = 0; i < rkcif->match_data->mipi->mipi_num; i++) { + enum rkcif_interface_index index = RKCIF_MIPI_BASE + i; + struct rkcif_interface *interface = &rkcif->interfaces[index]; + + intstat = rkcif_mipi_read(interface, RKCIF_MIPI_INTSTAT); + rkcif_mipi_write(interface, RKCIF_MIPI_INTSTAT, intstat); + + for (unsigned int j = 0; j < interface->streams_num; j++) { + struct rkcif_stream *stream = &interface->streams[j]; + + if (intstat & RKCIF_MIPI_INT_FRAME0_END(stream->id) || + intstat & RKCIF_MIPI_INT_FRAME1_END(stream->id)) { + ret = IRQ_HANDLED; + + if (stream->stopping) { + rkcif_mipi_stop_streaming(stream); + wake_up(&stream->wq_stopped); + continue; + } + + rkcif_stream_pingpong(stream); + } + } + } + + return ret; +} + +int rkcif_mipi_register(struct rkcif_device *rkcif) +{ + int ret; + + if (!rkcif->match_data->mipi) + return 0; + + for (unsigned int i = 0; i < rkcif->match_data->mipi->mipi_num; i++) { + enum rkcif_interface_index index = RKCIF_MIPI_BASE + i; + struct rkcif_interface *interface = &rkcif->interfaces[index]; + + interface->index = index; + interface->type = RKCIF_IF_MIPI; + interface->in_fmts = mipi_in_fmts; + interface->in_fmts_num = ARRAY_SIZE(mipi_in_fmts); + interface->set_crop = rkcif_mipi_set_crop; + interface->streams_num = 0; + ret = rkcif_interface_register(rkcif, interface); + if (ret) + continue; + + for (unsigned int j = 0; j < RKCIF_ID_MAX; j++) { + struct rkcif_stream *stream = &interface->streams[j]; + + stream->id = j; + stream->interface = interface; + stream->out_fmts = mipi_out_fmts; + stream->out_fmts_num = ARRAY_SIZE(mipi_out_fmts); + stream->queue_buffer = rkcif_mipi_queue_buffer; + stream->start_streaming = rkcif_mipi_start_streaming; + stream->stop_streaming = rkcif_mipi_stop_streaming; + ret = rkcif_stream_register(rkcif, stream); + if (ret) + goto err; + interface->streams_num++; + } + } + + return 0; + +err: + for (unsigned int i = 0; i < rkcif->match_data->mipi->mipi_num; i++) { + enum rkcif_interface_index index = RKCIF_MIPI_BASE + i; + struct rkcif_interface *interface = &rkcif->interfaces[index]; + + for (unsigned int j = 0; j < interface->streams_num; j++) + rkcif_stream_unregister(&interface->streams[j]); + + rkcif_interface_unregister(interface); + } + return ret; +} + +void rkcif_mipi_unregister(struct rkcif_device *rkcif) +{ + if (!rkcif->match_data->mipi) + return; + + for (unsigned int i = 0; i < rkcif->match_data->mipi->mipi_num; i++) { + enum rkcif_interface_index index = RKCIF_MIPI_BASE + i; + struct rkcif_interface *interface = &rkcif->interfaces[index]; + + for (unsigned int j = 0; j < interface->streams_num; j++) + rkcif_stream_unregister(&interface->streams[j]); + + rkcif_interface_unregister(interface); + } +} diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.h b/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.h new file mode 100644 index 000000000000..7f16eadc474c --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-capture-mipi.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#ifndef _RKCIF_CAPTURE_MIPI_H +#define _RKCIF_CAPTURE_MIPI_H + +#include "rkcif-common.h" + +extern const struct rkcif_mipi_match_data rkcif_rk3568_vicap_mipi_match_data; + +int rkcif_mipi_register(struct rkcif_device *rkcif); + +void rkcif_mipi_unregister(struct rkcif_device *rkcif); + +irqreturn_t rkcif_mipi_isr(int irq, void *ctx); + +#endif diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-common.h b/drivers/media/platform/rockchip/rkcif/rkcif-common.h new file mode 100644 index 000000000000..dd92cfbc879f --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-common.h @@ -0,0 +1,250 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2023 Mehdi Djait <mehdi.djait@bootlin.com> + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#ifndef _RKCIF_COMMON_H +#define _RKCIF_COMMON_H + +#include <linux/clk.h> +#include <linux/mutex.h> +#include <linux/regmap.h> + +#include <media/media-device.h> +#include <media/media-entity.h> +#include <media/v4l2-common.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mc.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-v4l2.h> + +#include "rkcif-regs.h" + +#define RKCIF_DRIVER_NAME "rockchip-cif" +#define RKCIF_CLK_MAX 4 + +enum rkcif_format_type { + RKCIF_FMT_TYPE_INVALID, + RKCIF_FMT_TYPE_YUV, + RKCIF_FMT_TYPE_RAW, +}; + +enum rkcif_id_index { + RKCIF_ID0, + RKCIF_ID1, + RKCIF_ID2, + RKCIF_ID3, + RKCIF_ID_MAX +}; + +enum rkcif_interface_index { + RKCIF_DVP, + RKCIF_MIPI_BASE, + RKCIF_MIPI1 = RKCIF_MIPI_BASE, + RKCIF_MIPI2, + RKCIF_MIPI3, + RKCIF_MIPI4, + RKCIF_MIPI5, + RKCIF_MIPI6, + RKCIF_MIPI_MAX, + RKCIF_IF_MAX = RKCIF_MIPI_MAX +}; + +enum rkcif_interface_pad_index { + RKCIF_IF_PAD_SINK, + RKCIF_IF_PAD_SRC, + RKCIF_IF_PAD_MAX +}; + +enum rkcif_interface_status { + RKCIF_IF_INACTIVE, + RKCIF_IF_ACTIVE, +}; + +enum rkcif_interface_type { + RKCIF_IF_INVALID, + RKCIF_IF_DVP, + RKCIF_IF_MIPI, +}; + +enum rkcif_mipi_format_type { + RKCIF_MIPI_TYPE_INVALID, + RKCIF_MIPI_TYPE_RAW8, + RKCIF_MIPI_TYPE_RAW10, + RKCIF_MIPI_TYPE_RAW12, + RKCIF_MIPI_TYPE_RGB888, + RKCIF_MIPI_TYPE_YUV422SP, + RKCIF_MIPI_TYPE_YUV420SP, + RKCIF_MIPI_TYPE_YUV400, +}; + +struct rkcif_buffer { + struct vb2_v4l2_buffer vb; + struct list_head queue; + dma_addr_t buff_addr[VIDEO_MAX_PLANES]; + bool is_dummy; +}; + +struct rkcif_dummy_buffer { + struct rkcif_buffer buffer; + void *vaddr; + u32 size; +}; + +enum rkcif_plane_index { + RKCIF_PLANE_Y, + RKCIF_PLANE_UV, + RKCIF_PLANE_MAX +}; + +struct rkcif_input_fmt { + u32 mbus_code; + + enum rkcif_format_type fmt_type; + enum v4l2_field field; + + union { + u32 dvp_fmt_val; + }; +}; + +struct rkcif_output_fmt { + u32 fourcc; + u32 mbus_code; + u8 cplanes; + u8 depth; + + union { + u32 dvp_fmt_val; + struct { + u8 dt; + bool compact; + enum rkcif_mipi_format_type type; + } mipi; + }; +}; + +struct rkcif_interface; + +struct rkcif_remote { + struct v4l2_async_connection async_conn; + struct v4l2_subdev *sd; + + struct rkcif_interface *interface; +}; + +struct rkcif_stream { + enum rkcif_id_index id; + struct rkcif_device *rkcif; + struct rkcif_interface *interface; + const struct rkcif_output_fmt *out_fmts; + unsigned int out_fmts_num; + + /* in ping-pong mode, two buffers can be provided to the HW */ + struct rkcif_buffer *buffers[2]; + int frame_idx; + int frame_phase; + + /* in case of no available buffer, HW can write to the dummy buffer */ + struct rkcif_dummy_buffer dummy; + + bool stopping; + wait_queue_head_t wq_stopped; + + /* queue of available buffers plus spinlock that protects it */ + spinlock_t driver_queue_lock; + struct list_head driver_queue; + + /* lock used by the V4L2 core */ + struct mutex vlock; + + struct media_pad pad; + struct media_pipeline pipeline; + struct v4l2_pix_format_mplane pix; + struct vb2_queue buf_queue; + struct video_device vdev; + + void (*queue_buffer)(struct rkcif_stream *stream, unsigned int index); + int (*start_streaming)(struct rkcif_stream *stream); + void (*stop_streaming)(struct rkcif_stream *stream); +}; + +struct rkcif_dvp { + u32 dvp_clk_delay; +}; + +struct rkcif_interface { + enum rkcif_interface_type type; + enum rkcif_interface_status status; + enum rkcif_interface_index index; + struct rkcif_device *rkcif; + struct rkcif_remote *remote; + struct rkcif_stream streams[RKCIF_ID_MAX]; + unsigned int streams_num; + const struct rkcif_input_fmt *in_fmts; + unsigned int in_fmts_num; + + struct media_pad pads[RKCIF_IF_PAD_MAX]; + struct v4l2_fwnode_endpoint vep; + struct v4l2_subdev sd; + + union { + struct rkcif_dvp dvp; + }; + + void (*set_crop)(struct rkcif_stream *stream, u16 left, u16 top); +}; + +struct rkcif_mipi_match_data { + unsigned int mipi_num; + unsigned int regs[RKCIF_MIPI_REGISTER_MAX]; + unsigned int regs_id[RKCIF_ID_MAX][RKCIF_MIPI_ID_REGISTER_MAX]; + u32 (*mipi_ctrl0)(struct rkcif_stream *stream, + const struct rkcif_output_fmt *active_out_fmt); + struct { + unsigned int offset; + } blocks[RKCIF_MIPI_MAX - RKCIF_MIPI_BASE]; +}; + +struct rkcif_dvp_match_data { + const struct rkcif_input_fmt *in_fmts; + unsigned int in_fmts_num; + const struct rkcif_output_fmt *out_fmts; + unsigned int out_fmts_num; + void (*setup)(struct rkcif_device *rkcif); + bool has_scaler; + bool has_ids; + unsigned int regs[RKCIF_DVP_REGISTER_MAX]; +}; + +struct rkcif_match_data { + const char *const *clks; + unsigned int clks_num; + const struct rkcif_dvp_match_data *dvp; + const struct rkcif_mipi_match_data *mipi; +}; + +struct rkcif_device { + struct device *dev; + + const struct rkcif_match_data *match_data; + struct clk_bulk_data clks[RKCIF_CLK_MAX]; + unsigned int clks_num; + struct regmap *grf; + struct reset_control *reset; + void __iomem *base_addr; + + struct rkcif_interface interfaces[RKCIF_IF_MAX]; + + struct media_device media_dev; + struct v4l2_device v4l2_dev; + struct v4l2_async_notifier notifier; +}; + +#endif diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-dev.c b/drivers/media/platform/rockchip/rkcif/rkcif-dev.c new file mode 100644 index 000000000000..b4cf1146f131 --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-dev.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2020 Maxime Chevallier <maxime.chevallier@bootlin.com> + * Copyright (C) 2023 Mehdi Djait <mehdi.djait@bootlin.com> + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_graph.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mc.h> + +#include "rkcif-capture-dvp.h" +#include "rkcif-capture-mipi.h" +#include "rkcif-common.h" + +static const char *const px30_vip_clks[] = { + "aclk", + "hclk", + "pclk", +}; + +static const struct rkcif_match_data px30_vip_match_data = { + .clks = px30_vip_clks, + .clks_num = ARRAY_SIZE(px30_vip_clks), + .dvp = &rkcif_px30_vip_dvp_match_data, +}; + +static const char *const rk3568_vicap_clks[] = { + "aclk", + "hclk", + "dclk", + "iclk", +}; + +static const struct rkcif_match_data rk3568_vicap_match_data = { + .clks = rk3568_vicap_clks, + .clks_num = ARRAY_SIZE(rk3568_vicap_clks), + .dvp = &rkcif_rk3568_vicap_dvp_match_data, + .mipi = &rkcif_rk3568_vicap_mipi_match_data, +}; + +static const struct of_device_id rkcif_plat_of_match[] = { + { + .compatible = "rockchip,px30-vip", + .data = &px30_vip_match_data, + }, + { + .compatible = "rockchip,rk3568-vicap", + .data = &rk3568_vicap_match_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, rkcif_plat_of_match); + +static int rkcif_register(struct rkcif_device *rkcif) +{ + int ret; + + ret = rkcif_dvp_register(rkcif); + if (ret && ret != -ENODEV) + goto err; + + ret = rkcif_mipi_register(rkcif); + if (ret && ret != -ENODEV) + goto err_dvp_unregister; + + return 0; + +err_dvp_unregister: + rkcif_dvp_unregister(rkcif); +err: + return ret; +} + +static void rkcif_unregister(struct rkcif_device *rkcif) +{ + rkcif_mipi_unregister(rkcif); + rkcif_dvp_unregister(rkcif); +} + +static int rkcif_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_connection *asd) +{ + struct rkcif_device *rkcif = + container_of(notifier, struct rkcif_device, notifier); + struct rkcif_remote *remote = + container_of(asd, struct rkcif_remote, async_conn); + struct media_pad *sink_pad = + &remote->interface->pads[RKCIF_IF_PAD_SINK]; + int ret; + + ret = v4l2_create_fwnode_links_to_pad(sd, sink_pad, + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_err(rkcif->dev, "failed to link source pad of %s\n", + sd->name); + return ret; + } + + remote->sd = sd; + + return 0; +} + +static int rkcif_notifier_complete(struct v4l2_async_notifier *notifier) +{ + struct rkcif_device *rkcif = + container_of(notifier, struct rkcif_device, notifier); + + return v4l2_device_register_subdev_nodes(&rkcif->v4l2_dev); +} + +static const struct v4l2_async_notifier_operations rkcif_notifier_ops = { + .bound = rkcif_notifier_bound, + .complete = rkcif_notifier_complete, +}; + +static irqreturn_t rkcif_isr(int irq, void *ctx) +{ + irqreturn_t ret = IRQ_NONE; + + if (rkcif_dvp_isr(irq, ctx) == IRQ_HANDLED) + ret = IRQ_HANDLED; + + if (rkcif_mipi_isr(irq, ctx) == IRQ_HANDLED) + ret = IRQ_HANDLED; + + return ret; +} + +static int rkcif_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rkcif_device *rkcif; + int ret, irq; + + rkcif = devm_kzalloc(dev, sizeof(*rkcif), GFP_KERNEL); + if (!rkcif) + return -ENOMEM; + + rkcif->match_data = of_device_get_match_data(dev); + if (!rkcif->match_data) + return -ENODEV; + + dev_set_drvdata(dev, rkcif); + rkcif->dev = dev; + + rkcif->base_addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(rkcif->base_addr)) + return PTR_ERR(rkcif->base_addr); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, rkcif_isr, IRQF_SHARED, + dev_driver_string(dev), dev); + if (ret) + return dev_err_probe(dev, ret, "failed to request irq\n"); + + if (rkcif->match_data->clks_num > RKCIF_CLK_MAX) + return dev_err_probe(dev, -EINVAL, "invalid number of clocks\n"); + + rkcif->clks_num = rkcif->match_data->clks_num; + for (unsigned int i = 0; i < rkcif->clks_num; i++) + rkcif->clks[i].id = rkcif->match_data->clks[i]; + ret = devm_clk_bulk_get(dev, rkcif->clks_num, rkcif->clks); + if (ret) + return dev_err_probe(dev, ret, "failed to get clocks\n"); + + rkcif->reset = devm_reset_control_array_get_exclusive(dev); + if (IS_ERR(rkcif->reset)) + return PTR_ERR(rkcif->reset); + + rkcif->grf = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,grf"); + if (IS_ERR(rkcif->grf)) + rkcif->grf = NULL; + + pm_runtime_enable(&pdev->dev); + + rkcif->media_dev.dev = dev; + strscpy(rkcif->media_dev.model, RKCIF_DRIVER_NAME, + sizeof(rkcif->media_dev.model)); + media_device_init(&rkcif->media_dev); + + rkcif->v4l2_dev.mdev = &rkcif->media_dev; + ret = v4l2_device_register(dev, &rkcif->v4l2_dev); + if (ret) + goto err_media_dev_cleanup; + + ret = media_device_register(&rkcif->media_dev); + if (ret < 0) { + dev_err(dev, "failed to register media device: %d\n", ret); + goto err_v4l2_dev_unregister; + } + + v4l2_async_nf_init(&rkcif->notifier, &rkcif->v4l2_dev); + rkcif->notifier.ops = &rkcif_notifier_ops; + + ret = rkcif_register(rkcif); + if (ret) { + dev_err(dev, "failed to register media entities: %d\n", ret); + goto err_notifier_cleanup; + } + + ret = v4l2_async_nf_register(&rkcif->notifier); + if (ret) + goto err_rkcif_unregister; + + return 0; + +err_rkcif_unregister: + rkcif_unregister(rkcif); +err_notifier_cleanup: + v4l2_async_nf_cleanup(&rkcif->notifier); + media_device_unregister(&rkcif->media_dev); +err_v4l2_dev_unregister: + v4l2_device_unregister(&rkcif->v4l2_dev); +err_media_dev_cleanup: + media_device_cleanup(&rkcif->media_dev); + pm_runtime_disable(&pdev->dev); + return ret; +} + +static void rkcif_remove(struct platform_device *pdev) +{ + struct rkcif_device *rkcif = platform_get_drvdata(pdev); + + v4l2_async_nf_unregister(&rkcif->notifier); + rkcif_unregister(rkcif); + v4l2_async_nf_cleanup(&rkcif->notifier); + media_device_unregister(&rkcif->media_dev); + v4l2_device_unregister(&rkcif->v4l2_dev); + media_device_cleanup(&rkcif->media_dev); + pm_runtime_disable(&pdev->dev); +} + +static int rkcif_runtime_suspend(struct device *dev) +{ + struct rkcif_device *rkcif = dev_get_drvdata(dev); + + /* + * Reset CIF (CRU, DMA, FIFOs) to allow a clean resume. + * Since this resets the IOMMU too, we cannot issue this reset when + * resuming. + */ + reset_control_assert(rkcif->reset); + udelay(5); + reset_control_deassert(rkcif->reset); + + clk_bulk_disable_unprepare(rkcif->clks_num, rkcif->clks); + + return 0; +} + +static int rkcif_runtime_resume(struct device *dev) +{ + struct rkcif_device *rkcif = dev_get_drvdata(dev); + int ret; + + ret = clk_bulk_prepare_enable(rkcif->clks_num, rkcif->clks); + if (ret) { + dev_err(dev, "failed to enable clocks\n"); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops rkcif_plat_pm_ops = { + .runtime_suspend = rkcif_runtime_suspend, + .runtime_resume = rkcif_runtime_resume, +}; + +static struct platform_driver rkcif_plat_drv = { + .driver = { + .name = RKCIF_DRIVER_NAME, + .of_match_table = rkcif_plat_of_match, + .pm = &rkcif_plat_pm_ops, + }, + .probe = rkcif_probe, + .remove = rkcif_remove, +}; +module_platform_driver(rkcif_plat_drv); + +MODULE_DESCRIPTION("Rockchip Camera Interface (CIF) platform driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-interface.c b/drivers/media/platform/rockchip/rkcif/rkcif-interface.c new file mode 100644 index 000000000000..523103872b7a --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-interface.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#include <media/v4l2-common.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mc.h> +#include <media/v4l2-subdev.h> + +#include "rkcif-common.h" +#include "rkcif-interface.h" + +static inline struct rkcif_interface *to_rkcif_interface(struct v4l2_subdev *sd) +{ + return container_of(sd, struct rkcif_interface, sd); +} + +static const struct media_entity_operations rkcif_interface_media_ops = { + .link_validate = v4l2_subdev_link_validate, + .has_pad_interdep = v4l2_subdev_has_pad_interdep, +}; + +static int rkcif_interface_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct rkcif_interface *interface = to_rkcif_interface(sd); + const struct rkcif_input_fmt *input; + struct v4l2_mbus_framefmt *sink, *src; + struct v4l2_rect *crop; + u32 other_pad, other_stream; + int ret; + + /* the format on the source pad always matches the sink pad */ + if (format->pad == RKCIF_IF_PAD_SRC) + return v4l2_subdev_get_fmt(sd, state, format); + + input = rkcif_interface_find_input_fmt(interface, true, + format->format.code); + format->format.code = input->mbus_code; + + sink = v4l2_subdev_state_get_format(state, format->pad, format->stream); + if (!sink) + return -EINVAL; + + *sink = format->format; + + /* propagate the format to the source pad */ + src = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, + format->stream); + if (!src) + return -EINVAL; + + *src = *sink; + + ret = v4l2_subdev_routing_find_opposite_end(&state->routing, + format->pad, format->stream, + &other_pad, &other_stream); + if (ret) + return -EINVAL; + + crop = v4l2_subdev_state_get_crop(state, other_pad, other_stream); + if (!crop) + return -EINVAL; + + /* reset crop */ + crop->left = 0; + crop->top = 0; + crop->width = sink->width; + crop->height = sink->height; + + return 0; +} + +static int rkcif_interface_get_sel(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *sink; + struct v4l2_rect *crop; + int ret = 0; + + if (sel->pad != RKCIF_IF_PAD_SRC) + return -EINVAL; + + sink = v4l2_subdev_state_get_opposite_stream_format(state, sel->pad, + sel->stream); + if (!sink) + return -EINVAL; + + crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); + if (!crop) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = sink->width; + sel->r.height = sink->height; + break; + case V4L2_SEL_TGT_CROP: + sel->r = *crop; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int rkcif_interface_set_sel(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *sink, *src; + struct v4l2_rect *crop; + + if (sel->pad != RKCIF_IF_PAD_SRC || sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + sink = v4l2_subdev_state_get_opposite_stream_format(state, sel->pad, + sel->stream); + if (!sink) + return -EINVAL; + + src = v4l2_subdev_state_get_format(state, sel->pad, sel->stream); + if (!src) + return -EINVAL; + + crop = v4l2_subdev_state_get_crop(state, sel->pad, sel->stream); + if (!crop) + return -EINVAL; + + *crop = sel->r; + + src->height = sel->r.height; + src->width = sel->r.width; + + return 0; +} + +static int rkcif_interface_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); + if (ret) + return ret; + + for (unsigned int i = 0; i < routing->num_routes; i++) { + const struct v4l2_subdev_route *route = &routing->routes[i]; + + if (route->source_stream >= RKCIF_ID_MAX) + return -EINVAL; + } + + ret = v4l2_subdev_set_routing(sd, state, routing); + + return ret; +} + +static int rkcif_interface_apply_crop(struct rkcif_stream *stream, + struct v4l2_subdev_state *state) +{ + struct rkcif_interface *interface = stream->interface; + struct v4l2_rect *crop; + + crop = v4l2_subdev_state_get_crop(state, RKCIF_IF_PAD_SRC, stream->id); + if (!crop) + return -EINVAL; + + if (interface->set_crop) + interface->set_crop(stream, crop->left, crop->top); + + return 0; +} + +static int rkcif_interface_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct rkcif_interface *interface = to_rkcif_interface(sd); + struct rkcif_stream *stream; + struct v4l2_subdev_route *route; + struct v4l2_subdev *remote_sd; + struct media_pad *remote_pad; + u64 mask; + + remote_pad = + media_pad_remote_pad_first(&sd->entity.pads[RKCIF_IF_PAD_SINK]); + remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); + + /* DVP has one crop setting for all IDs */ + if (interface->type == RKCIF_IF_DVP) { + stream = &interface->streams[RKCIF_ID0]; + rkcif_interface_apply_crop(stream, state); + } else { + for_each_active_route(&state->routing, route) { + stream = &interface->streams[route->sink_stream]; + rkcif_interface_apply_crop(stream, state); + } + } + + mask = v4l2_subdev_state_xlate_streams(state, RKCIF_IF_PAD_SINK, + RKCIF_IF_PAD_SRC, &streams_mask); + + return v4l2_subdev_enable_streams(remote_sd, remote_pad->index, mask); +} + +static int rkcif_interface_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct v4l2_subdev *remote_sd; + struct media_pad *remote_pad; + u64 mask; + + remote_pad = + media_pad_remote_pad_first(&sd->entity.pads[RKCIF_IF_PAD_SINK]); + remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); + + mask = v4l2_subdev_state_xlate_streams(state, RKCIF_IF_PAD_SINK, + RKCIF_IF_PAD_SRC, &streams_mask); + + return v4l2_subdev_disable_streams(remote_sd, remote_pad->index, mask); +} + +static const struct v4l2_subdev_pad_ops rkcif_interface_pad_ops = { + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = rkcif_interface_set_fmt, + .get_selection = rkcif_interface_get_sel, + .set_selection = rkcif_interface_set_sel, + .set_routing = rkcif_interface_set_routing, + .enable_streams = rkcif_interface_enable_streams, + .disable_streams = rkcif_interface_disable_streams, +}; + +static const struct v4l2_subdev_ops rkcif_interface_ops = { + .pad = &rkcif_interface_pad_ops, +}; + +static int rkcif_interface_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct rkcif_interface *interface = to_rkcif_interface(sd); + struct v4l2_subdev_route routes[] = { + { + .sink_pad = RKCIF_IF_PAD_SINK, + .sink_stream = 0, + .source_pad = RKCIF_IF_PAD_SRC, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + }; + struct v4l2_subdev_krouting routing = { + .len_routes = ARRAY_SIZE(routes), + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + const struct v4l2_mbus_framefmt dvp_default_format = { + .width = 3840, + .height = 2160, + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_REC709, + .ycbcr_enc = V4L2_YCBCR_ENC_709, + .quantization = V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_NONE, + }; + const struct v4l2_mbus_framefmt mipi_default_format = { + .width = 3840, + .height = 2160, + .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, + }; + const struct v4l2_mbus_framefmt *default_format; + int ret; + + default_format = (interface->type == RKCIF_IF_DVP) ? + &dvp_default_format : + &mipi_default_format; + + ret = v4l2_subdev_set_routing_with_fmt(sd, state, &routing, + default_format); + + return ret; +} + +static const struct v4l2_subdev_internal_ops rkcif_interface_internal_ops = { + .init_state = rkcif_interface_init_state, +}; + +static int rkcif_interface_add(struct rkcif_interface *interface) +{ + struct rkcif_device *rkcif = interface->rkcif; + struct rkcif_remote *remote; + struct v4l2_async_notifier *ntf = &rkcif->notifier; + struct v4l2_fwnode_endpoint *vep = &interface->vep; + struct device *dev = rkcif->dev; + struct fwnode_handle *ep; + u32 dvp_clk_delay = 0; + int ret; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), interface->index, + 0, 0); + if (!ep) + return -ENODEV; + + vep->bus_type = V4L2_MBUS_UNKNOWN; + ret = v4l2_fwnode_endpoint_parse(ep, vep); + if (ret) + goto complete; + + if (interface->type == RKCIF_IF_DVP) { + if (vep->bus_type != V4L2_MBUS_BT656 && + vep->bus_type != V4L2_MBUS_PARALLEL) { + ret = dev_err_probe(dev, -EINVAL, + "unsupported bus type\n"); + goto complete; + } + + fwnode_property_read_u32(ep, "rockchip,dvp-clk-delay", + &dvp_clk_delay); + interface->dvp.dvp_clk_delay = dvp_clk_delay; + } + + remote = v4l2_async_nf_add_fwnode_remote(ntf, ep, struct rkcif_remote); + if (IS_ERR(remote)) { + ret = PTR_ERR(remote); + goto complete; + } + + remote->interface = interface; + interface->remote = remote; + interface->status = RKCIF_IF_ACTIVE; + ret = 0; + +complete: + fwnode_handle_put(ep); + + return ret; +} + +int rkcif_interface_register(struct rkcif_device *rkcif, + struct rkcif_interface *interface) +{ + struct media_pad *pads = interface->pads; + struct v4l2_subdev *sd = &interface->sd; + int ret; + + interface->rkcif = rkcif; + + v4l2_subdev_init(sd, &rkcif_interface_ops); + sd->dev = rkcif->dev; + sd->entity.ops = &rkcif_interface_media_ops; + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; + sd->internal_ops = &rkcif_interface_internal_ops; + sd->owner = THIS_MODULE; + + if (interface->type == RKCIF_IF_DVP) + snprintf(sd->name, sizeof(sd->name), "rkcif-dvp0"); + else if (interface->type == RKCIF_IF_MIPI) + snprintf(sd->name, sizeof(sd->name), "rkcif-mipi%d", + interface->index - RKCIF_MIPI_BASE); + + pads[RKCIF_IF_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + pads[RKCIF_IF_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&sd->entity, RKCIF_IF_PAD_MAX, pads); + if (ret) + goto err; + + ret = v4l2_subdev_init_finalize(sd); + if (ret) + goto err_entity_cleanup; + + ret = v4l2_device_register_subdev(&rkcif->v4l2_dev, sd); + if (ret) { + dev_err(sd->dev, "failed to register subdev\n"); + goto err_subdev_cleanup; + } + + ret = rkcif_interface_add(interface); + if (ret) + goto err_subdev_unregister; + + return 0; + +err_subdev_unregister: + v4l2_device_unregister_subdev(sd); +err_subdev_cleanup: + v4l2_subdev_cleanup(sd); +err_entity_cleanup: + media_entity_cleanup(&sd->entity); +err: + return ret; +} + +void rkcif_interface_unregister(struct rkcif_interface *interface) +{ + struct v4l2_subdev *sd = &interface->sd; + + if (interface->status != RKCIF_IF_ACTIVE) + return; + + v4l2_device_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); +} + +const struct rkcif_input_fmt * +rkcif_interface_find_input_fmt(struct rkcif_interface *interface, bool ret_def, + u32 mbus_code) +{ + const struct rkcif_input_fmt *fmt; + + WARN_ON(interface->in_fmts_num == 0); + + for (unsigned int i = 0; i < interface->in_fmts_num; i++) { + fmt = &interface->in_fmts[i]; + if (fmt->mbus_code == mbus_code) + return fmt; + } + if (ret_def) + return &interface->in_fmts[0]; + else + return NULL; +} diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-interface.h b/drivers/media/platform/rockchip/rkcif/rkcif-interface.h new file mode 100644 index 000000000000..f13aa28b6fa7 --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-interface.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip Camera Interface (CIF) Driver + * + * Abstraction for the INTERFACE and CROP parts of the different CIF variants. + * They shall be represented as V4L2 subdevice with one sink pad and one + * source pad. The sink pad is connected to a subdevice: either the subdevice + * provided by the driver of the companion chip connected to the DVP, or the + * subdevice provided by the MIPI CSI-2 receiver driver. The source pad is + * to V4l2 device(s) provided by one or many instance(s) of the DMA + * abstraction. + * + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#ifndef _RKCIF_INTERFACE_H +#define _RKCIF_INTERFACE_H + +#include "rkcif-common.h" + +int rkcif_interface_register(struct rkcif_device *rkcif, + struct rkcif_interface *interface); + +void rkcif_interface_unregister(struct rkcif_interface *interface); + +const struct rkcif_input_fmt * +rkcif_interface_find_input_fmt(struct rkcif_interface *interface, bool ret_def, + u32 mbus_code); + +#endif diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-regs.h b/drivers/media/platform/rockchip/rkcif/rkcif-regs.h new file mode 100644 index 000000000000..3cf7ee19de30 --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-regs.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2018 Rockchip Electronics Co., Ltd. + * Copyright (C) 2023 Mehdi Djait <mehdi.djait@bootlin.com> + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + */ + +#ifndef _RKCIF_REGS_H +#define _RKCIF_REGS_H + +#define RKCIF_REGISTER_NOTSUPPORTED 0x420000 +#define RKCIF_FETCH_Y(VAL) ((VAL) & 0x1fff) +#define RKCIF_XY_COORD(x, y) (((y) << 16) | (x)) + +/* DVP register contents */ +#define RKCIF_CTRL_ENABLE_CAPTURE BIT(0) +#define RKCIF_CTRL_MODE_PINGPONG BIT(1) +#define RKCIF_CTRL_MODE_LINELOOP BIT(2) +#define RKCIF_CTRL_AXI_BURST_16 (0xf << 12) + +#define RKCIF_INTEN_FRAME_END_EN BIT(0) +#define RKCIF_INTEN_LINE_ERR_EN BIT(2) +#define RKCIF_INTEN_BUS_ERR_EN BIT(6) +#define RKCIF_INTEN_SCL_ERR_EN BIT(7) +#define RKCIF_INTEN_PST_INF_FRAME_END_EN BIT(9) + +#define RKCIF_INTSTAT_CLS 0x3ff +#define RKCIF_INTSTAT_FRAME_END BIT(0) +#define RKCIF_INTSTAT_LINE_END BIT(1) +#define RKCIF_INTSTAT_LINE_ERR BIT(2) +#define RKCIF_INTSTAT_PIX_ERR BIT(3) +#define RKCIF_INTSTAT_DFIFO_OF BIT(5) +#define RKCIF_INTSTAT_BUS_ERR BIT(6) +#define RKCIF_INTSTAT_PRE_INF_FRAME_END BIT(8) +#define RKCIF_INTSTAT_PST_INF_FRAME_END BIT(9) +#define RKCIF_INTSTAT_FRAME_END_CLR BIT(0) +#define RKCIF_INTSTAT_LINE_END_CLR BIT(1) +#define RKCIF_INTSTAT_LINE_ERR_CLR BIT(2) +#define RKCIF_INTSTAT_PST_INF_FRAME_END_CLR BIT(9) +#define RKCIF_INTSTAT_ERR 0xfc + +#define RKCIF_FRAME_STAT_CLS 0x00 +#define RKCIF_FRAME_FRM0_STAT_CLS 0x20 + +#define RKCIF_FORMAT_VSY_HIGH_ACTIVE BIT(0) +#define RKCIF_FORMAT_HSY_LOW_ACTIVE BIT(1) + +#define RKCIF_FORMAT_INPUT_MODE_YUV (0x00 << 2) +#define RKCIF_FORMAT_INPUT_MODE_PAL (0x02 << 2) +#define RKCIF_FORMAT_INPUT_MODE_NTSC (0x03 << 2) +#define RKCIF_FORMAT_INPUT_MODE_BT1120 (0x07 << 2) +#define RKCIF_FORMAT_INPUT_MODE_RAW (0x04 << 2) +#define RKCIF_FORMAT_INPUT_MODE_JPEG (0x05 << 2) +#define RKCIF_FORMAT_INPUT_MODE_MIPI (0x06 << 2) + +#define RKCIF_FORMAT_YUV_INPUT_ORDER_UYVY (0x00 << 5) +#define RKCIF_FORMAT_YUV_INPUT_ORDER_YVYU (0x01 << 5) +#define RKCIF_FORMAT_YUV_INPUT_ORDER_VYUY (0x02 << 5) +#define RKCIF_FORMAT_YUV_INPUT_ORDER_YUYV (0x03 << 5) +#define RKCIF_FORMAT_YUV_INPUT_422 (0x00 << 7) +#define RKCIF_FORMAT_YUV_INPUT_420 BIT(7) + +#define RKCIF_FORMAT_INPUT_420_ORDER_ODD BIT(8) + +#define RKCIF_FORMAT_CCIR_INPUT_ORDER_EVEN BIT(9) + +#define RKCIF_FORMAT_RAW_DATA_WIDTH_8 (0x00 << 11) +#define RKCIF_FORMAT_RAW_DATA_WIDTH_10 (0x01 << 11) +#define RKCIF_FORMAT_RAW_DATA_WIDTH_12 (0x02 << 11) + +#define RKCIF_FORMAT_YUV_OUTPUT_422 (0x00 << 16) +#define RKCIF_FORMAT_YUV_OUTPUT_420 BIT(16) + +#define RKCIF_FORMAT_OUTPUT_420_ORDER_EVEN (0x00 << 17) +#define RKCIF_FORMAT_OUTPUT_420_ORDER_ODD BIT(17) + +#define RKCIF_FORMAT_RAWD_DATA_LITTLE_ENDIAN (0x00 << 18) +#define RKCIF_FORMAT_RAWD_DATA_BIG_ENDIAN BIT(18) + +#define RKCIF_FORMAT_UV_STORAGE_ORDER_UVUV (0x00 << 19) +#define RKCIF_FORMAT_UV_STORAGE_ORDER_VUVU BIT(19) + +#define RKCIF_FORMAT_BT1120_CLOCK_SINGLE_EDGES (0x00 << 24) +#define RKCIF_FORMAT_BT1120_CLOCK_DOUBLE_EDGES BIT(24) +#define RKCIF_FORMAT_BT1120_TRANSMIT_INTERFACE (0x00 << 25) +#define RKCIF_FORMAT_BT1120_TRANSMIT_PROGRESS BIT(25) +#define RKCIF_FORMAT_BT1120_YC_SWAP BIT(26) + +#define RKCIF_SCL_CTRL_ENABLE_SCL_DOWN BIT(0) +#define RKCIF_SCL_CTRL_ENABLE_SCL_UP BIT(1) +#define RKCIF_SCL_CTRL_ENABLE_YUV_16BIT_BYPASS BIT(4) +#define RKCIF_SCL_CTRL_ENABLE_RAW_16BIT_BYPASS BIT(5) +#define RKCIF_SCL_CTRL_ENABLE_32BIT_BYPASS BIT(6) +#define RKCIF_SCL_CTRL_DISABLE_32BIT_BYPASS (0x00 << 6) + +#define RKCIF_INTSTAT_F0_READY BIT(0) +#define RKCIF_INTSTAT_F1_READY BIT(1) + +/* GRF register offsets and contents */ +#define RK3568_GRF_VI_CON0 0x340 +#define RK3568_GRF_VI_CON1 0x344 +#define RK3568_GRF_VI_STATUS0 0x348 + +#define RK3568_GRF_VI_CON1_CIF_DATAPATH BIT(9) +#define RK3568_GRF_VI_CON1_CIF_CLK_DELAYNUM GENMASK(6, 0) + +#define RK3568_GRF_WRITE_ENABLE(x) ((x) << 16) + +enum rkcif_dvp_register_index { + RKCIF_DVP_CTRL, + RKCIF_DVP_INTEN, + RKCIF_DVP_INTSTAT, + RKCIF_DVP_FOR, + RKCIF_DVP_LINE_NUM_ADDR, + RKCIF_DVP_FRM0_ADDR_Y, + RKCIF_DVP_FRM0_ADDR_UV, + RKCIF_DVP_FRM1_ADDR_Y, + RKCIF_DVP_FRM1_ADDR_UV, + RKCIF_DVP_VIR_LINE_WIDTH, + RKCIF_DVP_SET_SIZE, + RKCIF_DVP_SCL_CTRL, + RKCIF_DVP_CROP, + RKCIF_DVP_FRAME_STATUS, + RKCIF_DVP_LAST_LINE, + RKCIF_DVP_LAST_PIX, + RKCIF_DVP_REGISTER_MAX +}; + +enum rkcif_mipi_register_index { + RKCIF_MIPI_CTRL, + RKCIF_MIPI_INTEN, + RKCIF_MIPI_INTSTAT, + RKCIF_MIPI_REGISTER_MAX +}; + +enum rkcif_mipi_id_register_index { + RKCIF_MIPI_CTRL0, + RKCIF_MIPI_CTRL1, + RKCIF_MIPI_FRAME0_ADDR_Y, + RKCIF_MIPI_FRAME0_ADDR_UV, + RKCIF_MIPI_FRAME0_VLW_Y, + RKCIF_MIPI_FRAME0_VLW_UV, + RKCIF_MIPI_FRAME1_ADDR_Y, + RKCIF_MIPI_FRAME1_ADDR_UV, + RKCIF_MIPI_FRAME1_VLW_Y, + RKCIF_MIPI_FRAME1_VLW_UV, + RKCIF_MIPI_CROP_START, + RKCIF_MIPI_ID_REGISTER_MAX +}; + +#endif diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-stream.c b/drivers/media/platform/rockchip/rkcif/rkcif-stream.c new file mode 100644 index 000000000000..e00010a91e8b --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-stream.c @@ -0,0 +1,636 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Camera Interface (CIF) Driver + * + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#include <linux/pm_runtime.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mc.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-dma-contig.h> + +#include "rkcif-common.h" +#include "rkcif-stream.h" + +#define CIF_REQ_BUFS_MIN 1 +#define CIF_MIN_WIDTH 64 +#define CIF_MIN_HEIGHT 64 +#define CIF_MAX_WIDTH 8192 +#define CIF_MAX_HEIGHT 8192 + +static inline struct rkcif_buffer *to_rkcif_buffer(struct vb2_v4l2_buffer *vb) +{ + return container_of(vb, struct rkcif_buffer, vb); +} + +static inline struct rkcif_stream *to_rkcif_stream(struct video_device *vdev) +{ + return container_of(vdev, struct rkcif_stream, vdev); +} + +static struct rkcif_buffer *rkcif_stream_pop_buffer(struct rkcif_stream *stream) +{ + struct rkcif_buffer *buffer; + + guard(spinlock_irqsave)(&stream->driver_queue_lock); + + if (list_empty(&stream->driver_queue)) + return NULL; + + buffer = list_first_entry(&stream->driver_queue, struct rkcif_buffer, + queue); + list_del(&buffer->queue); + + return buffer; +} + +static void rkcif_stream_push_buffer(struct rkcif_stream *stream, + struct rkcif_buffer *buffer) +{ + guard(spinlock_irqsave)(&stream->driver_queue_lock); + + list_add_tail(&buffer->queue, &stream->driver_queue); +} + +static inline void rkcif_stream_return_buffer(struct rkcif_buffer *buffer, + enum vb2_buffer_state state) +{ + struct vb2_v4l2_buffer *vb = &buffer->vb; + + vb2_buffer_done(&vb->vb2_buf, state); +} + +static void rkcif_stream_complete_buffer(struct rkcif_stream *stream, + struct rkcif_buffer *buffer) +{ + struct vb2_v4l2_buffer *vb = &buffer->vb; + + vb->vb2_buf.timestamp = ktime_get_ns(); + vb->sequence = stream->frame_idx; + vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE); + stream->frame_idx++; +} + +void rkcif_stream_pingpong(struct rkcif_stream *stream) +{ + struct rkcif_buffer *buffer; + + buffer = stream->buffers[stream->frame_phase]; + if (!buffer->is_dummy) + rkcif_stream_complete_buffer(stream, buffer); + + buffer = rkcif_stream_pop_buffer(stream); + if (buffer) { + stream->buffers[stream->frame_phase] = buffer; + stream->buffers[stream->frame_phase]->is_dummy = false; + } else { + stream->buffers[stream->frame_phase] = &stream->dummy.buffer; + stream->buffers[stream->frame_phase]->is_dummy = true; + dev_dbg(stream->rkcif->dev, + "no buffer available, frame will be dropped\n"); + } + + if (stream->queue_buffer) + stream->queue_buffer(stream, stream->frame_phase); + + stream->frame_phase = 1 - stream->frame_phase; +} + +static int rkcif_stream_init_buffers(struct rkcif_stream *stream) +{ + struct v4l2_pix_format_mplane *pix = &stream->pix; + + stream->buffers[0] = rkcif_stream_pop_buffer(stream); + if (!stream->buffers[0]) + goto err_buff_0; + + stream->buffers[1] = rkcif_stream_pop_buffer(stream); + if (!stream->buffers[1]) + goto err_buff_1; + + if (stream->queue_buffer) { + stream->queue_buffer(stream, 0); + stream->queue_buffer(stream, 1); + } + + stream->dummy.size = pix->num_planes * pix->plane_fmt[0].sizeimage; + stream->dummy.vaddr = + dma_alloc_attrs(stream->rkcif->dev, stream->dummy.size, + &stream->dummy.buffer.buff_addr[0], GFP_KERNEL, + DMA_ATTR_NO_KERNEL_MAPPING); + if (!stream->dummy.vaddr) + goto err_dummy; + + for (unsigned int i = 1; i < pix->num_planes; i++) + stream->dummy.buffer.buff_addr[i] = + stream->dummy.buffer.buff_addr[i - 1] + + pix->plane_fmt[i - 1].bytesperline * pix->height; + + return 0; + +err_dummy: + rkcif_stream_return_buffer(stream->buffers[1], VB2_BUF_STATE_QUEUED); + stream->buffers[1] = NULL; + +err_buff_1: + rkcif_stream_return_buffer(stream->buffers[0], VB2_BUF_STATE_QUEUED); + stream->buffers[0] = NULL; +err_buff_0: + return -EINVAL; +} + +static void rkcif_stream_return_all_buffers(struct rkcif_stream *stream, + enum vb2_buffer_state state) +{ + struct rkcif_buffer *buffer; + + if (stream->buffers[0] && !stream->buffers[0]->is_dummy) { + rkcif_stream_return_buffer(stream->buffers[0], state); + stream->buffers[0] = NULL; + } + + if (stream->buffers[1] && !stream->buffers[1]->is_dummy) { + rkcif_stream_return_buffer(stream->buffers[1], state); + stream->buffers[1] = NULL; + } + + while ((buffer = rkcif_stream_pop_buffer(stream))) + rkcif_stream_return_buffer(buffer, state); + + if (stream->dummy.vaddr) { + dma_free_attrs(stream->rkcif->dev, stream->dummy.size, + stream->dummy.vaddr, + stream->dummy.buffer.buff_addr[0], + DMA_ATTR_NO_KERNEL_MAPPING); + stream->dummy.vaddr = NULL; + } +} + +static int rkcif_stream_setup_queue(struct vb2_queue *queue, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct rkcif_stream *stream = queue->drv_priv; + struct v4l2_pix_format_mplane *pix = &stream->pix; + + if (*num_planes) { + if (*num_planes != pix->num_planes) + return -EINVAL; + + for (unsigned int i = 0; i < pix->num_planes; i++) + if (sizes[i] < pix->plane_fmt[i].sizeimage) + return -EINVAL; + } else { + *num_planes = pix->num_planes; + for (unsigned int i = 0; i < pix->num_planes; i++) + sizes[i] = pix->plane_fmt[i].sizeimage; + } + + return 0; +} + +static int rkcif_stream_prepare_buffer(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkcif_buffer *buffer = to_rkcif_buffer(vbuf); + struct rkcif_stream *stream = vb->vb2_queue->drv_priv; + const struct rkcif_output_fmt *fmt; + struct v4l2_pix_format_mplane *pix = &stream->pix; + unsigned int i; + + memset(buffer->buff_addr, 0, sizeof(buffer->buff_addr)); + for (i = 0; i < pix->num_planes; i++) + buffer->buff_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); + + /* apply fallback for non-mplane formats, if required */ + if (pix->num_planes == 1) { + fmt = rkcif_stream_find_output_fmt(stream, true, + pix->pixelformat); + for (i = 1; i < fmt->cplanes; i++) + buffer->buff_addr[i] = + buffer->buff_addr[i - 1] + + pix->plane_fmt[i - 1].bytesperline * + pix->height; + } + + for (i = 0; i < pix->num_planes; i++) { + unsigned long size = pix->plane_fmt[i].sizeimage; + + if (vb2_plane_size(vb, i) < size) { + dev_err(stream->rkcif->dev, + "user buffer too small (%ld < %ld)\n", + vb2_plane_size(vb, i), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, i, size); + } + + vbuf->field = V4L2_FIELD_NONE; + + return 0; +} + +static void rkcif_stream_queue_buffer(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkcif_buffer *buffer = to_rkcif_buffer(vbuf); + struct rkcif_stream *stream = vb->vb2_queue->drv_priv; + + rkcif_stream_push_buffer(stream, buffer); +} + +static int rkcif_stream_start_streaming(struct vb2_queue *queue, + unsigned int count) +{ + struct rkcif_stream *stream = queue->drv_priv; + struct rkcif_device *rkcif = stream->rkcif; + u64 mask; + int ret; + + stream->frame_idx = 0; + stream->frame_phase = 0; + + ret = video_device_pipeline_start(&stream->vdev, &stream->pipeline); + if (ret) { + dev_err(rkcif->dev, "failed to start pipeline %d\n", ret); + goto err_out; + } + + ret = pm_runtime_resume_and_get(rkcif->dev); + if (ret < 0) { + dev_err(rkcif->dev, "failed to get runtime pm, %d\n", ret); + goto err_pipeline_stop; + } + + ret = rkcif_stream_init_buffers(stream); + if (ret) + goto err_runtime_put; + + if (stream->start_streaming) { + ret = stream->start_streaming(stream); + if (ret < 0) + goto err_runtime_put; + } + + mask = BIT_ULL(stream->id); + ret = v4l2_subdev_enable_streams(&stream->interface->sd, + RKCIF_IF_PAD_SRC, mask); + if (ret < 0) + goto err_stop_stream; + + return 0; + +err_stop_stream: + if (stream->stop_streaming) + stream->stop_streaming(stream); +err_runtime_put: + pm_runtime_put(rkcif->dev); +err_pipeline_stop: + video_device_pipeline_stop(&stream->vdev); +err_out: + rkcif_stream_return_all_buffers(stream, VB2_BUF_STATE_QUEUED); + return ret; +} + +static void rkcif_stream_stop_streaming(struct vb2_queue *queue) +{ + struct rkcif_stream *stream = queue->drv_priv; + struct rkcif_device *rkcif = stream->rkcif; + u64 mask; + int ret; + + mask = BIT_ULL(stream->id); + v4l2_subdev_disable_streams(&stream->interface->sd, RKCIF_IF_PAD_SRC, + mask); + + stream->stopping = true; + ret = wait_event_timeout(stream->wq_stopped, !stream->stopping, + msecs_to_jiffies(1000)); + + if (!ret && stream->stop_streaming) + stream->stop_streaming(stream); + + pm_runtime_put(rkcif->dev); + + rkcif_stream_return_all_buffers(stream, VB2_BUF_STATE_ERROR); + + video_device_pipeline_stop(&stream->vdev); +} + +static const struct vb2_ops rkcif_stream_vb2_ops = { + .queue_setup = rkcif_stream_setup_queue, + .buf_prepare = rkcif_stream_prepare_buffer, + .buf_queue = rkcif_stream_queue_buffer, + .start_streaming = rkcif_stream_start_streaming, + .stop_streaming = rkcif_stream_stop_streaming, +}; + +static int rkcif_stream_fill_format(struct rkcif_stream *stream, + struct v4l2_pix_format_mplane *pix) +{ + const struct rkcif_output_fmt *fmt; + u32 height, width; + int ret; + + fmt = rkcif_stream_find_output_fmt(stream, true, pix->pixelformat); + height = clamp_t(u32, pix->height, CIF_MIN_HEIGHT, CIF_MAX_HEIGHT); + width = clamp_t(u32, pix->width, CIF_MIN_WIDTH, CIF_MAX_WIDTH); + ret = v4l2_fill_pixfmt_mp(pix, fmt->fourcc, width, height); + if (ret) + return ret; + + pix->field = V4L2_FIELD_NONE; + + return 0; +} + +static int rkcif_stream_try_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rkcif_stream *stream = video_drvdata(file); + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + + return rkcif_stream_fill_format(stream, pix); +} + +static int rkcif_stream_set_format(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rkcif_stream *stream = video_drvdata(file); + struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + int ret; + + if (vb2_is_busy(&stream->buf_queue)) + return -EBUSY; + + ret = rkcif_stream_try_format(file, priv, f); + if (ret) + return ret; + + stream->pix = *pix; + + return 0; +} + +static int rkcif_stream_get_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rkcif_stream *stream = video_drvdata(file); + + f->fmt.pix_mp = stream->pix; + + return 0; +} + +static int rkcif_stream_enum_formats(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rkcif_stream *stream = video_drvdata(file); + + if (f->index >= stream->out_fmts_num) + return -EINVAL; + + f->pixelformat = stream->out_fmts[f->index].fourcc; + + return 0; +} + +static int rkcif_stream_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct rkcif_stream *stream = video_drvdata(file); + + if (fsize->index > 0) + return -EINVAL; + + if (!rkcif_stream_find_output_fmt(stream, false, fsize->pixel_format)) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = CIF_MIN_WIDTH; + fsize->stepwise.max_width = CIF_MAX_WIDTH; + fsize->stepwise.step_width = 8; + fsize->stepwise.min_height = CIF_MIN_HEIGHT; + fsize->stepwise.max_height = CIF_MAX_HEIGHT; + fsize->stepwise.step_height = 8; + + return 0; +} + +static int rkcif_stream_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct rkcif_stream *stream = video_drvdata(file); + struct device *dev = stream->rkcif->dev; + + strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); + strscpy(cap->card, dev->driver->name, sizeof(cap->card)); + + return 0; +} + +static const struct v4l2_ioctl_ops rkcif_stream_ioctl_ops = { + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_try_fmt_vid_cap_mplane = rkcif_stream_try_format, + .vidioc_s_fmt_vid_cap_mplane = rkcif_stream_set_format, + .vidioc_g_fmt_vid_cap_mplane = rkcif_stream_get_format, + .vidioc_enum_fmt_vid_cap = rkcif_stream_enum_formats, + .vidioc_enum_framesizes = rkcif_stream_enum_framesizes, + .vidioc_querycap = rkcif_stream_querycap, +}; + +static int rkcif_stream_link_validate(struct media_link *link) +{ + struct video_device *vdev = + media_entity_to_video_device(link->sink->entity); + struct v4l2_mbus_framefmt *source_fmt; + struct v4l2_subdev *sd; + struct v4l2_subdev_state *state; + struct rkcif_stream *stream = to_rkcif_stream(vdev); + int ret = -EINVAL; + + if (!media_entity_remote_source_pad_unique(link->sink->entity)) + return -ENOTCONN; + + sd = media_entity_to_v4l2_subdev(link->source->entity); + + state = v4l2_subdev_lock_and_get_active_state(sd); + + source_fmt = v4l2_subdev_state_get_format(state, link->source->index, + stream->id); + if (!source_fmt) + goto out; + + if (source_fmt->height != stream->pix.height || + source_fmt->width != stream->pix.width) { + dev_dbg(stream->rkcif->dev, + "link '%s':%u -> '%s':%u not valid: %ux%u != %ux%u\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index, + source_fmt->width, source_fmt->height, + stream->pix.width, stream->pix.height); + goto out; + } + + ret = 0; + +out: + v4l2_subdev_unlock_state(state); + return ret; +} + +static const struct media_entity_operations rkcif_stream_media_ops = { + .link_validate = rkcif_stream_link_validate, +}; + +static const struct v4l2_file_operations rkcif_stream_file_ops = { + .open = v4l2_fh_open, + .release = vb2_fop_release, + .unlocked_ioctl = video_ioctl2, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +}; + +static int rkcif_stream_init_vb2_queue(struct vb2_queue *q, + struct rkcif_stream *stream) +{ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = stream; + q->ops = &rkcif_stream_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct rkcif_buffer); + q->min_queued_buffers = CIF_REQ_BUFS_MIN; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &stream->vlock; + q->dev = stream->rkcif->dev; + + return vb2_queue_init(q); +} + +int rkcif_stream_register(struct rkcif_device *rkcif, + struct rkcif_stream *stream) +{ + struct rkcif_interface *interface = stream->interface; + struct v4l2_device *v4l2_dev = &rkcif->v4l2_dev; + struct video_device *vdev = &stream->vdev; + u32 link_flags = 0; + int ret; + + stream->rkcif = rkcif; + + INIT_LIST_HEAD(&stream->driver_queue); + spin_lock_init(&stream->driver_queue_lock); + + init_waitqueue_head(&stream->wq_stopped); + + mutex_init(&stream->vlock); + + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING | + V4L2_CAP_IO_MC; + vdev->entity.ops = &rkcif_stream_media_ops; + vdev->fops = &rkcif_stream_file_ops; + vdev->ioctl_ops = &rkcif_stream_ioctl_ops; + vdev->lock = &stream->vlock; + vdev->minor = -1; + vdev->release = video_device_release_empty; + vdev->v4l2_dev = v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + video_set_drvdata(vdev, stream); + + stream->pad.flags = MEDIA_PAD_FL_SINK; + + stream->pix.height = CIF_MIN_HEIGHT; + stream->pix.width = CIF_MIN_WIDTH; + rkcif_stream_fill_format(stream, &stream->pix); + + rkcif_stream_init_vb2_queue(&stream->buf_queue, stream); + + vdev->queue = &stream->buf_queue; + if (interface->type == RKCIF_IF_DVP) + snprintf(vdev->name, sizeof(vdev->name), "rkcif-dvp0-id%d", + stream->id); + else if (interface->type == RKCIF_IF_MIPI) + snprintf(vdev->name, sizeof(vdev->name), "rkcif-mipi%d-id%d", + interface->index - RKCIF_MIPI_BASE, stream->id); + + ret = media_entity_pads_init(&vdev->entity, 1, &stream->pad); + if (ret < 0) { + dev_err(rkcif->dev, + "failed to initialize stream media pad: %d\n", ret); + return ret; + } + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret < 0) { + dev_err(rkcif->dev, "failed to register video device: %d\n", + ret); + goto err_media_entity_cleanup; + } + + /* enable only stream ID0 by default */ + if (stream->id == RKCIF_ID0) + link_flags |= MEDIA_LNK_FL_ENABLED; + + ret = media_create_pad_link(&interface->sd.entity, RKCIF_IF_PAD_SRC, + &stream->vdev.entity, 0, link_flags); + if (ret) { + dev_err(rkcif->dev, "failed to link stream media pad: %d\n", + ret); + goto err_video_unregister; + } + + v4l2_info(v4l2_dev, "registered %s as /dev/video%d\n", vdev->name, + vdev->num); + + return 0; + +err_video_unregister: + video_unregister_device(&stream->vdev); +err_media_entity_cleanup: + media_entity_cleanup(&stream->vdev.entity); + return ret; +} + +void rkcif_stream_unregister(struct rkcif_stream *stream) +{ + video_unregister_device(&stream->vdev); + media_entity_cleanup(&stream->vdev.entity); +} + +const struct rkcif_output_fmt * +rkcif_stream_find_output_fmt(struct rkcif_stream *stream, bool ret_def, + u32 pixelfmt) +{ + const struct rkcif_output_fmt *fmt; + + WARN_ON(stream->out_fmts_num == 0); + + for (unsigned int i = 0; i < stream->out_fmts_num; i++) { + fmt = &stream->out_fmts[i]; + if (fmt->fourcc == pixelfmt) + return fmt; + } + + if (ret_def) + return &stream->out_fmts[0]; + else + return NULL; +} diff --git a/drivers/media/platform/rockchip/rkcif/rkcif-stream.h b/drivers/media/platform/rockchip/rkcif/rkcif-stream.h new file mode 100644 index 000000000000..590faf5d1a87 --- /dev/null +++ b/drivers/media/platform/rockchip/rkcif/rkcif-stream.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Rockchip Camera Interface (CIF) Driver + * + * Abstraction for the DMA part and the ping-pong scheme (a double-buffering + * mechanism) of the different CIF variants. + * Each stream is represented as V4L2 device whose corresponding media entity + * has one sink pad. + * The sink pad is connected to an instance of the INTERFACE/CROP abstraction + * in rkcif-interface.c. + * + * Copyright (C) 2025 Michael Riesch <michael.riesch@wolfvision.net> + * Copyright (C) 2025 Collabora, Ltd. + */ + +#ifndef _RKCIF_STREAM_H +#define _RKCIF_STREAM_H + +#include "rkcif-common.h" + +void rkcif_stream_pingpong(struct rkcif_stream *stream); + +int rkcif_stream_register(struct rkcif_device *rkcif, + struct rkcif_stream *stream); + +void rkcif_stream_unregister(struct rkcif_stream *stream); + +const struct rkcif_output_fmt * +rkcif_stream_find_output_fmt(struct rkcif_stream *stream, bool ret_def, + u32 pixelfmt); + +#endif diff --git a/drivers/media/platform/rockchip/rkisp1/Kconfig b/drivers/media/platform/rockchip/rkisp1/Kconfig index 731c9acbf6ef..f53eb1f3f3e7 100644 --- a/drivers/media/platform/rockchip/rkisp1/Kconfig +++ b/drivers/media/platform/rockchip/rkisp1/Kconfig @@ -10,6 +10,7 @@ config VIDEO_ROCKCHIP_ISP1 select VIDEOBUF2_VMALLOC select V4L2_FWNODE select GENERIC_PHY_MIPI_DPHY + select V4L2_ISP default n help Enable this to support the Image Signal Processing (ISP) module diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 5f187f9efc7b..5e6a4d5f6fd1 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -24,6 +24,7 @@ #include "rkisp1-regs.h" struct dentry; +struct dev_pm_domain_list; struct regmap; /* @@ -55,7 +56,7 @@ struct regmap; #define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME /* maximum number of clocks */ -#define RKISP1_MAX_BUS_CLK 8 +#define RKISP1_MAX_BUS_CLK 4 /* a bitmask of the ready stats */ #define RKISP1_STATS_MEAS_MASK (RKISP1_CIF_ISP_AWB_DONE | \ @@ -139,27 +140,31 @@ enum rkisp1_feature { /* * struct rkisp1_info - Model-specific ISP Information * - * @clks: array of ISP clock names - * @clk_size: number of entries in the @clks array + * @num_clocks: number of clocks * @isrs: array of ISP interrupt descriptors * @isr_size: number of entries in the @isrs array * @isp_ver: ISP version * @features: bitmask of rkisp1_feature features implemented by the ISP * @max_width: maximum input frame width * @max_height: maximum input frame height + * @pm_domains.names: name of the power domains + * @pm_domains.count: number of power domains * * This structure contains information about the ISP specific to a particular * ISP model, version, or integration in a particular SoC. */ struct rkisp1_info { - const char * const *clks; - unsigned int clk_size; + unsigned int num_clocks; const struct rkisp1_isr_data *isrs; unsigned int isr_size; enum rkisp1_cif_isp_version isp_ver; unsigned int features; unsigned int max_width; unsigned int max_height; + struct { + const char * const *names; + unsigned int count; + } pm_domains; }; /* @@ -222,6 +227,7 @@ struct rkisp1_isp { struct media_pad pads[RKISP1_ISP_PAD_MAX]; const struct rkisp1_mbus_info *sink_fmt; __u32 frame_sequence; + bool frame_active; }; /* @@ -483,6 +489,7 @@ struct rkisp1_debug { * @dev: a pointer to the struct device * @clk_size: number of clocks * @clks: array of clocks + * @pm_domains: power domains * @gasket: the gasket - i.MX8MP only * @gasket_id: the gasket ID (0 or 1) - i.MX8MP only * @v4l2_dev: v4l2_device variable @@ -507,6 +514,7 @@ struct rkisp1_device { struct device *dev; unsigned int clk_size; struct clk_bulk_data clks[RKISP1_MAX_BUS_CLK]; + struct dev_pm_domain_list *pm_domains; struct regmap *gasket; unsigned int gasket_id; struct v4l2_device v4l2_dev; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c index 841e58c20f7f..ddc6182f3e4b 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c @@ -368,8 +368,8 @@ static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable) source_pad = media_entity_remote_source_pad_unique(&sd->entity); if (IS_ERR(source_pad)) { - dev_dbg(rkisp1->dev, "Failed to get source for CSI: %ld\n", - PTR_ERR(source_pad)); + dev_dbg(rkisp1->dev, "Failed to get source for CSI: %pe\n", + source_pad); return -EPIPE; } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index dc65a7924f8a..1791c02a40ae 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -8,6 +8,7 @@ * Copyright (C) 2017 Rockchip Electronics Co., Ltd. */ +#include <linux/build_bug.h> #include <linux/clk.h> #include <linux/interrupt.h> #include <linux/mfd/syscon.h> @@ -16,6 +17,7 @@ #include <linux/of_graph.h> #include <linux/platform_device.h> #include <linux/pinctrl/consumer.h> +#include <linux/pm_domain.h> #include <linux/pm_runtime.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-mc.h> @@ -491,13 +493,6 @@ static irqreturn_t rkisp1_isr(int irq, void *ctx) return ret; } -static const char * const px30_isp_clks[] = { - "isp", - "aclk", - "hclk", - "pclk", -}; - static const struct rkisp1_isr_data px30_isp_isrs[] = { { "isp", rkisp1_isp_isr, BIT(RKISP1_IRQ_ISP) }, { "mi", rkisp1_capture_isr, BIT(RKISP1_IRQ_MI) }, @@ -505,8 +500,7 @@ static const struct rkisp1_isr_data px30_isp_isrs[] = { }; static const struct rkisp1_info px30_isp_info = { - .clks = px30_isp_clks, - .clk_size = ARRAY_SIZE(px30_isp_clks), + .num_clocks = 4, .isrs = px30_isp_isrs, .isr_size = ARRAY_SIZE(px30_isp_isrs), .isp_ver = RKISP1_V12, @@ -518,19 +512,12 @@ static const struct rkisp1_info px30_isp_info = { .max_height = 2448, }; -static const char * const rk3399_isp_clks[] = { - "isp", - "aclk", - "hclk", -}; - static const struct rkisp1_isr_data rk3399_isp_isrs[] = { { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) | BIT(RKISP1_IRQ_MIPI) }, }; static const struct rkisp1_info rk3399_isp_info = { - .clks = rk3399_isp_clks, - .clk_size = ARRAY_SIZE(rk3399_isp_clks), + .num_clocks = 3, .isrs = rk3399_isp_isrs, .isr_size = ARRAY_SIZE(rk3399_isp_isrs), .isp_ver = RKISP1_V10, @@ -542,19 +529,17 @@ static const struct rkisp1_info rk3399_isp_info = { .max_height = 3312, }; -static const char * const imx8mp_isp_clks[] = { - "isp", - "hclk", - "aclk", -}; - static const struct rkisp1_isr_data imx8mp_isp_isrs[] = { { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) }, }; +static const char * const imx8mp_isp_pm_domains[] = { + "isp", + "csi2", +}; + static const struct rkisp1_info imx8mp_isp_info = { - .clks = imx8mp_isp_clks, - .clk_size = ARRAY_SIZE(imx8mp_isp_clks), + .num_clocks = 3, .isrs = imx8mp_isp_isrs, .isr_size = ARRAY_SIZE(imx8mp_isp_isrs), .isp_ver = RKISP1_V_IMX8MP, @@ -563,6 +548,10 @@ static const struct rkisp1_info imx8mp_isp_info = { | RKISP1_FEATURE_COMPAND, .max_width = 4096, .max_height = 3072, + .pm_domains = { + .names = imx8mp_isp_pm_domains, + .count = ARRAY_SIZE(imx8mp_isp_pm_domains), + }, }; static const struct of_device_id rkisp1_of_match[] = { @@ -582,6 +571,81 @@ static const struct of_device_id rkisp1_of_match[] = { }; MODULE_DEVICE_TABLE(of, rkisp1_of_match); +static const char * const rkisp1_clk_names[] = { + "isp", + "aclk", + "hclk", + "pclk", +}; + +static int rkisp1_init_clocks(struct rkisp1_device *rkisp1) +{ + const struct rkisp1_info *info = rkisp1->info; + unsigned int i; + int ret; + + static_assert(ARRAY_SIZE(rkisp1_clk_names) == ARRAY_SIZE(rkisp1->clks)); + + for (i = 0; i < info->num_clocks; i++) + rkisp1->clks[i].id = rkisp1_clk_names[i]; + + ret = devm_clk_bulk_get(rkisp1->dev, info->num_clocks, rkisp1->clks); + if (ret) + return ret; + + rkisp1->clk_size = info->num_clocks; + + /* + * On i.MX8MP the pclk clock is needed to access the HDR stitching + * registers, but wasn't required by DT bindings. Try to acquire it as + * an optional clock to avoid breaking backward compatibility. + */ + if (info->isp_ver == RKISP1_V_IMX8MP) { + struct clk *clk; + + clk = devm_clk_get_optional(rkisp1->dev, "pclk"); + if (IS_ERR(clk)) + return dev_err_probe(rkisp1->dev, PTR_ERR(clk), + "Failed to acquire pclk clock\n"); + + if (clk) + rkisp1->clks[rkisp1->clk_size++].clk = clk; + } + + return 0; +} + +static int rkisp1_init_pm_domains(struct rkisp1_device *rkisp1) +{ + const struct rkisp1_info *info = rkisp1->info; + struct dev_pm_domain_attach_data pm_domain_data = { + .pd_names = info->pm_domains.names, + .num_pd_names = info->pm_domains.count, + }; + int ret; + + /* + * Most platforms have a single power domain, which the PM domain core + * automatically attaches at probe time. When that's the case there's + * nothing to do here. + */ + if (rkisp1->dev->pm_domain) + return 0; + + if (!pm_domain_data.num_pd_names) + return 0; + + ret = devm_pm_domain_attach_list(rkisp1->dev, &pm_domain_data, + &rkisp1->pm_domains); + if (ret < 0) { + dev_err_probe(rkisp1->dev, ret, + "Failed to attach power domains\n"); + return ret; + } + + return 0; +} + static int rkisp1_probe(struct platform_device *pdev) { const struct rkisp1_info *info; @@ -639,12 +703,13 @@ static int rkisp1_probe(struct platform_device *pdev) } } - for (i = 0; i < info->clk_size; i++) - rkisp1->clks[i].id = info->clks[i]; - ret = devm_clk_bulk_get(dev, info->clk_size, rkisp1->clks); + ret = rkisp1_init_clocks(rkisp1); + if (ret) + return ret; + + ret = rkisp1_init_pm_domains(rkisp1); if (ret) return ret; - rkisp1->clk_size = info->clk_size; if (info->isp_ver == RKISP1_V_IMX8MP) { unsigned int id; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 8c29a1c9309a..2311672cedb1 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -936,8 +936,8 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) sink_pad = &isp->pads[RKISP1_ISP_PAD_SINK_VIDEO]; source_pad = media_pad_remote_pad_unique(sink_pad); if (IS_ERR(source_pad)) { - dev_dbg(rkisp1->dev, "Failed to get source for ISP: %ld\n", - PTR_ERR(source_pad)); + dev_dbg(rkisp1->dev, "Failed to get source for ISP: %pe\n", + source_pad); return -EPIPE; } @@ -965,6 +965,7 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) } isp->frame_sequence = -1; + isp->frame_active = false; sd_state = v4l2_subdev_lock_and_get_active_state(sd); @@ -1086,12 +1087,15 @@ void rkisp1_isp_unregister(struct rkisp1_device *rkisp1) * Interrupt handlers */ -static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp) +static void rkisp1_isp_sof(struct rkisp1_isp *isp) { struct v4l2_event event = { .type = V4L2_EVENT_FRAME_SYNC, }; + isp->frame_sequence++; + isp->frame_active = true; + event.u.frame_sync.frame_sequence = isp->frame_sequence; v4l2_event_queue(isp->sd.devnode, &event); } @@ -1111,15 +1115,20 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx) rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, status); - /* Vertical sync signal, starting generating new frame */ - if (status & RKISP1_CIF_ISP_V_START) { - rkisp1->isp.frame_sequence++; - rkisp1_isp_queue_event_sof(&rkisp1->isp); + /* + * Vertical sync signal, starting new frame. Defer handling of vsync + * after RKISP1_CIF_ISP_FRAME if the previous frame was not completed + * yet. + */ + if (status & RKISP1_CIF_ISP_V_START && !rkisp1->isp.frame_active) { + status &= ~RKISP1_CIF_ISP_V_START; + rkisp1_isp_sof(&rkisp1->isp); if (status & RKISP1_CIF_ISP_FRAME) { WARN_ONCE(1, "irq delay is too long, buffers might not be in sync\n"); rkisp1->debug.irq_delay++; } } + if (status & RKISP1_CIF_ISP_PIC_SIZE_ERROR) { /* Clear pic_size_error */ isp_err = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ERR); @@ -1138,6 +1147,7 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx) if (status & RKISP1_CIF_ISP_FRAME) { u32 isp_ris; + rkisp1->isp.frame_active = false; rkisp1->debug.complete_frames++; /* New frame from the sensor received */ @@ -1152,5 +1162,12 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx) rkisp1_params_isr(rkisp1); } + /* + * Deferred handling of vsync if RKISP1_CIF_ISP_V_START and + * RKISP1_CIF_ISP_FRAME occurred in the same irq. + */ + if (status & RKISP1_CIF_ISP_V_START) + rkisp1_isp_sof(&rkisp1->isp); + return IRQ_HANDLED; } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index f1585f8fa0f4..c9f88635224c 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -6,12 +6,14 @@ */ #include <linux/bitfield.h> +#include <linux/build_bug.h> #include <linux/math.h> #include <linux/string.h> #include <media/v4l2-common.h> #include <media/v4l2-event.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-isp.h> #include <media/videobuf2-core.h> #include <media/videobuf2-vmalloc.h> /* for ISP params */ @@ -2097,122 +2099,133 @@ typedef void (*rkisp1_block_handler)(struct rkisp1_params *params, const union rkisp1_ext_params_config *config); static const struct rkisp1_ext_params_handler { - size_t size; rkisp1_block_handler handler; unsigned int group; unsigned int features; } rkisp1_ext_params_handlers[] = { [RKISP1_EXT_PARAMS_BLOCK_TYPE_BLS] = { - .size = sizeof(struct rkisp1_ext_params_bls_config), .handler = rkisp1_ext_params_bls, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, .features = RKISP1_FEATURE_BLS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_DPCC] = { - .size = sizeof(struct rkisp1_ext_params_dpcc_config), .handler = rkisp1_ext_params_dpcc, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_SDG] = { - .size = sizeof(struct rkisp1_ext_params_sdg_config), .handler = rkisp1_ext_params_sdg, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_GAIN] = { - .size = sizeof(struct rkisp1_ext_params_awb_gain_config), .handler = rkisp1_ext_params_awbg, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_FLT] = { - .size = sizeof(struct rkisp1_ext_params_flt_config), .handler = rkisp1_ext_params_flt, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_BDM] = { - .size = sizeof(struct rkisp1_ext_params_bdm_config), .handler = rkisp1_ext_params_bdm, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_CTK] = { - .size = sizeof(struct rkisp1_ext_params_ctk_config), .handler = rkisp1_ext_params_ctk, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_GOC] = { - .size = sizeof(struct rkisp1_ext_params_goc_config), .handler = rkisp1_ext_params_goc, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_DPF] = { - .size = sizeof(struct rkisp1_ext_params_dpf_config), .handler = rkisp1_ext_params_dpf, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_DPF_STRENGTH] = { - .size = sizeof(struct rkisp1_ext_params_dpf_strength_config), .handler = rkisp1_ext_params_dpfs, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_CPROC] = { - .size = sizeof(struct rkisp1_ext_params_cproc_config), .handler = rkisp1_ext_params_cproc, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_IE] = { - .size = sizeof(struct rkisp1_ext_params_ie_config), .handler = rkisp1_ext_params_ie, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_LSC] = { - .size = sizeof(struct rkisp1_ext_params_lsc_config), .handler = rkisp1_ext_params_lsc, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_LSC, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_AWB_MEAS] = { - .size = sizeof(struct rkisp1_ext_params_awb_meas_config), .handler = rkisp1_ext_params_awbm, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_HST_MEAS] = { - .size = sizeof(struct rkisp1_ext_params_hst_config), .handler = rkisp1_ext_params_hstm, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_AEC_MEAS] = { - .size = sizeof(struct rkisp1_ext_params_aec_config), .handler = rkisp1_ext_params_aecm, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_AFC_MEAS] = { - .size = sizeof(struct rkisp1_ext_params_afc_config), .handler = rkisp1_ext_params_afcm, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_BLS] = { - .size = sizeof(struct rkisp1_ext_params_compand_bls_config), .handler = rkisp1_ext_params_compand_bls, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, .features = RKISP1_FEATURE_COMPAND, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_EXPAND] = { - .size = sizeof(struct rkisp1_ext_params_compand_curve_config), .handler = rkisp1_ext_params_compand_expand, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, .features = RKISP1_FEATURE_COMPAND, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_COMPAND_COMPRESS] = { - .size = sizeof(struct rkisp1_ext_params_compand_curve_config), .handler = rkisp1_ext_params_compand_compress, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, .features = RKISP1_FEATURE_COMPAND, }, [RKISP1_EXT_PARAMS_BLOCK_TYPE_WDR] = { - .size = sizeof(struct rkisp1_ext_params_wdr_config), .handler = rkisp1_ext_params_wdr, .group = RKISP1_EXT_PARAMS_BLOCK_GROUP_OTHERS, }, }; +#define RKISP1_PARAMS_BLOCK_INFO(block, data) \ + [RKISP1_EXT_PARAMS_BLOCK_TYPE_ ## block] = { \ + .size = sizeof(struct rkisp1_ext_params_ ## data ## _config), \ + } + +static const struct v4l2_isp_params_block_type_info +rkisp1_ext_params_block_types_info[] = { + RKISP1_PARAMS_BLOCK_INFO(BLS, bls), + RKISP1_PARAMS_BLOCK_INFO(DPCC, dpcc), + RKISP1_PARAMS_BLOCK_INFO(SDG, sdg), + RKISP1_PARAMS_BLOCK_INFO(AWB_GAIN, awb_gain), + RKISP1_PARAMS_BLOCK_INFO(FLT, flt), + RKISP1_PARAMS_BLOCK_INFO(BDM, bdm), + RKISP1_PARAMS_BLOCK_INFO(CTK, ctk), + RKISP1_PARAMS_BLOCK_INFO(GOC, goc), + RKISP1_PARAMS_BLOCK_INFO(DPF, dpf), + RKISP1_PARAMS_BLOCK_INFO(DPF_STRENGTH, dpf_strength), + RKISP1_PARAMS_BLOCK_INFO(CPROC, cproc), + RKISP1_PARAMS_BLOCK_INFO(IE, ie), + RKISP1_PARAMS_BLOCK_INFO(LSC, lsc), + RKISP1_PARAMS_BLOCK_INFO(AWB_MEAS, awb_meas), + RKISP1_PARAMS_BLOCK_INFO(HST_MEAS, hst), + RKISP1_PARAMS_BLOCK_INFO(AEC_MEAS, aec), + RKISP1_PARAMS_BLOCK_INFO(AFC_MEAS, afc), + RKISP1_PARAMS_BLOCK_INFO(COMPAND_BLS, compand_bls), + RKISP1_PARAMS_BLOCK_INFO(COMPAND_EXPAND, compand_curve), + RKISP1_PARAMS_BLOCK_INFO(COMPAND_COMPRESS, compand_curve), + RKISP1_PARAMS_BLOCK_INFO(WDR, wdr), +}; + +static_assert(ARRAY_SIZE(rkisp1_ext_params_handlers) == + ARRAY_SIZE(rkisp1_ext_params_block_types_info)); + static void rkisp1_ext_params_config(struct rkisp1_params *params, struct rkisp1_ext_params_cfg *cfg, u32 block_group_mask) @@ -2646,31 +2659,16 @@ static int rkisp1_params_prepare_ext_params(struct rkisp1_params *params, { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct rkisp1_params_buffer *params_buf = to_rkisp1_params_buffer(vbuf); - size_t header_size = offsetof(struct rkisp1_ext_params_cfg, data); struct rkisp1_ext_params_cfg *cfg = params_buf->cfg; size_t payload_size = vb2_get_plane_payload(vb, 0); struct rkisp1_ext_params_cfg *usr_cfg = vb2_plane_vaddr(&vbuf->vb2_buf, 0); - size_t block_offset = 0; - size_t cfg_size; - - /* - * Validate the buffer payload size before copying the parameters. The - * payload has to be smaller than the destination buffer size and larger - * than the header size. - */ - if (payload_size > params->metafmt->buffersize) { - dev_dbg(params->rkisp1->dev, - "Too large buffer payload size %zu\n", payload_size); - return -EINVAL; - } + int ret; - if (payload_size < header_size) { - dev_dbg(params->rkisp1->dev, - "Buffer payload %zu smaller than header size %zu\n", - payload_size, header_size); - return -EINVAL; - } + ret = v4l2_isp_params_validate_buffer_size(params->rkisp1->dev, vb, + params->metafmt->buffersize); + if (ret) + return ret; /* * Copy the parameters buffer to the internal scratch buffer to avoid @@ -2678,71 +2676,10 @@ static int rkisp1_params_prepare_ext_params(struct rkisp1_params *params, */ memcpy(cfg, usr_cfg, payload_size); - /* Only v1 is supported at the moment. */ - if (cfg->version != RKISP1_EXT_PARAM_BUFFER_V1) { - dev_dbg(params->rkisp1->dev, - "Unsupported extensible format version: %u\n", - cfg->version); - return -EINVAL; - } - - /* Validate the size reported in the parameters buffer header. */ - cfg_size = header_size + cfg->data_size; - if (cfg_size != payload_size) { - dev_dbg(params->rkisp1->dev, - "Data size %zu different than buffer payload size %zu\n", - cfg_size, payload_size); - return -EINVAL; - } - - /* Walk the list of parameter blocks and validate them. */ - cfg_size = cfg->data_size; - while (cfg_size >= sizeof(struct rkisp1_ext_params_block_header)) { - const struct rkisp1_ext_params_block_header *block; - const struct rkisp1_ext_params_handler *handler; - - block = (const struct rkisp1_ext_params_block_header *) - &cfg->data[block_offset]; - - if (block->type >= ARRAY_SIZE(rkisp1_ext_params_handlers)) { - dev_dbg(params->rkisp1->dev, - "Invalid parameters block type\n"); - return -EINVAL; - } - - if (block->size > cfg_size) { - dev_dbg(params->rkisp1->dev, - "Premature end of parameters data\n"); - return -EINVAL; - } - - if ((block->flags & (RKISP1_EXT_PARAMS_FL_BLOCK_ENABLE | - RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE)) == - (RKISP1_EXT_PARAMS_FL_BLOCK_ENABLE | - RKISP1_EXT_PARAMS_FL_BLOCK_DISABLE)) { - dev_dbg(params->rkisp1->dev, - "Invalid parameters block flags\n"); - return -EINVAL; - } - - handler = &rkisp1_ext_params_handlers[block->type]; - if (block->size != handler->size) { - dev_dbg(params->rkisp1->dev, - "Invalid parameters block size\n"); - return -EINVAL; - } - - block_offset += block->size; - cfg_size -= block->size; - } - - if (cfg_size) { - dev_dbg(params->rkisp1->dev, - "Unexpected data after the parameters buffer end\n"); - return -EINVAL; - } - - return 0; + return v4l2_isp_params_validate_buffer(params->rkisp1->dev, vb, + (struct v4l2_isp_params_buffer *)cfg, + rkisp1_ext_params_block_types_info, + ARRAY_SIZE(rkisp1_ext_params_block_types_info)); } static int rkisp1_params_vb2_buf_prepare(struct vb2_buffer *vb) diff --git a/drivers/media/platform/rockchip/rkvdec/Makefile b/drivers/media/platform/rockchip/rkvdec/Makefile index cb86b429cfaa..a77122641d14 100644 --- a/drivers/media/platform/rockchip/rkvdec/Makefile +++ b/drivers/media/platform/rockchip/rkvdec/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rockchip-vdec.o -rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-vp9.o +rockchip-vdec-y += rkvdec.o rkvdec-h264.o rkvdec-hevc.o rkvdec-vp9.o diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c new file mode 100644 index 000000000000..eac4ea604949 --- /dev/null +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-data.c @@ -0,0 +1,1848 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Video Decoder driver + * + * Copyright (C) 2023 Collabora, Ltd. + * Sebastian Fricke <sebastian.fricke@collabora.com> + */ + +#include <linux/types.h> + +#define RKV_CABAC_TABLE_SIZE 27456 + +/* + * This file is #include from rkvdec-hevc.c and not compiled. + */ +static const u8 rkvdec_hevc_cabac_table[RKV_CABAC_TABLE_SIZE] = { + 0x07, 0x0f, 0x48, 0x58, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f, + 0x68, 0x48, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x40, + 0x40, 0x68, 0x58, 0x60, 0x40, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x60, + 0x60, 0x50, 0x58, 0x50, 0x07, 0x58, 0x68, 0x50, 0x58, 0x68, 0x68, 0x68, 0x68, 0x68, 0x50, + 0x48, 0x68, 0x60, 0x60, 0x50, 0x58, 0x50, 0x07, 0x58, 0x68, 0x50, 0x58, 0x68, 0x68, 0x68, + 0x68, 0x68, 0x50, 0x48, 0x68, 0x48, 0x48, 0x1f, 0x58, 0x68, 0x68, 0x58, 0x60, 0x60, 0x60, + 0x50, 0x50, 0x50, 0x48, 0x58, 0x58, 0x37, 0x07, 0x58, 0x48, 0x58, 0x58, 0x37, 0x07, 0x58, + 0x48, 0x58, 0x58, 0x37, 0x07, 0x58, 0x50, 0x48, 0x1f, 0x1f, 0x0f, 0x0f, 0x0f, 0x0f, 0x07, + 0x0f, 0x48, 0x68, 0x0f, 0x48, 0x68, 0x40, 0x40, 0x50, 0x50, 0x07, 0x40, 0x50, 0x0f, 0x40, + 0x48, 0x07, 0x40, 0x27, 0x50, 0x48, 0x48, 0x40, 0x0f, 0x50, 0x37, 0x1f, 0x1f, 0x50, 0x37, + 0x40, 0x27, 0x40, 0x07, 0x0f, 0x17, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0f, 0x47, 0x57, + 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x40, 0x0f, 0x66, 0x47, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x00, 0x00, 0x67, 0x57, 0x5e, + 0x00, 0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x47, 0x5f, 0x5f, 0x4f, 0x57, 0x4f, + 0x07, 0x57, 0x67, 0x4f, 0x57, 0x67, 0x67, 0x67, 0x67, 0x66, 0x4f, 0x47, 0x66, 0x5f, 0x5f, + 0x4f, 0x57, 0x4f, 0x07, 0x57, 0x67, 0x4f, 0x57, 0x67, 0x67, 0x67, 0x67, 0x66, 0x4f, 0x47, + 0x66, 0x46, 0x48, 0x20, 0x57, 0x67, 0x67, 0x57, 0x5f, 0x5f, 0x5e, 0x4f, 0x4f, 0x4f, 0x47, + 0x57, 0x57, 0x37, 0x07, 0x57, 0x47, 0x57, 0x57, 0x37, 0x07, 0x57, 0x47, 0x57, 0x57, 0x37, + 0x07, 0x57, 0x4f, 0x47, 0x1f, 0x1f, 0x0f, 0x10, 0x0f, 0x10, 0x07, 0x10, 0x47, 0x67, 0x10, + 0x47, 0x67, 0x40, 0x40, 0x4f, 0x4e, 0x08, 0x00, 0x4f, 0x0f, 0x00, 0x47, 0x07, 0x01, 0x27, + 0x4e, 0x47, 0x47, 0x00, 0x0f, 0x4f, 0x37, 0x1f, 0x1f, 0x4f, 0x36, 0x00, 0x27, 0x00, 0x07, + 0x10, 0x17, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0e, 0x47, 0x57, 0x58, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x0e, 0x40, 0x40, 0x40, 0x0e, 0x64, 0x47, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x00, 0x00, 0x66, 0x57, 0x5d, 0x00, 0x1e, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x47, 0x47, 0x5e, 0x5e, 0x4e, 0x56, 0x4f, 0x07, 0x56, 0x66, 0x4f, + 0x56, 0x66, 0x67, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x64, 0x5e, 0x5e, 0x4e, 0x56, 0x4f, 0x07, + 0x56, 0x66, 0x4f, 0x56, 0x66, 0x67, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x64, 0x45, 0x48, 0x20, + 0x57, 0x66, 0x66, 0x56, 0x5e, 0x5e, 0x5d, 0x4e, 0x4e, 0x4e, 0x46, 0x56, 0x57, 0x36, 0x07, + 0x56, 0x46, 0x56, 0x57, 0x36, 0x07, 0x56, 0x46, 0x56, 0x57, 0x36, 0x07, 0x56, 0x4f, 0x47, + 0x1e, 0x1e, 0x0f, 0x10, 0x0f, 0x10, 0x07, 0x10, 0x47, 0x66, 0x10, 0x47, 0x66, 0x40, 0x40, + 0x4f, 0x4d, 0x08, 0x00, 0x4f, 0x0f, 0x00, 0x47, 0x07, 0x03, 0x27, 0x4d, 0x47, 0x46, 0x01, + 0x0f, 0x4f, 0x36, 0x1f, 0x1e, 0x4f, 0x34, 0x01, 0x26, 0x00, 0x07, 0x10, 0x17, 0x0f, 0x0f, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x0d, 0x47, 0x57, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0e, 0x40, + 0x40, 0x40, 0x0e, 0x62, 0x47, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x07, 0x00, 0x00, 0x65, 0x57, 0x5c, 0x00, 0x1e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x47, 0x47, 0x5d, 0x5d, 0x4e, 0x56, 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x55, 0x65, 0x67, 0x66, + 0x65, 0x63, 0x4d, 0x46, 0x62, 0x5d, 0x5d, 0x4e, 0x56, 0x4f, 0x07, 0x56, 0x66, 0x4f, 0x55, + 0x65, 0x67, 0x66, 0x65, 0x63, 0x4d, 0x46, 0x62, 0x44, 0x48, 0x20, 0x57, 0x65, 0x65, 0x56, + 0x5d, 0x5d, 0x5c, 0x4e, 0x4d, 0x4e, 0x45, 0x56, 0x57, 0x36, 0x07, 0x56, 0x45, 0x56, 0x57, + 0x36, 0x07, 0x56, 0x45, 0x56, 0x57, 0x36, 0x07, 0x56, 0x4f, 0x47, 0x1e, 0x1e, 0x0f, 0x10, + 0x0f, 0x10, 0x07, 0x10, 0x47, 0x65, 0x10, 0x47, 0x65, 0x40, 0x40, 0x4f, 0x4c, 0x08, 0x00, + 0x4f, 0x0f, 0x00, 0x47, 0x07, 0x04, 0x27, 0x4c, 0x47, 0x45, 0x01, 0x0f, 0x4f, 0x36, 0x1f, + 0x1e, 0x4f, 0x33, 0x01, 0x25, 0x00, 0x07, 0x10, 0x17, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x0c, 0x46, 0x56, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0d, 0x40, 0x40, 0x40, 0x0d, 0x60, + 0x46, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x01, 0x01, + 0x64, 0x56, 0x5b, 0x01, 0x1d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x5c, 0x5c, + 0x4d, 0x55, 0x4e, 0x07, 0x55, 0x65, 0x4e, 0x54, 0x64, 0x66, 0x65, 0x64, 0x61, 0x4c, 0x45, + 0x60, 0x5c, 0x5c, 0x4d, 0x55, 0x4e, 0x07, 0x55, 0x65, 0x4e, 0x54, 0x64, 0x66, 0x65, 0x64, + 0x61, 0x4c, 0x45, 0x60, 0x43, 0x49, 0x21, 0x56, 0x64, 0x64, 0x55, 0x5c, 0x5c, 0x5b, 0x4d, + 0x4c, 0x4d, 0x44, 0x55, 0x56, 0x35, 0x07, 0x55, 0x44, 0x55, 0x56, 0x35, 0x07, 0x55, 0x44, + 0x55, 0x56, 0x35, 0x07, 0x55, 0x4e, 0x46, 0x1d, 0x1d, 0x0f, 0x11, 0x0f, 0x11, 0x07, 0x11, + 0x46, 0x64, 0x11, 0x46, 0x64, 0x40, 0x40, 0x4e, 0x4b, 0x09, 0x01, 0x4e, 0x0f, 0x01, 0x46, + 0x07, 0x06, 0x27, 0x4b, 0x46, 0x44, 0x02, 0x0f, 0x4e, 0x35, 0x1e, 0x1d, 0x4e, 0x31, 0x02, + 0x24, 0x01, 0x07, 0x11, 0x16, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0b, 0x46, 0x56, 0x58, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x0c, 0x40, 0x40, 0x40, 0x0c, 0x5e, 0x46, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x01, 0x01, 0x63, 0x56, 0x59, 0x01, + 0x1c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x5b, 0x5b, 0x4c, 0x54, 0x4e, 0x07, + 0x54, 0x64, 0x4e, 0x53, 0x63, 0x66, 0x64, 0x63, 0x60, 0x4b, 0x44, 0x5e, 0x5b, 0x5b, 0x4c, + 0x54, 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x53, 0x63, 0x66, 0x64, 0x63, 0x60, 0x4b, 0x44, 0x5e, + 0x41, 0x49, 0x21, 0x56, 0x63, 0x63, 0x54, 0x5b, 0x5b, 0x59, 0x4c, 0x4b, 0x4c, 0x43, 0x54, + 0x56, 0x34, 0x07, 0x54, 0x43, 0x54, 0x56, 0x34, 0x07, 0x54, 0x43, 0x54, 0x56, 0x34, 0x07, + 0x54, 0x4e, 0x46, 0x1c, 0x1c, 0x0f, 0x11, 0x0f, 0x11, 0x07, 0x11, 0x46, 0x63, 0x11, 0x46, + 0x63, 0x40, 0x40, 0x4e, 0x49, 0x09, 0x01, 0x4e, 0x0f, 0x01, 0x46, 0x07, 0x07, 0x27, 0x49, + 0x46, 0x43, 0x03, 0x0f, 0x4e, 0x34, 0x1e, 0x1c, 0x4e, 0x30, 0x03, 0x23, 0x01, 0x07, 0x11, + 0x16, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0a, 0x46, 0x56, 0x58, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x0c, 0x40, 0x40, 0x40, 0x0c, 0x5c, 0x46, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x07, 0x01, 0x01, 0x62, 0x56, 0x58, 0x01, 0x1c, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x46, 0x46, 0x5a, 0x5a, 0x4c, 0x54, 0x4e, 0x07, 0x54, 0x64, 0x4e, 0x52, + 0x62, 0x66, 0x64, 0x62, 0x5e, 0x4a, 0x44, 0x5c, 0x5a, 0x5a, 0x4c, 0x54, 0x4e, 0x07, 0x54, + 0x64, 0x4e, 0x52, 0x62, 0x66, 0x64, 0x62, 0x5e, 0x4a, 0x44, 0x5c, 0x40, 0x49, 0x21, 0x56, + 0x62, 0x62, 0x54, 0x5a, 0x5a, 0x58, 0x4c, 0x4a, 0x4c, 0x42, 0x54, 0x56, 0x34, 0x07, 0x54, + 0x42, 0x54, 0x56, 0x34, 0x07, 0x54, 0x42, 0x54, 0x56, 0x34, 0x07, 0x54, 0x4e, 0x46, 0x1c, + 0x1c, 0x0f, 0x11, 0x0f, 0x11, 0x07, 0x11, 0x46, 0x62, 0x11, 0x46, 0x62, 0x40, 0x40, 0x4e, + 0x48, 0x09, 0x01, 0x4e, 0x0f, 0x01, 0x46, 0x07, 0x09, 0x27, 0x48, 0x46, 0x42, 0x03, 0x0f, + 0x4e, 0x34, 0x1e, 0x1c, 0x4e, 0x2e, 0x03, 0x22, 0x01, 0x07, 0x11, 0x16, 0x0f, 0x0f, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x09, 0x45, 0x55, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0b, 0x40, 0x40, + 0x40, 0x0b, 0x5a, 0x45, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x07, 0x02, 0x02, 0x61, 0x55, 0x57, 0x02, 0x1b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, + 0x45, 0x59, 0x59, 0x4b, 0x53, 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x51, 0x61, 0x65, 0x63, 0x61, + 0x5d, 0x49, 0x43, 0x5a, 0x59, 0x59, 0x4b, 0x53, 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x51, 0x61, + 0x65, 0x63, 0x61, 0x5d, 0x49, 0x43, 0x5a, 0x00, 0x4a, 0x22, 0x55, 0x61, 0x61, 0x53, 0x59, + 0x59, 0x57, 0x4b, 0x49, 0x4b, 0x41, 0x53, 0x55, 0x33, 0x07, 0x53, 0x41, 0x53, 0x55, 0x33, + 0x07, 0x53, 0x41, 0x53, 0x55, 0x33, 0x07, 0x53, 0x4d, 0x45, 0x1b, 0x1b, 0x0f, 0x12, 0x0f, + 0x12, 0x07, 0x12, 0x45, 0x61, 0x12, 0x45, 0x61, 0x40, 0x40, 0x4d, 0x47, 0x0a, 0x02, 0x4d, + 0x0f, 0x02, 0x45, 0x07, 0x0a, 0x27, 0x47, 0x45, 0x41, 0x04, 0x0f, 0x4d, 0x33, 0x1d, 0x1b, + 0x4d, 0x2d, 0x04, 0x21, 0x02, 0x07, 0x12, 0x15, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x08, + 0x45, 0x55, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0a, 0x40, 0x40, 0x40, 0x0a, 0x59, 0x45, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x02, 0x02, 0x60, + 0x55, 0x56, 0x02, 0x1a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x58, 0x58, 0x4b, + 0x53, 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x50, 0x60, 0x65, 0x63, 0x60, 0x5b, 0x48, 0x43, 0x59, + 0x58, 0x58, 0x4b, 0x53, 0x4d, 0x07, 0x53, 0x63, 0x4d, 0x50, 0x60, 0x65, 0x63, 0x60, 0x5b, + 0x48, 0x43, 0x59, 0x01, 0x4a, 0x22, 0x55, 0x60, 0x60, 0x53, 0x58, 0x58, 0x56, 0x4b, 0x48, + 0x4b, 0x40, 0x53, 0x55, 0x32, 0x07, 0x53, 0x40, 0x53, 0x55, 0x32, 0x07, 0x53, 0x40, 0x53, + 0x55, 0x32, 0x07, 0x53, 0x4d, 0x45, 0x1a, 0x1a, 0x0f, 0x12, 0x0f, 0x12, 0x07, 0x12, 0x45, + 0x60, 0x12, 0x45, 0x60, 0x40, 0x40, 0x4d, 0x46, 0x0a, 0x02, 0x4d, 0x0f, 0x02, 0x45, 0x07, + 0x0c, 0x27, 0x46, 0x45, 0x40, 0x04, 0x0f, 0x4d, 0x32, 0x1d, 0x1a, 0x4d, 0x2b, 0x04, 0x20, + 0x02, 0x07, 0x12, 0x15, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x45, 0x55, 0x58, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x0a, 0x40, 0x40, 0x40, 0x0a, 0x57, 0x45, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x02, 0x02, 0x5f, 0x55, 0x54, 0x02, 0x1a, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x57, 0x57, 0x4a, 0x52, 0x4d, 0x07, 0x52, + 0x62, 0x4d, 0x4f, 0x5f, 0x65, 0x62, 0x5f, 0x59, 0x47, 0x42, 0x57, 0x57, 0x57, 0x4a, 0x52, + 0x4d, 0x07, 0x52, 0x62, 0x4d, 0x4f, 0x5f, 0x65, 0x62, 0x5f, 0x59, 0x47, 0x42, 0x57, 0x03, + 0x4a, 0x22, 0x55, 0x5f, 0x5f, 0x52, 0x57, 0x57, 0x54, 0x4a, 0x47, 0x4a, 0x00, 0x52, 0x55, + 0x32, 0x07, 0x52, 0x00, 0x52, 0x55, 0x32, 0x07, 0x52, 0x00, 0x52, 0x55, 0x32, 0x07, 0x52, + 0x4d, 0x45, 0x1a, 0x1a, 0x0f, 0x12, 0x0f, 0x12, 0x07, 0x12, 0x45, 0x5f, 0x12, 0x45, 0x5f, + 0x40, 0x40, 0x4d, 0x44, 0x0a, 0x02, 0x4d, 0x0f, 0x02, 0x45, 0x07, 0x0e, 0x27, 0x44, 0x45, + 0x00, 0x05, 0x0f, 0x4d, 0x32, 0x1d, 0x1a, 0x4d, 0x29, 0x05, 0x1f, 0x02, 0x07, 0x12, 0x15, + 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x44, 0x54, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x09, 0x40, 0x40, 0x40, 0x09, 0x55, 0x44, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x07, 0x03, 0x03, 0x5e, 0x54, 0x53, 0x03, 0x19, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x44, 0x44, 0x56, 0x56, 0x49, 0x51, 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4e, 0x5e, + 0x64, 0x61, 0x5e, 0x58, 0x46, 0x41, 0x55, 0x56, 0x56, 0x49, 0x51, 0x4c, 0x07, 0x51, 0x61, + 0x4c, 0x4e, 0x5e, 0x64, 0x61, 0x5e, 0x58, 0x46, 0x41, 0x55, 0x04, 0x4b, 0x23, 0x54, 0x5e, + 0x5e, 0x51, 0x56, 0x56, 0x53, 0x49, 0x46, 0x49, 0x01, 0x51, 0x54, 0x31, 0x07, 0x51, 0x01, + 0x51, 0x54, 0x31, 0x07, 0x51, 0x01, 0x51, 0x54, 0x31, 0x07, 0x51, 0x4c, 0x44, 0x19, 0x19, + 0x0f, 0x13, 0x0f, 0x13, 0x07, 0x13, 0x44, 0x5e, 0x13, 0x44, 0x5e, 0x40, 0x40, 0x4c, 0x43, + 0x0b, 0x03, 0x4c, 0x0f, 0x03, 0x44, 0x07, 0x0f, 0x27, 0x43, 0x44, 0x01, 0x06, 0x0f, 0x4c, + 0x31, 0x1c, 0x19, 0x4c, 0x28, 0x06, 0x1e, 0x03, 0x07, 0x13, 0x14, 0x0f, 0x0f, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x05, 0x44, 0x54, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x09, 0x40, 0x40, 0x40, + 0x09, 0x53, 0x44, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, + 0x03, 0x03, 0x5d, 0x54, 0x52, 0x03, 0x19, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, + 0x55, 0x55, 0x49, 0x51, 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4d, 0x5d, 0x64, 0x61, 0x5d, 0x56, + 0x45, 0x41, 0x53, 0x55, 0x55, 0x49, 0x51, 0x4c, 0x07, 0x51, 0x61, 0x4c, 0x4d, 0x5d, 0x64, + 0x61, 0x5d, 0x56, 0x45, 0x41, 0x53, 0x05, 0x4b, 0x23, 0x54, 0x5d, 0x5d, 0x51, 0x55, 0x55, + 0x52, 0x49, 0x45, 0x49, 0x02, 0x51, 0x54, 0x31, 0x07, 0x51, 0x02, 0x51, 0x54, 0x31, 0x07, + 0x51, 0x02, 0x51, 0x54, 0x31, 0x07, 0x51, 0x4c, 0x44, 0x19, 0x19, 0x0f, 0x13, 0x0f, 0x13, + 0x07, 0x13, 0x44, 0x5d, 0x13, 0x44, 0x5d, 0x40, 0x40, 0x4c, 0x42, 0x0b, 0x03, 0x4c, 0x0f, + 0x03, 0x44, 0x07, 0x11, 0x27, 0x42, 0x44, 0x02, 0x06, 0x0f, 0x4c, 0x31, 0x1c, 0x19, 0x4c, + 0x26, 0x06, 0x1d, 0x03, 0x07, 0x13, 0x14, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x44, + 0x54, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x08, 0x40, 0x40, 0x40, 0x08, 0x51, 0x44, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x03, 0x03, 0x5c, 0x54, + 0x51, 0x03, 0x18, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x44, 0x54, 0x54, 0x48, 0x50, + 0x4c, 0x07, 0x50, 0x60, 0x4c, 0x4c, 0x5c, 0x64, 0x60, 0x5c, 0x55, 0x44, 0x40, 0x51, 0x54, + 0x54, 0x48, 0x50, 0x4c, 0x07, 0x50, 0x60, 0x4c, 0x4c, 0x5c, 0x64, 0x60, 0x5c, 0x55, 0x44, + 0x40, 0x51, 0x06, 0x4b, 0x23, 0x54, 0x5c, 0x5c, 0x50, 0x54, 0x54, 0x51, 0x48, 0x44, 0x48, + 0x03, 0x50, 0x54, 0x30, 0x07, 0x50, 0x03, 0x50, 0x54, 0x30, 0x07, 0x50, 0x03, 0x50, 0x54, + 0x30, 0x07, 0x50, 0x4c, 0x44, 0x18, 0x18, 0x0f, 0x13, 0x0f, 0x13, 0x07, 0x13, 0x44, 0x5c, + 0x13, 0x44, 0x5c, 0x40, 0x40, 0x4c, 0x41, 0x0b, 0x03, 0x4c, 0x0f, 0x03, 0x44, 0x07, 0x12, + 0x27, 0x41, 0x44, 0x03, 0x07, 0x0f, 0x4c, 0x30, 0x1c, 0x18, 0x4c, 0x25, 0x07, 0x1c, 0x03, + 0x07, 0x13, 0x14, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x43, 0x53, 0x58, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x07, 0x40, 0x40, 0x40, 0x07, 0x4f, 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x5b, 0x53, 0x4f, 0x04, 0x17, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x53, 0x53, 0x47, 0x4f, 0x4b, 0x07, 0x4f, 0x5f, + 0x4b, 0x4b, 0x5b, 0x63, 0x5f, 0x5b, 0x53, 0x43, 0x00, 0x4f, 0x53, 0x53, 0x47, 0x4f, 0x4b, + 0x07, 0x4f, 0x5f, 0x4b, 0x4b, 0x5b, 0x63, 0x5f, 0x5b, 0x53, 0x43, 0x00, 0x4f, 0x08, 0x4c, + 0x24, 0x53, 0x5b, 0x5b, 0x4f, 0x53, 0x53, 0x4f, 0x47, 0x43, 0x47, 0x04, 0x4f, 0x53, 0x2f, + 0x07, 0x4f, 0x04, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x04, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x4b, + 0x43, 0x17, 0x17, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x5b, 0x14, 0x43, 0x5b, 0x40, + 0x40, 0x4b, 0x00, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x14, 0x27, 0x00, 0x43, 0x04, + 0x08, 0x0f, 0x4b, 0x2f, 0x1b, 0x17, 0x4b, 0x23, 0x08, 0x1b, 0x04, 0x07, 0x14, 0x13, 0x0f, + 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, + 0x40, 0x40, 0x40, 0x07, 0x4d, 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x07, 0x04, 0x04, 0x5a, 0x53, 0x4e, 0x04, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x43, 0x43, 0x52, 0x52, 0x47, 0x4f, 0x4b, 0x07, 0x4f, 0x5f, 0x4b, 0x4a, 0x5a, 0x63, + 0x5f, 0x5a, 0x52, 0x42, 0x00, 0x4d, 0x52, 0x52, 0x47, 0x4f, 0x4b, 0x07, 0x4f, 0x5f, 0x4b, + 0x4a, 0x5a, 0x63, 0x5f, 0x5a, 0x52, 0x42, 0x00, 0x4d, 0x09, 0x4c, 0x24, 0x53, 0x5a, 0x5a, + 0x4f, 0x52, 0x52, 0x4e, 0x47, 0x42, 0x47, 0x05, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x05, 0x4f, + 0x53, 0x2f, 0x07, 0x4f, 0x05, 0x4f, 0x53, 0x2f, 0x07, 0x4f, 0x4b, 0x43, 0x17, 0x17, 0x0f, + 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x5a, 0x14, 0x43, 0x5a, 0x40, 0x40, 0x4b, 0x01, 0x0c, + 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x15, 0x27, 0x01, 0x43, 0x05, 0x08, 0x0f, 0x4b, 0x2f, + 0x1b, 0x17, 0x4b, 0x22, 0x08, 0x1a, 0x04, 0x07, 0x14, 0x13, 0x0f, 0x0f, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x01, 0x43, 0x53, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x40, 0x40, 0x40, 0x06, + 0x4b, 0x43, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, + 0x04, 0x59, 0x53, 0x4d, 0x04, 0x16, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x51, + 0x51, 0x46, 0x4e, 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x50, 0x41, + 0x01, 0x4b, 0x51, 0x51, 0x46, 0x4e, 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, + 0x59, 0x50, 0x41, 0x01, 0x4b, 0x0a, 0x4c, 0x24, 0x53, 0x59, 0x59, 0x4e, 0x51, 0x51, 0x4d, + 0x46, 0x41, 0x46, 0x06, 0x4e, 0x53, 0x2e, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2e, 0x07, 0x4e, + 0x06, 0x4e, 0x53, 0x2e, 0x07, 0x4e, 0x4b, 0x43, 0x16, 0x16, 0x0f, 0x14, 0x0f, 0x14, 0x07, + 0x14, 0x43, 0x59, 0x14, 0x43, 0x59, 0x40, 0x40, 0x4b, 0x02, 0x0c, 0x04, 0x4b, 0x0f, 0x04, + 0x43, 0x07, 0x17, 0x27, 0x02, 0x43, 0x06, 0x09, 0x0f, 0x4b, 0x2e, 0x1b, 0x16, 0x4b, 0x20, + 0x09, 0x19, 0x04, 0x07, 0x14, 0x13, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x43, 0x53, + 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x40, 0x40, 0x40, 0x05, 0x4a, 0x43, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x04, 0x04, 0x59, 0x53, 0x4c, + 0x04, 0x15, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x43, 0x51, 0x51, 0x46, 0x4e, 0x4b, + 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x4f, 0x41, 0x01, 0x4a, 0x51, 0x51, + 0x46, 0x4e, 0x4b, 0x07, 0x4e, 0x5e, 0x4b, 0x49, 0x59, 0x63, 0x5e, 0x59, 0x4f, 0x41, 0x01, + 0x4a, 0x0b, 0x4d, 0x24, 0x53, 0x59, 0x59, 0x4e, 0x51, 0x51, 0x4c, 0x46, 0x41, 0x46, 0x06, + 0x4e, 0x53, 0x2d, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2d, 0x07, 0x4e, 0x06, 0x4e, 0x53, 0x2d, + 0x07, 0x4e, 0x4b, 0x43, 0x15, 0x15, 0x0f, 0x14, 0x0f, 0x14, 0x07, 0x14, 0x43, 0x59, 0x14, + 0x43, 0x59, 0x40, 0x40, 0x4b, 0x03, 0x0c, 0x04, 0x4b, 0x0f, 0x04, 0x43, 0x07, 0x18, 0x27, + 0x03, 0x43, 0x06, 0x09, 0x0f, 0x4b, 0x2d, 0x1a, 0x15, 0x4b, 0x1e, 0x09, 0x18, 0x04, 0x07, + 0x14, 0x12, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x42, 0x52, 0x58, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x05, 0x40, 0x40, 0x40, 0x05, 0x48, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x05, 0x05, 0x58, 0x52, 0x4a, 0x05, 0x15, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x50, 0x50, 0x45, 0x4d, 0x4a, 0x07, 0x4d, 0x5d, 0x4a, + 0x48, 0x58, 0x62, 0x5d, 0x58, 0x4d, 0x40, 0x02, 0x48, 0x50, 0x50, 0x45, 0x4d, 0x4a, 0x07, + 0x4d, 0x5d, 0x4a, 0x48, 0x58, 0x62, 0x5d, 0x58, 0x4d, 0x40, 0x02, 0x48, 0x0d, 0x4d, 0x25, + 0x52, 0x58, 0x58, 0x4d, 0x50, 0x50, 0x4a, 0x45, 0x40, 0x45, 0x07, 0x4d, 0x52, 0x2d, 0x07, + 0x4d, 0x07, 0x4d, 0x52, 0x2d, 0x07, 0x4d, 0x07, 0x4d, 0x52, 0x2d, 0x07, 0x4d, 0x4a, 0x42, + 0x15, 0x15, 0x0f, 0x15, 0x0f, 0x15, 0x07, 0x15, 0x42, 0x58, 0x15, 0x42, 0x58, 0x40, 0x40, + 0x4a, 0x05, 0x0d, 0x05, 0x4a, 0x0f, 0x05, 0x42, 0x07, 0x1a, 0x27, 0x05, 0x42, 0x07, 0x0a, + 0x0f, 0x4a, 0x2d, 0x1a, 0x15, 0x4a, 0x1d, 0x0a, 0x18, 0x05, 0x07, 0x15, 0x12, 0x0f, 0x0f, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x40, 0x42, 0x52, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x40, + 0x40, 0x40, 0x04, 0x46, 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x07, 0x05, 0x05, 0x57, 0x52, 0x49, 0x05, 0x14, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x42, 0x42, 0x4f, 0x4f, 0x44, 0x4c, 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x47, 0x57, 0x62, 0x5c, + 0x57, 0x4b, 0x00, 0x03, 0x46, 0x4f, 0x4f, 0x44, 0x4c, 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x47, + 0x57, 0x62, 0x5c, 0x57, 0x4b, 0x00, 0x03, 0x46, 0x0e, 0x4d, 0x25, 0x52, 0x57, 0x57, 0x4c, + 0x4f, 0x4f, 0x49, 0x44, 0x00, 0x44, 0x08, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x08, 0x4c, 0x52, + 0x2c, 0x07, 0x4c, 0x08, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x4a, 0x42, 0x14, 0x14, 0x0f, 0x15, + 0x0f, 0x15, 0x07, 0x15, 0x42, 0x57, 0x15, 0x42, 0x57, 0x40, 0x40, 0x4a, 0x06, 0x0d, 0x05, + 0x4a, 0x0f, 0x05, 0x42, 0x07, 0x1c, 0x27, 0x06, 0x42, 0x08, 0x0b, 0x0f, 0x4a, 0x2c, 0x1a, + 0x14, 0x4a, 0x1b, 0x0b, 0x17, 0x05, 0x07, 0x15, 0x12, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x41, 0x42, 0x52, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x40, 0x40, 0x40, 0x04, 0x44, + 0x42, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x05, 0x05, + 0x56, 0x52, 0x48, 0x05, 0x14, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4e, 0x4e, + 0x44, 0x4c, 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x46, 0x56, 0x62, 0x5c, 0x56, 0x4a, 0x01, 0x03, + 0x44, 0x4e, 0x4e, 0x44, 0x4c, 0x4a, 0x07, 0x4c, 0x5c, 0x4a, 0x46, 0x56, 0x62, 0x5c, 0x56, + 0x4a, 0x01, 0x03, 0x44, 0x0f, 0x4d, 0x25, 0x52, 0x56, 0x56, 0x4c, 0x4e, 0x4e, 0x48, 0x44, + 0x01, 0x44, 0x09, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x09, 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x09, + 0x4c, 0x52, 0x2c, 0x07, 0x4c, 0x4a, 0x42, 0x14, 0x14, 0x0f, 0x15, 0x0f, 0x15, 0x07, 0x15, + 0x42, 0x56, 0x15, 0x42, 0x56, 0x40, 0x40, 0x4a, 0x07, 0x0d, 0x05, 0x4a, 0x0f, 0x05, 0x42, + 0x07, 0x1d, 0x27, 0x07, 0x42, 0x09, 0x0b, 0x0f, 0x4a, 0x2c, 0x1a, 0x14, 0x4a, 0x1a, 0x0b, + 0x16, 0x05, 0x07, 0x15, 0x12, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x42, 0x41, 0x51, 0x58, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x40, 0x40, 0x40, 0x03, 0x42, 0x41, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x06, 0x06, 0x55, 0x51, 0x47, 0x06, + 0x13, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4d, 0x4d, 0x43, 0x4b, 0x49, 0x07, + 0x4b, 0x5b, 0x49, 0x45, 0x55, 0x61, 0x5b, 0x55, 0x48, 0x02, 0x04, 0x42, 0x4d, 0x4d, 0x43, + 0x4b, 0x49, 0x07, 0x4b, 0x5b, 0x49, 0x45, 0x55, 0x61, 0x5b, 0x55, 0x48, 0x02, 0x04, 0x42, + 0x10, 0x4e, 0x26, 0x51, 0x55, 0x55, 0x4b, 0x4d, 0x4d, 0x47, 0x43, 0x02, 0x43, 0x0a, 0x4b, + 0x51, 0x2b, 0x07, 0x4b, 0x0a, 0x4b, 0x51, 0x2b, 0x07, 0x4b, 0x0a, 0x4b, 0x51, 0x2b, 0x07, + 0x4b, 0x49, 0x41, 0x13, 0x13, 0x0f, 0x16, 0x0f, 0x16, 0x07, 0x16, 0x41, 0x55, 0x16, 0x41, + 0x55, 0x40, 0x40, 0x49, 0x08, 0x0e, 0x06, 0x49, 0x0f, 0x06, 0x41, 0x07, 0x1f, 0x27, 0x08, + 0x41, 0x0a, 0x0c, 0x0f, 0x49, 0x2b, 0x19, 0x13, 0x49, 0x18, 0x0c, 0x15, 0x06, 0x07, 0x16, + 0x11, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x43, 0x41, 0x51, 0x58, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x02, 0x40, 0x40, 0x40, 0x02, 0x40, 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x07, 0x06, 0x06, 0x54, 0x51, 0x45, 0x06, 0x12, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x41, 0x41, 0x4c, 0x4c, 0x42, 0x4a, 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x44, + 0x54, 0x61, 0x5a, 0x54, 0x47, 0x03, 0x05, 0x40, 0x4c, 0x4c, 0x42, 0x4a, 0x49, 0x07, 0x4a, + 0x5a, 0x49, 0x44, 0x54, 0x61, 0x5a, 0x54, 0x47, 0x03, 0x05, 0x40, 0x12, 0x4e, 0x26, 0x51, + 0x54, 0x54, 0x4a, 0x4c, 0x4c, 0x45, 0x42, 0x03, 0x42, 0x0b, 0x4a, 0x51, 0x2a, 0x07, 0x4a, + 0x0b, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x0b, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x49, 0x41, 0x12, + 0x12, 0x0f, 0x16, 0x0f, 0x16, 0x07, 0x16, 0x41, 0x54, 0x16, 0x41, 0x54, 0x40, 0x40, 0x49, + 0x0a, 0x0e, 0x06, 0x49, 0x0f, 0x06, 0x41, 0x07, 0x20, 0x27, 0x0a, 0x41, 0x0b, 0x0d, 0x0f, + 0x49, 0x2a, 0x19, 0x12, 0x49, 0x17, 0x0d, 0x14, 0x06, 0x07, 0x16, 0x11, 0x0f, 0x0f, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x44, 0x41, 0x51, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x40, 0x40, + 0x40, 0x02, 0x01, 0x41, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x07, 0x06, 0x06, 0x53, 0x51, 0x44, 0x06, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, + 0x41, 0x4b, 0x4b, 0x42, 0x4a, 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x43, 0x53, 0x61, 0x5a, 0x53, + 0x45, 0x04, 0x05, 0x01, 0x4b, 0x4b, 0x42, 0x4a, 0x49, 0x07, 0x4a, 0x5a, 0x49, 0x43, 0x53, + 0x61, 0x5a, 0x53, 0x45, 0x04, 0x05, 0x01, 0x13, 0x4e, 0x26, 0x51, 0x53, 0x53, 0x4a, 0x4b, + 0x4b, 0x44, 0x42, 0x04, 0x42, 0x0c, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x0c, 0x4a, 0x51, 0x2a, + 0x07, 0x4a, 0x0c, 0x4a, 0x51, 0x2a, 0x07, 0x4a, 0x49, 0x41, 0x12, 0x12, 0x0f, 0x16, 0x0f, + 0x16, 0x07, 0x16, 0x41, 0x53, 0x16, 0x41, 0x53, 0x40, 0x40, 0x49, 0x0b, 0x0e, 0x06, 0x49, + 0x0f, 0x06, 0x41, 0x07, 0x22, 0x27, 0x0b, 0x41, 0x0c, 0x0d, 0x0f, 0x49, 0x2a, 0x19, 0x12, + 0x49, 0x15, 0x0d, 0x13, 0x06, 0x07, 0x16, 0x11, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x45, + 0x40, 0x50, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x40, 0x40, 0x40, 0x01, 0x03, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x52, + 0x50, 0x43, 0x07, 0x11, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4a, 0x4a, 0x41, + 0x49, 0x48, 0x07, 0x49, 0x59, 0x48, 0x42, 0x52, 0x60, 0x59, 0x52, 0x44, 0x05, 0x06, 0x03, + 0x4a, 0x4a, 0x41, 0x49, 0x48, 0x07, 0x49, 0x59, 0x48, 0x42, 0x52, 0x60, 0x59, 0x52, 0x44, + 0x05, 0x06, 0x03, 0x14, 0x4f, 0x27, 0x50, 0x52, 0x52, 0x49, 0x4a, 0x4a, 0x43, 0x41, 0x05, + 0x41, 0x0d, 0x49, 0x50, 0x29, 0x07, 0x49, 0x0d, 0x49, 0x50, 0x29, 0x07, 0x49, 0x0d, 0x49, + 0x50, 0x29, 0x07, 0x49, 0x48, 0x40, 0x11, 0x11, 0x0f, 0x17, 0x0f, 0x17, 0x07, 0x17, 0x40, + 0x52, 0x17, 0x40, 0x52, 0x40, 0x40, 0x48, 0x0c, 0x0f, 0x07, 0x48, 0x0f, 0x07, 0x40, 0x07, + 0x23, 0x27, 0x0c, 0x40, 0x0d, 0x0e, 0x0f, 0x48, 0x29, 0x18, 0x11, 0x48, 0x14, 0x0e, 0x12, + 0x07, 0x07, 0x17, 0x10, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x46, 0x40, 0x50, 0x58, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x40, 0x40, 0x40, 0x00, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x51, 0x50, 0x42, 0x07, 0x10, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x41, 0x49, 0x48, 0x07, 0x49, + 0x59, 0x48, 0x41, 0x51, 0x60, 0x59, 0x51, 0x42, 0x06, 0x06, 0x04, 0x49, 0x49, 0x41, 0x49, + 0x48, 0x07, 0x49, 0x59, 0x48, 0x41, 0x51, 0x60, 0x59, 0x51, 0x42, 0x06, 0x06, 0x04, 0x15, + 0x4f, 0x27, 0x50, 0x51, 0x51, 0x49, 0x49, 0x49, 0x42, 0x41, 0x06, 0x41, 0x0e, 0x49, 0x50, + 0x28, 0x07, 0x49, 0x0e, 0x49, 0x50, 0x28, 0x07, 0x49, 0x0e, 0x49, 0x50, 0x28, 0x07, 0x49, + 0x48, 0x40, 0x10, 0x10, 0x0f, 0x17, 0x0f, 0x17, 0x07, 0x17, 0x40, 0x51, 0x17, 0x40, 0x51, + 0x40, 0x40, 0x48, 0x0d, 0x0f, 0x07, 0x48, 0x0f, 0x07, 0x40, 0x07, 0x25, 0x27, 0x0d, 0x40, + 0x0e, 0x0e, 0x0f, 0x48, 0x28, 0x18, 0x10, 0x48, 0x12, 0x0e, 0x11, 0x07, 0x07, 0x17, 0x10, + 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x47, 0x40, 0x50, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x40, 0x40, 0x40, 0x00, 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x50, 0x50, 0x40, 0x07, 0x10, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x40, 0x48, 0x48, 0x07, 0x48, 0x58, 0x48, 0x40, 0x50, + 0x60, 0x58, 0x50, 0x40, 0x07, 0x07, 0x06, 0x48, 0x48, 0x40, 0x48, 0x48, 0x07, 0x48, 0x58, + 0x48, 0x40, 0x50, 0x60, 0x58, 0x50, 0x40, 0x07, 0x07, 0x06, 0x17, 0x4f, 0x27, 0x50, 0x50, + 0x50, 0x48, 0x48, 0x48, 0x40, 0x40, 0x07, 0x40, 0x0f, 0x48, 0x50, 0x28, 0x07, 0x48, 0x0f, + 0x48, 0x50, 0x28, 0x07, 0x48, 0x0f, 0x48, 0x50, 0x28, 0x07, 0x48, 0x48, 0x40, 0x10, 0x10, + 0x0f, 0x17, 0x0f, 0x17, 0x07, 0x17, 0x40, 0x50, 0x17, 0x40, 0x50, 0x40, 0x40, 0x48, 0x0f, + 0x0f, 0x07, 0x48, 0x0f, 0x07, 0x40, 0x07, 0x27, 0x27, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x48, + 0x28, 0x18, 0x10, 0x48, 0x10, 0x0f, 0x10, 0x07, 0x07, 0x17, 0x10, 0x0f, 0x0f, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x48, 0x00, 0x4f, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x08, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, + 0x08, 0x08, 0x4f, 0x4f, 0x00, 0x08, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x47, 0x47, 0x00, 0x47, 0x47, 0x07, 0x47, 0x57, 0x47, 0x00, 0x4f, 0x5f, 0x57, 0x4f, 0x00, + 0x08, 0x08, 0x08, 0x47, 0x47, 0x00, 0x47, 0x47, 0x07, 0x47, 0x57, 0x47, 0x00, 0x4f, 0x5f, + 0x57, 0x4f, 0x00, 0x08, 0x08, 0x08, 0x18, 0x50, 0x28, 0x4f, 0x4f, 0x4f, 0x47, 0x47, 0x47, + 0x00, 0x00, 0x08, 0x00, 0x10, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x10, 0x47, 0x4f, 0x27, 0x07, + 0x47, 0x10, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x47, 0x00, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x18, + 0x07, 0x18, 0x00, 0x4f, 0x18, 0x00, 0x4f, 0x40, 0x40, 0x47, 0x10, 0x10, 0x08, 0x47, 0x0f, + 0x08, 0x00, 0x07, 0x28, 0x27, 0x10, 0x00, 0x10, 0x10, 0x0f, 0x47, 0x27, 0x17, 0x0f, 0x47, + 0x0f, 0x10, 0x0f, 0x08, 0x07, 0x18, 0x0f, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x49, 0x00, + 0x4f, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0a, 0x00, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x08, 0x08, 0x4e, 0x4f, + 0x01, 0x08, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x46, 0x46, 0x00, 0x47, + 0x47, 0x07, 0x47, 0x57, 0x47, 0x01, 0x4e, 0x5f, 0x57, 0x4e, 0x02, 0x09, 0x08, 0x0a, 0x46, + 0x46, 0x00, 0x47, 0x47, 0x07, 0x47, 0x57, 0x47, 0x01, 0x4e, 0x5f, 0x57, 0x4e, 0x02, 0x09, + 0x08, 0x0a, 0x19, 0x50, 0x28, 0x4f, 0x4e, 0x4e, 0x47, 0x46, 0x46, 0x01, 0x00, 0x09, 0x00, + 0x11, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x11, 0x47, 0x4f, 0x27, 0x07, 0x47, 0x11, 0x47, 0x4f, + 0x27, 0x07, 0x47, 0x47, 0x00, 0x0f, 0x0f, 0x0f, 0x18, 0x0f, 0x18, 0x07, 0x18, 0x00, 0x4e, + 0x18, 0x00, 0x4e, 0x40, 0x40, 0x47, 0x11, 0x10, 0x08, 0x47, 0x0f, 0x08, 0x00, 0x07, 0x2a, + 0x27, 0x11, 0x00, 0x11, 0x10, 0x0f, 0x47, 0x27, 0x17, 0x0f, 0x47, 0x0d, 0x10, 0x0e, 0x08, + 0x07, 0x18, 0x0f, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4a, 0x00, 0x4f, 0x58, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x41, 0x40, 0x40, 0x40, 0x41, 0x0c, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x08, 0x08, 0x4d, 0x4f, 0x02, 0x08, 0x0e, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x45, 0x45, 0x01, 0x46, 0x47, 0x07, 0x46, 0x56, + 0x47, 0x02, 0x4d, 0x5f, 0x56, 0x4d, 0x03, 0x0a, 0x09, 0x0c, 0x45, 0x45, 0x01, 0x46, 0x47, + 0x07, 0x46, 0x56, 0x47, 0x02, 0x4d, 0x5f, 0x56, 0x4d, 0x03, 0x0a, 0x09, 0x0c, 0x1a, 0x50, + 0x28, 0x4f, 0x4d, 0x4d, 0x46, 0x45, 0x45, 0x02, 0x01, 0x0a, 0x01, 0x12, 0x46, 0x4f, 0x26, + 0x07, 0x46, 0x12, 0x46, 0x4f, 0x26, 0x07, 0x46, 0x12, 0x46, 0x4f, 0x26, 0x07, 0x46, 0x47, + 0x00, 0x0e, 0x0e, 0x0f, 0x18, 0x0f, 0x18, 0x07, 0x18, 0x00, 0x4d, 0x18, 0x00, 0x4d, 0x40, + 0x40, 0x47, 0x12, 0x10, 0x08, 0x47, 0x0f, 0x08, 0x00, 0x07, 0x2b, 0x27, 0x12, 0x00, 0x12, + 0x11, 0x0f, 0x47, 0x26, 0x17, 0x0e, 0x47, 0x0c, 0x11, 0x0d, 0x08, 0x07, 0x18, 0x0f, 0x0f, + 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x4b, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, + 0x40, 0x40, 0x40, 0x42, 0x0e, 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x07, 0x09, 0x09, 0x4c, 0x4e, 0x04, 0x09, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x01, 0x01, 0x44, 0x44, 0x02, 0x45, 0x46, 0x07, 0x45, 0x55, 0x46, 0x03, 0x4c, 0x5e, + 0x55, 0x4c, 0x05, 0x0b, 0x0a, 0x0e, 0x44, 0x44, 0x02, 0x45, 0x46, 0x07, 0x45, 0x55, 0x46, + 0x03, 0x4c, 0x5e, 0x55, 0x4c, 0x05, 0x0b, 0x0a, 0x0e, 0x1c, 0x51, 0x29, 0x4e, 0x4c, 0x4c, + 0x45, 0x44, 0x44, 0x04, 0x02, 0x0b, 0x02, 0x13, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x13, 0x45, + 0x4e, 0x25, 0x07, 0x45, 0x13, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x46, 0x01, 0x0d, 0x0d, 0x0f, + 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4c, 0x19, 0x01, 0x4c, 0x40, 0x40, 0x46, 0x14, 0x11, + 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x2d, 0x27, 0x14, 0x01, 0x13, 0x12, 0x0f, 0x46, 0x25, + 0x16, 0x0d, 0x46, 0x0a, 0x12, 0x0c, 0x09, 0x07, 0x19, 0x0e, 0x0f, 0x0f, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x4c, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x42, 0x40, 0x40, 0x40, 0x42, + 0x10, 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, + 0x09, 0x4b, 0x4e, 0x05, 0x09, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x43, + 0x43, 0x02, 0x45, 0x46, 0x07, 0x45, 0x55, 0x46, 0x04, 0x4b, 0x5e, 0x55, 0x4b, 0x06, 0x0c, + 0x0a, 0x10, 0x43, 0x43, 0x02, 0x45, 0x46, 0x07, 0x45, 0x55, 0x46, 0x04, 0x4b, 0x5e, 0x55, + 0x4b, 0x06, 0x0c, 0x0a, 0x10, 0x1d, 0x51, 0x29, 0x4e, 0x4b, 0x4b, 0x45, 0x43, 0x43, 0x05, + 0x02, 0x0c, 0x02, 0x14, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x14, 0x45, 0x4e, 0x25, 0x07, 0x45, + 0x14, 0x45, 0x4e, 0x25, 0x07, 0x45, 0x46, 0x01, 0x0d, 0x0d, 0x0f, 0x19, 0x0f, 0x19, 0x07, + 0x19, 0x01, 0x4b, 0x19, 0x01, 0x4b, 0x40, 0x40, 0x46, 0x15, 0x11, 0x09, 0x46, 0x0f, 0x09, + 0x01, 0x07, 0x2e, 0x27, 0x15, 0x01, 0x14, 0x12, 0x0f, 0x46, 0x25, 0x16, 0x0d, 0x46, 0x09, + 0x12, 0x0b, 0x09, 0x07, 0x19, 0x0e, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4d, 0x01, 0x4e, + 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x43, 0x40, 0x40, 0x40, 0x43, 0x12, 0x01, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4a, 0x4e, 0x06, + 0x09, 0x0c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x42, 0x42, 0x03, 0x44, 0x46, + 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x08, 0x0d, 0x0b, 0x12, 0x42, 0x42, + 0x03, 0x44, 0x46, 0x07, 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x08, 0x0d, 0x0b, + 0x12, 0x1e, 0x51, 0x29, 0x4e, 0x4a, 0x4a, 0x44, 0x42, 0x42, 0x06, 0x03, 0x0d, 0x03, 0x15, + 0x44, 0x4e, 0x24, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x24, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x24, + 0x07, 0x44, 0x46, 0x01, 0x0c, 0x0c, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4a, 0x19, + 0x01, 0x4a, 0x40, 0x40, 0x46, 0x16, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x30, 0x27, + 0x16, 0x01, 0x15, 0x13, 0x0f, 0x46, 0x24, 0x16, 0x0c, 0x46, 0x07, 0x13, 0x0a, 0x09, 0x07, + 0x19, 0x0e, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4e, 0x01, 0x4e, 0x58, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x44, 0x40, 0x40, 0x40, 0x44, 0x13, 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x09, 0x09, 0x4a, 0x4e, 0x07, 0x09, 0x0b, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x42, 0x42, 0x03, 0x44, 0x46, 0x07, 0x44, 0x54, 0x46, + 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x09, 0x0d, 0x0b, 0x13, 0x42, 0x42, 0x03, 0x44, 0x46, 0x07, + 0x44, 0x54, 0x46, 0x05, 0x4a, 0x5e, 0x54, 0x4a, 0x09, 0x0d, 0x0b, 0x13, 0x1f, 0x52, 0x29, + 0x4e, 0x4a, 0x4a, 0x44, 0x42, 0x42, 0x07, 0x03, 0x0d, 0x03, 0x15, 0x44, 0x4e, 0x23, 0x07, + 0x44, 0x15, 0x44, 0x4e, 0x23, 0x07, 0x44, 0x15, 0x44, 0x4e, 0x23, 0x07, 0x44, 0x46, 0x01, + 0x0b, 0x0b, 0x0f, 0x19, 0x0f, 0x19, 0x07, 0x19, 0x01, 0x4a, 0x19, 0x01, 0x4a, 0x40, 0x40, + 0x46, 0x17, 0x11, 0x09, 0x46, 0x0f, 0x09, 0x01, 0x07, 0x31, 0x27, 0x17, 0x01, 0x15, 0x13, + 0x0f, 0x46, 0x23, 0x15, 0x0b, 0x46, 0x05, 0x13, 0x09, 0x09, 0x07, 0x19, 0x0d, 0x0f, 0x0f, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x4e, 0x02, 0x4d, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x44, 0x40, + 0x40, 0x40, 0x44, 0x15, 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x07, 0x0a, 0x0a, 0x49, 0x4d, 0x09, 0x0a, 0x0b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x02, 0x02, 0x41, 0x41, 0x04, 0x43, 0x45, 0x07, 0x43, 0x53, 0x45, 0x06, 0x49, 0x5d, 0x53, + 0x49, 0x0b, 0x0e, 0x0c, 0x15, 0x41, 0x41, 0x04, 0x43, 0x45, 0x07, 0x43, 0x53, 0x45, 0x06, + 0x49, 0x5d, 0x53, 0x49, 0x0b, 0x0e, 0x0c, 0x15, 0x21, 0x52, 0x2a, 0x4d, 0x49, 0x49, 0x43, + 0x41, 0x41, 0x09, 0x04, 0x0e, 0x04, 0x16, 0x43, 0x4d, 0x23, 0x07, 0x43, 0x16, 0x43, 0x4d, + 0x23, 0x07, 0x43, 0x16, 0x43, 0x4d, 0x23, 0x07, 0x43, 0x45, 0x02, 0x0b, 0x0b, 0x0f, 0x1a, + 0x0f, 0x1a, 0x07, 0x1a, 0x02, 0x49, 0x1a, 0x02, 0x49, 0x40, 0x40, 0x45, 0x19, 0x12, 0x0a, + 0x45, 0x0f, 0x0a, 0x02, 0x07, 0x33, 0x27, 0x19, 0x02, 0x16, 0x14, 0x0f, 0x45, 0x23, 0x15, + 0x0b, 0x45, 0x04, 0x14, 0x09, 0x0a, 0x07, 0x1a, 0x0d, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x4f, 0x02, 0x4d, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x40, 0x40, 0x40, 0x45, 0x17, + 0x02, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0a, 0x0a, + 0x48, 0x4d, 0x0a, 0x0a, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x40, 0x40, + 0x05, 0x42, 0x45, 0x07, 0x42, 0x52, 0x45, 0x07, 0x48, 0x5d, 0x52, 0x48, 0x0d, 0x0f, 0x0d, + 0x17, 0x40, 0x40, 0x05, 0x42, 0x45, 0x07, 0x42, 0x52, 0x45, 0x07, 0x48, 0x5d, 0x52, 0x48, + 0x0d, 0x0f, 0x0d, 0x17, 0x22, 0x52, 0x2a, 0x4d, 0x48, 0x48, 0x42, 0x40, 0x40, 0x0a, 0x05, + 0x0f, 0x05, 0x17, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x17, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x17, + 0x42, 0x4d, 0x22, 0x07, 0x42, 0x45, 0x02, 0x0a, 0x0a, 0x0f, 0x1a, 0x0f, 0x1a, 0x07, 0x1a, + 0x02, 0x48, 0x1a, 0x02, 0x48, 0x40, 0x40, 0x45, 0x1a, 0x12, 0x0a, 0x45, 0x0f, 0x0a, 0x02, + 0x07, 0x35, 0x27, 0x1a, 0x02, 0x17, 0x15, 0x0f, 0x45, 0x22, 0x15, 0x0a, 0x45, 0x02, 0x15, + 0x08, 0x0a, 0x07, 0x1a, 0x0d, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x50, 0x02, 0x4d, 0x58, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x45, 0x40, 0x40, 0x40, 0x45, 0x19, 0x02, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0a, 0x0a, 0x47, 0x4d, 0x0b, 0x0a, + 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x00, 0x00, 0x05, 0x42, 0x45, 0x07, + 0x42, 0x52, 0x45, 0x08, 0x47, 0x5d, 0x52, 0x47, 0x0e, 0x10, 0x0d, 0x19, 0x00, 0x00, 0x05, + 0x42, 0x45, 0x07, 0x42, 0x52, 0x45, 0x08, 0x47, 0x5d, 0x52, 0x47, 0x0e, 0x10, 0x0d, 0x19, + 0x23, 0x52, 0x2a, 0x4d, 0x47, 0x47, 0x42, 0x00, 0x00, 0x0b, 0x05, 0x10, 0x05, 0x18, 0x42, + 0x4d, 0x22, 0x07, 0x42, 0x18, 0x42, 0x4d, 0x22, 0x07, 0x42, 0x18, 0x42, 0x4d, 0x22, 0x07, + 0x42, 0x45, 0x02, 0x0a, 0x0a, 0x0f, 0x1a, 0x0f, 0x1a, 0x07, 0x1a, 0x02, 0x47, 0x1a, 0x02, + 0x47, 0x40, 0x40, 0x45, 0x1b, 0x12, 0x0a, 0x45, 0x0f, 0x0a, 0x02, 0x07, 0x36, 0x27, 0x1b, + 0x02, 0x18, 0x15, 0x0f, 0x45, 0x22, 0x15, 0x0a, 0x45, 0x01, 0x15, 0x07, 0x0a, 0x07, 0x1a, + 0x0d, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x51, 0x03, 0x4c, 0x58, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x46, 0x40, 0x40, 0x40, 0x46, 0x1b, 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x07, 0x0b, 0x0b, 0x46, 0x4c, 0x0c, 0x0b, 0x09, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x03, 0x03, 0x01, 0x01, 0x06, 0x41, 0x44, 0x07, 0x41, 0x51, 0x44, 0x09, + 0x46, 0x5c, 0x51, 0x46, 0x10, 0x11, 0x0e, 0x1b, 0x01, 0x01, 0x06, 0x41, 0x44, 0x07, 0x41, + 0x51, 0x44, 0x09, 0x46, 0x5c, 0x51, 0x46, 0x10, 0x11, 0x0e, 0x1b, 0x24, 0x53, 0x2b, 0x4c, + 0x46, 0x46, 0x41, 0x01, 0x01, 0x0c, 0x06, 0x11, 0x06, 0x19, 0x41, 0x4c, 0x21, 0x07, 0x41, + 0x19, 0x41, 0x4c, 0x21, 0x07, 0x41, 0x19, 0x41, 0x4c, 0x21, 0x07, 0x41, 0x44, 0x03, 0x09, + 0x09, 0x0f, 0x1b, 0x0f, 0x1b, 0x07, 0x1b, 0x03, 0x46, 0x1b, 0x03, 0x46, 0x40, 0x40, 0x44, + 0x1c, 0x13, 0x0b, 0x44, 0x0f, 0x0b, 0x03, 0x07, 0x38, 0x27, 0x1c, 0x03, 0x19, 0x16, 0x0f, + 0x44, 0x21, 0x14, 0x09, 0x44, 0x40, 0x16, 0x06, 0x0b, 0x07, 0x1b, 0x0c, 0x0f, 0x0f, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x52, 0x03, 0x4c, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x40, 0x40, + 0x40, 0x47, 0x1d, 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x07, 0x0b, 0x0b, 0x45, 0x4c, 0x0e, 0x0b, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, + 0x03, 0x02, 0x02, 0x07, 0x40, 0x44, 0x07, 0x40, 0x50, 0x44, 0x0a, 0x45, 0x5c, 0x50, 0x45, + 0x11, 0x12, 0x0f, 0x1d, 0x02, 0x02, 0x07, 0x40, 0x44, 0x07, 0x40, 0x50, 0x44, 0x0a, 0x45, + 0x5c, 0x50, 0x45, 0x11, 0x12, 0x0f, 0x1d, 0x26, 0x53, 0x2b, 0x4c, 0x45, 0x45, 0x40, 0x02, + 0x02, 0x0e, 0x07, 0x12, 0x07, 0x1a, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x1a, 0x40, 0x4c, 0x20, + 0x07, 0x40, 0x1a, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x44, 0x03, 0x08, 0x08, 0x0f, 0x1b, 0x0f, + 0x1b, 0x07, 0x1b, 0x03, 0x45, 0x1b, 0x03, 0x45, 0x40, 0x40, 0x44, 0x1e, 0x13, 0x0b, 0x44, + 0x0f, 0x0b, 0x03, 0x07, 0x39, 0x27, 0x1e, 0x03, 0x1a, 0x17, 0x0f, 0x44, 0x20, 0x14, 0x08, + 0x44, 0x41, 0x17, 0x05, 0x0b, 0x07, 0x1b, 0x0c, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x53, + 0x03, 0x4c, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x47, 0x40, 0x40, 0x40, 0x47, 0x1f, 0x03, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0b, 0x0b, 0x44, + 0x4c, 0x0f, 0x0b, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x03, 0x03, 0x03, 0x03, 0x07, + 0x40, 0x44, 0x07, 0x40, 0x50, 0x44, 0x0b, 0x44, 0x5c, 0x50, 0x44, 0x13, 0x13, 0x0f, 0x1f, + 0x03, 0x03, 0x07, 0x40, 0x44, 0x07, 0x40, 0x50, 0x44, 0x0b, 0x44, 0x5c, 0x50, 0x44, 0x13, + 0x13, 0x0f, 0x1f, 0x27, 0x53, 0x2b, 0x4c, 0x44, 0x44, 0x40, 0x03, 0x03, 0x0f, 0x07, 0x13, + 0x07, 0x1b, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x1b, 0x40, 0x4c, 0x20, 0x07, 0x40, 0x1b, 0x40, + 0x4c, 0x20, 0x07, 0x40, 0x44, 0x03, 0x08, 0x08, 0x0f, 0x1b, 0x0f, 0x1b, 0x07, 0x1b, 0x03, + 0x44, 0x1b, 0x03, 0x44, 0x40, 0x40, 0x44, 0x1f, 0x13, 0x0b, 0x44, 0x0f, 0x0b, 0x03, 0x07, + 0x3b, 0x27, 0x1f, 0x03, 0x1b, 0x17, 0x0f, 0x44, 0x20, 0x14, 0x08, 0x44, 0x43, 0x17, 0x04, + 0x0b, 0x07, 0x1b, 0x0c, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x54, 0x04, 0x4b, 0x58, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x48, 0x40, 0x40, 0x40, 0x48, 0x21, 0x04, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0c, 0x0c, 0x43, 0x4b, 0x10, 0x0c, 0x07, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x04, 0x04, 0x04, 0x08, 0x00, 0x43, 0x07, 0x00, + 0x4f, 0x43, 0x0c, 0x43, 0x5b, 0x4f, 0x43, 0x14, 0x14, 0x10, 0x21, 0x04, 0x04, 0x08, 0x00, + 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0c, 0x43, 0x5b, 0x4f, 0x43, 0x14, 0x14, 0x10, 0x21, 0x28, + 0x54, 0x2c, 0x4b, 0x43, 0x43, 0x00, 0x04, 0x04, 0x10, 0x08, 0x14, 0x08, 0x1c, 0x00, 0x4b, + 0x1f, 0x07, 0x00, 0x1c, 0x00, 0x4b, 0x1f, 0x07, 0x00, 0x1c, 0x00, 0x4b, 0x1f, 0x07, 0x00, + 0x43, 0x04, 0x07, 0x07, 0x0f, 0x1c, 0x0f, 0x1c, 0x07, 0x1c, 0x04, 0x43, 0x1c, 0x04, 0x43, + 0x40, 0x40, 0x43, 0x20, 0x14, 0x0c, 0x43, 0x0f, 0x0c, 0x04, 0x07, 0x3c, 0x27, 0x20, 0x04, + 0x1c, 0x18, 0x0f, 0x43, 0x1f, 0x13, 0x07, 0x43, 0x44, 0x18, 0x03, 0x0c, 0x07, 0x1c, 0x0b, + 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x55, 0x04, 0x4b, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x49, 0x40, 0x40, 0x40, 0x49, 0x22, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x07, 0x0c, 0x0c, 0x42, 0x4b, 0x11, 0x0c, 0x06, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x04, 0x04, 0x05, 0x05, 0x08, 0x00, 0x43, 0x07, 0x00, 0x4f, 0x43, 0x0d, 0x42, + 0x5b, 0x4f, 0x42, 0x16, 0x15, 0x10, 0x22, 0x05, 0x05, 0x08, 0x00, 0x43, 0x07, 0x00, 0x4f, + 0x43, 0x0d, 0x42, 0x5b, 0x4f, 0x42, 0x16, 0x15, 0x10, 0x22, 0x29, 0x54, 0x2c, 0x4b, 0x42, + 0x42, 0x00, 0x05, 0x05, 0x11, 0x08, 0x15, 0x08, 0x1d, 0x00, 0x4b, 0x1e, 0x07, 0x00, 0x1d, + 0x00, 0x4b, 0x1e, 0x07, 0x00, 0x1d, 0x00, 0x4b, 0x1e, 0x07, 0x00, 0x43, 0x04, 0x06, 0x06, + 0x0f, 0x1c, 0x0f, 0x1c, 0x07, 0x1c, 0x04, 0x42, 0x1c, 0x04, 0x42, 0x40, 0x40, 0x43, 0x21, + 0x14, 0x0c, 0x43, 0x0f, 0x0c, 0x04, 0x07, 0x3e, 0x27, 0x21, 0x04, 0x1d, 0x18, 0x0f, 0x43, + 0x1e, 0x13, 0x06, 0x43, 0x46, 0x18, 0x02, 0x0c, 0x07, 0x1c, 0x0b, 0x0f, 0x0f, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x56, 0x04, 0x4b, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x40, 0x40, 0x40, + 0x49, 0x24, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, + 0x0c, 0x0c, 0x41, 0x4b, 0x13, 0x0c, 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x04, 0x04, + 0x06, 0x06, 0x09, 0x01, 0x43, 0x07, 0x01, 0x4e, 0x43, 0x0e, 0x41, 0x5b, 0x4e, 0x41, 0x18, + 0x16, 0x11, 0x24, 0x06, 0x06, 0x09, 0x01, 0x43, 0x07, 0x01, 0x4e, 0x43, 0x0e, 0x41, 0x5b, + 0x4e, 0x41, 0x18, 0x16, 0x11, 0x24, 0x2b, 0x54, 0x2c, 0x4b, 0x41, 0x41, 0x01, 0x06, 0x06, + 0x13, 0x09, 0x16, 0x09, 0x1e, 0x01, 0x4b, 0x1e, 0x07, 0x01, 0x1e, 0x01, 0x4b, 0x1e, 0x07, + 0x01, 0x1e, 0x01, 0x4b, 0x1e, 0x07, 0x01, 0x43, 0x04, 0x06, 0x06, 0x0f, 0x1c, 0x0f, 0x1c, + 0x07, 0x1c, 0x04, 0x41, 0x1c, 0x04, 0x41, 0x40, 0x40, 0x43, 0x23, 0x14, 0x0c, 0x43, 0x0f, + 0x0c, 0x04, 0x07, 0x3e, 0x27, 0x23, 0x04, 0x1e, 0x19, 0x0f, 0x43, 0x1e, 0x13, 0x06, 0x43, + 0x48, 0x19, 0x01, 0x0c, 0x07, 0x1c, 0x0b, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x57, 0x05, + 0x4a, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4a, 0x40, 0x40, 0x40, 0x4a, 0x26, 0x05, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0d, 0x0d, 0x40, 0x4a, + 0x14, 0x0d, 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x05, 0x07, 0x07, 0x0a, 0x02, + 0x42, 0x07, 0x02, 0x4d, 0x42, 0x0f, 0x40, 0x5a, 0x4d, 0x40, 0x19, 0x17, 0x12, 0x26, 0x07, + 0x07, 0x0a, 0x02, 0x42, 0x07, 0x02, 0x4d, 0x42, 0x0f, 0x40, 0x5a, 0x4d, 0x40, 0x19, 0x17, + 0x12, 0x26, 0x2c, 0x55, 0x2d, 0x4a, 0x40, 0x40, 0x02, 0x07, 0x07, 0x14, 0x0a, 0x17, 0x0a, + 0x1f, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x1f, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x1f, 0x02, 0x4a, + 0x1d, 0x07, 0x02, 0x42, 0x05, 0x05, 0x05, 0x0f, 0x1d, 0x0f, 0x1d, 0x07, 0x1d, 0x05, 0x40, + 0x1d, 0x05, 0x40, 0x40, 0x40, 0x42, 0x24, 0x15, 0x0d, 0x42, 0x0f, 0x0d, 0x05, 0x07, 0x3e, + 0x27, 0x24, 0x05, 0x1f, 0x1a, 0x0f, 0x42, 0x1d, 0x12, 0x05, 0x42, 0x49, 0x1a, 0x00, 0x0d, + 0x07, 0x1d, 0x0a, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x58, 0x05, 0x4a, 0x58, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x4a, 0x40, 0x40, 0x40, 0x4a, 0x28, 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0d, 0x0d, 0x00, 0x4a, 0x15, 0x0d, 0x05, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x05, 0x05, 0x08, 0x08, 0x0a, 0x02, 0x42, 0x07, 0x02, 0x4d, + 0x42, 0x10, 0x00, 0x5a, 0x4d, 0x00, 0x1b, 0x18, 0x12, 0x28, 0x08, 0x08, 0x0a, 0x02, 0x42, + 0x07, 0x02, 0x4d, 0x42, 0x10, 0x00, 0x5a, 0x4d, 0x00, 0x1b, 0x18, 0x12, 0x28, 0x2d, 0x55, + 0x2d, 0x4a, 0x00, 0x00, 0x02, 0x08, 0x08, 0x15, 0x0a, 0x18, 0x0a, 0x20, 0x02, 0x4a, 0x1d, + 0x07, 0x02, 0x20, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x20, 0x02, 0x4a, 0x1d, 0x07, 0x02, 0x42, + 0x05, 0x05, 0x05, 0x0f, 0x1d, 0x0f, 0x1d, 0x07, 0x1d, 0x05, 0x00, 0x1d, 0x05, 0x00, 0x40, + 0x40, 0x42, 0x25, 0x15, 0x0d, 0x42, 0x0f, 0x0d, 0x05, 0x07, 0x3e, 0x27, 0x25, 0x05, 0x20, + 0x1a, 0x0f, 0x42, 0x1d, 0x12, 0x05, 0x42, 0x4b, 0x1a, 0x40, 0x0d, 0x07, 0x1d, 0x0a, 0x0f, + 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x59, 0x05, 0x4a, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4b, + 0x40, 0x40, 0x40, 0x4b, 0x2a, 0x05, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x07, 0x0d, 0x0d, 0x01, 0x4a, 0x16, 0x0d, 0x04, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x05, 0x05, 0x09, 0x09, 0x0b, 0x03, 0x42, 0x07, 0x03, 0x4c, 0x42, 0x11, 0x01, 0x5a, + 0x4c, 0x01, 0x1c, 0x19, 0x13, 0x2a, 0x09, 0x09, 0x0b, 0x03, 0x42, 0x07, 0x03, 0x4c, 0x42, + 0x11, 0x01, 0x5a, 0x4c, 0x01, 0x1c, 0x19, 0x13, 0x2a, 0x2e, 0x55, 0x2d, 0x4a, 0x01, 0x01, + 0x03, 0x09, 0x09, 0x16, 0x0b, 0x19, 0x0b, 0x21, 0x03, 0x4a, 0x1c, 0x07, 0x03, 0x21, 0x03, + 0x4a, 0x1c, 0x07, 0x03, 0x21, 0x03, 0x4a, 0x1c, 0x07, 0x03, 0x42, 0x05, 0x04, 0x04, 0x0f, + 0x1d, 0x0f, 0x1d, 0x07, 0x1d, 0x05, 0x01, 0x1d, 0x05, 0x01, 0x40, 0x40, 0x42, 0x26, 0x15, + 0x0d, 0x42, 0x0f, 0x0d, 0x05, 0x07, 0x3e, 0x27, 0x26, 0x05, 0x21, 0x1b, 0x0f, 0x42, 0x1c, + 0x12, 0x04, 0x42, 0x4c, 0x1b, 0x41, 0x0d, 0x07, 0x1d, 0x0a, 0x0f, 0x0f, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x5a, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4c, 0x40, 0x40, 0x40, 0x4c, + 0x2c, 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, + 0x0e, 0x02, 0x49, 0x18, 0x0e, 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0a, + 0x0a, 0x0c, 0x04, 0x41, 0x07, 0x04, 0x4b, 0x41, 0x12, 0x02, 0x59, 0x4b, 0x02, 0x1e, 0x1a, + 0x14, 0x2c, 0x0a, 0x0a, 0x0c, 0x04, 0x41, 0x07, 0x04, 0x4b, 0x41, 0x12, 0x02, 0x59, 0x4b, + 0x02, 0x1e, 0x1a, 0x14, 0x2c, 0x30, 0x56, 0x2e, 0x49, 0x02, 0x02, 0x04, 0x0a, 0x0a, 0x18, + 0x0c, 0x1a, 0x0c, 0x22, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x22, 0x04, 0x49, 0x1b, 0x07, 0x04, + 0x22, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x41, 0x06, 0x03, 0x03, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, + 0x1e, 0x06, 0x02, 0x1e, 0x06, 0x02, 0x40, 0x40, 0x41, 0x28, 0x16, 0x0e, 0x41, 0x0f, 0x0e, + 0x06, 0x07, 0x3e, 0x27, 0x28, 0x06, 0x22, 0x1c, 0x0f, 0x41, 0x1b, 0x11, 0x03, 0x41, 0x4e, + 0x1c, 0x42, 0x0e, 0x07, 0x1e, 0x09, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x5b, 0x06, 0x49, + 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4c, 0x40, 0x40, 0x40, 0x4c, 0x2e, 0x06, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x03, 0x49, 0x19, + 0x0e, 0x03, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0b, 0x0b, 0x0c, 0x04, 0x41, + 0x07, 0x04, 0x4b, 0x41, 0x13, 0x03, 0x59, 0x4b, 0x03, 0x1f, 0x1b, 0x14, 0x2e, 0x0b, 0x0b, + 0x0c, 0x04, 0x41, 0x07, 0x04, 0x4b, 0x41, 0x13, 0x03, 0x59, 0x4b, 0x03, 0x1f, 0x1b, 0x14, + 0x2e, 0x31, 0x56, 0x2e, 0x49, 0x03, 0x03, 0x04, 0x0b, 0x0b, 0x19, 0x0c, 0x1b, 0x0c, 0x23, + 0x04, 0x49, 0x1b, 0x07, 0x04, 0x23, 0x04, 0x49, 0x1b, 0x07, 0x04, 0x23, 0x04, 0x49, 0x1b, + 0x07, 0x04, 0x41, 0x06, 0x03, 0x03, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x03, 0x1e, + 0x06, 0x03, 0x40, 0x40, 0x41, 0x29, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, + 0x29, 0x06, 0x23, 0x1c, 0x0f, 0x41, 0x1b, 0x11, 0x03, 0x41, 0x4f, 0x1c, 0x43, 0x0e, 0x07, + 0x1e, 0x09, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x5c, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x4d, 0x40, 0x40, 0x40, 0x4d, 0x30, 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0e, 0x0e, 0x04, 0x49, 0x1a, 0x0e, 0x02, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x06, 0x06, 0x0c, 0x0c, 0x0d, 0x05, 0x41, 0x07, 0x05, 0x4a, 0x41, + 0x14, 0x04, 0x59, 0x4a, 0x04, 0x21, 0x1c, 0x15, 0x30, 0x0c, 0x0c, 0x0d, 0x05, 0x41, 0x07, + 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, 0x04, 0x21, 0x1c, 0x15, 0x30, 0x32, 0x56, 0x2e, + 0x49, 0x04, 0x04, 0x05, 0x0c, 0x0c, 0x1a, 0x0d, 0x1c, 0x0d, 0x24, 0x05, 0x49, 0x1a, 0x07, + 0x05, 0x24, 0x05, 0x49, 0x1a, 0x07, 0x05, 0x24, 0x05, 0x49, 0x1a, 0x07, 0x05, 0x41, 0x06, + 0x02, 0x02, 0x0f, 0x1e, 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x04, 0x1e, 0x06, 0x04, 0x40, 0x40, + 0x41, 0x2a, 0x16, 0x0e, 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x2a, 0x06, 0x24, 0x1d, + 0x0f, 0x41, 0x1a, 0x11, 0x02, 0x41, 0x51, 0x1d, 0x44, 0x0e, 0x07, 0x1e, 0x09, 0x0f, 0x0f, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x5d, 0x06, 0x49, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4e, 0x40, + 0x40, 0x40, 0x4e, 0x31, 0x06, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x07, 0x0e, 0x0e, 0x04, 0x49, 0x1b, 0x0e, 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x06, 0x06, 0x0c, 0x0c, 0x0d, 0x05, 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, 0x04, 0x59, 0x4a, + 0x04, 0x22, 0x1c, 0x15, 0x31, 0x0c, 0x0c, 0x0d, 0x05, 0x41, 0x07, 0x05, 0x4a, 0x41, 0x14, + 0x04, 0x59, 0x4a, 0x04, 0x22, 0x1c, 0x15, 0x31, 0x33, 0x57, 0x2e, 0x49, 0x04, 0x04, 0x05, + 0x0c, 0x0c, 0x1b, 0x0d, 0x1c, 0x0d, 0x24, 0x05, 0x49, 0x19, 0x07, 0x05, 0x24, 0x05, 0x49, + 0x19, 0x07, 0x05, 0x24, 0x05, 0x49, 0x19, 0x07, 0x05, 0x41, 0x06, 0x01, 0x01, 0x0f, 0x1e, + 0x0f, 0x1e, 0x07, 0x1e, 0x06, 0x04, 0x1e, 0x06, 0x04, 0x40, 0x40, 0x41, 0x2b, 0x16, 0x0e, + 0x41, 0x0f, 0x0e, 0x06, 0x07, 0x3e, 0x27, 0x2b, 0x06, 0x24, 0x1d, 0x0f, 0x41, 0x19, 0x10, + 0x01, 0x41, 0x53, 0x1d, 0x45, 0x0e, 0x07, 0x1e, 0x08, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x5d, 0x07, 0x48, 0x58, 0x40, 0x40, 0x40, 0x40, 0x40, 0x4e, 0x40, 0x40, 0x40, 0x4e, 0x33, + 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0f, 0x0f, + 0x05, 0x48, 0x1d, 0x0f, 0x01, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x0d, 0x0d, + 0x0e, 0x06, 0x40, 0x07, 0x06, 0x49, 0x40, 0x15, 0x05, 0x58, 0x49, 0x05, 0x24, 0x1d, 0x16, + 0x33, 0x0d, 0x0d, 0x0e, 0x06, 0x40, 0x07, 0x06, 0x49, 0x40, 0x15, 0x05, 0x58, 0x49, 0x05, + 0x24, 0x1d, 0x16, 0x33, 0x35, 0x57, 0x2f, 0x48, 0x05, 0x05, 0x06, 0x0d, 0x0d, 0x1d, 0x0e, + 0x1d, 0x0e, 0x25, 0x06, 0x48, 0x19, 0x07, 0x06, 0x25, 0x06, 0x48, 0x19, 0x07, 0x06, 0x25, + 0x06, 0x48, 0x19, 0x07, 0x06, 0x40, 0x07, 0x01, 0x01, 0x0f, 0x1f, 0x0f, 0x1f, 0x07, 0x1f, + 0x07, 0x05, 0x1f, 0x07, 0x05, 0x40, 0x40, 0x40, 0x2d, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x07, + 0x07, 0x3e, 0x27, 0x2d, 0x07, 0x25, 0x1e, 0x0f, 0x40, 0x19, 0x10, 0x01, 0x40, 0x54, 0x1e, + 0x45, 0x0f, 0x07, 0x1f, 0x08, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x5e, 0x07, 0x48, 0x58, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x4f, 0x40, 0x40, 0x40, 0x4f, 0x35, 0x07, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x0f, 0x0f, 0x06, 0x48, 0x1e, 0x0f, + 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x07, 0x07, 0x0e, 0x0e, 0x0f, 0x07, 0x40, 0x07, + 0x07, 0x48, 0x40, 0x16, 0x06, 0x58, 0x48, 0x06, 0x26, 0x1e, 0x17, 0x35, 0x0e, 0x0e, 0x0f, + 0x07, 0x40, 0x07, 0x07, 0x48, 0x40, 0x16, 0x06, 0x58, 0x48, 0x06, 0x26, 0x1e, 0x17, 0x35, + 0x36, 0x57, 0x2f, 0x48, 0x06, 0x06, 0x07, 0x0e, 0x0e, 0x1e, 0x0f, 0x1e, 0x0f, 0x26, 0x07, + 0x48, 0x18, 0x07, 0x07, 0x26, 0x07, 0x48, 0x18, 0x07, 0x07, 0x26, 0x07, 0x48, 0x18, 0x07, + 0x07, 0x40, 0x07, 0x00, 0x00, 0x0f, 0x1f, 0x0f, 0x1f, 0x07, 0x1f, 0x07, 0x06, 0x1f, 0x07, + 0x06, 0x40, 0x40, 0x40, 0x2e, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x07, 0x07, 0x3e, 0x27, 0x2e, + 0x07, 0x26, 0x1f, 0x0f, 0x40, 0x18, 0x10, 0x00, 0x40, 0x56, 0x1f, 0x46, 0x0f, 0x07, 0x1f, + 0x08, 0x0f, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x5f, 0x07, 0x48, 0x58, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x4f, 0x40, 0x40, 0x40, 0x4f, 0x37, 0x07, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x07, 0x0f, 0x0f, 0x07, 0x48, 0x1f, 0x0f, 0x00, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x07, 0x40, 0x07, 0x07, 0x48, 0x40, 0x17, + 0x07, 0x58, 0x48, 0x07, 0x27, 0x1f, 0x17, 0x37, 0x0f, 0x0f, 0x0f, 0x07, 0x40, 0x07, 0x07, + 0x48, 0x40, 0x17, 0x07, 0x58, 0x48, 0x07, 0x27, 0x1f, 0x17, 0x37, 0x37, 0x57, 0x2f, 0x48, + 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x1f, 0x0f, 0x1f, 0x0f, 0x27, 0x07, 0x48, 0x18, 0x07, 0x07, + 0x27, 0x07, 0x48, 0x18, 0x07, 0x07, 0x27, 0x07, 0x48, 0x18, 0x07, 0x07, 0x40, 0x07, 0x00, + 0x00, 0x0f, 0x1f, 0x0f, 0x1f, 0x07, 0x1f, 0x07, 0x07, 0x1f, 0x07, 0x07, 0x40, 0x40, 0x40, + 0x2f, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x07, 0x07, 0x3e, 0x27, 0x2f, 0x07, 0x27, 0x1f, 0x0f, + 0x40, 0x18, 0x10, 0x00, 0x40, 0x57, 0x1f, 0x47, 0x0f, 0x07, 0x1f, 0x08, 0x0f, 0x0f, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x07, 0x48, 0x48, 0x60, 0x40, 0x27, 0x07, 0x07, 0x27, 0x40, 0x48, 0x40, + 0x40, 0x40, 0x0f, 0x48, 0x68, 0x60, 0x40, 0x68, 0x68, 0x68, 0x68, 0x68, 0x07, 0x07, 0x0f, + 0x50, 0x40, 0x60, 0x07, 0x68, 0x27, 0x48, 0x17, 0x40, 0x50, 0x1f, 0x40, 0x40, 0x40, 0x48, + 0x48, 0x58, 0x60, 0x60, 0x60, 0x68, 0x68, 0x58, 0x68, 0x60, 0x60, 0x60, 0x68, 0x68, 0x68, + 0x60, 0x50, 0x48, 0x50, 0x58, 0x60, 0x60, 0x60, 0x68, 0x68, 0x58, 0x68, 0x60, 0x60, 0x60, + 0x68, 0x68, 0x68, 0x60, 0x50, 0x48, 0x50, 0x07, 0x50, 0x58, 0x40, 0x48, 0x40, 0x48, 0x07, + 0x48, 0x48, 0x48, 0x68, 0x07, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, + 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x40, 0x07, 0x48, 0x48, 0x48, 0x07, 0x48, + 0x07, 0x17, 0x17, 0x17, 0x50, 0x17, 0x17, 0x50, 0x40, 0x40, 0x40, 0x2f, 0x2f, 0x17, 0x40, + 0x0f, 0x17, 0x1f, 0x1f, 0x1f, 0x27, 0x0f, 0x07, 0x07, 0x0f, 0x07, 0x07, 0x3e, 0x1f, 0x17, + 0x40, 0x17, 0x07, 0x1f, 0x48, 0x17, 0x48, 0x40, 0x48, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, + 0x47, 0x47, 0x5f, 0x40, 0x27, 0x07, 0x07, 0x27, 0x40, 0x47, 0x40, 0x40, 0x40, 0x0f, 0x47, + 0x66, 0x5f, 0x00, 0x66, 0x66, 0x66, 0x65, 0x65, 0x07, 0x07, 0x0f, 0x4f, 0x00, 0x5e, 0x07, + 0x67, 0x27, 0x47, 0x17, 0x40, 0x4f, 0x1f, 0x40, 0x40, 0x40, 0x47, 0x47, 0x57, 0x5f, 0x5e, + 0x5f, 0x66, 0x66, 0x57, 0x67, 0x5f, 0x5e, 0x5f, 0x67, 0x67, 0x66, 0x5e, 0x4f, 0x47, 0x4f, + 0x57, 0x5f, 0x5e, 0x5f, 0x66, 0x66, 0x57, 0x67, 0x5f, 0x5e, 0x5f, 0x67, 0x67, 0x66, 0x5e, + 0x4f, 0x47, 0x4f, 0x08, 0x4f, 0x56, 0x40, 0x48, 0x40, 0x47, 0x07, 0x47, 0x47, 0x47, 0x66, + 0x07, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x17, + 0x4f, 0x10, 0x07, 0x40, 0x40, 0x07, 0x47, 0x47, 0x47, 0x08, 0x47, 0x08, 0x17, 0x17, 0x17, + 0x4f, 0x17, 0x17, 0x4f, 0x40, 0x40, 0x40, 0x2f, 0x2f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, + 0x20, 0x27, 0x10, 0x07, 0x08, 0x10, 0x08, 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x17, 0x08, 0x1f, + 0x47, 0x17, 0x46, 0x00, 0x47, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x46, 0x47, 0x5e, 0x40, + 0x26, 0x06, 0x06, 0x27, 0x40, 0x47, 0x40, 0x40, 0x40, 0x0f, 0x47, 0x64, 0x5e, 0x01, 0x65, + 0x64, 0x64, 0x63, 0x63, 0x07, 0x07, 0x0f, 0x4e, 0x00, 0x5d, 0x07, 0x66, 0x27, 0x46, 0x17, + 0x40, 0x4f, 0x1e, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5e, 0x5d, 0x5e, 0x65, 0x64, 0x56, + 0x66, 0x5e, 0x5c, 0x5e, 0x66, 0x66, 0x65, 0x5d, 0x4e, 0x46, 0x4e, 0x56, 0x5e, 0x5d, 0x5e, + 0x65, 0x64, 0x56, 0x66, 0x5e, 0x5c, 0x5e, 0x66, 0x66, 0x65, 0x5d, 0x4e, 0x46, 0x4e, 0x09, + 0x4f, 0x54, 0x40, 0x48, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x64, 0x07, 0x1f, 0x16, 0x4f, + 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, + 0x40, 0x07, 0x46, 0x46, 0x46, 0x09, 0x46, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, + 0x40, 0x40, 0x40, 0x2e, 0x2e, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, + 0x09, 0x10, 0x08, 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x17, 0x08, 0x1e, 0x46, 0x17, 0x45, 0x01, + 0x46, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x06, 0x45, 0x47, 0x5e, 0x40, 0x25, 0x06, 0x05, 0x27, + 0x40, 0x47, 0x40, 0x40, 0x40, 0x0f, 0x47, 0x63, 0x5d, 0x01, 0x64, 0x63, 0x62, 0x60, 0x60, + 0x07, 0x07, 0x0f, 0x4e, 0x00, 0x5c, 0x07, 0x65, 0x27, 0x45, 0x17, 0x40, 0x4f, 0x1d, 0x40, + 0x40, 0x40, 0x47, 0x47, 0x56, 0x5d, 0x5c, 0x5d, 0x64, 0x63, 0x56, 0x65, 0x5d, 0x5b, 0x5d, + 0x65, 0x65, 0x64, 0x5c, 0x4d, 0x46, 0x4d, 0x56, 0x5d, 0x5c, 0x5d, 0x64, 0x63, 0x56, 0x65, + 0x5d, 0x5b, 0x5d, 0x65, 0x65, 0x64, 0x5c, 0x4d, 0x46, 0x4d, 0x09, 0x4f, 0x52, 0x40, 0x48, + 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x62, 0x07, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, + 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, 0x07, 0x46, 0x46, + 0x45, 0x09, 0x45, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, 0x40, 0x2d, + 0x2d, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, 0x08, 0x07, + 0x3d, 0x1f, 0x17, 0x40, 0x17, 0x08, 0x1e, 0x45, 0x17, 0x44, 0x01, 0x45, 0x17, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x05, 0x44, 0x46, 0x5d, 0x40, 0x24, 0x05, 0x04, 0x27, 0x40, 0x46, 0x40, 0x40, + 0x40, 0x0f, 0x46, 0x61, 0x5c, 0x02, 0x63, 0x61, 0x60, 0x5e, 0x5e, 0x07, 0x07, 0x0e, 0x4d, + 0x01, 0x5b, 0x07, 0x64, 0x27, 0x44, 0x16, 0x40, 0x4e, 0x1c, 0x40, 0x40, 0x40, 0x46, 0x46, + 0x55, 0x5c, 0x5b, 0x5c, 0x63, 0x61, 0x55, 0x64, 0x5c, 0x59, 0x5c, 0x64, 0x64, 0x63, 0x5b, + 0x4c, 0x45, 0x4c, 0x55, 0x5c, 0x5b, 0x5c, 0x63, 0x61, 0x55, 0x64, 0x5c, 0x59, 0x5c, 0x64, + 0x64, 0x63, 0x5b, 0x4c, 0x45, 0x4c, 0x0a, 0x4e, 0x50, 0x40, 0x48, 0x40, 0x46, 0x07, 0x46, + 0x45, 0x45, 0x60, 0x07, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, + 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x41, 0x07, 0x45, 0x45, 0x44, 0x0a, 0x44, 0x0a, + 0x16, 0x17, 0x15, 0x4e, 0x17, 0x15, 0x4e, 0x40, 0x40, 0x40, 0x2c, 0x2c, 0x16, 0x40, 0x0f, + 0x16, 0x1d, 0x1d, 0x21, 0x27, 0x11, 0x07, 0x0a, 0x11, 0x09, 0x06, 0x3c, 0x1e, 0x16, 0x40, + 0x16, 0x09, 0x1d, 0x44, 0x16, 0x43, 0x02, 0x44, 0x16, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x43, + 0x46, 0x5c, 0x40, 0x23, 0x04, 0x03, 0x27, 0x40, 0x46, 0x40, 0x40, 0x40, 0x0f, 0x46, 0x60, + 0x5b, 0x03, 0x61, 0x60, 0x5e, 0x5b, 0x5b, 0x07, 0x07, 0x0e, 0x4c, 0x01, 0x59, 0x07, 0x63, + 0x27, 0x43, 0x16, 0x40, 0x4e, 0x1b, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5b, 0x59, 0x5b, + 0x61, 0x60, 0x54, 0x63, 0x5b, 0x58, 0x5b, 0x63, 0x63, 0x61, 0x59, 0x4b, 0x44, 0x4b, 0x54, + 0x5b, 0x59, 0x5b, 0x61, 0x60, 0x54, 0x63, 0x5b, 0x58, 0x5b, 0x63, 0x63, 0x61, 0x59, 0x4b, + 0x44, 0x4b, 0x0b, 0x4e, 0x4e, 0x40, 0x48, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5e, 0x07, + 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, + 0x11, 0x07, 0x40, 0x41, 0x07, 0x44, 0x44, 0x43, 0x0b, 0x43, 0x0b, 0x16, 0x17, 0x14, 0x4e, + 0x17, 0x14, 0x4e, 0x40, 0x40, 0x40, 0x2b, 0x2b, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, + 0x27, 0x11, 0x07, 0x0b, 0x11, 0x09, 0x06, 0x3b, 0x1e, 0x16, 0x40, 0x16, 0x09, 0x1c, 0x43, + 0x16, 0x41, 0x03, 0x43, 0x16, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x42, 0x46, 0x5c, 0x40, 0x22, + 0x04, 0x02, 0x27, 0x40, 0x46, 0x40, 0x40, 0x40, 0x0f, 0x46, 0x5e, 0x5a, 0x03, 0x60, 0x5e, + 0x5c, 0x59, 0x59, 0x07, 0x07, 0x0e, 0x4c, 0x01, 0x58, 0x07, 0x62, 0x27, 0x42, 0x16, 0x40, + 0x4e, 0x1a, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5a, 0x58, 0x5a, 0x60, 0x5e, 0x54, 0x62, + 0x5a, 0x56, 0x5a, 0x62, 0x62, 0x60, 0x58, 0x4a, 0x44, 0x4a, 0x54, 0x5a, 0x58, 0x5a, 0x60, + 0x5e, 0x54, 0x62, 0x5a, 0x56, 0x5a, 0x62, 0x62, 0x60, 0x58, 0x4a, 0x44, 0x4a, 0x0b, 0x4e, + 0x4c, 0x40, 0x48, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5c, 0x07, 0x1e, 0x14, 0x4e, 0x11, + 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, + 0x07, 0x44, 0x44, 0x42, 0x0b, 0x42, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, + 0x40, 0x40, 0x2a, 0x2a, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, + 0x11, 0x09, 0x06, 0x3a, 0x1e, 0x16, 0x40, 0x16, 0x09, 0x1c, 0x42, 0x16, 0x40, 0x03, 0x42, + 0x16, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x03, 0x41, 0x45, 0x5b, 0x40, 0x21, 0x03, 0x01, 0x27, 0x40, + 0x45, 0x40, 0x40, 0x40, 0x0f, 0x45, 0x5d, 0x59, 0x04, 0x5f, 0x5d, 0x5a, 0x56, 0x56, 0x07, + 0x07, 0x0d, 0x4b, 0x02, 0x57, 0x07, 0x61, 0x27, 0x41, 0x15, 0x40, 0x4d, 0x19, 0x40, 0x40, + 0x40, 0x45, 0x45, 0x53, 0x59, 0x57, 0x59, 0x5f, 0x5d, 0x53, 0x61, 0x59, 0x55, 0x59, 0x61, + 0x61, 0x5f, 0x57, 0x49, 0x43, 0x49, 0x53, 0x59, 0x57, 0x59, 0x5f, 0x5d, 0x53, 0x61, 0x59, + 0x55, 0x59, 0x61, 0x61, 0x5f, 0x57, 0x49, 0x43, 0x49, 0x0c, 0x4d, 0x4a, 0x40, 0x48, 0x40, + 0x45, 0x07, 0x45, 0x43, 0x43, 0x5a, 0x07, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x13, + 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x42, 0x07, 0x43, 0x43, 0x41, + 0x0c, 0x41, 0x0c, 0x15, 0x17, 0x13, 0x4d, 0x17, 0x13, 0x4d, 0x40, 0x40, 0x40, 0x29, 0x29, + 0x15, 0x40, 0x0f, 0x15, 0x1b, 0x1b, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x0a, 0x05, 0x39, + 0x1d, 0x15, 0x40, 0x15, 0x0a, 0x1b, 0x41, 0x15, 0x00, 0x04, 0x41, 0x15, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x02, 0x40, 0x45, 0x5b, 0x40, 0x20, 0x02, 0x00, 0x27, 0x40, 0x45, 0x40, 0x40, 0x40, + 0x0f, 0x45, 0x5b, 0x58, 0x04, 0x5e, 0x5b, 0x59, 0x54, 0x54, 0x07, 0x07, 0x0d, 0x4b, 0x02, + 0x56, 0x07, 0x60, 0x27, 0x40, 0x15, 0x40, 0x4d, 0x18, 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, + 0x58, 0x56, 0x58, 0x5e, 0x5b, 0x53, 0x60, 0x58, 0x53, 0x58, 0x60, 0x60, 0x5e, 0x56, 0x48, + 0x43, 0x48, 0x53, 0x58, 0x56, 0x58, 0x5e, 0x5b, 0x53, 0x60, 0x58, 0x53, 0x58, 0x60, 0x60, + 0x5e, 0x56, 0x48, 0x43, 0x48, 0x0c, 0x4d, 0x49, 0x40, 0x48, 0x40, 0x45, 0x07, 0x45, 0x43, + 0x43, 0x59, 0x07, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, + 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, 0x07, 0x43, 0x43, 0x40, 0x0c, 0x40, 0x0c, 0x15, + 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, 0x40, 0x28, 0x28, 0x15, 0x40, 0x0f, 0x15, + 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x0a, 0x05, 0x38, 0x1d, 0x15, 0x40, 0x15, + 0x0a, 0x1a, 0x40, 0x15, 0x01, 0x04, 0x40, 0x15, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x02, 0x00, 0x45, + 0x5a, 0x40, 0x1f, 0x02, 0x40, 0x27, 0x40, 0x45, 0x40, 0x40, 0x40, 0x0f, 0x45, 0x59, 0x57, + 0x05, 0x5c, 0x59, 0x57, 0x51, 0x51, 0x07, 0x07, 0x0d, 0x4a, 0x02, 0x54, 0x07, 0x5f, 0x27, + 0x00, 0x15, 0x40, 0x4d, 0x17, 0x40, 0x40, 0x40, 0x45, 0x45, 0x52, 0x57, 0x54, 0x57, 0x5c, + 0x59, 0x52, 0x5f, 0x57, 0x51, 0x57, 0x5f, 0x5f, 0x5c, 0x54, 0x47, 0x42, 0x47, 0x52, 0x57, + 0x54, 0x57, 0x5c, 0x59, 0x52, 0x5f, 0x57, 0x51, 0x57, 0x5f, 0x5f, 0x5c, 0x54, 0x47, 0x42, + 0x47, 0x0d, 0x4d, 0x47, 0x40, 0x48, 0x40, 0x45, 0x07, 0x45, 0x42, 0x42, 0x57, 0x07, 0x1d, + 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, + 0x07, 0x40, 0x42, 0x07, 0x42, 0x42, 0x00, 0x0d, 0x00, 0x0d, 0x15, 0x17, 0x12, 0x4d, 0x17, + 0x12, 0x4d, 0x40, 0x40, 0x40, 0x27, 0x27, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, + 0x12, 0x07, 0x0d, 0x12, 0x0a, 0x05, 0x37, 0x1d, 0x15, 0x40, 0x15, 0x0a, 0x1a, 0x00, 0x15, + 0x03, 0x05, 0x00, 0x15, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x01, 0x44, 0x59, 0x40, 0x1e, 0x01, + 0x41, 0x27, 0x40, 0x44, 0x40, 0x40, 0x40, 0x0f, 0x44, 0x58, 0x56, 0x06, 0x5b, 0x58, 0x55, + 0x4f, 0x4f, 0x07, 0x07, 0x0c, 0x49, 0x03, 0x53, 0x07, 0x5e, 0x27, 0x01, 0x14, 0x40, 0x4c, + 0x16, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x56, 0x53, 0x56, 0x5b, 0x58, 0x51, 0x5e, 0x56, + 0x50, 0x56, 0x5e, 0x5e, 0x5b, 0x53, 0x46, 0x41, 0x46, 0x51, 0x56, 0x53, 0x56, 0x5b, 0x58, + 0x51, 0x5e, 0x56, 0x50, 0x56, 0x5e, 0x5e, 0x5b, 0x53, 0x46, 0x41, 0x46, 0x0e, 0x4c, 0x45, + 0x40, 0x48, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x55, 0x07, 0x1c, 0x11, 0x4c, 0x13, 0x07, + 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, 0x07, + 0x41, 0x41, 0x01, 0x0e, 0x01, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, + 0x40, 0x26, 0x26, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, + 0x0b, 0x04, 0x36, 0x1c, 0x14, 0x40, 0x14, 0x0b, 0x19, 0x01, 0x14, 0x04, 0x06, 0x01, 0x14, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x01, 0x02, 0x44, 0x59, 0x40, 0x1d, 0x01, 0x42, 0x27, 0x40, 0x44, + 0x40, 0x40, 0x40, 0x0f, 0x44, 0x56, 0x55, 0x06, 0x5a, 0x56, 0x53, 0x4c, 0x4c, 0x07, 0x07, + 0x0c, 0x49, 0x03, 0x52, 0x07, 0x5d, 0x27, 0x02, 0x14, 0x40, 0x4c, 0x15, 0x40, 0x40, 0x40, + 0x44, 0x44, 0x51, 0x55, 0x52, 0x55, 0x5a, 0x56, 0x51, 0x5d, 0x55, 0x4e, 0x55, 0x5d, 0x5d, + 0x5a, 0x52, 0x45, 0x41, 0x45, 0x51, 0x55, 0x52, 0x55, 0x5a, 0x56, 0x51, 0x5d, 0x55, 0x4e, + 0x55, 0x5d, 0x5d, 0x5a, 0x52, 0x45, 0x41, 0x45, 0x0e, 0x4c, 0x43, 0x40, 0x48, 0x40, 0x44, + 0x07, 0x44, 0x41, 0x41, 0x53, 0x07, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, + 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, 0x07, 0x41, 0x41, 0x02, 0x0e, + 0x02, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, 0x40, 0x25, 0x25, 0x14, + 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x0b, 0x04, 0x35, 0x1c, + 0x14, 0x40, 0x14, 0x0b, 0x19, 0x02, 0x14, 0x05, 0x06, 0x02, 0x14, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x03, 0x44, 0x58, 0x40, 0x1c, 0x00, 0x43, 0x27, 0x40, 0x44, 0x40, 0x40, 0x40, 0x0f, + 0x44, 0x55, 0x54, 0x07, 0x59, 0x55, 0x51, 0x4a, 0x4a, 0x07, 0x07, 0x0c, 0x48, 0x03, 0x51, + 0x07, 0x5c, 0x27, 0x03, 0x14, 0x40, 0x4c, 0x14, 0x40, 0x40, 0x40, 0x44, 0x44, 0x50, 0x54, + 0x51, 0x54, 0x59, 0x55, 0x50, 0x5c, 0x54, 0x4d, 0x54, 0x5c, 0x5c, 0x59, 0x51, 0x44, 0x40, + 0x44, 0x50, 0x54, 0x51, 0x54, 0x59, 0x55, 0x50, 0x5c, 0x54, 0x4d, 0x54, 0x5c, 0x5c, 0x59, + 0x51, 0x44, 0x40, 0x44, 0x0f, 0x4c, 0x41, 0x40, 0x48, 0x40, 0x44, 0x07, 0x44, 0x40, 0x40, + 0x51, 0x07, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x1c, + 0x10, 0x4c, 0x13, 0x07, 0x40, 0x43, 0x07, 0x40, 0x40, 0x03, 0x0f, 0x03, 0x0f, 0x14, 0x17, + 0x10, 0x4c, 0x17, 0x10, 0x4c, 0x40, 0x40, 0x40, 0x24, 0x24, 0x14, 0x40, 0x0f, 0x14, 0x18, + 0x18, 0x23, 0x27, 0x13, 0x07, 0x0f, 0x13, 0x0b, 0x04, 0x34, 0x1c, 0x14, 0x40, 0x14, 0x0b, + 0x18, 0x03, 0x14, 0x06, 0x07, 0x03, 0x14, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x04, 0x43, 0x57, + 0x40, 0x1b, 0x40, 0x44, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, 0x43, 0x53, 0x53, 0x08, + 0x57, 0x53, 0x4f, 0x47, 0x47, 0x07, 0x07, 0x0b, 0x47, 0x04, 0x4f, 0x07, 0x5b, 0x27, 0x04, + 0x13, 0x40, 0x4b, 0x13, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x53, 0x4f, 0x53, 0x57, 0x53, + 0x4f, 0x5b, 0x53, 0x4b, 0x53, 0x5b, 0x5b, 0x57, 0x4f, 0x43, 0x00, 0x43, 0x4f, 0x53, 0x4f, + 0x53, 0x57, 0x53, 0x4f, 0x5b, 0x53, 0x4b, 0x53, 0x5b, 0x5b, 0x57, 0x4f, 0x43, 0x00, 0x43, + 0x10, 0x4b, 0x00, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4f, 0x07, 0x1b, 0x0f, + 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, + 0x40, 0x44, 0x07, 0x00, 0x00, 0x04, 0x10, 0x04, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, + 0x4b, 0x40, 0x40, 0x40, 0x23, 0x23, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, + 0x07, 0x10, 0x14, 0x0c, 0x03, 0x33, 0x1b, 0x13, 0x40, 0x13, 0x0c, 0x17, 0x04, 0x13, 0x08, + 0x08, 0x04, 0x13, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x40, 0x05, 0x43, 0x57, 0x40, 0x1a, 0x40, 0x45, + 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, 0x43, 0x52, 0x52, 0x08, 0x56, 0x52, 0x4d, 0x45, + 0x45, 0x07, 0x07, 0x0b, 0x47, 0x04, 0x4e, 0x07, 0x5a, 0x27, 0x05, 0x13, 0x40, 0x4b, 0x12, + 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x52, 0x4e, 0x52, 0x56, 0x52, 0x4f, 0x5a, 0x52, 0x4a, + 0x52, 0x5a, 0x5a, 0x56, 0x4e, 0x42, 0x00, 0x42, 0x4f, 0x52, 0x4e, 0x52, 0x56, 0x52, 0x4f, + 0x5a, 0x52, 0x4a, 0x52, 0x5a, 0x5a, 0x56, 0x4e, 0x42, 0x00, 0x42, 0x10, 0x4b, 0x02, 0x40, + 0x48, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4d, 0x07, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, + 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, 0x07, 0x00, + 0x00, 0x05, 0x10, 0x05, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, 0x40, 0x40, + 0x22, 0x22, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, 0x14, 0x0c, + 0x03, 0x32, 0x1b, 0x13, 0x40, 0x13, 0x0c, 0x17, 0x05, 0x13, 0x09, 0x08, 0x05, 0x13, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x41, 0x06, 0x43, 0x56, 0x40, 0x19, 0x41, 0x46, 0x27, 0x40, 0x43, 0x40, + 0x40, 0x40, 0x0f, 0x43, 0x50, 0x51, 0x09, 0x55, 0x50, 0x4b, 0x42, 0x42, 0x07, 0x07, 0x0b, + 0x46, 0x04, 0x4d, 0x07, 0x59, 0x27, 0x06, 0x13, 0x40, 0x4b, 0x11, 0x40, 0x40, 0x40, 0x43, + 0x43, 0x4e, 0x51, 0x4d, 0x51, 0x55, 0x50, 0x4e, 0x59, 0x51, 0x48, 0x51, 0x59, 0x59, 0x55, + 0x4d, 0x41, 0x01, 0x41, 0x4e, 0x51, 0x4d, 0x51, 0x55, 0x50, 0x4e, 0x59, 0x51, 0x48, 0x51, + 0x59, 0x59, 0x55, 0x4d, 0x41, 0x01, 0x41, 0x11, 0x4b, 0x04, 0x40, 0x48, 0x40, 0x43, 0x07, + 0x43, 0x01, 0x01, 0x4b, 0x07, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, + 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x44, 0x07, 0x01, 0x01, 0x06, 0x11, 0x06, + 0x11, 0x13, 0x17, 0x0e, 0x4b, 0x17, 0x0e, 0x4b, 0x40, 0x40, 0x40, 0x21, 0x21, 0x13, 0x40, + 0x0f, 0x13, 0x16, 0x16, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x0c, 0x03, 0x31, 0x1b, 0x13, + 0x40, 0x13, 0x0c, 0x16, 0x06, 0x13, 0x0a, 0x09, 0x06, 0x13, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x42, + 0x06, 0x43, 0x56, 0x40, 0x18, 0x42, 0x47, 0x27, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0f, 0x43, + 0x4f, 0x51, 0x09, 0x54, 0x4f, 0x4a, 0x40, 0x40, 0x07, 0x07, 0x0a, 0x46, 0x04, 0x4c, 0x07, + 0x59, 0x27, 0x06, 0x12, 0x40, 0x4b, 0x10, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, 0x51, 0x4c, + 0x51, 0x54, 0x4f, 0x4e, 0x59, 0x51, 0x47, 0x51, 0x59, 0x59, 0x54, 0x4c, 0x41, 0x01, 0x41, + 0x4e, 0x51, 0x4c, 0x51, 0x54, 0x4f, 0x4e, 0x59, 0x51, 0x47, 0x51, 0x59, 0x59, 0x54, 0x4c, + 0x41, 0x01, 0x41, 0x11, 0x4b, 0x05, 0x40, 0x48, 0x40, 0x43, 0x07, 0x43, 0x01, 0x01, 0x4a, + 0x07, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x1a, 0x0d, + 0x4b, 0x14, 0x07, 0x40, 0x45, 0x07, 0x01, 0x01, 0x06, 0x11, 0x06, 0x11, 0x12, 0x17, 0x0d, + 0x4b, 0x17, 0x0d, 0x4b, 0x40, 0x40, 0x40, 0x20, 0x20, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, + 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x0c, 0x02, 0x30, 0x1a, 0x12, 0x40, 0x12, 0x0c, 0x15, + 0x06, 0x12, 0x0b, 0x09, 0x06, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x42, 0x07, 0x42, 0x55, 0x40, + 0x18, 0x42, 0x47, 0x27, 0x40, 0x42, 0x40, 0x40, 0x40, 0x0f, 0x42, 0x4d, 0x50, 0x0a, 0x52, + 0x4d, 0x48, 0x02, 0x02, 0x07, 0x07, 0x0a, 0x45, 0x05, 0x4a, 0x07, 0x58, 0x27, 0x07, 0x12, + 0x40, 0x4a, 0x10, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4d, 0x50, 0x4a, 0x50, 0x52, 0x4d, 0x4d, + 0x58, 0x50, 0x45, 0x50, 0x58, 0x58, 0x52, 0x4a, 0x40, 0x02, 0x40, 0x4d, 0x50, 0x4a, 0x50, + 0x52, 0x4d, 0x4d, 0x58, 0x50, 0x45, 0x50, 0x58, 0x58, 0x52, 0x4a, 0x40, 0x02, 0x40, 0x12, + 0x4a, 0x07, 0x40, 0x48, 0x40, 0x42, 0x07, 0x42, 0x02, 0x02, 0x48, 0x07, 0x1a, 0x0d, 0x4a, + 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, + 0x45, 0x07, 0x02, 0x02, 0x07, 0x12, 0x07, 0x12, 0x12, 0x17, 0x0d, 0x4a, 0x17, 0x0d, 0x4a, + 0x40, 0x40, 0x40, 0x20, 0x20, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x25, 0x27, 0x15, 0x07, + 0x12, 0x15, 0x0d, 0x02, 0x30, 0x1a, 0x12, 0x40, 0x12, 0x0d, 0x15, 0x07, 0x12, 0x0d, 0x0a, + 0x07, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x43, 0x08, 0x42, 0x54, 0x40, 0x17, 0x43, 0x48, 0x27, + 0x40, 0x42, 0x40, 0x40, 0x40, 0x0f, 0x42, 0x4b, 0x4f, 0x0b, 0x51, 0x4b, 0x46, 0x04, 0x04, + 0x07, 0x07, 0x0a, 0x44, 0x05, 0x49, 0x07, 0x57, 0x27, 0x08, 0x12, 0x40, 0x4a, 0x0f, 0x40, + 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4f, 0x49, 0x4f, 0x51, 0x4b, 0x4c, 0x57, 0x4f, 0x43, 0x4f, + 0x57, 0x57, 0x51, 0x49, 0x00, 0x03, 0x00, 0x4c, 0x4f, 0x49, 0x4f, 0x51, 0x4b, 0x4c, 0x57, + 0x4f, 0x43, 0x4f, 0x57, 0x57, 0x51, 0x49, 0x00, 0x03, 0x00, 0x13, 0x4a, 0x09, 0x40, 0x48, + 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x46, 0x07, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, + 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, 0x07, 0x03, 0x03, + 0x08, 0x13, 0x08, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, 0x40, 0x1f, + 0x1f, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0d, 0x02, + 0x2f, 0x1a, 0x12, 0x40, 0x12, 0x0d, 0x14, 0x08, 0x12, 0x0e, 0x0b, 0x08, 0x12, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x43, 0x09, 0x42, 0x54, 0x40, 0x16, 0x43, 0x49, 0x27, 0x40, 0x42, 0x40, 0x40, + 0x40, 0x0f, 0x42, 0x4a, 0x4e, 0x0b, 0x50, 0x4a, 0x44, 0x07, 0x07, 0x07, 0x07, 0x0a, 0x44, + 0x05, 0x48, 0x07, 0x56, 0x27, 0x09, 0x12, 0x40, 0x4a, 0x0e, 0x40, 0x40, 0x40, 0x42, 0x42, + 0x4c, 0x4e, 0x48, 0x4e, 0x50, 0x4a, 0x4c, 0x56, 0x4e, 0x42, 0x4e, 0x56, 0x56, 0x50, 0x48, + 0x01, 0x03, 0x01, 0x4c, 0x4e, 0x48, 0x4e, 0x50, 0x4a, 0x4c, 0x56, 0x4e, 0x42, 0x4e, 0x56, + 0x56, 0x50, 0x48, 0x01, 0x03, 0x01, 0x13, 0x4a, 0x0b, 0x40, 0x48, 0x40, 0x42, 0x07, 0x42, + 0x03, 0x03, 0x44, 0x07, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, + 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, 0x07, 0x03, 0x03, 0x09, 0x13, 0x09, 0x13, + 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, 0x40, 0x1e, 0x1e, 0x12, 0x40, 0x0f, + 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0d, 0x02, 0x2e, 0x1a, 0x12, 0x40, + 0x12, 0x0d, 0x14, 0x09, 0x12, 0x0f, 0x0b, 0x09, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x44, 0x0a, + 0x41, 0x53, 0x40, 0x15, 0x44, 0x4a, 0x27, 0x40, 0x41, 0x40, 0x40, 0x40, 0x0f, 0x41, 0x48, + 0x4d, 0x0c, 0x4f, 0x48, 0x42, 0x09, 0x09, 0x07, 0x07, 0x09, 0x43, 0x06, 0x47, 0x07, 0x55, + 0x27, 0x0a, 0x11, 0x40, 0x49, 0x0d, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4b, 0x4d, 0x47, 0x4d, + 0x4f, 0x48, 0x4b, 0x55, 0x4d, 0x40, 0x4d, 0x55, 0x55, 0x4f, 0x47, 0x02, 0x04, 0x02, 0x4b, + 0x4d, 0x47, 0x4d, 0x4f, 0x48, 0x4b, 0x55, 0x4d, 0x40, 0x4d, 0x55, 0x55, 0x4f, 0x47, 0x02, + 0x04, 0x02, 0x14, 0x49, 0x0d, 0x40, 0x48, 0x40, 0x41, 0x07, 0x41, 0x04, 0x04, 0x42, 0x07, + 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, + 0x16, 0x07, 0x40, 0x46, 0x07, 0x04, 0x04, 0x0a, 0x14, 0x0a, 0x14, 0x11, 0x17, 0x0b, 0x49, + 0x17, 0x0b, 0x49, 0x40, 0x40, 0x40, 0x1d, 0x1d, 0x11, 0x40, 0x0f, 0x11, 0x13, 0x13, 0x26, + 0x27, 0x16, 0x07, 0x14, 0x16, 0x0e, 0x01, 0x2d, 0x19, 0x11, 0x40, 0x11, 0x0e, 0x13, 0x0a, + 0x11, 0x10, 0x0c, 0x0a, 0x11, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x45, 0x0b, 0x41, 0x52, 0x40, 0x14, + 0x45, 0x4b, 0x27, 0x40, 0x41, 0x40, 0x40, 0x40, 0x0f, 0x41, 0x47, 0x4c, 0x0d, 0x4d, 0x47, + 0x40, 0x0c, 0x0c, 0x07, 0x07, 0x09, 0x42, 0x06, 0x45, 0x07, 0x54, 0x27, 0x0b, 0x11, 0x40, + 0x49, 0x0c, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4c, 0x45, 0x4c, 0x4d, 0x47, 0x4a, 0x54, + 0x4c, 0x00, 0x4c, 0x54, 0x54, 0x4d, 0x45, 0x03, 0x05, 0x03, 0x4a, 0x4c, 0x45, 0x4c, 0x4d, + 0x47, 0x4a, 0x54, 0x4c, 0x00, 0x4c, 0x54, 0x54, 0x4d, 0x45, 0x03, 0x05, 0x03, 0x15, 0x49, + 0x0f, 0x40, 0x48, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x40, 0x07, 0x19, 0x0a, 0x49, 0x16, + 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, + 0x07, 0x05, 0x05, 0x0b, 0x15, 0x0b, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, + 0x40, 0x40, 0x1c, 0x1c, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, + 0x16, 0x0e, 0x01, 0x2c, 0x19, 0x11, 0x40, 0x11, 0x0e, 0x12, 0x0b, 0x11, 0x12, 0x0d, 0x0b, + 0x11, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x45, 0x0c, 0x41, 0x52, 0x40, 0x13, 0x45, 0x4c, 0x27, 0x40, + 0x41, 0x40, 0x40, 0x40, 0x0f, 0x41, 0x45, 0x4b, 0x0d, 0x4c, 0x45, 0x01, 0x0e, 0x0e, 0x07, + 0x07, 0x09, 0x42, 0x06, 0x44, 0x07, 0x53, 0x27, 0x0c, 0x11, 0x40, 0x49, 0x0b, 0x40, 0x40, + 0x40, 0x41, 0x41, 0x4a, 0x4b, 0x44, 0x4b, 0x4c, 0x45, 0x4a, 0x53, 0x4b, 0x02, 0x4b, 0x53, + 0x53, 0x4c, 0x44, 0x04, 0x05, 0x04, 0x4a, 0x4b, 0x44, 0x4b, 0x4c, 0x45, 0x4a, 0x53, 0x4b, + 0x02, 0x4b, 0x53, 0x53, 0x4c, 0x44, 0x04, 0x05, 0x04, 0x15, 0x49, 0x11, 0x40, 0x48, 0x40, + 0x41, 0x07, 0x41, 0x05, 0x05, 0x01, 0x07, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, + 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, 0x07, 0x05, 0x05, 0x0c, + 0x15, 0x0c, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, 0x40, 0x1b, 0x1b, + 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0e, 0x01, 0x2b, + 0x19, 0x11, 0x40, 0x11, 0x0e, 0x12, 0x0c, 0x11, 0x13, 0x0d, 0x0c, 0x11, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x46, 0x0d, 0x40, 0x51, 0x40, 0x12, 0x46, 0x4d, 0x27, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x0f, 0x40, 0x44, 0x4a, 0x0e, 0x4b, 0x44, 0x03, 0x11, 0x11, 0x07, 0x07, 0x08, 0x41, 0x07, + 0x43, 0x07, 0x52, 0x27, 0x0d, 0x10, 0x40, 0x48, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, + 0x4a, 0x43, 0x4a, 0x4b, 0x44, 0x49, 0x52, 0x4a, 0x03, 0x4a, 0x52, 0x52, 0x4b, 0x43, 0x05, + 0x06, 0x05, 0x49, 0x4a, 0x43, 0x4a, 0x4b, 0x44, 0x49, 0x52, 0x4a, 0x03, 0x4a, 0x52, 0x52, + 0x4b, 0x43, 0x05, 0x06, 0x05, 0x16, 0x48, 0x13, 0x40, 0x48, 0x40, 0x40, 0x07, 0x40, 0x06, + 0x06, 0x03, 0x07, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, + 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x47, 0x07, 0x06, 0x06, 0x0d, 0x16, 0x0d, 0x16, 0x10, + 0x17, 0x09, 0x48, 0x17, 0x09, 0x48, 0x40, 0x40, 0x40, 0x1a, 0x1a, 0x10, 0x40, 0x0f, 0x10, + 0x11, 0x11, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0f, 0x00, 0x2a, 0x18, 0x10, 0x40, 0x10, + 0x0f, 0x11, 0x0d, 0x10, 0x14, 0x0e, 0x0d, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x47, 0x0e, 0x40, + 0x51, 0x40, 0x11, 0x47, 0x4e, 0x27, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x42, 0x49, + 0x0e, 0x4a, 0x42, 0x04, 0x13, 0x13, 0x07, 0x07, 0x08, 0x41, 0x07, 0x42, 0x07, 0x51, 0x27, + 0x0e, 0x10, 0x40, 0x48, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x42, 0x49, 0x4a, + 0x42, 0x49, 0x51, 0x49, 0x05, 0x49, 0x51, 0x51, 0x4a, 0x42, 0x06, 0x06, 0x06, 0x49, 0x49, + 0x42, 0x49, 0x4a, 0x42, 0x49, 0x51, 0x49, 0x05, 0x49, 0x51, 0x51, 0x4a, 0x42, 0x06, 0x06, + 0x06, 0x16, 0x48, 0x14, 0x40, 0x48, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x04, 0x07, 0x18, + 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, + 0x07, 0x40, 0x47, 0x07, 0x06, 0x06, 0x0e, 0x16, 0x0e, 0x16, 0x10, 0x17, 0x08, 0x48, 0x17, + 0x08, 0x48, 0x40, 0x40, 0x40, 0x19, 0x19, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, + 0x17, 0x07, 0x16, 0x17, 0x0f, 0x00, 0x29, 0x18, 0x10, 0x40, 0x10, 0x0f, 0x10, 0x0e, 0x10, + 0x15, 0x0e, 0x0e, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x47, 0x0f, 0x40, 0x50, 0x40, 0x10, 0x47, + 0x4f, 0x27, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0f, 0x40, 0x40, 0x48, 0x0f, 0x48, 0x40, 0x06, + 0x16, 0x16, 0x07, 0x07, 0x08, 0x40, 0x07, 0x40, 0x07, 0x50, 0x27, 0x0f, 0x10, 0x40, 0x48, + 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x40, 0x48, 0x48, 0x40, 0x48, 0x50, 0x48, + 0x07, 0x48, 0x50, 0x50, 0x48, 0x40, 0x07, 0x07, 0x07, 0x48, 0x48, 0x40, 0x48, 0x48, 0x40, + 0x48, 0x50, 0x48, 0x07, 0x48, 0x50, 0x50, 0x48, 0x40, 0x07, 0x07, 0x07, 0x17, 0x48, 0x16, + 0x40, 0x48, 0x40, 0x40, 0x07, 0x40, 0x07, 0x07, 0x06, 0x07, 0x18, 0x08, 0x48, 0x17, 0x07, + 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x47, 0x07, + 0x07, 0x07, 0x0f, 0x17, 0x0f, 0x17, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, + 0x40, 0x18, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, 0x17, 0x17, + 0x0f, 0x00, 0x28, 0x18, 0x10, 0x40, 0x10, 0x0f, 0x10, 0x0f, 0x10, 0x17, 0x0f, 0x0f, 0x10, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x48, 0x10, 0x00, 0x4f, 0x40, 0x0f, 0x48, 0x50, 0x27, 0x40, 0x00, + 0x40, 0x40, 0x40, 0x0f, 0x00, 0x00, 0x47, 0x10, 0x47, 0x00, 0x08, 0x18, 0x18, 0x07, 0x07, + 0x07, 0x00, 0x08, 0x00, 0x07, 0x4f, 0x27, 0x10, 0x0f, 0x40, 0x47, 0x07, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x47, 0x47, 0x00, 0x47, 0x47, 0x00, 0x47, 0x4f, 0x47, 0x08, 0x47, 0x4f, 0x4f, + 0x47, 0x00, 0x08, 0x08, 0x08, 0x47, 0x47, 0x00, 0x47, 0x47, 0x00, 0x47, 0x4f, 0x47, 0x08, + 0x47, 0x4f, 0x4f, 0x47, 0x00, 0x08, 0x08, 0x08, 0x18, 0x47, 0x18, 0x40, 0x48, 0x40, 0x00, + 0x07, 0x00, 0x08, 0x08, 0x08, 0x07, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, + 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, 0x07, 0x08, 0x08, 0x10, 0x18, + 0x10, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, 0x40, 0x17, 0x17, 0x0f, + 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, 0x40, 0x27, 0x17, + 0x0f, 0x40, 0x0f, 0x10, 0x0f, 0x10, 0x0f, 0x18, 0x10, 0x10, 0x0f, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x48, 0x11, 0x00, 0x4f, 0x40, 0x0e, 0x48, 0x51, 0x27, 0x40, 0x00, 0x40, 0x40, 0x40, 0x0f, + 0x00, 0x02, 0x46, 0x10, 0x46, 0x02, 0x0a, 0x1b, 0x1b, 0x07, 0x07, 0x07, 0x00, 0x08, 0x01, + 0x07, 0x4e, 0x27, 0x11, 0x0f, 0x40, 0x47, 0x06, 0x40, 0x40, 0x40, 0x00, 0x00, 0x47, 0x46, + 0x01, 0x46, 0x46, 0x02, 0x47, 0x4e, 0x46, 0x0a, 0x46, 0x4e, 0x4e, 0x46, 0x01, 0x09, 0x08, + 0x09, 0x47, 0x46, 0x01, 0x46, 0x46, 0x02, 0x47, 0x4e, 0x46, 0x0a, 0x46, 0x4e, 0x4e, 0x46, + 0x01, 0x09, 0x08, 0x09, 0x18, 0x47, 0x1a, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, + 0x0a, 0x07, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, + 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, 0x07, 0x08, 0x08, 0x11, 0x18, 0x11, 0x18, 0x0f, 0x17, + 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, 0x40, 0x16, 0x16, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, + 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, 0x40, 0x26, 0x17, 0x0f, 0x40, 0x0f, 0x10, + 0x0f, 0x11, 0x0f, 0x19, 0x10, 0x11, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x49, 0x12, 0x00, 0x4e, + 0x40, 0x0d, 0x49, 0x52, 0x27, 0x40, 0x00, 0x40, 0x40, 0x40, 0x0f, 0x00, 0x03, 0x45, 0x11, + 0x45, 0x03, 0x0c, 0x1d, 0x1d, 0x07, 0x07, 0x07, 0x01, 0x08, 0x02, 0x07, 0x4d, 0x27, 0x12, + 0x0f, 0x40, 0x47, 0x05, 0x40, 0x40, 0x40, 0x00, 0x00, 0x46, 0x45, 0x02, 0x45, 0x45, 0x03, + 0x46, 0x4d, 0x45, 0x0b, 0x45, 0x4d, 0x4d, 0x45, 0x02, 0x0a, 0x09, 0x0a, 0x46, 0x45, 0x02, + 0x45, 0x45, 0x03, 0x46, 0x4d, 0x45, 0x0b, 0x45, 0x4d, 0x4d, 0x45, 0x02, 0x0a, 0x09, 0x0a, + 0x19, 0x47, 0x1c, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x09, 0x09, 0x0c, 0x07, 0x17, 0x06, + 0x47, 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, + 0x40, 0x48, 0x07, 0x09, 0x09, 0x12, 0x19, 0x12, 0x19, 0x0f, 0x17, 0x06, 0x47, 0x17, 0x06, + 0x47, 0x40, 0x40, 0x40, 0x15, 0x15, 0x0f, 0x40, 0x0f, 0x0f, 0x0e, 0x0e, 0x28, 0x27, 0x18, + 0x07, 0x19, 0x18, 0x10, 0x40, 0x25, 0x17, 0x0f, 0x40, 0x0f, 0x10, 0x0e, 0x12, 0x0f, 0x1a, + 0x11, 0x12, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4a, 0x13, 0x01, 0x4d, 0x40, 0x0c, 0x4a, 0x53, + 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, 0x01, 0x05, 0x44, 0x12, 0x43, 0x05, 0x0e, 0x20, + 0x20, 0x07, 0x07, 0x06, 0x02, 0x09, 0x04, 0x07, 0x4c, 0x27, 0x13, 0x0e, 0x40, 0x46, 0x04, + 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x44, 0x04, 0x44, 0x43, 0x05, 0x45, 0x4c, 0x44, 0x0d, + 0x44, 0x4c, 0x4c, 0x43, 0x04, 0x0b, 0x0a, 0x0b, 0x45, 0x44, 0x04, 0x44, 0x43, 0x05, 0x45, + 0x4c, 0x44, 0x0d, 0x44, 0x4c, 0x4c, 0x43, 0x04, 0x0b, 0x0a, 0x0b, 0x1a, 0x46, 0x1e, 0x40, + 0x48, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x0e, 0x07, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, + 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, 0x07, 0x0a, + 0x0a, 0x13, 0x1a, 0x13, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, 0x40, + 0x14, 0x14, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x11, + 0x41, 0x24, 0x16, 0x0e, 0x40, 0x0e, 0x11, 0x0d, 0x13, 0x0e, 0x1c, 0x12, 0x13, 0x0e, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x4a, 0x14, 0x01, 0x4d, 0x40, 0x0b, 0x4a, 0x54, 0x27, 0x40, 0x01, 0x40, + 0x40, 0x40, 0x0f, 0x01, 0x06, 0x43, 0x12, 0x42, 0x06, 0x10, 0x22, 0x22, 0x07, 0x07, 0x06, + 0x02, 0x09, 0x05, 0x07, 0x4b, 0x27, 0x14, 0x0e, 0x40, 0x46, 0x03, 0x40, 0x40, 0x40, 0x01, + 0x01, 0x45, 0x43, 0x05, 0x43, 0x42, 0x06, 0x45, 0x4b, 0x43, 0x0e, 0x43, 0x4b, 0x4b, 0x42, + 0x05, 0x0c, 0x0a, 0x0c, 0x45, 0x43, 0x05, 0x43, 0x42, 0x06, 0x45, 0x4b, 0x43, 0x0e, 0x43, + 0x4b, 0x4b, 0x42, 0x05, 0x0c, 0x0a, 0x0c, 0x1a, 0x46, 0x20, 0x40, 0x48, 0x40, 0x01, 0x07, + 0x01, 0x0a, 0x0a, 0x10, 0x07, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, + 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, 0x07, 0x0a, 0x0a, 0x14, 0x1a, 0x14, + 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, 0x40, 0x13, 0x13, 0x0e, 0x40, + 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x11, 0x41, 0x23, 0x16, 0x0e, + 0x40, 0x0e, 0x11, 0x0d, 0x14, 0x0e, 0x1d, 0x12, 0x14, 0x0e, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4b, + 0x15, 0x01, 0x4c, 0x40, 0x0a, 0x4b, 0x55, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, 0x01, + 0x08, 0x42, 0x13, 0x41, 0x08, 0x12, 0x25, 0x25, 0x07, 0x07, 0x06, 0x03, 0x09, 0x06, 0x07, + 0x4a, 0x27, 0x15, 0x0e, 0x40, 0x46, 0x02, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x06, + 0x42, 0x41, 0x08, 0x44, 0x4a, 0x42, 0x10, 0x42, 0x4a, 0x4a, 0x41, 0x06, 0x0d, 0x0b, 0x0d, + 0x44, 0x42, 0x06, 0x42, 0x41, 0x08, 0x44, 0x4a, 0x42, 0x10, 0x42, 0x4a, 0x4a, 0x41, 0x06, + 0x0d, 0x0b, 0x0d, 0x1b, 0x46, 0x22, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x12, + 0x07, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x16, 0x04, + 0x46, 0x19, 0x07, 0x40, 0x49, 0x07, 0x0b, 0x0b, 0x15, 0x1b, 0x15, 0x1b, 0x0e, 0x17, 0x04, + 0x46, 0x17, 0x04, 0x46, 0x40, 0x40, 0x40, 0x12, 0x12, 0x0e, 0x40, 0x0f, 0x0e, 0x0c, 0x0c, + 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x11, 0x41, 0x22, 0x16, 0x0e, 0x40, 0x0e, 0x11, 0x0c, + 0x15, 0x0e, 0x1e, 0x13, 0x15, 0x0e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4c, 0x15, 0x01, 0x4c, 0x40, + 0x09, 0x4c, 0x56, 0x27, 0x40, 0x01, 0x40, 0x40, 0x40, 0x0f, 0x01, 0x09, 0x42, 0x13, 0x40, + 0x09, 0x13, 0x27, 0x27, 0x07, 0x07, 0x05, 0x03, 0x09, 0x07, 0x07, 0x4a, 0x27, 0x15, 0x0d, + 0x40, 0x46, 0x01, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x07, 0x42, 0x40, 0x09, 0x44, + 0x4a, 0x42, 0x11, 0x42, 0x4a, 0x4a, 0x40, 0x07, 0x0d, 0x0b, 0x0d, 0x44, 0x42, 0x07, 0x42, + 0x40, 0x09, 0x44, 0x4a, 0x42, 0x11, 0x42, 0x4a, 0x4a, 0x40, 0x07, 0x0d, 0x0b, 0x0d, 0x1b, + 0x46, 0x23, 0x40, 0x48, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x13, 0x07, 0x15, 0x03, 0x46, + 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, + 0x4a, 0x07, 0x0b, 0x0b, 0x15, 0x1b, 0x15, 0x1b, 0x0d, 0x17, 0x03, 0x46, 0x17, 0x03, 0x46, + 0x40, 0x40, 0x40, 0x11, 0x11, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x29, 0x27, 0x19, 0x07, + 0x1b, 0x19, 0x11, 0x42, 0x21, 0x15, 0x0d, 0x40, 0x0d, 0x11, 0x0b, 0x15, 0x0d, 0x1f, 0x13, + 0x15, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4c, 0x16, 0x02, 0x4b, 0x40, 0x09, 0x4c, 0x56, 0x27, + 0x40, 0x02, 0x40, 0x40, 0x40, 0x0f, 0x02, 0x0b, 0x41, 0x14, 0x01, 0x0b, 0x15, 0x2a, 0x2a, + 0x07, 0x07, 0x05, 0x04, 0x0a, 0x09, 0x07, 0x49, 0x27, 0x16, 0x0d, 0x40, 0x45, 0x01, 0x40, + 0x40, 0x40, 0x02, 0x02, 0x43, 0x41, 0x09, 0x41, 0x01, 0x0b, 0x43, 0x49, 0x41, 0x13, 0x41, + 0x49, 0x49, 0x01, 0x09, 0x0e, 0x0c, 0x0e, 0x43, 0x41, 0x09, 0x41, 0x01, 0x0b, 0x43, 0x49, + 0x41, 0x13, 0x41, 0x49, 0x49, 0x01, 0x09, 0x0e, 0x0c, 0x0e, 0x1c, 0x45, 0x25, 0x40, 0x48, + 0x40, 0x02, 0x07, 0x02, 0x0c, 0x0c, 0x15, 0x07, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x15, + 0x03, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x4a, 0x07, 0x0c, 0x0c, + 0x16, 0x1c, 0x16, 0x1c, 0x0d, 0x17, 0x03, 0x45, 0x17, 0x03, 0x45, 0x40, 0x40, 0x40, 0x11, + 0x11, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x2a, 0x27, 0x1a, 0x07, 0x1c, 0x1a, 0x12, 0x42, + 0x21, 0x15, 0x0d, 0x40, 0x0d, 0x12, 0x0b, 0x16, 0x0d, 0x21, 0x14, 0x16, 0x0d, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x4d, 0x17, 0x02, 0x4a, 0x40, 0x08, 0x4d, 0x57, 0x27, 0x40, 0x02, 0x40, 0x40, + 0x40, 0x0f, 0x02, 0x0d, 0x40, 0x15, 0x02, 0x0d, 0x17, 0x2c, 0x2c, 0x07, 0x07, 0x05, 0x05, + 0x0a, 0x0a, 0x07, 0x48, 0x27, 0x17, 0x0d, 0x40, 0x45, 0x00, 0x40, 0x40, 0x40, 0x02, 0x02, + 0x42, 0x40, 0x0a, 0x40, 0x02, 0x0d, 0x42, 0x48, 0x40, 0x15, 0x40, 0x48, 0x48, 0x02, 0x0a, + 0x0f, 0x0d, 0x0f, 0x42, 0x40, 0x0a, 0x40, 0x02, 0x0d, 0x42, 0x48, 0x40, 0x15, 0x40, 0x48, + 0x48, 0x02, 0x0a, 0x0f, 0x0d, 0x0f, 0x1d, 0x45, 0x27, 0x40, 0x48, 0x40, 0x02, 0x07, 0x02, + 0x0d, 0x0d, 0x17, 0x07, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, + 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, 0x07, 0x0d, 0x0d, 0x17, 0x1d, 0x17, 0x1d, + 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, 0x40, 0x10, 0x10, 0x0d, 0x40, 0x0f, + 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x12, 0x42, 0x20, 0x15, 0x0d, 0x40, + 0x0d, 0x12, 0x0a, 0x17, 0x0d, 0x22, 0x15, 0x17, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4d, 0x18, + 0x02, 0x4a, 0x40, 0x07, 0x4d, 0x58, 0x27, 0x40, 0x02, 0x40, 0x40, 0x40, 0x0f, 0x02, 0x0e, + 0x00, 0x15, 0x03, 0x0e, 0x19, 0x2f, 0x2f, 0x07, 0x07, 0x05, 0x05, 0x0a, 0x0b, 0x07, 0x47, + 0x27, 0x18, 0x0d, 0x40, 0x45, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x00, 0x0b, 0x00, + 0x03, 0x0e, 0x42, 0x47, 0x00, 0x16, 0x00, 0x47, 0x47, 0x03, 0x0b, 0x10, 0x0d, 0x10, 0x42, + 0x00, 0x0b, 0x00, 0x03, 0x0e, 0x42, 0x47, 0x00, 0x16, 0x00, 0x47, 0x47, 0x03, 0x0b, 0x10, + 0x0d, 0x10, 0x1d, 0x45, 0x29, 0x40, 0x48, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, 0x19, 0x07, + 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, + 0x1a, 0x07, 0x40, 0x4a, 0x07, 0x0d, 0x0d, 0x18, 0x1d, 0x18, 0x1d, 0x0d, 0x17, 0x02, 0x45, + 0x17, 0x02, 0x45, 0x40, 0x40, 0x40, 0x0f, 0x0f, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, + 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x12, 0x42, 0x1f, 0x15, 0x0d, 0x40, 0x0d, 0x12, 0x0a, 0x18, + 0x0d, 0x23, 0x15, 0x18, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x4e, 0x19, 0x03, 0x49, 0x40, 0x06, + 0x4e, 0x59, 0x27, 0x40, 0x03, 0x40, 0x40, 0x40, 0x0f, 0x03, 0x10, 0x01, 0x16, 0x04, 0x10, + 0x1b, 0x31, 0x31, 0x07, 0x07, 0x04, 0x06, 0x0b, 0x0c, 0x07, 0x46, 0x27, 0x19, 0x0c, 0x40, + 0x44, 0x41, 0x40, 0x40, 0x40, 0x03, 0x03, 0x41, 0x01, 0x0c, 0x01, 0x04, 0x10, 0x41, 0x46, + 0x01, 0x18, 0x01, 0x46, 0x46, 0x04, 0x0c, 0x11, 0x0e, 0x11, 0x41, 0x01, 0x0c, 0x01, 0x04, + 0x10, 0x41, 0x46, 0x01, 0x18, 0x01, 0x46, 0x46, 0x04, 0x0c, 0x11, 0x0e, 0x11, 0x1e, 0x44, + 0x2b, 0x40, 0x48, 0x40, 0x03, 0x07, 0x03, 0x0e, 0x0e, 0x1b, 0x07, 0x14, 0x01, 0x44, 0x1b, + 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x4b, + 0x07, 0x0e, 0x0e, 0x19, 0x1e, 0x19, 0x1e, 0x0c, 0x17, 0x01, 0x44, 0x17, 0x01, 0x44, 0x40, + 0x40, 0x40, 0x0e, 0x0e, 0x0c, 0x40, 0x0f, 0x0c, 0x09, 0x09, 0x2b, 0x27, 0x1b, 0x07, 0x1e, + 0x1b, 0x13, 0x43, 0x1e, 0x14, 0x0c, 0x40, 0x0c, 0x13, 0x09, 0x19, 0x0c, 0x24, 0x16, 0x19, + 0x0c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x4f, 0x1a, 0x03, 0x48, 0x40, 0x05, 0x4f, 0x5a, 0x27, 0x40, + 0x03, 0x40, 0x40, 0x40, 0x0f, 0x03, 0x11, 0x02, 0x17, 0x06, 0x11, 0x1d, 0x34, 0x34, 0x07, + 0x07, 0x04, 0x07, 0x0b, 0x0e, 0x07, 0x45, 0x27, 0x1a, 0x0c, 0x40, 0x44, 0x42, 0x40, 0x40, + 0x40, 0x03, 0x03, 0x40, 0x02, 0x0e, 0x02, 0x06, 0x11, 0x40, 0x45, 0x02, 0x19, 0x02, 0x45, + 0x45, 0x06, 0x0e, 0x12, 0x0f, 0x12, 0x40, 0x02, 0x0e, 0x02, 0x06, 0x11, 0x40, 0x45, 0x02, + 0x19, 0x02, 0x45, 0x45, 0x06, 0x0e, 0x12, 0x0f, 0x12, 0x1f, 0x44, 0x2d, 0x40, 0x48, 0x40, + 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1d, 0x07, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, + 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, 0x07, 0x0f, 0x0f, 0x1a, + 0x1f, 0x1a, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, 0x40, 0x0d, 0x0d, + 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x13, 0x43, 0x1d, + 0x14, 0x0c, 0x40, 0x0c, 0x13, 0x08, 0x1a, 0x0c, 0x26, 0x17, 0x1a, 0x0c, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x4f, 0x1b, 0x03, 0x48, 0x40, 0x04, 0x4f, 0x5b, 0x27, 0x40, 0x03, 0x40, 0x40, 0x40, + 0x0f, 0x03, 0x13, 0x03, 0x17, 0x07, 0x13, 0x1f, 0x36, 0x36, 0x07, 0x07, 0x04, 0x07, 0x0b, + 0x0f, 0x07, 0x44, 0x27, 0x1b, 0x0c, 0x40, 0x44, 0x43, 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, + 0x03, 0x0f, 0x03, 0x07, 0x13, 0x40, 0x44, 0x03, 0x1b, 0x03, 0x44, 0x44, 0x07, 0x0f, 0x13, + 0x0f, 0x13, 0x40, 0x03, 0x0f, 0x03, 0x07, 0x13, 0x40, 0x44, 0x03, 0x1b, 0x03, 0x44, 0x44, + 0x07, 0x0f, 0x13, 0x0f, 0x13, 0x1f, 0x44, 0x2f, 0x40, 0x48, 0x40, 0x03, 0x07, 0x03, 0x0f, + 0x0f, 0x1f, 0x07, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, + 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, 0x07, 0x0f, 0x0f, 0x1b, 0x1f, 0x1b, 0x1f, 0x0c, + 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, 0x40, 0x0c, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, + 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x13, 0x43, 0x1c, 0x14, 0x0c, 0x40, 0x0c, + 0x13, 0x08, 0x1b, 0x0c, 0x27, 0x17, 0x1b, 0x0c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x50, 0x1c, 0x04, + 0x47, 0x40, 0x03, 0x50, 0x5c, 0x27, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, 0x04, 0x14, 0x04, + 0x18, 0x08, 0x14, 0x21, 0x39, 0x39, 0x07, 0x07, 0x03, 0x08, 0x0c, 0x10, 0x07, 0x43, 0x27, + 0x1c, 0x0b, 0x40, 0x43, 0x44, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x04, 0x10, 0x04, 0x08, + 0x14, 0x00, 0x43, 0x04, 0x1c, 0x04, 0x43, 0x43, 0x08, 0x10, 0x14, 0x10, 0x14, 0x00, 0x04, + 0x10, 0x04, 0x08, 0x14, 0x00, 0x43, 0x04, 0x1c, 0x04, 0x43, 0x43, 0x08, 0x10, 0x14, 0x10, + 0x14, 0x20, 0x43, 0x31, 0x40, 0x48, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x21, 0x07, 0x13, + 0x40, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, + 0x07, 0x40, 0x4c, 0x07, 0x10, 0x10, 0x1c, 0x20, 0x1c, 0x20, 0x0b, 0x17, 0x40, 0x43, 0x17, + 0x40, 0x43, 0x40, 0x40, 0x40, 0x0b, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x07, 0x07, 0x2c, 0x27, + 0x1c, 0x07, 0x20, 0x1c, 0x14, 0x44, 0x1b, 0x13, 0x0b, 0x40, 0x0b, 0x14, 0x07, 0x1c, 0x0b, + 0x28, 0x18, 0x1c, 0x0b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x51, 0x1d, 0x04, 0x47, 0x40, 0x02, 0x51, + 0x5d, 0x27, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, 0x04, 0x16, 0x05, 0x18, 0x09, 0x16, 0x22, + 0x3b, 0x3b, 0x07, 0x07, 0x03, 0x08, 0x0c, 0x11, 0x07, 0x42, 0x27, 0x1d, 0x0b, 0x40, 0x43, + 0x45, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x05, 0x11, 0x05, 0x09, 0x16, 0x00, 0x42, 0x05, + 0x1e, 0x05, 0x42, 0x42, 0x09, 0x11, 0x15, 0x10, 0x15, 0x00, 0x05, 0x11, 0x05, 0x09, 0x16, + 0x00, 0x42, 0x05, 0x1e, 0x05, 0x42, 0x42, 0x09, 0x11, 0x15, 0x10, 0x15, 0x20, 0x43, 0x32, + 0x40, 0x48, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x22, 0x07, 0x13, 0x41, 0x43, 0x1c, 0x07, + 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, 0x07, + 0x10, 0x10, 0x1d, 0x20, 0x1d, 0x20, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, + 0x40, 0x0a, 0x0a, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, + 0x14, 0x44, 0x1a, 0x13, 0x0b, 0x40, 0x0b, 0x14, 0x06, 0x1d, 0x0b, 0x29, 0x18, 0x1d, 0x0b, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x51, 0x1e, 0x04, 0x46, 0x40, 0x01, 0x51, 0x5e, 0x27, 0x40, 0x04, + 0x40, 0x40, 0x40, 0x0f, 0x04, 0x18, 0x06, 0x19, 0x0b, 0x18, 0x24, 0x3e, 0x3e, 0x07, 0x07, + 0x03, 0x09, 0x0c, 0x13, 0x07, 0x41, 0x27, 0x1e, 0x0b, 0x40, 0x43, 0x46, 0x40, 0x40, 0x40, + 0x04, 0x04, 0x01, 0x06, 0x13, 0x06, 0x0b, 0x18, 0x01, 0x41, 0x06, 0x20, 0x06, 0x41, 0x41, + 0x0b, 0x13, 0x16, 0x11, 0x16, 0x01, 0x06, 0x13, 0x06, 0x0b, 0x18, 0x01, 0x41, 0x06, 0x20, + 0x06, 0x41, 0x41, 0x0b, 0x13, 0x16, 0x11, 0x16, 0x21, 0x43, 0x34, 0x40, 0x48, 0x40, 0x04, + 0x07, 0x04, 0x11, 0x11, 0x24, 0x07, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, + 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, 0x07, 0x11, 0x11, 0x1e, 0x21, + 0x1e, 0x21, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, 0x40, 0x09, 0x09, 0x0b, + 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x21, 0x1c, 0x14, 0x44, 0x19, 0x13, + 0x0b, 0x40, 0x0b, 0x14, 0x06, 0x1e, 0x0b, 0x2b, 0x19, 0x1e, 0x0b, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x52, 0x1f, 0x05, 0x45, 0x40, 0x00, 0x52, 0x5f, 0x27, 0x40, 0x05, 0x40, 0x40, 0x40, 0x0f, + 0x05, 0x19, 0x07, 0x1a, 0x0c, 0x19, 0x26, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0a, 0x0d, 0x14, + 0x07, 0x40, 0x27, 0x1f, 0x0a, 0x40, 0x42, 0x47, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x07, + 0x14, 0x07, 0x0c, 0x19, 0x02, 0x40, 0x07, 0x21, 0x07, 0x40, 0x40, 0x0c, 0x14, 0x17, 0x12, + 0x17, 0x02, 0x07, 0x14, 0x07, 0x0c, 0x19, 0x02, 0x40, 0x07, 0x21, 0x07, 0x40, 0x40, 0x0c, + 0x14, 0x17, 0x12, 0x17, 0x22, 0x42, 0x36, 0x40, 0x48, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, + 0x26, 0x07, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, + 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, 0x07, 0x12, 0x12, 0x1f, 0x22, 0x1f, 0x22, 0x0a, 0x17, + 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, 0x40, 0x08, 0x08, 0x0a, 0x40, 0x0f, 0x0a, 0x05, + 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x15, 0x45, 0x18, 0x12, 0x0a, 0x40, 0x0a, 0x15, + 0x05, 0x1f, 0x0a, 0x2c, 0x1a, 0x1f, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x52, 0x20, 0x05, 0x45, + 0x40, 0x40, 0x52, 0x60, 0x27, 0x40, 0x05, 0x40, 0x40, 0x40, 0x0f, 0x05, 0x1b, 0x08, 0x1a, + 0x0d, 0x1b, 0x28, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0a, 0x0d, 0x15, 0x07, 0x00, 0x27, 0x20, + 0x0a, 0x40, 0x42, 0x48, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x08, 0x15, 0x08, 0x0d, 0x1b, + 0x02, 0x00, 0x08, 0x23, 0x08, 0x00, 0x00, 0x0d, 0x15, 0x18, 0x12, 0x18, 0x02, 0x08, 0x15, + 0x08, 0x0d, 0x1b, 0x02, 0x00, 0x08, 0x23, 0x08, 0x00, 0x00, 0x0d, 0x15, 0x18, 0x12, 0x18, + 0x22, 0x42, 0x38, 0x40, 0x48, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x28, 0x07, 0x12, 0x42, + 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, + 0x40, 0x4d, 0x07, 0x12, 0x12, 0x20, 0x22, 0x20, 0x22, 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, + 0x42, 0x40, 0x40, 0x40, 0x07, 0x07, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, + 0x07, 0x22, 0x1d, 0x15, 0x45, 0x17, 0x12, 0x0a, 0x40, 0x0a, 0x15, 0x05, 0x20, 0x0a, 0x2d, + 0x1a, 0x20, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x53, 0x21, 0x05, 0x44, 0x40, 0x41, 0x53, 0x61, + 0x27, 0x40, 0x05, 0x40, 0x40, 0x40, 0x0f, 0x05, 0x1c, 0x09, 0x1b, 0x0e, 0x1c, 0x2a, 0x3e, + 0x3e, 0x07, 0x07, 0x02, 0x0b, 0x0d, 0x16, 0x07, 0x01, 0x27, 0x21, 0x0a, 0x40, 0x42, 0x49, + 0x40, 0x40, 0x40, 0x05, 0x05, 0x03, 0x09, 0x16, 0x09, 0x0e, 0x1c, 0x03, 0x01, 0x09, 0x24, + 0x09, 0x01, 0x01, 0x0e, 0x16, 0x19, 0x13, 0x19, 0x03, 0x09, 0x16, 0x09, 0x0e, 0x1c, 0x03, + 0x01, 0x09, 0x24, 0x09, 0x01, 0x01, 0x0e, 0x16, 0x19, 0x13, 0x19, 0x23, 0x42, 0x3a, 0x40, + 0x48, 0x40, 0x05, 0x07, 0x05, 0x13, 0x13, 0x2a, 0x07, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, + 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x4d, 0x07, 0x13, + 0x13, 0x21, 0x23, 0x21, 0x23, 0x0a, 0x17, 0x43, 0x42, 0x17, 0x43, 0x42, 0x40, 0x40, 0x40, + 0x06, 0x06, 0x0a, 0x40, 0x0f, 0x0a, 0x04, 0x04, 0x2d, 0x27, 0x1d, 0x07, 0x23, 0x1d, 0x15, + 0x45, 0x16, 0x12, 0x0a, 0x40, 0x0a, 0x15, 0x04, 0x21, 0x0a, 0x2e, 0x1b, 0x21, 0x0a, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x54, 0x22, 0x06, 0x43, 0x40, 0x42, 0x54, 0x62, 0x27, 0x40, 0x06, 0x40, + 0x40, 0x40, 0x0f, 0x06, 0x1e, 0x0a, 0x1c, 0x10, 0x1e, 0x2c, 0x3e, 0x3e, 0x07, 0x07, 0x01, + 0x0c, 0x0e, 0x18, 0x07, 0x02, 0x27, 0x22, 0x09, 0x40, 0x41, 0x4a, 0x40, 0x40, 0x40, 0x06, + 0x06, 0x04, 0x0a, 0x18, 0x0a, 0x10, 0x1e, 0x04, 0x02, 0x0a, 0x26, 0x0a, 0x02, 0x02, 0x10, + 0x18, 0x1a, 0x14, 0x1a, 0x04, 0x0a, 0x18, 0x0a, 0x10, 0x1e, 0x04, 0x02, 0x0a, 0x26, 0x0a, + 0x02, 0x02, 0x10, 0x18, 0x1a, 0x14, 0x1a, 0x24, 0x41, 0x3c, 0x40, 0x48, 0x40, 0x06, 0x07, + 0x06, 0x14, 0x14, 0x2c, 0x07, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, + 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, 0x07, 0x14, 0x14, 0x22, 0x24, 0x22, + 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, 0x40, 0x05, 0x05, 0x09, 0x40, + 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x16, 0x46, 0x15, 0x11, 0x09, + 0x40, 0x09, 0x16, 0x03, 0x22, 0x09, 0x30, 0x1c, 0x22, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x54, + 0x23, 0x06, 0x43, 0x40, 0x43, 0x54, 0x63, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, 0x06, + 0x1f, 0x0b, 0x1c, 0x11, 0x1f, 0x2e, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x0c, 0x0e, 0x19, 0x07, + 0x03, 0x27, 0x23, 0x09, 0x40, 0x41, 0x4b, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, 0x0b, 0x19, + 0x0b, 0x11, 0x1f, 0x04, 0x03, 0x0b, 0x27, 0x0b, 0x03, 0x03, 0x11, 0x19, 0x1b, 0x14, 0x1b, + 0x04, 0x0b, 0x19, 0x0b, 0x11, 0x1f, 0x04, 0x03, 0x0b, 0x27, 0x0b, 0x03, 0x03, 0x11, 0x19, + 0x1b, 0x14, 0x1b, 0x24, 0x41, 0x3e, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x14, 0x14, 0x2e, + 0x07, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, + 0x41, 0x1e, 0x07, 0x40, 0x4e, 0x07, 0x14, 0x14, 0x23, 0x24, 0x23, 0x24, 0x09, 0x17, 0x44, + 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, 0x40, 0x04, 0x04, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, + 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x16, 0x46, 0x14, 0x11, 0x09, 0x40, 0x09, 0x16, 0x03, + 0x23, 0x09, 0x31, 0x1c, 0x23, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x55, 0x24, 0x06, 0x42, 0x40, + 0x44, 0x55, 0x64, 0x27, 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, 0x06, 0x21, 0x0c, 0x1d, 0x12, + 0x21, 0x30, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x0d, 0x0e, 0x1a, 0x07, 0x04, 0x27, 0x24, 0x09, + 0x40, 0x41, 0x4c, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x1a, 0x0c, 0x12, 0x21, 0x05, + 0x04, 0x0c, 0x29, 0x0c, 0x04, 0x04, 0x12, 0x1a, 0x1c, 0x15, 0x1c, 0x05, 0x0c, 0x1a, 0x0c, + 0x12, 0x21, 0x05, 0x04, 0x0c, 0x29, 0x0c, 0x04, 0x04, 0x12, 0x1a, 0x1c, 0x15, 0x1c, 0x25, + 0x41, 0x3e, 0x40, 0x48, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x30, 0x07, 0x11, 0x45, 0x41, + 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, + 0x4e, 0x07, 0x15, 0x15, 0x24, 0x25, 0x24, 0x25, 0x09, 0x17, 0x45, 0x41, 0x17, 0x45, 0x41, + 0x40, 0x40, 0x40, 0x03, 0x03, 0x09, 0x40, 0x0f, 0x09, 0x02, 0x02, 0x2e, 0x27, 0x1e, 0x07, + 0x25, 0x1e, 0x16, 0x46, 0x13, 0x11, 0x09, 0x40, 0x09, 0x16, 0x02, 0x24, 0x09, 0x32, 0x1d, + 0x24, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x56, 0x24, 0x06, 0x42, 0x40, 0x45, 0x56, 0x65, 0x27, + 0x40, 0x06, 0x40, 0x40, 0x40, 0x0f, 0x06, 0x22, 0x0c, 0x1d, 0x13, 0x22, 0x31, 0x3e, 0x3e, + 0x07, 0x07, 0x00, 0x0d, 0x0e, 0x1b, 0x07, 0x04, 0x27, 0x24, 0x08, 0x40, 0x41, 0x4d, 0x40, + 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x1b, 0x0c, 0x13, 0x22, 0x05, 0x04, 0x0c, 0x2a, 0x0c, + 0x04, 0x04, 0x13, 0x1b, 0x1c, 0x15, 0x1c, 0x05, 0x0c, 0x1b, 0x0c, 0x13, 0x22, 0x05, 0x04, + 0x0c, 0x2a, 0x0c, 0x04, 0x04, 0x13, 0x1b, 0x1c, 0x15, 0x1c, 0x25, 0x41, 0x3e, 0x40, 0x48, + 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x31, 0x07, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x10, + 0x46, 0x41, 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x4f, 0x07, 0x15, 0x15, + 0x24, 0x25, 0x24, 0x25, 0x08, 0x17, 0x46, 0x41, 0x17, 0x46, 0x41, 0x40, 0x40, 0x40, 0x02, + 0x02, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, 0x16, 0x47, + 0x12, 0x10, 0x08, 0x40, 0x08, 0x16, 0x01, 0x24, 0x08, 0x33, 0x1d, 0x24, 0x08, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x56, 0x25, 0x07, 0x41, 0x40, 0x45, 0x56, 0x65, 0x27, 0x40, 0x07, 0x40, 0x40, + 0x40, 0x0f, 0x07, 0x24, 0x0d, 0x1e, 0x15, 0x24, 0x33, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0e, + 0x0f, 0x1d, 0x07, 0x05, 0x27, 0x25, 0x08, 0x40, 0x40, 0x4d, 0x40, 0x40, 0x40, 0x07, 0x07, + 0x06, 0x0d, 0x1d, 0x0d, 0x15, 0x24, 0x06, 0x05, 0x0d, 0x2c, 0x0d, 0x05, 0x05, 0x15, 0x1d, + 0x1d, 0x16, 0x1d, 0x06, 0x0d, 0x1d, 0x0d, 0x15, 0x24, 0x06, 0x05, 0x0d, 0x2c, 0x0d, 0x05, + 0x05, 0x15, 0x1d, 0x1d, 0x16, 0x1d, 0x26, 0x40, 0x3e, 0x40, 0x48, 0x40, 0x07, 0x07, 0x07, + 0x16, 0x16, 0x33, 0x07, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, + 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x4f, 0x07, 0x16, 0x16, 0x25, 0x26, 0x25, 0x26, + 0x08, 0x17, 0x46, 0x40, 0x17, 0x46, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x08, 0x40, 0x0f, + 0x08, 0x01, 0x01, 0x2f, 0x27, 0x1f, 0x07, 0x26, 0x1f, 0x17, 0x47, 0x12, 0x10, 0x08, 0x40, + 0x08, 0x17, 0x01, 0x25, 0x08, 0x35, 0x1e, 0x25, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x57, 0x26, + 0x07, 0x40, 0x40, 0x46, 0x57, 0x66, 0x27, 0x40, 0x07, 0x40, 0x40, 0x40, 0x0f, 0x07, 0x26, + 0x0e, 0x1f, 0x16, 0x26, 0x35, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0f, 0x0f, 0x1e, 0x07, 0x06, + 0x27, 0x26, 0x08, 0x40, 0x40, 0x4e, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0e, 0x1e, 0x0e, + 0x16, 0x26, 0x07, 0x06, 0x0e, 0x2e, 0x0e, 0x06, 0x06, 0x16, 0x1e, 0x1e, 0x17, 0x1e, 0x07, + 0x0e, 0x1e, 0x0e, 0x16, 0x26, 0x07, 0x06, 0x0e, 0x2e, 0x0e, 0x06, 0x06, 0x16, 0x1e, 0x1e, + 0x17, 0x1e, 0x27, 0x40, 0x3e, 0x40, 0x48, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x35, 0x07, + 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, + 0x1f, 0x07, 0x40, 0x4f, 0x07, 0x17, 0x17, 0x26, 0x27, 0x26, 0x27, 0x08, 0x17, 0x47, 0x40, + 0x17, 0x47, 0x40, 0x40, 0x40, 0x40, 0x01, 0x01, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, + 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x17, 0x47, 0x11, 0x10, 0x08, 0x40, 0x08, 0x17, 0x00, 0x26, + 0x08, 0x36, 0x1f, 0x26, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x57, 0x27, 0x07, 0x40, 0x40, 0x47, + 0x57, 0x67, 0x27, 0x40, 0x07, 0x40, 0x40, 0x40, 0x0f, 0x07, 0x27, 0x0f, 0x1f, 0x17, 0x27, + 0x37, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x0f, 0x0f, 0x1f, 0x07, 0x07, 0x27, 0x27, 0x08, 0x40, + 0x40, 0x4f, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0f, 0x1f, 0x0f, 0x17, 0x27, 0x07, 0x07, + 0x0f, 0x2f, 0x0f, 0x07, 0x07, 0x17, 0x1f, 0x1f, 0x17, 0x1f, 0x07, 0x0f, 0x1f, 0x0f, 0x17, + 0x27, 0x07, 0x07, 0x0f, 0x2f, 0x0f, 0x07, 0x07, 0x17, 0x1f, 0x1f, 0x17, 0x1f, 0x27, 0x40, + 0x3e, 0x40, 0x48, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x37, 0x07, 0x10, 0x47, 0x40, 0x1f, + 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, + 0x07, 0x17, 0x17, 0x27, 0x27, 0x27, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, + 0x1f, 0x17, 0x47, 0x10, 0x10, 0x08, 0x40, 0x08, 0x17, 0x00, 0x27, 0x08, 0x37, 0x1f, 0x27, + 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x48, 0x48, 0x60, 0x40, 0x27, 0x07, 0x07, 0x1f, 0x40, + 0x48, 0x40, 0x40, 0x17, 0x0f, 0x48, 0x68, 0x40, 0x07, 0x68, 0x68, 0x68, 0x68, 0x68, 0x07, + 0x07, 0x0f, 0x3e, 0x17, 0x40, 0x07, 0x68, 0x27, 0x50, 0x17, 0x40, 0x07, 0x1f, 0x40, 0x40, + 0x40, 0x48, 0x48, 0x58, 0x60, 0x50, 0x60, 0x68, 0x60, 0x58, 0x68, 0x68, 0x68, 0x58, 0x60, + 0x68, 0x68, 0x68, 0x50, 0x48, 0x58, 0x58, 0x60, 0x50, 0x60, 0x68, 0x60, 0x58, 0x68, 0x68, + 0x68, 0x58, 0x60, 0x68, 0x68, 0x68, 0x50, 0x48, 0x58, 0x07, 0x50, 0x58, 0x40, 0x40, 0x40, + 0x48, 0x07, 0x48, 0x48, 0x48, 0x68, 0x50, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x1f, 0x17, + 0x50, 0x0f, 0x07, 0x40, 0x1f, 0x17, 0x50, 0x0f, 0x07, 0x40, 0x40, 0x07, 0x40, 0x40, 0x40, + 0x07, 0x40, 0x07, 0x17, 0x17, 0x17, 0x50, 0x17, 0x17, 0x50, 0x40, 0x40, 0x40, 0x2f, 0x17, + 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x1f, 0x1f, 0x27, 0x0f, 0x07, 0x07, 0x0f, 0x40, 0x07, 0x3e, + 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1f, 0x48, 0x17, 0x48, 0x48, 0x48, 0x17, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x3e, 0x47, 0x47, 0x5f, 0x40, 0x27, 0x07, 0x07, 0x20, 0x40, 0x47, 0x40, 0x40, 0x17, + 0x0f, 0x47, 0x66, 0x40, 0x08, 0x66, 0x66, 0x66, 0x65, 0x65, 0x07, 0x07, 0x0f, 0x3e, 0x17, + 0x00, 0x07, 0x67, 0x27, 0x4e, 0x17, 0x40, 0x07, 0x1f, 0x40, 0x40, 0x40, 0x47, 0x47, 0x57, + 0x5f, 0x4f, 0x5f, 0x66, 0x5e, 0x57, 0x67, 0x67, 0x66, 0x57, 0x5f, 0x67, 0x67, 0x66, 0x4f, + 0x47, 0x56, 0x57, 0x5f, 0x4f, 0x5f, 0x66, 0x5e, 0x57, 0x67, 0x67, 0x66, 0x57, 0x5f, 0x67, + 0x67, 0x66, 0x4f, 0x47, 0x56, 0x08, 0x4f, 0x56, 0x40, 0x40, 0x40, 0x47, 0x07, 0x47, 0x47, + 0x47, 0x66, 0x4f, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, + 0x1f, 0x17, 0x4f, 0x10, 0x07, 0x40, 0x40, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x08, 0x17, + 0x17, 0x17, 0x4f, 0x17, 0x17, 0x4f, 0x40, 0x40, 0x40, 0x2f, 0x17, 0x17, 0x40, 0x0f, 0x17, + 0x1f, 0x1f, 0x20, 0x27, 0x10, 0x07, 0x08, 0x10, 0x00, 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, + 0x17, 0x1f, 0x47, 0x17, 0x46, 0x47, 0x47, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x46, 0x47, + 0x5e, 0x40, 0x26, 0x06, 0x06, 0x20, 0x40, 0x47, 0x40, 0x40, 0x16, 0x0f, 0x47, 0x64, 0x40, + 0x08, 0x65, 0x64, 0x64, 0x63, 0x63, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x01, 0x07, 0x66, 0x27, + 0x4d, 0x17, 0x40, 0x07, 0x1e, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5e, 0x4e, 0x5e, 0x65, + 0x5d, 0x56, 0x66, 0x66, 0x64, 0x56, 0x5e, 0x66, 0x66, 0x64, 0x4e, 0x46, 0x55, 0x56, 0x5e, + 0x4e, 0x5e, 0x65, 0x5d, 0x56, 0x66, 0x66, 0x64, 0x56, 0x5e, 0x66, 0x66, 0x64, 0x4e, 0x46, + 0x55, 0x09, 0x4f, 0x54, 0x40, 0x40, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x64, 0x4e, 0x1f, + 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, + 0x07, 0x40, 0x40, 0x07, 0x00, 0x00, 0x01, 0x09, 0x01, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, + 0x16, 0x4f, 0x40, 0x40, 0x40, 0x2e, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, + 0x10, 0x07, 0x09, 0x10, 0x01, 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x46, 0x17, + 0x45, 0x46, 0x46, 0x17, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x45, 0x47, 0x5e, 0x40, 0x25, 0x06, + 0x05, 0x20, 0x40, 0x47, 0x40, 0x40, 0x16, 0x0f, 0x47, 0x63, 0x40, 0x08, 0x64, 0x63, 0x62, + 0x60, 0x60, 0x07, 0x07, 0x0f, 0x3e, 0x17, 0x01, 0x07, 0x65, 0x27, 0x4c, 0x17, 0x40, 0x07, + 0x1d, 0x40, 0x40, 0x40, 0x47, 0x47, 0x56, 0x5d, 0x4e, 0x5d, 0x64, 0x5c, 0x56, 0x65, 0x65, + 0x63, 0x56, 0x5e, 0x65, 0x65, 0x63, 0x4d, 0x46, 0x54, 0x56, 0x5d, 0x4e, 0x5d, 0x64, 0x5c, + 0x56, 0x65, 0x65, 0x63, 0x56, 0x5e, 0x65, 0x65, 0x63, 0x4d, 0x46, 0x54, 0x09, 0x4f, 0x52, + 0x40, 0x40, 0x40, 0x47, 0x07, 0x47, 0x46, 0x46, 0x62, 0x4e, 0x1f, 0x16, 0x4f, 0x10, 0x07, + 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x1f, 0x16, 0x4f, 0x10, 0x07, 0x40, 0x40, 0x07, + 0x00, 0x00, 0x01, 0x09, 0x01, 0x09, 0x17, 0x17, 0x16, 0x4f, 0x17, 0x16, 0x4f, 0x40, 0x40, + 0x40, 0x2d, 0x17, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x1e, 0x20, 0x27, 0x10, 0x07, 0x09, 0x10, + 0x01, 0x07, 0x3e, 0x1f, 0x17, 0x40, 0x0f, 0x17, 0x1e, 0x45, 0x17, 0x44, 0x45, 0x45, 0x17, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x3e, 0x44, 0x46, 0x5d, 0x40, 0x24, 0x05, 0x04, 0x21, 0x40, 0x46, + 0x40, 0x40, 0x15, 0x0f, 0x46, 0x61, 0x40, 0x09, 0x63, 0x61, 0x60, 0x5e, 0x5e, 0x07, 0x07, + 0x0e, 0x3e, 0x16, 0x02, 0x07, 0x64, 0x27, 0x4b, 0x16, 0x40, 0x06, 0x1c, 0x40, 0x40, 0x40, + 0x46, 0x46, 0x55, 0x5c, 0x4d, 0x5c, 0x63, 0x5b, 0x55, 0x64, 0x64, 0x61, 0x55, 0x5d, 0x64, + 0x64, 0x61, 0x4c, 0x45, 0x53, 0x55, 0x5c, 0x4d, 0x5c, 0x63, 0x5b, 0x55, 0x64, 0x64, 0x61, + 0x55, 0x5d, 0x64, 0x64, 0x61, 0x4c, 0x45, 0x53, 0x0a, 0x4e, 0x50, 0x40, 0x41, 0x40, 0x46, + 0x07, 0x46, 0x45, 0x45, 0x60, 0x4d, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, + 0x11, 0x07, 0x40, 0x1e, 0x15, 0x4e, 0x11, 0x07, 0x40, 0x41, 0x07, 0x01, 0x01, 0x02, 0x0a, + 0x02, 0x0a, 0x16, 0x17, 0x15, 0x4e, 0x17, 0x15, 0x4e, 0x40, 0x40, 0x40, 0x2c, 0x16, 0x16, + 0x40, 0x0f, 0x16, 0x1d, 0x1d, 0x21, 0x27, 0x11, 0x07, 0x0a, 0x11, 0x02, 0x06, 0x3e, 0x1e, + 0x16, 0x40, 0x0f, 0x16, 0x1d, 0x44, 0x16, 0x43, 0x44, 0x44, 0x16, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x3e, 0x43, 0x46, 0x5c, 0x40, 0x23, 0x04, 0x03, 0x21, 0x40, 0x46, 0x40, 0x40, 0x14, 0x0f, + 0x46, 0x60, 0x40, 0x09, 0x61, 0x60, 0x5e, 0x5b, 0x5b, 0x07, 0x07, 0x0e, 0x3e, 0x16, 0x03, + 0x07, 0x63, 0x27, 0x49, 0x16, 0x40, 0x06, 0x1b, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5b, + 0x4c, 0x5b, 0x61, 0x59, 0x54, 0x63, 0x63, 0x60, 0x54, 0x5c, 0x63, 0x63, 0x60, 0x4b, 0x44, + 0x51, 0x54, 0x5b, 0x4c, 0x5b, 0x61, 0x59, 0x54, 0x63, 0x63, 0x60, 0x54, 0x5c, 0x63, 0x63, + 0x60, 0x4b, 0x44, 0x51, 0x0b, 0x4e, 0x4e, 0x40, 0x41, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, + 0x5e, 0x4c, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, + 0x14, 0x4e, 0x11, 0x07, 0x40, 0x41, 0x07, 0x01, 0x01, 0x03, 0x0b, 0x03, 0x0b, 0x16, 0x17, + 0x14, 0x4e, 0x17, 0x14, 0x4e, 0x40, 0x40, 0x40, 0x2b, 0x16, 0x16, 0x40, 0x0f, 0x16, 0x1c, + 0x1c, 0x21, 0x27, 0x11, 0x07, 0x0b, 0x11, 0x03, 0x06, 0x3e, 0x1e, 0x16, 0x40, 0x0f, 0x16, + 0x1c, 0x43, 0x16, 0x41, 0x43, 0x43, 0x16, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x42, 0x46, 0x5c, + 0x40, 0x22, 0x04, 0x02, 0x21, 0x40, 0x46, 0x40, 0x40, 0x14, 0x0f, 0x46, 0x5e, 0x40, 0x09, + 0x60, 0x5e, 0x5c, 0x59, 0x59, 0x07, 0x07, 0x0e, 0x3e, 0x16, 0x03, 0x07, 0x62, 0x27, 0x48, + 0x16, 0x40, 0x06, 0x1a, 0x40, 0x40, 0x40, 0x46, 0x46, 0x54, 0x5a, 0x4c, 0x5a, 0x60, 0x58, + 0x54, 0x62, 0x62, 0x5e, 0x54, 0x5c, 0x62, 0x62, 0x5e, 0x4a, 0x44, 0x50, 0x54, 0x5a, 0x4c, + 0x5a, 0x60, 0x58, 0x54, 0x62, 0x62, 0x5e, 0x54, 0x5c, 0x62, 0x62, 0x5e, 0x4a, 0x44, 0x50, + 0x0b, 0x4e, 0x4c, 0x40, 0x41, 0x40, 0x46, 0x07, 0x46, 0x44, 0x44, 0x5c, 0x4c, 0x1e, 0x14, + 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, 0x40, 0x1e, 0x14, 0x4e, 0x11, 0x07, + 0x40, 0x41, 0x07, 0x01, 0x01, 0x03, 0x0b, 0x03, 0x0b, 0x16, 0x17, 0x14, 0x4e, 0x17, 0x14, + 0x4e, 0x40, 0x40, 0x40, 0x2a, 0x16, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x1c, 0x21, 0x27, 0x11, + 0x07, 0x0b, 0x11, 0x03, 0x06, 0x3e, 0x1e, 0x16, 0x40, 0x0f, 0x16, 0x1c, 0x42, 0x16, 0x40, + 0x42, 0x42, 0x16, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x41, 0x45, 0x5b, 0x40, 0x21, 0x03, 0x01, + 0x22, 0x40, 0x45, 0x40, 0x40, 0x13, 0x0f, 0x45, 0x5d, 0x40, 0x0a, 0x5f, 0x5d, 0x5a, 0x56, + 0x56, 0x07, 0x07, 0x0d, 0x3e, 0x15, 0x04, 0x07, 0x61, 0x27, 0x47, 0x15, 0x40, 0x05, 0x19, + 0x40, 0x40, 0x40, 0x45, 0x45, 0x53, 0x59, 0x4b, 0x59, 0x5f, 0x57, 0x53, 0x61, 0x61, 0x5d, + 0x53, 0x5b, 0x61, 0x61, 0x5d, 0x49, 0x43, 0x4f, 0x53, 0x59, 0x4b, 0x59, 0x5f, 0x57, 0x53, + 0x61, 0x61, 0x5d, 0x53, 0x5b, 0x61, 0x61, 0x5d, 0x49, 0x43, 0x4f, 0x0c, 0x4d, 0x4a, 0x40, + 0x42, 0x40, 0x45, 0x07, 0x45, 0x43, 0x43, 0x5a, 0x4b, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, + 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x13, 0x4d, 0x12, 0x07, 0x40, 0x42, 0x07, 0x02, + 0x02, 0x04, 0x0c, 0x04, 0x0c, 0x15, 0x17, 0x13, 0x4d, 0x17, 0x13, 0x4d, 0x40, 0x40, 0x40, + 0x29, 0x15, 0x15, 0x40, 0x0f, 0x15, 0x1b, 0x1b, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x04, + 0x05, 0x3e, 0x1d, 0x15, 0x40, 0x0f, 0x15, 0x1b, 0x41, 0x15, 0x00, 0x41, 0x41, 0x15, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x3e, 0x40, 0x45, 0x5b, 0x40, 0x20, 0x02, 0x00, 0x22, 0x40, 0x45, 0x40, + 0x40, 0x12, 0x0f, 0x45, 0x5b, 0x40, 0x0a, 0x5e, 0x5b, 0x59, 0x54, 0x54, 0x07, 0x07, 0x0d, + 0x3e, 0x15, 0x04, 0x07, 0x60, 0x27, 0x46, 0x15, 0x40, 0x05, 0x18, 0x40, 0x40, 0x40, 0x45, + 0x45, 0x53, 0x58, 0x4b, 0x58, 0x5e, 0x56, 0x53, 0x60, 0x60, 0x5b, 0x53, 0x5b, 0x60, 0x60, + 0x5b, 0x48, 0x43, 0x4e, 0x53, 0x58, 0x4b, 0x58, 0x5e, 0x56, 0x53, 0x60, 0x60, 0x5b, 0x53, + 0x5b, 0x60, 0x60, 0x5b, 0x48, 0x43, 0x4e, 0x0c, 0x4d, 0x49, 0x40, 0x42, 0x40, 0x45, 0x07, + 0x45, 0x43, 0x43, 0x59, 0x4b, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, + 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x42, 0x07, 0x02, 0x02, 0x04, 0x0c, 0x04, + 0x0c, 0x15, 0x17, 0x12, 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, 0x40, 0x28, 0x15, 0x15, 0x40, + 0x0f, 0x15, 0x1a, 0x1a, 0x22, 0x27, 0x12, 0x07, 0x0c, 0x12, 0x04, 0x05, 0x3e, 0x1d, 0x15, + 0x40, 0x0f, 0x15, 0x1a, 0x40, 0x15, 0x01, 0x40, 0x40, 0x15, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, + 0x00, 0x45, 0x5a, 0x40, 0x1f, 0x02, 0x40, 0x22, 0x40, 0x45, 0x40, 0x40, 0x12, 0x0f, 0x45, + 0x59, 0x40, 0x0a, 0x5c, 0x59, 0x57, 0x51, 0x51, 0x07, 0x07, 0x0d, 0x3e, 0x15, 0x05, 0x07, + 0x5f, 0x27, 0x44, 0x15, 0x40, 0x05, 0x17, 0x40, 0x40, 0x40, 0x45, 0x45, 0x52, 0x57, 0x4a, + 0x57, 0x5c, 0x54, 0x52, 0x5f, 0x5f, 0x59, 0x52, 0x5a, 0x5f, 0x5f, 0x59, 0x47, 0x42, 0x4c, + 0x52, 0x57, 0x4a, 0x57, 0x5c, 0x54, 0x52, 0x5f, 0x5f, 0x59, 0x52, 0x5a, 0x5f, 0x5f, 0x59, + 0x47, 0x42, 0x4c, 0x0d, 0x4d, 0x47, 0x40, 0x42, 0x40, 0x45, 0x07, 0x45, 0x42, 0x42, 0x57, + 0x4a, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, 0x4d, 0x12, 0x07, 0x40, 0x1d, 0x12, + 0x4d, 0x12, 0x07, 0x40, 0x42, 0x07, 0x02, 0x02, 0x05, 0x0d, 0x05, 0x0d, 0x15, 0x17, 0x12, + 0x4d, 0x17, 0x12, 0x4d, 0x40, 0x40, 0x40, 0x27, 0x15, 0x15, 0x40, 0x0f, 0x15, 0x1a, 0x1a, + 0x22, 0x27, 0x12, 0x07, 0x0d, 0x12, 0x05, 0x05, 0x3e, 0x1d, 0x15, 0x40, 0x0f, 0x15, 0x1a, + 0x00, 0x15, 0x03, 0x00, 0x00, 0x15, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x01, 0x44, 0x59, 0x40, + 0x1e, 0x01, 0x41, 0x23, 0x40, 0x44, 0x40, 0x40, 0x11, 0x0f, 0x44, 0x58, 0x40, 0x0b, 0x5b, + 0x58, 0x55, 0x4f, 0x4f, 0x07, 0x07, 0x0c, 0x3e, 0x14, 0x06, 0x07, 0x5e, 0x27, 0x43, 0x14, + 0x40, 0x04, 0x16, 0x40, 0x40, 0x40, 0x44, 0x44, 0x51, 0x56, 0x49, 0x56, 0x5b, 0x53, 0x51, + 0x5e, 0x5e, 0x58, 0x51, 0x59, 0x5e, 0x5e, 0x58, 0x46, 0x41, 0x4b, 0x51, 0x56, 0x49, 0x56, + 0x5b, 0x53, 0x51, 0x5e, 0x5e, 0x58, 0x51, 0x59, 0x5e, 0x5e, 0x58, 0x46, 0x41, 0x4b, 0x0e, + 0x4c, 0x45, 0x40, 0x43, 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x55, 0x49, 0x1c, 0x11, 0x4c, + 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, + 0x43, 0x07, 0x03, 0x03, 0x06, 0x0e, 0x06, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, + 0x40, 0x40, 0x40, 0x26, 0x14, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, + 0x0e, 0x13, 0x06, 0x04, 0x3e, 0x1c, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x01, 0x14, 0x04, 0x01, + 0x01, 0x14, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x02, 0x44, 0x59, 0x40, 0x1d, 0x01, 0x42, 0x23, + 0x40, 0x44, 0x40, 0x40, 0x11, 0x0f, 0x44, 0x56, 0x40, 0x0b, 0x5a, 0x56, 0x53, 0x4c, 0x4c, + 0x07, 0x07, 0x0c, 0x3e, 0x14, 0x06, 0x07, 0x5d, 0x27, 0x42, 0x14, 0x40, 0x04, 0x15, 0x40, + 0x40, 0x40, 0x44, 0x44, 0x51, 0x55, 0x49, 0x55, 0x5a, 0x52, 0x51, 0x5d, 0x5d, 0x56, 0x51, + 0x59, 0x5d, 0x5d, 0x56, 0x45, 0x41, 0x4a, 0x51, 0x55, 0x49, 0x55, 0x5a, 0x52, 0x51, 0x5d, + 0x5d, 0x56, 0x51, 0x59, 0x5d, 0x5d, 0x56, 0x45, 0x41, 0x4a, 0x0e, 0x4c, 0x43, 0x40, 0x43, + 0x40, 0x44, 0x07, 0x44, 0x41, 0x41, 0x53, 0x49, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, + 0x11, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x11, 0x4c, 0x13, 0x07, 0x40, 0x43, 0x07, 0x03, 0x03, + 0x06, 0x0e, 0x06, 0x0e, 0x14, 0x17, 0x11, 0x4c, 0x17, 0x11, 0x4c, 0x40, 0x40, 0x40, 0x25, + 0x14, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x19, 0x23, 0x27, 0x13, 0x07, 0x0e, 0x13, 0x06, 0x04, + 0x3e, 0x1c, 0x14, 0x40, 0x0f, 0x14, 0x19, 0x02, 0x14, 0x05, 0x02, 0x02, 0x14, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x3e, 0x03, 0x44, 0x58, 0x40, 0x1c, 0x00, 0x43, 0x23, 0x40, 0x44, 0x40, 0x40, + 0x10, 0x0f, 0x44, 0x55, 0x40, 0x0b, 0x59, 0x55, 0x51, 0x4a, 0x4a, 0x07, 0x07, 0x0c, 0x3d, + 0x14, 0x07, 0x07, 0x5c, 0x27, 0x41, 0x14, 0x40, 0x04, 0x14, 0x40, 0x40, 0x40, 0x44, 0x44, + 0x50, 0x54, 0x48, 0x54, 0x59, 0x51, 0x50, 0x5c, 0x5c, 0x55, 0x50, 0x58, 0x5c, 0x5c, 0x55, + 0x44, 0x40, 0x49, 0x50, 0x54, 0x48, 0x54, 0x59, 0x51, 0x50, 0x5c, 0x5c, 0x55, 0x50, 0x58, + 0x5c, 0x5c, 0x55, 0x44, 0x40, 0x49, 0x0f, 0x4c, 0x41, 0x40, 0x43, 0x40, 0x44, 0x07, 0x44, + 0x40, 0x40, 0x51, 0x48, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, + 0x40, 0x1c, 0x10, 0x4c, 0x13, 0x07, 0x40, 0x43, 0x07, 0x03, 0x03, 0x07, 0x0f, 0x07, 0x0f, + 0x14, 0x17, 0x10, 0x4c, 0x17, 0x10, 0x4c, 0x40, 0x40, 0x40, 0x24, 0x14, 0x14, 0x40, 0x0f, + 0x14, 0x18, 0x18, 0x23, 0x27, 0x13, 0x07, 0x0f, 0x13, 0x07, 0x04, 0x3e, 0x1c, 0x14, 0x40, + 0x0f, 0x14, 0x18, 0x03, 0x14, 0x06, 0x03, 0x03, 0x14, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x04, + 0x43, 0x57, 0x40, 0x1b, 0x40, 0x44, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0f, 0x0f, 0x43, 0x53, + 0x40, 0x0c, 0x57, 0x53, 0x4f, 0x47, 0x47, 0x07, 0x07, 0x0b, 0x3b, 0x13, 0x08, 0x07, 0x5b, + 0x27, 0x00, 0x13, 0x40, 0x03, 0x13, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x53, 0x47, 0x53, + 0x57, 0x4f, 0x4f, 0x5b, 0x5b, 0x53, 0x4f, 0x57, 0x5b, 0x5b, 0x53, 0x43, 0x00, 0x47, 0x4f, + 0x53, 0x47, 0x53, 0x57, 0x4f, 0x4f, 0x5b, 0x5b, 0x53, 0x4f, 0x57, 0x5b, 0x5b, 0x53, 0x43, + 0x00, 0x47, 0x10, 0x4b, 0x00, 0x40, 0x44, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4f, 0x47, + 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, + 0x14, 0x07, 0x40, 0x44, 0x07, 0x04, 0x04, 0x08, 0x10, 0x08, 0x10, 0x13, 0x17, 0x0f, 0x4b, + 0x17, 0x0f, 0x4b, 0x40, 0x40, 0x40, 0x23, 0x13, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, + 0x27, 0x14, 0x07, 0x10, 0x14, 0x08, 0x03, 0x3e, 0x1b, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x04, + 0x13, 0x08, 0x04, 0x04, 0x13, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x05, 0x43, 0x57, 0x40, 0x1a, + 0x40, 0x45, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0f, 0x0f, 0x43, 0x52, 0x40, 0x0c, 0x56, 0x52, + 0x4d, 0x45, 0x45, 0x07, 0x07, 0x0b, 0x3a, 0x13, 0x08, 0x07, 0x5a, 0x27, 0x01, 0x13, 0x40, + 0x03, 0x12, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4f, 0x52, 0x47, 0x52, 0x56, 0x4e, 0x4f, 0x5a, + 0x5a, 0x52, 0x4f, 0x57, 0x5a, 0x5a, 0x52, 0x42, 0x00, 0x46, 0x4f, 0x52, 0x47, 0x52, 0x56, + 0x4e, 0x4f, 0x5a, 0x5a, 0x52, 0x4f, 0x57, 0x5a, 0x5a, 0x52, 0x42, 0x00, 0x46, 0x10, 0x4b, + 0x02, 0x40, 0x44, 0x40, 0x43, 0x07, 0x43, 0x00, 0x00, 0x4d, 0x47, 0x1b, 0x0f, 0x4b, 0x14, + 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0f, 0x4b, 0x14, 0x07, 0x40, 0x44, + 0x07, 0x04, 0x04, 0x08, 0x10, 0x08, 0x10, 0x13, 0x17, 0x0f, 0x4b, 0x17, 0x0f, 0x4b, 0x40, + 0x40, 0x40, 0x22, 0x13, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x17, 0x24, 0x27, 0x14, 0x07, 0x10, + 0x14, 0x08, 0x03, 0x3e, 0x1b, 0x13, 0x40, 0x0f, 0x13, 0x17, 0x05, 0x13, 0x09, 0x05, 0x05, + 0x13, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x06, 0x43, 0x56, 0x40, 0x19, 0x41, 0x46, 0x24, 0x40, + 0x43, 0x40, 0x40, 0x0e, 0x0f, 0x43, 0x50, 0x40, 0x0c, 0x55, 0x50, 0x4b, 0x42, 0x42, 0x07, + 0x07, 0x0b, 0x38, 0x13, 0x09, 0x07, 0x59, 0x27, 0x02, 0x13, 0x40, 0x03, 0x11, 0x40, 0x40, + 0x40, 0x43, 0x43, 0x4e, 0x51, 0x46, 0x51, 0x55, 0x4d, 0x4e, 0x59, 0x59, 0x50, 0x4e, 0x56, + 0x59, 0x59, 0x50, 0x41, 0x01, 0x45, 0x4e, 0x51, 0x46, 0x51, 0x55, 0x4d, 0x4e, 0x59, 0x59, + 0x50, 0x4e, 0x56, 0x59, 0x59, 0x50, 0x41, 0x01, 0x45, 0x11, 0x4b, 0x04, 0x40, 0x44, 0x40, + 0x43, 0x07, 0x43, 0x01, 0x01, 0x4b, 0x46, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0e, + 0x4b, 0x14, 0x07, 0x40, 0x1b, 0x0e, 0x4b, 0x14, 0x07, 0x40, 0x44, 0x07, 0x04, 0x04, 0x09, + 0x11, 0x09, 0x11, 0x13, 0x17, 0x0e, 0x4b, 0x17, 0x0e, 0x4b, 0x40, 0x40, 0x40, 0x21, 0x13, + 0x13, 0x40, 0x0f, 0x13, 0x16, 0x16, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x09, 0x03, 0x3d, + 0x1b, 0x13, 0x40, 0x0f, 0x13, 0x16, 0x06, 0x13, 0x0a, 0x06, 0x06, 0x13, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x3e, 0x06, 0x43, 0x56, 0x40, 0x18, 0x42, 0x47, 0x24, 0x40, 0x43, 0x40, 0x40, 0x0d, + 0x0f, 0x43, 0x4f, 0x40, 0x0c, 0x54, 0x4f, 0x4a, 0x40, 0x40, 0x07, 0x07, 0x0a, 0x36, 0x12, + 0x09, 0x07, 0x59, 0x27, 0x03, 0x12, 0x40, 0x02, 0x10, 0x40, 0x40, 0x40, 0x43, 0x43, 0x4e, + 0x51, 0x46, 0x51, 0x54, 0x4c, 0x4e, 0x59, 0x59, 0x4f, 0x4e, 0x56, 0x59, 0x59, 0x4f, 0x41, + 0x01, 0x44, 0x4e, 0x51, 0x46, 0x51, 0x54, 0x4c, 0x4e, 0x59, 0x59, 0x4f, 0x4e, 0x56, 0x59, + 0x59, 0x4f, 0x41, 0x01, 0x44, 0x11, 0x4b, 0x05, 0x40, 0x45, 0x40, 0x43, 0x07, 0x43, 0x01, + 0x01, 0x4a, 0x46, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, + 0x1a, 0x0d, 0x4b, 0x14, 0x07, 0x40, 0x45, 0x07, 0x04, 0x04, 0x09, 0x11, 0x09, 0x11, 0x12, + 0x17, 0x0d, 0x4b, 0x17, 0x0d, 0x4b, 0x40, 0x40, 0x40, 0x20, 0x12, 0x12, 0x40, 0x0f, 0x12, + 0x15, 0x15, 0x24, 0x27, 0x14, 0x07, 0x11, 0x14, 0x09, 0x02, 0x3b, 0x1a, 0x12, 0x40, 0x0f, + 0x12, 0x15, 0x06, 0x12, 0x0b, 0x06, 0x06, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x07, 0x42, + 0x55, 0x40, 0x18, 0x42, 0x47, 0x25, 0x40, 0x42, 0x40, 0x40, 0x0d, 0x0f, 0x42, 0x4d, 0x40, + 0x0d, 0x52, 0x4d, 0x48, 0x02, 0x02, 0x07, 0x07, 0x0a, 0x35, 0x12, 0x0a, 0x07, 0x58, 0x27, + 0x05, 0x12, 0x40, 0x02, 0x10, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4d, 0x50, 0x45, 0x50, 0x52, + 0x4a, 0x4d, 0x58, 0x58, 0x4d, 0x4d, 0x55, 0x58, 0x58, 0x4d, 0x40, 0x02, 0x42, 0x4d, 0x50, + 0x45, 0x50, 0x52, 0x4a, 0x4d, 0x58, 0x58, 0x4d, 0x4d, 0x55, 0x58, 0x58, 0x4d, 0x40, 0x02, + 0x42, 0x12, 0x4a, 0x07, 0x40, 0x45, 0x40, 0x42, 0x07, 0x42, 0x02, 0x02, 0x48, 0x45, 0x1a, + 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0d, 0x4a, 0x15, + 0x07, 0x40, 0x45, 0x07, 0x05, 0x05, 0x0a, 0x12, 0x0a, 0x12, 0x12, 0x17, 0x0d, 0x4a, 0x17, + 0x0d, 0x4a, 0x40, 0x40, 0x40, 0x20, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x15, 0x25, 0x27, + 0x15, 0x07, 0x12, 0x15, 0x0a, 0x02, 0x3a, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x15, 0x07, 0x12, + 0x0d, 0x07, 0x07, 0x12, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x08, 0x42, 0x54, 0x40, 0x17, 0x43, + 0x48, 0x25, 0x40, 0x42, 0x40, 0x40, 0x0c, 0x0f, 0x42, 0x4b, 0x40, 0x0d, 0x51, 0x4b, 0x46, + 0x04, 0x04, 0x07, 0x07, 0x0a, 0x33, 0x12, 0x0b, 0x07, 0x57, 0x27, 0x06, 0x12, 0x40, 0x02, + 0x0f, 0x40, 0x40, 0x40, 0x42, 0x42, 0x4c, 0x4f, 0x44, 0x4f, 0x51, 0x49, 0x4c, 0x57, 0x57, + 0x4b, 0x4c, 0x54, 0x57, 0x57, 0x4b, 0x00, 0x03, 0x41, 0x4c, 0x4f, 0x44, 0x4f, 0x51, 0x49, + 0x4c, 0x57, 0x57, 0x4b, 0x4c, 0x54, 0x57, 0x57, 0x4b, 0x00, 0x03, 0x41, 0x13, 0x4a, 0x09, + 0x40, 0x45, 0x40, 0x42, 0x07, 0x42, 0x03, 0x03, 0x46, 0x44, 0x1a, 0x0c, 0x4a, 0x15, 0x07, + 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, 0x07, + 0x05, 0x05, 0x0b, 0x13, 0x0b, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, + 0x40, 0x1f, 0x12, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, + 0x0b, 0x02, 0x39, 0x1a, 0x12, 0x40, 0x0f, 0x12, 0x14, 0x08, 0x12, 0x0e, 0x08, 0x08, 0x12, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x3e, 0x09, 0x42, 0x54, 0x40, 0x16, 0x43, 0x49, 0x25, 0x40, 0x42, + 0x40, 0x40, 0x0c, 0x0f, 0x42, 0x4a, 0x40, 0x0d, 0x50, 0x4a, 0x44, 0x07, 0x07, 0x07, 0x07, + 0x0a, 0x32, 0x12, 0x0b, 0x07, 0x56, 0x27, 0x07, 0x12, 0x40, 0x02, 0x0e, 0x40, 0x40, 0x40, + 0x42, 0x42, 0x4c, 0x4e, 0x44, 0x4e, 0x50, 0x48, 0x4c, 0x56, 0x56, 0x4a, 0x4c, 0x54, 0x56, + 0x56, 0x4a, 0x01, 0x03, 0x40, 0x4c, 0x4e, 0x44, 0x4e, 0x50, 0x48, 0x4c, 0x56, 0x56, 0x4a, + 0x4c, 0x54, 0x56, 0x56, 0x4a, 0x01, 0x03, 0x40, 0x13, 0x4a, 0x0b, 0x40, 0x45, 0x40, 0x42, + 0x07, 0x42, 0x03, 0x03, 0x44, 0x44, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, + 0x15, 0x07, 0x40, 0x1a, 0x0c, 0x4a, 0x15, 0x07, 0x40, 0x45, 0x07, 0x05, 0x05, 0x0b, 0x13, + 0x0b, 0x13, 0x12, 0x17, 0x0c, 0x4a, 0x17, 0x0c, 0x4a, 0x40, 0x40, 0x40, 0x1e, 0x12, 0x12, + 0x40, 0x0f, 0x12, 0x14, 0x14, 0x25, 0x27, 0x15, 0x07, 0x13, 0x15, 0x0b, 0x02, 0x38, 0x1a, + 0x12, 0x40, 0x0f, 0x12, 0x14, 0x09, 0x12, 0x0f, 0x09, 0x09, 0x12, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x3e, 0x0a, 0x41, 0x53, 0x40, 0x15, 0x44, 0x4a, 0x26, 0x40, 0x41, 0x40, 0x40, 0x0b, 0x0f, + 0x41, 0x48, 0x40, 0x0e, 0x4f, 0x48, 0x42, 0x09, 0x09, 0x07, 0x07, 0x09, 0x30, 0x11, 0x0c, + 0x07, 0x55, 0x27, 0x08, 0x11, 0x40, 0x01, 0x0d, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4b, 0x4d, + 0x43, 0x4d, 0x4f, 0x47, 0x4b, 0x55, 0x55, 0x48, 0x4b, 0x53, 0x55, 0x55, 0x48, 0x02, 0x04, + 0x00, 0x4b, 0x4d, 0x43, 0x4d, 0x4f, 0x47, 0x4b, 0x55, 0x55, 0x48, 0x4b, 0x53, 0x55, 0x55, + 0x48, 0x02, 0x04, 0x00, 0x14, 0x49, 0x0d, 0x40, 0x46, 0x40, 0x41, 0x07, 0x41, 0x04, 0x04, + 0x42, 0x43, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0b, 0x49, 0x16, 0x07, 0x40, 0x19, + 0x0b, 0x49, 0x16, 0x07, 0x40, 0x46, 0x07, 0x06, 0x06, 0x0c, 0x14, 0x0c, 0x14, 0x11, 0x17, + 0x0b, 0x49, 0x17, 0x0b, 0x49, 0x40, 0x40, 0x40, 0x1d, 0x11, 0x11, 0x40, 0x0f, 0x11, 0x13, + 0x13, 0x26, 0x27, 0x16, 0x07, 0x14, 0x16, 0x0c, 0x01, 0x36, 0x19, 0x11, 0x40, 0x0f, 0x11, + 0x13, 0x0a, 0x11, 0x10, 0x0a, 0x0a, 0x11, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x0b, 0x41, 0x52, + 0x40, 0x14, 0x45, 0x4b, 0x26, 0x40, 0x41, 0x40, 0x40, 0x0a, 0x0f, 0x41, 0x47, 0x40, 0x0e, + 0x4d, 0x47, 0x40, 0x0c, 0x0c, 0x07, 0x07, 0x09, 0x2f, 0x11, 0x0d, 0x07, 0x54, 0x27, 0x0a, + 0x11, 0x40, 0x01, 0x0c, 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4c, 0x42, 0x4c, 0x4d, 0x45, + 0x4a, 0x54, 0x54, 0x47, 0x4a, 0x52, 0x54, 0x54, 0x47, 0x03, 0x05, 0x02, 0x4a, 0x4c, 0x42, + 0x4c, 0x4d, 0x45, 0x4a, 0x54, 0x54, 0x47, 0x4a, 0x52, 0x54, 0x54, 0x47, 0x03, 0x05, 0x02, + 0x15, 0x49, 0x0f, 0x40, 0x46, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x40, 0x42, 0x19, 0x0a, + 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, + 0x40, 0x46, 0x07, 0x06, 0x06, 0x0d, 0x15, 0x0d, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, + 0x49, 0x40, 0x40, 0x40, 0x1c, 0x11, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, + 0x07, 0x15, 0x16, 0x0d, 0x01, 0x35, 0x19, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x0b, 0x11, 0x12, + 0x0b, 0x0b, 0x11, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x0c, 0x41, 0x52, 0x40, 0x13, 0x45, 0x4c, + 0x26, 0x40, 0x41, 0x40, 0x40, 0x0a, 0x0f, 0x41, 0x45, 0x40, 0x0e, 0x4c, 0x45, 0x01, 0x0e, + 0x0e, 0x07, 0x07, 0x09, 0x2d, 0x11, 0x0d, 0x07, 0x53, 0x27, 0x0b, 0x11, 0x40, 0x01, 0x0b, + 0x40, 0x40, 0x40, 0x41, 0x41, 0x4a, 0x4b, 0x42, 0x4b, 0x4c, 0x44, 0x4a, 0x53, 0x53, 0x45, + 0x4a, 0x52, 0x53, 0x53, 0x45, 0x04, 0x05, 0x03, 0x4a, 0x4b, 0x42, 0x4b, 0x4c, 0x44, 0x4a, + 0x53, 0x53, 0x45, 0x4a, 0x52, 0x53, 0x53, 0x45, 0x04, 0x05, 0x03, 0x15, 0x49, 0x11, 0x40, + 0x46, 0x40, 0x41, 0x07, 0x41, 0x05, 0x05, 0x01, 0x42, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, + 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x19, 0x0a, 0x49, 0x16, 0x07, 0x40, 0x46, 0x07, 0x06, + 0x06, 0x0d, 0x15, 0x0d, 0x15, 0x11, 0x17, 0x0a, 0x49, 0x17, 0x0a, 0x49, 0x40, 0x40, 0x40, + 0x1b, 0x11, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x12, 0x26, 0x27, 0x16, 0x07, 0x15, 0x16, 0x0d, + 0x01, 0x34, 0x19, 0x11, 0x40, 0x0f, 0x11, 0x12, 0x0c, 0x11, 0x13, 0x0c, 0x0c, 0x11, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x3e, 0x0d, 0x40, 0x51, 0x40, 0x12, 0x46, 0x4d, 0x27, 0x40, 0x40, 0x40, + 0x40, 0x09, 0x0f, 0x40, 0x44, 0x40, 0x0f, 0x4b, 0x44, 0x03, 0x11, 0x11, 0x07, 0x07, 0x08, + 0x2c, 0x10, 0x0e, 0x07, 0x52, 0x27, 0x0c, 0x10, 0x40, 0x00, 0x0a, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x49, 0x4a, 0x41, 0x4a, 0x4b, 0x43, 0x49, 0x52, 0x52, 0x44, 0x49, 0x51, 0x52, 0x52, + 0x44, 0x05, 0x06, 0x04, 0x49, 0x4a, 0x41, 0x4a, 0x4b, 0x43, 0x49, 0x52, 0x52, 0x44, 0x49, + 0x51, 0x52, 0x52, 0x44, 0x05, 0x06, 0x04, 0x16, 0x48, 0x13, 0x40, 0x47, 0x40, 0x40, 0x07, + 0x40, 0x06, 0x06, 0x03, 0x41, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, + 0x07, 0x40, 0x18, 0x09, 0x48, 0x17, 0x07, 0x40, 0x47, 0x07, 0x07, 0x07, 0x0e, 0x16, 0x0e, + 0x16, 0x10, 0x17, 0x09, 0x48, 0x17, 0x09, 0x48, 0x40, 0x40, 0x40, 0x1a, 0x10, 0x10, 0x40, + 0x0f, 0x10, 0x11, 0x11, 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0e, 0x00, 0x33, 0x18, 0x10, + 0x40, 0x0f, 0x10, 0x11, 0x0d, 0x10, 0x14, 0x0d, 0x0d, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, + 0x0e, 0x40, 0x51, 0x40, 0x11, 0x47, 0x4e, 0x27, 0x40, 0x40, 0x40, 0x40, 0x08, 0x0f, 0x40, + 0x42, 0x40, 0x0f, 0x4a, 0x42, 0x04, 0x13, 0x13, 0x07, 0x07, 0x08, 0x2a, 0x10, 0x0e, 0x07, + 0x51, 0x27, 0x0d, 0x10, 0x40, 0x00, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x41, + 0x49, 0x4a, 0x42, 0x49, 0x51, 0x51, 0x42, 0x49, 0x51, 0x51, 0x51, 0x42, 0x06, 0x06, 0x05, + 0x49, 0x49, 0x41, 0x49, 0x4a, 0x42, 0x49, 0x51, 0x51, 0x42, 0x49, 0x51, 0x51, 0x51, 0x42, + 0x06, 0x06, 0x05, 0x16, 0x48, 0x14, 0x40, 0x47, 0x40, 0x40, 0x07, 0x40, 0x06, 0x06, 0x04, + 0x41, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, + 0x48, 0x17, 0x07, 0x40, 0x47, 0x07, 0x07, 0x07, 0x0e, 0x16, 0x0e, 0x16, 0x10, 0x17, 0x08, + 0x48, 0x17, 0x08, 0x48, 0x40, 0x40, 0x40, 0x19, 0x10, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, + 0x27, 0x27, 0x17, 0x07, 0x16, 0x17, 0x0e, 0x00, 0x31, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x10, + 0x0e, 0x10, 0x15, 0x0e, 0x0e, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x0f, 0x40, 0x50, 0x40, + 0x10, 0x47, 0x4f, 0x27, 0x40, 0x40, 0x40, 0x40, 0x08, 0x0f, 0x40, 0x40, 0x40, 0x0f, 0x48, + 0x40, 0x06, 0x16, 0x16, 0x07, 0x07, 0x08, 0x28, 0x10, 0x0f, 0x07, 0x50, 0x27, 0x0f, 0x10, + 0x40, 0x00, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x40, 0x48, 0x48, 0x40, 0x48, + 0x50, 0x50, 0x40, 0x48, 0x50, 0x50, 0x50, 0x40, 0x07, 0x07, 0x07, 0x48, 0x48, 0x40, 0x48, + 0x48, 0x40, 0x48, 0x50, 0x50, 0x40, 0x48, 0x50, 0x50, 0x50, 0x40, 0x07, 0x07, 0x07, 0x17, + 0x48, 0x16, 0x40, 0x47, 0x40, 0x40, 0x07, 0x40, 0x07, 0x07, 0x06, 0x40, 0x18, 0x08, 0x48, + 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, 0x18, 0x08, 0x48, 0x17, 0x07, 0x40, + 0x47, 0x07, 0x07, 0x07, 0x0f, 0x17, 0x0f, 0x17, 0x10, 0x17, 0x08, 0x48, 0x17, 0x08, 0x48, + 0x40, 0x40, 0x40, 0x18, 0x10, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x10, 0x27, 0x27, 0x17, 0x07, + 0x17, 0x17, 0x0f, 0x00, 0x30, 0x18, 0x10, 0x40, 0x0f, 0x10, 0x10, 0x0f, 0x10, 0x17, 0x0f, + 0x0f, 0x10, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x10, 0x00, 0x4f, 0x40, 0x0f, 0x48, 0x50, 0x28, + 0x40, 0x00, 0x40, 0x40, 0x07, 0x0f, 0x00, 0x00, 0x40, 0x10, 0x47, 0x00, 0x08, 0x18, 0x18, + 0x07, 0x07, 0x07, 0x27, 0x0f, 0x10, 0x07, 0x4f, 0x27, 0x10, 0x0f, 0x40, 0x40, 0x07, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x47, 0x47, 0x00, 0x47, 0x47, 0x00, 0x47, 0x4f, 0x4f, 0x00, 0x47, + 0x4f, 0x4f, 0x4f, 0x00, 0x08, 0x08, 0x08, 0x47, 0x47, 0x00, 0x47, 0x47, 0x00, 0x47, 0x4f, + 0x4f, 0x00, 0x47, 0x4f, 0x4f, 0x4f, 0x00, 0x08, 0x08, 0x08, 0x18, 0x47, 0x18, 0x40, 0x48, + 0x40, 0x00, 0x07, 0x00, 0x08, 0x08, 0x08, 0x00, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, + 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, 0x07, 0x08, 0x08, + 0x10, 0x18, 0x10, 0x18, 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, 0x40, 0x17, + 0x0f, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, 0x40, + 0x2f, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0f, 0x10, 0x0f, 0x18, 0x10, 0x10, 0x0f, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x3e, 0x11, 0x00, 0x4f, 0x40, 0x0e, 0x48, 0x51, 0x28, 0x40, 0x00, 0x40, 0x40, + 0x07, 0x0f, 0x00, 0x02, 0x40, 0x10, 0x46, 0x02, 0x0a, 0x1b, 0x1b, 0x07, 0x07, 0x07, 0x25, + 0x0f, 0x10, 0x07, 0x4e, 0x27, 0x11, 0x0f, 0x40, 0x40, 0x06, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x47, 0x46, 0x00, 0x46, 0x46, 0x01, 0x47, 0x4e, 0x4e, 0x02, 0x47, 0x4f, 0x4e, 0x4e, 0x02, + 0x09, 0x08, 0x09, 0x47, 0x46, 0x00, 0x46, 0x46, 0x01, 0x47, 0x4e, 0x4e, 0x02, 0x47, 0x4f, + 0x4e, 0x4e, 0x02, 0x09, 0x08, 0x09, 0x18, 0x47, 0x1a, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, + 0x08, 0x08, 0x0a, 0x00, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, + 0x40, 0x17, 0x07, 0x47, 0x18, 0x07, 0x40, 0x48, 0x07, 0x08, 0x08, 0x10, 0x18, 0x10, 0x18, + 0x0f, 0x17, 0x07, 0x47, 0x17, 0x07, 0x47, 0x40, 0x40, 0x40, 0x16, 0x0f, 0x0f, 0x40, 0x0f, + 0x0f, 0x0f, 0x0f, 0x28, 0x27, 0x18, 0x07, 0x18, 0x18, 0x10, 0x40, 0x2e, 0x17, 0x0f, 0x40, + 0x0f, 0x0f, 0x0f, 0x11, 0x0f, 0x19, 0x11, 0x11, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x12, + 0x00, 0x4e, 0x40, 0x0d, 0x49, 0x52, 0x28, 0x40, 0x00, 0x40, 0x40, 0x06, 0x0f, 0x00, 0x03, + 0x40, 0x10, 0x45, 0x03, 0x0c, 0x1d, 0x1d, 0x07, 0x07, 0x07, 0x24, 0x0f, 0x11, 0x07, 0x4d, + 0x27, 0x12, 0x0f, 0x40, 0x40, 0x05, 0x40, 0x40, 0x40, 0x00, 0x00, 0x46, 0x45, 0x01, 0x45, + 0x45, 0x02, 0x46, 0x4d, 0x4d, 0x03, 0x46, 0x4e, 0x4d, 0x4d, 0x03, 0x0a, 0x09, 0x0a, 0x46, + 0x45, 0x01, 0x45, 0x45, 0x02, 0x46, 0x4d, 0x4d, 0x03, 0x46, 0x4e, 0x4d, 0x4d, 0x03, 0x0a, + 0x09, 0x0a, 0x19, 0x47, 0x1c, 0x40, 0x48, 0x40, 0x00, 0x07, 0x00, 0x09, 0x09, 0x0c, 0x01, + 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, 0x18, 0x07, 0x40, 0x17, 0x06, 0x47, + 0x18, 0x07, 0x40, 0x48, 0x07, 0x08, 0x08, 0x11, 0x19, 0x11, 0x19, 0x0f, 0x17, 0x06, 0x47, + 0x17, 0x06, 0x47, 0x40, 0x40, 0x40, 0x15, 0x0f, 0x0f, 0x40, 0x0f, 0x0f, 0x0e, 0x0e, 0x28, + 0x27, 0x18, 0x07, 0x19, 0x18, 0x11, 0x40, 0x2c, 0x17, 0x0f, 0x40, 0x0f, 0x0f, 0x0e, 0x12, + 0x0f, 0x1a, 0x12, 0x12, 0x0f, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x13, 0x01, 0x4d, 0x40, 0x0c, + 0x4a, 0x53, 0x29, 0x40, 0x01, 0x40, 0x40, 0x05, 0x0f, 0x01, 0x05, 0x40, 0x11, 0x43, 0x05, + 0x0e, 0x20, 0x20, 0x07, 0x07, 0x06, 0x22, 0x0e, 0x12, 0x07, 0x4c, 0x27, 0x14, 0x0e, 0x40, + 0x41, 0x04, 0x40, 0x40, 0x40, 0x01, 0x01, 0x45, 0x44, 0x02, 0x44, 0x43, 0x04, 0x45, 0x4c, + 0x4c, 0x05, 0x45, 0x4d, 0x4c, 0x4c, 0x05, 0x0b, 0x0a, 0x0c, 0x45, 0x44, 0x02, 0x44, 0x43, + 0x04, 0x45, 0x4c, 0x4c, 0x05, 0x45, 0x4d, 0x4c, 0x4c, 0x05, 0x0b, 0x0a, 0x0c, 0x1a, 0x46, + 0x1e, 0x40, 0x49, 0x40, 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x0e, 0x02, 0x16, 0x05, 0x46, 0x19, + 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, + 0x07, 0x09, 0x09, 0x12, 0x1a, 0x12, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, + 0x40, 0x40, 0x14, 0x0e, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, + 0x19, 0x12, 0x41, 0x2b, 0x16, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x13, 0x0e, 0x1c, 0x13, 0x13, + 0x0e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x14, 0x01, 0x4d, 0x40, 0x0b, 0x4a, 0x54, 0x29, 0x40, + 0x01, 0x40, 0x40, 0x05, 0x0f, 0x01, 0x06, 0x40, 0x11, 0x42, 0x06, 0x10, 0x22, 0x22, 0x07, + 0x07, 0x06, 0x21, 0x0e, 0x12, 0x07, 0x4b, 0x27, 0x15, 0x0e, 0x40, 0x41, 0x03, 0x40, 0x40, + 0x40, 0x01, 0x01, 0x45, 0x43, 0x02, 0x43, 0x42, 0x05, 0x45, 0x4b, 0x4b, 0x06, 0x45, 0x4d, + 0x4b, 0x4b, 0x06, 0x0c, 0x0a, 0x0d, 0x45, 0x43, 0x02, 0x43, 0x42, 0x05, 0x45, 0x4b, 0x4b, + 0x06, 0x45, 0x4d, 0x4b, 0x4b, 0x06, 0x0c, 0x0a, 0x0d, 0x1a, 0x46, 0x20, 0x40, 0x49, 0x40, + 0x01, 0x07, 0x01, 0x0a, 0x0a, 0x10, 0x02, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, + 0x46, 0x19, 0x07, 0x40, 0x16, 0x05, 0x46, 0x19, 0x07, 0x40, 0x49, 0x07, 0x09, 0x09, 0x12, + 0x1a, 0x12, 0x1a, 0x0e, 0x17, 0x05, 0x46, 0x17, 0x05, 0x46, 0x40, 0x40, 0x40, 0x13, 0x0e, + 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x0d, 0x29, 0x27, 0x19, 0x07, 0x1a, 0x19, 0x12, 0x41, 0x2a, + 0x16, 0x0e, 0x40, 0x0f, 0x0e, 0x0d, 0x14, 0x0e, 0x1d, 0x14, 0x14, 0x0e, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x3e, 0x15, 0x01, 0x4c, 0x40, 0x0a, 0x4b, 0x55, 0x29, 0x40, 0x01, 0x40, 0x40, 0x04, + 0x0f, 0x01, 0x08, 0x40, 0x11, 0x41, 0x08, 0x12, 0x25, 0x25, 0x07, 0x07, 0x06, 0x1f, 0x0e, + 0x13, 0x07, 0x4a, 0x27, 0x16, 0x0e, 0x40, 0x41, 0x02, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, + 0x42, 0x03, 0x42, 0x41, 0x06, 0x44, 0x4a, 0x4a, 0x08, 0x44, 0x4c, 0x4a, 0x4a, 0x08, 0x0d, + 0x0b, 0x0e, 0x44, 0x42, 0x03, 0x42, 0x41, 0x06, 0x44, 0x4a, 0x4a, 0x08, 0x44, 0x4c, 0x4a, + 0x4a, 0x08, 0x0d, 0x0b, 0x0e, 0x1b, 0x46, 0x22, 0x40, 0x49, 0x40, 0x01, 0x07, 0x01, 0x0b, + 0x0b, 0x12, 0x03, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, + 0x16, 0x04, 0x46, 0x19, 0x07, 0x40, 0x49, 0x07, 0x09, 0x09, 0x13, 0x1b, 0x13, 0x1b, 0x0e, + 0x17, 0x04, 0x46, 0x17, 0x04, 0x46, 0x40, 0x40, 0x40, 0x12, 0x0e, 0x0e, 0x40, 0x0f, 0x0e, + 0x0c, 0x0c, 0x29, 0x27, 0x19, 0x07, 0x1b, 0x19, 0x13, 0x41, 0x29, 0x16, 0x0e, 0x40, 0x0f, + 0x0e, 0x0c, 0x15, 0x0e, 0x1e, 0x15, 0x15, 0x0e, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x15, 0x01, + 0x4c, 0x40, 0x09, 0x4c, 0x56, 0x29, 0x40, 0x01, 0x40, 0x40, 0x03, 0x0f, 0x01, 0x09, 0x40, + 0x11, 0x40, 0x09, 0x13, 0x27, 0x27, 0x07, 0x07, 0x05, 0x1d, 0x0d, 0x13, 0x07, 0x4a, 0x27, + 0x17, 0x0d, 0x40, 0x42, 0x01, 0x40, 0x40, 0x40, 0x01, 0x01, 0x44, 0x42, 0x03, 0x42, 0x40, + 0x07, 0x44, 0x4a, 0x4a, 0x09, 0x44, 0x4c, 0x4a, 0x4a, 0x09, 0x0d, 0x0b, 0x0f, 0x44, 0x42, + 0x03, 0x42, 0x40, 0x07, 0x44, 0x4a, 0x4a, 0x09, 0x44, 0x4c, 0x4a, 0x4a, 0x09, 0x0d, 0x0b, + 0x0f, 0x1b, 0x46, 0x23, 0x40, 0x4a, 0x40, 0x01, 0x07, 0x01, 0x0b, 0x0b, 0x13, 0x03, 0x15, + 0x03, 0x46, 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, 0x07, 0x40, 0x15, 0x03, 0x46, 0x19, + 0x07, 0x40, 0x4a, 0x07, 0x09, 0x09, 0x13, 0x1b, 0x13, 0x1b, 0x0d, 0x17, 0x03, 0x46, 0x17, + 0x03, 0x46, 0x40, 0x40, 0x40, 0x11, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x29, 0x27, + 0x19, 0x07, 0x1b, 0x19, 0x13, 0x42, 0x27, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x15, 0x0d, + 0x1f, 0x15, 0x15, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x16, 0x02, 0x4b, 0x40, 0x09, 0x4c, + 0x56, 0x2a, 0x40, 0x02, 0x40, 0x40, 0x03, 0x0f, 0x02, 0x0b, 0x40, 0x12, 0x01, 0x0b, 0x15, + 0x2a, 0x2a, 0x07, 0x07, 0x05, 0x1c, 0x0d, 0x14, 0x07, 0x49, 0x27, 0x19, 0x0d, 0x40, 0x42, + 0x01, 0x40, 0x40, 0x40, 0x02, 0x02, 0x43, 0x41, 0x04, 0x41, 0x01, 0x09, 0x43, 0x49, 0x49, + 0x0b, 0x43, 0x4b, 0x49, 0x49, 0x0b, 0x0e, 0x0c, 0x11, 0x43, 0x41, 0x04, 0x41, 0x01, 0x09, + 0x43, 0x49, 0x49, 0x0b, 0x43, 0x4b, 0x49, 0x49, 0x0b, 0x0e, 0x0c, 0x11, 0x1c, 0x45, 0x25, + 0x40, 0x4a, 0x40, 0x02, 0x07, 0x02, 0x0c, 0x0c, 0x15, 0x04, 0x15, 0x03, 0x45, 0x1a, 0x07, + 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x03, 0x45, 0x1a, 0x07, 0x40, 0x4a, 0x07, + 0x0a, 0x0a, 0x14, 0x1c, 0x14, 0x1c, 0x0d, 0x17, 0x03, 0x45, 0x17, 0x03, 0x45, 0x40, 0x40, + 0x40, 0x11, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x0b, 0x2a, 0x27, 0x1a, 0x07, 0x1c, 0x1a, + 0x14, 0x42, 0x26, 0x15, 0x0d, 0x40, 0x0f, 0x0d, 0x0b, 0x16, 0x0d, 0x21, 0x16, 0x16, 0x0d, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x3e, 0x17, 0x02, 0x4a, 0x40, 0x08, 0x4d, 0x57, 0x2a, 0x40, 0x02, + 0x40, 0x40, 0x02, 0x0f, 0x02, 0x0d, 0x40, 0x12, 0x02, 0x0d, 0x17, 0x2c, 0x2c, 0x07, 0x07, + 0x05, 0x1a, 0x0d, 0x15, 0x07, 0x48, 0x27, 0x1a, 0x0d, 0x40, 0x42, 0x00, 0x40, 0x40, 0x40, + 0x02, 0x02, 0x42, 0x40, 0x05, 0x40, 0x02, 0x0a, 0x42, 0x48, 0x48, 0x0d, 0x42, 0x4a, 0x48, + 0x48, 0x0d, 0x0f, 0x0d, 0x12, 0x42, 0x40, 0x05, 0x40, 0x02, 0x0a, 0x42, 0x48, 0x48, 0x0d, + 0x42, 0x4a, 0x48, 0x48, 0x0d, 0x0f, 0x0d, 0x12, 0x1d, 0x45, 0x27, 0x40, 0x4a, 0x40, 0x02, + 0x07, 0x02, 0x0d, 0x0d, 0x17, 0x05, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, + 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, 0x07, 0x0a, 0x0a, 0x15, 0x1d, + 0x15, 0x1d, 0x0d, 0x17, 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, 0x40, 0x10, 0x0d, 0x0d, + 0x40, 0x0f, 0x0d, 0x0a, 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x15, 0x42, 0x25, 0x15, + 0x0d, 0x40, 0x0f, 0x0d, 0x0a, 0x17, 0x0d, 0x22, 0x17, 0x17, 0x0d, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x3e, 0x18, 0x02, 0x4a, 0x40, 0x07, 0x4d, 0x58, 0x2a, 0x40, 0x02, 0x40, 0x40, 0x02, 0x0f, + 0x02, 0x0e, 0x40, 0x12, 0x03, 0x0e, 0x19, 0x2f, 0x2f, 0x07, 0x07, 0x05, 0x19, 0x0d, 0x15, + 0x07, 0x47, 0x27, 0x1b, 0x0d, 0x40, 0x42, 0x40, 0x40, 0x40, 0x40, 0x02, 0x02, 0x42, 0x00, + 0x05, 0x00, 0x03, 0x0b, 0x42, 0x47, 0x47, 0x0e, 0x42, 0x4a, 0x47, 0x47, 0x0e, 0x10, 0x0d, + 0x13, 0x42, 0x00, 0x05, 0x00, 0x03, 0x0b, 0x42, 0x47, 0x47, 0x0e, 0x42, 0x4a, 0x47, 0x47, + 0x0e, 0x10, 0x0d, 0x13, 0x1d, 0x45, 0x29, 0x40, 0x4a, 0x40, 0x02, 0x07, 0x02, 0x0d, 0x0d, + 0x19, 0x05, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, 0x02, 0x45, 0x1a, 0x07, 0x40, 0x15, + 0x02, 0x45, 0x1a, 0x07, 0x40, 0x4a, 0x07, 0x0a, 0x0a, 0x15, 0x1d, 0x15, 0x1d, 0x0d, 0x17, + 0x02, 0x45, 0x17, 0x02, 0x45, 0x40, 0x40, 0x40, 0x0f, 0x0d, 0x0d, 0x40, 0x0f, 0x0d, 0x0a, + 0x0a, 0x2a, 0x27, 0x1a, 0x07, 0x1d, 0x1a, 0x15, 0x42, 0x24, 0x15, 0x0d, 0x40, 0x0f, 0x0d, + 0x0a, 0x18, 0x0d, 0x23, 0x18, 0x18, 0x0d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x19, 0x03, 0x49, + 0x40, 0x06, 0x4e, 0x59, 0x2b, 0x40, 0x03, 0x40, 0x40, 0x01, 0x0f, 0x03, 0x10, 0x40, 0x13, + 0x04, 0x10, 0x1b, 0x31, 0x31, 0x07, 0x07, 0x04, 0x17, 0x0c, 0x16, 0x07, 0x46, 0x27, 0x1c, + 0x0c, 0x40, 0x43, 0x41, 0x40, 0x40, 0x40, 0x03, 0x03, 0x41, 0x01, 0x06, 0x01, 0x04, 0x0c, + 0x41, 0x46, 0x46, 0x10, 0x41, 0x49, 0x46, 0x46, 0x10, 0x11, 0x0e, 0x14, 0x41, 0x01, 0x06, + 0x01, 0x04, 0x0c, 0x41, 0x46, 0x46, 0x10, 0x41, 0x49, 0x46, 0x46, 0x10, 0x11, 0x0e, 0x14, + 0x1e, 0x44, 0x2b, 0x40, 0x4b, 0x40, 0x03, 0x07, 0x03, 0x0e, 0x0e, 0x1b, 0x06, 0x14, 0x01, + 0x44, 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x01, 0x44, 0x1b, 0x07, + 0x40, 0x4b, 0x07, 0x0b, 0x0b, 0x16, 0x1e, 0x16, 0x1e, 0x0c, 0x17, 0x01, 0x44, 0x17, 0x01, + 0x44, 0x40, 0x40, 0x40, 0x0e, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x09, 0x09, 0x2b, 0x27, 0x1b, + 0x07, 0x1e, 0x1b, 0x16, 0x43, 0x22, 0x14, 0x0c, 0x40, 0x0f, 0x0c, 0x09, 0x19, 0x0c, 0x24, + 0x19, 0x19, 0x0c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x1a, 0x03, 0x48, 0x40, 0x05, 0x4f, 0x5a, + 0x2b, 0x40, 0x03, 0x40, 0x40, 0x00, 0x0f, 0x03, 0x11, 0x40, 0x13, 0x06, 0x11, 0x1d, 0x34, + 0x34, 0x07, 0x07, 0x04, 0x16, 0x0c, 0x17, 0x07, 0x45, 0x27, 0x1e, 0x0c, 0x40, 0x43, 0x42, + 0x40, 0x40, 0x40, 0x03, 0x03, 0x40, 0x02, 0x07, 0x02, 0x06, 0x0e, 0x40, 0x45, 0x45, 0x11, + 0x40, 0x48, 0x45, 0x45, 0x11, 0x12, 0x0f, 0x16, 0x40, 0x02, 0x07, 0x02, 0x06, 0x0e, 0x40, + 0x45, 0x45, 0x11, 0x40, 0x48, 0x45, 0x45, 0x11, 0x12, 0x0f, 0x16, 0x1f, 0x44, 0x2d, 0x40, + 0x4b, 0x40, 0x03, 0x07, 0x03, 0x0f, 0x0f, 0x1d, 0x07, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, + 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, 0x07, 0x0b, + 0x0b, 0x17, 0x1f, 0x17, 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, 0x40, + 0x0d, 0x0c, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x17, + 0x43, 0x21, 0x14, 0x0c, 0x40, 0x0f, 0x0c, 0x08, 0x1a, 0x0c, 0x26, 0x1a, 0x1a, 0x0c, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0x3e, 0x1b, 0x03, 0x48, 0x40, 0x04, 0x4f, 0x5b, 0x2b, 0x40, 0x03, 0x40, + 0x40, 0x00, 0x0f, 0x03, 0x13, 0x40, 0x13, 0x07, 0x13, 0x1f, 0x36, 0x36, 0x07, 0x07, 0x04, + 0x14, 0x0c, 0x17, 0x07, 0x44, 0x27, 0x1f, 0x0c, 0x40, 0x43, 0x43, 0x40, 0x40, 0x40, 0x03, + 0x03, 0x40, 0x03, 0x07, 0x03, 0x07, 0x0f, 0x40, 0x44, 0x44, 0x13, 0x40, 0x48, 0x44, 0x44, + 0x13, 0x13, 0x0f, 0x17, 0x40, 0x03, 0x07, 0x03, 0x07, 0x0f, 0x40, 0x44, 0x44, 0x13, 0x40, + 0x48, 0x44, 0x44, 0x13, 0x13, 0x0f, 0x17, 0x1f, 0x44, 0x2f, 0x40, 0x4b, 0x40, 0x03, 0x07, + 0x03, 0x0f, 0x0f, 0x1f, 0x07, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, + 0x07, 0x40, 0x14, 0x00, 0x44, 0x1b, 0x07, 0x40, 0x4b, 0x07, 0x0b, 0x0b, 0x17, 0x1f, 0x17, + 0x1f, 0x0c, 0x17, 0x00, 0x44, 0x17, 0x00, 0x44, 0x40, 0x40, 0x40, 0x0c, 0x0c, 0x0c, 0x40, + 0x0f, 0x0c, 0x08, 0x08, 0x2b, 0x27, 0x1b, 0x07, 0x1f, 0x1b, 0x17, 0x43, 0x20, 0x14, 0x0c, + 0x40, 0x0f, 0x0c, 0x08, 0x1b, 0x0c, 0x27, 0x1b, 0x1b, 0x0c, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, + 0x1c, 0x04, 0x47, 0x40, 0x03, 0x50, 0x5c, 0x2c, 0x40, 0x04, 0x40, 0x40, 0x40, 0x0f, 0x04, + 0x14, 0x40, 0x14, 0x08, 0x14, 0x21, 0x39, 0x39, 0x07, 0x07, 0x03, 0x13, 0x0b, 0x18, 0x07, + 0x43, 0x27, 0x20, 0x0b, 0x40, 0x44, 0x44, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x04, 0x08, + 0x04, 0x08, 0x10, 0x00, 0x43, 0x43, 0x14, 0x00, 0x47, 0x43, 0x43, 0x14, 0x14, 0x10, 0x18, + 0x00, 0x04, 0x08, 0x04, 0x08, 0x10, 0x00, 0x43, 0x43, 0x14, 0x00, 0x47, 0x43, 0x43, 0x14, + 0x14, 0x10, 0x18, 0x20, 0x43, 0x31, 0x40, 0x4c, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x21, + 0x08, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x40, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x40, + 0x43, 0x1c, 0x07, 0x40, 0x4c, 0x07, 0x0c, 0x0c, 0x18, 0x20, 0x18, 0x20, 0x0b, 0x17, 0x40, + 0x43, 0x17, 0x40, 0x43, 0x40, 0x40, 0x40, 0x0b, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x07, 0x07, + 0x2c, 0x27, 0x1c, 0x07, 0x20, 0x1c, 0x18, 0x44, 0x1f, 0x13, 0x0b, 0x40, 0x0f, 0x0b, 0x07, + 0x1c, 0x0b, 0x28, 0x1c, 0x1c, 0x0b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x1d, 0x04, 0x47, 0x40, + 0x02, 0x51, 0x5d, 0x2c, 0x40, 0x04, 0x40, 0x40, 0x41, 0x0f, 0x04, 0x16, 0x40, 0x14, 0x09, + 0x16, 0x22, 0x3b, 0x3b, 0x07, 0x07, 0x03, 0x11, 0x0b, 0x18, 0x07, 0x42, 0x27, 0x21, 0x0b, + 0x40, 0x44, 0x45, 0x40, 0x40, 0x40, 0x04, 0x04, 0x00, 0x05, 0x08, 0x05, 0x09, 0x11, 0x00, + 0x42, 0x42, 0x16, 0x00, 0x47, 0x42, 0x42, 0x16, 0x15, 0x10, 0x19, 0x00, 0x05, 0x08, 0x05, + 0x09, 0x11, 0x00, 0x42, 0x42, 0x16, 0x00, 0x47, 0x42, 0x42, 0x16, 0x15, 0x10, 0x19, 0x20, + 0x43, 0x32, 0x40, 0x4c, 0x40, 0x04, 0x07, 0x04, 0x10, 0x10, 0x22, 0x08, 0x13, 0x41, 0x43, + 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, + 0x4c, 0x07, 0x0c, 0x0c, 0x18, 0x20, 0x18, 0x20, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, + 0x40, 0x40, 0x40, 0x0a, 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, + 0x20, 0x1c, 0x18, 0x44, 0x1d, 0x13, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x1d, 0x0b, 0x29, 0x1d, + 0x1d, 0x0b, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x1e, 0x04, 0x46, 0x40, 0x01, 0x51, 0x5e, 0x2c, + 0x40, 0x04, 0x40, 0x40, 0x41, 0x0f, 0x04, 0x18, 0x40, 0x14, 0x0b, 0x18, 0x24, 0x3e, 0x3e, + 0x07, 0x07, 0x03, 0x0f, 0x0b, 0x19, 0x07, 0x41, 0x27, 0x23, 0x0b, 0x40, 0x44, 0x46, 0x40, + 0x40, 0x40, 0x04, 0x04, 0x01, 0x06, 0x09, 0x06, 0x0b, 0x13, 0x01, 0x41, 0x41, 0x18, 0x01, + 0x46, 0x41, 0x41, 0x18, 0x16, 0x11, 0x1b, 0x01, 0x06, 0x09, 0x06, 0x0b, 0x13, 0x01, 0x41, + 0x41, 0x18, 0x01, 0x46, 0x41, 0x41, 0x18, 0x16, 0x11, 0x1b, 0x21, 0x43, 0x34, 0x40, 0x4c, + 0x40, 0x04, 0x07, 0x04, 0x11, 0x11, 0x24, 0x09, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, + 0x41, 0x43, 0x1c, 0x07, 0x40, 0x13, 0x41, 0x43, 0x1c, 0x07, 0x40, 0x4c, 0x07, 0x0c, 0x0c, + 0x19, 0x21, 0x19, 0x21, 0x0b, 0x17, 0x41, 0x43, 0x17, 0x41, 0x43, 0x40, 0x40, 0x40, 0x09, + 0x0b, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x06, 0x2c, 0x27, 0x1c, 0x07, 0x21, 0x1c, 0x19, 0x44, + 0x1c, 0x13, 0x0b, 0x40, 0x0f, 0x0b, 0x06, 0x1e, 0x0b, 0x2b, 0x1e, 0x1e, 0x0b, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x3e, 0x1f, 0x05, 0x45, 0x40, 0x00, 0x52, 0x5f, 0x2d, 0x40, 0x05, 0x40, 0x40, + 0x42, 0x0f, 0x05, 0x19, 0x40, 0x15, 0x0c, 0x19, 0x26, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0e, + 0x0a, 0x1a, 0x07, 0x40, 0x27, 0x24, 0x0a, 0x40, 0x45, 0x47, 0x40, 0x40, 0x40, 0x05, 0x05, + 0x02, 0x07, 0x0a, 0x07, 0x0c, 0x14, 0x02, 0x40, 0x40, 0x19, 0x02, 0x45, 0x40, 0x40, 0x19, + 0x17, 0x12, 0x1c, 0x02, 0x07, 0x0a, 0x07, 0x0c, 0x14, 0x02, 0x40, 0x40, 0x19, 0x02, 0x45, + 0x40, 0x40, 0x19, 0x17, 0x12, 0x1c, 0x22, 0x42, 0x36, 0x40, 0x4d, 0x40, 0x05, 0x07, 0x05, + 0x12, 0x12, 0x26, 0x0a, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, + 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x4d, 0x07, 0x0d, 0x0d, 0x1a, 0x22, 0x1a, 0x22, + 0x0a, 0x17, 0x42, 0x42, 0x17, 0x42, 0x42, 0x40, 0x40, 0x40, 0x08, 0x0a, 0x0a, 0x40, 0x0f, + 0x0a, 0x05, 0x05, 0x2d, 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x1a, 0x45, 0x1b, 0x12, 0x0a, 0x40, + 0x0f, 0x0a, 0x05, 0x1f, 0x0a, 0x2c, 0x1f, 0x1f, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x20, + 0x05, 0x45, 0x40, 0x40, 0x52, 0x60, 0x2d, 0x40, 0x05, 0x40, 0x40, 0x42, 0x0f, 0x05, 0x1b, + 0x40, 0x15, 0x0d, 0x1b, 0x28, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0c, 0x0a, 0x1a, 0x07, 0x00, + 0x27, 0x25, 0x0a, 0x40, 0x45, 0x48, 0x40, 0x40, 0x40, 0x05, 0x05, 0x02, 0x08, 0x0a, 0x08, + 0x0d, 0x15, 0x02, 0x00, 0x00, 0x1b, 0x02, 0x45, 0x00, 0x00, 0x1b, 0x18, 0x12, 0x1d, 0x02, + 0x08, 0x0a, 0x08, 0x0d, 0x15, 0x02, 0x00, 0x00, 0x1b, 0x02, 0x45, 0x00, 0x00, 0x1b, 0x18, + 0x12, 0x1d, 0x22, 0x42, 0x38, 0x40, 0x4d, 0x40, 0x05, 0x07, 0x05, 0x12, 0x12, 0x28, 0x0a, + 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x42, 0x42, + 0x1d, 0x07, 0x40, 0x4d, 0x07, 0x0d, 0x0d, 0x1a, 0x22, 0x1a, 0x22, 0x0a, 0x17, 0x42, 0x42, + 0x17, 0x42, 0x42, 0x40, 0x40, 0x40, 0x07, 0x0a, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x05, 0x2d, + 0x27, 0x1d, 0x07, 0x22, 0x1d, 0x1a, 0x45, 0x1a, 0x12, 0x0a, 0x40, 0x0f, 0x0a, 0x05, 0x20, + 0x0a, 0x2d, 0x20, 0x20, 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x21, 0x05, 0x44, 0x40, 0x41, + 0x53, 0x61, 0x2d, 0x40, 0x05, 0x40, 0x40, 0x43, 0x0f, 0x05, 0x1c, 0x40, 0x15, 0x0e, 0x1c, + 0x2a, 0x3e, 0x3e, 0x07, 0x07, 0x02, 0x0b, 0x0a, 0x1b, 0x07, 0x01, 0x27, 0x26, 0x0a, 0x40, + 0x45, 0x49, 0x40, 0x40, 0x40, 0x05, 0x05, 0x03, 0x09, 0x0b, 0x09, 0x0e, 0x16, 0x03, 0x01, + 0x01, 0x1c, 0x03, 0x44, 0x01, 0x01, 0x1c, 0x19, 0x13, 0x1e, 0x03, 0x09, 0x0b, 0x09, 0x0e, + 0x16, 0x03, 0x01, 0x01, 0x1c, 0x03, 0x44, 0x01, 0x01, 0x1c, 0x19, 0x13, 0x1e, 0x23, 0x42, + 0x3a, 0x40, 0x4d, 0x40, 0x05, 0x07, 0x05, 0x13, 0x13, 0x2a, 0x0b, 0x12, 0x43, 0x42, 0x1d, + 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x12, 0x43, 0x42, 0x1d, 0x07, 0x40, 0x4d, + 0x07, 0x0d, 0x0d, 0x1b, 0x23, 0x1b, 0x23, 0x0a, 0x17, 0x43, 0x42, 0x17, 0x43, 0x42, 0x40, + 0x40, 0x40, 0x06, 0x0a, 0x0a, 0x40, 0x0f, 0x0a, 0x04, 0x04, 0x2d, 0x27, 0x1d, 0x07, 0x23, + 0x1d, 0x1b, 0x45, 0x18, 0x12, 0x0a, 0x40, 0x0f, 0x0a, 0x04, 0x21, 0x0a, 0x2e, 0x21, 0x21, + 0x0a, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x22, 0x06, 0x43, 0x40, 0x42, 0x54, 0x62, 0x2e, 0x40, + 0x06, 0x40, 0x40, 0x44, 0x0f, 0x06, 0x1e, 0x40, 0x16, 0x10, 0x1e, 0x2c, 0x3e, 0x3e, 0x07, + 0x07, 0x01, 0x09, 0x09, 0x1c, 0x07, 0x02, 0x27, 0x28, 0x09, 0x40, 0x46, 0x4a, 0x40, 0x40, + 0x40, 0x06, 0x06, 0x04, 0x0a, 0x0c, 0x0a, 0x10, 0x18, 0x04, 0x02, 0x02, 0x1e, 0x04, 0x43, + 0x02, 0x02, 0x1e, 0x1a, 0x14, 0x20, 0x04, 0x0a, 0x0c, 0x0a, 0x10, 0x18, 0x04, 0x02, 0x02, + 0x1e, 0x04, 0x43, 0x02, 0x02, 0x1e, 0x1a, 0x14, 0x20, 0x24, 0x41, 0x3c, 0x40, 0x4e, 0x40, + 0x06, 0x07, 0x06, 0x14, 0x14, 0x2c, 0x0c, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, + 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, 0x07, 0x0e, 0x0e, 0x1c, + 0x24, 0x1c, 0x24, 0x09, 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, 0x40, 0x05, 0x09, + 0x09, 0x40, 0x0f, 0x09, 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x1c, 0x46, 0x17, + 0x11, 0x09, 0x40, 0x0f, 0x09, 0x03, 0x22, 0x09, 0x30, 0x22, 0x22, 0x09, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x3e, 0x23, 0x06, 0x43, 0x40, 0x43, 0x54, 0x63, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x44, + 0x0f, 0x06, 0x1f, 0x40, 0x16, 0x11, 0x1f, 0x2e, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x08, 0x09, + 0x1c, 0x07, 0x03, 0x27, 0x29, 0x09, 0x40, 0x46, 0x4b, 0x40, 0x40, 0x40, 0x06, 0x06, 0x04, + 0x0b, 0x0c, 0x0b, 0x11, 0x19, 0x04, 0x03, 0x03, 0x1f, 0x04, 0x43, 0x03, 0x03, 0x1f, 0x1b, + 0x14, 0x21, 0x04, 0x0b, 0x0c, 0x0b, 0x11, 0x19, 0x04, 0x03, 0x03, 0x1f, 0x04, 0x43, 0x03, + 0x03, 0x1f, 0x1b, 0x14, 0x21, 0x24, 0x41, 0x3e, 0x40, 0x4e, 0x40, 0x06, 0x07, 0x06, 0x14, + 0x14, 0x2e, 0x0c, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, + 0x11, 0x44, 0x41, 0x1e, 0x07, 0x40, 0x4e, 0x07, 0x0e, 0x0e, 0x1c, 0x24, 0x1c, 0x24, 0x09, + 0x17, 0x44, 0x41, 0x17, 0x44, 0x41, 0x40, 0x40, 0x40, 0x04, 0x09, 0x09, 0x40, 0x0f, 0x09, + 0x03, 0x03, 0x2e, 0x27, 0x1e, 0x07, 0x24, 0x1e, 0x1c, 0x46, 0x16, 0x11, 0x09, 0x40, 0x0f, + 0x09, 0x03, 0x23, 0x09, 0x31, 0x23, 0x23, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x24, 0x06, + 0x42, 0x40, 0x44, 0x55, 0x64, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x45, 0x0f, 0x06, 0x21, 0x40, + 0x16, 0x12, 0x21, 0x30, 0x3e, 0x3e, 0x07, 0x07, 0x01, 0x06, 0x09, 0x1d, 0x07, 0x04, 0x27, + 0x2a, 0x09, 0x40, 0x46, 0x4c, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x0d, 0x0c, 0x12, + 0x1a, 0x05, 0x04, 0x04, 0x21, 0x05, 0x42, 0x04, 0x04, 0x21, 0x1c, 0x15, 0x22, 0x05, 0x0c, + 0x0d, 0x0c, 0x12, 0x1a, 0x05, 0x04, 0x04, 0x21, 0x05, 0x42, 0x04, 0x04, 0x21, 0x1c, 0x15, + 0x22, 0x25, 0x41, 0x3e, 0x40, 0x4e, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x30, 0x0d, 0x11, + 0x45, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, 0x07, 0x40, 0x11, 0x45, 0x41, 0x1e, + 0x07, 0x40, 0x4e, 0x07, 0x0e, 0x0e, 0x1d, 0x25, 0x1d, 0x25, 0x09, 0x17, 0x45, 0x41, 0x17, + 0x45, 0x41, 0x40, 0x40, 0x40, 0x03, 0x09, 0x09, 0x40, 0x0f, 0x09, 0x02, 0x02, 0x2e, 0x27, + 0x1e, 0x07, 0x25, 0x1e, 0x1d, 0x46, 0x15, 0x11, 0x09, 0x40, 0x0f, 0x09, 0x02, 0x24, 0x09, + 0x32, 0x24, 0x24, 0x09, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x24, 0x06, 0x42, 0x40, 0x45, 0x56, + 0x65, 0x2e, 0x40, 0x06, 0x40, 0x40, 0x46, 0x0f, 0x06, 0x22, 0x40, 0x16, 0x13, 0x22, 0x31, + 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x04, 0x08, 0x1d, 0x07, 0x04, 0x27, 0x2b, 0x08, 0x40, 0x47, + 0x4d, 0x40, 0x40, 0x40, 0x06, 0x06, 0x05, 0x0c, 0x0d, 0x0c, 0x13, 0x1b, 0x05, 0x04, 0x04, + 0x22, 0x05, 0x42, 0x04, 0x04, 0x22, 0x1c, 0x15, 0x23, 0x05, 0x0c, 0x0d, 0x0c, 0x13, 0x1b, + 0x05, 0x04, 0x04, 0x22, 0x05, 0x42, 0x04, 0x04, 0x22, 0x1c, 0x15, 0x23, 0x25, 0x41, 0x3e, + 0x40, 0x4f, 0x40, 0x06, 0x07, 0x06, 0x15, 0x15, 0x31, 0x0d, 0x10, 0x46, 0x41, 0x1e, 0x07, + 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x10, 0x46, 0x41, 0x1e, 0x07, 0x40, 0x4f, 0x07, + 0x0e, 0x0e, 0x1d, 0x25, 0x1d, 0x25, 0x08, 0x17, 0x46, 0x41, 0x17, 0x46, 0x41, 0x40, 0x40, + 0x40, 0x02, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2e, 0x27, 0x1e, 0x07, 0x25, 0x1e, + 0x1d, 0x47, 0x13, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x01, 0x24, 0x08, 0x33, 0x24, 0x24, 0x08, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x3e, 0x25, 0x07, 0x41, 0x40, 0x45, 0x56, 0x65, 0x2f, 0x40, 0x07, + 0x40, 0x40, 0x46, 0x0f, 0x07, 0x24, 0x40, 0x17, 0x15, 0x24, 0x33, 0x3e, 0x3e, 0x07, 0x07, + 0x00, 0x03, 0x08, 0x1e, 0x07, 0x05, 0x27, 0x2d, 0x08, 0x40, 0x47, 0x4d, 0x40, 0x40, 0x40, + 0x07, 0x07, 0x06, 0x0d, 0x0e, 0x0d, 0x15, 0x1d, 0x06, 0x05, 0x05, 0x24, 0x06, 0x41, 0x05, + 0x05, 0x24, 0x1d, 0x16, 0x25, 0x06, 0x0d, 0x0e, 0x0d, 0x15, 0x1d, 0x06, 0x05, 0x05, 0x24, + 0x06, 0x41, 0x05, 0x05, 0x24, 0x1d, 0x16, 0x25, 0x26, 0x40, 0x3e, 0x40, 0x4f, 0x40, 0x07, + 0x07, 0x07, 0x16, 0x16, 0x33, 0x0e, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, + 0x1f, 0x07, 0x40, 0x10, 0x46, 0x40, 0x1f, 0x07, 0x40, 0x4f, 0x07, 0x0f, 0x0f, 0x1e, 0x26, + 0x1e, 0x26, 0x08, 0x17, 0x46, 0x40, 0x17, 0x46, 0x40, 0x40, 0x40, 0x40, 0x02, 0x08, 0x08, + 0x40, 0x0f, 0x08, 0x01, 0x01, 0x2f, 0x27, 0x1f, 0x07, 0x26, 0x1f, 0x1e, 0x47, 0x12, 0x10, + 0x08, 0x40, 0x0f, 0x08, 0x01, 0x25, 0x08, 0x35, 0x25, 0x25, 0x08, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, + 0x3e, 0x26, 0x07, 0x40, 0x40, 0x46, 0x57, 0x66, 0x2f, 0x40, 0x07, 0x40, 0x40, 0x47, 0x0f, + 0x07, 0x26, 0x40, 0x17, 0x16, 0x26, 0x35, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x01, 0x08, 0x1f, + 0x07, 0x06, 0x27, 0x2e, 0x08, 0x40, 0x47, 0x4e, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0e, + 0x0f, 0x0e, 0x16, 0x1e, 0x07, 0x06, 0x06, 0x26, 0x07, 0x40, 0x06, 0x06, 0x26, 0x1e, 0x17, + 0x26, 0x07, 0x0e, 0x0f, 0x0e, 0x16, 0x1e, 0x07, 0x06, 0x06, 0x26, 0x07, 0x40, 0x06, 0x06, + 0x26, 0x1e, 0x17, 0x26, 0x27, 0x40, 0x3e, 0x40, 0x4f, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, + 0x35, 0x0f, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, + 0x47, 0x40, 0x1f, 0x07, 0x40, 0x4f, 0x07, 0x0f, 0x0f, 0x1f, 0x27, 0x1f, 0x27, 0x08, 0x17, + 0x47, 0x40, 0x17, 0x47, 0x40, 0x40, 0x40, 0x40, 0x01, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x00, + 0x00, 0x2f, 0x27, 0x1f, 0x07, 0x27, 0x1f, 0x1f, 0x47, 0x11, 0x10, 0x08, 0x40, 0x0f, 0x08, + 0x00, 0x26, 0x08, 0x36, 0x26, 0x26, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x3e, 0x27, 0x07, 0x40, + 0x40, 0x47, 0x57, 0x67, 0x2f, 0x40, 0x07, 0x40, 0x40, 0x47, 0x0f, 0x07, 0x27, 0x40, 0x17, + 0x17, 0x27, 0x37, 0x3e, 0x3e, 0x07, 0x07, 0x00, 0x00, 0x08, 0x1f, 0x07, 0x07, 0x27, 0x2f, + 0x08, 0x40, 0x47, 0x4f, 0x40, 0x40, 0x40, 0x07, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x17, 0x1f, + 0x07, 0x07, 0x07, 0x27, 0x07, 0x40, 0x07, 0x07, 0x27, 0x1f, 0x17, 0x27, 0x07, 0x0f, 0x0f, + 0x0f, 0x17, 0x1f, 0x07, 0x07, 0x07, 0x27, 0x07, 0x40, 0x07, 0x07, 0x27, 0x1f, 0x17, 0x27, + 0x27, 0x40, 0x3e, 0x40, 0x4f, 0x40, 0x07, 0x07, 0x07, 0x17, 0x17, 0x37, 0x0f, 0x10, 0x47, + 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, 0x40, 0x10, 0x47, 0x40, 0x1f, 0x07, + 0x40, 0x4f, 0x07, 0x0f, 0x0f, 0x1f, 0x27, 0x1f, 0x27, 0x08, 0x17, 0x47, 0x40, 0x17, 0x47, + 0x40, 0x40, 0x40, 0x40, 0x00, 0x08, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x00, 0x2f, 0x27, 0x1f, + 0x07, 0x27, 0x1f, 0x1f, 0x47, 0x10, 0x10, 0x08, 0x40, 0x0f, 0x08, 0x00, 0x27, 0x08, 0x37, + 0x27, 0x27, 0x08, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c new file mode 100644 index 000000000000..fc7e6a260b0a --- /dev/null +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c @@ -0,0 +1,820 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Rockchip Video Decoder HEVC backend + * + * Copyright (C) 2023 Collabora, Ltd. + * Sebastian Fricke <sebastian.fricke@collabora.com> + * + * Copyright (C) 2019 Collabora, Ltd. + * Boris Brezillon <boris.brezillon@collabora.com> + * + * Copyright (C) 2016 Rockchip Electronics Co., Ltd. + * Jeffy Chen <jeffy.chen@rock-chips.com> + */ + +#include <media/v4l2-mem2mem.h> + +#include "rkvdec.h" +#include "rkvdec-regs.h" +#include "rkvdec-hevc-data.c" + +/* Size in u8/u32 units. */ +#define RKV_SCALING_LIST_SIZE 1360 +#define RKV_PPS_SIZE (80 / 4) +#define RKV_PPS_LEN 64 +#define RKV_RPS_SIZE (32 / 4) +#define RKV_RPS_LEN 600 + +struct rkvdec_sps_pps_packet { + u32 info[RKV_PPS_SIZE]; +}; + +struct rkvdec_rps_packet { + u32 info[RKV_RPS_SIZE]; +}; + +struct rkvdec_ps_field { + u16 offset; + u8 len; +}; + +#define PS_FIELD(_offset, _len) \ + ((struct rkvdec_ps_field){ _offset, _len }) + +/* SPS */ +#define VIDEO_PARAMETER_SET_ID PS_FIELD(0, 4) +#define SEQ_PARAMETER_SET_ID PS_FIELD(4, 4) +#define CHROMA_FORMAT_IDC PS_FIELD(8, 2) +#define PIC_WIDTH_IN_LUMA_SAMPLES PS_FIELD(10, 13) +#define PIC_HEIGHT_IN_LUMA_SAMPLES PS_FIELD(23, 13) +#define BIT_DEPTH_LUMA PS_FIELD(36, 4) +#define BIT_DEPTH_CHROMA PS_FIELD(40, 4) +#define LOG2_MAX_PIC_ORDER_CNT_LSB PS_FIELD(44, 5) +#define LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE PS_FIELD(49, 2) +#define LOG2_MIN_LUMA_CODING_BLOCK_SIZE PS_FIELD(51, 3) +#define LOG2_MIN_TRANSFORM_BLOCK_SIZE PS_FIELD(54, 3) +#define LOG2_DIFF_MAX_MIN_LUMA_TRANSFORM_BLOCK_SIZE PS_FIELD(57, 2) +#define MAX_TRANSFORM_HIERARCHY_DEPTH_INTER PS_FIELD(59, 3) +#define MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA PS_FIELD(62, 3) +#define SCALING_LIST_ENABLED_FLAG PS_FIELD(65, 1) +#define AMP_ENABLED_FLAG PS_FIELD(66, 1) +#define SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG PS_FIELD(67, 1) +#define PCM_ENABLED_FLAG PS_FIELD(68, 1) +#define PCM_SAMPLE_BIT_DEPTH_LUMA PS_FIELD(69, 4) +#define PCM_SAMPLE_BIT_DEPTH_CHROMA PS_FIELD(73, 4) +#define PCM_LOOP_FILTER_DISABLED_FLAG PS_FIELD(77, 1) +#define LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE PS_FIELD(78, 3) +#define LOG2_MIN_PCM_LUMA_CODING_BLOCK_SIZE PS_FIELD(81, 3) +#define NUM_SHORT_TERM_REF_PIC_SETS PS_FIELD(84, 7) +#define LONG_TERM_REF_PICS_PRESENT_FLAG PS_FIELD(91, 1) +#define NUM_LONG_TERM_REF_PICS_SPS PS_FIELD(92, 6) +#define SPS_TEMPORAL_MVP_ENABLED_FLAG PS_FIELD(98, 1) +#define STRONG_INTRA_SMOOTHING_ENABLED_FLAG PS_FIELD(99, 1) +/* PPS */ +#define PIC_PARAMETER_SET_ID PS_FIELD(128, 6) +#define PPS_SEQ_PARAMETER_SET_ID PS_FIELD(134, 4) +#define DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG PS_FIELD(138, 1) +#define OUTPUT_FLAG_PRESENT_FLAG PS_FIELD(139, 1) +#define NUM_EXTRA_SLICE_HEADER_BITS PS_FIELD(140, 13) +#define SIGN_DATA_HIDING_ENABLED_FLAG PS_FIELD(153, 1) +#define CABAC_INIT_PRESENT_FLAG PS_FIELD(154, 1) +#define NUM_REF_IDX_L0_DEFAULT_ACTIVE PS_FIELD(155, 4) +#define NUM_REF_IDX_L1_DEFAULT_ACTIVE PS_FIELD(159, 4) +#define INIT_QP_MINUS26 PS_FIELD(163, 7) +#define CONSTRAINED_INTRA_PRED_FLAG PS_FIELD(170, 1) +#define TRANSFORM_SKIP_ENABLED_FLAG PS_FIELD(171, 1) +#define CU_QP_DELTA_ENABLED_FLAG PS_FIELD(172, 1) +#define LOG2_MIN_CU_QP_DELTA_SIZE PS_FIELD(173, 3) +#define PPS_CB_QP_OFFSET PS_FIELD(176, 5) +#define PPS_CR_QP_OFFSET PS_FIELD(181, 5) +#define PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG PS_FIELD(186, 1) +#define WEIGHTED_PRED_FLAG PS_FIELD(187, 1) +#define WEIGHTED_BIPRED_FLAG PS_FIELD(188, 1) +#define TRANSQUANT_BYPASS_ENABLED_FLAG PS_FIELD(189, 1) +#define TILES_ENABLED_FLAG PS_FIELD(190, 1) +#define ENTROPY_CODING_SYNC_ENABLED_FLAG PS_FIELD(191, 1) +#define PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG PS_FIELD(192, 1) +#define LOOP_FILTER_ACROSS_TILES_ENABLED_FLAG PS_FIELD(193, 1) +#define DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG PS_FIELD(194, 1) +#define PPS_DEBLOCKING_FILTER_DISABLED_FLAG PS_FIELD(195, 1) +#define PPS_BETA_OFFSET_DIV2 PS_FIELD(196, 4) +#define PPS_TC_OFFSET_DIV2 PS_FIELD(200, 4) +#define LISTS_MODIFICATION_PRESENT_FLAG PS_FIELD(204, 1) +#define LOG2_PARALLEL_MERGE_LEVEL PS_FIELD(205, 3) +#define SLICE_SEGMENT_HEADER_EXTENSION_PRESENT_FLAG PS_FIELD(208, 1) +#define NUM_TILE_COLUMNS PS_FIELD(212, 5) +#define NUM_TILE_ROWS PS_FIELD(217, 5) +#define COLUMN_WIDTH(i) PS_FIELD(256 + ((i) * 8), 8) +#define ROW_HEIGHT(i) PS_FIELD(416 + ((i) * 8), 8) +#define SCALING_LIST_ADDRESS PS_FIELD(592, 32) + +/* Data structure describing auxiliary buffer format. */ +struct rkvdec_hevc_priv_tbl { + u8 cabac_table[RKV_CABAC_TABLE_SIZE]; + u8 scaling_list[RKV_SCALING_LIST_SIZE]; + struct rkvdec_sps_pps_packet param_set[RKV_PPS_LEN]; + struct rkvdec_rps_packet rps[RKV_RPS_LEN]; +}; + +struct rkvdec_hevc_run { + struct rkvdec_run base; + const struct v4l2_ctrl_hevc_slice_params *slices_params; + const struct v4l2_ctrl_hevc_decode_params *decode_params; + const struct v4l2_ctrl_hevc_sps *sps; + const struct v4l2_ctrl_hevc_pps *pps; + const struct v4l2_ctrl_hevc_scaling_matrix *scaling_matrix; + int num_slices; +}; + +struct rkvdec_hevc_ctx { + struct rkvdec_aux_buf priv_tbl; + struct v4l2_ctrl_hevc_scaling_matrix scaling_matrix_cache; +}; + +struct scaling_factor { + u8 scalingfactor0[1248]; + u8 scalingfactor1[96]; /*4X4 TU Rotate, total 16X4*/ + u8 scalingdc[12]; /*N1005 Vienna Meeting*/ + u8 reserved[4]; /*16Bytes align*/ +}; + +static void set_ps_field(u32 *buf, struct rkvdec_ps_field field, u32 value) +{ + u8 bit = field.offset % 32, word = field.offset / 32; + u64 mask = GENMASK_ULL(bit + field.len - 1, bit); + u64 val = ((u64)value << bit) & mask; + + buf[word] &= ~mask; + buf[word] |= val; + if (bit + field.len > 32) { + buf[word + 1] &= ~(mask >> 32); + buf[word + 1] |= val >> 32; + } +} + +static void assemble_hw_pps(struct rkvdec_ctx *ctx, + struct rkvdec_hevc_run *run) +{ + struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; + const struct v4l2_ctrl_hevc_sps *sps = run->sps; + const struct v4l2_ctrl_hevc_pps *pps = run->pps; + struct rkvdec_hevc_priv_tbl *priv_tbl = hevc_ctx->priv_tbl.cpu; + struct rkvdec_sps_pps_packet *hw_ps; + u32 min_cb_log2_size_y, ctb_log2_size_y, ctb_size_y; + u32 log2_min_cu_qp_delta_size, scaling_distance; + dma_addr_t scaling_list_address; + int i; + + /* + * HW read the SPS/PPS information from PPS packet index by PPS id. + * offset from the base can be calculated by PPS_id * 80 (size per PPS + * packet unit). so the driver copy SPS/PPS information to the exact PPS + * packet unit for HW accessing. + */ + hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id]; + memset(hw_ps, 0, sizeof(*hw_ps)); + +#define WRITE_PPS(value, field) set_ps_field(hw_ps->info, field, value) + /* write sps */ + WRITE_PPS(sps->video_parameter_set_id, VIDEO_PARAMETER_SET_ID); + WRITE_PPS(sps->seq_parameter_set_id, SEQ_PARAMETER_SET_ID); + WRITE_PPS(sps->chroma_format_idc, CHROMA_FORMAT_IDC); + WRITE_PPS(sps->pic_width_in_luma_samples, PIC_WIDTH_IN_LUMA_SAMPLES); + WRITE_PPS(sps->pic_height_in_luma_samples, PIC_HEIGHT_IN_LUMA_SAMPLES); + WRITE_PPS(sps->bit_depth_luma_minus8 + 8, BIT_DEPTH_LUMA); + WRITE_PPS(sps->bit_depth_chroma_minus8 + 8, BIT_DEPTH_CHROMA); + WRITE_PPS(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, + LOG2_MAX_PIC_ORDER_CNT_LSB); + WRITE_PPS(sps->log2_diff_max_min_luma_coding_block_size, + LOG2_DIFF_MAX_MIN_LUMA_CODING_BLOCK_SIZE); + WRITE_PPS(sps->log2_min_luma_coding_block_size_minus3 + 3, + LOG2_MIN_LUMA_CODING_BLOCK_SIZE); + WRITE_PPS(sps->log2_min_luma_transform_block_size_minus2 + 2, + LOG2_MIN_TRANSFORM_BLOCK_SIZE); + WRITE_PPS(sps->log2_diff_max_min_luma_transform_block_size, + LOG2_DIFF_MAX_MIN_LUMA_TRANSFORM_BLOCK_SIZE); + WRITE_PPS(sps->max_transform_hierarchy_depth_inter, + MAX_TRANSFORM_HIERARCHY_DEPTH_INTER); + WRITE_PPS(sps->max_transform_hierarchy_depth_intra, + MAX_TRANSFORM_HIERARCHY_DEPTH_INTRA); + WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED), + SCALING_LIST_ENABLED_FLAG); + WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_AMP_ENABLED), + AMP_ENABLED_FLAG); + WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET), + SAMPLE_ADAPTIVE_OFFSET_ENABLED_FLAG); + if (sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED) { + WRITE_PPS(1, PCM_ENABLED_FLAG); + WRITE_PPS(sps->pcm_sample_bit_depth_luma_minus1 + 1, + PCM_SAMPLE_BIT_DEPTH_LUMA); + WRITE_PPS(sps->pcm_sample_bit_depth_chroma_minus1 + 1, + PCM_SAMPLE_BIT_DEPTH_CHROMA); + WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED), + PCM_LOOP_FILTER_DISABLED_FLAG); + WRITE_PPS(sps->log2_diff_max_min_pcm_luma_coding_block_size, + LOG2_DIFF_MAX_MIN_PCM_LUMA_CODING_BLOCK_SIZE); + WRITE_PPS(sps->log2_min_pcm_luma_coding_block_size_minus3 + 3, + LOG2_MIN_PCM_LUMA_CODING_BLOCK_SIZE); + } + WRITE_PPS(sps->num_short_term_ref_pic_sets, NUM_SHORT_TERM_REF_PIC_SETS); + WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT), + LONG_TERM_REF_PICS_PRESENT_FLAG); + WRITE_PPS(sps->num_long_term_ref_pics_sps, NUM_LONG_TERM_REF_PICS_SPS); + WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED), + SPS_TEMPORAL_MVP_ENABLED_FLAG); + WRITE_PPS(!!(sps->flags & V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED), + STRONG_INTRA_SMOOTHING_ENABLED_FLAG); + + /* write pps */ + WRITE_PPS(pps->pic_parameter_set_id, PIC_PARAMETER_SET_ID); + WRITE_PPS(sps->seq_parameter_set_id, PPS_SEQ_PARAMETER_SET_ID); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED), + DEPENDENT_SLICE_SEGMENTS_ENABLED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT), + OUTPUT_FLAG_PRESENT_FLAG); + WRITE_PPS(pps->num_extra_slice_header_bits, NUM_EXTRA_SLICE_HEADER_BITS); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED), + SIGN_DATA_HIDING_ENABLED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT), + CABAC_INIT_PRESENT_FLAG); + WRITE_PPS(pps->num_ref_idx_l0_default_active_minus1 + 1, + NUM_REF_IDX_L0_DEFAULT_ACTIVE); + WRITE_PPS(pps->num_ref_idx_l1_default_active_minus1 + 1, + NUM_REF_IDX_L1_DEFAULT_ACTIVE); + WRITE_PPS(pps->init_qp_minus26, INIT_QP_MINUS26); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED), + CONSTRAINED_INTRA_PRED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED), + TRANSFORM_SKIP_ENABLED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED), + CU_QP_DELTA_ENABLED_FLAG); + + min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3; + ctb_log2_size_y = min_cb_log2_size_y + + sps->log2_diff_max_min_luma_coding_block_size; + ctb_size_y = 1 << ctb_log2_size_y; + log2_min_cu_qp_delta_size = ctb_log2_size_y - pps->diff_cu_qp_delta_depth; + WRITE_PPS(log2_min_cu_qp_delta_size, LOG2_MIN_CU_QP_DELTA_SIZE); + WRITE_PPS(pps->pps_cb_qp_offset, PPS_CB_QP_OFFSET); + WRITE_PPS(pps->pps_cr_qp_offset, PPS_CR_QP_OFFSET); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT), + PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED), + WEIGHTED_PRED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED), + WEIGHTED_BIPRED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED), + TRANSQUANT_BYPASS_ENABLED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED), + TILES_ENABLED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED), + ENTROPY_CODING_SYNC_ENABLED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED), + PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED), + LOOP_FILTER_ACROSS_TILES_ENABLED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED), + DEBLOCKING_FILTER_OVERRIDE_ENABLED_FLAG); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER), + PPS_DEBLOCKING_FILTER_DISABLED_FLAG); + WRITE_PPS(pps->pps_beta_offset_div2, PPS_BETA_OFFSET_DIV2); + WRITE_PPS(pps->pps_tc_offset_div2, PPS_TC_OFFSET_DIV2); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT), + LISTS_MODIFICATION_PRESENT_FLAG); + WRITE_PPS(pps->log2_parallel_merge_level_minus2 + 2, LOG2_PARALLEL_MERGE_LEVEL); + WRITE_PPS(!!(pps->flags & V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT), + SLICE_SEGMENT_HEADER_EXTENSION_PRESENT_FLAG); + WRITE_PPS(pps->num_tile_columns_minus1 + 1, NUM_TILE_COLUMNS); + WRITE_PPS(pps->num_tile_rows_minus1 + 1, NUM_TILE_ROWS); + + if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) { + /* Userspace also provide column width and row height for uniform spacing */ + for (i = 0; i <= pps->num_tile_columns_minus1; i++) + WRITE_PPS(pps->column_width_minus1[i], COLUMN_WIDTH(i)); + for (i = 0; i <= pps->num_tile_rows_minus1; i++) + WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i)); + } else { + WRITE_PPS(((sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1, + COLUMN_WIDTH(0)); + WRITE_PPS(((sps->pic_height_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1, + ROW_HEIGHT(0)); + } + + scaling_distance = offsetof(struct rkvdec_hevc_priv_tbl, scaling_list); + scaling_list_address = hevc_ctx->priv_tbl.dma + scaling_distance; + WRITE_PPS(scaling_list_address, SCALING_LIST_ADDRESS); +} + +/* + * Creation of the Reference Picture Set memory blob for the hardware. + * The layout looks like this: + * [0] 32 bits for L0 (6 references + 2 bits of the 7th reference) + * [1] 32 bits for L0 (remaining 3 bits of the 7th reference + 5 references + * + 4 bits of the 13th reference) + * [2] 11 bits for L0 (remaining bit for 13 and 2 references) and + * 21 bits for L1 (4 references + first bit of 5) + * [3] 32 bits of padding with 0s + * [4] 32 bits for L1 (remaining 4 bits for 5 + 5 references + 3 bits of 11) + * [5] 22 bits for L1 (remaining 2 bits of 11 and 4 references) + * lowdelay flag (bit 23), rps bit offset long term (bit 24 - 32) + * [6] rps bit offset long term (bit 1 - 3), rps bit offset short term (bit 4 - 12) + * number of references (bit 13 - 16), remaining 16 bits of padding with 0s + * [7] 32 bits of padding with 0s + * + * Thus we have to set up padding in between reference 5 of the L1 list. + */ +static void assemble_sw_rps(struct rkvdec_ctx *ctx, + struct rkvdec_hevc_run *run) +{ + const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params; + const struct v4l2_ctrl_hevc_sps *sps = run->sps; + const struct v4l2_ctrl_hevc_slice_params *sl_params; + const struct v4l2_hevc_dpb_entry *dpb; + struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; + struct rkvdec_hevc_priv_tbl *priv_tbl = hevc_ctx->priv_tbl.cpu; + struct rkvdec_rps_packet *hw_ps; + int i, j; + unsigned int lowdelay; + +#define WRITE_RPS(value, field) set_ps_field(hw_ps->info, field, value) + +#define REF_PIC_LONG_TERM_L0(i) PS_FIELD((i) * 5, 1) +#define REF_PIC_IDX_L0(i) PS_FIELD(1 + ((i) * 5), 4) +#define REF_PIC_LONG_TERM_L1(i) PS_FIELD(((i) < 5 ? 75 : 132) + ((i) * 5), 1) +#define REF_PIC_IDX_L1(i) PS_FIELD(((i) < 4 ? 76 : 128) + ((i) * 5), 4) + +#define LOWDELAY PS_FIELD(182, 1) +#define LONG_TERM_RPS_BIT_OFFSET PS_FIELD(183, 10) +#define SHORT_TERM_RPS_BIT_OFFSET PS_FIELD(193, 9) +#define NUM_RPS_POC PS_FIELD(202, 4) + + for (j = 0; j < run->num_slices; j++) { + uint st_bit_offset = 0; + uint num_l0_refs = 0; + uint num_l1_refs = 0; + + sl_params = &run->slices_params[j]; + dpb = decode_params->dpb; + + if (sl_params->slice_type != V4L2_HEVC_SLICE_TYPE_I) { + num_l0_refs = sl_params->num_ref_idx_l0_active_minus1 + 1; + + if (sl_params->slice_type == V4L2_HEVC_SLICE_TYPE_B) + num_l1_refs = sl_params->num_ref_idx_l1_active_minus1 + 1; + + lowdelay = 1; + } else { + lowdelay = 0; + } + + hw_ps = &priv_tbl->rps[j]; + memset(hw_ps, 0, sizeof(*hw_ps)); + + for (i = 0; i < num_l0_refs; i++) { + const struct v4l2_hevc_dpb_entry dpb_l0 = dpb[sl_params->ref_idx_l0[i]]; + + WRITE_RPS(!!(dpb_l0.flags & V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE), + REF_PIC_LONG_TERM_L0(i)); + WRITE_RPS(sl_params->ref_idx_l0[i], REF_PIC_IDX_L0(i)); + + if (dpb_l0.pic_order_cnt_val > sl_params->slice_pic_order_cnt) + lowdelay = 0; + } + + for (i = 0; i < num_l1_refs; i++) { + const struct v4l2_hevc_dpb_entry dpb_l1 = dpb[sl_params->ref_idx_l1[i]]; + int is_long_term = + !!(dpb_l1.flags & V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE); + + WRITE_RPS(is_long_term, REF_PIC_LONG_TERM_L1(i)); + WRITE_RPS(sl_params->ref_idx_l1[i], REF_PIC_IDX_L1(i)); + + if (dpb_l1.pic_order_cnt_val > sl_params->slice_pic_order_cnt) + lowdelay = 0; + } + + WRITE_RPS(lowdelay, LOWDELAY); + + if (!(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC)) { + if (sl_params->short_term_ref_pic_set_size) + st_bit_offset = sl_params->short_term_ref_pic_set_size; + else if (sps->num_short_term_ref_pic_sets > 1) + st_bit_offset = fls(sps->num_short_term_ref_pic_sets - 1); + } + + WRITE_RPS(st_bit_offset + sl_params->long_term_ref_pic_set_size, + LONG_TERM_RPS_BIT_OFFSET); + WRITE_RPS(sl_params->short_term_ref_pic_set_size, + SHORT_TERM_RPS_BIT_OFFSET); + + WRITE_RPS(decode_params->num_poc_st_curr_before + + decode_params->num_poc_st_curr_after + + decode_params->num_poc_lt_curr, + NUM_RPS_POC); + } +} + +/* + * Flip one or more matrices along their main diagonal and flatten them + * before writing it to the memory. + * Convert: + * ABCD AEIM + * EFGH => BFJN => AEIMBFJNCGKODHLP + * IJKL CGKO + * MNOP DHLP + */ +static void transpose_and_flatten_matrices(u8 *output, const u8 *input, + int matrices, int row_length) +{ + int i, j, row, x_offset, matrix_offset, rot_index, y_offset, matrix_size, new_value; + + matrix_size = row_length * row_length; + for (i = 0; i < matrices; i++) { + row = 0; + x_offset = 0; + matrix_offset = i * matrix_size; + for (j = 0; j < matrix_size; j++) { + y_offset = j - (row * row_length); + rot_index = y_offset * row_length + x_offset; + new_value = *(input + i * matrix_size + j); + output[matrix_offset + rot_index] = new_value; + if ((j + 1) % row_length == 0) { + row += 1; + x_offset += 1; + } + } + } +} + +static void assemble_scalingfactor0(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input) +{ + int offset = 0; + + transpose_and_flatten_matrices(output, (const u8 *)input->scaling_list_4x4, 6, 4); + offset = 6 * 16 * sizeof(u8); + transpose_and_flatten_matrices(output + offset, (const u8 *)input->scaling_list_8x8, 6, 8); + offset += 6 * 64 * sizeof(u8); + transpose_and_flatten_matrices(output + offset, + (const u8 *)input->scaling_list_16x16, 6, 8); + offset += 6 * 64 * sizeof(u8); + /* Add a 128 byte padding with 0s between the two 32x32 matrices */ + transpose_and_flatten_matrices(output + offset, + (const u8 *)input->scaling_list_32x32, 1, 8); + offset += 64 * sizeof(u8); + memset(output + offset, 0, 128); + offset += 128 * sizeof(u8); + transpose_and_flatten_matrices(output + offset, + (const u8 *)input->scaling_list_32x32 + (64 * sizeof(u8)), + 1, 8); + offset += 64 * sizeof(u8); + memset(output + offset, 0, 128); +} + +/* + * Required layout: + * A = scaling_list_dc_coef_16x16 + * B = scaling_list_dc_coef_32x32 + * 0 = Padding + * + * A, A, A, A, A, A, B, 0, 0, B, 0, 0 + */ +static void assemble_scalingdc(u8 *output, const struct v4l2_ctrl_hevc_scaling_matrix *input) +{ + u8 list_32x32[6] = {0}; + + memcpy(output, input->scaling_list_dc_coef_16x16, 6 * sizeof(u8)); + list_32x32[0] = input->scaling_list_dc_coef_32x32[0]; + list_32x32[3] = input->scaling_list_dc_coef_32x32[1]; + memcpy(output + 6 * sizeof(u8), list_32x32, 6 * sizeof(u8)); +} + +static void translate_scaling_list(struct scaling_factor *output, + const struct v4l2_ctrl_hevc_scaling_matrix *input) +{ + assemble_scalingfactor0(output->scalingfactor0, input); + memcpy(output->scalingfactor1, (const u8 *)input->scaling_list_4x4, 96); + assemble_scalingdc(output->scalingdc, input); + memset(output->reserved, 0, 4 * sizeof(u8)); +} + +static void assemble_hw_scaling_list(struct rkvdec_ctx *ctx, + struct rkvdec_hevc_run *run) +{ + const struct v4l2_ctrl_hevc_scaling_matrix *scaling = run->scaling_matrix; + struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; + struct rkvdec_hevc_priv_tbl *tbl = hevc_ctx->priv_tbl.cpu; + u8 *dst; + + if (!memcmp((void *)&hevc_ctx->scaling_matrix_cache, scaling, + sizeof(struct v4l2_ctrl_hevc_scaling_matrix))) + return; + + dst = tbl->scaling_list; + translate_scaling_list((struct scaling_factor *)dst, scaling); + + memcpy((void *)&hevc_ctx->scaling_matrix_cache, scaling, + sizeof(struct v4l2_ctrl_hevc_scaling_matrix)); +} + +static struct vb2_buffer * +get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run, + unsigned int dpb_idx) +{ + struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; + const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params; + const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb; + struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; + struct vb2_buffer *buf = NULL; + + if (dpb_idx < decode_params->num_active_dpb_entries) + buf = vb2_find_buffer(cap_q, dpb[dpb_idx].timestamp); + + /* + * If a DPB entry is unused or invalid, the address of current destination + * buffer is returned. + */ + if (!buf) + return &run->base.bufs.dst->vb2_buf; + + return buf; +} + +static void config_registers(struct rkvdec_ctx *ctx, + struct rkvdec_hevc_run *run) +{ + struct rkvdec_dev *rkvdec = ctx->dev; + const struct v4l2_ctrl_hevc_decode_params *decode_params = run->decode_params; + const struct v4l2_ctrl_hevc_sps *sps = run->sps; + const struct v4l2_ctrl_hevc_slice_params *sl_params = &run->slices_params[0]; + const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb; + struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; + dma_addr_t priv_start_addr = hevc_ctx->priv_tbl.dma; + const struct v4l2_pix_format_mplane *dst_fmt; + struct vb2_v4l2_buffer *src_buf = run->base.bufs.src; + struct vb2_v4l2_buffer *dst_buf = run->base.bufs.dst; + const struct v4l2_format *f; + dma_addr_t rlc_addr; + dma_addr_t refer_addr; + u32 rlc_len; + u32 hor_virstride; + u32 ver_virstride; + u32 y_virstride; + u32 yuv_virstride = 0; + u32 offset; + dma_addr_t dst_addr; + u32 reg, i; + + reg = RKVDEC_MODE(RKVDEC_MODE_HEVC); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_SYSCTRL); + + f = &ctx->decoded_fmt; + dst_fmt = &f->fmt.pix_mp; + hor_virstride = dst_fmt->plane_fmt[0].bytesperline; + ver_virstride = dst_fmt->height; + y_virstride = hor_virstride * ver_virstride; + + if (sps->chroma_format_idc == 0) + yuv_virstride = y_virstride; + else if (sps->chroma_format_idc == 1) + yuv_virstride = y_virstride + y_virstride / 2; + else if (sps->chroma_format_idc == 2) + yuv_virstride = 2 * y_virstride; + + reg = RKVDEC_Y_HOR_VIRSTRIDE(hor_virstride / 16) | + RKVDEC_UV_HOR_VIRSTRIDE(hor_virstride / 16) | + RKVDEC_SLICE_NUM_LOWBITS(run->num_slices); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_PICPAR); + + /* config rlc base address */ + rlc_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + writel_relaxed(rlc_addr, rkvdec->regs + RKVDEC_REG_STRM_RLC_BASE); + + rlc_len = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + reg = RKVDEC_STRM_LEN(round_up(rlc_len, 16) + 64); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_STRM_LEN); + + /* config cabac table */ + offset = offsetof(struct rkvdec_hevc_priv_tbl, cabac_table); + writel_relaxed(priv_start_addr + offset, + rkvdec->regs + RKVDEC_REG_CABACTBL_PROB_BASE); + + /* config output base address */ + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); + writel_relaxed(dst_addr, rkvdec->regs + RKVDEC_REG_DECOUT_BASE); + + reg = RKVDEC_Y_VIRSTRIDE(y_virstride / 16); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_Y_VIRSTRIDE); + + reg = RKVDEC_YUV_VIRSTRIDE(yuv_virstride / 16); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_YUV_VIRSTRIDE); + + /* config ref pic address */ + for (i = 0; i < 15; i++) { + struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i); + + if (i < 4 && decode_params->num_active_dpb_entries) { + reg = GENMASK(decode_params->num_active_dpb_entries - 1, 0); + reg = (reg >> (i * 4)) & 0xf; + } else { + reg = 0; + } + + refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0); + writel_relaxed(refer_addr | reg, + rkvdec->regs + RKVDEC_REG_H264_BASE_REFER(i)); + + reg = RKVDEC_POC_REFER(i < decode_params->num_active_dpb_entries ? + dpb[i].pic_order_cnt_val : 0); + writel_relaxed(reg, + rkvdec->regs + RKVDEC_REG_H264_POC_REFER0(i)); + } + + reg = RKVDEC_CUR_POC(sl_params->slice_pic_order_cnt); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0); + + /* config hw pps address */ + offset = offsetof(struct rkvdec_hevc_priv_tbl, param_set); + writel_relaxed(priv_start_addr + offset, + rkvdec->regs + RKVDEC_REG_PPS_BASE); + + /* config hw rps address */ + offset = offsetof(struct rkvdec_hevc_priv_tbl, rps); + writel_relaxed(priv_start_addr + offset, + rkvdec->regs + RKVDEC_REG_RPS_BASE); + + reg = RKVDEC_AXI_DDR_RDATA(0); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_RDATA); + + reg = RKVDEC_AXI_DDR_WDATA(0); + writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_AXI_DDR_WDATA); +} + +#define RKVDEC_HEVC_MAX_DEPTH_IN_BYTES 2 + +static int rkvdec_hevc_adjust_fmt(struct rkvdec_ctx *ctx, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *fmt = &f->fmt.pix_mp; + + fmt->num_planes = 1; + if (!fmt->plane_fmt[0].sizeimage) + fmt->plane_fmt[0].sizeimage = fmt->width * fmt->height * + RKVDEC_HEVC_MAX_DEPTH_IN_BYTES; + return 0; +} + +static enum rkvdec_image_fmt rkvdec_hevc_get_image_fmt(struct rkvdec_ctx *ctx, + struct v4l2_ctrl *ctrl) +{ + const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps; + + if (ctrl->id != V4L2_CID_STATELESS_HEVC_SPS) + return RKVDEC_IMG_FMT_ANY; + + if (sps->bit_depth_luma_minus8 == 0) { + if (sps->chroma_format_idc == 2) + return RKVDEC_IMG_FMT_422_8BIT; + else + return RKVDEC_IMG_FMT_420_8BIT; + } else if (sps->bit_depth_luma_minus8 == 2) { + if (sps->chroma_format_idc == 2) + return RKVDEC_IMG_FMT_422_10BIT; + else + return RKVDEC_IMG_FMT_420_10BIT; + } + + return RKVDEC_IMG_FMT_ANY; +} + +static int rkvdec_hevc_validate_sps(struct rkvdec_ctx *ctx, + const struct v4l2_ctrl_hevc_sps *sps) +{ + if (sps->chroma_format_idc > 1) + /* Only 4:0:0 and 4:2:0 are supported */ + return -EINVAL; + if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) + /* Luma and chroma bit depth mismatch */ + return -EINVAL; + if (sps->bit_depth_luma_minus8 != 0 && sps->bit_depth_luma_minus8 != 2) + /* Only 8-bit and 10-bit is supported */ + return -EINVAL; + + if (sps->pic_width_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.width || + sps->pic_height_in_luma_samples > ctx->coded_fmt.fmt.pix_mp.height) + return -EINVAL; + + return 0; +} + +static int rkvdec_hevc_start(struct rkvdec_ctx *ctx) +{ + struct rkvdec_dev *rkvdec = ctx->dev; + struct rkvdec_hevc_priv_tbl *priv_tbl; + struct rkvdec_hevc_ctx *hevc_ctx; + + hevc_ctx = kzalloc(sizeof(*hevc_ctx), GFP_KERNEL); + if (!hevc_ctx) + return -ENOMEM; + + priv_tbl = dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), + &hevc_ctx->priv_tbl.dma, GFP_KERNEL); + if (!priv_tbl) { + kfree(hevc_ctx); + return -ENOMEM; + } + + hevc_ctx->priv_tbl.size = sizeof(*priv_tbl); + hevc_ctx->priv_tbl.cpu = priv_tbl; + memcpy(priv_tbl->cabac_table, rkvdec_hevc_cabac_table, + sizeof(rkvdec_hevc_cabac_table)); + + ctx->priv = hevc_ctx; + return 0; +} + +static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx) +{ + struct rkvdec_hevc_ctx *hevc_ctx = ctx->priv; + struct rkvdec_dev *rkvdec = ctx->dev; + + dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size, + hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma); + kfree(hevc_ctx); +} + +static void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, + struct rkvdec_hevc_run *run) +{ + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_STATELESS_HEVC_DECODE_PARAMS); + run->decode_params = ctrl ? ctrl->p_cur.p : NULL; + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_STATELESS_HEVC_SLICE_PARAMS); + run->slices_params = ctrl ? ctrl->p_cur.p : NULL; + run->num_slices = ctrl ? ctrl->new_elems : 0; + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_STATELESS_HEVC_SPS); + run->sps = ctrl ? ctrl->p_cur.p : NULL; + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_STATELESS_HEVC_PPS); + run->pps = ctrl ? ctrl->p_cur.p : NULL; + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_STATELESS_HEVC_SCALING_MATRIX); + run->scaling_matrix = ctrl ? ctrl->p_cur.p : NULL; + + rkvdec_run_preamble(ctx, &run->base); +} + +static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) +{ + struct rkvdec_dev *rkvdec = ctx->dev; + struct rkvdec_hevc_run run; + u32 reg; + + rkvdec_hevc_run_preamble(ctx, &run); + + assemble_hw_scaling_list(ctx, &run); + assemble_hw_pps(ctx, &run); + assemble_sw_rps(ctx, &run); + config_registers(ctx, &run); + + rkvdec_run_postamble(ctx, &run.base); + + schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); + + writel(0, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN); + writel(0, rkvdec->regs + RKVDEC_REG_H264_ERR_E); + writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); + writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); + + if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS) + rkvdec_quirks_disable_qos(ctx); + + /* Start decoding! */ + reg = (run.pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) ? + 0 : RKVDEC_WR_DDR_ALIGN_EN; + writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | + RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E | reg, + rkvdec->regs + RKVDEC_REG_INTERRUPT); + + return 0; +} + +static int rkvdec_hevc_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) +{ + if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) + return rkvdec_hevc_validate_sps(ctx, ctrl->p_new.p_hevc_sps); + + return 0; +} + +const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops = { + .adjust_fmt = rkvdec_hevc_adjust_fmt, + .start = rkvdec_hevc_start, + .stop = rkvdec_hevc_stop, + .run = rkvdec_hevc_run, + .try_ctrl = rkvdec_hevc_try_ctrl, + .get_image_fmt = rkvdec_hevc_get_image_fmt, +}; diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h index 15b9bee92016..c627b6b6f53a 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-regs.h @@ -28,6 +28,7 @@ #define RKVDEC_SOFTRST_EN_P BIT(20) #define RKVDEC_FORCE_SOFTRESET_VALID BIT(21) #define RKVDEC_SOFTRESET_RDY BIT(22) +#define RKVDEC_WR_DDR_ALIGN_EN BIT(23) #define RKVDEC_REG_SYSCTRL 0x008 #define RKVDEC_IN_ENDIAN BIT(0) @@ -43,6 +44,7 @@ #define RKVDEC_RLC_MODE BIT(11) #define RKVDEC_STRM_START_BIT(x) (((x) & 0x7f) << 12) #define RKVDEC_MODE(x) (((x) & 0x03) << 20) +#define RKVDEC_MODE_HEVC 0 #define RKVDEC_MODE_H264 1 #define RKVDEC_MODE_VP9 2 #define RKVDEC_RPS_MODE BIT(24) @@ -217,6 +219,8 @@ #define RKVDEC_REG_H264_ERR_E 0x134 #define RKVDEC_H264_ERR_EN_HIGHBITS(x) ((x) & 0x3fffffff) +#define RKVDEC_REG_QOS_CTRL 0x18C + #define RKVDEC_REG_PREF_LUMA_CACHE_COMMAND 0x410 #define RKVDEC_REG_PREF_CHR_CACHE_COMMAND 0x450 diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c index 0e7e16f20eeb..b4bf01e839ef 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c @@ -824,6 +824,10 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx) writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); writel(0xe, rkvdec->regs + RKVDEC_REG_STRMD_ERR_EN); + + if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS) + rkvdec_quirks_disable_qos(ctx); + /* Start decoding! */ writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E, diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index d707088ec0dc..5af9aa5ab353 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -14,6 +14,7 @@ #include <linux/iommu.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -158,6 +159,67 @@ static const struct v4l2_ctrl_ops rkvdec_ctrl_ops = { .s_ctrl = rkvdec_s_ctrl, }; +static const struct rkvdec_ctrl_desc rkvdec_hevc_ctrl_descs[] = { + { + .cfg.id = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS, + .cfg.flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY, + .cfg.type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, + .cfg.dims = { 600 }, + }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_SPS, + .cfg.ops = &rkvdec_ctrl_ops, + }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_PPS, + }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX, + }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS, + }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_DECODE_MODE, + .cfg.min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, + .cfg.max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, + .cfg.def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED, + }, + { + .cfg.id = V4L2_CID_STATELESS_HEVC_START_CODE, + .cfg.min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, + .cfg.def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, + .cfg.max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B, + }, + { + .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + .cfg.min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .cfg.max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .cfg.def = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + }, + { + .cfg.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + .cfg.min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .cfg.max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + }, +}; + +static const struct rkvdec_ctrls rkvdec_hevc_ctrls = { + .ctrls = rkvdec_hevc_ctrl_descs, + .num_ctrls = ARRAY_SIZE(rkvdec_hevc_ctrl_descs), +}; + +static const struct rkvdec_decoded_fmt_desc rkvdec_hevc_decoded_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .image_fmt = RKVDEC_IMG_FMT_420_8BIT, + }, + { + .fourcc = V4L2_PIX_FMT_NV15, + .image_fmt = RKVDEC_IMG_FMT_420_10BIT, + }, +}; + static const struct rkvdec_ctrl_desc rkvdec_h264_ctrl_descs[] = { { .cfg.id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, @@ -253,6 +315,22 @@ static const struct rkvdec_decoded_fmt_desc rkvdec_vp9_decoded_fmts[] = { static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { { + .fourcc = V4L2_PIX_FMT_HEVC_SLICE, + .frmsize = { + .min_width = 64, + .max_width = 4096, + .step_width = 64, + .min_height = 64, + .max_height = 2304, + .step_height = 16, + }, + .ctrls = &rkvdec_hevc_ctrls, + .ops = &rkvdec_hevc_fmt_ops, + .num_decoded_fmts = ARRAY_SIZE(rkvdec_hevc_decoded_fmts), + .decoded_fmts = rkvdec_hevc_decoded_fmts, + .capability = RKVDEC_CAPABILITY_HEVC, + }, + { .fourcc = V4L2_PIX_FMT_H264_SLICE, .frmsize = { .min_width = 64, @@ -267,6 +345,7 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_decoded_fmts), .decoded_fmts = rkvdec_h264_decoded_fmts, .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF, + .capability = RKVDEC_CAPABILITY_H264, }, { .fourcc = V4L2_PIX_FMT_VP9_FRAME, @@ -282,16 +361,40 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { .ops = &rkvdec_vp9_fmt_ops, .num_decoded_fmts = ARRAY_SIZE(rkvdec_vp9_decoded_fmts), .decoded_fmts = rkvdec_vp9_decoded_fmts, + .capability = RKVDEC_CAPABILITY_VP9, } }; +static bool rkvdec_is_capable(struct rkvdec_ctx *ctx, unsigned int capability) +{ + return (ctx->dev->variant->capabilities & capability) == capability; +} + +static const struct rkvdec_coded_fmt_desc * +rkvdec_enum_coded_fmt_desc(struct rkvdec_ctx *ctx, int index) +{ + int fmt_idx = -1; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) { + if (!rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability)) + continue; + fmt_idx++; + if (index == fmt_idx) + return &rkvdec_coded_fmts[i]; + } + + return NULL; +} + static const struct rkvdec_coded_fmt_desc * -rkvdec_find_coded_fmt_desc(u32 fourcc) +rkvdec_find_coded_fmt_desc(struct rkvdec_ctx *ctx, u32 fourcc) { unsigned int i; for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) { - if (rkvdec_coded_fmts[i].fourcc == fourcc) + if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability) && + rkvdec_coded_fmts[i].fourcc == fourcc) return &rkvdec_coded_fmts[i]; } @@ -302,7 +405,7 @@ static void rkvdec_reset_coded_fmt(struct rkvdec_ctx *ctx) { struct v4l2_format *f = &ctx->coded_fmt; - ctx->coded_fmt_desc = &rkvdec_coded_fmts[0]; + ctx->coded_fmt_desc = rkvdec_enum_coded_fmt_desc(ctx, 0); rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->fourcc); f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; @@ -316,21 +419,22 @@ static void rkvdec_reset_coded_fmt(struct rkvdec_ctx *ctx) static int rkvdec_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - const struct rkvdec_coded_fmt_desc *fmt; + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); + const struct rkvdec_coded_fmt_desc *desc; if (fsize->index != 0) return -EINVAL; - fmt = rkvdec_find_coded_fmt_desc(fsize->pixel_format); - if (!fmt) + desc = rkvdec_find_coded_fmt_desc(ctx, fsize->pixel_format); + if (!desc) return -EINVAL; fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; fsize->stepwise.min_width = 1; - fsize->stepwise.max_width = fmt->frmsize.max_width; + fsize->stepwise.max_width = desc->frmsize.max_width; fsize->stepwise.step_width = 1; fsize->stepwise.min_height = 1; - fsize->stepwise.max_height = fmt->frmsize.max_height; + fsize->stepwise.max_height = desc->frmsize.max_height; fsize->stepwise.step_height = 1; return 0; @@ -354,7 +458,7 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); const struct rkvdec_coded_fmt_desc *coded_desc; /* @@ -387,13 +491,13 @@ static int rkvdec_try_output_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); const struct rkvdec_coded_fmt_desc *desc; - desc = rkvdec_find_coded_fmt_desc(pix_mp->pixelformat); + desc = rkvdec_find_coded_fmt_desc(ctx, pix_mp->pixelformat); if (!desc) { - pix_mp->pixelformat = rkvdec_coded_fmts[0].fourcc; - desc = &rkvdec_coded_fmts[0]; + desc = rkvdec_enum_coded_fmt_desc(ctx, 0); + pix_mp->pixelformat = desc->fourcc; } v4l2_apply_frmsize_constraints(&pix_mp->width, @@ -418,7 +522,7 @@ static int rkvdec_try_output_fmt(struct file *file, void *priv, static int rkvdec_s_capture_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); struct vb2_queue *vq; int ret; @@ -439,7 +543,7 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv, static int rkvdec_s_output_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; const struct rkvdec_coded_fmt_desc *desc; struct v4l2_format *cap_fmt; @@ -470,7 +574,7 @@ static int rkvdec_s_output_fmt(struct file *file, void *priv, if (ret) return ret; - desc = rkvdec_find_coded_fmt_desc(f->fmt.pix_mp.pixelformat); + desc = rkvdec_find_coded_fmt_desc(ctx, f->fmt.pix_mp.pixelformat); if (!desc) return -EINVAL; ctx->coded_fmt_desc = desc; @@ -504,7 +608,7 @@ static int rkvdec_s_output_fmt(struct file *file, void *priv, static int rkvdec_g_output_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); *f = ctx->coded_fmt; return 0; @@ -513,7 +617,7 @@ static int rkvdec_g_output_fmt(struct file *file, void *priv, static int rkvdec_g_capture_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); *f = ctx->decoded_fmt; return 0; @@ -522,17 +626,21 @@ static int rkvdec_g_capture_fmt(struct file *file, void *priv, static int rkvdec_enum_output_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - if (f->index >= ARRAY_SIZE(rkvdec_coded_fmts)) + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); + const struct rkvdec_coded_fmt_desc *desc; + + desc = rkvdec_enum_coded_fmt_desc(ctx, f->index); + if (!desc) return -EINVAL; - f->pixelformat = rkvdec_coded_fmts[f->index].fourcc; + f->pixelformat = desc->fourcc; return 0; } static int rkvdec_enum_capture_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(priv); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(file); u32 fourcc; fourcc = rkvdec_enum_decoded_fmt(ctx, f->index, ctx->image_fmt); @@ -765,7 +873,6 @@ static void rkvdec_job_finish(struct rkvdec_ctx *ctx, { struct rkvdec_dev *rkvdec = ctx->dev; - pm_runtime_mark_last_busy(rkvdec->dev); pm_runtime_put_autosuspend(rkvdec->dev); rkvdec_job_finish_no_pm(ctx, result); } @@ -784,7 +891,7 @@ void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run) if (src_req) v4l2_ctrl_request_setup(src_req, &ctx->ctrl_hdl); - v4l2_m2m_buf_copy_metadata(run->bufs.src, run->bufs.dst, true); + v4l2_m2m_buf_copy_metadata(run->bufs.src, run->bufs.dst); } void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run) @@ -795,6 +902,18 @@ void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run) v4l2_ctrl_request_complete(src_req, &ctx->ctrl_hdl); } +void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx) +{ + struct rkvdec_dev *rkvdec = ctx->dev; + u32 reg; + + /* Set undocumented swreg_block_gating_e field */ + reg = readl(rkvdec->regs + RKVDEC_REG_QOS_CTRL); + reg &= GENMASK(31, 16); + reg |= 0xEFFF; + writel(reg, rkvdec->regs + RKVDEC_REG_QOS_CTRL); +} + static void rkvdec_device_run(void *priv) { struct rkvdec_ctx *ctx = priv; @@ -890,14 +1009,17 @@ static int rkvdec_init_ctrls(struct rkvdec_ctx *ctx) int ret; for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) - nctrls += rkvdec_coded_fmts[i].ctrls->num_ctrls; + if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability)) + nctrls += rkvdec_coded_fmts[i].ctrls->num_ctrls; v4l2_ctrl_handler_init(&ctx->ctrl_hdl, nctrls); for (i = 0; i < ARRAY_SIZE(rkvdec_coded_fmts); i++) { - ret = rkvdec_add_ctrls(ctx, rkvdec_coded_fmts[i].ctrls); - if (ret) - goto err_free_handler; + if (rkvdec_is_capable(ctx, rkvdec_coded_fmts[i].capability)) { + ret = rkvdec_add_ctrls(ctx, rkvdec_coded_fmts[i].ctrls); + if (ret) + goto err_free_handler; + } } ret = v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); @@ -938,8 +1060,7 @@ static int rkvdec_open(struct file *filp) if (ret) goto err_cleanup_m2m_ctx; - filp->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, filp); return 0; @@ -953,9 +1074,9 @@ err_free_ctx: static int rkvdec_release(struct file *filp) { - struct rkvdec_ctx *ctx = fh_to_rkvdec_ctx(filp->private_data); + struct rkvdec_ctx *ctx = file_to_rkvdec_ctx(filp); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, filp); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); v4l2_fh_exit(&ctx->fh); @@ -1111,8 +1232,39 @@ static void rkvdec_watchdog_func(struct work_struct *work) } } +static const struct rkvdec_variant rk3288_rkvdec_variant = { + .num_regs = 68, + .capabilities = RKVDEC_CAPABILITY_HEVC, +}; + +static const struct rkvdec_variant rk3328_rkvdec_variant = { + .num_regs = 109, + .capabilities = RKVDEC_CAPABILITY_HEVC | + RKVDEC_CAPABILITY_H264 | + RKVDEC_CAPABILITY_VP9, + .quirks = RKVDEC_QUIRK_DISABLE_QOS, +}; + +static const struct rkvdec_variant rk3399_rkvdec_variant = { + .num_regs = 78, + .capabilities = RKVDEC_CAPABILITY_HEVC | + RKVDEC_CAPABILITY_H264 | + RKVDEC_CAPABILITY_VP9, +}; + static const struct of_device_id of_rkvdec_match[] = { - { .compatible = "rockchip,rk3399-vdec" }, + { + .compatible = "rockchip,rk3288-vdec", + .data = &rk3288_rkvdec_variant, + }, + { + .compatible = "rockchip,rk3328-vdec", + .data = &rk3328_rkvdec_variant, + }, + { + .compatible = "rockchip,rk3399-vdec", + .data = &rk3399_rkvdec_variant, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, of_rkvdec_match); @@ -1123,16 +1275,22 @@ static const char * const rkvdec_clk_names[] = { static int rkvdec_probe(struct platform_device *pdev) { + const struct rkvdec_variant *variant; struct rkvdec_dev *rkvdec; unsigned int i; int ret, irq; + variant = of_device_get_match_data(&pdev->dev); + if (!variant) + return -EINVAL; + rkvdec = devm_kzalloc(&pdev->dev, sizeof(*rkvdec), GFP_KERNEL); if (!rkvdec) return -ENOMEM; platform_set_drvdata(pdev, rkvdec); rkvdec->dev = &pdev->dev; + rkvdec->variant = variant; mutex_init(&rkvdec->vdev_lock); INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func); @@ -1159,13 +1317,6 @@ static int rkvdec_probe(struct platform_device *pdev) return ret; } - if (iommu_get_domain_for_dev(&pdev->dev)) { - rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev); - - if (!rkvdec->empty_domain) - dev_warn(rkvdec->dev, "cannot alloc new empty domain\n"); - } - vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); irq = platform_get_irq(pdev, 0); @@ -1188,6 +1339,15 @@ static int rkvdec_probe(struct platform_device *pdev) if (ret) goto err_disable_runtime_pm; + if (iommu_get_domain_for_dev(&pdev->dev)) { + rkvdec->empty_domain = iommu_paging_domain_alloc(rkvdec->dev); + + if (IS_ERR(rkvdec->empty_domain)) { + rkvdec->empty_domain = NULL; + dev_warn(rkvdec->dev, "cannot alloc new empty domain\n"); + } + } + return 0; err_disable_runtime_pm: diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h index f6e8bf38add3..566e06fa2b1e 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h @@ -22,6 +22,12 @@ #include <media/videobuf2-core.h> #include <media/videobuf2-dma-contig.h> +#define RKVDEC_CAPABILITY_HEVC BIT(0) +#define RKVDEC_CAPABILITY_H264 BIT(1) +#define RKVDEC_CAPABILITY_VP9 BIT(2) + +#define RKVDEC_QUIRK_DISABLE_QOS BIT(0) + struct rkvdec_ctx; struct rkvdec_ctrl_desc { @@ -63,6 +69,12 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf) base.vb.vb2_buf); } +struct rkvdec_variant { + unsigned int num_regs; + unsigned int capabilities; + unsigned int quirks; +}; + struct rkvdec_coded_fmt_ops { int (*adjust_fmt)(struct rkvdec_ctx *ctx, struct v4l2_format *f); @@ -98,6 +110,7 @@ struct rkvdec_coded_fmt_desc { unsigned int num_decoded_fmts; const struct rkvdec_decoded_fmt_desc *decoded_fmts; u32 subsystem_flags; + unsigned int capability; }; struct rkvdec_dev { @@ -111,6 +124,7 @@ struct rkvdec_dev { struct mutex vdev_lock; /* serializes ioctls */ struct delayed_work watchdog_work; struct iommu_domain *empty_domain; + const struct rkvdec_variant *variant; }; struct rkvdec_ctx { @@ -124,9 +138,9 @@ struct rkvdec_ctx { void *priv; }; -static inline struct rkvdec_ctx *fh_to_rkvdec_ctx(struct v4l2_fh *fh) +static inline struct rkvdec_ctx *file_to_rkvdec_ctx(struct file *filp) { - return container_of(fh, struct rkvdec_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct rkvdec_ctx, fh); } struct rkvdec_aux_buf { @@ -138,7 +152,10 @@ struct rkvdec_aux_buf { void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); +void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx); + extern const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops; +extern const struct rkvdec_coded_fmt_ops rkvdec_hevc_fmt_ops; extern const struct rkvdec_coded_fmt_ops rkvdec_vp9_fmt_ops; #endif /* RKVDEC_H_ */ diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h index b9777e07fb6d..265221abf4dc 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h @@ -85,7 +85,6 @@ enum gsc_yuv_fmt { GSC_CRCB, }; -#define fh_to_ctx(__fh) container_of(__fh, struct gsc_ctx, fh) #define is_rgb(x) (!!((x) & 0x1)) #define is_yuv420(x) (!!((x) & 0x2)) #define is_yuv422(x) (!!((x) & 0x4)) @@ -381,6 +380,11 @@ struct gsc_ctx { enum v4l2_colorspace out_colorspace; }; +static inline struct gsc_ctx *file_to_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct gsc_ctx, fh); +} + void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm); int gsc_register_m2m_device(struct gsc_dev *gsc); void gsc_unregister_m2m_device(struct gsc_dev *gsc); diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c index 4bda1c369c44..722e2531e23f 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c @@ -297,7 +297,7 @@ static int gsc_m2m_enum_fmt(struct file *file, void *priv, static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return gsc_g_fmt_mplane(ctx, f); } @@ -305,7 +305,7 @@ static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh, static int gsc_m2m_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return gsc_try_fmt_mplane(ctx, f); } @@ -313,7 +313,7 @@ static int gsc_m2m_try_fmt_mplane(struct file *file, void *fh, static int gsc_m2m_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); struct vb2_queue *vq; struct gsc_frame *frame; struct v4l2_pix_format_mplane *pix; @@ -359,7 +359,7 @@ static int gsc_m2m_s_fmt_mplane(struct file *file, void *fh, static int gsc_m2m_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *reqbufs) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_dev *gsc = ctx->gsc_dev; u32 max_cnt; @@ -374,35 +374,35 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh, static int gsc_m2m_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *eb) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); } static int gsc_m2m_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); } static int gsc_m2m_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); } static int gsc_m2m_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); } static int gsc_m2m_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); /* The source and target color format need to be set */ if (V4L2_TYPE_IS_OUTPUT(type)) { @@ -418,7 +418,7 @@ static int gsc_m2m_streamon(struct file *file, void *fh, static int gsc_m2m_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) { - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); } @@ -440,8 +440,8 @@ static int is_rectangle_enclosed(struct v4l2_rect *a, struct v4l2_rect *b) static int gsc_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_frame *frame; - struct gsc_ctx *ctx = fh_to_ctx(fh); if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) @@ -478,7 +478,7 @@ static int gsc_m2m_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { struct gsc_frame *frame; - struct gsc_ctx *ctx = fh_to_ctx(fh); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_variant *variant = ctx->gsc_dev->variant; struct v4l2_selection sel = *s; int ret; @@ -625,8 +625,7 @@ static int gsc_m2m_open(struct file *file) /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->gsc_dev = gsc; /* Default color format */ @@ -655,7 +654,7 @@ static int gsc_m2m_open(struct file *file) error_ctrls: gsc_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); error_fh: v4l2_fh_exit(&ctx->fh); kfree(ctx); @@ -666,7 +665,7 @@ unlock: static int gsc_m2m_release(struct file *file) { - struct gsc_ctx *ctx = fh_to_ctx(file->private_data); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_dev *gsc = ctx->gsc_dev; pr_debug("pid: %d, state: 0x%lx, refcnt= %d", @@ -676,7 +675,7 @@ static int gsc_m2m_release(struct file *file) v4l2_m2m_ctx_release(ctx->m2m_ctx); gsc_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); if (--gsc->m2m.refcnt <= 0) @@ -690,7 +689,7 @@ static int gsc_m2m_release(struct file *file) static __poll_t gsc_m2m_poll(struct file *file, struct poll_table_struct *wait) { - struct gsc_ctx *ctx = fh_to_ctx(file->private_data); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_dev *gsc = ctx->gsc_dev; __poll_t ret; @@ -705,7 +704,7 @@ static __poll_t gsc_m2m_poll(struct file *file, static int gsc_m2m_mmap(struct file *file, struct vm_area_struct *vma) { - struct gsc_ctx *ctx = fh_to_ctx(file->private_data); + struct gsc_ctx *ctx = file_to_ctx(file); struct gsc_dev *gsc = ctx->gsc_dev; int ret; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.h b/drivers/media/platform/samsung/exynos4-is/fimc-core.h index 63385152a2ff..c23cbdee7afc 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-core.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.h @@ -496,7 +496,10 @@ struct fimc_ctx { struct fimc_ctrls ctrls; }; -#define fh_to_ctx(__fh) container_of(__fh, struct fimc_ctx, fh) +static inline struct fimc_ctx *file_to_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct fimc_ctx, fh); +} static inline void set_frame_bounds(struct fimc_frame *f, u32 width, u32 height) { diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c index ed7b7ca16f71..0827fdaf455a 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c @@ -996,7 +996,6 @@ static void fimc_is_module_exit(void) module_init(fimc_is_module_init); module_exit(fimc_is_module_exit); -MODULE_ALIAS("platform:" FIMC_IS_DRV_NAME); MODULE_AUTHOR("Younghwan Joo <yhwan.joo@samsung.com>"); MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); MODULE_DESCRIPTION("Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver"); diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 0ce293b0718b..8be20fd32d1c 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -1662,4 +1662,3 @@ static struct platform_driver fimc_lite_driver = { module_platform_driver(fimc_lite_driver); MODULE_DESCRIPTION("Samsung EXYNOS FIMC-LITE (camera host interface) driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" 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 951433c8e92a..562c57f186c6 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c @@ -249,7 +249,7 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv, static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); const struct fimc_frame *frame = ctx_get_frame(ctx, f->type); if (IS_ERR(frame)) @@ -308,7 +308,7 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); return fimc_try_fmt_mplane(ctx, f); } @@ -337,7 +337,7 @@ static void __set_frame_format(struct fimc_frame *frame, static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); struct fimc_dev *fimc = ctx->fimc_dev; const struct fimc_fmt *fmt; struct vb2_queue *vq; @@ -376,7 +376,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, static int fimc_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); const struct fimc_frame *frame; frame = ctx_get_frame(ctx, s->type); @@ -484,7 +484,7 @@ static int fimc_m2m_try_selection(struct fimc_ctx *ctx, static int fimc_m2m_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct fimc_ctx *ctx = fh_to_ctx(fh); + struct fimc_ctx *ctx = file_to_ctx(file); struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_frame *f; int ret; @@ -634,8 +634,7 @@ static int fimc_m2m_open(struct file *file) /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrls.handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); /* Setup the device context for memory-to-memory mode */ ctx->state = FIMC_CTX_M2M; @@ -664,7 +663,7 @@ error_m2m_ctx: v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); error_c: fimc_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); error_fh: v4l2_fh_exit(&ctx->fh); kfree(ctx); @@ -675,7 +674,7 @@ unlock: static int fimc_m2m_release(struct file *file) { - struct fimc_ctx *ctx = fh_to_ctx(file->private_data); + struct fimc_ctx *ctx = file_to_ctx(file); struct fimc_dev *fimc = ctx->fimc_dev; dbg("pid: %d, state: 0x%lx, refcnt= %d", @@ -685,7 +684,7 @@ static int fimc_m2m_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); fimc_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); if (--fimc->m2m.refcnt <= 0) diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c index c781853586fd..bc7087eb761a 100644 --- a/drivers/media/platform/samsung/exynos4-is/media-dev.c +++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c @@ -1333,8 +1333,8 @@ static int fimc_md_register_clk_provider(struct fimc_md *fmd) cp->clks[i] = clk_register(NULL, &camclk->hw); if (IS_ERR(cp->clks[i])) { - dev_err(dev, "failed to register clock: %s (%ld)\n", - init.name, PTR_ERR(cp->clks[i])); + dev_err(dev, "failed to register clock: %s (%pe)\n", + init.name, cp->clks[i]); ret = PTR_ERR(cp->clks[i]); goto err; } @@ -1399,12 +1399,14 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier) mutex_lock(&fmd->media_dev.graph_mutex); ret = fimc_md_create_links(fmd); - if (ret < 0) - goto unlock; + if (ret < 0) { + mutex_unlock(&fmd->media_dev.graph_mutex); + return ret; + } - ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); -unlock: mutex_unlock(&fmd->media_dev.graph_mutex); + + ret = v4l2_device_register_subdev_nodes(&fmd->v4l2_dev); if (ret < 0) return ret; diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c index 3e566b65f417..ed1a1d693293 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c @@ -572,7 +572,7 @@ static int s3c_camif_close(struct file *file) mutex_lock(&camif->lock); - if (vp->owner == file->private_data) { + if (vp->owner == file_to_v4l2_fh(file)) { camif_stop_capture(vp); vb2_queue_release(&vp->vb_queue); vp->owner = NULL; @@ -595,7 +595,7 @@ static __poll_t s3c_camif_poll(struct file *file, __poll_t ret; mutex_lock(&camif->lock); - if (vp->owner && vp->owner != file->private_data) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) ret = EPOLLERR; else ret = vb2_poll(&vp->vb_queue, file, wait); @@ -609,7 +609,7 @@ static int s3c_camif_mmap(struct file *file, struct vm_area_struct *vma) struct camif_vp *vp = video_drvdata(file); int ret; - if (vp->owner && vp->owner != file->private_data) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) ret = -EBUSY; else ret = vb2_mmap(&vp->vb_queue, vma); @@ -791,7 +791,7 @@ static int s3c_camif_vidioc_s_fmt(struct file *file, void *priv, out_frame->rect.top = 0; if (vp->owner == NULL) - vp->owner = priv; + vp->owner = file_to_v4l2_fh(file); pr_debug("%ux%u. payload: %u. fmt: 0x%08x. %d %d. sizeimage: %d. bpl: %d\n", out_frame->f_width, out_frame->f_height, vp->payload, @@ -841,7 +841,7 @@ static int s3c_camif_streamon(struct file *file, void *priv, if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; if (s3c_vp_active(vp)) @@ -872,7 +872,7 @@ static int s3c_camif_streamoff(struct file *file, void *priv, if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; ret = vb2_streamoff(&vp->vb_queue, type); @@ -888,9 +888,9 @@ static int s3c_camif_reqbufs(struct file *file, void *priv, int ret; pr_debug("[vp%d] rb count: %d, owner: %p, priv: %p\n", - vp->id, rb->count, vp->owner, priv); + vp->id, rb->count, vp->owner, file_to_v4l2_fh(file)); - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; if (rb->count) @@ -910,7 +910,7 @@ static int s3c_camif_reqbufs(struct file *file, void *priv, vp->reqbufs_count = rb->count; if (vp->owner == NULL && rb->count > 0) - vp->owner = priv; + vp->owner = file_to_v4l2_fh(file); return ret; } @@ -929,7 +929,7 @@ static int s3c_camif_qbuf(struct file *file, void *priv, pr_debug("[vp%d]\n", vp->id); - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; return vb2_qbuf(&vp->vb_queue, vp->vdev.v4l2_dev->mdev, buf); @@ -942,7 +942,7 @@ static int s3c_camif_dqbuf(struct file *file, void *priv, pr_debug("[vp%d] sequence: %d\n", vp->id, vp->frame_sequence); - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; return vb2_dqbuf(&vp->vb_queue, buf, file->f_flags & O_NONBLOCK); @@ -954,14 +954,14 @@ static int s3c_camif_create_bufs(struct file *file, void *priv, struct camif_vp *vp = video_drvdata(file); int ret; - if (vp->owner && vp->owner != priv) + if (vp->owner && vp->owner != file_to_v4l2_fh(file)) return -EBUSY; create->count = max_t(u32, 1, create->count); ret = vb2_create_bufs(&vp->vb_queue, create); if (!ret && vp->owner == NULL) - vp->owner = priv; + vp->owner = file_to_v4l2_fh(file); return ret; } diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c index ffed16a34493..e765dfcc2830 100644 --- a/drivers/media/platform/samsung/s5p-g2d/g2d.c +++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c @@ -25,7 +25,10 @@ #include "g2d.h" #include "g2d-regs.h" -#define fh2ctx(__fh) container_of(__fh, struct g2d_ctx, fh) +static inline struct g2d_ctx *file2ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct g2d_ctx, fh); +} static struct g2d_fmt formats[] = { { @@ -254,8 +257,7 @@ static int g2d_open(struct file *file) return ret; } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); g2d_setup_ctrls(ctx); @@ -272,13 +274,13 @@ static int g2d_open(struct file *file) static int g2d_release(struct file *file) { struct g2d_dev *dev = video_drvdata(file); - struct g2d_ctx *ctx = fh2ctx(file->private_data); + struct g2d_ctx *ctx = file2ctx(file); mutex_lock(&dev->mutex); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(&dev->mutex); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); v4l2_info(&dev->v4l2_dev, "instance closed\n"); @@ -295,7 +297,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= NUM_FORMATS) return -EINVAL; @@ -303,15 +305,11 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) return 0; } -static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct g2d_ctx *ctx = prv; - struct vb2_queue *vq; + struct g2d_ctx *ctx = file2ctx(file); struct g2d_frame *frm; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; frm = get_frame(ctx, f->type); if (IS_ERR(frm)) return PTR_ERR(frm); @@ -325,7 +323,7 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct g2d_fmt *fmt; enum v4l2_field *field; @@ -355,9 +353,9 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct g2d_ctx *ctx = prv; + struct g2d_ctx *ctx = file2ctx(file); struct g2d_dev *dev = ctx->dev; struct vb2_queue *vq; struct g2d_frame *frm; @@ -366,7 +364,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) /* Adjust all values accordingly to the hardware capabilities * and chosen format. */ - ret = vidioc_try_fmt(file, prv, f); + ret = vidioc_try_fmt(file, priv, f); if (ret) return ret; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); @@ -395,10 +393,10 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_g_selection(struct file *file, void *prv, +static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct g2d_ctx *ctx = prv; + struct g2d_ctx *ctx = file2ctx(file); struct g2d_frame *f; f = get_frame(ctx, s->type); @@ -445,10 +443,10 @@ static int vidioc_g_selection(struct file *file, void *prv, return 0; } -static int vidioc_try_selection(struct file *file, void *prv, +static int vidioc_try_selection(struct file *file, void *priv, const struct v4l2_selection *s) { - struct g2d_ctx *ctx = prv; + struct g2d_ctx *ctx = file2ctx(file); struct g2d_dev *dev = ctx->dev; struct g2d_frame *f; @@ -473,14 +471,14 @@ static int vidioc_try_selection(struct file *file, void *prv, return 0; } -static int vidioc_s_selection(struct file *file, void *prv, +static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct g2d_ctx *ctx = prv; + struct g2d_ctx *ctx = file2ctx(file); struct g2d_frame *f; int ret; - ret = vidioc_try_selection(file, prv, s); + ret = vidioc_try_selection(file, priv, s); if (ret) return ret; f = get_frame(ctx, s->type); diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index ac4cf269456a..ff28482759ec 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -580,9 +580,9 @@ static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c) return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler); } -static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh) +static inline struct s5p_jpeg_ctx *file_to_ctx(struct file *filp) { - return container_of(fh, struct s5p_jpeg_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct s5p_jpeg_ctx, fh); } static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx) @@ -965,8 +965,7 @@ static int s5p_jpeg_open(struct file *file) v4l2_fh_init(&ctx->fh, vfd); /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->jpeg = jpeg; if (vfd == jpeg->vfd_encoder) { @@ -1001,7 +1000,7 @@ static int s5p_jpeg_open(struct file *file) return 0; error: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); mutex_unlock(&jpeg->lock); free: @@ -1011,13 +1010,13 @@ free: static int s5p_jpeg_release(struct file *file) { + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); struct s5p_jpeg *jpeg = video_drvdata(file); - struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); mutex_lock(&jpeg->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); mutex_unlock(&jpeg->lock); @@ -1249,7 +1248,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result, static int s5p_jpeg_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); if (ctx->mode == S5P_JPEG_ENCODE) { strscpy(cap->driver, S5P_JPEG_M2M_NAME, @@ -1297,7 +1296,7 @@ static int enum_fmt(struct s5p_jpeg_ctx *ctx, static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); if (ctx->mode == S5P_JPEG_ENCODE) return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, @@ -1310,7 +1309,7 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); if (ctx->mode == S5P_JPEG_ENCODE) return enum_fmt(ctx, sjpeg_formats, SJPEG_NUM_FORMATS, f, @@ -1333,14 +1332,9 @@ static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx, static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct vb2_queue *vq; struct s5p_jpeg_q_data *q_data = NULL; struct v4l2_pix_format *pix = &f->fmt.pix; - struct s5p_jpeg_ctx *ct = fh_to_ctx(priv); - - vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; + struct s5p_jpeg_ctx *ct = file_to_ctx(file); if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && ct->mode == S5P_JPEG_DECODE && !ct->hdr_parsed) @@ -1476,7 +1470,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt, static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); struct v4l2_pix_format *pix = &f->fmt.pix; struct s5p_jpeg_fmt *fmt; int ret; @@ -1535,7 +1529,7 @@ exit: static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); struct s5p_jpeg_fmt *fmt; fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat, @@ -1594,8 +1588,6 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f) unsigned int f_type; vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; q_data = get_q_data(ct, f->type); BUG_ON(q_data == NULL); @@ -1682,7 +1674,7 @@ static int s5p_jpeg_s_fmt_vid_cap(struct file *file, void *priv, if (ret) return ret; - return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); + return s5p_jpeg_s_fmt(file_to_ctx(file), f); } static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, @@ -1694,7 +1686,7 @@ static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv, if (ret) return ret; - return s5p_jpeg_s_fmt(fh_to_ctx(priv), f); + return s5p_jpeg_s_fmt(file_to_ctx(file), f); } static int s5p_jpeg_subscribe_event(struct v4l2_fh *fh, @@ -1791,7 +1783,7 @@ static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx, static int s5p_jpeg_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -1828,7 +1820,7 @@ static int s5p_jpeg_g_selection(struct file *file, void *priv, static int s5p_jpeg_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_jpeg_ctx *ctx = file_to_ctx(file); struct v4l2_rect *rect = &s->r; int ret = -EINVAL; diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index 73fdcd362265..4948d734eb02 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -801,8 +801,7 @@ static int s5p_mfc_open(struct file *file) } init_waitqueue_head(&ctx->queue); v4l2_fh_init(&ctx->fh, vdev); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ctx->dev = dev; INIT_LIST_HEAD(&ctx->src_queue); INIT_LIST_HEAD(&ctx->dst_queue); @@ -877,7 +876,7 @@ static int s5p_mfc_open(struct file *file) /* Init videobuf2 queue for CAPTURE */ q = &ctx->vq_dst; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->drv_priv = &ctx->fh; + q->drv_priv = ctx; q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; @@ -904,7 +903,7 @@ static int s5p_mfc_open(struct file *file) /* Init videobuf2 queue for OUTPUT */ q = &ctx->vq_src; q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - q->drv_priv = &ctx->fh; + q->drv_priv = ctx; q->lock = &dev->mfc_mutex; if (vdev == dev->vfd_dec) { q->io_modes = VB2_MMAP; @@ -956,7 +955,7 @@ err_ctrls_setup: err_bad_node: dev->ctx[ctx->num] = NULL; err_no_ctx: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); err_alloc: @@ -970,7 +969,7 @@ err_enter: /* Release MFC context */ static int s5p_mfc_release(struct file *file) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; /* if dev is null, do cleanup that doesn't need dev */ @@ -1011,7 +1010,7 @@ static int s5p_mfc_release(struct file *file) if (dev) dev->ctx[ctx->num] = NULL; s5p_mfc_dec_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); /* vdev is gone if dev is null */ if (dev) v4l2_fh_exit(&ctx->fh); @@ -1027,7 +1026,7 @@ static int s5p_mfc_release(struct file *file) static __poll_t s5p_mfc_poll(struct file *file, struct poll_table_struct *wait) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; struct vb2_queue *src_q, *dst_q; struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; @@ -1078,7 +1077,7 @@ end: /* Mmap */ static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; int ret; diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c index 47bc3014b5d8..f7c682fca645 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c @@ -14,8 +14,7 @@ #include "s5p_mfc_opr.h" #include "s5p_mfc_cmd_v6.h" -static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, - const struct s5p_mfc_cmd_args *args) +static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd) { mfc_debug(2, "Issue the command: %d\n", cmd); @@ -31,7 +30,6 @@ static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, static int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) { - struct s5p_mfc_cmd_args h2r_args; const struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; int ret; @@ -41,33 +39,23 @@ static int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) mfc_write(dev, dev->ctx_buf.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); mfc_write(dev, buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE_V6); - return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SYS_INIT_V6, - &h2r_args); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SYS_INIT_V6); } static int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) { - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SLEEP_V6, - &h2r_args); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SLEEP_V6); } static int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) { - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_WAKEUP_V6, - &h2r_args); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_WAKEUP_V6); } /* Open a new instance and get its number */ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; int codec_type; mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); @@ -129,23 +117,20 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); mfc_write(dev, 0, S5P_FIMV_D_CRC_CTRL_V6); /* no crc */ - return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6, - &h2r_args); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6); } /* Close instance */ static int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; int ret = 0; dev->curr_ctx = ctx->num; if (ctx->state != MFCINST_FREE) { mfc_write(dev, ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); ret = s5p_mfc_cmd_host2risc_v6(dev, - S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6, - &h2r_args); + S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6); } else { ret = -EINVAL; } @@ -153,9 +138,15 @@ static int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) return ret; } +static int s5p_mfc_cmd_host2risc_v6_args(struct s5p_mfc_dev *dev, int cmd, + const struct s5p_mfc_cmd_args *ignored) +{ + return s5p_mfc_cmd_host2risc_v6(dev, cmd); +} + /* Initialize cmd function pointers for MFC v6 */ static const struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { - .cmd_host2risc = s5p_mfc_cmd_host2risc_v6, + .cmd_host2risc = s5p_mfc_cmd_host2risc_v6_args, .sys_init_cmd = s5p_mfc_sys_init_cmd_v6, .sleep_cmd = s5p_mfc_sleep_cmd_v6, .wakeup_cmd = s5p_mfc_wakeup_cmd_v6, diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h index 86c316c1ff8f..58dc1768082c 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h @@ -767,7 +767,11 @@ struct mfc_control { #define s5p_mfc_hw_call(f, op, args...) \ ((f && f->op) ? f->op(args) : (typeof(f->op(args)))(-ENODEV)) -#define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) +static inline struct s5p_mfc_ctx *file_to_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct s5p_mfc_ctx, fh); +} + #define ctrl_to_ctx(__ctrl) \ container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler) 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 3efbc3367906..afd28beabfde 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -330,7 +330,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return 0; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, false); @@ -345,7 +345,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, /* Get format */ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct v4l2_pix_format_mplane *pix_mp; mfc_debug_enter(); @@ -442,7 +442,7 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret = 0; struct v4l2_pix_format_mplane *pix_mp; const struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; @@ -598,7 +598,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (reqbufs->memory != V4L2_MEMORY_MMAP) { mfc_debug(2, "Only V4L2_MEMORY_MMAP is supported\n"); @@ -619,7 +619,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret; int i; @@ -647,7 +647,7 @@ static int vidioc_querybuf(struct file *file, void *priv, /* Queue a buffer */ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (ctx->state == MFCINST_ERROR) { mfc_err("Call on QBUF after unrecoverable error\n"); @@ -666,7 +666,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret; if (ctx->state == MFCINST_ERROR) { @@ -695,7 +695,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) static int vidioc_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *eb) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_expbuf(&ctx->vq_src, eb); @@ -708,7 +708,7 @@ static int vidioc_expbuf(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret = -EINVAL; mfc_debug_enter(); @@ -724,7 +724,7 @@ static int vidioc_streamon(struct file *file, void *priv, static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_streamoff(&ctx->vq_src, type); @@ -801,7 +801,7 @@ static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = { static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *s) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; u32 left, right, top, bottom; u32 width, height; @@ -856,7 +856,7 @@ static int vidioc_g_selection(struct file *file, void *priv, static int vidioc_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *buf; unsigned long flags; @@ -937,7 +937,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *plane_count, unsigned int psize[], struct device *alloc_devs[]) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); struct s5p_mfc_dev *dev = ctx->dev; const struct v4l2_format_info *format; @@ -1006,7 +1006,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); unsigned int i; if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -1068,7 +1068,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(q); struct s5p_mfc_dev *dev = ctx->dev; v4l2_ctrl_handler_setup(&ctx->ctrl_handler); @@ -1085,7 +1085,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) static void s5p_mfc_stop_streaming(struct vb2_queue *q) { unsigned long flags; - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(q); struct s5p_mfc_dev *dev = ctx->dev; int aborted = 0; @@ -1130,7 +1130,7 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) static void s5p_mfc_buf_queue(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); struct s5p_mfc_dev *dev = ctx->dev; unsigned long flags; struct s5p_mfc_buf *mfc_buf; 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 6c603dcd5664..3f8701e5614f 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -1375,7 +1375,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return -EINVAL; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, false); @@ -1389,8 +1389,8 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + struct s5p_mfc_ctx *ctx = file_to_ctx(file); mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state); if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -1472,8 +1472,8 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; int ret = 0; @@ -1531,7 +1531,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret = 0; /* if memory is not mmp or userptr or dmabuf return error */ @@ -1601,7 +1601,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); int ret = 0; /* if memory is not mmp or userptr or dmabuf return error */ @@ -1636,7 +1636,7 @@ static int vidioc_querybuf(struct file *file, void *priv, /* Queue a buffer */ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (ctx->state == MFCINST_ERROR) { mfc_err("Call on QBUF after unrecoverable error\n"); @@ -1657,10 +1657,10 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) /* Dequeue a buffer */ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { + struct s5p_mfc_ctx *ctx = file_to_ctx(file); const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret; if (ctx->state == MFCINST_ERROR) { @@ -1685,7 +1685,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) static int vidioc_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *eb) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_expbuf(&ctx->vq_src, eb); @@ -1698,7 +1698,7 @@ static int vidioc_expbuf(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_streamon(&ctx->vq_src, type); @@ -1711,7 +1711,7 @@ static int vidioc_streamon(struct file *file, void *priv, static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) return vb2_streamoff(&ctx->vq_src, type); @@ -2284,7 +2284,7 @@ static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = { static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { ctx->enc_params.rc_framerate_num = @@ -2301,7 +2301,7 @@ static int vidioc_s_parm(struct file *file, void *priv, static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { a->parm.output.timeperframe.denominator = @@ -2318,7 +2318,7 @@ static int vidioc_g_parm(struct file *file, void *priv, static int vidioc_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *cmd) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_ctx *ctx = file_to_ctx(file); struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *buf; unsigned long flags; @@ -2418,7 +2418,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, unsigned int *plane_count, unsigned int psize[], struct device *alloc_devs[]) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); struct s5p_mfc_dev *dev = ctx->dev; if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -2477,7 +2477,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); unsigned int i; int ret; @@ -2516,7 +2516,7 @@ static int s5p_mfc_buf_init(struct vb2_buffer *vb) static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); int ret; if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -2557,7 +2557,7 @@ static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) { - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(q); struct s5p_mfc_dev *dev = ctx->dev; if (IS_MFCV6_PLUS(dev) && @@ -2588,7 +2588,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) static void s5p_mfc_stop_streaming(struct vb2_queue *q) { unsigned long flags; - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(q); struct s5p_mfc_dev *dev = ctx->dev; if ((ctx->state == MFCINST_FINISHING || @@ -2617,7 +2617,7 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q) static void s5p_mfc_buf_queue(struct vb2_buffer *vb) { struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_ctx *ctx = vb2_get_drv_priv(vq); struct s5p_mfc_dev *dev = ctx->dev; unsigned long flags; struct s5p_mfc_buf *mfc_buf; diff --git a/drivers/media/platform/st/Makefile b/drivers/media/platform/st/Makefile index a1f75b2a8225..615a93d62662 100644 --- a/drivers/media/platform/st/Makefile +++ b/drivers/media/platform/st/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += sti/bdisp/ -obj-y += sti/c8sectpfe/ obj-y += sti/delta/ obj-y += sti/hva/ obj-y += stm32/ diff --git a/drivers/media/platform/st/sti/Kconfig b/drivers/media/platform/st/sti/Kconfig index 60068e8b47b8..91ca0950ff73 100644 --- a/drivers/media/platform/st/sti/Kconfig +++ b/drivers/media/platform/st/sti/Kconfig @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only source "drivers/media/platform/st/sti/bdisp/Kconfig" -source "drivers/media/platform/st/sti/c8sectpfe/Kconfig" source "drivers/media/platform/st/sti/delta/Kconfig" source "drivers/media/platform/st/sti/hva/Kconfig" diff --git a/drivers/media/platform/st/sti/Makefile b/drivers/media/platform/st/sti/Makefile index f9ce8169b040..3328d50fb6cf 100644 --- a/drivers/media/platform/st/sti/Makefile +++ b/drivers/media/platform/st/sti/Makefile @@ -1,6 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y += bdisp/ -obj-y += c8sectpfe/ obj-y += delta/ obj-y += hva/ obj-y += stm32/ diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c index 1eb934490c0b..56169b70652d 100644 --- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c @@ -33,7 +33,10 @@ #define BDISP_MIN_H 1 #define BDISP_MAX_H 8191 -#define fh_to_ctx(__fh) container_of(__fh, struct bdisp_ctx, fh) +static inline struct bdisp_ctx *file_to_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct bdisp_ctx, fh); +} enum bdisp_dev_flags { ST_M2M_OPEN, /* Driver opened */ @@ -603,8 +606,7 @@ static int bdisp_open(struct file *file) /* Use separate control handler per file handle */ ctx->fh.ctrl_handler = &ctx->ctrl_handler; - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); /* Default format */ ctx->src = bdisp_dflt_fmt; @@ -630,7 +632,7 @@ static int bdisp_open(struct file *file) error_ctrls: bdisp_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); error_fh: v4l2_fh_exit(&ctx->fh); bdisp_hw_free_nodes(ctx); @@ -644,7 +646,7 @@ unlock: static int bdisp_release(struct file *file) { - struct bdisp_ctx *ctx = fh_to_ctx(file->private_data); + struct bdisp_ctx *ctx = file_to_ctx(file); struct bdisp_dev *bdisp = ctx->bdisp_dev; dev_dbg(bdisp->dev, "%s\n", __func__); @@ -655,7 +657,7 @@ static int bdisp_release(struct file *file) bdisp_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); if (--bdisp->m2m.refcnt <= 0) @@ -682,7 +684,7 @@ static const struct v4l2_file_operations bdisp_fops = { static int bdisp_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); struct bdisp_dev *bdisp = ctx->bdisp_dev; strscpy(cap->driver, bdisp->pdev->name, sizeof(cap->driver)); @@ -694,7 +696,7 @@ static int bdisp_querycap(struct file *file, void *fh, static int bdisp_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); const struct bdisp_fmt *fmt; if (f->index >= ARRAY_SIZE(bdisp_formats)) @@ -714,7 +716,7 @@ static int bdisp_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) static int bdisp_g_fmt(struct file *file, void *fh, struct v4l2_format *f) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); struct v4l2_pix_format *pix; struct bdisp_frame *frame = ctx_get_frame(ctx, f->type); @@ -738,7 +740,7 @@ static int bdisp_g_fmt(struct file *file, void *fh, struct v4l2_format *f) static int bdisp_try_fmt(struct file *file, void *fh, struct v4l2_format *f) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); struct v4l2_pix_format *pix = &f->fmt.pix; const struct bdisp_fmt *format; u32 in_w, in_h; @@ -788,7 +790,7 @@ static int bdisp_try_fmt(struct file *file, void *fh, struct v4l2_format *f) static int bdisp_s_fmt(struct file *file, void *fh, struct v4l2_format *f) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); struct vb2_queue *vq; struct bdisp_frame *frame; struct v4l2_pix_format *pix; @@ -841,8 +843,8 @@ static int bdisp_s_fmt(struct file *file, void *fh, struct v4l2_format *f) static int bdisp_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct bdisp_ctx *ctx = file_to_ctx(file); struct bdisp_frame *frame; - struct bdisp_ctx *ctx = fh_to_ctx(fh); frame = ctx_get_frame(ctx, s->type); if (IS_ERR(frame)) { @@ -919,8 +921,8 @@ static int is_rect_enclosed(struct v4l2_rect *a, struct v4l2_rect *b) static int bdisp_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { + struct bdisp_ctx *ctx = file_to_ctx(file); struct bdisp_frame *frame; - struct bdisp_ctx *ctx = fh_to_ctx(fh); struct v4l2_rect *in, out; bool valid = false; @@ -997,7 +999,7 @@ static int bdisp_s_selection(struct file *file, void *fh, static int bdisp_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct bdisp_ctx *ctx = fh_to_ctx(fh); + struct bdisp_ctx *ctx = file_to_ctx(file); if ((type == V4L2_BUF_TYPE_VIDEO_OUTPUT) && !bdisp_ctx_state_is_set(BDISP_SRC_FMT, ctx)) { diff --git a/drivers/media/platform/st/sti/c8sectpfe/Kconfig b/drivers/media/platform/st/sti/c8sectpfe/Kconfig deleted file mode 100644 index 01c33d9c9ec3..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config DVB_C8SECTPFE - tristate "STMicroelectronics C8SECTPFE DVB support" - depends on DVB_PLATFORM_DRIVERS - depends on PINCTRL && DVB_CORE && I2C - depends on ARCH_STI || ARCH_MULTIPLATFORM || COMPILE_TEST - select FW_LOADER - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT - - help - This adds support for DVB front-end cards connected - to TS inputs of STiH407/410 SoC. - - The driver currently supports C8SECTPFE's TS input block, - memdma engine, and HW PID filtering. - - Supported DVB front-end cards are: - - STMicroelectronics DVB-T B2100A (STV0367 + TDA18212) - - STMicroelectronics DVB-S/S2 STV0903 + STV6110 + LNBP24 board - - To compile this driver as a module, choose M here: the - module will be called c8sectpfe. diff --git a/drivers/media/platform/st/sti/c8sectpfe/Makefile b/drivers/media/platform/st/sti/c8sectpfe/Makefile deleted file mode 100644 index 99425137ee0a..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -c8sectpfe-y += c8sectpfe-core.o c8sectpfe-common.o c8sectpfe-dvb.o - -ifneq ($(CONFIG_DEBUG_FS),) -c8sectpfe-y += c8sectpfe-debugfs.o -endif - -obj-$(CONFIG_DVB_C8SECTPFE) += c8sectpfe.o - -ccflags-y += -I $(srctree)/drivers/media/dvb-frontends/ -ccflags-y += -I $(srctree)/drivers/media/tuners/ diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.c deleted file mode 100644 index 5df67da25525..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.c +++ /dev/null @@ -1,262 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * c8sectpfe-common.c - C8SECTPFE STi DVB driver - * - * Copyright (c) STMicroelectronics 2015 - * - * Author: Peter Griffin <peter.griffin@linaro.org> - * - */ -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/dvb/dmx.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/ioport.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/time.h> -#include <linux/wait.h> - -#include <media/dmxdev.h> -#include <media/dvbdev.h> -#include <media/dvb_demux.h> -#include <media/dvb_frontend.h> -#include <media/dvb_net.h> - -#include "c8sectpfe-common.h" -#include "c8sectpfe-core.h" -#include "c8sectpfe-dvb.h" - -static int register_dvb(struct stdemux *demux, struct dvb_adapter *adap, - void *start_feed, void *stop_feed, - struct c8sectpfei *fei) -{ - int result; - - demux->dvb_demux.dmx.capabilities = DMX_TS_FILTERING | - DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - - demux->dvb_demux.priv = demux; - demux->dvb_demux.filternum = C8SECTPFE_MAXCHANNEL; - demux->dvb_demux.feednum = C8SECTPFE_MAXCHANNEL; - - demux->dvb_demux.start_feed = start_feed; - demux->dvb_demux.stop_feed = stop_feed; - demux->dvb_demux.write_to_decoder = NULL; - - result = dvb_dmx_init(&demux->dvb_demux); - if (result < 0) { - dev_err(fei->dev, "dvb_dmx_init failed (errno = %d)\n", - result); - goto err_dmx; - } - - demux->dmxdev.filternum = demux->dvb_demux.filternum; - demux->dmxdev.demux = &demux->dvb_demux.dmx; - demux->dmxdev.capabilities = 0; - - result = dvb_dmxdev_init(&demux->dmxdev, adap); - if (result < 0) { - dev_err(fei->dev, "dvb_dmxdev_init failed (errno = %d)\n", - result); - - goto err_dmxdev; - } - - demux->hw_frontend.source = DMX_FRONTEND_0 + demux->tsin_index; - - result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx, - &demux->hw_frontend); - if (result < 0) { - dev_err(fei->dev, "add_frontend failed (errno = %d)\n", result); - goto err_fe_hw; - } - - demux->mem_frontend.source = DMX_MEMORY_FE; - result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx, - &demux->mem_frontend); - if (result < 0) { - dev_err(fei->dev, "add_frontend failed (%d)\n", result); - goto err_fe_mem; - } - - result = demux->dvb_demux.dmx.connect_frontend(&demux->dvb_demux.dmx, - &demux->hw_frontend); - if (result < 0) { - dev_err(fei->dev, "connect_frontend (%d)\n", result); - goto err_fe_con; - } - - return 0; - -err_fe_con: - demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx, - &demux->mem_frontend); -err_fe_mem: - demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx, - &demux->hw_frontend); -err_fe_hw: - dvb_dmxdev_release(&demux->dmxdev); -err_dmxdev: - dvb_dmx_release(&demux->dvb_demux); -err_dmx: - return result; - -} - -static void unregister_dvb(struct stdemux *demux) -{ - - demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx, - &demux->mem_frontend); - - demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx, - &demux->hw_frontend); - - dvb_dmxdev_release(&demux->dmxdev); - - dvb_dmx_release(&demux->dvb_demux); -} - -static struct c8sectpfe *c8sectpfe_create(struct c8sectpfei *fei, - void *start_feed, - void *stop_feed) -{ - struct c8sectpfe *c8sectpfe; - int result; - int i, j; - - short int ids[] = { -1 }; - - c8sectpfe = kzalloc(sizeof(struct c8sectpfe), GFP_KERNEL); - if (!c8sectpfe) - goto err1; - - mutex_init(&c8sectpfe->lock); - - c8sectpfe->device = fei->dev; - - result = dvb_register_adapter(&c8sectpfe->adapter, "STi c8sectpfe", - THIS_MODULE, fei->dev, ids); - if (result < 0) { - dev_err(fei->dev, "dvb_register_adapter failed (errno = %d)\n", - result); - goto err2; - } - - c8sectpfe->adapter.priv = fei; - - for (i = 0; i < fei->tsin_count; i++) { - - c8sectpfe->demux[i].tsin_index = i; - c8sectpfe->demux[i].c8sectpfei = fei; - - result = register_dvb(&c8sectpfe->demux[i], &c8sectpfe->adapter, - start_feed, stop_feed, fei); - if (result < 0) { - dev_err(fei->dev, - "register_dvb feed=%d failed (errno = %d)\n", - result, i); - - /* we take a all or nothing approach */ - for (j = 0; j < i; j++) - unregister_dvb(&c8sectpfe->demux[j]); - goto err3; - } - } - - c8sectpfe->num_feeds = fei->tsin_count; - - return c8sectpfe; -err3: - dvb_unregister_adapter(&c8sectpfe->adapter); -err2: - kfree(c8sectpfe); -err1: - return NULL; -}; - -static void c8sectpfe_delete(struct c8sectpfe *c8sectpfe) -{ - int i; - - if (!c8sectpfe) - return; - - for (i = 0; i < c8sectpfe->num_feeds; i++) - unregister_dvb(&c8sectpfe->demux[i]); - - dvb_unregister_adapter(&c8sectpfe->adapter); - - kfree(c8sectpfe); -}; - -void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe, - struct c8sectpfei *fei) -{ - int n; - struct channel_info *tsin; - - for (n = 0; n < fei->tsin_count; n++) { - - tsin = fei->channel_data[n]; - - if (tsin) { - if (tsin->frontend) { - dvb_unregister_frontend(tsin->frontend); - dvb_frontend_detach(tsin->frontend); - } - - i2c_put_adapter(tsin->i2c_adapter); - - if (tsin->i2c_client) { - module_put(tsin->i2c_client->dev.driver->owner); - i2c_unregister_device(tsin->i2c_client); - } - } - } - - c8sectpfe_delete(c8sectpfe); -}; - -int c8sectpfe_tuner_register_frontend(struct c8sectpfe **c8sectpfe, - struct c8sectpfei *fei, - void *start_feed, - void *stop_feed) -{ - struct channel_info *tsin; - struct dvb_frontend *frontend; - int n, res; - - *c8sectpfe = c8sectpfe_create(fei, start_feed, stop_feed); - if (!*c8sectpfe) - return -ENOMEM; - - for (n = 0; n < fei->tsin_count; n++) { - tsin = fei->channel_data[n]; - - res = c8sectpfe_frontend_attach(&frontend, *c8sectpfe, tsin, n); - if (res) - goto err; - - res = dvb_register_frontend(&c8sectpfe[0]->adapter, frontend); - if (res < 0) { - dev_err(fei->dev, "dvb_register_frontend failed (%d)\n", - res); - goto err; - } - - tsin->frontend = frontend; - } - - return 0; - -err: - c8sectpfe_tuner_unregister_frontend(*c8sectpfe, fei); - return res; -} diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h deleted file mode 100644 index f8d97841f366..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * c8sectpfe-common.h - C8SECTPFE STi DVB driver - * - * Copyright (c) STMicroelectronics 2015 - * - * Author: Peter Griffin <peter.griffin@linaro.org> - * - */ -#ifndef _C8SECTPFE_COMMON_H_ -#define _C8SECTPFE_COMMON_H_ - -#include <linux/dvb/dmx.h> -#include <linux/dvb/frontend.h> -#include <linux/gpio.h> - -#include <media/dmxdev.h> -#include <media/dvb_demux.h> -#include <media/dvb_frontend.h> -#include <media/dvb_net.h> - -/* Maximum number of channels */ -#define C8SECTPFE_MAXADAPTER (4) -#define C8SECTPFE_MAXCHANNEL 64 -#define STPTI_MAXCHANNEL 64 - -#define MAX_INPUTBLOCKS 7 - -struct c8sectpfe; -struct stdemux; - -struct stdemux { - struct dvb_demux dvb_demux; - struct dmxdev dmxdev; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - int tsin_index; - int running_feed_count; - struct c8sectpfei *c8sectpfei; -}; - -struct c8sectpfe { - struct stdemux demux[MAX_INPUTBLOCKS]; - struct mutex lock; - struct dvb_adapter adapter; - struct device *device; - int mapping; - int num_feeds; -}; - -/* Channel registration */ -int c8sectpfe_tuner_register_frontend(struct c8sectpfe **c8sectpfe, - struct c8sectpfei *fei, - void *start_feed, - void *stop_feed); - -void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe, - struct c8sectpfei *fei); - -#endif diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c deleted file mode 100644 index 89bd15a4d26a..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c +++ /dev/null @@ -1,1158 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * c8sectpfe-core.c - C8SECTPFE STi DVB driver - * - * Copyright (c) STMicroelectronics 2015 - * - * Author:Peter Bennett <peter.bennett@st.com> - * Peter Griffin <peter.griffin@linaro.org> - * - */ -#include <linux/atomic.h> -#include <linux/clk.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/dvb/dmx.h> -#include <linux/dvb/frontend.h> -#include <linux/err.h> -#include <linux/errno.h> -#include <linux/firmware.h> -#include <linux/gpio/consumer.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of_platform.h> -#include <linux/pinctrl/consumer.h> -#include <linux/pinctrl/pinctrl.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/time.h> -#include <linux/usb.h> -#include <linux/wait.h> - -#include "c8sectpfe-common.h" -#include "c8sectpfe-core.h" -#include "c8sectpfe-debugfs.h" - -#include <media/dmxdev.h> -#include <media/dvb_demux.h> -#include <media/dvb_frontend.h> -#include <media/dvb_net.h> - -#define FIRMWARE_MEMDMA "pti_memdma_h407.elf" -MODULE_FIRMWARE(FIRMWARE_MEMDMA); - -#define PID_TABLE_SIZE 1024 -#define POLL_MSECS 50 - -static int load_c8sectpfe_fw(struct c8sectpfei *fei); - -#define TS_PKT_SIZE 188 -#define HEADER_SIZE (4) -#define PACKET_SIZE (TS_PKT_SIZE+HEADER_SIZE) - -#define FEI_ALIGNMENT (32) -/* hw requires minimum of 8*PACKET_SIZE and padded to 8byte boundary */ -#define FEI_BUFFER_SIZE (8*PACKET_SIZE*340) - -#define FIFO_LEN 1024 - -static void c8sectpfe_timer_interrupt(struct timer_list *t) -{ - struct c8sectpfei *fei = timer_container_of(fei, t, timer); - struct channel_info *channel; - int chan_num; - - /* iterate through input block channels */ - for (chan_num = 0; chan_num < fei->tsin_count; chan_num++) { - channel = fei->channel_data[chan_num]; - - /* is this descriptor initialised and TP enabled */ - if (channel->irec && readl(channel->irec + DMA_PRDS_TPENABLE)) - queue_work(system_bh_wq, &channel->bh_work); - } - - fei->timer.expires = jiffies + msecs_to_jiffies(POLL_MSECS); - add_timer(&fei->timer); -} - -static void channel_swdemux_bh_work(struct work_struct *t) -{ - struct channel_info *channel = from_work(channel, t, bh_work); - struct c8sectpfei *fei; - unsigned long wp, rp; - int pos, num_packets, n, size; - u8 *buf; - - if (unlikely(!channel || !channel->irec)) - return; - - fei = channel->fei; - - wp = readl(channel->irec + DMA_PRDS_BUSWP_TP(0)); - rp = readl(channel->irec + DMA_PRDS_BUSRP_TP(0)); - - pos = rp - channel->back_buffer_busaddr; - - /* has it wrapped */ - if (wp < rp) - wp = channel->back_buffer_busaddr + FEI_BUFFER_SIZE; - - size = wp - rp; - num_packets = size / PACKET_SIZE; - - /* manage cache so data is visible to CPU */ - dma_sync_single_for_cpu(fei->dev, - rp, - size, - DMA_FROM_DEVICE); - - buf = channel->back_buffer_aligned; - - dev_dbg(fei->dev, - "chan=%d channel=%p num_packets = %d, buf = %p, pos = 0x%x\n\trp=0x%lx, wp=0x%lx\n", - channel->tsin_id, channel, num_packets, buf, pos, rp, wp); - - for (n = 0; n < num_packets; n++) { - dvb_dmx_swfilter_packets( - &fei->c8sectpfe[0]-> - demux[channel->demux_mapping].dvb_demux, - &buf[pos], 1); - - pos += PACKET_SIZE; - } - - /* advance the read pointer */ - if (wp == (channel->back_buffer_busaddr + FEI_BUFFER_SIZE)) - writel(channel->back_buffer_busaddr, channel->irec + - DMA_PRDS_BUSRP_TP(0)); - else - writel(wp, channel->irec + DMA_PRDS_BUSRP_TP(0)); -} - -static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - struct dvb_demux *demux = dvbdmxfeed->demux; - struct stdemux *stdemux = demux->priv; - struct c8sectpfei *fei = stdemux->c8sectpfei; - struct channel_info *channel; - u32 tmp; - unsigned long *bitmap; - int ret; - - switch (dvbdmxfeed->type) { - case DMX_TYPE_TS: - break; - case DMX_TYPE_SEC: - break; - default: - dev_err(fei->dev, "%s:%d Error bailing\n" - , __func__, __LINE__); - return -EINVAL; - } - - if (dvbdmxfeed->type == DMX_TYPE_TS) { - switch (dvbdmxfeed->pes_type) { - case DMX_PES_VIDEO: - case DMX_PES_AUDIO: - case DMX_PES_TELETEXT: - case DMX_PES_PCR: - case DMX_PES_OTHER: - break; - default: - dev_err(fei->dev, "%s:%d Error bailing\n" - , __func__, __LINE__); - return -EINVAL; - } - } - - if (!atomic_read(&fei->fw_loaded)) { - ret = load_c8sectpfe_fw(fei); - if (ret) - return ret; - } - - mutex_lock(&fei->lock); - - channel = fei->channel_data[stdemux->tsin_index]; - - bitmap = channel->pid_buffer_aligned; - - /* 8192 is a special PID */ - if (dvbdmxfeed->pid == 8192) { - tmp = readl(fei->io + C8SECTPFE_IB_PID_SET(channel->tsin_id)); - tmp &= ~C8SECTPFE_PID_ENABLE; - writel(tmp, fei->io + C8SECTPFE_IB_PID_SET(channel->tsin_id)); - - } else { - bitmap_set(bitmap, dvbdmxfeed->pid, 1); - } - - /* manage cache so PID bitmap is visible to HW */ - dma_sync_single_for_device(fei->dev, - channel->pid_buffer_busaddr, - PID_TABLE_SIZE, - DMA_TO_DEVICE); - - channel->active = 1; - - if (fei->global_feed_count == 0) { - fei->timer.expires = jiffies + - msecs_to_jiffies(msecs_to_jiffies(POLL_MSECS)); - - add_timer(&fei->timer); - } - - if (stdemux->running_feed_count == 0) { - - dev_dbg(fei->dev, "Starting channel=%p\n", channel); - - INIT_WORK(&channel->bh_work, channel_swdemux_bh_work); - - /* Reset the internal inputblock sram pointers */ - writel(channel->fifo, - fei->io + C8SECTPFE_IB_BUFF_STRT(channel->tsin_id)); - writel(channel->fifo + FIFO_LEN - 1, - fei->io + C8SECTPFE_IB_BUFF_END(channel->tsin_id)); - - writel(channel->fifo, - fei->io + C8SECTPFE_IB_READ_PNT(channel->tsin_id)); - writel(channel->fifo, - fei->io + C8SECTPFE_IB_WRT_PNT(channel->tsin_id)); - - - /* reset read / write memdma ptrs for this channel */ - writel(channel->back_buffer_busaddr, channel->irec + - DMA_PRDS_BUSBASE_TP(0)); - - tmp = channel->back_buffer_busaddr + FEI_BUFFER_SIZE - 1; - writel(tmp, channel->irec + DMA_PRDS_BUSTOP_TP(0)); - - writel(channel->back_buffer_busaddr, channel->irec + - DMA_PRDS_BUSWP_TP(0)); - - /* Issue a reset and enable InputBlock */ - writel(C8SECTPFE_SYS_ENABLE | C8SECTPFE_SYS_RESET - , fei->io + C8SECTPFE_IB_SYS(channel->tsin_id)); - - /* and enable the tp */ - writel(0x1, channel->irec + DMA_PRDS_TPENABLE); - - dev_dbg(fei->dev, "%s:%d Starting DMA feed on stdemux=%p\n" - , __func__, __LINE__, stdemux); - } - - stdemux->running_feed_count++; - fei->global_feed_count++; - - mutex_unlock(&fei->lock); - - return 0; -} - -static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed) -{ - - struct dvb_demux *demux = dvbdmxfeed->demux; - struct stdemux *stdemux = demux->priv; - struct c8sectpfei *fei = stdemux->c8sectpfei; - struct channel_info *channel; - int idlereq; - u32 tmp; - int ret; - unsigned long *bitmap; - - if (!atomic_read(&fei->fw_loaded)) { - ret = load_c8sectpfe_fw(fei); - if (ret) - return ret; - } - - mutex_lock(&fei->lock); - - channel = fei->channel_data[stdemux->tsin_index]; - - bitmap = channel->pid_buffer_aligned; - - if (dvbdmxfeed->pid == 8192) { - tmp = readl(fei->io + C8SECTPFE_IB_PID_SET(channel->tsin_id)); - tmp |= C8SECTPFE_PID_ENABLE; - writel(tmp, fei->io + C8SECTPFE_IB_PID_SET(channel->tsin_id)); - } else { - bitmap_clear(bitmap, dvbdmxfeed->pid, 1); - } - - /* manage cache so data is visible to HW */ - dma_sync_single_for_device(fei->dev, - channel->pid_buffer_busaddr, - PID_TABLE_SIZE, - DMA_TO_DEVICE); - - if (--stdemux->running_feed_count == 0) { - - channel = fei->channel_data[stdemux->tsin_index]; - - /* TP re-configuration on page 168 of functional spec */ - - /* disable IB (prevents more TS data going to memdma) */ - writel(0, fei->io + C8SECTPFE_IB_SYS(channel->tsin_id)); - - /* disable this channels descriptor */ - writel(0, channel->irec + DMA_PRDS_TPENABLE); - - disable_work_sync(&channel->bh_work); - - /* now request memdma channel goes idle */ - idlereq = (1 << channel->tsin_id) | IDLEREQ; - writel(idlereq, fei->io + DMA_IDLE_REQ); - - /* wait for idle irq handler to signal completion */ - ret = wait_for_completion_timeout(&channel->idle_completion, - msecs_to_jiffies(100)); - - if (ret == 0) - dev_warn(fei->dev, - "Timeout waiting for idle irq on tsin%d\n", - channel->tsin_id); - - reinit_completion(&channel->idle_completion); - - /* reset read / write ptrs for this channel */ - - writel(channel->back_buffer_busaddr, - channel->irec + DMA_PRDS_BUSBASE_TP(0)); - - tmp = channel->back_buffer_busaddr + FEI_BUFFER_SIZE - 1; - writel(tmp, channel->irec + DMA_PRDS_BUSTOP_TP(0)); - - writel(channel->back_buffer_busaddr, - channel->irec + DMA_PRDS_BUSWP_TP(0)); - - dev_dbg(fei->dev, - "%s:%d stopping DMA feed on stdemux=%p channel=%d\n", - __func__, __LINE__, stdemux, channel->tsin_id); - - /* turn off all PIDS in the bitmap */ - memset(channel->pid_buffer_aligned, 0, PID_TABLE_SIZE); - - /* manage cache so data is visible to HW */ - dma_sync_single_for_device(fei->dev, - channel->pid_buffer_busaddr, - PID_TABLE_SIZE, - DMA_TO_DEVICE); - - channel->active = 0; - } - - if (--fei->global_feed_count == 0) { - dev_dbg(fei->dev, "%s:%d global_feed_count=%d\n" - , __func__, __LINE__, fei->global_feed_count); - - timer_delete(&fei->timer); - } - - mutex_unlock(&fei->lock); - - return 0; -} - -static struct channel_info *find_channel(struct c8sectpfei *fei, int tsin_num) -{ - int i; - - for (i = 0; i < C8SECTPFE_MAX_TSIN_CHAN; i++) { - if (!fei->channel_data[i]) - continue; - - if (fei->channel_data[i]->tsin_id == tsin_num) - return fei->channel_data[i]; - } - - return NULL; -} - -static void c8sectpfe_getconfig(struct c8sectpfei *fei) -{ - struct c8sectpfe_hw *hw = &fei->hw_stats; - - hw->num_ib = readl(fei->io + SYS_CFG_NUM_IB); - hw->num_mib = readl(fei->io + SYS_CFG_NUM_MIB); - hw->num_swts = readl(fei->io + SYS_CFG_NUM_SWTS); - hw->num_tsout = readl(fei->io + SYS_CFG_NUM_TSOUT); - hw->num_ccsc = readl(fei->io + SYS_CFG_NUM_CCSC); - hw->num_ram = readl(fei->io + SYS_CFG_NUM_RAM); - hw->num_tp = readl(fei->io + SYS_CFG_NUM_TP); - - dev_info(fei->dev, "C8SECTPFE hw supports the following:\n"); - dev_info(fei->dev, "Input Blocks: %d\n", hw->num_ib); - dev_info(fei->dev, "Merged Input Blocks: %d\n", hw->num_mib); - dev_info(fei->dev, "Software Transport Stream Inputs: %d\n" - , hw->num_swts); - dev_info(fei->dev, "Transport Stream Output: %d\n", hw->num_tsout); - dev_info(fei->dev, "Cable Card Converter: %d\n", hw->num_ccsc); - dev_info(fei->dev, "RAMs supported by C8SECTPFE: %d\n", hw->num_ram); - dev_info(fei->dev, "Tango TPs supported by C8SECTPFE: %d\n" - , hw->num_tp); -} - -static irqreturn_t c8sectpfe_idle_irq_handler(int irq, void *priv) -{ - struct c8sectpfei *fei = priv; - struct channel_info *chan; - int bit; - unsigned long tmp = readl(fei->io + DMA_IDLE_REQ); - - /* page 168 of functional spec: Clear the idle request - by writing 0 to the C8SECTPFE_DMA_IDLE_REQ register. */ - - /* signal idle completion */ - for_each_set_bit(bit, &tmp, fei->hw_stats.num_ib) { - - chan = find_channel(fei, bit); - - if (chan) - complete(&chan->idle_completion); - } - - writel(0, fei->io + DMA_IDLE_REQ); - - return IRQ_HANDLED; -} - - -static void free_input_block(struct c8sectpfei *fei, struct channel_info *tsin) -{ - if (!fei || !tsin) - return; - - if (tsin->back_buffer_busaddr) - if (!dma_mapping_error(fei->dev, tsin->back_buffer_busaddr)) - dma_unmap_single(fei->dev, tsin->back_buffer_busaddr, - FEI_BUFFER_SIZE, DMA_BIDIRECTIONAL); - - kfree(tsin->back_buffer_start); - - if (tsin->pid_buffer_busaddr) - if (!dma_mapping_error(fei->dev, tsin->pid_buffer_busaddr)) - dma_unmap_single(fei->dev, tsin->pid_buffer_busaddr, - PID_TABLE_SIZE, DMA_BIDIRECTIONAL); - - kfree(tsin->pid_buffer_start); -} - -#define MAX_NAME 20 - -static int configure_memdma_and_inputblock(struct c8sectpfei *fei, - struct channel_info *tsin) -{ - int ret; - u32 tmp; - char tsin_pin_name[MAX_NAME]; - - if (!fei || !tsin) - return -EINVAL; - - dev_dbg(fei->dev, "%s:%d Configuring channel=%p tsin=%d\n" - , __func__, __LINE__, tsin, tsin->tsin_id); - - init_completion(&tsin->idle_completion); - - tsin->back_buffer_start = kzalloc(FEI_BUFFER_SIZE + FEI_ALIGNMENT, GFP_KERNEL); - if (!tsin->back_buffer_start) { - ret = -ENOMEM; - goto err_unmap; - } - - /* Ensure backbuffer is 32byte aligned */ - tsin->back_buffer_aligned = tsin->back_buffer_start + FEI_ALIGNMENT; - - tsin->back_buffer_aligned = PTR_ALIGN(tsin->back_buffer_aligned, FEI_ALIGNMENT); - - tsin->back_buffer_busaddr = dma_map_single(fei->dev, - tsin->back_buffer_aligned, - FEI_BUFFER_SIZE, - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(fei->dev, tsin->back_buffer_busaddr)) { - dev_err(fei->dev, "failed to map back_buffer\n"); - ret = -EFAULT; - goto err_unmap; - } - - /* - * The pid buffer can be configured (in hw) for byte or bit - * per pid. By powers of deduction we conclude stih407 family - * is configured (at SoC design stage) for bit per pid. - */ - tsin->pid_buffer_start = kzalloc(PID_TABLE_SIZE + PID_TABLE_SIZE, GFP_KERNEL); - if (!tsin->pid_buffer_start) { - ret = -ENOMEM; - goto err_unmap; - } - - /* - * PID buffer needs to be aligned to size of the pid table - * which at bit per pid is 1024 bytes (8192 pids / 8). - * PIDF_BASE register enforces this alignment when writing - * the register. - */ - - tsin->pid_buffer_aligned = tsin->pid_buffer_start + PID_TABLE_SIZE; - - tsin->pid_buffer_aligned = PTR_ALIGN(tsin->pid_buffer_aligned, PID_TABLE_SIZE); - - tsin->pid_buffer_busaddr = dma_map_single(fei->dev, - tsin->pid_buffer_aligned, - PID_TABLE_SIZE, - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(fei->dev, tsin->pid_buffer_busaddr)) { - dev_err(fei->dev, "failed to map pid_bitmap\n"); - ret = -EFAULT; - goto err_unmap; - } - - /* manage cache so pid bitmap is visible to HW */ - dma_sync_single_for_device(fei->dev, - tsin->pid_buffer_busaddr, - PID_TABLE_SIZE, - DMA_TO_DEVICE); - - snprintf(tsin_pin_name, MAX_NAME, "tsin%d-%s", tsin->tsin_id, - (tsin->serial_not_parallel ? "serial" : "parallel")); - - tsin->pstate = pinctrl_lookup_state(fei->pinctrl, tsin_pin_name); - if (IS_ERR(tsin->pstate)) { - dev_err(fei->dev, "%s: pinctrl_lookup_state couldn't find %s state\n" - , __func__, tsin_pin_name); - ret = PTR_ERR(tsin->pstate); - goto err_unmap; - } - - ret = pinctrl_select_state(fei->pinctrl, tsin->pstate); - - if (ret) { - dev_err(fei->dev, "%s: pinctrl_select_state failed\n" - , __func__); - goto err_unmap; - } - - /* Enable this input block */ - tmp = readl(fei->io + SYS_INPUT_CLKEN); - tmp |= BIT(tsin->tsin_id); - writel(tmp, fei->io + SYS_INPUT_CLKEN); - - if (tsin->serial_not_parallel) - tmp |= C8SECTPFE_SERIAL_NOT_PARALLEL; - - if (tsin->invert_ts_clk) - tmp |= C8SECTPFE_INVERT_TSCLK; - - if (tsin->async_not_sync) - tmp |= C8SECTPFE_ASYNC_NOT_SYNC; - - tmp |= C8SECTPFE_ALIGN_BYTE_SOP | C8SECTPFE_BYTE_ENDIANNESS_MSB; - - writel(tmp, fei->io + C8SECTPFE_IB_IP_FMT_CFG(tsin->tsin_id)); - - writel(C8SECTPFE_SYNC(0x9) | - C8SECTPFE_DROP(0x9) | - C8SECTPFE_TOKEN(0x47), - fei->io + C8SECTPFE_IB_SYNCLCKDRP_CFG(tsin->tsin_id)); - - writel(TS_PKT_SIZE, fei->io + C8SECTPFE_IB_PKT_LEN(tsin->tsin_id)); - - /* Place the FIFO's at the end of the irec descriptors */ - - tsin->fifo = (tsin->tsin_id * FIFO_LEN); - - writel(tsin->fifo, fei->io + C8SECTPFE_IB_BUFF_STRT(tsin->tsin_id)); - writel(tsin->fifo + FIFO_LEN - 1, - fei->io + C8SECTPFE_IB_BUFF_END(tsin->tsin_id)); - - writel(tsin->fifo, fei->io + C8SECTPFE_IB_READ_PNT(tsin->tsin_id)); - writel(tsin->fifo, fei->io + C8SECTPFE_IB_WRT_PNT(tsin->tsin_id)); - - writel(tsin->pid_buffer_busaddr, - fei->io + PIDF_BASE(tsin->tsin_id)); - - dev_dbg(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n", - tsin->tsin_id, readl(fei->io + PIDF_BASE(tsin->tsin_id)), - &tsin->pid_buffer_busaddr); - - /* Configure and enable HW PID filtering */ - - /* - * The PID value is created by assembling the first 8 bytes of - * the TS packet into a 64-bit word in big-endian format. A - * slice of that 64-bit word is taken from - * (PID_OFFSET+PID_NUM_BITS-1) to PID_OFFSET. - */ - tmp = (C8SECTPFE_PID_ENABLE | C8SECTPFE_PID_NUMBITS(13) - | C8SECTPFE_PID_OFFSET(40)); - - writel(tmp, fei->io + C8SECTPFE_IB_PID_SET(tsin->tsin_id)); - - dev_dbg(fei->dev, "chan=%d setting wp: %d, rp: %d, buf: %d-%d\n", - tsin->tsin_id, - readl(fei->io + C8SECTPFE_IB_WRT_PNT(tsin->tsin_id)), - readl(fei->io + C8SECTPFE_IB_READ_PNT(tsin->tsin_id)), - readl(fei->io + C8SECTPFE_IB_BUFF_STRT(tsin->tsin_id)), - readl(fei->io + C8SECTPFE_IB_BUFF_END(tsin->tsin_id))); - - /* Get base addpress of pointer record block from DMEM */ - tsin->irec = fei->io + DMA_MEMDMA_OFFSET + DMA_DMEM_OFFSET + - readl(fei->io + DMA_PTRREC_BASE); - - /* fill out pointer record data structure */ - - /* advance pointer record block to our channel */ - tsin->irec += (tsin->tsin_id * DMA_PRDS_SIZE); - - writel(tsin->fifo, tsin->irec + DMA_PRDS_MEMBASE); - - writel(tsin->fifo + FIFO_LEN - 1, tsin->irec + DMA_PRDS_MEMTOP); - - writel((188 + 7)&~7, tsin->irec + DMA_PRDS_PKTSIZE); - - writel(0x1, tsin->irec + DMA_PRDS_TPENABLE); - - /* read/write pointers with physical bus address */ - - writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSBASE_TP(0)); - - tmp = tsin->back_buffer_busaddr + FEI_BUFFER_SIZE - 1; - writel(tmp, tsin->irec + DMA_PRDS_BUSTOP_TP(0)); - - writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSWP_TP(0)); - writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSRP_TP(0)); - - /* initialize bh work */ - INIT_WORK(&tsin->bh_work, channel_swdemux_bh_work); - - return 0; - -err_unmap: - free_input_block(fei, tsin); - return ret; -} - -static irqreturn_t c8sectpfe_error_irq_handler(int irq, void *priv) -{ - struct c8sectpfei *fei = priv; - - dev_err(fei->dev, "%s: error handling not yet implemented\n" - , __func__); - - /* - * TODO FIXME we should detect some error conditions here - * and ideally do something about them! - */ - - return IRQ_HANDLED; -} - -static int c8sectpfe_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - struct c8sectpfei *fei; - struct resource *res; - int ret, index = 0; - struct channel_info *tsin; - - /* Allocate the c8sectpfei structure */ - fei = devm_kzalloc(dev, sizeof(struct c8sectpfei), GFP_KERNEL); - if (!fei) - return -ENOMEM; - - fei->dev = dev; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "c8sectpfe"); - fei->io = devm_ioremap_resource(dev, res); - if (IS_ERR(fei->io)) - return PTR_ERR(fei->io); - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "c8sectpfe-ram"); - fei->sram = devm_ioremap_resource(dev, res); - if (IS_ERR(fei->sram)) - return PTR_ERR(fei->sram); - - fei->sram_size = resource_size(res); - - fei->idle_irq = platform_get_irq_byname(pdev, "c8sectpfe-idle-irq"); - if (fei->idle_irq < 0) - return fei->idle_irq; - - fei->error_irq = platform_get_irq_byname(pdev, "c8sectpfe-error-irq"); - if (fei->error_irq < 0) - return fei->error_irq; - - platform_set_drvdata(pdev, fei); - - fei->c8sectpfeclk = devm_clk_get_enabled(dev, "c8sectpfe"); - if (IS_ERR(fei->c8sectpfeclk)) { - dev_err(dev, "Failed to enable c8sectpfe clock\n"); - return PTR_ERR(fei->c8sectpfeclk); - } - - /* to save power disable all IP's (on by default) */ - writel(0, fei->io + SYS_INPUT_CLKEN); - - /* Enable memdma clock */ - writel(MEMDMAENABLE, fei->io + SYS_OTHER_CLKEN); - - /* clear internal sram */ - memset_io(fei->sram, 0x0, fei->sram_size); - - c8sectpfe_getconfig(fei); - - ret = devm_request_irq(dev, fei->idle_irq, c8sectpfe_idle_irq_handler, - 0, "c8sectpfe-idle-irq", fei); - if (ret) { - dev_err(dev, "Can't register c8sectpfe-idle-irq IRQ.\n"); - return ret; - } - - ret = devm_request_irq(dev, fei->error_irq, - c8sectpfe_error_irq_handler, 0, - "c8sectpfe-error-irq", fei); - if (ret) { - dev_err(dev, "Can't register c8sectpfe-error-irq IRQ.\n"); - return ret; - } - - fei->tsin_count = of_get_child_count(np); - - if (fei->tsin_count > C8SECTPFE_MAX_TSIN_CHAN || - fei->tsin_count > fei->hw_stats.num_ib) { - - dev_err(dev, "More tsin declared than exist on SoC!\n"); - return -EINVAL; - } - - fei->pinctrl = devm_pinctrl_get(dev); - - if (IS_ERR(fei->pinctrl)) { - dev_err(dev, "Error getting tsin pins\n"); - return PTR_ERR(fei->pinctrl); - } - - for_each_child_of_node_scoped(np, child) { - struct device_node *i2c_bus; - - fei->channel_data[index] = devm_kzalloc(dev, - sizeof(struct channel_info), - GFP_KERNEL); - - if (!fei->channel_data[index]) - return -ENOMEM; - - tsin = fei->channel_data[index]; - - tsin->fei = fei; - - ret = of_property_read_u32(child, "tsin-num", &tsin->tsin_id); - if (ret) { - dev_err(&pdev->dev, "No tsin_num found\n"); - return ret; - } - - /* sanity check value */ - if (tsin->tsin_id > fei->hw_stats.num_ib) { - dev_err(&pdev->dev, - "tsin-num %d specified greater than number\n\tof input block hw in SoC! (%d)", - tsin->tsin_id, fei->hw_stats.num_ib); - return -EINVAL; - } - - tsin->invert_ts_clk = of_property_read_bool(child, - "invert-ts-clk"); - - tsin->serial_not_parallel = of_property_read_bool(child, - "serial-not-parallel"); - - tsin->async_not_sync = of_property_read_bool(child, - "async-not-sync"); - - ret = of_property_read_u32(child, "dvb-card", - &tsin->dvb_card); - if (ret) { - dev_err(&pdev->dev, "No dvb-card found\n"); - return ret; - } - - i2c_bus = of_parse_phandle(child, "i2c-bus", 0); - if (!i2c_bus) { - dev_err(&pdev->dev, "No i2c-bus found\n"); - return -ENODEV; - } - tsin->i2c_adapter = - of_find_i2c_adapter_by_node(i2c_bus); - of_node_put(i2c_bus); - if (!tsin->i2c_adapter) { - dev_err(&pdev->dev, "No i2c adapter found\n"); - return -ENODEV; - } - - /* Acquire reset GPIO and activate it */ - tsin->rst_gpio = devm_fwnode_gpiod_get(dev, - of_fwnode_handle(child), - "reset", GPIOD_OUT_HIGH, - "NIM reset"); - ret = PTR_ERR_OR_ZERO(tsin->rst_gpio); - if (ret && ret != -EBUSY) { - dev_err(dev, "Can't request tsin%d reset gpio\n", - fei->channel_data[index]->tsin_id); - return ret; - } - - if (!ret) { - /* wait for the chip to reset */ - usleep_range(3500, 5000); - /* release the reset line */ - gpiod_set_value_cansleep(tsin->rst_gpio, 0); - usleep_range(3000, 5000); - } - - tsin->demux_mapping = index; - - dev_dbg(fei->dev, - "channel=%p n=%d tsin_num=%d, invert-ts-clk=%d\n\tserial-not-parallel=%d pkt-clk-valid=%d dvb-card=%d\n", - fei->channel_data[index], index, - tsin->tsin_id, tsin->invert_ts_clk, - tsin->serial_not_parallel, tsin->async_not_sync, - tsin->dvb_card); - - index++; - } - - /* Setup timer interrupt */ - timer_setup(&fei->timer, c8sectpfe_timer_interrupt, 0); - - mutex_init(&fei->lock); - - /* Get the configuration information about the tuners */ - ret = c8sectpfe_tuner_register_frontend(&fei->c8sectpfe[0], - (void *)fei, - c8sectpfe_start_feed, - c8sectpfe_stop_feed); - if (ret) { - dev_err(dev, "c8sectpfe_tuner_register_frontend failed (%d)\n", - ret); - return ret; - } - - c8sectpfe_debugfs_init(fei); - - return 0; -} - -static void c8sectpfe_remove(struct platform_device *pdev) -{ - struct c8sectpfei *fei = platform_get_drvdata(pdev); - struct channel_info *channel; - int i; - - wait_for_completion(&fei->fw_ack); - - c8sectpfe_tuner_unregister_frontend(fei->c8sectpfe[0], fei); - - /* - * Now loop through and un-configure each of the InputBlock resources - */ - for (i = 0; i < fei->tsin_count; i++) { - channel = fei->channel_data[i]; - free_input_block(fei, channel); - } - - c8sectpfe_debugfs_exit(fei); - - dev_info(fei->dev, "Stopping memdma SLIM core\n"); - if (readl(fei->io + DMA_CPU_RUN)) - writel(0x0, fei->io + DMA_CPU_RUN); - - /* unclock all internal IP's */ - if (readl(fei->io + SYS_INPUT_CLKEN)) - writel(0, fei->io + SYS_INPUT_CLKEN); - - if (readl(fei->io + SYS_OTHER_CLKEN)) - writel(0, fei->io + SYS_OTHER_CLKEN); -} - - -static int configure_channels(struct c8sectpfei *fei) -{ - int index = 0, ret; - struct device_node *np = fei->dev->of_node; - - /* iterate round each tsin and configure memdma descriptor and IB hw */ - for_each_child_of_node_scoped(np, child) { - ret = configure_memdma_and_inputblock(fei, - fei->channel_data[index]); - if (ret) { - dev_err(fei->dev, - "configure_memdma_and_inputblock failed\n"); - goto err_unmap; - } - index++; - } - - return 0; - -err_unmap: - while (--index >= 0) - free_input_block(fei, fei->channel_data[index]); - - return ret; -} - -static int -c8sectpfe_elf_sanity_check(struct c8sectpfei *fei, const struct firmware *fw) -{ - struct elf32_hdr *ehdr; - char class; - - if (!fw) { - dev_err(fei->dev, "failed to load %s\n", FIRMWARE_MEMDMA); - return -EINVAL; - } - - if (fw->size < sizeof(struct elf32_hdr)) { - dev_err(fei->dev, "Image is too small\n"); - return -EINVAL; - } - - ehdr = (struct elf32_hdr *)fw->data; - - /* We only support ELF32 at this point */ - class = ehdr->e_ident[EI_CLASS]; - if (class != ELFCLASS32) { - dev_err(fei->dev, "Unsupported class: %d\n", class); - return -EINVAL; - } - - if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { - dev_err(fei->dev, "Unsupported firmware endianness\n"); - return -EINVAL; - } - - if (fw->size < ehdr->e_shoff + sizeof(struct elf32_shdr)) { - dev_err(fei->dev, "Image is too small\n"); - return -EINVAL; - } - - if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) { - dev_err(fei->dev, "Image is corrupted (bad magic)\n"); - return -EINVAL; - } - - /* Check ELF magic */ - ehdr = (Elf32_Ehdr *)fw->data; - if (ehdr->e_ident[EI_MAG0] != ELFMAG0 || - ehdr->e_ident[EI_MAG1] != ELFMAG1 || - ehdr->e_ident[EI_MAG2] != ELFMAG2 || - ehdr->e_ident[EI_MAG3] != ELFMAG3) { - dev_err(fei->dev, "Invalid ELF magic\n"); - return -EINVAL; - } - - if (ehdr->e_type != ET_EXEC) { - dev_err(fei->dev, "Unsupported ELF header type\n"); - return -EINVAL; - } - - if (ehdr->e_phoff > fw->size) { - dev_err(fei->dev, "Firmware size is too small\n"); - return -EINVAL; - } - - return 0; -} - - -static void load_imem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr, - const struct firmware *fw, u8 __iomem *dest, - int seg_num) -{ - const u8 *imem_src = fw->data + phdr->p_offset; - int i; - - /* - * For IMEM segments, the segment contains 24-bit - * instructions which must be padded to 32-bit - * instructions before being written. The written - * segment is padded with NOP instructions. - */ - - dev_dbg(fei->dev, - "Loading IMEM segment %d 0x%08x\n\t (0x%x bytes) -> 0x%p (0x%x bytes)\n", - seg_num, phdr->p_paddr, phdr->p_filesz, dest, - phdr->p_memsz + phdr->p_memsz / 3); - - for (i = 0; i < phdr->p_filesz; i++) { - - writeb(readb((void __iomem *)imem_src), (void __iomem *)dest); - - /* Every 3 bytes, add an additional - * padding zero in destination */ - if (i % 3 == 2) { - dest++; - writeb(0x00, (void __iomem *)dest); - } - - dest++; - imem_src++; - } -} - -static void load_dmem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr, - const struct firmware *fw, u8 __iomem *dst, int seg_num) -{ - /* - * For DMEM segments copy the segment data from the ELF - * file and pad segment with zeroes - */ - - dev_dbg(fei->dev, - "Loading DMEM segment %d 0x%08x\n\t(0x%x bytes) -> 0x%p (0x%x bytes)\n", - seg_num, phdr->p_paddr, phdr->p_filesz, - dst, phdr->p_memsz); - - memcpy((void __force *)dst, (void *)fw->data + phdr->p_offset, - phdr->p_filesz); - - memset((void __force *)dst + phdr->p_filesz, 0, - phdr->p_memsz - phdr->p_filesz); -} - -static int load_slim_core_fw(const struct firmware *fw, struct c8sectpfei *fei) -{ - Elf32_Ehdr *ehdr; - Elf32_Phdr *phdr; - u8 __iomem *dst; - int err = 0, i; - - if (!fw || !fei) - return -EINVAL; - - ehdr = (Elf32_Ehdr *)fw->data; - phdr = (Elf32_Phdr *)(fw->data + ehdr->e_phoff); - - /* go through the available ELF segments */ - for (i = 0; i < ehdr->e_phnum; i++, phdr++) { - - /* Only consider LOAD segments */ - if (phdr->p_type != PT_LOAD) - continue; - - /* - * Check segment is contained within the fw->data buffer - */ - if (phdr->p_offset + phdr->p_filesz > fw->size) { - dev_err(fei->dev, - "Segment %d is outside of firmware file\n", i); - err = -EINVAL; - break; - } - - /* - * MEMDMA IMEM has executable flag set, otherwise load - * this segment into DMEM. - * - */ - - if (phdr->p_flags & PF_X) { - dst = (u8 __iomem *) fei->io + DMA_MEMDMA_IMEM; - /* - * The Slim ELF file uses 32-bit word addressing for - * load offsets. - */ - dst += (phdr->p_paddr & 0xFFFFF) * sizeof(unsigned int); - load_imem_segment(fei, phdr, fw, dst, i); - } else { - dst = (u8 __iomem *) fei->io + DMA_MEMDMA_DMEM; - /* - * The Slim ELF file uses 32-bit word addressing for - * load offsets. - */ - dst += (phdr->p_paddr & 0xFFFFF) * sizeof(unsigned int); - load_dmem_segment(fei, phdr, fw, dst, i); - } - } - - return err; -} - -static int load_c8sectpfe_fw(struct c8sectpfei *fei) -{ - const struct firmware *fw; - int err; - - dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA); - - err = request_firmware(&fw, FIRMWARE_MEMDMA, fei->dev); - if (err) - return err; - - err = c8sectpfe_elf_sanity_check(fei, fw); - if (err) { - dev_err(fei->dev, "c8sectpfe_elf_sanity_check failed err=(%d)\n" - , err); - release_firmware(fw); - return err; - } - - err = load_slim_core_fw(fw, fei); - release_firmware(fw); - if (err) { - dev_err(fei->dev, "load_slim_core_fw failed err=(%d)\n", err); - return err; - } - - /* now the firmware is loaded configure the input blocks */ - err = configure_channels(fei); - if (err) { - dev_err(fei->dev, "configure_channels failed err=(%d)\n", err); - return err; - } - - /* - * STBus target port can access IMEM and DMEM ports - * without waiting for CPU - */ - writel(0x1, fei->io + DMA_PER_STBUS_SYNC); - - dev_info(fei->dev, "Boot the memdma SLIM core\n"); - writel(0x1, fei->io + DMA_CPU_RUN); - - atomic_set(&fei->fw_loaded, 1); - - return 0; -} - -static const struct of_device_id c8sectpfe_match[] = { - { .compatible = "st,stih407-c8sectpfe" }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, c8sectpfe_match); - -static struct platform_driver c8sectpfe_driver = { - .driver = { - .name = "c8sectpfe", - .of_match_table = c8sectpfe_match, - }, - .probe = c8sectpfe_probe, - .remove = c8sectpfe_remove, -}; - -module_platform_driver(c8sectpfe_driver); - -MODULE_AUTHOR("Peter Bennett <peter.bennett@st.com>"); -MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>"); -MODULE_DESCRIPTION("C8SECTPFE STi DVB Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.h b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.h deleted file mode 100644 index c1b124c6ef12..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.h +++ /dev/null @@ -1,287 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * c8sectpfe-core.h - C8SECTPFE STi DVB driver - * - * Copyright (c) STMicroelectronics 2015 - * - * Author:Peter Bennett <peter.bennett@st.com> - * Peter Griffin <peter.griffin@linaro.org> - * - */ -#ifndef _C8SECTPFE_CORE_H_ -#define _C8SECTPFE_CORE_H_ - -#define C8SECTPFEI_MAXCHANNEL 16 -#define C8SECTPFEI_MAXADAPTER 3 - -#define C8SECTPFE_MAX_TSIN_CHAN 8 - -struct gpio_desc; - -struct channel_info { - - int tsin_id; - bool invert_ts_clk; - bool serial_not_parallel; - bool async_not_sync; - int i2c; - int dvb_card; - - struct gpio_desc *rst_gpio; - - struct i2c_adapter *i2c_adapter; - struct i2c_adapter *tuner_i2c; - struct i2c_adapter *lnb_i2c; - struct i2c_client *i2c_client; - struct dvb_frontend *frontend; - - struct pinctrl_state *pstate; - - int demux_mapping; - int active; - - void *back_buffer_start; - void *back_buffer_aligned; - dma_addr_t back_buffer_busaddr; - - void *pid_buffer_start; - void *pid_buffer_aligned; - dma_addr_t pid_buffer_busaddr; - - unsigned long fifo; - - struct completion idle_completion; - struct work_struct bh_work; - - struct c8sectpfei *fei; - void __iomem *irec; - -}; - -struct c8sectpfe_hw { - int num_ib; - int num_mib; - int num_swts; - int num_tsout; - int num_ccsc; - int num_ram; - int num_tp; -}; - -struct c8sectpfei { - - struct device *dev; - struct pinctrl *pinctrl; - - struct dentry *root; - struct debugfs_regset32 *regset; - struct completion fw_ack; - atomic_t fw_loaded; - - int tsin_count; - - struct c8sectpfe_hw hw_stats; - - struct c8sectpfe *c8sectpfe[C8SECTPFEI_MAXADAPTER]; - - int mapping[C8SECTPFEI_MAXCHANNEL]; - - struct mutex lock; - - struct timer_list timer; /* timer interrupts for outputs */ - - void __iomem *io; - void __iomem *sram; - - unsigned long sram_size; - - struct channel_info *channel_data[C8SECTPFE_MAX_TSIN_CHAN]; - - struct clk *c8sectpfeclk; - int nima_rst_gpio; - int nimb_rst_gpio; - - int idle_irq; - int error_irq; - - int global_feed_count; -}; - -/* C8SECTPFE SYS Regs list */ - -#define SYS_INPUT_ERR_STATUS 0x0 -#define SYS_OTHER_ERR_STATUS 0x8 -#define SYS_INPUT_ERR_MASK 0x10 -#define SYS_OTHER_ERR_MASK 0x18 -#define SYS_DMA_ROUTE 0x20 -#define SYS_INPUT_CLKEN 0x30 -#define IBENABLE_MASK 0x7F - -#define SYS_OTHER_CLKEN 0x38 -#define TSDMAENABLE BIT(1) -#define MEMDMAENABLE BIT(0) - -#define SYS_CFG_NUM_IB 0x200 -#define SYS_CFG_NUM_MIB 0x204 -#define SYS_CFG_NUM_SWTS 0x208 -#define SYS_CFG_NUM_TSOUT 0x20C -#define SYS_CFG_NUM_CCSC 0x210 -#define SYS_CFG_NUM_RAM 0x214 -#define SYS_CFG_NUM_TP 0x218 - -/* Input Block Regs */ - -#define C8SECTPFE_INPUTBLK_OFFSET 0x1000 -#define C8SECTPFE_CHANNEL_OFFSET(x) ((x*0x40) + C8SECTPFE_INPUTBLK_OFFSET) - -#define C8SECTPFE_IB_IP_FMT_CFG(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x00) -#define C8SECTPFE_IGNORE_ERR_AT_SOP BIT(7) -#define C8SECTPFE_IGNORE_ERR_IN_PKT BIT(6) -#define C8SECTPFE_IGNORE_ERR_IN_BYTE BIT(5) -#define C8SECTPFE_INVERT_TSCLK BIT(4) -#define C8SECTPFE_ALIGN_BYTE_SOP BIT(3) -#define C8SECTPFE_ASYNC_NOT_SYNC BIT(2) -#define C8SECTPFE_BYTE_ENDIANNESS_MSB BIT(1) -#define C8SECTPFE_SERIAL_NOT_PARALLEL BIT(0) - -#define C8SECTPFE_IB_SYNCLCKDRP_CFG(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x04) -#define C8SECTPFE_SYNC(x) (x & 0xf) -#define C8SECTPFE_DROP(x) ((x<<4) & 0xf) -#define C8SECTPFE_TOKEN(x) ((x<<8) & 0xff00) -#define C8SECTPFE_SLDENDIANNESS BIT(16) - -#define C8SECTPFE_IB_TAGBYTES_CFG(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x08) -#define C8SECTPFE_TAG_HEADER(x) (x << 16) -#define C8SECTPFE_TAG_COUNTER(x) ((x<<1) & 0x7fff) -#define C8SECTPFE_TAG_ENABLE BIT(0) - -#define C8SECTPFE_IB_PID_SET(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x0C) -#define C8SECTPFE_PID_OFFSET(x) (x & 0x3f) -#define C8SECTPFE_PID_NUMBITS(x) ((x << 6) & 0xfff) -#define C8SECTPFE_PID_ENABLE BIT(31) - -#define C8SECTPFE_IB_PKT_LEN(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x10) - -#define C8SECTPFE_IB_BUFF_STRT(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x14) -#define C8SECTPFE_IB_BUFF_END(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x18) -#define C8SECTPFE_IB_READ_PNT(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x1C) -#define C8SECTPFE_IB_WRT_PNT(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x20) - -#define C8SECTPFE_IB_PRI_THRLD(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x24) -#define C8SECTPFE_PRI_VALUE(x) (x & 0x7fffff) -#define C8SECTPFE_PRI_LOWPRI(x) ((x & 0xf) << 24) -#define C8SECTPFE_PRI_HIGHPRI(x) ((x & 0xf) << 28) - -#define C8SECTPFE_IB_STAT(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x28) -#define C8SECTPFE_STAT_FIFO_OVERFLOW(x) (x & 0x1) -#define C8SECTPFE_STAT_BUFFER_OVERFLOW(x) (x & 0x2) -#define C8SECTPFE_STAT_OUTOFORDERRP(x) (x & 0x4) -#define C8SECTPFE_STAT_PID_OVERFLOW(x) (x & 0x8) -#define C8SECTPFE_STAT_PKT_OVERFLOW(x) (x & 0x10) -#define C8SECTPFE_STAT_ERROR_PACKETS(x) ((x >> 8) & 0xf) -#define C8SECTPFE_STAT_SHORT_PACKETS(x) ((x >> 12) & 0xf) - -#define C8SECTPFE_IB_MASK(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x2C) -#define C8SECTPFE_MASK_FIFO_OVERFLOW BIT(0) -#define C8SECTPFE_MASK_BUFFER_OVERFLOW BIT(1) -#define C8SECTPFE_MASK_OUTOFORDERRP(x) BIT(2) -#define C8SECTPFE_MASK_PID_OVERFLOW(x) BIT(3) -#define C8SECTPFE_MASK_PKT_OVERFLOW(x) BIT(4) -#define C8SECTPFE_MASK_ERROR_PACKETS(x) ((x & 0xf) << 8) -#define C8SECTPFE_MASK_SHORT_PACKETS(x) ((x & 0xf) >> 12) - -#define C8SECTPFE_IB_SYS(x) (C8SECTPFE_CHANNEL_OFFSET(x) + 0x30) -#define C8SECTPFE_SYS_RESET BIT(1) -#define C8SECTPFE_SYS_ENABLE BIT(0) - -/* - * Pointer record data structure required for each input block - * see Table 82 on page 167 of functional specification. - */ - -#define DMA_PRDS_MEMBASE 0x0 /* Internal sram base address */ -#define DMA_PRDS_MEMTOP 0x4 /* Internal sram top address */ - -/* - * TS packet size, including tag bytes added by input block, - * rounded up to the next multiple of 8 bytes. The packet size, - * including any tagging bytes and rounded up to the nearest - * multiple of 8 bytes must be less than 255 bytes. - */ -#define DMA_PRDS_PKTSIZE 0x8 -#define DMA_PRDS_TPENABLE 0xc - -#define TP0_OFFSET 0x10 -#define DMA_PRDS_BUSBASE_TP(x) ((0x10*x) + TP0_OFFSET) -#define DMA_PRDS_BUSTOP_TP(x) ((0x10*x) + TP0_OFFSET + 0x4) -#define DMA_PRDS_BUSWP_TP(x) ((0x10*x) + TP0_OFFSET + 0x8) -#define DMA_PRDS_BUSRP_TP(x) ((0x10*x) + TP0_OFFSET + 0xc) - -#define DMA_PRDS_SIZE (0x20) - -#define DMA_MEMDMA_OFFSET 0x4000 -#define DMA_IMEM_OFFSET 0x0 -#define DMA_DMEM_OFFSET 0x4000 -#define DMA_CPU 0x8000 -#define DMA_PER_OFFSET 0xb000 - -#define DMA_MEMDMA_DMEM (DMA_MEMDMA_OFFSET + DMA_DMEM_OFFSET) -#define DMA_MEMDMA_IMEM (DMA_MEMDMA_OFFSET + DMA_IMEM_OFFSET) - -/* XP70 Slim core regs */ -#define DMA_CPU_ID (DMA_MEMDMA_OFFSET + DMA_CPU + 0x0) -#define DMA_CPU_VCR (DMA_MEMDMA_OFFSET + DMA_CPU + 0x4) -#define DMA_CPU_RUN (DMA_MEMDMA_OFFSET + DMA_CPU + 0x8) -#define DMA_CPU_CLOCKGATE (DMA_MEMDMA_OFFSET + DMA_CPU + 0xc) -#define DMA_CPU_PC (DMA_MEMDMA_OFFSET + DMA_CPU + 0x20) - -/* Enable Interrupt for a IB */ -#define DMA_PER_TPn_DREQ_MASK (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xd00) -/* Ack interrupt by setting corresponding bit */ -#define DMA_PER_TPn_DACK_SET (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xd80) -#define DMA_PER_TPn_DREQ (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xe00) -#define DMA_PER_TPn_DACK (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xe80) -#define DMA_PER_DREQ_MODE (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xf80) -#define DMA_PER_STBUS_SYNC (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xf88) -#define DMA_PER_STBUS_ACCESS (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xf8c) -#define DMA_PER_STBUS_ADDRESS (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xf90) -#define DMA_PER_IDLE_INT (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfa8) -#define DMA_PER_PRIORITY (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfac) -#define DMA_PER_MAX_OPCODE (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfb0) -#define DMA_PER_MAX_CHUNK (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfb4) -#define DMA_PER_PAGE_SIZE (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfbc) -#define DMA_PER_MBOX_STATUS (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfc0) -#define DMA_PER_MBOX_SET (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfc8) -#define DMA_PER_MBOX_CLEAR (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfd0) -#define DMA_PER_MBOX_MASK (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfd8) -#define DMA_PER_INJECT_PKT_SRC (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfe0) -#define DMA_PER_INJECT_PKT_DEST (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfe4) -#define DMA_PER_INJECT_PKT_ADDR (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfe8) -#define DMA_PER_INJECT_PKT (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xfec) -#define DMA_PER_PAT_PTR_INIT (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xff0) -#define DMA_PER_PAT_PTR (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xff4) -#define DMA_PER_SLEEP_MASK (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xff8) -#define DMA_PER_SLEEP_COUNTER (DMA_MEMDMA_OFFSET + DMA_PER_OFFSET + 0xffc) -/* #define DMA_RF_CPUREGn DMA_RFBASEADDR n=0 to 15) slim regsa */ - -/* The following are from DMA_DMEM_BaseAddress */ -#define DMA_FIRMWARE_VERSION (DMA_MEMDMA_OFFSET + DMA_DMEM_OFFSET + 0x0) -#define DMA_PTRREC_BASE (DMA_MEMDMA_OFFSET + DMA_DMEM_OFFSET + 0x4) -#define DMA_PTRREC_INPUT_OFFSET (DMA_MEMDMA_OFFSET + DMA_DMEM_OFFSET + 0x8) -#define DMA_ERRREC_BASE (DMA_MEMDMA_OFFSET + DMA_DMEM_OFFSET + 0xc) -#define DMA_ERROR_RECORD(n) ((n*4) + DMA_ERRREC_BASE + 0x4) -#define DMA_IDLE_REQ (DMA_MEMDMA_OFFSET + DMA_DMEM_OFFSET + 0x10) -#define IDLEREQ BIT(31) - -#define DMA_FIRMWARE_CONFIG (DMA_MEMDMA_OFFSET + DMA_DMEM_OFFSET + 0x14) - -/* Regs for PID Filter */ - -#define PIDF_OFFSET 0x2800 -#define PIDF_BASE(n) ((n*4) + PIDF_OFFSET) -#define PIDF_LEAK_ENABLE (PIDF_OFFSET + 0x100) -#define PIDF_LEAK_STATUS (PIDF_OFFSET + 0x108) -#define PIDF_LEAK_COUNT_RESET (PIDF_OFFSET + 0x110) -#define PIDF_LEAK_COUNTER (PIDF_OFFSET + 0x114) - -#endif /* _C8SECTPFE_CORE_H_ */ diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.c deleted file mode 100644 index 301fa10f419b..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.c +++ /dev/null @@ -1,244 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * c8sectpfe-debugfs.c - C8SECTPFE STi DVB driver - * - * Copyright (c) STMicroelectronics 2015 - * - * Author: Peter Griffin <peter.griffin@linaro.org> - * - */ -#include <linux/debugfs.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/seq_file.h> -#include <linux/slab.h> -#include <linux/types.h> - -#include "c8sectpfe-debugfs.h" - -#define dump_register(nm ...) \ -{ \ - .name = #nm, \ - .offset = nm, \ -} - -static const struct debugfs_reg32 fei_sys_regs[] = { - dump_register(SYS_INPUT_ERR_STATUS), - dump_register(SYS_OTHER_ERR_STATUS), - dump_register(SYS_INPUT_ERR_MASK), - dump_register(SYS_DMA_ROUTE), - dump_register(SYS_INPUT_CLKEN), - dump_register(IBENABLE_MASK), - dump_register(SYS_OTHER_CLKEN), - dump_register(SYS_CFG_NUM_IB), - dump_register(SYS_CFG_NUM_MIB), - dump_register(SYS_CFG_NUM_SWTS), - dump_register(SYS_CFG_NUM_TSOUT), - dump_register(SYS_CFG_NUM_CCSC), - dump_register(SYS_CFG_NUM_RAM), - dump_register(SYS_CFG_NUM_TP), - - dump_register(C8SECTPFE_IB_IP_FMT_CFG(0)), - dump_register(C8SECTPFE_IB_TAGBYTES_CFG(0)), - dump_register(C8SECTPFE_IB_PID_SET(0)), - dump_register(C8SECTPFE_IB_PKT_LEN(0)), - dump_register(C8SECTPFE_IB_BUFF_STRT(0)), - dump_register(C8SECTPFE_IB_BUFF_END(0)), - dump_register(C8SECTPFE_IB_READ_PNT(0)), - dump_register(C8SECTPFE_IB_WRT_PNT(0)), - dump_register(C8SECTPFE_IB_PRI_THRLD(0)), - dump_register(C8SECTPFE_IB_STAT(0)), - dump_register(C8SECTPFE_IB_MASK(0)), - dump_register(C8SECTPFE_IB_SYS(0)), - - dump_register(C8SECTPFE_IB_IP_FMT_CFG(1)), - dump_register(C8SECTPFE_IB_TAGBYTES_CFG(1)), - dump_register(C8SECTPFE_IB_PID_SET(1)), - dump_register(C8SECTPFE_IB_PKT_LEN(1)), - dump_register(C8SECTPFE_IB_BUFF_STRT(1)), - dump_register(C8SECTPFE_IB_BUFF_END(1)), - dump_register(C8SECTPFE_IB_READ_PNT(1)), - dump_register(C8SECTPFE_IB_WRT_PNT(1)), - dump_register(C8SECTPFE_IB_PRI_THRLD(1)), - dump_register(C8SECTPFE_IB_STAT(1)), - dump_register(C8SECTPFE_IB_MASK(1)), - dump_register(C8SECTPFE_IB_SYS(1)), - - dump_register(C8SECTPFE_IB_IP_FMT_CFG(2)), - dump_register(C8SECTPFE_IB_TAGBYTES_CFG(2)), - dump_register(C8SECTPFE_IB_PID_SET(2)), - dump_register(C8SECTPFE_IB_PKT_LEN(2)), - dump_register(C8SECTPFE_IB_BUFF_STRT(2)), - dump_register(C8SECTPFE_IB_BUFF_END(2)), - dump_register(C8SECTPFE_IB_READ_PNT(2)), - dump_register(C8SECTPFE_IB_WRT_PNT(2)), - dump_register(C8SECTPFE_IB_PRI_THRLD(2)), - dump_register(C8SECTPFE_IB_STAT(2)), - dump_register(C8SECTPFE_IB_MASK(2)), - dump_register(C8SECTPFE_IB_SYS(2)), - - dump_register(C8SECTPFE_IB_IP_FMT_CFG(3)), - dump_register(C8SECTPFE_IB_TAGBYTES_CFG(3)), - dump_register(C8SECTPFE_IB_PID_SET(3)), - dump_register(C8SECTPFE_IB_PKT_LEN(3)), - dump_register(C8SECTPFE_IB_BUFF_STRT(3)), - dump_register(C8SECTPFE_IB_BUFF_END(3)), - dump_register(C8SECTPFE_IB_READ_PNT(3)), - dump_register(C8SECTPFE_IB_WRT_PNT(3)), - dump_register(C8SECTPFE_IB_PRI_THRLD(3)), - dump_register(C8SECTPFE_IB_STAT(3)), - dump_register(C8SECTPFE_IB_MASK(3)), - dump_register(C8SECTPFE_IB_SYS(3)), - - dump_register(C8SECTPFE_IB_IP_FMT_CFG(4)), - dump_register(C8SECTPFE_IB_TAGBYTES_CFG(4)), - dump_register(C8SECTPFE_IB_PID_SET(4)), - dump_register(C8SECTPFE_IB_PKT_LEN(4)), - dump_register(C8SECTPFE_IB_BUFF_STRT(4)), - dump_register(C8SECTPFE_IB_BUFF_END(4)), - dump_register(C8SECTPFE_IB_READ_PNT(4)), - dump_register(C8SECTPFE_IB_WRT_PNT(4)), - dump_register(C8SECTPFE_IB_PRI_THRLD(4)), - dump_register(C8SECTPFE_IB_STAT(4)), - dump_register(C8SECTPFE_IB_MASK(4)), - dump_register(C8SECTPFE_IB_SYS(4)), - - dump_register(C8SECTPFE_IB_IP_FMT_CFG(5)), - dump_register(C8SECTPFE_IB_TAGBYTES_CFG(5)), - dump_register(C8SECTPFE_IB_PID_SET(5)), - dump_register(C8SECTPFE_IB_PKT_LEN(5)), - dump_register(C8SECTPFE_IB_BUFF_STRT(5)), - dump_register(C8SECTPFE_IB_BUFF_END(5)), - dump_register(C8SECTPFE_IB_READ_PNT(5)), - dump_register(C8SECTPFE_IB_WRT_PNT(5)), - dump_register(C8SECTPFE_IB_PRI_THRLD(5)), - dump_register(C8SECTPFE_IB_STAT(5)), - dump_register(C8SECTPFE_IB_MASK(5)), - dump_register(C8SECTPFE_IB_SYS(5)), - - dump_register(C8SECTPFE_IB_IP_FMT_CFG(6)), - dump_register(C8SECTPFE_IB_TAGBYTES_CFG(6)), - dump_register(C8SECTPFE_IB_PID_SET(6)), - dump_register(C8SECTPFE_IB_PKT_LEN(6)), - dump_register(C8SECTPFE_IB_BUFF_STRT(6)), - dump_register(C8SECTPFE_IB_BUFF_END(6)), - dump_register(C8SECTPFE_IB_READ_PNT(6)), - dump_register(C8SECTPFE_IB_WRT_PNT(6)), - dump_register(C8SECTPFE_IB_PRI_THRLD(6)), - dump_register(C8SECTPFE_IB_STAT(6)), - dump_register(C8SECTPFE_IB_MASK(6)), - dump_register(C8SECTPFE_IB_SYS(6)), - - dump_register(DMA_CPU_ID), - dump_register(DMA_CPU_VCR), - dump_register(DMA_CPU_RUN), - dump_register(DMA_CPU_PC), - - dump_register(DMA_PER_TPn_DREQ_MASK), - dump_register(DMA_PER_TPn_DACK_SET), - dump_register(DMA_PER_TPn_DREQ), - dump_register(DMA_PER_TPn_DACK), - dump_register(DMA_PER_DREQ_MODE), - dump_register(DMA_PER_STBUS_SYNC), - dump_register(DMA_PER_STBUS_ACCESS), - dump_register(DMA_PER_STBUS_ADDRESS), - dump_register(DMA_PER_IDLE_INT), - dump_register(DMA_PER_PRIORITY), - dump_register(DMA_PER_MAX_OPCODE), - dump_register(DMA_PER_MAX_CHUNK), - dump_register(DMA_PER_PAGE_SIZE), - dump_register(DMA_PER_MBOX_STATUS), - dump_register(DMA_PER_MBOX_SET), - dump_register(DMA_PER_MBOX_CLEAR), - dump_register(DMA_PER_MBOX_MASK), - dump_register(DMA_PER_INJECT_PKT_SRC), - dump_register(DMA_PER_INJECT_PKT_DEST), - dump_register(DMA_PER_INJECT_PKT_ADDR), - dump_register(DMA_PER_INJECT_PKT), - dump_register(DMA_PER_PAT_PTR_INIT), - dump_register(DMA_PER_PAT_PTR), - dump_register(DMA_PER_SLEEP_MASK), - dump_register(DMA_PER_SLEEP_COUNTER), - - dump_register(DMA_FIRMWARE_VERSION), - dump_register(DMA_PTRREC_BASE), - dump_register(DMA_PTRREC_INPUT_OFFSET), - dump_register(DMA_ERRREC_BASE), - - dump_register(DMA_ERROR_RECORD(0)), - dump_register(DMA_ERROR_RECORD(1)), - dump_register(DMA_ERROR_RECORD(2)), - dump_register(DMA_ERROR_RECORD(3)), - dump_register(DMA_ERROR_RECORD(4)), - dump_register(DMA_ERROR_RECORD(5)), - dump_register(DMA_ERROR_RECORD(6)), - dump_register(DMA_ERROR_RECORD(7)), - dump_register(DMA_ERROR_RECORD(8)), - dump_register(DMA_ERROR_RECORD(9)), - dump_register(DMA_ERROR_RECORD(10)), - dump_register(DMA_ERROR_RECORD(11)), - dump_register(DMA_ERROR_RECORD(12)), - dump_register(DMA_ERROR_RECORD(13)), - dump_register(DMA_ERROR_RECORD(14)), - dump_register(DMA_ERROR_RECORD(15)), - dump_register(DMA_ERROR_RECORD(16)), - dump_register(DMA_ERROR_RECORD(17)), - dump_register(DMA_ERROR_RECORD(18)), - dump_register(DMA_ERROR_RECORD(19)), - dump_register(DMA_ERROR_RECORD(20)), - dump_register(DMA_ERROR_RECORD(21)), - dump_register(DMA_ERROR_RECORD(22)), - - dump_register(DMA_IDLE_REQ), - dump_register(DMA_FIRMWARE_CONFIG), - - dump_register(PIDF_BASE(0)), - dump_register(PIDF_BASE(1)), - dump_register(PIDF_BASE(2)), - dump_register(PIDF_BASE(3)), - dump_register(PIDF_BASE(4)), - dump_register(PIDF_BASE(5)), - dump_register(PIDF_BASE(6)), - dump_register(PIDF_BASE(7)), - dump_register(PIDF_BASE(8)), - dump_register(PIDF_BASE(9)), - dump_register(PIDF_BASE(10)), - dump_register(PIDF_BASE(11)), - dump_register(PIDF_BASE(12)), - dump_register(PIDF_BASE(13)), - dump_register(PIDF_BASE(14)), - dump_register(PIDF_BASE(15)), - dump_register(PIDF_BASE(16)), - dump_register(PIDF_BASE(17)), - dump_register(PIDF_BASE(18)), - dump_register(PIDF_BASE(19)), - dump_register(PIDF_BASE(20)), - dump_register(PIDF_BASE(21)), - dump_register(PIDF_BASE(22)), - dump_register(PIDF_LEAK_ENABLE), - dump_register(PIDF_LEAK_STATUS), - dump_register(PIDF_LEAK_COUNT_RESET), - dump_register(PIDF_LEAK_COUNTER), -}; - -void c8sectpfe_debugfs_init(struct c8sectpfei *fei) -{ - fei->regset = devm_kzalloc(fei->dev, sizeof(*fei->regset), GFP_KERNEL); - if (!fei->regset) - return; - - fei->regset->regs = fei_sys_regs; - fei->regset->nregs = ARRAY_SIZE(fei_sys_regs); - fei->regset->base = fei->io; - - fei->root = debugfs_create_dir("c8sectpfe", NULL); - debugfs_create_regset32("registers", S_IRUGO, fei->root, fei->regset); -} - -void c8sectpfe_debugfs_exit(struct c8sectpfei *fei) -{ - debugfs_remove_recursive(fei->root); - fei->root = NULL; -} diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h deleted file mode 100644 index 3fe177b59b16..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * c8sectpfe-debugfs.h - C8SECTPFE STi DVB driver debugfs header - * - * Copyright (c) STMicroelectronics 2015 - * - * Authors: Peter Griffin <peter.griffin@linaro.org> - */ - -#ifndef __C8SECTPFE_DEBUG_H -#define __C8SECTPFE_DEBUG_H - -#include "c8sectpfe-core.h" - -#if defined(CONFIG_DEBUG_FS) -void c8sectpfe_debugfs_init(struct c8sectpfei *); -void c8sectpfe_debugfs_exit(struct c8sectpfei *); -#else -static inline void c8sectpfe_debugfs_init(struct c8sectpfei *fei) {}; -static inline void c8sectpfe_debugfs_exit(struct c8sectpfei *fei) {}; -#endif - -#endif /* __C8SECTPFE_DEBUG_H */ diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-dvb.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-dvb.c deleted file mode 100644 index feb48cb546d7..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-dvb.c +++ /dev/null @@ -1,235 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * c8sectpfe-dvb.c - C8SECTPFE STi DVB driver - * - * Copyright (c) STMicroelectronics 2015 - * - * Author Peter Griffin <peter.griffin@linaro.org> - * - */ -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/interrupt.h> - -#include <dt-bindings/media/c8sectpfe.h> - -#include "c8sectpfe-common.h" -#include "c8sectpfe-core.h" -#include "c8sectpfe-dvb.h" - -#include "dvb-pll.h" -#include "lnbh24.h" -#include "stv0367.h" -#include "stv0367_priv.h" -#include "stv6110x.h" -#include "stv090x.h" -#include "tda18212.h" - -static inline const char *dvb_card_str(unsigned int c) -{ - switch (c) { - case STV0367_TDA18212_NIMA_1: return "STV0367_TDA18212_NIMA_1"; - case STV0367_TDA18212_NIMA_2: return "STV0367_TDA18212_NIMA_2"; - case STV0367_TDA18212_NIMB_1: return "STV0367_TDA18212_NIMB_1"; - case STV0367_TDA18212_NIMB_2: return "STV0367_TDA18212_NIMB_2"; - case STV0903_6110_LNB24_NIMA: return "STV0903_6110_LNB24_NIMA"; - case STV0903_6110_LNB24_NIMB: return "STV0903_6110_LNB24_NIMB"; - default: return "unknown dvb frontend card"; - } -} - -static struct stv090x_config stv090x_config = { - .device = STV0903, - .demod_mode = STV090x_SINGLE, - .clk_mode = STV090x_CLK_EXT, - .xtal = 16000000, - .address = 0x69, - - .ts1_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, - .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, - - .repeater_level = STV090x_RPTLEVEL_64, - - .tuner_init = NULL, - .tuner_set_mode = NULL, - .tuner_set_frequency = NULL, - .tuner_get_frequency = NULL, - .tuner_set_bandwidth = NULL, - .tuner_get_bandwidth = NULL, - .tuner_set_bbgain = NULL, - .tuner_get_bbgain = NULL, - .tuner_set_refclk = NULL, - .tuner_get_status = NULL, -}; - -static struct stv6110x_config stv6110x_config = { - .addr = 0x60, - .refclk = 16000000, -}; - -#define NIMA 0 -#define NIMB 1 - -static struct stv0367_config stv0367_tda18212_config[] = { - { - .demod_address = 0x1c, - .xtal = 16000000, - .if_khz = 4500, - .if_iq_mode = FE_TER_NORMAL_IF_TUNER, - .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, - .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, - }, { - .demod_address = 0x1d, - .xtal = 16000000, - .if_khz = 4500, - .if_iq_mode = FE_TER_NORMAL_IF_TUNER, - .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, - .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, - }, { - .demod_address = 0x1e, - .xtal = 16000000, - .if_khz = 4500, - .if_iq_mode = FE_TER_NORMAL_IF_TUNER, - .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, - .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT, - }, -}; - -static struct tda18212_config tda18212_conf = { - .if_dvbt_6 = 4150, - .if_dvbt_7 = 4150, - .if_dvbt_8 = 4500, - .if_dvbc = 5000, -}; - -int c8sectpfe_frontend_attach(struct dvb_frontend **fe, - struct c8sectpfe *c8sectpfe, - struct channel_info *tsin, int chan_num) -{ - struct tda18212_config *tda18212; - const struct stv6110x_devctl *fe2; - struct i2c_client *client; - struct i2c_board_info tda18212_info = { - .type = "tda18212", - .addr = 0x60, - }; - - if (!tsin) - return -EINVAL; - - switch (tsin->dvb_card) { - - case STV0367_TDA18212_NIMA_1: - case STV0367_TDA18212_NIMA_2: - case STV0367_TDA18212_NIMB_1: - case STV0367_TDA18212_NIMB_2: - if (tsin->dvb_card == STV0367_TDA18212_NIMA_1) - *fe = dvb_attach(stv0367ter_attach, - &stv0367_tda18212_config[0], - tsin->i2c_adapter); - else if (tsin->dvb_card == STV0367_TDA18212_NIMB_1) - *fe = dvb_attach(stv0367ter_attach, - &stv0367_tda18212_config[1], - tsin->i2c_adapter); - else - *fe = dvb_attach(stv0367ter_attach, - &stv0367_tda18212_config[2], - tsin->i2c_adapter); - - if (!*fe) { - dev_err(c8sectpfe->device, - "%s: stv0367ter_attach failed for NIM card %s\n" - , __func__, dvb_card_str(tsin->dvb_card)); - return -ENODEV; - } - - /* - * init the demod so that i2c gate_ctrl - * to the tuner works correctly - */ - (*fe)->ops.init(*fe); - - /* Allocate the tda18212 structure */ - tda18212 = devm_kzalloc(c8sectpfe->device, - sizeof(struct tda18212_config), - GFP_KERNEL); - if (!tda18212) { - dev_err(c8sectpfe->device, - "%s: devm_kzalloc failed\n", __func__); - return -ENOMEM; - } - - memcpy(tda18212, &tda18212_conf, - sizeof(struct tda18212_config)); - - tda18212->fe = (*fe); - - tda18212_info.platform_data = tda18212; - - /* attach tuner */ - request_module("tda18212"); - client = i2c_new_client_device(tsin->i2c_adapter, - &tda18212_info); - if (!i2c_client_has_driver(client)) { - dvb_frontend_detach(*fe); - return -ENODEV; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - dvb_frontend_detach(*fe); - return -ENODEV; - } - - tsin->i2c_client = client; - - break; - - case STV0903_6110_LNB24_NIMA: - *fe = dvb_attach(stv090x_attach, &stv090x_config, - tsin->i2c_adapter, STV090x_DEMODULATOR_0); - if (!*fe) { - dev_err(c8sectpfe->device, "%s: stv090x_attach failed\n" - "\tfor NIM card %s\n", - __func__, dvb_card_str(tsin->dvb_card)); - return -ENODEV; - } - - fe2 = dvb_attach(stv6110x_attach, *fe, - &stv6110x_config, tsin->i2c_adapter); - if (!fe2) { - dev_err(c8sectpfe->device, - "%s: stv6110x_attach failed for NIM card %s\n" - , __func__, dvb_card_str(tsin->dvb_card)); - return -ENODEV; - } - - stv090x_config.tuner_init = fe2->tuner_init; - stv090x_config.tuner_set_mode = fe2->tuner_set_mode; - stv090x_config.tuner_set_frequency = fe2->tuner_set_frequency; - stv090x_config.tuner_get_frequency = fe2->tuner_get_frequency; - stv090x_config.tuner_set_bandwidth = fe2->tuner_set_bandwidth; - stv090x_config.tuner_get_bandwidth = fe2->tuner_get_bandwidth; - stv090x_config.tuner_set_bbgain = fe2->tuner_set_bbgain; - stv090x_config.tuner_get_bbgain = fe2->tuner_get_bbgain; - stv090x_config.tuner_set_refclk = fe2->tuner_set_refclk; - stv090x_config.tuner_get_status = fe2->tuner_get_status; - - dvb_attach(lnbh24_attach, *fe, tsin->i2c_adapter, 0, 0, 0x9); - break; - - default: - dev_err(c8sectpfe->device, - "%s: DVB frontend card %s not yet supported\n", - __func__, dvb_card_str(tsin->dvb_card)); - return -ENODEV; - } - - (*fe)->id = chan_num; - - dev_info(c8sectpfe->device, - "DVB frontend card %s successfully attached", - dvb_card_str(tsin->dvb_card)); - return 0; -} diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-dvb.h b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-dvb.h deleted file mode 100644 index 3d87a9ae8702..000000000000 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-dvb.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * c8sectpfe-common.h - C8SECTPFE STi DVB driver - * - * Copyright (c) STMicroelectronics 2015 - * - * Author: Peter Griffin <peter.griffin@linaro.org> - * - */ -#ifndef _C8SECTPFE_DVB_H_ -#define _C8SECTPFE_DVB_H_ - -int c8sectpfe_frontend_attach(struct dvb_frontend **fe, - struct c8sectpfe *c8sectpfe, struct channel_info *tsin, - int chan_num); - -#endif diff --git a/drivers/media/platform/st/sti/delta/delta-mjpeg-dec.c b/drivers/media/platform/st/sti/delta/delta-mjpeg-dec.c index 0533d4a083d2..a078f1107300 100644 --- a/drivers/media/platform/st/sti/delta/delta-mjpeg-dec.c +++ b/drivers/media/platform/st/sti/delta/delta-mjpeg-dec.c @@ -239,7 +239,7 @@ static int delta_mjpeg_ipc_open(struct delta_ctx *pctx) return 0; } -static int delta_mjpeg_ipc_decode(struct delta_ctx *pctx, struct delta_au *au) +static int delta_mjpeg_ipc_decode(struct delta_ctx *pctx, dma_addr_t pstart, dma_addr_t pend) { struct delta_dev *delta = pctx->dev; struct delta_mjpeg_ctx *ctx = to_ctx(pctx); @@ -256,8 +256,8 @@ static int delta_mjpeg_ipc_decode(struct delta_ctx *pctx, struct delta_au *au) memset(params, 0, sizeof(*params)); - params->picture_start_addr_p = (u32)(au->paddr); - params->picture_end_addr_p = (u32)(au->paddr + au->size - 1); + params->picture_start_addr_p = pstart; + params->picture_end_addr_p = pend; /* * !WARNING! @@ -374,12 +374,14 @@ static int delta_mjpeg_decode(struct delta_ctx *pctx, struct delta_au *pau) struct delta_dev *delta = pctx->dev; struct delta_mjpeg_ctx *ctx = to_ctx(pctx); int ret; - struct delta_au au = *pau; + void *au_vaddr = pau->vaddr; + dma_addr_t au_dma = pau->paddr; + size_t au_size = pau->size; unsigned int data_offset = 0; struct mjpeg_header *header = &ctx->header_struct; if (!ctx->header) { - ret = delta_mjpeg_read_header(pctx, au.vaddr, au.size, + ret = delta_mjpeg_read_header(pctx, au_vaddr, au_size, header, &data_offset); if (ret) { pctx->stream_errors++; @@ -405,17 +407,17 @@ static int delta_mjpeg_decode(struct delta_ctx *pctx, struct delta_au *pau) goto err; } - ret = delta_mjpeg_read_header(pctx, au.vaddr, au.size, + ret = delta_mjpeg_read_header(pctx, au_vaddr, au_size, ctx->header, &data_offset); if (ret) { pctx->stream_errors++; goto err; } - au.paddr += data_offset; - au.vaddr += data_offset; + au_dma += data_offset; + au_vaddr += data_offset; - ret = delta_mjpeg_ipc_decode(pctx, &au); + ret = delta_mjpeg_ipc_decode(pctx, au_dma, au_dma + au_size - 1); if (ret) goto err; diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index 196e6a40335d..6c1a53c771f7 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -24,7 +24,11 @@ #define DELTA_PREFIX "[---:----]" -#define to_ctx(__fh) container_of(__fh, struct delta_ctx, fh) +static inline struct delta_ctx *file_to_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct delta_ctx, fh); +} + #define to_au(__vbuf) container_of(__vbuf, struct delta_au, vbuf) #define to_frame(__vbuf) container_of(__vbuf, struct delta_frame, vbuf) @@ -382,7 +386,7 @@ static int delta_open_decoder(struct delta_ctx *ctx, u32 streamformat, static int delta_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; strscpy(cap->driver, DELTA_NAME, sizeof(cap->driver)); @@ -396,7 +400,7 @@ static int delta_querycap(struct file *file, void *priv, static int delta_enum_fmt_stream(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; if (unlikely(f->index >= delta->nb_of_streamformats)) @@ -410,7 +414,7 @@ static int delta_enum_fmt_stream(struct file *file, void *priv, static int delta_enum_fmt_frame(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; if (unlikely(f->index >= delta->nb_of_pixelformats)) @@ -424,7 +428,7 @@ static int delta_enum_fmt_frame(struct file *file, void *priv, static int delta_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct v4l2_pix_format *pix = &f->fmt.pix; struct delta_streaminfo *streaminfo = &ctx->streaminfo; @@ -452,7 +456,7 @@ static int delta_g_fmt_stream(struct file *file, void *fh, static int delta_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct v4l2_pix_format *pix = &f->fmt.pix; struct delta_frameinfo *frameinfo = &ctx->frameinfo; @@ -491,7 +495,7 @@ static int delta_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) static int delta_try_fmt_stream(struct file *file, void *priv, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct v4l2_pix_format *pix = &f->fmt.pix; u32 streamformat = pix->pixelformat; @@ -545,7 +549,7 @@ static int delta_try_fmt_stream(struct file *file, void *priv, static int delta_try_fmt_frame(struct file *file, void *priv, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct v4l2_pix_format *pix = &f->fmt.pix; u32 pixelformat = pix->pixelformat; @@ -605,7 +609,7 @@ static int delta_try_fmt_frame(struct file *file, void *priv, static int delta_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; struct vb2_queue *vq; struct v4l2_pix_format *pix = &f->fmt.pix; @@ -641,7 +645,7 @@ static int delta_s_fmt_stream(struct file *file, void *fh, static int delta_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; const struct delta_dec *dec = ctx->dec; struct v4l2_pix_format *pix = &f->fmt.pix; @@ -721,7 +725,7 @@ static int delta_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) static int delta_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct delta_ctx *ctx = to_ctx(fh); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_frameinfo *frameinfo = &ctx->frameinfo; struct v4l2_rect crop; @@ -803,7 +807,7 @@ static int delta_try_decoder_cmd(struct file *file, void *fh, return 0; } -static int delta_decoder_stop_cmd(struct delta_ctx *ctx, void *fh) +static int delta_decoder_stop_cmd(struct delta_ctx *ctx) { const struct delta_dec *dec = ctx->dec; struct delta_dev *delta = ctx->dev; @@ -866,14 +870,14 @@ delay_eos: static int delta_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { - struct delta_ctx *ctx = to_ctx(fh); + struct delta_ctx *ctx = file_to_ctx(file); int ret = 0; ret = delta_try_decoder_cmd(file, fh, cmd); if (ret) return ret; - return delta_decoder_stop_cmd(ctx, fh); + return delta_decoder_stop_cmd(ctx); } static int delta_subscribe_event(struct v4l2_fh *fh, @@ -1633,8 +1637,7 @@ static int delta_open(struct file *file) ctx->dev = delta; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); INIT_WORK(&ctx->run_work, delta_run_work); mutex_init(&ctx->lock); @@ -1679,7 +1682,7 @@ static int delta_open(struct file *file) return 0; err_fh_del: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); err: @@ -1690,7 +1693,7 @@ err: static int delta_release(struct file *file) { - struct delta_ctx *ctx = to_ctx(file->private_data); + struct delta_ctx *ctx = file_to_ctx(file); struct delta_dev *delta = ctx->dev; const struct delta_dec *dec = ctx->dec; @@ -1707,7 +1710,7 @@ static int delta_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); /* disable ST231 clocks */ diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c index 5366c0f92549..3581b73a99b8 100644 --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c @@ -36,7 +36,10 @@ #define to_type_str(type) (type == V4L2_BUF_TYPE_VIDEO_OUTPUT ? \ "frame" : "stream") -#define fh_to_ctx(f) (container_of(f, struct hva_ctx, fh)) +static inline struct hva_ctx *file_to_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct hva_ctx, fh); +} /* registry of available encoders */ static const struct hva_enc *hva_encoders[] = { @@ -254,7 +257,7 @@ static void hva_dbg_summary(struct hva_ctx *ctx) static int hva_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_dev *hva = ctx_to_hdev(ctx); strscpy(cap->driver, HVA_NAME, sizeof(cap->driver)); @@ -268,7 +271,7 @@ static int hva_querycap(struct file *file, void *priv, static int hva_enum_fmt_stream(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_dev *hva = ctx_to_hdev(ctx); if (unlikely(f->index >= hva->nb_of_streamformats)) @@ -282,7 +285,7 @@ static int hva_enum_fmt_stream(struct file *file, void *priv, static int hva_enum_fmt_frame(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_dev *hva = ctx_to_hdev(ctx); if (unlikely(f->index >= hva->nb_of_pixelformats)) @@ -295,7 +298,7 @@ static int hva_enum_fmt_frame(struct file *file, void *priv, static int hva_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_streaminfo *streaminfo = &ctx->streaminfo; f->fmt.pix.width = streaminfo->width; @@ -314,7 +317,7 @@ static int hva_g_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) static int hva_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_frameinfo *frameinfo = &ctx->frameinfo; f->fmt.pix.width = frameinfo->width; @@ -335,7 +338,7 @@ static int hva_g_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) static int hva_try_fmt_stream(struct file *file, void *priv, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); struct v4l2_pix_format *pix = &f->fmt.pix; u32 streamformat = pix->pixelformat; @@ -399,7 +402,7 @@ static int hva_try_fmt_stream(struct file *file, void *priv, static int hva_try_fmt_frame(struct file *file, void *priv, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); struct v4l2_pix_format *pix = &f->fmt.pix; u32 pixelformat = pix->pixelformat; @@ -449,7 +452,7 @@ static int hva_try_fmt_frame(struct file *file, void *priv, static int hva_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); struct vb2_queue *vq; int ret; @@ -479,7 +482,7 @@ static int hva_s_fmt_stream(struct file *file, void *fh, struct v4l2_format *f) static int hva_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); struct v4l2_pix_format *pix = &f->fmt.pix; struct vb2_queue *vq; @@ -517,7 +520,7 @@ static int hva_s_fmt_frame(struct file *file, void *fh, struct v4l2_format *f) static int hva_g_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct v4l2_fract *time_per_frame = &ctx->ctrls.time_per_frame; if (sp->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -533,7 +536,7 @@ static int hva_g_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) static int hva_s_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct v4l2_fract *time_per_frame = &ctx->ctrls.time_per_frame; if (sp->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -553,7 +556,7 @@ static int hva_s_parm(struct file *file, void *fh, struct v4l2_streamparm *sp) static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct device *dev = ctx_to_dev(ctx); if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { @@ -1171,8 +1174,7 @@ static int hva_open(struct file *file) INIT_WORK(&ctx->run_work, hva_run_work); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ret = hva_ctrls_setup(ctx); if (ret) { @@ -1216,7 +1218,7 @@ static int hva_open(struct file *file) err_ctrls: v4l2_ctrl_handler_free(&ctx->ctrl_handler); err_fh: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); out: @@ -1225,7 +1227,7 @@ out: static int hva_release(struct file *file) { - struct hva_ctx *ctx = fh_to_ctx(file->private_data); + struct hva_ctx *ctx = file_to_ctx(file); struct hva_dev *hva = ctx_to_hdev(ctx); struct device *dev = ctx_to_dev(ctx); const struct hva_enc *enc = ctx->enc; @@ -1247,7 +1249,7 @@ static int hva_release(struct file *file) v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); #ifdef CONFIG_VIDEO_STI_HVA_DEBUGFS diff --git a/drivers/media/platform/st/sti/hva/hva.h b/drivers/media/platform/st/sti/hva/hva.h index ba6b893416ec..1fe561082a74 100644 --- a/drivers/media/platform/st/sti/hva/hva.h +++ b/drivers/media/platform/st/sti/hva/hva.h @@ -13,8 +13,6 @@ #include <media/videobuf2-v4l2.h> #include <media/v4l2-mem2mem.h> -#define fh_to_ctx(f) (container_of(f, struct hva_ctx, fh)) - #define hva_to_dev(h) (h->dev) #define ctx_to_dev(c) (c->hva_dev->dev) diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c index 48fa781aab06..72488aa922fc 100644 --- a/drivers/media/platform/st/stm32/dma2d/dma2d.c +++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c @@ -45,7 +45,10 @@ * whole of a destination image with a pixel format conversion. */ -#define fh2ctx(__fh) container_of(__fh, struct dma2d_ctx, fh) +static inline struct dma2d_ctx *file2ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct dma2d_ctx, fh); +} static const struct dma2d_fmt formats[] = { { @@ -301,8 +304,7 @@ static int dma2d_open(struct file *file) } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); dma2d_setup_ctrls(ctx); @@ -318,13 +320,13 @@ static int dma2d_open(struct file *file) static int dma2d_release(struct file *file) { struct dma2d_dev *dev = video_drvdata(file); - struct dma2d_ctx *ctx = fh2ctx(file->private_data); + struct dma2d_ctx *ctx = file2ctx(file); mutex_lock(&dev->mutex); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(&dev->mutex); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); kfree(ctx); @@ -341,7 +343,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= NUM_FORMATS) return -EINVAL; @@ -350,16 +352,11 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) return 0; } -static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct dma2d_ctx *ctx = prv; - struct vb2_queue *vq; + struct dma2d_ctx *ctx = file2ctx(file); struct dma2d_frame *frm; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - frm = get_frame(ctx, f->type); f->fmt.pix.width = frm->width; f->fmt.pix.height = frm->height; @@ -375,9 +372,9 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct dma2d_ctx *ctx = prv; + struct dma2d_ctx *ctx = file2ctx(file); struct dma2d_fmt *fmt; enum v4l2_field *field; u32 fourcc = f->fmt.pix.pixelformat; @@ -418,9 +415,9 @@ static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) return 0; } -static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct dma2d_ctx *ctx = prv; + struct dma2d_ctx *ctx = file2ctx(file); struct vb2_queue *vq; struct dma2d_frame *frm; struct dma2d_fmt *fmt; @@ -429,7 +426,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) /* Adjust all values accordingly to the hardware capabilities * and chosen format. */ - ret = vidioc_try_fmt(file, prv, f); + ret = vidioc_try_fmt(file, priv, f); if (ret) return ret; @@ -488,7 +485,7 @@ static void device_run(void *prv) src->sequence = frm_out->sequence++; dst->sequence = frm_cap->sequence++; - v4l2_m2m_buf_copy_metadata(src, dst, true); + v4l2_m2m_buf_copy_metadata(src, dst); if (clk_enable(dev->gate)) goto end; diff --git a/drivers/media/platform/st/stm32/stm32-csi.c b/drivers/media/platform/st/stm32/stm32-csi.c index b69048144cc1..fd2b6dfbd44c 100644 --- a/drivers/media/platform/st/stm32/stm32-csi.c +++ b/drivers/media/platform/st/stm32/stm32-csi.c @@ -443,8 +443,7 @@ static void stm32_csi_phy_reg_write(struct stm32_csi_dev *csidev, static int stm32_csi_start(struct stm32_csi_dev *csidev, struct v4l2_subdev_state *state) { - struct media_pad *src_pad = - &csidev->s_subdev->entity.pads[csidev->s_subdev_pad_nb]; + struct media_pad *src_pad; const struct stm32_csi_mbps_phy_reg *phy_regs = NULL; struct v4l2_mbus_framefmt *sink_fmt; const struct stm32_csi_fmts *fmt; @@ -466,6 +465,7 @@ static int stm32_csi_start(struct stm32_csi_dev *csidev, if (!csidev->s_subdev) return -EIO; + src_pad = &csidev->s_subdev->entity.pads[csidev->s_subdev_pad_nb]; link_freq = v4l2_get_link_freq(src_pad, fmt->bpp, 2 * csidev->num_lanes); if (link_freq < 0) diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index d94c61b8569d..13762861b769 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -1701,8 +1701,8 @@ static int dcmi_framesizes_init(struct stm32_dcmi *dcmi) .which = V4L2_SUBDEV_FORMAT_ACTIVE, .code = dcmi->sd_format->mbus_code, }; - unsigned int ret; unsigned int i; + int ret; /* Allocate discrete framesizes array */ while (!v4l2_subdev_call(subdev, pad, enum_frame_size, @@ -1808,8 +1808,8 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_async_connection *asd) { struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier); - unsigned int ret; int src_pad; + int ret; dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name); 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 76356bc7f10e..65879f4802c0 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c @@ -711,7 +711,7 @@ static void sun6i_csi_capture_format_prepare(struct v4l2_format *format) pix_format->xfer_func = V4L2_XFER_FUNC_DEFAULT; } -static int sun6i_csi_capture_querycap(struct file *file, void *private, +static int sun6i_csi_capture_querycap(struct file *file, void *priv, struct v4l2_capability *capability) { struct sun6i_csi_device *csi_dev = video_drvdata(file); @@ -725,7 +725,7 @@ static int sun6i_csi_capture_querycap(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_enum_fmt(struct file *file, void *private, +static int sun6i_csi_capture_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmtdesc) { u32 index = fmtdesc->index; @@ -738,7 +738,7 @@ static int sun6i_csi_capture_enum_fmt(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_g_fmt(struct file *file, void *private, +static int sun6i_csi_capture_g_fmt(struct file *file, void *priv, struct v4l2_format *format) { struct sun6i_csi_device *csi_dev = video_drvdata(file); @@ -748,7 +748,7 @@ static int sun6i_csi_capture_g_fmt(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_s_fmt(struct file *file, void *private, +static int sun6i_csi_capture_s_fmt(struct file *file, void *priv, struct v4l2_format *format) { struct sun6i_csi_device *csi_dev = video_drvdata(file); @@ -764,7 +764,7 @@ static int sun6i_csi_capture_s_fmt(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_try_fmt(struct file *file, void *private, +static int sun6i_csi_capture_try_fmt(struct file *file, void *priv, struct v4l2_format *format) { sun6i_csi_capture_format_prepare(format); @@ -772,7 +772,7 @@ static int sun6i_csi_capture_try_fmt(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_enum_input(struct file *file, void *private, +static int sun6i_csi_capture_enum_input(struct file *file, void *priv, struct v4l2_input *input) { if (input->index != 0) @@ -784,7 +784,7 @@ static int sun6i_csi_capture_enum_input(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_g_input(struct file *file, void *private, +static int sun6i_csi_capture_g_input(struct file *file, void *priv, unsigned int *index) { *index = 0; @@ -792,7 +792,7 @@ static int sun6i_csi_capture_g_input(struct file *file, void *private, return 0; } -static int sun6i_csi_capture_s_input(struct file *file, void *private, +static int sun6i_csi_capture_s_input(struct file *file, void *priv, unsigned int index) { if (index != 0) diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index 3e7f2df70408..7c4dd1ac772d 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -71,7 +71,7 @@ static void deinterlace_device_run(void *priv) src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - v4l2_m2m_buf_copy_metadata(src, dst, true); + v4l2_m2m_buf_copy_metadata(src, dst); deinterlace_write(dev, DEINTERLACE_MOD_ENABLE, DEINTERLACE_MOD_ENABLE_EN); @@ -309,7 +309,7 @@ static void deinterlace_init(struct deinterlace_dev *dev) static inline struct deinterlace_ctx *deinterlace_file2ctx(struct file *file) { - return container_of(file->private_data, struct deinterlace_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct deinterlace_ctx, fh); } static bool deinterlace_check_format(u32 pixelformat) @@ -730,7 +730,6 @@ static int deinterlace_open(struct file *file) deinterlace_prepare_format(&ctx->dst_fmt); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, @@ -740,7 +739,7 @@ static int deinterlace_open(struct file *file) goto err_free; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); mutex_unlock(&dev->dev_mutex); @@ -756,12 +755,11 @@ err_free: static int deinterlace_release(struct file *file) { struct deinterlace_dev *dev = video_drvdata(file); - struct deinterlace_ctx *ctx = container_of(file->private_data, - struct deinterlace_ctx, fh); + struct deinterlace_ctx *ctx = deinterlace_file2ctx(file); mutex_lock(&dev->dev_mutex); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c index abd10b218aa1..2deab920884a 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c +++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c @@ -70,7 +70,7 @@ static void rotate_device_run(void *priv) src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - v4l2_m2m_buf_copy_metadata(src, dst, true); + v4l2_m2m_buf_copy_metadata(src, dst); val = ROTATE_GLB_CTL_MODE(ROTATE_MODE_COPY_ROTATE); if (ctx->hflip) @@ -170,7 +170,7 @@ static irqreturn_t rotate_irq(int irq, void *data) static inline struct rotate_ctx *rotate_file2ctx(struct file *file) { - return container_of(file->private_data, struct rotate_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct rotate_ctx, fh); } static void rotate_prepare_format(struct v4l2_pix_format *pix_fmt) @@ -659,7 +659,6 @@ static int rotate_open(struct file *file) rotate_set_cap_format(ctx, &ctx->dst_fmt, ctx->rotate); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, @@ -669,7 +668,7 @@ static int rotate_open(struct file *file) goto err_free; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); ret = rotate_setup_ctrls(ctx); if (ret) @@ -691,13 +690,12 @@ err_free: static int rotate_release(struct file *file) { struct rotate_dev *dev = video_drvdata(file); - struct rotate_ctx *ctx = container_of(file->private_data, - struct rotate_ctx, fh); + struct rotate_ctx *ctx = rotate_file2ctx(file); mutex_lock(&dev->dev_mutex); v4l2_ctrl_handler_free(&ctx->ctrl_handler); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c index 7af6765532e3..c3007e09bc9f 100644 --- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c +++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.c @@ -237,7 +237,7 @@ static bool tx_5v_power_present(struct snps_hdmirx_dev *hdmirx_dev) break; } - ret = (cnt >= detection_threshold) ? true : false; + ret = cnt >= detection_threshold; v4l2_dbg(3, debug, &hdmirx_dev->v4l2_dev, "%s: %d\n", __func__, ret); return ret; @@ -459,7 +459,7 @@ static bool port_no_link(struct snps_hdmirx_dev *hdmirx_dev) return !tx_5v_power_present(hdmirx_dev); } -static int hdmirx_query_dv_timings(struct file *file, void *_fh, +static int hdmirx_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdmirx_stream *stream = video_drvdata(file); @@ -751,7 +751,7 @@ static int hdmirx_dv_timings_cap(struct file *file, void *fh, return 0; } -static int hdmirx_enum_dv_timings(struct file *file, void *_fh, +static int hdmirx_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { return v4l2_enum_dv_timings_cap(timings, &hdmirx_timings_cap, NULL, NULL); @@ -1323,7 +1323,7 @@ static int hdmirx_g_fmt_vid_cap_mplane(struct file *file, void *fh, return 0; } -static int hdmirx_g_dv_timings(struct file *file, void *_fh, +static int hdmirx_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdmirx_stream *stream = video_drvdata(file); @@ -1339,7 +1339,7 @@ static int hdmirx_g_dv_timings(struct file *file, void *_fh, return 0; } -static int hdmirx_s_dv_timings(struct file *file, void *_fh, +static int hdmirx_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdmirx_stream *stream = video_drvdata(file); diff --git a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h index 220ab99ca611..b13f58e31944 100644 --- a/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h +++ b/drivers/media/platform/synopsys/hdmirx/snps_hdmirx.h @@ -8,10 +8,12 @@ #ifndef DW_HDMIRX_H #define DW_HDMIRX_H +#include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/hw_bitfield.h> -#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) -#define HIWORD_UPDATE(v, h, l) (((v) << (l)) | (GENMASK((h), (l)) << 16)) +#define UPDATE(x, h, l) FIELD_PREP(GENMASK((h), (l)), (x)) +#define HIWORD_UPDATE(v, h, l) FIELD_PREP_WM16(GENMASK((h), (l)), (v)) /* SYS_GRF */ #define SYS_GRF_SOC_CON1 0x0304 diff --git a/drivers/media/platform/ti/Kconfig b/drivers/media/platform/ti/Kconfig index bab998c4179a..3bc4aa35887e 100644 --- a/drivers/media/platform/ti/Kconfig +++ b/drivers/media/platform/ti/Kconfig @@ -67,7 +67,8 @@ config VIDEO_TI_J721E_CSI2RX tristate "TI J721E CSI2RX wrapper layer driver" depends on VIDEO_DEV && VIDEO_V4L2_SUBDEV_API depends on MEDIA_SUPPORT && MEDIA_CONTROLLER - depends on (PHY_CADENCE_DPHY_RX && VIDEO_CADENCE_CSI2RX) || COMPILE_TEST + depends on VIDEO_CADENCE_CSI2RX + depends on PHY_CADENCE_DPHY_RX || COMPILE_TEST depends on ARCH_K3 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c index b644ed890412..3e25ce0c3c3b 100644 --- a/drivers/media/platform/ti/cal/cal.c +++ b/drivers/media/platform/ti/cal/cal.c @@ -1107,8 +1107,7 @@ static int cal_init_camerarx_regmap(struct cal_dev *cal) return 0; } - dev_warn(cal->dev, "failed to get ti,camerrx-control: %ld\n", - PTR_ERR(syscon)); + dev_warn(cal->dev, "failed to get ti,camerrx-control: %pe\n", syscon); /* * Backward DTS compatibility. If syscon entry is not present then diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c index d053972888d1..243c6196b024 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.c +++ b/drivers/media/platform/ti/davinci/vpif_capture.c @@ -1600,7 +1600,7 @@ err_cleanup: * This creates device entries by register itself to the V4L2 driver and * initializes fields of each channel objects */ -static __init int vpif_probe(struct platform_device *pdev) +static int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct i2c_adapter *i2c_adap; @@ -1807,7 +1807,7 @@ static int vpif_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(vpif_pm_ops, vpif_suspend, vpif_resume); -static __refdata struct platform_driver vpif_driver = { +static struct platform_driver vpif_driver = { .driver = { .name = VPIF_DRIVER_NAME, .pm = &vpif_pm_ops, diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c index 70c89549f4b6..1e7815e9f8e0 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.c +++ b/drivers/media/platform/ti/davinci/vpif_display.c @@ -1214,7 +1214,7 @@ probe_out: * vpif_probe: This function creates device entries by register itself to the * V4L2 driver and initializes fields of each channel objects */ -static __init int vpif_probe(struct platform_device *pdev) +static int vpif_probe(struct platform_device *pdev) { struct vpif_subdev_info *subdevdata; struct i2c_adapter *i2c_adap; @@ -1390,7 +1390,7 @@ static int vpif_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(vpif_pm_ops, vpif_suspend, vpif_resume); -static __refdata struct platform_driver vpif_driver = { +static struct platform_driver vpif_driver = { .driver = { .name = VPIF_DRIVER_NAME, .pm = &vpif_pm_ops, diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index b628d6e081db..b75aa363d1bf 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -13,7 +13,9 @@ #include <linux/module.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/property.h> +#include <media/cadence/cdns-csi2rx.h> #include <media/mipi-csi2.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> @@ -28,6 +30,7 @@ #define SHIM_DMACNTX 0x20 #define SHIM_DMACNTX_EN BIT(31) #define SHIM_DMACNTX_YUV422 GENMASK(27, 26) +#define SHIM_DMACNTX_DUAL_PCK_CFG BIT(24) #define SHIM_DMACNTX_SIZE GENMASK(21, 20) #define SHIM_DMACNTX_FMT GENMASK(5, 0) #define SHIM_DMACNTX_YUV422_MODE_11 3 @@ -39,6 +42,7 @@ #define SHIM_PSI_CFG0_SRC_TAG GENMASK(15, 0) #define SHIM_PSI_CFG0_DST_TAG GENMASK(31, 16) +#define TI_CSI2RX_MAX_PIX_PER_CLK 4 #define PSIL_WORD_SIZE_BYTES 16 /* * There are no hard limits on the width or height. The DMA engine can handle @@ -52,6 +56,8 @@ #define DRAIN_TIMEOUT_MS 50 #define DRAIN_BUFFER_SIZE SZ_32K +#define CSI2RX_BRIDGE_SOURCE_PAD 1 + struct ti_csi2rx_fmt { u32 fourcc; /* Four character code. */ u32 code; /* Mbus code. */ @@ -107,6 +113,7 @@ struct ti_csi2rx_dev { struct v4l2_format v_fmt; struct ti_csi2rx_dma dma; u32 sequence; + u8 pix_per_clk; }; static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { @@ -299,7 +306,7 @@ static int ti_csi2rx_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int ti_csi2rx_g_fmt_vid_cap(struct file *file, void *prov, +static int ti_csi2rx_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct ti_csi2rx_dev *csi = video_drvdata(file); @@ -426,8 +433,9 @@ static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier) if (ret) return ret; - ret = v4l2_create_fwnode_links_to_pad(csi->source, &csi->pad, - MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); + ret = media_create_pad_link(&csi->source->entity, CSI2RX_BRIDGE_SOURCE_PAD, + &vdev->entity, csi->pad.index, + MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); if (ret) { video_unregister_device(vdev); @@ -450,25 +458,23 @@ static int ti_csi2rx_notifier_register(struct ti_csi2rx_dev *csi) { struct fwnode_handle *fwnode; struct v4l2_async_connection *asc; - struct device_node *node; int ret; - node = of_get_child_by_name(csi->dev->of_node, "csi-bridge"); - if (!node) + fwnode = fwnode_get_named_child_node(csi->dev->fwnode, "csi-bridge"); + if (!fwnode) return -EINVAL; - fwnode = of_fwnode_handle(node); - if (!fwnode) { - of_node_put(node); - return -EINVAL; - } - v4l2_async_nf_init(&csi->notifier, &csi->v4l2_dev); csi->notifier.ops = &csi_async_notifier_ops; asc = v4l2_async_nf_add_fwnode(&csi->notifier, fwnode, struct v4l2_async_connection); - of_node_put(node); + /* + * Calling v4l2_async_nf_add_fwnode grabs a refcount, + * so drop the one we got in fwnode_get_named_child_node + */ + fwnode_handle_put(fwnode); + if (IS_ERR(asc)) { v4l2_async_nf_cleanup(&csi->notifier); return PTR_ERR(asc); @@ -483,6 +489,26 @@ static int ti_csi2rx_notifier_register(struct ti_csi2rx_dev *csi) return 0; } +/* Request maximum possible pixels per clock from the bridge */ +static void ti_csi2rx_request_max_ppc(struct ti_csi2rx_dev *csi) +{ + u8 ppc = TI_CSI2RX_MAX_PIX_PER_CLK; + struct media_pad *pad; + int ret; + + pad = media_entity_remote_source_pad_unique(&csi->vdev.entity); + if (IS_ERR(pad)) + return; + + ret = cdns_csi2rx_negotiate_ppc(csi->source, pad->index, &ppc); + if (ret) { + dev_warn(csi->dev, "NUM_PIXELS negotiation failed: %d\n", ret); + csi->pix_per_clk = 1; + } else { + csi->pix_per_clk = ppc; + } +} + static void ti_csi2rx_setup_shim(struct ti_csi2rx_dev *csi) { const struct ti_csi2rx_fmt *fmt; @@ -494,6 +520,9 @@ static void ti_csi2rx_setup_shim(struct ti_csi2rx_dev *csi) reg = SHIM_CNTL_PIX_RST; writel(reg, csi->shim + SHIM_CNTL); + /* Negotiate pixel count from the source */ + ti_csi2rx_request_max_ppc(csi); + reg = SHIM_DMACNTX_EN; reg |= FIELD_PREP(SHIM_DMACNTX_FMT, fmt->csi_dt); @@ -522,14 +551,18 @@ static void ti_csi2rx_setup_shim(struct ti_csi2rx_dev *csi) case V4L2_PIX_FMT_YVYU: reg |= FIELD_PREP(SHIM_DMACNTX_YUV422, SHIM_DMACNTX_YUV422_MODE_11); + /* Multiple pixels are handled differently for packed YUV */ + if (csi->pix_per_clk == 2) + reg |= SHIM_DMACNTX_DUAL_PCK_CFG; + reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, fmt->size); break; default: - /* Ignore if not YUV 4:2:2 */ + /* By default we change the shift size for multiple pixels */ + reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, + fmt->size + (csi->pix_per_clk >> 1)); break; } - reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, fmt->size); - writel(reg, csi->shim + SHIM_DMACNTX); reg = FIELD_PREP(SHIM_PSI_CFG0_SRC_TAG, 0) | @@ -1120,7 +1153,7 @@ static int ti_csi2rx_probe(struct platform_device *pdev) if (ret) goto err_vb2q; - ret = of_platform_populate(csi->dev->of_node, NULL, NULL, csi->dev); + ret = devm_of_platform_populate(csi->dev); if (ret) { dev_err(csi->dev, "Failed to create children: %d\n", ret); goto err_subdev; diff --git a/drivers/media/platform/ti/omap/omap_vout.c b/drivers/media/platform/ti/omap/omap_vout.c index a87d5030ac35..22782e9f1f4e 100644 --- a/drivers/media/platform/ti/omap/omap_vout.c +++ b/drivers/media/platform/ti/omap/omap_vout.c @@ -1236,7 +1236,7 @@ static int vidioc_g_fbuf(struct file *file, void *fh, return 0; } -static int vidioc_enum_output(struct file *file, void *priv_fh, +static int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out) { if (out->index) @@ -1246,13 +1246,13 @@ static int vidioc_enum_output(struct file *file, void *priv_fh, return 0; } -static int vidioc_g_output(struct file *file, void *priv_fh, unsigned int *i) +static int vidioc_g_output(struct file *file, void *priv, unsigned int *i) { *i = 0; return 0; } -static int vidioc_s_output(struct file *file, void *priv_fh, unsigned int i) +static int vidioc_s_output(struct file *file, void *priv, unsigned int i) { return i ? -EINVAL : 0; } diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c index f51cf6119e97..8ac2bdcdf87b 100644 --- a/drivers/media/platform/ti/omap3isp/isp.c +++ b/drivers/media/platform/ti/omap3isp/isp.c @@ -240,11 +240,11 @@ static u32 isp_xclk_calc_divider(unsigned long *rate, unsigned long parent_rate) return divider; } -static long isp_xclk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int isp_xclk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - isp_xclk_calc_divider(&rate, *parent_rate); - return rate; + isp_xclk_calc_divider(&req->rate, req->best_parent_rate); + return 0; } static int isp_xclk_set_rate(struct clk_hw *hw, unsigned long rate, @@ -275,7 +275,7 @@ static const struct clk_ops isp_xclk_ops = { .enable = isp_xclk_enable, .disable = isp_xclk_disable, .recalc_rate = isp_xclk_recalc_rate, - .round_rate = isp_xclk_round_rate, + .determine_rate = isp_xclk_determine_rate, .set_rate = isp_xclk_set_rate, }; diff --git a/drivers/media/platform/ti/omap3isp/ispccdc.c b/drivers/media/platform/ti/omap3isp/ispccdc.c index 7d0c723dcd11..55ee14e8b449 100644 --- a/drivers/media/platform/ti/omap3isp/ispccdc.c +++ b/drivers/media/platform/ti/omap3isp/ispccdc.c @@ -1873,12 +1873,6 @@ static int ccdc_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, return v4l2_event_subscribe(fh, sub, OMAP3ISP_CCDC_NEVENTS, NULL); } -static int ccdc_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return v4l2_event_unsubscribe(fh, sub); -} - /* * ccdc_set_stream - Enable/Disable streaming on the CCDC module * @sd: ISP CCDC V4L2 subdevice @@ -2487,7 +2481,7 @@ static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static const struct v4l2_subdev_core_ops ccdc_v4l2_core_ops = { .ioctl = ccdc_ioctl, .subscribe_event = ccdc_subscribe_event, - .unsubscribe_event = ccdc_unsubscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; /* V4L2 subdev video operations */ diff --git a/drivers/media/platform/ti/omap3isp/isph3a_aewb.c b/drivers/media/platform/ti/omap3isp/isph3a_aewb.c index e6c54c4bbfca..ae93da9c4542 100644 --- a/drivers/media/platform/ti/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/ti/omap3isp/isph3a_aewb.c @@ -269,7 +269,7 @@ static const struct ispstat_ops h3a_aewb_ops = { static const struct v4l2_subdev_core_ops h3a_aewb_subdev_core_ops = { .ioctl = h3a_aewb_ioctl, .subscribe_event = omap3isp_stat_subscribe_event, - .unsubscribe_event = omap3isp_stat_unsubscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops h3a_aewb_subdev_video_ops = { diff --git a/drivers/media/platform/ti/omap3isp/isph3a_af.c b/drivers/media/platform/ti/omap3isp/isph3a_af.c index de7b116d0122..ca478da4ad34 100644 --- a/drivers/media/platform/ti/omap3isp/isph3a_af.c +++ b/drivers/media/platform/ti/omap3isp/isph3a_af.c @@ -334,7 +334,7 @@ static const struct ispstat_ops h3a_af_ops = { static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = { .ioctl = h3a_af_ioctl, .subscribe_event = omap3isp_stat_subscribe_event, - .unsubscribe_event = omap3isp_stat_unsubscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = { diff --git a/drivers/media/platform/ti/omap3isp/isphist.c b/drivers/media/platform/ti/omap3isp/isphist.c index 0ef78aace6da..7851ad13d84f 100644 --- a/drivers/media/platform/ti/omap3isp/isphist.c +++ b/drivers/media/platform/ti/omap3isp/isphist.c @@ -456,7 +456,7 @@ static const struct ispstat_ops hist_ops = { static const struct v4l2_subdev_core_ops hist_subdev_core_ops = { .ioctl = hist_ioctl, .subscribe_event = omap3isp_stat_subscribe_event, - .unsubscribe_event = omap3isp_stat_unsubscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops hist_subdev_video_ops = { diff --git a/drivers/media/platform/ti/omap3isp/ispstat.c b/drivers/media/platform/ti/omap3isp/ispstat.c index d3da68408ecb..07bd62a93d99 100644 --- a/drivers/media/platform/ti/omap3isp/ispstat.c +++ b/drivers/media/platform/ti/omap3isp/ispstat.c @@ -1010,13 +1010,6 @@ int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, return v4l2_event_subscribe(fh, sub, STAT_NEVENTS, NULL); } -int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, - struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) -{ - return v4l2_event_unsubscribe(fh, sub); -} - void omap3isp_stat_unregister_entities(struct ispstat *stat) { v4l2_device_unregister_subdev(&stat->subdev); diff --git a/drivers/media/platform/ti/omap3isp/ispstat.h b/drivers/media/platform/ti/omap3isp/ispstat.h index b548e617cf62..59842c4a9c33 100644 --- a/drivers/media/platform/ti/omap3isp/ispstat.h +++ b/drivers/media/platform/ti/omap3isp/ispstat.h @@ -135,9 +135,6 @@ void omap3isp_stat_cleanup(struct ispstat *stat); int omap3isp_stat_subscribe_event(struct v4l2_subdev *subdev, struct v4l2_fh *fh, struct v4l2_event_subscription *sub); -int omap3isp_stat_unsubscribe_event(struct v4l2_subdev *subdev, - struct v4l2_fh *fh, - struct v4l2_event_subscription *sub); int omap3isp_stat_s_stream(struct v4l2_subdev *subdev, int enable); int omap3isp_stat_busy(struct ispstat *stat); diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c index 78e30298c7ad..0e7f0bf2b346 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.c +++ b/drivers/media/platform/ti/omap3isp/ispvideo.c @@ -657,7 +657,7 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) static int isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); if (format->type != video->type) @@ -673,7 +673,7 @@ isp_video_get_format(struct file *file, void *fh, struct v4l2_format *format) static int isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); struct v4l2_mbus_framefmt fmt; @@ -858,7 +858,7 @@ isp_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel) static int isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || @@ -876,7 +876,7 @@ isp_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) static int isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || @@ -894,7 +894,7 @@ isp_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a) static int isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); int ret; @@ -908,7 +908,7 @@ isp_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) static int isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); int ret; @@ -922,7 +922,7 @@ isp_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) static int isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); int ret; @@ -936,7 +936,7 @@ isp_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) static int isp_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); int ret; @@ -1074,7 +1074,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video, static int isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); enum isp_pipeline_state state; struct isp_pipeline *pipe; @@ -1180,7 +1180,7 @@ err_enum_init: static int isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) { - struct isp_video_fh *vfh = to_isp_video_fh(fh); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); struct isp_pipeline *pipe = to_isp_pipeline(&video->video.entity); enum isp_pipeline_state state; @@ -1297,7 +1297,7 @@ static int isp_video_open(struct file *file) return -ENOMEM; v4l2_fh_init(&handle->vfh, &video->video); - v4l2_fh_add(&handle->vfh); + v4l2_fh_add(&handle->vfh, file); /* If this is the first user, initialise the pipeline. */ if (omap3isp_get(video->isp) == NULL) { @@ -1333,11 +1333,10 @@ static int isp_video_open(struct file *file) handle->timeperframe.denominator = 1; handle->video = video; - file->private_data = &handle->vfh; done: if (ret < 0) { - v4l2_fh_del(&handle->vfh); + v4l2_fh_del(&handle->vfh, file); v4l2_fh_exit(&handle->vfh); kfree(handle); } @@ -1348,8 +1347,8 @@ done: static int isp_video_release(struct file *file) { struct isp_video *video = video_drvdata(file); - struct v4l2_fh *vfh = file->private_data; - struct isp_video_fh *handle = to_isp_video_fh(vfh); + struct v4l2_fh *vfh = file_to_v4l2_fh(file); + struct isp_video_fh *handle = file_to_isp_video_fh(file); /* Disable streaming and free the buffers queue resources. */ isp_video_streamoff(file, vfh, video->type); @@ -1361,10 +1360,9 @@ static int isp_video_release(struct file *file) v4l2_pipeline_pm_put(&video->video.entity); /* Release the file handle. */ - v4l2_fh_del(vfh); + v4l2_fh_del(vfh, file); v4l2_fh_exit(vfh); kfree(handle); - file->private_data = NULL; omap3isp_put(video->isp); @@ -1373,7 +1371,7 @@ static int isp_video_release(struct file *file) static __poll_t isp_video_poll(struct file *file, poll_table *wait) { - struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); struct isp_video *video = video_drvdata(file); __poll_t ret; @@ -1386,7 +1384,7 @@ static __poll_t isp_video_poll(struct file *file, poll_table *wait) static int isp_video_mmap(struct file *file, struct vm_area_struct *vma) { - struct isp_video_fh *vfh = to_isp_video_fh(file->private_data); + struct isp_video_fh *vfh = file_to_isp_video_fh(file); return vb2_mmap(&vfh->queue, vma); } diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.h b/drivers/media/platform/ti/omap3isp/ispvideo.h index 1d23df576e6b..537da59cff62 100644 --- a/drivers/media/platform/ti/omap3isp/ispvideo.h +++ b/drivers/media/platform/ti/omap3isp/ispvideo.h @@ -194,7 +194,11 @@ struct isp_video_fh { struct v4l2_fract timeperframe; }; -#define to_isp_video_fh(fh) container_of(fh, struct isp_video_fh, vfh) +static inline struct isp_video_fh *file_to_isp_video_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct isp_video_fh, vfh); +} + #define isp_video_queue_to_isp_video_fh(q) \ container_of(q, struct isp_video_fh, queue) diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c index 636d76ecebcd..1a549775cabe 100644 --- a/drivers/media/platform/ti/vpe/vpe.c +++ b/drivers/media/platform/ti/vpe/vpe.c @@ -422,6 +422,10 @@ struct vpe_ctx { unsigned int src_mv_buf_selector; }; +static inline struct vpe_ctx *to_vpe_ctx(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct vpe_ctx, fh); +} /* * M2M devices get 2 queues. @@ -1562,14 +1566,9 @@ static int vpe_enum_fmt(struct file *file, void *priv, static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct vpe_ctx *ctx = file->private_data; - struct vb2_queue *vq; + struct vpe_ctx *ctx = to_vpe_ctx(file); struct vpe_q_data *q_data; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - q_data = get_q_data(ctx, f->type); if (!q_data) return -EINVAL; @@ -1719,7 +1718,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); struct vpe_fmt *fmt = find_format(f); if (V4L2_TYPE_IS_OUTPUT(f->type)) @@ -1736,8 +1735,6 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) struct vb2_queue *vq; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; if (vb2_is_busy(vq)) { vpe_err(ctx->dev, "queue busy\n"); @@ -1783,7 +1780,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { int ret; - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); ret = vpe_try_fmt(file, priv, f); if (ret) @@ -1871,7 +1868,7 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) static int vpe_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); struct vpe_q_data *q_data; struct v4l2_pix_format_mplane *pix; bool use_c_rect = false; @@ -1935,7 +1932,7 @@ static int vpe_g_selection(struct file *file, void *fh, static int vpe_s_selection(struct file *file, void *fh, struct v4l2_selection *s) { - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); struct vpe_q_data *q_data; struct v4l2_selection sel = *s; int ret; @@ -2306,7 +2303,6 @@ static int vpe_open(struct file *file) init_adb_hdrs(ctx); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = ctx; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 1); @@ -2360,7 +2356,7 @@ static int vpe_open(struct file *file) goto exit_fh; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); /* * for now, just report the creation of the first instance, we can later @@ -2400,7 +2396,7 @@ free_ctx: static int vpe_release(struct file *file) { struct vpe_dev *dev = video_drvdata(file); - struct vpe_ctx *ctx = file->private_data; + struct vpe_ctx *ctx = to_vpe_ctx(file); vpe_dbg(dev, "releasing instance %p\n", ctx); @@ -2418,7 +2414,7 @@ static int vpe_release(struct file *file) vpdma_free_desc_buf(&ctx->sc_coeff_v); vpdma_free_desc_buf(&ctx->sc_coeff_h); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h index 81328c63b796..e0fdc4535b2d 100644 --- a/drivers/media/platform/verisilicon/hantro.h +++ b/drivers/media/platform/verisilicon/hantro.h @@ -382,9 +382,9 @@ extern int hantro_debug; pr_err("%s:%d: " fmt, __func__, __LINE__, ##args) /* Structure access helpers. */ -static __always_inline struct hantro_ctx *fh_to_ctx(struct v4l2_fh *fh) +static __always_inline struct hantro_ctx *file_to_ctx(struct file *filp) { - return container_of(fh, struct hantro_ctx, fh); + return container_of(file_to_v4l2_fh(filp), struct hantro_ctx, fh); } /* Register accessors. */ diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 8542238e0fb1..60b95b5d8565 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -89,7 +89,6 @@ static void hantro_job_finish(struct hantro_dev *vpu, struct hantro_ctx *ctx, enum vb2_buffer_state result) { - pm_runtime_mark_last_busy(vpu->dev); pm_runtime_put_autosuspend(vpu->dev); clk_bulk_disable(vpu->variant->num_clocks, vpu->clocks); @@ -184,7 +183,7 @@ static void device_run(void *priv) if (ret) goto err_cancel_job; - v4l2_m2m_buf_copy_metadata(src, dst, true); + v4l2_m2m_buf_copy_metadata(src, dst); if (ctx->codec_ops->run(ctx)) goto err_cancel_job; @@ -663,8 +662,7 @@ static int hantro_open(struct file *filp) } v4l2_fh_init(&ctx->fh, vdev); - filp->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, filp); hantro_reset_fmts(ctx); @@ -678,7 +676,7 @@ static int hantro_open(struct file *filp) return 0; err_fh_free: - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, filp); v4l2_fh_exit(&ctx->fh); err_ctx_free: kfree(ctx); @@ -687,15 +685,14 @@ err_ctx_free: static int hantro_release(struct file *filp) { - struct hantro_ctx *ctx = - container_of(filp->private_data, struct hantro_ctx, fh); + struct hantro_ctx *ctx = file_to_ctx(filp); /* * No need for extra locking because this was the last reference * to this file. */ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, filp); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_handler); kfree(ctx); @@ -918,6 +915,8 @@ static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) vpu->decoder = func; v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_G_SELECTION); + v4l2_disable_ioctl(vfd, VIDIOC_S_SELECTION); } video_set_drvdata(vfd, vpu); diff --git a/drivers/media/platform/verisilicon/hantro_g2.c b/drivers/media/platform/verisilicon/hantro_g2.c index aae0b562fabb..318673b66da8 100644 --- a/drivers/media/platform/verisilicon/hantro_g2.c +++ b/drivers/media/platform/verisilicon/hantro_g2.c @@ -5,43 +5,93 @@ * Copyright (C) 2021 Collabora Ltd, Andrzej Pietrasiewicz <andrzej.p@collabora.com> */ +#include <linux/delay.h> #include "hantro_hw.h" #include "hantro_g2_regs.h" #define G2_ALIGN 16 -void hantro_g2_check_idle(struct hantro_dev *vpu) +static bool hantro_g2_active(struct hantro_ctx *ctx) { - int i; - - for (i = 0; i < 3; i++) { - u32 status; - - /* Make sure the VPU is idle */ - status = vdpu_read(vpu, G2_REG_INTERRUPT); - if (status & G2_REG_INTERRUPT_DEC_E) { - dev_warn(vpu->dev, "device still running, aborting"); - status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS; - vdpu_write(vpu, status, G2_REG_INTERRUPT); - } + struct hantro_dev *vpu = ctx->dev; + u32 status; + + status = vdpu_read(vpu, G2_REG_INTERRUPT); + + return (status & G2_REG_INTERRUPT_DEC_E); +} + +/** + * hantro_g2_reset: + * @ctx: the hantro context + * + * Emulates a reset using Hantro abort function. Failing this procedure would + * results in programming a running IP which leads to CPU hang. + * + * Using a hard reset procedure instead is prefferred. + */ +void hantro_g2_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + u32 status; + + status = vdpu_read(vpu, G2_REG_INTERRUPT); + if (status & G2_REG_INTERRUPT_DEC_E) { + dev_warn_ratelimited(vpu->dev, "device still running, aborting"); + status |= G2_REG_INTERRUPT_DEC_ABORT_E | G2_REG_INTERRUPT_DEC_IRQ_DIS; + vdpu_write(vpu, status, G2_REG_INTERRUPT); + + do { + mdelay(1); + } while (hantro_g2_active(ctx)); } } irqreturn_t hantro_g2_irq(int irq, void *dev_id) { struct hantro_dev *vpu = dev_id; - enum vb2_buffer_state state; u32 status; status = vdpu_read(vpu, G2_REG_INTERRUPT); - state = (status & G2_REG_INTERRUPT_DEC_RDY_INT) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - vdpu_write(vpu, 0, G2_REG_INTERRUPT); - vdpu_write(vpu, G2_REG_CONFIG_DEC_CLK_GATE_E, G2_REG_CONFIG); + if (!(status & G2_REG_INTERRUPT_DEC_IRQ)) + return IRQ_NONE; + + hantro_reg_write(vpu, &g2_dec_irq, 0); + hantro_reg_write(vpu, &g2_dec_int_stat, 0); + hantro_reg_write(vpu, &g2_clk_gate_e, 1); + + if (status & G2_REG_INTERRUPT_DEC_RDY_INT) { + hantro_irq_done(vpu, VB2_BUF_STATE_DONE); + return IRQ_HANDLED; + } + + if (status & G2_REG_INTERRUPT_DEC_ABORT_INT) { + /* disabled on abort, though lets be safe and handle it */ + dev_warn_ratelimited(vpu->dev, "decode operation aborted."); + return IRQ_HANDLED; + } + + if (status & G2_REG_INTERRUPT_DEC_LAST_SLICE_INT) + dev_warn_ratelimited(vpu->dev, "not all macroblocks were decoded."); + + if (status & G2_REG_INTERRUPT_DEC_BUS_INT) + dev_warn_ratelimited(vpu->dev, "bus error detected."); + + if (status & G2_REG_INTERRUPT_DEC_ERROR_INT) + dev_warn_ratelimited(vpu->dev, "decode error detected."); + + if (status & G2_REG_INTERRUPT_DEC_TIMEOUT) + dev_warn_ratelimited(vpu->dev, "frame decode timed out."); - hantro_irq_done(vpu, state); + /** + * If the decoding haven't stopped, let it continue. The hardware timeout + * will trigger if it is trully stuck. + */ + if (status & G2_REG_INTERRUPT_DEC_E) + return IRQ_HANDLED; + hantro_irq_done(vpu, VB2_BUF_STATE_ERROR); return IRQ_HANDLED; } diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c index 0e212198dd65..e8c2e83379de 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c @@ -283,6 +283,15 @@ static void set_params(struct hantro_ctx *ctx) hantro_reg_write(vpu, &g2_apf_threshold, 8); } +static u32 get_dpb_index(const struct v4l2_ctrl_hevc_decode_params *decode_params, + const u32 index) +{ + if (index > decode_params->num_active_dpb_entries) + return 0; + + return index; +} + static void set_ref_pic_list(struct hantro_ctx *ctx) { const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; @@ -355,8 +364,10 @@ static void set_ref_pic_list(struct hantro_ctx *ctx) list1[j++] = list1[i++]; for (i = 0; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) { - hantro_reg_write(vpu, &ref_pic_regs0[i], list0[i]); - hantro_reg_write(vpu, &ref_pic_regs1[i], list1[i]); + hantro_reg_write(vpu, &ref_pic_regs0[i], + get_dpb_index(decode_params, list0[i])); + hantro_reg_write(vpu, &ref_pic_regs1[i], + get_dpb_index(decode_params, list1[i])); } } @@ -582,8 +593,6 @@ int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; int ret; - hantro_g2_check_idle(vpu); - /* Prepare HEVC decoder context. */ ret = hantro_hevc_dec_prepare_run(ctx); if (ret) diff --git a/drivers/media/platform/verisilicon/hantro_g2_regs.h b/drivers/media/platform/verisilicon/hantro_g2_regs.h index b943b1816db7..c614951121c7 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_regs.h +++ b/drivers/media/platform/verisilicon/hantro_g2_regs.h @@ -22,7 +22,14 @@ #define G2_REG_VERSION G2_SWREG(0) #define G2_REG_INTERRUPT G2_SWREG(1) +#define G2_REG_INTERRUPT_DEC_LAST_SLICE_INT BIT(19) +#define G2_REG_INTERRUPT_DEC_TIMEOUT BIT(18) +#define G2_REG_INTERRUPT_DEC_ERROR_INT BIT(16) +#define G2_REG_INTERRUPT_DEC_BUF_INT BIT(14) +#define G2_REG_INTERRUPT_DEC_BUS_INT BIT(13) #define G2_REG_INTERRUPT_DEC_RDY_INT BIT(12) +#define G2_REG_INTERRUPT_DEC_ABORT_INT BIT(11) +#define G2_REG_INTERRUPT_DEC_IRQ BIT(8) #define G2_REG_INTERRUPT_DEC_ABORT_E BIT(5) #define G2_REG_INTERRUPT_DEC_IRQ_DIS BIT(4) #define G2_REG_INTERRUPT_DEC_E BIT(0) @@ -35,6 +42,9 @@ #define BUS_WIDTH_128 2 #define BUS_WIDTH_256 3 +#define g2_dec_int_stat G2_DEC_REG(1, 11, 0xf) +#define g2_dec_irq G2_DEC_REG(1, 8, 0x1) + #define g2_strm_swap G2_DEC_REG(2, 28, 0xf) #define g2_strm_swap_old G2_DEC_REG(2, 27, 0x1f) #define g2_pic_swap G2_DEC_REG(2, 22, 0x1f) @@ -225,6 +235,9 @@ #define vp9_filt_level_seg5 G2_DEC_REG(19, 8, 0x3f) #define vp9_quant_seg5 G2_DEC_REG(19, 0, 0xff) +#define g2_timemout_override_e G2_DEC_REG(45, 31, 0x1) +#define g2_timemout_cycles G2_DEC_REG(45, 0, 0x7fffffff) + #define hevc_cur_poc_00 G2_DEC_REG(46, 24, 0xff) #define hevc_cur_poc_01 G2_DEC_REG(46, 16, 0xff) #define hevc_cur_poc_02 G2_DEC_REG(46, 8, 0xff) diff --git a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c index 82a478ac645e..56c79e339030 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_vp9_dec.c @@ -893,8 +893,6 @@ int hantro_g2_vp9_dec_run(struct hantro_ctx *ctx) struct vb2_v4l2_buffer *dst; int ret; - hantro_g2_check_idle(ctx->dev); - ret = start_prepare_run(ctx, &decode_params); if (ret) { hantro_end_prepare_run(ctx); diff --git a/drivers/media/platform/verisilicon/hantro_hw.h b/drivers/media/platform/verisilicon/hantro_hw.h index c9b6556f8b2b..5f2011529f02 100644 --- a/drivers/media/platform/verisilicon/hantro_hw.h +++ b/drivers/media/platform/verisilicon/hantro_hw.h @@ -583,6 +583,7 @@ void hantro_g2_vp9_dec_done(struct hantro_ctx *ctx); int hantro_vp9_dec_init(struct hantro_ctx *ctx); void hantro_vp9_dec_exit(struct hantro_ctx *ctx); void hantro_g2_check_idle(struct hantro_dev *vpu); +void hantro_g2_reset(struct hantro_ctx *ctx); irqreturn_t hantro_g2_irq(int irq, void *dev_id); #endif /* HANTRO_HW_H_ */ diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c index 7c3515cf7d64..fcf3bd9bcda2 100644 --- a/drivers/media/platform/verisilicon/hantro_v4l2.c +++ b/drivers/media/platform/verisilicon/hantro_v4l2.c @@ -185,7 +185,7 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); const struct hantro_fmt *fmt; fmt = hantro_find_format(ctx, fsize->pixel_format); @@ -217,7 +217,7 @@ static int vidioc_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f, bool capture) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); const struct hantro_fmt *fmt, *formats; unsigned int num_fmts, i, j = 0; bool skip_mode_none, enum_all_formats; @@ -297,7 +297,7 @@ static int vidioc_g_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); vpu_debug(4, "f->type = %d\n", f->type); @@ -310,7 +310,7 @@ static int vidioc_g_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); vpu_debug(4, "f->type = %d\n", f->type); @@ -398,13 +398,13 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx, static int vidioc_try_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - return hantro_try_fmt(fh_to_ctx(priv), &f->fmt.pix_mp, f->type); + return hantro_try_fmt(file_to_ctx(file), &f->fmt.pix_mp, f->type); } static int vidioc_try_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { - return hantro_try_fmt(fh_to_ctx(priv), &f->fmt.pix_mp, f->type); + return hantro_try_fmt(file_to_ctx(file), &f->fmt.pix_mp, f->type); } static void @@ -648,23 +648,22 @@ static int hantro_set_fmt_cap(struct hantro_ctx *ctx, static int vidioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { - return hantro_set_fmt_out(fh_to_ctx(priv), &f->fmt.pix_mp, HANTRO_AUTO_POSTPROC); + return hantro_set_fmt_out(file_to_ctx(file), &f->fmt.pix_mp, HANTRO_AUTO_POSTPROC); } static int vidioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - return hantro_set_fmt_cap(fh_to_ctx(priv), &f->fmt.pix_mp); + return hantro_set_fmt_cap(file_to_ctx(file), &f->fmt.pix_mp); } static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); /* Crop only supported on source. */ - if (!ctx->is_encoder || - sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; switch (sel->target) { @@ -691,13 +690,12 @@ static int vidioc_g_selection(struct file *file, void *priv, static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); struct v4l2_rect *rect = &sel->r; struct vb2_queue *vq; /* Crop only supported on source. */ - if (!ctx->is_encoder || - sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; /* Change not allowed if the queue is streaming. */ @@ -738,7 +736,7 @@ static const struct v4l2_event hantro_eos_event = { static int vidioc_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec) { - struct hantro_ctx *ctx = fh_to_ctx(priv); + struct hantro_ctx *ctx = file_to_ctx(file); int ret; ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, ec); diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c index 35799da534ed..5be0e2e76882 100644 --- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c +++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c @@ -234,24 +234,6 @@ static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = { }, }; -static irqreturn_t imx8m_vpu_g1_irq(int irq, void *dev_id) -{ - struct hantro_dev *vpu = dev_id; - enum vb2_buffer_state state; - u32 status; - - status = vdpu_read(vpu, G1_REG_INTERRUPT); - state = (status & G1_REG_INTERRUPT_DEC_RDY_INT) ? - VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - - vdpu_write(vpu, 0, G1_REG_INTERRUPT); - vdpu_write(vpu, G1_REG_CONFIG_DEC_CLK_GATE_E, G1_REG_CONFIG); - - hantro_irq_done(vpu, state); - - return IRQ_HANDLED; -} - static int imx8mq_vpu_hw_init(struct hantro_dev *vpu) { vpu->ctrl_base = vpu->reg_bases[vpu->variant->num_regs - 1]; @@ -312,11 +294,13 @@ static const struct hantro_codec_ops imx8mq_vpu_g1_codec_ops[] = { static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = { [HANTRO_MODE_HEVC_DEC] = { .run = hantro_g2_hevc_dec_run, + .reset = hantro_g2_reset, .init = hantro_hevc_dec_init, .exit = hantro_hevc_dec_exit, }, [HANTRO_MODE_VP9_DEC] = { .run = hantro_g2_vp9_dec_run, + .reset = hantro_g2_reset, .done = hantro_g2_vp9_dec_done, .init = hantro_vp9_dec_init, .exit = hantro_vp9_dec_exit, @@ -328,7 +312,7 @@ static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = { */ static const struct hantro_irq imx8mq_irqs[] = { - { "g1", imx8m_vpu_g1_irq }, + { "g1", hantro_g1_irq }, }; static const struct hantro_irq imx8mq_g2_irqs[] = { diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 18bfa6001909..fcfe0883aba5 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -469,7 +469,7 @@ static const struct vb2_ops xvip_dma_queue_qops = { static int xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); cap->capabilities = dma->xdev->v4l2_caps | V4L2_CAP_STREAMING | @@ -491,7 +491,7 @@ xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap) static int xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); if (f->index > 0) @@ -505,7 +505,7 @@ xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) static int xvip_dma_get_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); format->fmt.pix = dma->format; @@ -565,7 +565,7 @@ __xvip_dma_try_format(struct xvip_dma *dma, struct v4l2_pix_format *pix, static int xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); __xvip_dma_try_format(dma, &format->fmt.pix, NULL); @@ -575,7 +575,7 @@ xvip_dma_try_format(struct file *file, void *fh, struct v4l2_format *format) static int xvip_dma_set_format(struct file *file, void *fh, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct xvip_dma *dma = to_xvip_dma(vfh->vdev); const struct xvip_video_format *info; diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 72776d08046a..bbbdd054ba64 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -141,23 +141,6 @@ config RADIO_TIMBERDALE found behind the Timberdale FPGA on the Russellville board. Enabling this driver will automatically select the DSP and tuner. -config RADIO_WL1273 - tristate "Texas Instruments WL1273 I2C FM Radio" - depends on I2C - select MFD_CORE - select MFD_WL1273_CORE - select FW_LOADER - help - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - <file:Documentation/userspace-api/media/index.rst>. - - To compile this driver as a module, choose M here: the - module will be called radio-wl1273. - config USB_DSBR tristate "D-Link/GemTek USB FM radio support" depends on USB diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile index 1ff46f3a6ed3..f54693ebdb30 100644 --- a/drivers/media/radio/Makefile +++ b/drivers/media/radio/Makefile @@ -30,7 +30,6 @@ obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o -obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o obj-$(CONFIG_USB_DSBR) += dsbr100.o diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 3c8c17d64821..2c1d413e8636 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 <hansverk@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hverkuil@kernel.org> * 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-aztech.c b/drivers/media/radio/radio-aztech.c index d989c0b3966f..0a4667bb7034 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -2,7 +2,7 @@ /* * radio-aztech.c - Aztech radio card driver * - * Converted to the radio-isa framework by Hans Verkuil <hverkuil@xs4all.nl> + * Converted to the radio-isa framework by Hans Verkuil <hverkuil@kernel.org> * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org> * Adapted to support the Video for Linux API by * Russell Kroll <rkroll@exploits.org>. Based on original tuner code by: diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 5ca6274c45bd..a3265f1dd189 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 <hansverk@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hverkuil@kernel.org> * 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 4f87c76a2a96..1a144536ffa7 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 <hansverk@cisco.com> + * Copyright (C) 2012 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/module.h> diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h index 0f3db473da5e..62ff5c3fb5d5 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 <hansverk@cisco.com> + * Copyright (C) 2012 Hans Verkuil <hverkuil@kernel.org> */ #ifndef _RADIO_ISA_H_ diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c index a35648316aa8..f3b57f0cb1ec 100644 --- a/drivers/media/radio/radio-keene.c +++ b/drivers/media/radio/radio-keene.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2012 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (c) 2012 Hans Verkuil <hverkuil@kernel.org> */ /* kernel includes */ @@ -18,7 +18,7 @@ #include <linux/mutex.h> /* driver and module definitions */ -MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_DESCRIPTION("Keene FM Transmitter driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 27f058c5e677..67712ab3d564 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 <hansverk@cisco.com> + * Hans Verkuil <hverkuil@kernel.org> */ #include <linux/module.h> diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c index 64c7452c05b5..f60775b005e1 100644 --- a/drivers/media/radio/radio-raremono.c +++ b/drivers/media/radio/radio-raremono.c @@ -25,14 +25,14 @@ * * The USB protocol has been reversed engineered using wireshark, initially * by Dinesh Ram <dinesh.ram@cern.ch> and finished by Hans Verkuil - * <hverkuil@xs4all.nl>. + * <hverkuil@kernel.org>. * * Sadly the firmware used in this product hides lots of goodies since the * si4734 has more features than are supported by the firmware. Oh well... */ /* driver and module definitions */ -MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_DESCRIPTION("Thanko's Raremono AM/FM/SW Receiver USB driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 16b13a63bfed..efc02069bf9d 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 <hansverk@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hverkuil@kernel.org> * 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-terratec.c b/drivers/media/radio/radio-terratec.c index 720080634454..43817dd0a0fe 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 <hansverk@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hverkuil@kernel.org> * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org> */ diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c deleted file mode 100644 index f55217ccf2b8..000000000000 --- a/drivers/media/radio/radio-wl1273.c +++ /dev/null @@ -1,2159 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Driver for the Texas Instruments WL1273 FM radio. - * - * Copyright (C) 2011 Nokia Corporation - * Author: Matti J. Aaltonen <matti.j.aaltonen@nokia.com> - */ - -#include <linux/delay.h> -#include <linux/firmware.h> -#include <linux/interrupt.h> -#include <linux/mfd/wl1273-core.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> - -#define DRIVER_DESC "Wl1273 FM Radio" - -#define WL1273_POWER_SET_OFF 0 -#define WL1273_POWER_SET_FM BIT(0) -#define WL1273_POWER_SET_RDS BIT(1) -#define WL1273_POWER_SET_RETENTION BIT(4) - -#define WL1273_PUPD_SET_OFF 0x00 -#define WL1273_PUPD_SET_ON 0x01 -#define WL1273_PUPD_SET_RETENTION 0x10 - -#define WL1273_FREQ(x) (x * 10000 / 625) -#define WL1273_INV_FREQ(x) (x * 625 / 10000) - -/* - * static int radio_nr - The number of the radio device - * - * The default is 0. - */ -static int radio_nr; -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(radio_nr, "The number of the radio device. Default = 0"); - -struct wl1273_device { - char *bus_type; - - u8 forbidden; - unsigned int preemphasis; - unsigned int spacing; - unsigned int tx_power; - unsigned int rx_frequency; - unsigned int tx_frequency; - unsigned int rangelow; - unsigned int rangehigh; - unsigned int band; - bool stereo; - - /* RDS */ - unsigned int rds_on; - - wait_queue_head_t read_queue; - struct mutex lock; /* for serializing fm radio operations */ - struct completion busy; - - unsigned char *buffer; - unsigned int buf_size; - unsigned int rd_index; - unsigned int wr_index; - - /* Selected interrupts */ - u16 irq_flags; - u16 irq_received; - - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_device v4l2dev; - struct video_device videodev; - struct device *dev; - struct wl1273_core *core; - struct file *owner; - char *write_buf; - unsigned int rds_users; -}; - -#define WL1273_IRQ_MASK (WL1273_FR_EVENT | \ - WL1273_POW_ENB_EVENT) - -/* - * static unsigned int rds_buf - the number of RDS buffer blocks used. - * - * The default number is 100. - */ -static unsigned int rds_buf = 100; -module_param(rds_buf, uint, 0); -MODULE_PARM_DESC(rds_buf, "Number of RDS buffer entries. Default = 100"); - -static int wl1273_fm_write_fw(struct wl1273_core *core, - __u8 *fw, int len) -{ - struct i2c_client *client = core->client; - struct i2c_msg msg; - int i, r = 0; - - msg.addr = client->addr; - msg.flags = 0; - - for (i = 0; i <= len; i++) { - msg.len = fw[0]; - msg.buf = fw + 1; - - fw += msg.len + 1; - dev_dbg(&client->dev, "%s:len[%d]: %d\n", __func__, i, msg.len); - - r = i2c_transfer(client->adapter, &msg, 1); - if (r < 0 && i < len + 1) - break; - } - - dev_dbg(&client->dev, "%s: i: %d\n", __func__, i); - dev_dbg(&client->dev, "%s: len + 1: %d\n", __func__, len + 1); - - /* Last transfer always fails. */ - if (i == len || r == 1) - r = 0; - - return r; -} - -#define WL1273_FIFO_HAS_DATA(status) (1 << 5 & status) -#define WL1273_RDS_CORRECTABLE_ERROR (1 << 3) -#define WL1273_RDS_UNCORRECTABLE_ERROR (1 << 4) - -static int wl1273_fm_rds(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - struct i2c_client *client = core->client; - u16 val; - u8 b0 = WL1273_RDS_DATA_GET, status; - struct v4l2_rds_data rds = { 0, 0, 0 }; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .buf = &b0, - .len = 1, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .buf = (u8 *) &rds, - .len = sizeof(rds), - } - }; - int r; - - if (core->mode != WL1273_MODE_RX) - return 0; - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) - return r; - - if ((val & 0x01) == 0) { - /* RDS decoder not synchronized */ - return -EAGAIN; - } - - /* copy all four RDS blocks to internal buffer */ - do { - r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); - if (r != ARRAY_SIZE(msg)) { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME - ": %s: read_rds error r == %i)\n", - __func__, r); - } - - status = rds.block; - - if (!WL1273_FIFO_HAS_DATA(status)) - break; - - /* copy bits 0-2 (the block ID) to bits 3-5 */ - rds.block = V4L2_RDS_BLOCK_MSK & status; - rds.block |= rds.block << 3; - - /* copy the error bits to standard positions */ - if (WL1273_RDS_UNCORRECTABLE_ERROR & status) { - rds.block |= V4L2_RDS_BLOCK_ERROR; - rds.block &= ~V4L2_RDS_BLOCK_CORRECTED; - } else if (WL1273_RDS_CORRECTABLE_ERROR & status) { - rds.block &= ~V4L2_RDS_BLOCK_ERROR; - rds.block |= V4L2_RDS_BLOCK_CORRECTED; - } - - /* copy RDS block to internal buffer */ - memcpy(&radio->buffer[radio->wr_index], &rds, RDS_BLOCK_SIZE); - radio->wr_index += 3; - - /* wrap write pointer */ - if (radio->wr_index >= radio->buf_size) - radio->wr_index = 0; - - /* check for overflow & start over */ - if (radio->wr_index == radio->rd_index) { - dev_dbg(radio->dev, "RDS OVERFLOW"); - - radio->rd_index = 0; - radio->wr_index = 0; - break; - } - } while (WL1273_FIFO_HAS_DATA(status)); - - /* wake up read queue */ - if (radio->wr_index != radio->rd_index) - wake_up_interruptible(&radio->read_queue); - - return 0; -} - -static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id) -{ - struct wl1273_device *radio = dev_id; - struct wl1273_core *core = radio->core; - u16 flags; - int r; - - r = core->read(core, WL1273_FLAG_GET, &flags); - if (r) - goto out; - - if (flags & WL1273_BL_EVENT) { - radio->irq_received = flags; - dev_dbg(radio->dev, "IRQ: BL\n"); - } - - if (flags & WL1273_RDS_EVENT) { - msleep(200); - - wl1273_fm_rds(radio); - } - - if (flags & WL1273_BBLK_EVENT) - dev_dbg(radio->dev, "IRQ: BBLK\n"); - - if (flags & WL1273_LSYNC_EVENT) - dev_dbg(radio->dev, "IRQ: LSYNC\n"); - - if (flags & WL1273_LEV_EVENT) { - u16 level; - - r = core->read(core, WL1273_RSSI_LVL_GET, &level); - if (r) - goto out; - - if (level > 14) - dev_dbg(radio->dev, "IRQ: LEV: 0x%x04\n", level); - } - - if (flags & WL1273_IFFR_EVENT) - dev_dbg(radio->dev, "IRQ: IFFR\n"); - - if (flags & WL1273_PI_EVENT) - dev_dbg(radio->dev, "IRQ: PI\n"); - - if (flags & WL1273_PD_EVENT) - dev_dbg(radio->dev, "IRQ: PD\n"); - - if (flags & WL1273_STIC_EVENT) - dev_dbg(radio->dev, "IRQ: STIC\n"); - - if (flags & WL1273_MAL_EVENT) - dev_dbg(radio->dev, "IRQ: MAL\n"); - - if (flags & WL1273_POW_ENB_EVENT) { - complete(&radio->busy); - dev_dbg(radio->dev, "NOT BUSY\n"); - dev_dbg(radio->dev, "IRQ: POW_ENB\n"); - } - - if (flags & WL1273_SCAN_OVER_EVENT) - dev_dbg(radio->dev, "IRQ: SCAN_OVER\n"); - - if (flags & WL1273_ERROR_EVENT) - dev_dbg(radio->dev, "IRQ: ERROR\n"); - - if (flags & WL1273_FR_EVENT) { - u16 freq; - - dev_dbg(radio->dev, "IRQ: FR:\n"); - - if (core->mode == WL1273_MODE_RX) { - r = core->write(core, WL1273_TUNER_MODE_SET, - TUNER_MODE_STOP_SEARCH); - if (r) { - dev_err(radio->dev, - "%s: TUNER_MODE_SET fails: %d\n", - __func__, r); - goto out; - } - - r = core->read(core, WL1273_FREQ_SET, &freq); - if (r) - goto out; - - if (radio->band == WL1273_BAND_JAPAN) - radio->rx_frequency = WL1273_BAND_JAPAN_LOW + - freq * 50; - else - radio->rx_frequency = WL1273_BAND_OTHER_LOW + - freq * 50; - /* - * The driver works better with this msleep, - * the documentation doesn't mention it. - */ - usleep_range(10000, 15000); - - dev_dbg(radio->dev, "%dkHz\n", radio->rx_frequency); - - } else { - r = core->read(core, WL1273_CHANL_SET, &freq); - if (r) - goto out; - - dev_dbg(radio->dev, "%dkHz\n", freq); - } - dev_dbg(radio->dev, "%s: NOT BUSY\n", __func__); - } - -out: - core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - complete(&radio->busy); - - return IRQ_HANDLED; -} - -static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq) -{ - struct wl1273_core *core = radio->core; - int r = 0; - unsigned long t; - - if (freq < WL1273_BAND_TX_LOW) { - dev_err(radio->dev, - "Frequency out of range: %d < %d\n", freq, - WL1273_BAND_TX_LOW); - return -ERANGE; - } - - if (freq > WL1273_BAND_TX_HIGH) { - dev_err(radio->dev, - "Frequency out of range: %d > %d\n", freq, - WL1273_BAND_TX_HIGH); - return -ERANGE; - } - - /* - * The driver works better with this sleep, - * the documentation doesn't mention it. - */ - usleep_range(5000, 10000); - - dev_dbg(radio->dev, "%s: freq: %d kHz\n", __func__, freq); - - /* Set the current tx channel */ - r = core->write(core, WL1273_CHANL_SET, freq / 10); - if (r) - return r; - - reinit_completion(&radio->busy); - - /* wait for the FR IRQ */ - t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); - if (!t) - return -ETIMEDOUT; - - dev_dbg(radio->dev, "WL1273_CHANL_SET: %lu\n", t); - - /* Enable the output power */ - r = core->write(core, WL1273_POWER_ENB_SET, 1); - if (r) - return r; - - reinit_completion(&radio->busy); - - /* wait for the POWER_ENB IRQ */ - t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); - if (!t) - return -ETIMEDOUT; - - radio->tx_frequency = freq; - dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %lu\n", t); - - return 0; -} - -static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq) -{ - struct wl1273_core *core = radio->core; - int r, f; - unsigned long t; - - if (freq < radio->rangelow) { - dev_err(radio->dev, - "Frequency out of range: %d < %d\n", freq, - radio->rangelow); - r = -ERANGE; - goto err; - } - - if (freq > radio->rangehigh) { - dev_err(radio->dev, - "Frequency out of range: %d > %d\n", freq, - radio->rangehigh); - r = -ERANGE; - goto err; - } - - dev_dbg(radio->dev, "%s: %dkHz\n", __func__, freq); - - core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - - if (radio->band == WL1273_BAND_JAPAN) - f = (freq - WL1273_BAND_JAPAN_LOW) / 50; - else - f = (freq - WL1273_BAND_OTHER_LOW) / 50; - - r = core->write(core, WL1273_FREQ_SET, f); - if (r) { - dev_err(radio->dev, "FREQ_SET fails\n"); - goto err; - } - - r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET); - if (r) { - dev_err(radio->dev, "TUNER_MODE_SET fails\n"); - goto err; - } - - reinit_completion(&radio->busy); - - t = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000)); - if (!t) { - dev_err(radio->dev, "%s: TIMEOUT\n", __func__); - return -ETIMEDOUT; - } - - radio->rd_index = 0; - radio->wr_index = 0; - radio->rx_frequency = freq; - return 0; -err: - return r; -} - -static int wl1273_fm_get_freq(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - unsigned int freq; - u16 f; - int r; - - if (core->mode == WL1273_MODE_RX) { - r = core->read(core, WL1273_FREQ_SET, &f); - if (r) - return r; - - dev_dbg(radio->dev, "Freq get: 0x%04x\n", f); - if (radio->band == WL1273_BAND_JAPAN) - freq = WL1273_BAND_JAPAN_LOW + 50 * f; - else - freq = WL1273_BAND_OTHER_LOW + 50 * f; - } else { - r = core->read(core, WL1273_CHANL_SET, &f); - if (r) - return r; - - freq = f * 10; - } - - return freq; -} - -/** - * wl1273_fm_upload_firmware_patch() - Upload the firmware. - * @radio: A pointer to the device struct. - * - * The firmware file consists of arrays of bytes where the first byte - * gives the array length. The first byte in the file gives the - * number of these arrays. - */ -static int wl1273_fm_upload_firmware_patch(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - unsigned int packet_num; - const struct firmware *fw_p; - const char *fw_name = "radio-wl1273-fw.bin"; - struct device *dev = radio->dev; - __u8 *ptr; - int r; - - dev_dbg(dev, "%s:\n", __func__); - - /* - * Uploading the firmware patch is not always necessary, - * so we only print an info message. - */ - if (request_firmware(&fw_p, fw_name, dev)) { - dev_info(dev, "%s - %s not found\n", __func__, fw_name); - - return 0; - } - - ptr = (__u8 *) fw_p->data; - packet_num = ptr[0]; - dev_dbg(dev, "%s: packets: %d\n", __func__, packet_num); - - r = wl1273_fm_write_fw(core, ptr + 1, packet_num); - if (r) { - dev_err(dev, "FW upload error: %d\n", r); - goto out; - } - - /* ignore possible error here */ - core->write(core, WL1273_RESET, 0); - - dev_dbg(dev, "%s - download OK, r: %d\n", __func__, r); -out: - release_firmware(fw_p); - return r; -} - -static int wl1273_fm_stop(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - - if (core->mode == WL1273_MODE_RX) { - int r = core->write(core, WL1273_POWER_SET, - WL1273_POWER_SET_OFF); - if (r) - dev_err(radio->dev, "%s: POWER_SET fails: %d\n", - __func__, r); - } else if (core->mode == WL1273_MODE_TX) { - int r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_OFF); - if (r) - dev_err(radio->dev, - "%s: PUPD_SET fails: %d\n", __func__, r); - } - - if (core->pdata->disable) { - core->pdata->disable(); - dev_dbg(radio->dev, "Back to reset\n"); - } - - return 0; -} - -static int wl1273_fm_start(struct wl1273_device *radio, int new_mode) -{ - struct wl1273_core *core = radio->core; - struct wl1273_fm_platform_data *pdata = core->pdata; - struct device *dev = radio->dev; - int r = -EINVAL; - - if (pdata->enable && core->mode == WL1273_MODE_OFF) { - dev_dbg(radio->dev, "Out of reset\n"); - - pdata->enable(); - msleep(250); - } - - if (new_mode == WL1273_MODE_RX) { - u16 val = WL1273_POWER_SET_FM; - - if (radio->rds_on) - val |= WL1273_POWER_SET_RDS; - - /* If this fails try again */ - r = core->write(core, WL1273_POWER_SET, val); - if (r) { - msleep(100); - - r = core->write(core, WL1273_POWER_SET, val); - if (r) { - dev_err(dev, "%s: POWER_SET fails\n", __func__); - goto fail; - } - } - - /* rds buffer configuration */ - radio->wr_index = 0; - radio->rd_index = 0; - - } else if (new_mode == WL1273_MODE_TX) { - /* If this fails try again once */ - r = core->write(core, WL1273_PUPD_SET, WL1273_PUPD_SET_ON); - if (r) { - msleep(100); - r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_ON); - if (r) { - dev_err(dev, "%s: PUPD_SET fails\n", __func__); - goto fail; - } - } - - if (radio->rds_on) { - r = core->write(core, WL1273_RDS_DATA_ENB, 1); - if (r) { - dev_err(dev, "%s: RDS_DATA_ENB ON fails\n", - __func__); - goto fail; - } - } else { - r = core->write(core, WL1273_RDS_DATA_ENB, 0); - if (r) { - dev_err(dev, "%s: RDS_DATA_ENB OFF fails\n", - __func__); - goto fail; - } - } - } else { - dev_warn(dev, "%s: Illegal mode.\n", __func__); - } - - if (core->mode == WL1273_MODE_OFF) { - r = wl1273_fm_upload_firmware_patch(radio); - if (r) - dev_warn(dev, "Firmware upload failed.\n"); - - /* - * Sometimes the chip is in a wrong power state at this point. - * So we set the power once again. - */ - if (new_mode == WL1273_MODE_RX) { - u16 val = WL1273_POWER_SET_FM; - - if (radio->rds_on) - val |= WL1273_POWER_SET_RDS; - - r = core->write(core, WL1273_POWER_SET, val); - if (r) { - dev_err(dev, "%s: POWER_SET fails\n", __func__); - goto fail; - } - } else if (new_mode == WL1273_MODE_TX) { - r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_ON); - if (r) { - dev_err(dev, "%s: PUPD_SET fails\n", __func__); - goto fail; - } - } - } - - return 0; -fail: - if (pdata->disable) - pdata->disable(); - - dev_dbg(dev, "%s: return: %d\n", __func__, r); - return r; -} - -static int wl1273_fm_suspend(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - int r; - - /* Cannot go from OFF to SUSPENDED */ - if (core->mode == WL1273_MODE_RX) - r = core->write(core, WL1273_POWER_SET, - WL1273_POWER_SET_RETENTION); - else if (core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_PUPD_SET, - WL1273_PUPD_SET_RETENTION); - else - r = -EINVAL; - - if (r) { - dev_err(radio->dev, "%s: POWER_SET fails: %d\n", __func__, r); - goto out; - } - -out: - return r; -} - -static int wl1273_fm_set_mode(struct wl1273_device *radio, int mode) -{ - struct wl1273_core *core = radio->core; - struct device *dev = radio->dev; - int old_mode; - int r; - - dev_dbg(dev, "%s\n", __func__); - dev_dbg(dev, "Forbidden modes: 0x%02x\n", radio->forbidden); - - old_mode = core->mode; - if (mode & radio->forbidden) { - r = -EPERM; - goto out; - } - - switch (mode) { - case WL1273_MODE_RX: - case WL1273_MODE_TX: - r = wl1273_fm_start(radio, mode); - if (r) { - dev_err(dev, "%s: Cannot start.\n", __func__); - wl1273_fm_stop(radio); - goto out; - } - - core->mode = mode; - r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - if (r) { - dev_err(dev, "INT_MASK_SET fails.\n"); - goto out; - } - - /* remember previous settings */ - if (mode == WL1273_MODE_RX) { - r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); - if (r) { - dev_err(dev, "set freq fails: %d.\n", r); - goto out; - } - - r = core->set_volume(core, core->volume); - if (r) { - dev_err(dev, "set volume fails: %d.\n", r); - goto out; - } - - dev_dbg(dev, "%s: Set vol: %d.\n", __func__, - core->volume); - } else { - r = wl1273_fm_set_tx_freq(radio, radio->tx_frequency); - if (r) { - dev_err(dev, "set freq fails: %d.\n", r); - goto out; - } - } - - dev_dbg(radio->dev, "%s: Set audio mode.\n", __func__); - - r = core->set_audio(core, core->audio_mode); - if (r) - dev_err(dev, "Cannot set audio mode.\n"); - break; - - case WL1273_MODE_OFF: - r = wl1273_fm_stop(radio); - if (r) - dev_err(dev, "%s: Off fails: %d\n", __func__, r); - else - core->mode = WL1273_MODE_OFF; - - break; - - case WL1273_MODE_SUSPENDED: - r = wl1273_fm_suspend(radio); - if (r) - dev_err(dev, "%s: Suspend fails: %d\n", __func__, r); - else - core->mode = WL1273_MODE_SUSPENDED; - - break; - - default: - dev_err(dev, "%s: Unknown mode: %d\n", __func__, mode); - r = -EINVAL; - break; - } -out: - if (r) - core->mode = old_mode; - - return r; -} - -static int wl1273_fm_set_seek(struct wl1273_device *radio, - unsigned int wrap_around, - unsigned int seek_upward, - int level) -{ - struct wl1273_core *core = radio->core; - int r = 0; - unsigned int dir = (seek_upward == 0) ? 0 : 1; - unsigned int f; - - f = radio->rx_frequency; - dev_dbg(radio->dev, "rx_frequency: %d\n", f); - - if (dir && f + radio->spacing <= radio->rangehigh) - r = wl1273_fm_set_rx_freq(radio, f + radio->spacing); - else if (dir && wrap_around) - r = wl1273_fm_set_rx_freq(radio, radio->rangelow); - else if (f - radio->spacing >= radio->rangelow) - r = wl1273_fm_set_rx_freq(radio, f - radio->spacing); - else if (wrap_around) - r = wl1273_fm_set_rx_freq(radio, radio->rangehigh); - - if (r) - goto out; - - if (level < SCHAR_MIN || level > SCHAR_MAX) - return -EINVAL; - - reinit_completion(&radio->busy); - dev_dbg(radio->dev, "%s: BUSY\n", __func__); - - r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - if (r) - goto out; - - dev_dbg(radio->dev, "%s\n", __func__); - - r = core->write(core, WL1273_SEARCH_LVL_SET, level); - if (r) - goto out; - - r = core->write(core, WL1273_SEARCH_DIR_SET, dir); - if (r) - goto out; - - r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); - if (r) - goto out; - - /* wait for the FR IRQ */ - wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000)); - if (!(radio->irq_received & WL1273_BL_EVENT)) { - r = -ETIMEDOUT; - goto out; - } - - radio->irq_received &= ~WL1273_BL_EVENT; - - if (!wrap_around) - goto out; - - /* Wrap around */ - dev_dbg(radio->dev, "Wrap around in HW seek.\n"); - - if (seek_upward) - f = radio->rangelow; - else - f = radio->rangehigh; - - r = wl1273_fm_set_rx_freq(radio, f); - if (r) - goto out; - - reinit_completion(&radio->busy); - dev_dbg(radio->dev, "%s: BUSY\n", __func__); - - r = core->write(core, WL1273_TUNER_MODE_SET, TUNER_MODE_AUTO_SEEK); - if (r) - goto out; - - /* wait for the FR IRQ */ - if (!wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000))) - r = -ETIMEDOUT; -out: - dev_dbg(radio->dev, "%s: Err: %d\n", __func__, r); - return r; -} - -/** - * wl1273_fm_get_tx_ctune() - Get the TX tuning capacitor value. - * @radio: A pointer to the device struct. - */ -static unsigned int wl1273_fm_get_tx_ctune(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - struct device *dev = radio->dev; - u16 val; - int r; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - r = core->read(core, WL1273_READ_FMANT_TUNE_VALUE, &val); - if (r) { - dev_err(dev, "%s: read error: %d\n", __func__, r); - goto out; - } - -out: - return val; -} - -/** - * wl1273_fm_set_preemphasis() - Set the TX pre-emphasis value. - * @radio: A pointer to the device struct. - * @preemphasis: The new pre-amphasis value. - * - * Possible pre-emphasis values are: V4L2_PREEMPHASIS_DISABLED, - * V4L2_PREEMPHASIS_50_uS and V4L2_PREEMPHASIS_75_uS. - */ -static int wl1273_fm_set_preemphasis(struct wl1273_device *radio, - unsigned int preemphasis) -{ - struct wl1273_core *core = radio->core; - int r; - u16 em; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - mutex_lock(&core->lock); - - switch (preemphasis) { - case V4L2_PREEMPHASIS_DISABLED: - em = 1; - break; - case V4L2_PREEMPHASIS_50_uS: - em = 0; - break; - case V4L2_PREEMPHASIS_75_uS: - em = 2; - break; - default: - r = -EINVAL; - goto out; - } - - r = core->write(core, WL1273_PREMPH_SET, em); - if (r) - goto out; - - radio->preemphasis = preemphasis; - -out: - mutex_unlock(&core->lock); - return r; -} - -static int wl1273_fm_rds_on(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - if (radio->rds_on) - return 0; - - r = core->write(core, WL1273_POWER_SET, - WL1273_POWER_SET_FM | WL1273_POWER_SET_RDS); - if (r) - goto out; - - r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); - if (r) - dev_err(radio->dev, "set freq fails: %d.\n", r); -out: - return r; -} - -static int wl1273_fm_rds_off(struct wl1273_device *radio) -{ - struct wl1273_core *core = radio->core; - int r; - - if (!radio->rds_on) - return 0; - - radio->irq_flags &= ~WL1273_RDS_EVENT; - - r = core->write(core, WL1273_INT_MASK_SET, radio->irq_flags); - if (r) - goto out; - - /* Service pending read */ - wake_up_interruptible(&radio->read_queue); - - dev_dbg(radio->dev, "%s\n", __func__); - - r = core->write(core, WL1273_POWER_SET, WL1273_POWER_SET_FM); - if (r) - goto out; - - r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency); - if (r) - dev_err(radio->dev, "set freq fails: %d.\n", r); -out: - dev_dbg(radio->dev, "%s: exiting...\n", __func__); - - return r; -} - -static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode) -{ - int r = 0; - struct wl1273_core *core = radio->core; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - if (new_mode == WL1273_RDS_RESET) { - r = core->write(core, WL1273_RDS_CNTRL_SET, 1); - return r; - } - - if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_OFF) { - r = core->write(core, WL1273_RDS_DATA_ENB, 0); - } else if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_ON) { - r = core->write(core, WL1273_RDS_DATA_ENB, 1); - } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_OFF) { - r = wl1273_fm_rds_off(radio); - } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_ON) { - r = wl1273_fm_rds_on(radio); - } else { - dev_err(radio->dev, "%s: Unknown mode: %d\n", - __func__, new_mode); - r = -EINVAL; - } - - if (!r) - radio->rds_on = new_mode == WL1273_RDS_ON; - - return r; -} - -static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - u16 val; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (core->mode != WL1273_MODE_TX) - return count; - - if (radio->rds_users == 0) { - dev_warn(radio->dev, "%s: RDS not on.\n", __func__); - return 0; - } - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - /* - * Multiple processes can open the device, but only - * one gets to write to it. - */ - if (radio->owner && radio->owner != file) { - r = -EBUSY; - goto out; - } - radio->owner = file; - - /* Manual Mode */ - if (count > 255) - val = 255; - else - val = count; - - core->write(core, WL1273_RDS_CONFIG_DATA_SET, val); - - if (copy_from_user(radio->write_buf + 1, buf, val)) { - r = -EFAULT; - goto out; - } - - dev_dbg(radio->dev, "Count: %d\n", val); - dev_dbg(radio->dev, "From user: \"%s\"\n", radio->write_buf); - - radio->write_buf[0] = WL1273_RDS_DATA_SET; - core->write_data(core, radio->write_buf, val + 1); - - r = val; -out: - mutex_unlock(&core->lock); - - return r; -} - -static __poll_t wl1273_fm_fops_poll(struct file *file, - struct poll_table_struct *pts) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - - if (radio->owner && radio->owner != file) - return EPOLLERR; - - radio->owner = file; - - if (core->mode == WL1273_MODE_RX) { - poll_wait(file, &radio->read_queue, pts); - - if (radio->rd_index != radio->wr_index) - return EPOLLIN | EPOLLRDNORM; - - } else if (core->mode == WL1273_MODE_TX) { - return EPOLLOUT | EPOLLWRNORM; - } - - return 0; -} - -static int wl1273_fm_fops_open(struct file *file) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (core->mode == WL1273_MODE_RX && radio->rds_on && - !radio->rds_users) { - dev_dbg(radio->dev, "%s: Mode: %d\n", __func__, core->mode); - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - radio->irq_flags |= WL1273_RDS_EVENT; - - r = core->write(core, WL1273_INT_MASK_SET, - radio->irq_flags); - if (r) { - mutex_unlock(&core->lock); - goto out; - } - - radio->rds_users++; - - mutex_unlock(&core->lock); - } -out: - return r; -} - -static int wl1273_fm_fops_release(struct file *file) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (radio->rds_users > 0) { - radio->rds_users--; - if (radio->rds_users == 0) { - mutex_lock(&core->lock); - - radio->irq_flags &= ~WL1273_RDS_EVENT; - - if (core->mode == WL1273_MODE_RX) { - r = core->write(core, - WL1273_INT_MASK_SET, - radio->irq_flags); - if (r) { - mutex_unlock(&core->lock); - goto out; - } - } - mutex_unlock(&core->lock); - } - } - - if (file == radio->owner) - radio->owner = NULL; -out: - return r; -} - -static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - int r = 0; - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - unsigned int block_count = 0; - u16 val; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (core->mode != WL1273_MODE_RX) - return 0; - - if (radio->rds_users == 0) { - dev_warn(radio->dev, "%s: RDS not on.\n", __func__); - return 0; - } - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - /* - * Multiple processes can open the device, but only - * one at a time gets read access. - */ - if (radio->owner && radio->owner != file) { - r = -EBUSY; - goto out; - } - radio->owner = file; - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) { - dev_err(radio->dev, "%s: Get RDS_SYNC fails.\n", __func__); - goto out; - } else if (val == 0) { - dev_info(radio->dev, "RDS_SYNC: Not synchronized\n"); - r = -ENODATA; - goto out; - } - - /* block if no new data available */ - while (radio->wr_index == radio->rd_index) { - if (file->f_flags & O_NONBLOCK) { - r = -EWOULDBLOCK; - goto out; - } - - dev_dbg(radio->dev, "%s: Wait for RDS data.\n", __func__); - if (wait_event_interruptible(radio->read_queue, - radio->wr_index != - radio->rd_index) < 0) { - r = -EINTR; - goto out; - } - } - - /* calculate block count from byte count */ - count /= RDS_BLOCK_SIZE; - - /* copy RDS blocks from the internal buffer and to user buffer */ - while (block_count < count) { - if (radio->rd_index == radio->wr_index) - break; - - /* always transfer complete RDS blocks */ - if (copy_to_user(buf, &radio->buffer[radio->rd_index], - RDS_BLOCK_SIZE)) - break; - - /* increment and wrap the read pointer */ - radio->rd_index += RDS_BLOCK_SIZE; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - - /* increment counters */ - block_count++; - buf += RDS_BLOCK_SIZE; - r += RDS_BLOCK_SIZE; - } - -out: - dev_dbg(radio->dev, "%s: exit\n", __func__); - mutex_unlock(&core->lock); - - return r; -} - -static const struct v4l2_file_operations wl1273_fops = { - .owner = THIS_MODULE, - .read = wl1273_fm_fops_read, - .write = wl1273_fm_fops_write, - .poll = wl1273_fm_fops_poll, - .unlocked_ioctl = video_ioctl2, - .open = wl1273_fm_fops_open, - .release = wl1273_fm_fops_release, -}; - -static int wl1273_fm_vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *capability) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - strscpy(capability->driver, WL1273_FM_DRIVER_NAME, - sizeof(capability->driver)); - strscpy(capability->card, "TI Wl1273 FM Radio", - sizeof(capability->card)); - strscpy(capability->bus_info, radio->bus_type, - sizeof(capability->bus_info)); - return 0; -} - -static int wl1273_fm_vidioc_g_input(struct file *file, void *priv, - unsigned int *i) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - *i = 0; - - return 0; -} - -static int wl1273_fm_vidioc_s_input(struct file *file, void *priv, - unsigned int i) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - if (i != 0) - return -EINVAL; - - return 0; -} - -/** - * wl1273_fm_set_tx_power() - Set the transmission power value. - * @radio: A pointer to the device struct. - * @power: The new power value. - */ -static int wl1273_fm_set_tx_power(struct wl1273_device *radio, u16 power) -{ - struct wl1273_core *core = radio->core; - int r; - - if (core->mode == WL1273_MODE_OFF || - core->mode == WL1273_MODE_SUSPENDED) - return -EPERM; - - mutex_lock(&core->lock); - - /* Convert the dBuV value to chip presentation */ - r = core->write(core, WL1273_POWER_LEV_SET, 122 - power); - if (r) - goto out; - - radio->tx_power = power; - -out: - mutex_unlock(&core->lock); - return r; -} - -#define WL1273_SPACING_50kHz 1 -#define WL1273_SPACING_100kHz 2 -#define WL1273_SPACING_200kHz 4 - -static int wl1273_fm_tx_set_spacing(struct wl1273_device *radio, - unsigned int spacing) -{ - struct wl1273_core *core = radio->core; - int r; - - if (spacing == 0) { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_100kHz); - radio->spacing = 100; - } else if (spacing - 50000 < 25000) { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_50kHz); - radio->spacing = 50; - } else if (spacing - 100000 < 50000) { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_100kHz); - radio->spacing = 100; - } else { - r = core->write(core, WL1273_SCAN_SPACING_SET, - WL1273_SPACING_200kHz); - radio->spacing = 200; - } - - return r; -} - -static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct wl1273_device *radio = ctrl->priv; - struct wl1273_core *core = radio->core; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - switch (ctrl->id) { - case V4L2_CID_TUNE_ANTENNA_CAPACITOR: - ctrl->val = wl1273_fm_get_tx_ctune(radio); - break; - - default: - dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n", - __func__, ctrl->id); - break; - } - - mutex_unlock(&core->lock); - - return 0; -} - -#define WL1273_MUTE_SOFT_ENABLE (1 << 0) -#define WL1273_MUTE_AC (1 << 1) -#define WL1273_MUTE_HARD_LEFT (1 << 2) -#define WL1273_MUTE_HARD_RIGHT (1 << 3) -#define WL1273_MUTE_SOFT_FORCE (1 << 4) - -static inline struct wl1273_device *to_radio(struct v4l2_ctrl *ctrl) -{ - return container_of(ctrl->handler, struct wl1273_device, ctrl_handler); -} - -static int wl1273_fm_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct wl1273_device *radio = to_radio(ctrl); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - if (core->mode == WL1273_MODE_RX && ctrl->val) - r = core->write(core, - WL1273_MUTE_STATUS_SET, - WL1273_MUTE_HARD_LEFT | - WL1273_MUTE_HARD_RIGHT); - else if (core->mode == WL1273_MODE_RX) - r = core->write(core, - WL1273_MUTE_STATUS_SET, 0x0); - else if (core->mode == WL1273_MODE_TX && ctrl->val) - r = core->write(core, WL1273_MUTE, 1); - else if (core->mode == WL1273_MODE_TX) - r = core->write(core, WL1273_MUTE, 0); - - mutex_unlock(&core->lock); - break; - - case V4L2_CID_AUDIO_VOLUME: - if (ctrl->val == 0) - r = wl1273_fm_set_mode(radio, WL1273_MODE_OFF); - else - r = core->set_volume(core, core->volume); - break; - - case V4L2_CID_TUNE_PREEMPHASIS: - r = wl1273_fm_set_preemphasis(radio, ctrl->val); - break; - - case V4L2_CID_TUNE_POWER_LEVEL: - r = wl1273_fm_set_tx_power(radio, ctrl->val); - break; - - default: - dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n", - __func__, ctrl->id); - break; - } - - dev_dbg(radio->dev, "%s\n", __func__); - return r; -} - -static int wl1273_fm_vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *audio) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - if (audio->index > 1) - return -EINVAL; - - strscpy(audio->name, "Radio", sizeof(audio->name)); - audio->capability = V4L2_AUDCAP_STEREO; - - return 0; -} - -static int wl1273_fm_vidioc_s_audio(struct file *file, void *priv, - const struct v4l2_audio *audio) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - - dev_dbg(radio->dev, "%s\n", __func__); - - if (audio->index != 0) - return -EINVAL; - - return 0; -} - -#define WL1273_RDS_NOT_SYNCHRONIZED 0 -#define WL1273_RDS_SYNCHRONIZED 1 - -static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *tuner) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - u16 val; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (tuner->index > 0) - return -EINVAL; - - strscpy(tuner->name, WL1273_FM_DRIVER_NAME, sizeof(tuner->name)); - tuner->type = V4L2_TUNER_RADIO; - - tuner->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW); - tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH); - - tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO | - V4L2_TUNER_CAP_HWSEEK_BOUNDED | V4L2_TUNER_CAP_HWSEEK_WRAP; - - if (radio->stereo) - tuner->audmode = V4L2_TUNER_MODE_STEREO; - else - tuner->audmode = V4L2_TUNER_MODE_MONO; - - if (core->mode != WL1273_MODE_RX) - return 0; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = core->read(core, WL1273_STEREO_GET, &val); - if (r) - goto out; - - if (val == 1) - tuner->rxsubchans = V4L2_TUNER_SUB_STEREO; - else - tuner->rxsubchans = V4L2_TUNER_SUB_MONO; - - r = core->read(core, WL1273_RSSI_LVL_GET, &val); - if (r) - goto out; - - tuner->signal = (s16) val; - dev_dbg(radio->dev, "Signal: %d\n", tuner->signal); - - tuner->afc = 0; - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) - goto out; - - if (val == WL1273_RDS_SYNCHRONIZED) - tuner->rxsubchans |= V4L2_TUNER_SUB_RDS; -out: - mutex_unlock(&core->lock); - - return r; -} - -static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *tuner) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - dev_dbg(radio->dev, "tuner->index: %d\n", tuner->index); - dev_dbg(radio->dev, "tuner->name: %s\n", tuner->name); - dev_dbg(radio->dev, "tuner->capability: 0x%04x\n", tuner->capability); - dev_dbg(radio->dev, "tuner->rxsubchans: 0x%04x\n", tuner->rxsubchans); - dev_dbg(radio->dev, "tuner->rangelow: %d\n", tuner->rangelow); - dev_dbg(radio->dev, "tuner->rangehigh: %d\n", tuner->rangehigh); - - if (tuner->index > 0) - return -EINVAL; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = wl1273_fm_set_mode(radio, WL1273_MODE_RX); - if (r) - goto out; - - if (tuner->rxsubchans & V4L2_TUNER_SUB_RDS) - r = wl1273_fm_set_rds(radio, WL1273_RDS_ON); - else - r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF); - - if (r) - dev_warn(radio->dev, "%s: RDS fails: %d\n", __func__, r); - - if (tuner->audmode == V4L2_TUNER_MODE_MONO) { - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_MONO); - if (r < 0) { - dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", - __func__, r); - goto out; - } - radio->stereo = false; - } else if (tuner->audmode == V4L2_TUNER_MODE_STEREO) { - r = core->write(core, WL1273_MOST_MODE_SET, WL1273_RX_STEREO); - if (r < 0) { - dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n", - __func__, r); - goto out; - } - radio->stereo = true; - } else { - dev_err(radio->dev, "%s: tuner->audmode: %d\n", - __func__, tuner->audmode); - r = -EINVAL; - goto out; - } - -out: - mutex_unlock(&core->lock); - - return r; -} - -static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *freq) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - freq->type = V4L2_TUNER_RADIO; - freq->frequency = WL1273_FREQ(wl1273_fm_get_freq(radio)); - - mutex_unlock(&core->lock); - - return 0; -} - -static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *freq) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r; - - dev_dbg(radio->dev, "%s: %d\n", __func__, freq->frequency); - - if (freq->type != V4L2_TUNER_RADIO) { - dev_dbg(radio->dev, - "freq->type != V4L2_TUNER_RADIO: %d\n", freq->type); - return -EINVAL; - } - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - if (core->mode == WL1273_MODE_RX) { - dev_dbg(radio->dev, "freq: %d\n", freq->frequency); - - r = wl1273_fm_set_rx_freq(radio, - WL1273_INV_FREQ(freq->frequency)); - if (r) - dev_warn(radio->dev, WL1273_FM_DRIVER_NAME - ": set frequency failed with %d\n", r); - } else { - r = wl1273_fm_set_tx_freq(radio, - WL1273_INV_FREQ(freq->frequency)); - if (r) - dev_warn(radio->dev, WL1273_FM_DRIVER_NAME - ": set frequency failed with %d\n", r); - } - - mutex_unlock(&core->lock); - - dev_dbg(radio->dev, "wl1273_vidioc_s_frequency: DONE\n"); - return r; -} - -#define WL1273_DEFAULT_SEEK_LEVEL 7 - -static int wl1273_fm_vidioc_s_hw_freq_seek(struct file *file, void *priv, - const struct v4l2_hw_freq_seek *seek) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (seek->tuner != 0 || seek->type != V4L2_TUNER_RADIO) - return -EINVAL; - - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = wl1273_fm_set_mode(radio, WL1273_MODE_RX); - if (r) - goto out; - - r = wl1273_fm_tx_set_spacing(radio, seek->spacing); - if (r) - dev_warn(radio->dev, "HW seek failed: %d\n", r); - - r = wl1273_fm_set_seek(radio, seek->wrap_around, seek->seek_upward, - WL1273_DEFAULT_SEEK_LEVEL); - if (r) - dev_warn(radio->dev, "HW seek failed: %d\n", r); - -out: - mutex_unlock(&core->lock); - return r; -} - -static int wl1273_fm_vidioc_s_modulator(struct file *file, void *priv, - const struct v4l2_modulator *modulator) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - int r = 0; - - dev_dbg(radio->dev, "%s\n", __func__); - - if (modulator->index > 0) - return -EINVAL; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = wl1273_fm_set_mode(radio, WL1273_MODE_TX); - if (r) - goto out; - - if (modulator->txsubchans & V4L2_TUNER_SUB_RDS) - r = wl1273_fm_set_rds(radio, WL1273_RDS_ON); - else - r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF); - - if (modulator->txsubchans & V4L2_TUNER_SUB_MONO) - r = core->write(core, WL1273_MONO_SET, WL1273_TX_MONO); - else - r = core->write(core, WL1273_MONO_SET, - WL1273_RX_STEREO); - if (r < 0) - dev_warn(radio->dev, WL1273_FM_DRIVER_NAME - "MONO_SET fails: %d\n", r); -out: - mutex_unlock(&core->lock); - - return r; -} - -static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv, - struct v4l2_modulator *modulator) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - u16 val; - int r; - - dev_dbg(radio->dev, "%s\n", __func__); - - strscpy(modulator->name, WL1273_FM_DRIVER_NAME, - sizeof(modulator->name)); - - modulator->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW); - modulator->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH); - - modulator->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO; - - if (core->mode != WL1273_MODE_TX) - return 0; - - if (mutex_lock_interruptible(&core->lock)) - return -EINTR; - - r = core->read(core, WL1273_MONO_SET, &val); - if (r) - goto out; - - if (val == WL1273_TX_STEREO) - modulator->txsubchans = V4L2_TUNER_SUB_STEREO; - else - modulator->txsubchans = V4L2_TUNER_SUB_MONO; - - if (radio->rds_on) - modulator->txsubchans |= V4L2_TUNER_SUB_RDS; -out: - mutex_unlock(&core->lock); - - return 0; -} - -static int wl1273_fm_vidioc_log_status(struct file *file, void *priv) -{ - struct wl1273_device *radio = video_get_drvdata(video_devdata(file)); - struct wl1273_core *core = radio->core; - struct device *dev = radio->dev; - u16 val; - int r; - - dev_info(dev, DRIVER_DESC); - - if (core->mode == WL1273_MODE_OFF) { - dev_info(dev, "Mode: Off\n"); - return 0; - } - - if (core->mode == WL1273_MODE_SUSPENDED) { - dev_info(dev, "Mode: Suspended\n"); - return 0; - } - - r = core->read(core, WL1273_ASIC_ID_GET, &val); - if (r) - dev_err(dev, "%s: Get ASIC_ID fails.\n", __func__); - else - dev_info(dev, "ASIC_ID: 0x%04x\n", val); - - r = core->read(core, WL1273_ASIC_VER_GET, &val); - if (r) - dev_err(dev, "%s: Get ASIC_VER fails.\n", __func__); - else - dev_info(dev, "ASIC Version: 0x%04x\n", val); - - r = core->read(core, WL1273_FIRM_VER_GET, &val); - if (r) - dev_err(dev, "%s: Get FIRM_VER fails.\n", __func__); - else - dev_info(dev, "FW version: %d(0x%04x)\n", val, val); - - r = core->read(core, WL1273_BAND_SET, &val); - if (r) - dev_err(dev, "%s: Get BAND fails.\n", __func__); - else - dev_info(dev, "BAND: %d\n", val); - - if (core->mode == WL1273_MODE_TX) { - r = core->read(core, WL1273_PUPD_SET, &val); - if (r) - dev_err(dev, "%s: Get PUPD fails.\n", __func__); - else - dev_info(dev, "PUPD: 0x%04x\n", val); - - r = core->read(core, WL1273_CHANL_SET, &val); - if (r) - dev_err(dev, "%s: Get CHANL fails.\n", __func__); - else - dev_info(dev, "Tx frequency: %dkHz\n", val*10); - } else if (core->mode == WL1273_MODE_RX) { - int bf = radio->rangelow; - - r = core->read(core, WL1273_FREQ_SET, &val); - if (r) - dev_err(dev, "%s: Get FREQ fails.\n", __func__); - else - dev_info(dev, "RX Frequency: %dkHz\n", bf + val*50); - - r = core->read(core, WL1273_MOST_MODE_SET, &val); - if (r) - dev_err(dev, "%s: Get MOST_MODE fails.\n", - __func__); - else if (val == 0) - dev_info(dev, "MOST_MODE: Stereo according to blend\n"); - else if (val == 1) - dev_info(dev, "MOST_MODE: Force mono output\n"); - else - dev_info(dev, "MOST_MODE: Unexpected value: %d\n", val); - - r = core->read(core, WL1273_MOST_BLEND_SET, &val); - if (r) - dev_err(dev, "%s: Get MOST_BLEND fails.\n", __func__); - else if (val == 0) - dev_info(dev, - "MOST_BLEND: Switched blend & hysteresis.\n"); - else if (val == 1) - dev_info(dev, "MOST_BLEND: Soft blend.\n"); - else - dev_info(dev, "MOST_BLEND: Unexpected val: %d\n", val); - - r = core->read(core, WL1273_STEREO_GET, &val); - if (r) - dev_err(dev, "%s: Get STEREO fails.\n", __func__); - else if (val == 0) - dev_info(dev, "STEREO: Not detected\n"); - else if (val == 1) - dev_info(dev, "STEREO: Detected\n"); - else - dev_info(dev, "STEREO: Unexpected value: %d\n", val); - - r = core->read(core, WL1273_RSSI_LVL_GET, &val); - if (r) - dev_err(dev, "%s: Get RSSI_LVL fails.\n", __func__); - else - dev_info(dev, "RX signal strength: %d\n", (s16) val); - - r = core->read(core, WL1273_POWER_SET, &val); - if (r) - dev_err(dev, "%s: Get POWER fails.\n", __func__); - else - dev_info(dev, "POWER: 0x%04x\n", val); - - r = core->read(core, WL1273_INT_MASK_SET, &val); - if (r) - dev_err(dev, "%s: Get INT_MASK fails.\n", __func__); - else - dev_info(dev, "INT_MASK: 0x%04x\n", val); - - r = core->read(core, WL1273_RDS_SYNC_GET, &val); - if (r) - dev_err(dev, "%s: Get RDS_SYNC fails.\n", - __func__); - else if (val == 0) - dev_info(dev, "RDS_SYNC: Not synchronized\n"); - - else if (val == 1) - dev_info(dev, "RDS_SYNC: Synchronized\n"); - else - dev_info(dev, "RDS_SYNC: Unexpected value: %d\n", val); - - r = core->read(core, WL1273_I2S_MODE_CONFIG_SET, &val); - if (r) - dev_err(dev, "%s: Get I2S_MODE_CONFIG fails.\n", - __func__); - else - dev_info(dev, "I2S_MODE_CONFIG: 0x%04x\n", val); - - r = core->read(core, WL1273_VOLUME_SET, &val); - if (r) - dev_err(dev, "%s: Get VOLUME fails.\n", __func__); - else - dev_info(dev, "VOLUME: 0x%04x\n", val); - } - - return 0; -} - -static void wl1273_vdev_release(struct video_device *dev) -{ -} - -static const struct v4l2_ctrl_ops wl1273_ctrl_ops = { - .s_ctrl = wl1273_fm_s_ctrl, - .g_volatile_ctrl = wl1273_fm_g_volatile_ctrl, -}; - -static const struct v4l2_ioctl_ops wl1273_ioctl_ops = { - .vidioc_querycap = wl1273_fm_vidioc_querycap, - .vidioc_g_input = wl1273_fm_vidioc_g_input, - .vidioc_s_input = wl1273_fm_vidioc_s_input, - .vidioc_g_audio = wl1273_fm_vidioc_g_audio, - .vidioc_s_audio = wl1273_fm_vidioc_s_audio, - .vidioc_g_tuner = wl1273_fm_vidioc_g_tuner, - .vidioc_s_tuner = wl1273_fm_vidioc_s_tuner, - .vidioc_g_frequency = wl1273_fm_vidioc_g_frequency, - .vidioc_s_frequency = wl1273_fm_vidioc_s_frequency, - .vidioc_s_hw_freq_seek = wl1273_fm_vidioc_s_hw_freq_seek, - .vidioc_g_modulator = wl1273_fm_vidioc_g_modulator, - .vidioc_s_modulator = wl1273_fm_vidioc_s_modulator, - .vidioc_log_status = wl1273_fm_vidioc_log_status, -}; - -static const struct video_device wl1273_viddev_template = { - .fops = &wl1273_fops, - .ioctl_ops = &wl1273_ioctl_ops, - .name = WL1273_FM_DRIVER_NAME, - .release = wl1273_vdev_release, - .vfl_dir = VFL_DIR_TX, - .device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | - V4L2_CAP_RADIO | V4L2_CAP_AUDIO | - V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR | - V4L2_CAP_RDS_OUTPUT, -}; - -static void wl1273_fm_radio_remove(struct platform_device *pdev) -{ - struct wl1273_device *radio = platform_get_drvdata(pdev); - struct wl1273_core *core = radio->core; - - dev_info(&pdev->dev, "%s.\n", __func__); - - free_irq(core->client->irq, radio); - core->pdata->free_resources(); - - v4l2_ctrl_handler_free(&radio->ctrl_handler); - video_unregister_device(&radio->videodev); - v4l2_device_unregister(&radio->v4l2dev); -} - -static int wl1273_fm_radio_probe(struct platform_device *pdev) -{ - struct wl1273_core **core = pdev->dev.platform_data; - struct wl1273_device *radio; - struct v4l2_ctrl *ctrl; - int r = 0; - - pr_debug("%s\n", __func__); - - if (!core) { - dev_err(&pdev->dev, "No platform data.\n"); - r = -EINVAL; - goto pdata_err; - } - - radio = devm_kzalloc(&pdev->dev, sizeof(*radio), GFP_KERNEL); - if (!radio) { - r = -ENOMEM; - goto pdata_err; - } - - /* RDS buffer allocation */ - radio->buf_size = rds_buf * RDS_BLOCK_SIZE; - radio->buffer = devm_kzalloc(&pdev->dev, radio->buf_size, GFP_KERNEL); - if (!radio->buffer) { - pr_err("Cannot allocate memory for RDS buffer.\n"); - r = -ENOMEM; - goto pdata_err; - } - - radio->core = *core; - radio->irq_flags = WL1273_IRQ_MASK; - radio->dev = &radio->core->client->dev; - radio->rds_on = false; - radio->core->mode = WL1273_MODE_OFF; - radio->tx_power = 118; - radio->core->audio_mode = WL1273_AUDIO_ANALOG; - radio->band = WL1273_BAND_OTHER; - radio->core->i2s_mode = WL1273_I2S_DEF_MODE; - radio->core->channel_number = 2; - radio->core->volume = WL1273_DEFAULT_VOLUME; - radio->rx_frequency = WL1273_BAND_OTHER_LOW; - radio->tx_frequency = WL1273_BAND_OTHER_HIGH; - radio->rangelow = WL1273_BAND_OTHER_LOW; - radio->rangehigh = WL1273_BAND_OTHER_HIGH; - radio->stereo = true; - radio->bus_type = "I2C"; - - if (radio->core->pdata->request_resources) { - r = radio->core->pdata->request_resources(radio->core->client); - if (r) { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME - ": Cannot get platform data\n"); - goto pdata_err; - } - - dev_dbg(radio->dev, "irq: %d\n", radio->core->client->irq); - - r = request_threaded_irq(radio->core->client->irq, NULL, - wl1273_fm_irq_thread_handler, - IRQF_ONESHOT | IRQF_TRIGGER_FALLING, - "wl1273-fm", radio); - if (r < 0) { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME - ": Unable to register IRQ handler: %d\n", r); - goto err_request_irq; - } - } else { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ not configured"); - r = -EINVAL; - goto pdata_err; - } - - init_completion(&radio->busy); - init_waitqueue_head(&radio->read_queue); - - radio->write_buf = devm_kzalloc(&pdev->dev, 256, GFP_KERNEL); - if (!radio->write_buf) { - r = -ENOMEM; - goto write_buf_err; - } - - radio->dev = &pdev->dev; - radio->v4l2dev.ctrl_handler = &radio->ctrl_handler; - radio->rds_users = 0; - - r = v4l2_device_register(&pdev->dev, &radio->v4l2dev); - if (r) { - dev_err(&pdev->dev, "Cannot register v4l2_device.\n"); - goto write_buf_err; - } - - /* V4L2 configuration */ - radio->videodev = wl1273_viddev_template; - - radio->videodev.v4l2_dev = &radio->v4l2dev; - - v4l2_ctrl_handler_init(&radio->ctrl_handler, 6); - - /* add in ascending ID order */ - v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_AUDIO_VOLUME, 0, WL1273_MAX_VOLUME, 1, - WL1273_DEFAULT_VOLUME); - - v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); - - v4l2_ctrl_new_std_menu(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_TUNE_PREEMPHASIS, - V4L2_PREEMPHASIS_75_uS, 0x03, - V4L2_PREEMPHASIS_50_uS); - - v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_TUNE_POWER_LEVEL, 91, 122, 1, 118); - - ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops, - V4L2_CID_TUNE_ANTENNA_CAPACITOR, - 0, 255, 1, 255); - if (ctrl) - ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - - if (radio->ctrl_handler.error) { - r = radio->ctrl_handler.error; - dev_err(&pdev->dev, "Ctrl handler error: %d\n", r); - goto handler_init_err; - } - - video_set_drvdata(&radio->videodev, radio); - platform_set_drvdata(pdev, radio); - - /* register video device */ - r = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); - if (r) { - dev_err(&pdev->dev, WL1273_FM_DRIVER_NAME - ": Could not register video device\n"); - goto handler_init_err; - } - - return 0; - -handler_init_err: - v4l2_ctrl_handler_free(&radio->ctrl_handler); - v4l2_device_unregister(&radio->v4l2dev); -write_buf_err: - free_irq(radio->core->client->irq, radio); -err_request_irq: - radio->core->pdata->free_resources(); -pdata_err: - return r; -} - -static struct platform_driver wl1273_fm_radio_driver = { - .probe = wl1273_fm_radio_probe, - .remove = wl1273_fm_radio_remove, - .driver = { - .name = "wl1273_fm_radio", - }, -}; - -module_platform_driver(wl1273_fm_radio_driver); - -MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>"); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:wl1273_fm_radio"); diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index 099b7af6a410..e043bee52384 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 <hansverk@cisco.com> + * Converted to the radio-isa framework by Hans Verkuil <hverkuil@kernel.org> * * 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/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index cdd2ac198f2c..3932a449a1b1 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -10,7 +10,7 @@ /* driver definitions */ -#define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>"; +#define DRIVER_AUTHOR "Joonyoung Shim <jy0922.shim@samsung.com>" #define DRIVER_CARD "Silicon Labs Si470x FM Radio" #define DRIVER_DESC "I2C radio driver for Si470x FM Radio Receivers" #define DRIVER_VERSION "1.0.2" diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c index 67b4afadc95a..4132968110e3 100644 --- a/drivers/media/radio/si4713/radio-platform-si4713.c +++ b/drivers/media/radio/si4713/radio-platform-si4713.c @@ -75,35 +75,35 @@ static inline struct v4l2_device *get_v4l2_dev(struct file *file) return &((struct radio_si4713_device *)video_drvdata(file))->v4l2_dev; } -static int radio_si4713_g_modulator(struct file *file, void *p, +static int radio_si4713_g_modulator(struct file *file, void *priv, struct v4l2_modulator *vm) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, g_modulator, vm); } -static int radio_si4713_s_modulator(struct file *file, void *p, +static int radio_si4713_s_modulator(struct file *file, void *priv, const struct v4l2_modulator *vm) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, s_modulator, vm); } -static int radio_si4713_g_frequency(struct file *file, void *p, +static int radio_si4713_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, g_frequency, vf); } -static int radio_si4713_s_frequency(struct file *file, void *p, +static int radio_si4713_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, tuner, s_frequency, vf); } -static long radio_si4713_default(struct file *file, void *p, +static long radio_si4713_default(struct file *file, void *priv, bool valid_prio, unsigned int cmd, void *arg) { return v4l2_device_call_until_err(get_v4l2_dev(file), 0, core, diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index bf6d8fa983bf..a6418ef782bc 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -48,10 +48,8 @@ static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) if (val >= 0) ir_raw_event_store_edge(gpio_dev->rcdev, val == 1); - if (pmdev) { - pm_runtime_mark_last_busy(pmdev); + if (pmdev) pm_runtime_put_autosuspend(pmdev); - } return IRQ_HANDLED; } diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index f5221b018808..35b9e07003d8 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -39,11 +39,6 @@ #define DISPLAY_MINOR_BASE 144 #define DEVICE_NAME "lcd%d" -#define BUF_CHUNK_SIZE 8 -#define BUF_SIZE 128 - -#define BIT_DURATION 250 /* each bit received is 250us */ - #define IMON_CLOCK_ENABLE_PACKETS 2 /*** P R O T O T Y P E S ***/ @@ -536,7 +531,9 @@ static int display_open(struct inode *inode, struct file *file) mutex_lock(&ictx->lock); - if (!ictx->display_supported) { + if (ictx->disconnected) { + retval = -ENODEV; + } else if (!ictx->display_supported) { pr_err("display not supported by device\n"); retval = -ENODEV; } else if (ictx->display_isopen) { @@ -598,6 +595,11 @@ static int send_packet(struct imon_context *ictx) int retval = 0; struct usb_ctrlrequest *control_req = NULL; + lockdep_assert_held(&ictx->lock); + + if (ictx->disconnected) + return -ENODEV; + /* Check if we need to use control or interrupt urb */ if (!ictx->tx_control) { pipe = usb_sndintpipe(ictx->usbdev_intf0, @@ -645,12 +647,15 @@ static int send_packet(struct imon_context *ictx) smp_rmb(); /* ensure later readers know we're not busy */ pr_err_ratelimited("error submitting urb(%d)\n", retval); } else { - /* Wait for transmission to complete (or abort) */ - retval = wait_for_completion_interruptible( - &ictx->tx.finished); - if (retval) { + /* Wait for transmission to complete (or abort or timeout) */ + retval = wait_for_completion_interruptible_timeout(&ictx->tx.finished, 10 * HZ); + if (retval <= 0) { usb_kill_urb(ictx->tx_urb); pr_err_ratelimited("task interrupted\n"); + if (retval < 0) + ictx->tx.status = retval; + else + ictx->tx.status = -ETIMEDOUT; } ictx->tx.busy = false; @@ -949,12 +954,14 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, static const unsigned char vfd_packet6[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; - if (ictx->disconnected) - return -ENODEV; - if (mutex_lock_interruptible(&ictx->lock)) return -ERESTARTSYS; + if (ictx->disconnected) { + retval = -ENODEV; + goto exit; + } + if (!ictx->dev_present_intf0) { pr_err_ratelimited("no iMON device present\n"); retval = -ENODEV; @@ -1029,11 +1036,13 @@ static ssize_t lcd_write(struct file *file, const char __user *buf, int retval = 0; struct imon_context *ictx = file->private_data; - if (ictx->disconnected) - return -ENODEV; - mutex_lock(&ictx->lock); + if (ictx->disconnected) { + retval = -ENODEV; + goto exit; + } + if (!ictx->display_supported) { pr_err_ratelimited("no iMON display present\n"); retval = -ENODEV; @@ -1121,7 +1130,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto) int retval; struct imon_context *ictx = rc->priv; struct device *dev = ictx->dev; - bool unlock = false; + const bool unlock = mutex_trylock(&ictx->lock); unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; @@ -1148,8 +1157,6 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto) memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); - unlock = mutex_trylock(&ictx->lock); - retval = send_packet(ictx); if (retval) goto out; @@ -1745,14 +1752,6 @@ static void usb_rx_callback_intf0(struct urb *urb) if (!ictx) return; - /* - * if we get a callback before we're done configuring the hardware, we - * can't yet process the data, as there's nowhere to send it, but we - * still need to submit a new rx URB to avoid wedging the hardware - */ - if (!ictx->dev_present_intf0) - goto out; - switch (urb->status) { case -ENOENT: /* usbcore unlink successful! */ return; @@ -1761,16 +1760,29 @@ static void usb_rx_callback_intf0(struct urb *urb) break; case 0: - imon_incoming_packet(ictx, urb, intfnum); + /* + * if we get a callback before we're done configuring the hardware, we + * can't yet process the data, as there's nowhere to send it, but we + * still need to submit a new rx URB to avoid wedging the hardware + */ + if (ictx->dev_present_intf0) + imon_incoming_packet(ictx, urb, intfnum); break; + case -ECONNRESET: + case -EILSEQ: + case -EPROTO: + case -EPIPE: + dev_warn(ictx->dev, "imon %s: status(%d)\n", + __func__, urb->status); + return; + default: dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", __func__, urb->status); break; } -out: usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); } @@ -1786,14 +1798,6 @@ static void usb_rx_callback_intf1(struct urb *urb) if (!ictx) return; - /* - * if we get a callback before we're done configuring the hardware, we - * can't yet process the data, as there's nowhere to send it, but we - * still need to submit a new rx URB to avoid wedging the hardware - */ - if (!ictx->dev_present_intf1) - goto out; - switch (urb->status) { case -ENOENT: /* usbcore unlink successful! */ return; @@ -1802,16 +1806,29 @@ static void usb_rx_callback_intf1(struct urb *urb) break; case 0: - imon_incoming_packet(ictx, urb, intfnum); + /* + * if we get a callback before we're done configuring the hardware, we + * can't yet process the data, as there's nowhere to send it, but we + * still need to submit a new rx URB to avoid wedging the hardware + */ + if (ictx->dev_present_intf1) + imon_incoming_packet(ictx, urb, intfnum); break; + case -ECONNRESET: + case -EILSEQ: + case -EPROTO: + case -EPIPE: + dev_warn(ictx->dev, "imon %s: status(%d)\n", + __func__, urb->status); + return; + default: dev_warn(ictx->dev, "imon %s: status(%d): ignored\n", __func__, urb->status); break; } -out: usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); } @@ -2499,7 +2516,11 @@ static void imon_disconnect(struct usb_interface *interface) int ifnum; ictx = usb_get_intfdata(interface); + + mutex_lock(&ictx->lock); ictx->disconnected = true; + mutex_unlock(&ictx->lock); + dev = ictx->dev; ifnum = interface->cur_altsetting->desc.bInterfaceNumber; diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index afd80d2350c6..edc46828509c 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -402,4 +402,3 @@ module_platform_driver(hix5hd2_ir_driver); MODULE_DESCRIPTION("IR controller driver for hix5hd2 platforms"); MODULE_AUTHOR("Guoxiong Yan <yanguoxiong@huawei.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:hix5hd2-ir"); diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index a2257dc2f25d..7d4942925993 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -736,11 +736,11 @@ int lirc_register(struct rc_dev *dev) cdev_init(&dev->lirc_cdev, &lirc_fops); + get_device(&dev->dev); + err = cdev_device_add(&dev->lirc_cdev, &dev->lirc_dev); if (err) - goto out_ida; - - get_device(&dev->dev); + goto out_put_device; switch (dev->driver_type) { case RC_DRIVER_SCANCODE: @@ -764,7 +764,8 @@ int lirc_register(struct rc_dev *dev) return 0; -out_ida: +out_put_device: + put_device(&dev->lirc_dev); ida_free(&lirc_ida, minor); return err; } diff --git a/drivers/media/rc/pwm-ir-tx.c b/drivers/media/rc/pwm-ir-tx.c index 84533fdd61aa..047472dc9244 100644 --- a/drivers/media/rc/pwm-ir-tx.c +++ b/drivers/media/rc/pwm-ir-tx.c @@ -117,7 +117,6 @@ static int pwm_ir_tx_atomic(struct rc_dev *dev, unsigned int *txbuf, static enum hrtimer_restart pwm_ir_timer(struct hrtimer *timer) { struct pwm_ir *pwm_ir = container_of(timer, struct pwm_ir, timer); - ktime_t now; /* * If we happen to hit an odd latency spike, loop through the @@ -139,9 +138,7 @@ static enum hrtimer_restart pwm_ir_timer(struct hrtimer *timer) hrtimer_add_expires_ns(timer, ns); pwm_ir->txbuf_index++; - - now = timer->base->get_time(); - } while (hrtimer_get_expires_tv64(timer) < now); + } while (hrtimer_expires_remaining(timer) > 0); return HRTIMER_RESTART; } diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index d89a4cfe3c89..a49173f54a4d 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -422,7 +422,7 @@ static int redrat3_send_cmd(int cmd, struct redrat3_dev *rr3) static int redrat3_enable_detector(struct redrat3_dev *rr3) { struct device *dev = rr3->dev; - u8 ret; + int ret; ret = redrat3_send_cmd(RR3_RC_DET_ENABLE, rr3); if (ret != 0) diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c index 6539fa0a6e79..6b70bac5f45d 100644 --- a/drivers/media/rc/st_rc.c +++ b/drivers/media/rc/st_rc.c @@ -284,7 +284,7 @@ static int st_rc_probe(struct platform_device *pdev) else rc_dev->rx_base = rc_dev->base; - rc_dev->rstc = reset_control_get_optional_exclusive(dev, NULL); + rc_dev->rstc = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(rc_dev->rstc)) { ret = PTR_ERR(rc_dev->rstc); goto err; diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index c45f5cf12ded..a7ab668ce70b 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 <hansverk@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_LICENSE("GPL v2"); static bool multiplanar; @@ -144,7 +144,7 @@ static const struct v4l2_event vicodec_eos_event = { static inline struct vicodec_ctx *file2ctx(struct file *file) { - return container_of(file->private_data, struct vicodec_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct vicodec_ctx, fh); } static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx, @@ -421,7 +421,7 @@ static void device_run(void *priv) else dst_buf->sequence = q_dst->sequence++; dst_buf->flags &= ~V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); spin_lock(ctx->lock); if (!ctx->comp_has_next_frame && @@ -555,7 +555,7 @@ static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf, vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); dst_buf->sequence = q_dst->sequence++; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf); dst_buf->flags |= V4L2_BUF_FLAG_LAST; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); } @@ -760,16 +760,11 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) { - struct vb2_queue *vq; struct vicodec_q_data *q_data; struct v4l2_pix_format_mplane *pix_mp; struct v4l2_pix_format *pix; const struct v4l2_fwht_pixfmt_info *info; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - q_data = get_q_data(ctx, f->type); info = q_data->info; @@ -976,8 +971,6 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) struct v4l2_pix_format *pix; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; q_data = get_q_data(ctx, f->type); if (!q_data) @@ -1207,20 +1200,20 @@ static int vidioc_s_selection(struct file *file, void *priv, return 0; } -static int vicodec_encoder_cmd(struct file *file, void *fh, +static int vicodec_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec) { struct vicodec_ctx *ctx = file2ctx(file); int ret; - ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, ec); if (ret < 0) return ret; if (!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) return 0; - ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec); + ret = v4l2_m2m_ioctl_encoder_cmd(file, priv, ec); if (ret < 0) return ret; @@ -1235,7 +1228,7 @@ static int vicodec_encoder_cmd(struct file *file, void *fh, return 0; } -static int vicodec_decoder_cmd(struct file *file, void *fh, +static int vicodec_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { struct vicodec_ctx *ctx = file2ctx(file); @@ -1247,14 +1240,14 @@ static int vicodec_decoder_cmd(struct file *file, void *fh, */ WARN_ON(ctx->is_stateless); - ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, priv, dc); if (ret < 0) return ret; if (!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) return 0; - ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc); + ret = v4l2_m2m_ioctl_decoder_cmd(file, priv, dc); if (ret < 0) return ret; @@ -1269,7 +1262,7 @@ static int vicodec_decoder_cmd(struct file *file, void *fh, return 0; } -static int vicodec_enum_framesizes(struct file *file, void *fh, +static int vicodec_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { switch (fsize->pixel_format) { @@ -1848,7 +1841,6 @@ static int vicodec_open(struct file *file) ctx->is_stateless = true; v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 5); @@ -1932,7 +1924,7 @@ static int vicodec_open(struct file *file) goto open_unlock; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); open_unlock: mutex_unlock(vfd->lock); @@ -1947,7 +1939,7 @@ static int vicodec_release(struct file *file) mutex_lock(vfd->lock); v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); mutex_unlock(vfd->lock); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); kvfree(ctx->state.compressed_frame); diff --git a/drivers/media/test-drivers/vidtv/vidtv_channel.c b/drivers/media/test-drivers/vidtv/vidtv_channel.c index f3023e91b3eb..3541155c6fc6 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_channel.c +++ b/drivers/media/test-drivers/vidtv/vidtv_channel.c @@ -461,12 +461,15 @@ int vidtv_channel_si_init(struct vidtv_mux *m) /* assemble all programs and assign to PAT */ vidtv_psi_pat_program_assign(m->si.pat, programs); + programs = NULL; /* assemble all services and assign to SDT */ vidtv_psi_sdt_service_assign(m->si.sdt, services); + services = NULL; /* assemble all events and assign to EIT */ vidtv_psi_eit_event_assign(m->si.eit, events); + events = NULL; m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, m->pcr_pid); diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index 1d1a9e768505..c33c18ea5210 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -191,9 +191,7 @@ static void get_alignment(u32 fourcc, struct vim2m_dev { struct v4l2_device v4l2_dev; struct video_device vfd; -#ifdef CONFIG_MEDIA_CONTROLLER struct media_device mdev; -#endif atomic_t num_inst; struct mutex dev_mutex; @@ -236,7 +234,7 @@ struct vim2m_ctx { static inline struct vim2m_ctx *file2ctx(struct file *file) { - return container_of(file->private_data, struct vim2m_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct vim2m_ctx, fh); } static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx, @@ -268,9 +266,6 @@ static const char *type_name(enum v4l2_buf_type type) } } -#define CLIP(__color) \ - (u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color))) - static void copy_line(struct vim2m_q_data *q_data_out, u8 *src, u8 *dst, bool reverse) { @@ -482,7 +477,7 @@ static int device_process(struct vim2m_ctx *ctx, out_vb->sequence = q_data_out->sequence++; in_vb->sequence = q_data_in->sequence++; - v4l2_m2m_buf_copy_metadata(in_vb, out_vb, true); + v4l2_m2m_buf_copy_metadata(in_vb, out_vb); if (ctx->mode & MEM2MEM_VFLIP) { start = height - 1; @@ -729,14 +724,9 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) { - struct vb2_queue *vq; struct vim2m_q_data *q_data; int ret; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - q_data = get_q_data(ctx, f->type); if (!q_data) return -EINVAL; @@ -757,14 +747,9 @@ static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) static int vidioc_g_fmt_mplane(struct vim2m_ctx *ctx, struct v4l2_format *f) { - struct vb2_queue *vq; struct vim2m_q_data *q_data; int ret; - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - q_data = get_q_data(ctx, f->type); if (!q_data) return -EINVAL; @@ -976,8 +961,6 @@ static int vidioc_s_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) u32 height = (is_mplane) ? f->fmt.pix_mp.height : f->fmt.pix.height; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; q_data = get_q_data(ctx, f->type); if (!q_data) @@ -1389,7 +1372,6 @@ static int vim2m_open(struct file *file) } v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; hdl = &ctx->hdl; v4l2_ctrl_handler_init(hdl, 4); @@ -1433,7 +1415,7 @@ static int vim2m_open(struct file *file) goto open_unlock; } - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); atomic_inc(&dev->num_inst); dprintk(dev, 1, "Created instance: %p, m2m_ctx: %p\n", @@ -1451,7 +1433,7 @@ static int vim2m_release(struct file *file) dprintk(dev, 1, "Releasing instance %p\n", ctx); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(&dev->dev_mutex); @@ -1470,9 +1452,7 @@ static void vim2m_device_release(struct video_device *vdev) v4l2_device_unregister(&dev->v4l2_dev); v4l2_m2m_release(dev->m2m_dev); -#ifdef CONFIG_MEDIA_CONTROLLER media_device_cleanup(&dev->mdev); -#endif kfree(dev); } @@ -1543,7 +1523,6 @@ static int vim2m_probe(struct platform_device *pdev) goto error_dev; } -#ifdef CONFIG_MEDIA_CONTROLLER dev->mdev.dev = &pdev->dev; strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model)); strscpy(dev->mdev.bus_info, "platform:vim2m", @@ -1551,7 +1530,6 @@ static int vim2m_probe(struct platform_device *pdev) media_device_init(&dev->mdev); dev->mdev.ops = &m2m_media_ops; dev->v4l2_dev.mdev = &dev->mdev; -#endif ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); if (ret) { @@ -1562,7 +1540,6 @@ static int vim2m_probe(struct platform_device *pdev) v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n", vfd->num); -#ifdef CONFIG_MEDIA_CONTROLLER ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret) { @@ -1575,13 +1552,11 @@ static int vim2m_probe(struct platform_device *pdev) v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n"); goto error_m2m_mc; } -#endif + return 0; -#ifdef CONFIG_MEDIA_CONTROLLER error_m2m_mc: v4l2_m2m_unregister_media_controller(dev->m2m_dev); -#endif error_v4l2: video_unregister_device(&dev->vfd); /* vim2m_device_release called by video_unregister_device to release various objects */ @@ -1602,10 +1577,8 @@ static void vim2m_remove(struct platform_device *pdev) v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); -#ifdef CONFIG_MEDIA_CONTROLLER media_device_unregister(&dev->mdev); v4l2_m2m_unregister_media_controller(dev->m2m_dev); -#endif video_unregister_device(&dev->vfd); } diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index 10df039278e7..7f6124025fc9 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -57,8 +57,6 @@ static int vimc_capture_querycap(struct file *file, void *priv, { strscpy(cap->driver, VIMC_PDEV_NAME, sizeof(cap->driver)); strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", VIMC_PDEV_NAME); return 0; } @@ -169,7 +167,7 @@ static int vimc_capture_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vimc_capture_enum_framesizes(struct file *file, void *fh, +static int vimc_capture_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { const struct vimc_pix_map *vpix; diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c index c812fa9f0650..f632c77e52f5 100644 --- a/drivers/media/test-drivers/vimc/vimc-core.c +++ b/drivers/media/test-drivers/vimc/vimc-core.c @@ -366,8 +366,6 @@ static int vimc_probe(struct platform_device *pdev) /* Initialize media device */ strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, sizeof(vimc->mdev.model)); - snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info), - "platform:%s", VIMC_PDEV_NAME); vimc->mdev.dev = &pdev->dev; media_device_init(&vimc->mdev); diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c index 5bf3136b36eb..26c6c6835f79 100644 --- a/drivers/media/test-drivers/visl/visl-core.c +++ b/drivers/media/test-drivers/visl/visl-core.c @@ -341,7 +341,6 @@ static int visl_open(struct file *file) ctx->tpg_str_buf = kzalloc(TPG_STR_BUF_SZ, GFP_KERNEL); v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; ctx->dev = dev; rc = visl_init_ctrls(ctx); @@ -361,7 +360,7 @@ static int visl_open(struct file *file) if (rc) goto free_m2m_ctx; - v4l2_fh_add(&ctx->fh); + v4l2_fh_add(&ctx->fh, file); dprintk(dev, "Created instance: %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); @@ -390,7 +389,7 @@ static int visl_release(struct file *file) dprintk(dev, "Releasing instance %p\n", ctx); tpg_free(&ctx->tpg); - v4l2_fh_del(&ctx->fh); + v4l2_fh_del(&ctx->fh, file); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); mutex_lock(&dev->dev_mutex); diff --git a/drivers/media/test-drivers/visl/visl-dec.c b/drivers/media/test-drivers/visl/visl-dec.c index 6a9639bd4d61..d90b79de8384 100644 --- a/drivers/media/test-drivers/visl/visl-dec.c +++ b/drivers/media/test-drivers/visl/visl-dec.c @@ -572,7 +572,7 @@ void visl_device_run(void *priv) if (src_req) v4l2_ctrl_request_setup(src_req, &ctx->hdl); - v4l2_m2m_buf_copy_metadata(run.src, run.dst, true); + v4l2_m2m_buf_copy_metadata(run.src, run.dst); run.dst->sequence = ctx->q_data[V4L2_M2M_DST].sequence++; run.src->sequence = ctx->q_data[V4L2_M2M_SRC].sequence++; run.dst->field = ctx->decoded_fmt.fmt.pix.field; diff --git a/drivers/media/test-drivers/visl/visl.h b/drivers/media/test-drivers/visl/visl.h index 434e9efbf9b2..2971e8b37ff6 100644 --- a/drivers/media/test-drivers/visl/visl.h +++ b/drivers/media/test-drivers/visl/visl.h @@ -163,12 +163,7 @@ struct visl_ctrl_desc { static inline struct visl_ctx *visl_file_to_ctx(struct file *file) { - return container_of(file->private_data, struct visl_ctx, fh); -} - -static inline struct visl_ctx *visl_v4l2fh_to_ctx(struct v4l2_fh *v4l2_fh) -{ - return container_of(v4l2_fh, struct visl_ctx, fh); + return container_of(file_to_v4l2_fh(file), struct visl_ctx, fh); } void *visl_find_control_data(struct visl_ctx *ctx, u32 id); diff --git a/drivers/media/test-drivers/vivid/vivid-cec.c b/drivers/media/test-drivers/vivid/vivid-cec.c index 356a988dd6a1..2d15fdd5d999 100644 --- a/drivers/media/test-drivers/vivid/vivid-cec.c +++ b/drivers/media/test-drivers/vivid/vivid-cec.c @@ -327,7 +327,7 @@ static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg) char osd[14]; if (!cec_is_sink(adap)) - return -ENOMSG; + break; cec_ops_set_osd_string(msg, &disp_ctl, osd); switch (disp_ctl) { case CEC_OP_DISP_CTL_DEFAULT: @@ -348,7 +348,7 @@ static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg) cec_transmit_msg(adap, &reply, false); break; } - break; + return 0; } case CEC_MSG_VENDOR_COMMAND_WITH_ID: { u32 vendor_id; @@ -379,7 +379,7 @@ static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg) if (size == 1) { // Ignore even op values if (!(vendor_cmd[0] & 1)) - break; + return 0; reply.len = msg->len; memcpy(reply.msg + 1, msg->msg + 1, msg->len - 1); reply.msg[msg->len - 1]++; @@ -388,12 +388,10 @@ static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg) CEC_OP_ABORT_INVALID_OP); } cec_transmit_msg(adap, &reply, false); - break; + return 0; } - default: - return -ENOMSG; } - return 0; + return -ENOMSG; } static const struct cec_adap_ops vivid_cec_adap_ops = { diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index 8d56168c72aa..9c0b1a32b5c9 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -277,49 +277,49 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) +static int vidioc_s_hw_freq_seek(struct file *file, void *priv, const struct v4l2_hw_freq_seek *a) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_s_hw_freq_seek(file, fh, a); + return vivid_radio_rx_s_hw_freq_seek(file, priv, a); return -ENOTTY; } -static int vidioc_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) +static int vidioc_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_enum_freq_bands(file, fh, band); + return vivid_radio_rx_enum_freq_bands(file, priv, band); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_enum_freq_bands(file, fh, band); + return vivid_sdr_enum_freq_bands(file, priv, band); return -ENOTTY; } -static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_g_tuner(file, fh, vt); + return vivid_radio_rx_g_tuner(file, priv, vt); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_g_tuner(file, fh, vt); - return vivid_video_g_tuner(file, fh, vt); + return vivid_sdr_g_tuner(file, priv, vt); + return vivid_video_g_tuner(file, priv, vt); } -static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_s_tuner(file, fh, vt); + return vivid_radio_rx_s_tuner(file, priv, vt); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_s_tuner(file, fh, vt); - return vivid_video_s_tuner(file, fh, vt); + return vivid_sdr_s_tuner(file, priv, vt); + return vivid_video_s_tuner(file, priv, vt); } -static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); @@ -329,11 +329,11 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency vdev->vfl_dir == VFL_DIR_RX ? &dev->radio_rx_freq : &dev->radio_tx_freq, vf); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_g_frequency(file, fh, vf); - return vivid_video_g_frequency(file, fh, vf); + return vivid_sdr_g_frequency(file, priv, vf); + return vivid_video_g_frequency(file, priv, vf); } -static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); @@ -343,113 +343,113 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre vdev->vfl_dir == VFL_DIR_RX ? &dev->radio_rx_freq : &dev->radio_tx_freq, vf); if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_s_frequency(file, fh, vf); - return vivid_video_s_frequency(file, fh, vf); + return vivid_sdr_s_frequency(file, priv, vf); + return vivid_video_s_frequency(file, priv, vf); } -static int vidioc_overlay(struct file *file, void *fh, unsigned i) +static int vidioc_overlay(struct file *file, void *priv, unsigned i) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) return -ENOTTY; - return vivid_vid_out_overlay(file, fh, i); + return vivid_vid_out_overlay(file, priv, i); } -static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a) +static int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *a) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) return -ENOTTY; - return vivid_vid_out_g_fbuf(file, fh, a); + return vivid_vid_out_g_fbuf(file, priv, a); } -static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a) +static int vidioc_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *a) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) return -ENOTTY; - return vivid_vid_out_s_fbuf(file, fh, a); + return vivid_vid_out_s_fbuf(file, priv, a); } -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_std(file, fh, id); - return vivid_vid_out_s_std(file, fh, id); + return vivid_vid_cap_s_std(file, priv, id); + return vivid_vid_out_s_std(file, priv, id); } -static int vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings) +static int vidioc_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_dv_timings(file, fh, timings); - return vivid_vid_out_s_dv_timings(file, fh, timings); + return vivid_vid_cap_s_dv_timings(file, priv, timings); + return vivid_vid_out_s_dv_timings(file, priv, timings); } -static int vidioc_g_pixelaspect(struct file *file, void *fh, +static int vidioc_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_pixelaspect(file, fh, type, f); - return vivid_vid_out_g_pixelaspect(file, fh, type, f); + return vivid_vid_cap_g_pixelaspect(file, priv, type, f); + return vivid_vid_out_g_pixelaspect(file, priv, type, f); } -static int vidioc_g_selection(struct file *file, void *fh, +static int vidioc_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_selection(file, fh, sel); - return vivid_vid_out_g_selection(file, fh, sel); + return vivid_vid_cap_g_selection(file, priv, sel); + return vivid_vid_out_g_selection(file, priv, sel); } -static int vidioc_s_selection(struct file *file, void *fh, +static int vidioc_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_selection(file, fh, sel); - return vivid_vid_out_s_selection(file, fh, sel); + return vivid_vid_cap_s_selection(file, priv, sel); + return vivid_vid_out_s_selection(file, priv, sel); } -static int vidioc_g_parm(struct file *file, void *fh, +static int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_parm_tch(file, fh, parm); + return vivid_g_parm_tch(file, priv, parm); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_parm(file, fh, parm); - return vivid_vid_out_g_parm(file, fh, parm); + return vivid_vid_cap_g_parm(file, priv, parm); + return vivid_vid_out_g_parm(file, priv, parm); } -static int vidioc_s_parm(struct file *file, void *fh, +static int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { struct video_device *vdev = video_devdata(file); if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_parm(file, fh, parm); + return vivid_vid_cap_s_parm(file, priv, parm); return -ENOTTY; } -static int vidioc_log_status(struct file *file, void *fh) +static int vidioc_log_status(struct file *file, void *priv) { struct vivid_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); - v4l2_ctrl_log_status(file, fh); + v4l2_ctrl_log_status(file, priv); if (vdev->vfl_dir == VFL_DIR_RX && vdev->vfl_type == VFL_TYPE_VIDEO) tpg_log_status(&dev->tpg); return 0; @@ -654,11 +654,11 @@ static int vivid_fop_release(struct file *file) v4l2_info(&dev->v4l2_dev, "reconnect\n"); vivid_reconnect(dev); } - if (file->private_data == dev->radio_rx_rds_owner) { + if (file_to_v4l2_fh(file) == dev->radio_rx_rds_owner) { dev->radio_rx_rds_last_block = 0; dev->radio_rx_rds_owner = NULL; } - if (file->private_data == dev->radio_tx_rds_owner) { + if (file_to_v4l2_fh(file) == dev->radio_tx_rds_owner) { dev->radio_tx_rds_last_block = 0; dev->radio_tx_rds_owner = NULL; } @@ -1856,15 +1856,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) tpg_init(&dev->tpg, 640, 360); if (tpg_alloc(&dev->tpg, array_size(MAX_WIDTH, MAX_ZOOM))) goto free_dev; - dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); + dev->scaled_line = vcalloc(MAX_WIDTH, MAX_ZOOM); if (!dev->scaled_line) goto free_dev; - dev->blended_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); + dev->blended_line = vcalloc(MAX_WIDTH, MAX_ZOOM); if (!dev->blended_line) goto free_dev; /* load the edid */ - dev->edid = vmalloc(array_size(256, 128)); + dev->edid = vmalloc_array(256, 128); if (!dev->edid) goto free_dev; diff --git a/drivers/media/test-drivers/vivid/vivid-radio-rx.c b/drivers/media/test-drivers/vivid/vivid-radio-rx.c index 79c1723bd84c..b5e3026f883e 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-rx.c +++ b/drivers/media/test-drivers/vivid/vivid-radio-rx.c @@ -42,13 +42,13 @@ ssize_t vivid_radio_rx_read(struct file *file, char __user *buf, if (mutex_lock_interruptible(&dev->mutex)) return -ERESTARTSYS; if (dev->radio_rx_rds_owner && - file->private_data != dev->radio_rx_rds_owner) { + file_to_v4l2_fh(file) != dev->radio_rx_rds_owner) { mutex_unlock(&dev->mutex); return -EBUSY; } if (dev->radio_rx_rds_owner == NULL) { vivid_radio_rds_init(dev); - dev->radio_rx_rds_owner = file->private_data; + dev->radio_rx_rds_owner = file_to_v4l2_fh(file); } retry: @@ -133,7 +133,7 @@ __poll_t vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait) return EPOLLIN | EPOLLRDNORM | v4l2_ctrl_poll(file, wait); } -int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) +int vivid_radio_rx_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { if (band->tuner != 0) return -EINVAL; @@ -145,7 +145,7 @@ int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_freq return 0; } -int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) +int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *priv, const struct v4l2_hw_freq_seek *a) { struct vivid_dev *dev = video_drvdata(file); unsigned low, high; @@ -214,7 +214,7 @@ int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2 return 0; } -int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +int vivid_radio_rx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { struct vivid_dev *dev = video_drvdata(file); int delta = 800; @@ -267,7 +267,7 @@ int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) return 0; } -int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +int vivid_radio_rx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-radio-rx.h b/drivers/media/test-drivers/vivid/vivid-radio-rx.h index c9c7849f6f99..a2ae17c78ece 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-rx.h +++ b/drivers/media/test-drivers/vivid/vivid-radio-rx.h @@ -11,9 +11,9 @@ ssize_t vivid_radio_rx_read(struct file *, char __user *, size_t, loff_t *); __poll_t vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait); -int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); -int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a); -int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); -int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); +int vivid_radio_rx_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band); +int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *priv, const struct v4l2_hw_freq_seek *a); +int vivid_radio_rx_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt); +int vivid_radio_rx_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt); #endif diff --git a/drivers/media/test-drivers/vivid/vivid-radio-tx.c b/drivers/media/test-drivers/vivid/vivid-radio-tx.c index 049d40b948bb..ada60722066e 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-tx.c +++ b/drivers/media/test-drivers/vivid/vivid-radio-tx.c @@ -39,11 +39,11 @@ ssize_t vivid_radio_tx_write(struct file *file, const char __user *buf, if (mutex_lock_interruptible(&dev->mutex)) return -ERESTARTSYS; if (dev->radio_tx_rds_owner && - file->private_data != dev->radio_tx_rds_owner) { + file_to_v4l2_fh(file) != dev->radio_tx_rds_owner) { mutex_unlock(&dev->mutex); return -EBUSY; } - dev->radio_tx_rds_owner = file->private_data; + dev->radio_tx_rds_owner = file_to_v4l2_fh(file); retry: timestamp = ktime_sub(ktime_get(), dev->radio_rds_init_time); @@ -96,7 +96,7 @@ __poll_t vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait) return EPOLLOUT | EPOLLWRNORM | v4l2_ctrl_poll(file, wait); } -int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a) +int vidioc_g_modulator(struct file *file, void *priv, struct v4l2_modulator *a) { struct vivid_dev *dev = video_drvdata(file); @@ -115,7 +115,7 @@ int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a) return 0; } -int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a) +int vidioc_s_modulator(struct file *file, void *priv, const struct v4l2_modulator *a) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-radio-tx.h b/drivers/media/test-drivers/vivid/vivid-radio-tx.h index c2bf1e7e634a..20cb6f1363ff 100644 --- a/drivers/media/test-drivers/vivid/vivid-radio-tx.h +++ b/drivers/media/test-drivers/vivid/vivid-radio-tx.h @@ -11,7 +11,7 @@ ssize_t vivid_radio_tx_write(struct file *, const char __user *, size_t, loff_t *); __poll_t vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait); -int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a); -int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a); +int vidioc_g_modulator(struct file *file, void *priv, struct v4l2_modulator *a); +int vidioc_s_modulator(struct file *file, void *priv, const struct v4l2_modulator *a); #endif diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c index c633fc2ed664..2664a593e8e1 100644 --- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c @@ -344,7 +344,7 @@ const struct vb2_ops vivid_sdr_cap_qops = { .buf_request_complete = sdr_cap_buf_request_complete, }; -int vivid_sdr_enum_freq_bands(struct file *file, void *fh, +int vivid_sdr_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band) { switch (band->tuner) { @@ -363,7 +363,7 @@ int vivid_sdr_enum_freq_bands(struct file *file, void *fh, } } -int vivid_sdr_g_frequency(struct file *file, void *fh, +int vivid_sdr_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); @@ -382,7 +382,7 @@ int vivid_sdr_g_frequency(struct file *file, void *fh, } } -int vivid_sdr_s_frequency(struct file *file, void *fh, +int vivid_sdr_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); @@ -423,7 +423,7 @@ int vivid_sdr_s_frequency(struct file *file, void *fh, } } -int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +int vivid_sdr_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { switch (vt->index) { case 0: @@ -447,14 +447,14 @@ int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) } } -int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +int vivid_sdr_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { if (vt->index > 1) return -EINVAL; return 0; } -int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +int vidioc_enum_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index >= ARRAY_SIZE(formats)) return -EINVAL; @@ -462,7 +462,7 @@ int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) return 0; } -int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +int vidioc_g_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivid_dev *dev = video_drvdata(file); @@ -471,7 +471,7 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) return 0; } -int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +int vidioc_s_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vivid_dev *dev = video_drvdata(file); struct vb2_queue *q = &dev->vb_sdr_cap_q; @@ -495,7 +495,7 @@ int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) return 0; } -int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +int vidioc_try_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f) { int i; diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.h b/drivers/media/test-drivers/vivid/vivid-sdr-cap.h index 813c9248e5a7..3d8eeabbfc10 100644 --- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.h +++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.h @@ -8,15 +8,15 @@ #ifndef _VIVID_SDR_CAP_H_ #define _VIVID_SDR_CAP_H_ -int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); -int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); -int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); -int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); -int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); -int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f); -int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); -int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); -int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); +int vivid_sdr_enum_freq_bands(struct file *file, void *priv, struct v4l2_frequency_band *band); +int vivid_sdr_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf); +int vivid_sdr_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf); +int vivid_sdr_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt); +int vivid_sdr_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt); +int vidioc_enum_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_g_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_sdr_cap(struct file *file, void *priv, struct v4l2_format *f); void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); extern const struct vb2_ops vivid_sdr_cap_qops; diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c index a09f62c66c33..791382a54b4f 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c @@ -282,7 +282,7 @@ void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_se } } -int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; @@ -294,7 +294,7 @@ int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format return 0; } -int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; @@ -310,11 +310,11 @@ int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_forma return 0; } -int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt); + int ret = vidioc_try_fmt_sliced_vbi_cap(file, priv, fmt); if (ret) return ret; @@ -324,7 +324,7 @@ int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format return 0; } -int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) +int vidioc_g_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_sliced_vbi_cap *cap) { struct vivid_dev *dev = video_drvdata(file); struct video_device *vdev = video_devdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.h b/drivers/media/test-drivers/vivid/vivid-vbi-cap.h index 91d2de01381c..ec2d200c9e0d 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.h +++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.h @@ -16,10 +16,10 @@ int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap); +int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_g_sliced_vbi_cap(struct file *file, void *priv, struct v4l2_sliced_vbi_cap *cap); void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set); diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.c b/drivers/media/test-drivers/vivid/vivid-vbi-out.c index b7a09d2f394e..7b3ea96744bb 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.c @@ -168,7 +168,7 @@ int vidioc_s_fmt_vbi_out(struct file *file, void *priv, return 0; } -int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; @@ -180,7 +180,7 @@ int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format return 0; } -int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; @@ -196,12 +196,12 @@ int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_forma return 0; } -int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, +int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - int ret = vidioc_try_fmt_sliced_vbi_out(file, fh, fmt); + int ret = vidioc_try_fmt_sliced_vbi_out(file, priv, fmt); if (ret) return ret; diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.h b/drivers/media/test-drivers/vivid/vivid-vbi-out.h index 76584940cdaf..a28e55519ade 100644 --- a/drivers/media/test-drivers/vivid/vivid-vbi-out.h +++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.h @@ -13,9 +13,9 @@ int vidioc_g_fmt_vbi_out(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vbi_out(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt); +int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *priv, struct v4l2_format *fmt); extern const struct vb2_ops vivid_vbi_out_qops; diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c index 2e4c1ed37cd2..b95f06a9b5ae 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c @@ -302,8 +302,10 @@ void vivid_update_quality(struct vivid_dev *dev) */ freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16); if (freq_modulus > 2 * 16) { + struct rnd_state prng; + prandom_seed_state(&prng, dev->tv_freq ^ 0x55); tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, - next_pseudo_random32(dev->tv_freq ^ 0x55) & 0x3f); + prandom_u32_state(&prng) & 0x3f); return; } if (freq_modulus < 12 /*0.75 * 16*/ || freq_modulus > 20 /*1.25 * 16*/) @@ -899,7 +901,7 @@ int vivid_vid_cap_g_selection(struct file *file, void *priv, return 0; } -int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +int vivid_vid_cap_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_rect *crop = &dev->crop_cap; @@ -1222,7 +1224,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) return 0; } -int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin) { if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) return -EINVAL; @@ -1230,7 +1232,7 @@ int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) return 0; } -int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *vin) { struct vivid_dev *dev = video_drvdata(file); @@ -1240,7 +1242,7 @@ int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) return 0; } -int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin) +int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *vin) { struct vivid_dev *dev = video_drvdata(file); @@ -1252,7 +1254,7 @@ int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin) return 0; } -int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +int vivid_video_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); @@ -1262,7 +1264,7 @@ int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency * return 0; } -int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +int vivid_video_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { struct vivid_dev *dev = video_drvdata(file); @@ -1274,7 +1276,7 @@ int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequ return 0; } -int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +int vivid_video_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { struct vivid_dev *dev = video_drvdata(file); @@ -1286,7 +1288,7 @@ int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt return 0; } -int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +int vivid_video_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { struct vivid_dev *dev = video_drvdata(file); enum tpg_quality qual; @@ -1490,7 +1492,7 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) return false; } -int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, +int vivid_vid_cap_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); @@ -1513,7 +1515,7 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, return 0; } -int vidioc_query_dv_timings(struct file *file, void *_fh, +int vidioc_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); @@ -1600,7 +1602,7 @@ void vivid_update_connected_outputs(struct vivid_dev *dev) } } -int vidioc_s_edid(struct file *file, void *_fh, +int vidioc_s_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct vivid_dev *dev = video_drvdata(file); @@ -1638,7 +1640,7 @@ int vidioc_s_edid(struct file *file, void *_fh, return 0; } -int vidioc_enum_framesizes(struct file *file, void *fh, +int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.h b/drivers/media/test-drivers/vivid/vivid-vid-cap.h index 7a8daf0af2ca..38a99f7e038e 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-cap.h +++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.h @@ -29,7 +29,7 @@ int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); -int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s); +int vivid_vid_cap_s_selection(struct file *file, void *priv, struct v4l2_selection *s); int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); @@ -38,19 +38,19 @@ int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format * int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp); int vidioc_g_input(struct file *file, void *priv, unsigned *i); int vidioc_s_input(struct file *file, void *priv, unsigned i); -int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin); -int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin); -int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin); -int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); -int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); -int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); -int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); +int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin); +int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *vin); +int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *vin); +int vivid_video_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf); +int vivid_video_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf); +int vivid_video_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt); +int vivid_video_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt); int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id); int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id); -int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid); -int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize); +int vivid_vid_cap_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings); +int vidioc_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings); +int vidioc_s_edid(struct file *file, void *priv, struct v4l2_edid *edid); +int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize); int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival); int vivid_vid_cap_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-common.c b/drivers/media/test-drivers/vivid/vivid-vid-common.c index df7678db67fb..786a1aa3b26b 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-common.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-common.c @@ -1021,7 +1021,7 @@ int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) return 0; } -int vidioc_g_dv_timings(struct file *file, void *_fh, +int vidioc_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); @@ -1039,7 +1039,7 @@ int vidioc_g_dv_timings(struct file *file, void *_fh, return 0; } -int vidioc_enum_dv_timings(struct file *file, void *_fh, +int vidioc_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); @@ -1056,7 +1056,7 @@ int vidioc_enum_dv_timings(struct file *file, void *_fh, NULL, NULL); } -int vidioc_dv_timings_cap(struct file *file, void *_fh, +int vidioc_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap) { struct vivid_dev *dev = video_drvdata(file); @@ -1073,7 +1073,7 @@ int vidioc_dv_timings_cap(struct file *file, void *_fh, return 0; } -int vidioc_g_edid(struct file *file, void *_fh, +int vidioc_g_edid(struct file *file, void *priv, struct v4l2_edid *edid) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-common.h b/drivers/media/test-drivers/vivid/vivid-vid-common.h index c49ac85abaed..fb5878174dba 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-common.h +++ b/drivers/media/test-drivers/vivid/vivid-vid-common.h @@ -32,10 +32,10 @@ int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id); -int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings); -int vidioc_dv_timings_cap(struct file *file, void *_fh, struct v4l2_dv_timings_cap *cap); -int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid); +int vidioc_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings); +int vidioc_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings); +int vidioc_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap); +int vidioc_g_edid(struct file *file, void *priv, struct v4l2_edid *edid); int vidioc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub); #endif diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c index c3398bce6c15..8c037b90833e 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c @@ -672,7 +672,7 @@ int vivid_vid_out_g_selection(struct file *file, void *priv, return 0; } -int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +int vivid_vid_out_s_selection(struct file *file, void *priv, struct v4l2_selection *s) { struct vivid_dev *dev = video_drvdata(file); struct v4l2_rect *crop = &dev->crop_out; @@ -880,7 +880,7 @@ int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, return ret; } -int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i) +int vivid_vid_out_overlay(struct file *file, void *priv, unsigned i) { struct vivid_dev *dev = video_drvdata(file); @@ -893,7 +893,7 @@ int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i) return 0; } -int vivid_vid_out_g_fbuf(struct file *file, void *fh, +int vivid_vid_out_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *a) { struct vivid_dev *dev = video_drvdata(file); @@ -920,7 +920,7 @@ int vivid_vid_out_g_fbuf(struct file *file, void *fh, return 0; } -int vivid_vid_out_s_fbuf(struct file *file, void *fh, +int vivid_vid_out_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *a) { struct vivid_dev *dev = video_drvdata(file); @@ -1016,7 +1016,7 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o) return 0; } -int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout) +int vidioc_enumaudout(struct file *file, void *priv, struct v4l2_audioout *vout) { if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) return -EINVAL; @@ -1024,7 +1024,7 @@ int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout) return 0; } -int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout) +int vidioc_g_audout(struct file *file, void *priv, struct v4l2_audioout *vout) { struct vivid_dev *dev = video_drvdata(file); @@ -1034,7 +1034,7 @@ int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout) return 0; } -int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout) +int vidioc_s_audout(struct file *file, void *priv, const struct v4l2_audioout *vout) { struct vivid_dev *dev = video_drvdata(file); @@ -1072,7 +1072,7 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) return false; } -int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, +int vivid_vid_out_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.h b/drivers/media/test-drivers/vivid/vivid-vid-out.h index 8d56314f4ea1..1d03891a5de5 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-out.h +++ b/drivers/media/test-drivers/vivid/vivid-vid-out.h @@ -22,23 +22,23 @@ int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); -int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s); +int vivid_vid_out_s_selection(struct file *file, void *priv, struct v4l2_selection *s); int vivid_vid_out_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); int vidioc_enum_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); -int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i); -int vivid_vid_out_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a); -int vivid_vid_out_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a); +int vivid_vid_out_overlay(struct file *file, void *priv, unsigned i); +int vivid_vid_out_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *a); +int vivid_vid_out_s_fbuf(struct file *file, void *priv, const struct v4l2_framebuffer *a); int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out); int vidioc_g_output(struct file *file, void *priv, unsigned *i); int vidioc_s_output(struct file *file, void *priv, unsigned i); -int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout); -int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout); -int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout); +int vidioc_enumaudout(struct file *file, void *priv, struct v4l2_audioout *vout); +int vidioc_g_audout(struct file *file, void *priv, struct v4l2_audioout *vout); +int vidioc_s_audout(struct file *file, void *priv, const struct v4l2_audioout *vout); int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id); -int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vivid_vid_out_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings); int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); #endif diff --git a/drivers/media/tuners/xc2028.c b/drivers/media/tuners/xc2028.c index 8e6638e5f688..807585d2dfde 100644 --- a/drivers/media/tuners/xc2028.c +++ b/drivers/media/tuners/xc2028.c @@ -1361,16 +1361,9 @@ static void load_firmware_cb(const struct firmware *fw, void *context) { struct dvb_frontend *fe = context; - struct xc2028_data *priv; + struct xc2028_data *priv = fe->tuner_priv; int rc; - if (!fe) { - pr_warn("xc2028: No frontend in %s\n", __func__); - return; - } - - priv = fe->tuner_priv; - tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error"); if (!fw) { tuner_err("Could not load firmware %s.\n", priv->fname); diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index 3cf54d776d36..b44c97e4e5ec 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -1087,12 +1087,12 @@ fail: static void xc_debug_dump(struct xc4000_priv *priv) { - u16 adc_envelope; + u16 adc_envelope = 0; u32 freq_error_hz = 0; - u16 lock_status; + u16 lock_status = 0; u32 hsync_freq_hz = 0; - u16 frame_lines; - u16 quality; + u16 frame_lines = 0; + u16 quality = 0; u16 signal = 0; u16 noise = 0; u8 hw_majorversion = 0, hw_minorversion = 0; diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index 30aa4ee958bd..a28481edd22e 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -622,14 +622,14 @@ static int xc5000_fwupload(struct dvb_frontend *fe, static void xc_debug_dump(struct xc5000_priv *priv) { - u16 adc_envelope; + u16 adc_envelope = 0; u32 freq_error_hz = 0; - u16 lock_status; + u16 lock_status = 0; u32 hsync_freq_hz = 0; - u16 frame_lines; - u16 quality; - u16 snr; - u16 totalgain; + u16 frame_lines = 0; + u16 quality = 0; + u16 snr = 0; + u16 totalgain = 0; u8 hw_majorversion = 0, hw_minorversion = 0; u8 fw_majorversion = 0, fw_minorversion = 0; u16 fw_buildversion = 0; @@ -1304,7 +1304,7 @@ static void xc5000_release(struct dvb_frontend *fe) mutex_lock(&xc5000_list_mutex); if (priv) { - cancel_delayed_work(&priv->timer_sleep); + cancel_delayed_work_sync(&priv->timer_sleep); hybrid_tuner_release_state(priv); } diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index e5dff969ed57..fbaa542c8259 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1921,9 +1921,8 @@ int au0828_analog_register(struct au0828_dev *dev, iface_desc = interface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { endpoint = &iface_desc->endpoint[i].desc; - if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) && - ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + if (usb_endpoint_dir_in(endpoint) && + (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_ISOC)) { /* we find our isoc in endpoint */ diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index e585c8f6e4c5..c695a97e202b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1499,7 +1499,7 @@ static int vidioc_g_selection(struct file *file, void *priv, return 0; } -static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm) +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm) { struct cx231xx *dev = video_drvdata(file); diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 0c510035805b..05c18b6de5c6 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -70,12 +70,12 @@ #include "ts2020.h" -#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw"; -#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw"; -#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw"; -#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw"; -#define LME2510_LG "dvb-usb-lme2510-lg.fw"; -#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw"; +#define LME2510_C_S7395 "dvb-usb-lme2510c-s7395.fw" +#define LME2510_C_LG "dvb-usb-lme2510c-lg.fw" +#define LME2510_C_S0194 "dvb-usb-lme2510c-s0194.fw" +#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw" +#define LME2510_LG "dvb-usb-lme2510-lg.fw" +#define LME2510_S0194 "dvb-usb-lme2510-s0194.fw" /* debug */ static int dvb_usb_lme2510_debug; diff --git a/drivers/media/usb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c index 3d85c6f7f6ec..c448e2ebda1a 100644 --- a/drivers/media/usb/dvb-usb/dtv5100.c +++ b/drivers/media/usb/dvb-usb/dtv5100.c @@ -55,6 +55,11 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, } index = (addr << 8) + wbuf[0]; + if (rlen > sizeof(st->data)) { + warn("rlen = %x is too big!\n", rlen); + return -EINVAL; + } + memcpy(st->data, rbuf, rlen); msleep(1); /* avoid I2C errors */ return usb_control_msg(d->udev, pipe, request, diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index 5094de9a312e..bc7a224d829e 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -422,16 +422,15 @@ static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, u8 id; int ret; + if (snd_len > 64 - 7 || rcv_len > 64 - 7) + return -EINVAL; + buf = kmalloc(64, GFP_KERNEL); if (!buf) return -ENOMEM; id = state->c++; - ret = -EINVAL; - if (snd_len > 64 - 7 || rcv_len > 64 - 7) - goto failed; - buf[0] = SYNC_BYTE_OUT; buf[1] = id; buf[2] = PCTV_CMD_I2C; diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index cb61fd6cc6c6..3122d4bdfc59 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -68,6 +68,7 @@ config VIDEO_EM28XX_DVB select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT select DVB_MXL692 if MEDIA_SUBDRV_AUTOSELECT + select GPIOLIB_LEGACY if GPIOLIB && DVB_CXD2820R help This adds support for DVB cards based on the Empiatech em28xx chips. diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 9fce59979e3b..b94f5c70ab75 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -727,7 +727,7 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv; struct em28xx *dev = i2c_bus->dev; -#ifdef CONFIG_GPIOLIB +#ifdef CONFIG_GPIOLIB_LEGACY struct em28xx_dvb *dvb = dev->dvb; int ret; unsigned long flags; @@ -1705,7 +1705,7 @@ static int em28xx_dvb_init(struct em28xx *dev) goto out_free; } -#ifdef CONFIG_GPIOLIB +#ifdef CONFIG_GPIOLIB_LEGACY /* enable LNA for DVB-T, DVB-T2 and DVB-C */ result = gpio_request_one(dvb->lna_gpio, GPIOF_OUT_INIT_LOW, NULL); diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 25edd2189654..3fc15d16df8e 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1029,15 +1029,15 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; fmt->fmt.pix = gspca_dev->pixfmt; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } @@ -1075,24 +1075,24 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, return mode; /* used when s_fmt */ } -static int vidioc_try_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; if (try_fmt_vid_cap(gspca_dev, fmt) < 0) return -EINVAL; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } -static int vidioc_s_fmt_vid_cap(struct file *file, void *_priv, +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct gspca_dev *gspca_dev = video_drvdata(file); - u32 priv = fmt->fmt.pix.priv; + u32 fmt_priv = fmt->fmt.pix.priv; int mode; if (vb2_is_busy(&gspca_dev->queue)) @@ -1109,7 +1109,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *_priv, else gspca_dev->pixfmt = gspca_dev->cam.cam_mode[mode]; /* some drivers use priv internally, so keep the original value */ - fmt->fmt.pix.priv = priv; + fmt->fmt.pix.priv = fmt_priv; return 0; } diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index fd7d2a9d0449..8c7ae362d992 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -52,6 +52,11 @@ struct hdpvr_fh { bool legacy_mode; }; +static inline struct hdpvr_fh *file_to_hdpvr_fh(struct file *file) +{ + return container_of(file_to_v4l2_fh(file), struct hdpvr_fh, fh); +} + static uint list_size(struct list_head *list) { struct list_head *tmp; @@ -380,8 +385,7 @@ static int hdpvr_open(struct file *file) return -ENOMEM; fh->legacy_mode = true; v4l2_fh_init(&fh->fh, video_devdata(file)); - v4l2_fh_add(&fh->fh); - file->private_data = fh; + v4l2_fh_add(&fh->fh, file); return 0; } @@ -390,7 +394,7 @@ static int hdpvr_release(struct file *file) struct hdpvr_device *dev = video_drvdata(file); mutex_lock(&dev->io_mutex); - if (file->private_data == dev->owner) { + if (file_to_v4l2_fh(file) == dev->owner) { hdpvr_stop_streaming(dev); dev->owner = NULL; } @@ -426,7 +430,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, mutex_unlock(&dev->io_mutex); goto err; } - dev->owner = file->private_data; + dev->owner = file_to_v4l2_fh(file); print_buffer_status(); } mutex_unlock(&dev->io_mutex); @@ -541,7 +545,7 @@ static __poll_t hdpvr_poll(struct file *filp, poll_table *wait) "start_streaming failed\n"); dev->status = STATUS_IDLE; } else { - dev->owner = filp->private_data; + dev->owner = file_to_v4l2_fh(filp); } print_buffer_status(); @@ -586,11 +590,11 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_s_std(struct file *file, void *_fh, +static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); u8 std_type = 1; if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) @@ -606,11 +610,12 @@ static int vidioc_s_std(struct file *file, void *_fh, return hdpvr_config_call(dev, CTRL_VIDEO_STD_TYPE, std_type); } -static int vidioc_g_std(struct file *file, void *_fh, +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); + if (!fh->legacy_mode && dev->options.video_input == HDPVR_COMPONENT) return -ENODATA; @@ -618,11 +623,11 @@ static int vidioc_g_std(struct file *file, void *_fh, return 0; } -static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) +static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *a) { struct hdpvr_device *dev = video_drvdata(file); + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); struct hdpvr_video_info vid_info; - struct hdpvr_fh *fh = _fh; int ret; *a = V4L2_STD_UNKNOWN; @@ -637,11 +642,11 @@ static int vidioc_querystd(struct file *file, void *_fh, v4l2_std_id *a) return ret; } -static int vidioc_s_dv_timings(struct file *file, void *_fh, +static int vidioc_s_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); int i; fh->legacy_mode = false; @@ -660,11 +665,11 @@ static int vidioc_s_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_g_dv_timings(struct file *file, void *_fh, +static int vidioc_g_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; if (dev->options.video_input) @@ -673,11 +678,11 @@ static int vidioc_g_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_query_dv_timings(struct file *file, void *_fh, +static int vidioc_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); struct hdpvr_video_info vid_info; bool interlaced; int ret = 0; @@ -715,11 +720,11 @@ static int vidioc_query_dv_timings(struct file *file, void *_fh, return ret; } -static int vidioc_enum_dv_timings(struct file *file, void *_fh, +static int vidioc_enum_dv_timings(struct file *file, void *priv, struct v4l2_enum_dv_timings *timings) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; memset(timings->reserved, 0, sizeof(timings->reserved)); @@ -731,11 +736,11 @@ static int vidioc_enum_dv_timings(struct file *file, void *_fh, return 0; } -static int vidioc_dv_timings_cap(struct file *file, void *_fh, +static int vidioc_dv_timings_cap(struct file *file, void *priv, struct v4l2_dv_timings_cap *cap) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); fh->legacy_mode = false; if (dev->options.video_input) @@ -758,7 +763,7 @@ static const char *iname[] = { [HDPVR_COMPOSITE] = "Composite", }; -static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) +static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { unsigned int n; @@ -778,7 +783,7 @@ static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) return 0; } -static int vidioc_s_input(struct file *file, void *_fh, +static int vidioc_s_input(struct file *file, void *priv, unsigned int index) { struct hdpvr_device *dev = video_drvdata(file); @@ -812,7 +817,7 @@ static int vidioc_s_input(struct file *file, void *_fh, return retval; } -static int vidioc_g_input(struct file *file, void *private_data, +static int vidioc_g_input(struct file *file, void *priv, unsigned int *index) { struct hdpvr_device *dev = video_drvdata(file); @@ -844,7 +849,7 @@ static int vidioc_enumaudio(struct file *file, void *priv, return 0; } -static int vidioc_s_audio(struct file *file, void *private_data, +static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *audio) { struct hdpvr_device *dev = video_drvdata(file); @@ -863,7 +868,7 @@ static int vidioc_s_audio(struct file *file, void *private_data, return retval; } -static int vidioc_g_audio(struct file *file, void *private_data, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *audio) { struct hdpvr_device *dev = video_drvdata(file); @@ -980,7 +985,7 @@ static int hdpvr_s_ctrl(struct v4l2_ctrl *ctrl) return ret; } -static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index != 0) @@ -991,11 +996,11 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, return 0; } -static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct hdpvr_device *dev = video_drvdata(file); - struct hdpvr_fh *fh = _fh; + struct hdpvr_fh *fh = file_to_hdpvr_fh(file); int ret; /* @@ -1048,7 +1053,7 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv, switch (a->cmd) { case V4L2_ENC_CMD_START: - if (dev->owner && filp->private_data != dev->owner) { + if (dev->owner && file_to_v4l2_fh(filp) != dev->owner) { res = -EBUSY; break; } @@ -1056,12 +1061,12 @@ static int vidioc_encoder_cmd(struct file *filp, void *priv, break; res = hdpvr_start_streaming(dev); if (!res) - dev->owner = filp->private_data; + dev->owner = file_to_v4l2_fh(filp); else dev->status = STATUS_IDLE; break; case V4L2_ENC_CMD_STOP: - if (dev->owner && filp->private_data != dev->owner) { + if (dev->owner && file_to_v4l2_fh(filp) != dev->owner) { res = -EBUSY; break; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index f21c2806eb9f..b32bb906a9de 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -3622,7 +3622,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, pvr2_trace( PVR2_TRACE_ERROR_LEGS, "Attempted to execute %d byte control-read transfer (limit=%d)", - write_len,PVR2_CTL_BUFFSIZE); + read_len, PVR2_CTL_BUFFSIZE); return -EINVAL; } if ((!write_len) && (!read_len)) { diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index ad38e1240541..f9535a484738 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -21,8 +21,6 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> -struct pvr2_v4l2_dev; -struct pvr2_v4l2_fh; struct pvr2_v4l2; struct pvr2_v4l2_dev { @@ -48,6 +46,11 @@ struct pvr2_v4l2_fh { unsigned int input_cnt; }; +static inline struct pvr2_v4l2_fh *to_pvr2_v4l2_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct pvr2_v4l2_fh, fh); +} + struct pvr2_v4l2 { struct pvr2_channel channel; @@ -108,7 +111,7 @@ static struct v4l2_format pvr_format [] = { */ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; strscpy(cap->driver, "pvrusb2", sizeof(cap->driver)); @@ -123,7 +126,7 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability * static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int ret; @@ -136,7 +139,7 @@ static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -148,7 +151,7 @@ static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id std) static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int ret; @@ -161,7 +164,7 @@ static int pvr2_querystd(struct file *file, void *priv, v4l2_std_id *std) static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *cptr; struct v4l2_input tmp; @@ -209,7 +212,7 @@ static int pvr2_enum_input(struct file *file, void *priv, struct v4l2_input *vi) static int pvr2_g_input(struct file *file, void *priv, unsigned int *i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned int idx; struct pvr2_ctrl *cptr; @@ -231,7 +234,7 @@ static int pvr2_g_input(struct file *file, void *priv, unsigned int *i) static int pvr2_s_input(struct file *file, void *priv, unsigned int inp) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -286,7 +289,7 @@ static int pvr2_s_audio(struct file *file, void *priv, const struct v4l2_audio * static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; if (vt->index != 0) @@ -298,7 +301,7 @@ static int pvr2_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -314,7 +317,7 @@ static int pvr2_s_tuner(struct file *file, void *priv, const struct v4l2_tuner * static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned long fv; struct v4l2_tuner vt; @@ -349,7 +352,7 @@ static int pvr2_s_frequency(struct file *file, void *priv, const struct v4l2_fre static int pvr2_g_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val = 0; int cur_input; @@ -391,7 +394,7 @@ static int pvr2_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtd static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int val; @@ -411,7 +414,7 @@ static int pvr2_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int lmin, lmax, ldef; struct pvr2_ctrl *hcp, *vcp; @@ -449,7 +452,7 @@ static int pvr2_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_forma static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *hcp, *vcp; int ret = pvr2_try_fmt_vid_cap(file, fh, vf); @@ -466,7 +469,7 @@ static int pvr2_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_v4l2_dev *pdi = fh->pdi; int ret; @@ -485,7 +488,7 @@ static int pvr2_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; if (!fh->pdi->stream) { @@ -500,7 +503,7 @@ static int pvr2_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) static int pvr2_query_ext_ctrl(struct file *file, void *priv, struct v4l2_query_ext_ctrl *vc) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct pvr2_ctrl *cptr; int val; @@ -561,7 +564,7 @@ static int pvr2_query_ext_ctrl(struct file *file, void *priv, static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu *vm) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; unsigned int cnt = 0; int ret; @@ -577,7 +580,7 @@ static int pvr2_querymenu(struct file *file, void *priv, struct v4l2_querymenu * static int pvr2_g_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; struct pvr2_ctrl *cptr; @@ -612,7 +615,7 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv, static int pvr2_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; unsigned int idx; @@ -637,7 +640,7 @@ commit: static int pvr2_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctls) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_ext_control *ctrl; struct pvr2_ctrl *pctl; @@ -659,7 +662,7 @@ static int pvr2_try_ext_ctrls(struct file *file, void *priv, static int pvr2_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_cropcap cap = { .type = type }; int ret; @@ -675,7 +678,7 @@ static int pvr2_g_pixelaspect(struct file *file, void *priv, static int pvr2_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; struct v4l2_cropcap cap; int val = 0; @@ -726,7 +729,7 @@ static int pvr2_g_selection(struct file *file, void *priv, static int pvr2_s_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; int ret; @@ -758,7 +761,7 @@ commit: static int pvr2_log_status(struct file *file, void *priv) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; pvr2_hdw_trigger_module_log(hdw); @@ -882,7 +885,7 @@ static void pvr2_v4l2_internal_check(struct pvr2_channel *chp) static int pvr2_v4l2_release(struct file *file) { - struct pvr2_v4l2_fh *fhp = file->private_data; + struct pvr2_v4l2_fh *fhp = to_pvr2_v4l2_fh(file); struct pvr2_v4l2 *vp = fhp->pdi->v4lp; struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw; @@ -897,9 +900,8 @@ static int pvr2_v4l2_release(struct file *file) fhp->rhp = NULL; } - v4l2_fh_del(&fhp->fh); + v4l2_fh_del(&fhp->fh, file); v4l2_fh_exit(&fhp->fh); - file->private_data = NULL; pvr2_channel_done(&fhp->channel); pvr2_trace(PVR2_TRACE_STRUCT, @@ -1000,10 +1002,9 @@ static int pvr2_v4l2_open(struct file *file) } fhp->file = file; - file->private_data = fhp; fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw); - v4l2_fh_add(&fhp->fh); + v4l2_fh_add(&fhp->fh, file); return 0; } @@ -1055,7 +1056,7 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) static ssize_t pvr2_v4l2_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); int ret; if (fh->fw_mode_flag) { @@ -1117,7 +1118,7 @@ static ssize_t pvr2_v4l2_read(struct file *file, static __poll_t pvr2_v4l2_poll(struct file *file, poll_table *wait) { __poll_t mask = 0; - struct pvr2_v4l2_fh *fh = file->private_data; + struct pvr2_v4l2_fh *fh = to_pvr2_v4l2_fh(file); int ret; if (fh->fw_mode_flag) { diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index ce717502ea4c..25d725c2ab3c 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -195,8 +195,7 @@ static int stk1160_scan_usb(struct usb_interface *intf, struct usb_device *udev, if (udev->speed == USB_SPEED_HIGH) size = size * hb_mult(sizedescr); - if (usb_endpoint_xfer_isoc(desc) && - usb_endpoint_dir_in(desc)) { + if (usb_endpoint_is_isoc_in(desc)) { switch (desc->bEndpointAddress) { case STK1160_EP_AUDIO: has_audio = true; diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 416cb74377eb..f4baf9263286 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -408,8 +408,13 @@ static int stk1160_fill_urb(struct stk1160 *dev, struct stk1160_urb *stk_urb, stk_urb->transfer_buffer = usb_alloc_noncoherent(dev->udev, sb_size, GFP_KERNEL, &stk_urb->dma, DMA_FROM_DEVICE, &stk_urb->sgt); - if (!stk_urb->transfer_buffer) + if (!stk_urb->transfer_buffer) { + /* + * If the buffer allocation failed, we exit but return 0 since + * we allow the driver working with less buffers. + */ goto free_urb; + } stk_urb->dev = dev; return 0; diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index efe609d70877..2905505c240c 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -376,6 +376,15 @@ static const struct uvc_control_info uvc_ctrls[] = { | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_AUTO_UPDATE, }, + { + .entity = UVC_GUID_CHROMEOS_XU, + .selector = UVC_CROSXU_CONTROL_IQ_PROFILE, + .index = 3, + .size = 1, + .flags = UVC_CTRL_FLAG_SET_CUR + | UVC_CTRL_FLAG_GET_RANGE + | UVC_CTRL_FLAG_RESTORE, + }, }; static const u32 uvc_control_classes[] = { @@ -384,6 +393,19 @@ static const u32 uvc_control_classes[] = { }; static const int exposure_auto_mapping[] = { 2, 1, 4, 8 }; +static const int cros_colorfx_mapping[] = { + 1, /* V4L2_COLORFX_NONE */ + -1, /* V4L2_COLORFX_BW */ + -1, /* V4L2_COLORFX_SEPIA */ + -1, /* V4L2_COLORFX_NEGATIVE */ + -1, /* V4L2_COLORFX_EMBOSS */ + -1, /* V4L2_COLORFX_SKETCH */ + -1, /* V4L2_COLORFX_SKY_BLUE */ + -1, /* V4L2_COLORFX_GRASS_GREEN */ + -1, /* V4L2_COLORFX_SKIN_WHITEN */ + 0, /* V4L2_COLORFX_VIVID */ +}; + static bool uvc_ctrl_mapping_is_compound(struct uvc_control_mapping *mapping) { @@ -975,6 +997,18 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = { .data_type = UVC_CTRL_DATA_TYPE_BITMASK, .name = "Region of Interest Auto Ctrls", }, + { + .id = V4L2_CID_COLORFX, + .entity = UVC_GUID_CHROMEOS_XU, + .selector = UVC_CROSXU_CONTROL_IQ_PROFILE, + .size = 8, + .offset = 0, + .v4l2_type = V4L2_CTRL_TYPE_MENU, + .data_type = UVC_CTRL_DATA_TYPE_ENUM, + .menu_mapping = cros_colorfx_mapping, + .menu_mask = BIT(V4L2_COLORFX_VIVID) | + BIT(V4L2_COLORFX_NONE), + }, }; /* ------------------------------------------------------------------------ @@ -1619,7 +1653,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, } if (ret == -EIO) { - dev_warn_ratelimited(&chain->dev->udev->dev, + dev_warn_ratelimited(&chain->dev->intf->dev, "UVC non compliance: Error %d querying master control %x (%s)\n", ret, master_map->id, uvc_map_get_name(master_map)); @@ -1643,7 +1677,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl); if (ret && !mapping->disabled) { - dev_warn(&chain->dev->udev->dev, + dev_warn(&chain->dev->intf->dev, "UVC non compliance: permanently disabling control %x (%s), due to error %d\n", mapping->id, uvc_map_get_name(mapping), ret); mapping->disabled = true; @@ -1858,7 +1892,7 @@ static int uvc_ctrl_set_handle(struct uvc_control *ctrl, struct uvc_fh *handle) lockdep_assert_held(&handle->chain->ctrl_mutex); if (ctrl->handle) { - dev_warn_ratelimited(&handle->stream->dev->udev->dev, + dev_warn_ratelimited(&handle->stream->dev->intf->dev, "UVC non compliance: Setting an async control with a pending operation."); if (ctrl->handle == handle) @@ -1956,7 +1990,7 @@ static void uvc_ctrl_status_event_work(struct work_struct *work) w->urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(w->urb, GFP_KERNEL); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to resubmit status URB (%d).\n", ret); } @@ -2895,7 +2929,7 @@ int uvc_ctrl_restore_values(struct uvc_device *dev) if (!ctrl->initialized || !ctrl->modified || (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0) continue; - dev_dbg(&dev->udev->dev, + dev_dbg(&dev->intf->dev, "restoring control %pUl/%u/%u\n", ctrl->info.entity, ctrl->info.index, ctrl->info.selector); @@ -3181,15 +3215,6 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain, { unsigned int i; - /* - * XU controls initialization requires querying the device for control - * information. As some buggy UVC devices will crash when queried - * repeatedly in a tight loop, delay XU controls initialization until - * first use. - */ - if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT) - return; - for (i = 0; i < ARRAY_SIZE(uvc_ctrls); ++i) { const struct uvc_control_info *info = &uvc_ctrls[i]; @@ -3307,7 +3332,6 @@ int uvc_ctrl_init_device(struct uvc_device *dev) void uvc_ctrl_cleanup_fh(struct uvc_fh *handle) { struct uvc_entity *entity; - int i; guard(mutex)(&handle->chain->ctrl_mutex); @@ -3325,7 +3349,7 @@ void uvc_ctrl_cleanup_fh(struct uvc_fh *handle) if (!WARN_ON(handle->pending_async_ctrls)) return; - for (i = 0; i < handle->pending_async_ctrls; i++) + for (unsigned int i = 0; i < handle->pending_async_ctrls; i++) uvc_pm_put(handle->stream->dev); } diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 775bede0d93d..ee4f54d68349 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -137,6 +137,9 @@ struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) { struct uvc_entity *entity; + if (id == UVC_INVALID_ENTITY_ID) + return NULL; + list_for_each_entry(entity, &dev->entities, list) { if (entity->id == id) return entity; @@ -164,13 +167,26 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev, static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id) { - struct uvc_streaming *stream; + struct uvc_streaming *stream, *last_stream; + unsigned int count = 0; list_for_each_entry(stream, &dev->streams, list) { + count += 1; + last_stream = stream; if (stream->header.bTerminalLink == id) return stream; } + /* + * If the streaming entity is referenced by an invalid ID, notify the + * user and use heuristics to guess the correct entity. + */ + if (count == 1 && id == UVC_INVALID_ENTITY_ID) { + dev_warn(&dev->intf->dev, + "UVC non compliance: Invalid USB header. The streaming entity has an invalid ID, guessing the correct one."); + return last_stream; + } + return NULL; } @@ -183,8 +199,6 @@ static void uvc_stream_delete(struct uvc_streaming *stream) if (stream->async_wq) destroy_workqueue(stream->async_wq); - mutex_destroy(&stream->mutex); - usb_put_intf(stream->intf); kfree(stream->formats); @@ -201,8 +215,6 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev, if (stream == NULL) return NULL; - mutex_init(&stream->mutex); - stream->dev = dev; stream->intf = usb_get_intf(intf); stream->intfnum = intf->cur_altsetting->desc.bInterfaceNumber; @@ -539,7 +551,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, unsigned int nformats = 0, nframes = 0, nintervals = 0; unsigned int size, i, n, p; u32 *interval; - u16 psize; + u32 psize; int ret = -EINVAL; if (intf->cur_altsetting->desc.bInterfaceSubClass @@ -775,7 +787,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, streaming->header.bEndpointAddress); if (ep == NULL) continue; - psize = uvc_endpoint_max_bpi(dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(dev->udev, ep); if (psize > streaming->maxpsize) streaming->maxpsize = psize; } @@ -795,14 +807,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->intf->dev, "Found Unit with invalid ID 0\n"); + id = UVC_INVALID_ENTITY_ID; + } + + /* Per UVC 1.1+ spec 3.7.2, the ID is unique. */ + if (uvc_entity_by_id(dev, id)) { + dev_err(&dev->intf->dev, "Found multiple Units with ID %u\n", id); + id = UVC_INVALID_ENTITY_ID; + } + extra_size = roundup(extra_size, sizeof(*entity->pads)); if (num_pads) num_inputs = type & UVC_TERM_OUTPUT ? num_pads : num_pads - 1; @@ -812,7 +837,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; @@ -882,7 +907,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, unsigned int n, p; int handled = 0; - switch (le16_to_cpu(dev->udev->descriptor.idVendor)) { + switch (le16_to_cpu(udev->descriptor.idVendor)) { case 0x046d: /* Logitech */ if (buffer[1] != 0x41 || buffer[2] != 0x01) break; @@ -924,10 +949,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]; @@ -1036,10 +1061,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; @@ -1095,10 +1120,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); @@ -1117,9 +1142,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); @@ -1139,9 +1165,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 = @@ -1168,9 +1194,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]; @@ -1315,9 +1342,10 @@ static int uvc_gpio_parse(struct uvc_device *dev) return dev_err_probe(&dev->intf->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; @@ -1868,7 +1896,7 @@ static int uvc_scan_device(struct uvc_device *dev) uvc_scan_fallback(dev); if (list_empty(&dev->chains)) { - dev_info(&dev->udev->dev, "No valid video chain found.\n"); + dev_info(&dev->intf->dev, "No valid video chain found.\n"); return -ENODEV; } @@ -1958,11 +1986,11 @@ static void uvc_unregister_video(struct uvc_device *dev) list_for_each_entry(stream, &dev->streams, list) { /* Nothing to do here, continue. */ - if (!video_is_registered(&stream->vdev)) + if (!video_is_registered(&stream->queue.vdev)) continue; - vb2_video_unregister_device(&stream->vdev); - vb2_video_unregister_device(&stream->meta.vdev); + vb2_video_unregister_device(&stream->queue.vdev); + vb2_video_unregister_device(&stream->meta.queue.vdev); /* * Now both vdevs are not streaming and all the ioctls will @@ -1984,12 +2012,12 @@ static void uvc_unregister_video(struct uvc_device *dev) int uvc_register_video_device(struct uvc_device *dev, struct uvc_streaming *stream, - struct video_device *vdev, struct uvc_video_queue *queue, enum v4l2_buf_type type, const struct v4l2_file_operations *fops, const struct v4l2_ioctl_ops *ioctl_ops) { + struct video_device *vdev = &queue->vdev; int ret; /* Initialize the video buffers queue. */ @@ -2071,9 +2099,9 @@ static int uvc_register_video(struct uvc_device *dev, uvc_debugfs_init_stream(stream); /* Register the device with V4L. */ - return uvc_register_video_device(dev, stream, &stream->vdev, - &stream->queue, stream->type, - &uvc_fops, &uvc_ioctl_ops); + return uvc_register_video_device(dev, stream, &stream->queue, + stream->type, &uvc_fops, + &uvc_ioctl_ops); } /* @@ -2092,7 +2120,7 @@ static int uvc_register_terms(struct uvc_device *dev, stream = uvc_stream_by_id(dev, term->id); if (stream == NULL) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "No streaming interface found for terminal %u.", term->id); continue; @@ -2109,7 +2137,7 @@ static int uvc_register_terms(struct uvc_device *dev, */ uvc_meta_register(stream); - term->vdev = &stream->vdev; + term->vdev = &stream->queue.vdev; } return 0; @@ -2128,7 +2156,7 @@ static int uvc_register_chains(struct uvc_device *dev) #ifdef CONFIG_MEDIA_CONTROLLER ret = uvc_mc_register_entities(chain); if (ret < 0) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Failed to register entities (%d).\n", ret); #endif } @@ -2229,23 +2257,23 @@ static int uvc_probe(struct usb_interface *intf, if (ret < 0) goto error; - dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n", + dev_info(&dev->intf->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n", dev->uvc_version >> 8, dev->uvc_version & 0xff, udev->product ? udev->product : "<unnamed>", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); if (dev->quirks != dev->info->quirks) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Forcing device quirks to 0x%x by module parameter for testing purpose.\n", dev->quirks); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Please report required quirks to the linux-media mailing list.\n"); } if (dev->info->uvc_version) { dev->uvc_version = dev->info->uvc_version; - dev_info(&dev->udev->dev, "Forcing UVC version to %u.%02x\n", + dev_info(&dev->intf->dev, "Forcing UVC version to %u.%02x\n", dev->uvc_version >> 8, dev->uvc_version & 0xff); } @@ -2281,21 +2309,21 @@ static int uvc_probe(struct usb_interface *intf, /* Initialize the interrupt URB. */ ret = uvc_status_init(dev); if (ret < 0) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Unable to initialize the status endpoint (%d), status interrupt will not be supported.\n", ret); } ret = uvc_gpio_init_irq(dev); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Unable to request privacy GPIO IRQ (%d)\n", ret); goto error; } ret = uvc_meta_init(dev); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Error initializing the metadata formats (%d)\n", ret); goto error; } diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index cc68dd24eb42..3823ac9c8045 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -140,7 +140,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) list_for_each_entry(entity, &chain->entities, chain) { ret = uvc_mc_init_entity(chain, entity); if (ret < 0) { - dev_info(&chain->dev->udev->dev, + dev_info(&chain->dev->intf->dev, "Failed to initialize entity for entity %u\n", entity->id); return ret; @@ -150,7 +150,7 @@ int uvc_mc_register_entities(struct uvc_video_chain *chain) list_for_each_entry(entity, &chain->entities, chain) { ret = uvc_mc_create_links(chain, entity); if (ret < 0) { - dev_info(&chain->dev->udev->dev, + dev_info(&chain->dev->intf->dev, "Failed to create links for entity %u\n", entity->id); return ret; diff --git a/drivers/media/usb/uvc/uvc_metadata.c b/drivers/media/usb/uvc/uvc_metadata.c index 229e08ff323e..c23b174965c3 100644 --- a/drivers/media/usb/uvc/uvc_metadata.c +++ b/drivers/media/usb/uvc/uvc_metadata.c @@ -23,10 +23,10 @@ * V4L2 ioctls */ -static int uvc_meta_v4l2_querycap(struct file *file, void *fh, +static int uvc_meta_v4l2_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_video_chain *chain = stream->chain; @@ -39,28 +39,26 @@ static int uvc_meta_v4l2_querycap(struct file *file, void *fh, return 0; } -static int uvc_meta_v4l2_get_format(struct file *file, void *fh, +static int uvc_meta_v4l2_get_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; if (format->type != vfh->vdev->queue->type) return -EINVAL; - memset(fmt, 0, sizeof(*fmt)); - fmt->dataformat = stream->meta.format; fmt->buffersize = UVC_METADATA_BUF_SIZE; return 0; } -static int uvc_meta_v4l2_try_format(struct file *file, void *fh, +static int uvc_meta_v4l2_try_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; struct v4l2_meta_format *fmt = &format->fmt.meta; @@ -69,11 +67,12 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh, if (format->type != vfh->vdev->queue->type) return -EINVAL; - for (unsigned int i = 0; i < dev->nmeta_formats; i++) + for (unsigned int i = 0; i < dev->nmeta_formats; i++) { if (dev->meta_formats[i] == fmt->dataformat) { fmeta = fmt->dataformat; break; } + } memset(fmt, 0, sizeof(*fmt)); @@ -83,15 +82,15 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh, return 0; } -static int uvc_meta_v4l2_set_format(struct file *file, void *fh, +static int uvc_meta_v4l2_set_format(struct file *file, void *priv, struct v4l2_format *format) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct v4l2_meta_format *fmt = &format->fmt.meta; int ret; - ret = uvc_meta_v4l2_try_format(file, fh, format); + ret = uvc_meta_v4l2_try_format(file, priv, format); if (ret < 0) return ret; @@ -100,37 +99,28 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh, * Metadata buffers would still be perfectly parseable, but it's more * consistent and cleaner to disallow that. */ - mutex_lock(&stream->mutex); - if (vb2_is_busy(&stream->meta.queue.queue)) - ret = -EBUSY; - else - stream->meta.format = fmt->dataformat; + return -EBUSY; - mutex_unlock(&stream->mutex); + stream->meta.format = fmt->dataformat; - return ret; + return 0; } -static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh, +static int uvc_meta_v4l2_enum_formats(struct file *file, void *priv, struct v4l2_fmtdesc *fdesc) { - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct uvc_streaming *stream = video_get_drvdata(vfh->vdev); struct uvc_device *dev = stream->dev; - u32 i = fdesc->index; if (fdesc->type != vfh->vdev->queue->type) return -EINVAL; - if (i >= dev->nmeta_formats) + if (fdesc->index >= dev->nmeta_formats) return -EINVAL; - memset(fdesc, 0, sizeof(*fdesc)); - - fdesc->type = vfh->vdev->queue->type; - fdesc->index = i; - fdesc->pixelformat = dev->meta_formats[i]; + fdesc->pixelformat = dev->meta_formats[fdesc->index]; return 0; } @@ -177,7 +167,6 @@ static struct uvc_entity *uvc_meta_find_msxu(struct uvc_device *dev) return NULL; } -#define MSXU_CONTROL_METADATA 0x9 static int uvc_meta_detect_msxu(struct uvc_device *dev) { u32 *data __free(kfree) = NULL; @@ -196,9 +185,12 @@ static int uvc_meta_detect_msxu(struct uvc_device *dev) if (!data) return -ENOMEM; - /* Check if the metadata is already enabled. */ + /* + * Check if the metadata is already enabled, or if the device always + * returns metadata. + */ ret = uvc_query_ctrl(dev, UVC_GET_CUR, entity->id, dev->intfnum, - MSXU_CONTROL_METADATA, data, sizeof(*data)); + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); if (ret) return 0; @@ -208,21 +200,23 @@ static int uvc_meta_detect_msxu(struct uvc_device *dev) } /* - * We have seen devices that require 1 to enable the metadata, others - * requiring a value != 1 and others requiring a value >1. Luckily for - * us, the value from GET_MAX seems to work all the time. + * Set the value of UVC_MSXU_CONTROL_METADATA to the value reported by + * GET_MAX to enable production of MSXU metadata. The GET_MAX request + * reports the maximum size of the metadata, if its value is 0 then MSXU + * metadata is not supported. For more information, see + * https://learn.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5#2229-metadata-control */ ret = uvc_query_ctrl(dev, UVC_GET_MAX, entity->id, dev->intfnum, - MSXU_CONTROL_METADATA, data, sizeof(*data)); + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); if (ret || !*data) return 0; /* - * If we can set MSXU_CONTROL_METADATA, the device will report + * If we can set UVC_MSXU_CONTROL_METADATA, the device will report * metadata. */ ret = uvc_query_ctrl(dev, UVC_SET_CUR, entity->id, dev->intfnum, - MSXU_CONTROL_METADATA, data, sizeof(*data)); + UVC_MSXU_CONTROL_METADATA, data, sizeof(*data)); if (!ret) dev->quirks |= UVC_QUIRK_MSXU_META; @@ -232,12 +226,11 @@ static int uvc_meta_detect_msxu(struct uvc_device *dev) int uvc_meta_register(struct uvc_streaming *stream) { struct uvc_device *dev = stream->dev; - struct video_device *vdev = &stream->meta.vdev; struct uvc_video_queue *queue = &stream->meta.queue; stream->meta.format = V4L2_META_FMT_UVC; - return uvc_register_video_device(dev, stream, vdev, queue, + return uvc_register_video_device(dev, stream, queue, V4L2_BUF_TYPE_META_CAPTURE, &uvc_meta_fops, &uvc_meta_ioctl_ops); } diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c index ee01dce4b783..231cfee8e7c2 100644 --- a/drivers/media/usb/uvc/uvc_status.c +++ b/drivers/media/usb/uvc/uvc_status.c @@ -62,7 +62,8 @@ static int uvc_input_init(struct uvc_device *dev) __set_bit(EV_KEY, input->evbit); __set_bit(KEY_CAMERA, input->keybit); - if ((ret = input_register_device(input)) < 0) + ret = input_register_device(input); + if (ret < 0) goto error; dev->input = input; @@ -215,7 +216,7 @@ static void uvc_status_complete(struct urb *urb) return; default: - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "Non-zero status (%d) in status completion handler.\n", urb->status); return; @@ -247,7 +248,7 @@ static void uvc_status_complete(struct urb *urb) urb->interval = dev->int_ep->desc.bInterval; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to resubmit status URB (%d).\n", ret); } diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 160f9cf6e6db..9e4a251eca88 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -329,14 +329,12 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, * developers test their webcams with the Linux driver as well as with * the Windows driver). */ - mutex_lock(&stream->mutex); if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS) probe->dwMaxVideoFrameSize = stream->ctrl.dwMaxVideoFrameSize; /* Probe the device. */ ret = uvc_probe_video(stream, probe); - mutex_unlock(&stream->mutex); if (ret < 0) return ret; @@ -388,26 +386,22 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, return ret; } -static int uvc_ioctl_g_fmt(struct file *file, void *fh, +static int uvc_ioctl_g_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format; const struct uvc_frame *frame; - int ret = 0; if (fmt->type != stream->type) return -EINVAL; - mutex_lock(&stream->mutex); format = stream->cur_format; frame = stream->cur_frame; - if (format == NULL || frame == NULL) { - ret = -EINVAL; - goto done; - } + if (!format || !frame) + return -EINVAL; fmt->fmt.pix.pixelformat = format->fcc; fmt->fmt.pix.width = frame->wWidth; @@ -419,15 +413,13 @@ static int uvc_ioctl_g_fmt(struct file *file, void *fh, fmt->fmt.pix.xfer_func = format->xfer_func; fmt->fmt.pix.ycbcr_enc = format->ycbcr_enc; -done: - mutex_unlock(&stream->mutex); - return ret; + return 0; } -static int uvc_ioctl_s_fmt(struct file *file, void *fh, +static int uvc_ioctl_s_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; const struct uvc_format *format; @@ -441,35 +433,27 @@ static int uvc_ioctl_s_fmt(struct file *file, void *fh, if (ret < 0) return ret; - mutex_lock(&stream->mutex); - if (vb2_is_busy(&stream->queue.queue)) { - ret = -EBUSY; - goto done; - } + if (vb2_is_busy(&stream->queue.queue)) + return -EBUSY; stream->ctrl = probe; stream->cur_format = format; stream->cur_frame = frame; -done: - mutex_unlock(&stream->mutex); - return ret; + return 0; } -static int uvc_ioctl_g_parm(struct file *file, void *fh, +static int uvc_ioctl_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { u32 numerator, denominator; - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; if (parm->type != stream->type) return -EINVAL; - mutex_lock(&stream->mutex); numerator = stream->ctrl.dwFrameInterval; - mutex_unlock(&stream->mutex); - denominator = 10000000; v4l2_simplify_fraction(&numerator, &denominator, 8, 333); @@ -493,10 +477,10 @@ static int uvc_ioctl_g_parm(struct file *file, void *fh, return 0; } -static int uvc_ioctl_s_parm(struct file *file, void *fh, +static int uvc_ioctl_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; struct v4l2_fract timeperframe; @@ -519,12 +503,8 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh, uvc_dbg(stream->dev, FORMAT, "Setting frame interval to %u/%u (%u)\n", timeperframe.numerator, timeperframe.denominator, interval); - mutex_lock(&stream->mutex); - - if (uvc_queue_streaming(&stream->queue)) { - mutex_unlock(&stream->mutex); + if (uvc_queue_streaming(&stream->queue)) return -EBUSY; - } format = stream->cur_format; frame = stream->cur_frame; @@ -556,14 +536,11 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh, /* Probe the device with the new settings. */ ret = uvc_probe_video(stream, &probe); - if (ret < 0) { - mutex_unlock(&stream->mutex); + if (ret < 0) return ret; - } stream->ctrl = probe; stream->cur_frame = frame; - mutex_unlock(&stream->mutex); /* Return the actual frame period. */ timeperframe.numerator = probe.dwFrameInterval; @@ -599,18 +576,17 @@ static int uvc_v4l2_open(struct file *file) if (!handle) return -ENOMEM; - v4l2_fh_init(&handle->vfh, &stream->vdev); - v4l2_fh_add(&handle->vfh); + v4l2_fh_init(&handle->vfh, &stream->queue.vdev); + v4l2_fh_add(&handle->vfh, file); handle->chain = stream->chain; handle->stream = stream; - file->private_data = handle; return 0; } static int uvc_v4l2_release(struct file *file) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; uvc_dbg(stream->dev, CALLS, "%s\n", __func__); @@ -623,10 +599,10 @@ static int uvc_v4l2_release(struct file *file) return 0; } -static int uvc_ioctl_querycap(struct file *file, void *fh, +static int uvc_ioctl_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct uvc_streaming *stream = handle->stream; @@ -639,10 +615,10 @@ static int uvc_ioctl_querycap(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_fmt(struct file *file, void *fh, +static int uvc_ioctl_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; enum v4l2_buf_type type = fmt->type; const struct uvc_format *format; @@ -663,20 +639,20 @@ static int uvc_ioctl_enum_fmt(struct file *file, void *fh, return 0; } -static int uvc_ioctl_try_fmt(struct file *file, void *fh, +static int uvc_ioctl_try_fmt(struct file *file, void *priv, struct v4l2_format *fmt) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_streaming_control probe; return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL); } -static int uvc_ioctl_enum_input(struct file *file, void *fh, +static int uvc_ioctl_enum_input(struct file *file, void *priv, struct v4l2_input *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; const struct uvc_entity *selector = chain->selector; struct uvc_entity *iterm = NULL; @@ -716,9 +692,9 @@ static int uvc_ioctl_enum_input(struct file *file, void *fh, return 0; } -static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) +static int uvc_ioctl_g_input(struct file *file, void *priv, unsigned int *input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; u8 *buf; int ret; @@ -744,9 +720,9 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) return ret; } -static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) +static int uvc_ioctl_s_input(struct file *file, void *priv, unsigned int input) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; struct uvc_video_chain *chain = handle->chain; u8 *buf; @@ -778,10 +754,10 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) return ret; } -static int uvc_ioctl_query_ext_ctrl(struct file *file, void *fh, +static int uvc_ioctl_query_ext_ctrl(struct file *file, void *priv, struct v4l2_query_ext_ctrl *qec) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; return uvc_query_v4l2_ctrl(chain, qec); @@ -806,10 +782,10 @@ static int uvc_ctrl_check_access(struct uvc_video_chain *chain, return ret; } -static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_g_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; struct v4l2_ext_control *ctrl = ctrls->controls; unsigned int i; @@ -890,35 +866,35 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle, return uvc_ctrl_rollback(handle); } -static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_s_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_S_EXT_CTRLS); } -static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh, +static int uvc_ioctl_try_ext_ctrls(struct file *file, void *priv, struct v4l2_ext_controls *ctrls) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, VIDIOC_TRY_EXT_CTRLS); } -static int uvc_ioctl_querymenu(struct file *file, void *fh, +static int uvc_ioctl_querymenu(struct file *file, void *priv, struct v4l2_querymenu *qm) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; return uvc_query_v4l2_menu(chain, qm); } -static int uvc_ioctl_g_selection(struct file *file, void *fh, +static int uvc_ioctl_g_selection(struct file *file, void *priv, struct v4l2_selection *sel) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; if (sel->type != stream->type) @@ -941,18 +917,16 @@ static int uvc_ioctl_g_selection(struct file *file, void *fh, sel->r.left = 0; sel->r.top = 0; - mutex_lock(&stream->mutex); sel->r.width = stream->cur_frame->wWidth; sel->r.height = stream->cur_frame->wHeight; - mutex_unlock(&stream->mutex); return 0; } -static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, +static int uvc_ioctl_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format = NULL; const struct uvc_frame *frame = NULL; @@ -989,10 +963,10 @@ static int uvc_ioctl_enum_framesizes(struct file *file, void *fh, return 0; } -static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh, +static int uvc_ioctl_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_streaming *stream = handle->stream; const struct uvc_format *format = NULL; const struct uvc_frame *frame = NULL; @@ -1061,10 +1035,10 @@ static int uvc_ioctl_subscribe_event(struct v4l2_fh *fh, } } -static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio, +static long uvc_ioctl_default(struct file *file, void *priv, bool valid_prio, unsigned int cmd, void *arg) { - struct uvc_fh *handle = fh; + struct uvc_fh *handle = to_uvc_fh(file); struct uvc_video_chain *chain = handle->chain; switch (cmd) { @@ -1170,7 +1144,7 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp, static long uvc_v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); union { struct uvc_xu_control_mapping xmap; struct uvc_xu_control_query xqry; @@ -1221,7 +1195,7 @@ static long uvc_v4l2_compat_ioctl32(struct file *file, static long uvc_v4l2_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct uvc_fh *handle = file->private_data; + struct uvc_fh *handle = to_uvc_fh(file); unsigned int converted_cmd = v4l2_translate_cmd(cmd); int ret; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index a5013a7fbca4..2094e059d7d3 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -95,14 +95,14 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, */ if (ret > 0 && query != UVC_GET_INFO) { memset(data + ret, 0, size - ret); - dev_warn_once(&dev->udev->dev, + dev_warn_once(&dev->intf->dev, "UVC non compliance: %s control %u on unit %u returned %d bytes when we expected %u.\n", uvc_query_name(query), cs, unit, ret, size); return 0; } if (ret != -EPIPE) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Failed to query (%s) UVC control %u on unit %u: %d (exp. %u).\n", uvc_query_name(query), cs, unit, ret, size); return ret < 0 ? ret : -EPIPE; @@ -119,7 +119,7 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, *(u8 *)data = tmp; if (ret != 1) { - dev_err_ratelimited(&dev->udev->dev, + dev_err_ratelimited(&dev->intf->dev, "Failed to query (%s) UVC error code control %u on unit %u: %d (exp. 1).\n", uvc_query_name(query), cs, unit, ret); return ret < 0 ? ret : -EPIPE; @@ -266,7 +266,7 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream, if (stream->intf->num_altsetting > 1 && ctrl->dwMaxPayloadTransferSize > stream->maxpsize) { dev_warn_ratelimited(&stream->intf->dev, - "UVC non compliance: the max payload transmission size (%u) exceeds the size of the ep max packet (%u). Using the max size.\n", + "UVC non compliance: Reducing max payload transfer size (%u) to fit endpoint limit (%u).\n", ctrl->dwMaxPayloadTransferSize, stream->maxpsize); ctrl->dwMaxPayloadTransferSize = stream->maxpsize; @@ -1691,7 +1691,7 @@ static void uvc_video_complete(struct urb *urb) struct uvc_streaming *stream = uvc_urb->stream; struct uvc_video_queue *queue = &stream->queue; struct uvc_video_queue *qmeta = &stream->meta.queue; - struct vb2_queue *vb2_qmeta = stream->meta.vdev.queue; + struct vb2_queue *vb2_qmeta = stream->meta.queue.vdev.queue; struct uvc_buffer *buf = NULL; struct uvc_buffer *buf_meta = NULL; unsigned long flags; @@ -1870,24 +1870,6 @@ static void uvc_video_stop_transfer(struct uvc_streaming *stream, } /* - * Compute the maximum number of bytes per interval for an endpoint. - */ -u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep) -{ - u16 psize; - - switch (dev->speed) { - case USB_SPEED_SUPER: - case USB_SPEED_SUPER_PLUS: - return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); - default: - psize = usb_endpoint_maxp(&ep->desc); - psize *= usb_endpoint_maxp_mult(&ep->desc); - return psize; - } -} - -/* * Initialize isochronous URBs and allocate transfer buffers. The packet size * is given by the endpoint. */ @@ -1897,10 +1879,10 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, struct urb *urb; struct uvc_urb *uvc_urb; unsigned int npackets, i; - u16 psize; + u32 psize; u32 size; - psize = uvc_endpoint_max_bpi(stream->dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(stream->dev->udev, ep); size = stream->ctrl.dwMaxVideoFrameSize; npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags); @@ -2043,7 +2025,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, continue; /* Check if the bandwidth is high enough. */ - psize = uvc_endpoint_max_bpi(stream->dev->udev, ep); + psize = usb_endpoint_max_periodic_payload(stream->dev->udev, ep); if (psize >= bandwidth && psize < best_psize) { altsetting = alts->desc.bAlternateSetting; best_psize = psize; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 757254fc4fe9..ed7bad31f75c 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -41,6 +41,8 @@ #define UVC_EXT_GPIO_UNIT 0x7ffe #define UVC_EXT_GPIO_UNIT_ID 0x100 +#define UVC_INVALID_ENTITY_ID 0xffff + /* ------------------------------------------------------------------------ * Driver specific constants. */ @@ -328,6 +330,7 @@ struct uvc_buffer { #define UVC_QUEUE_DISCONNECTED (1 << 0) struct uvc_video_queue { + struct video_device vdev; struct vb2_queue queue; struct mutex mutex; /* * Serializes vb2_queue and @@ -450,13 +453,12 @@ struct uvc_urb { struct uvc_streaming { struct list_head list; struct uvc_device *dev; - struct video_device vdev; struct uvc_video_chain *chain; atomic_t active; struct usb_interface *intf; int intfnum; - u16 maxpsize; + u32 maxpsize; struct uvc_streaming_header header; enum v4l2_buf_type type; @@ -469,12 +471,6 @@ struct uvc_streaming { const struct uvc_format *cur_format; const struct uvc_frame *cur_frame; - /* - * Protect access to ctrl, cur_format, cur_frame and hardware video - * probe control. - */ - struct mutex mutex; - /* Buffers queue. */ unsigned int frozen : 1; struct uvc_video_queue queue; @@ -483,7 +479,6 @@ struct uvc_streaming { struct uvc_buffer *meta_buf); struct { - struct video_device vdev; struct uvc_video_queue queue; u32 format; } meta; @@ -637,6 +632,11 @@ struct uvc_fh { unsigned int pending_async_ctrls; }; +static inline struct uvc_fh *to_uvc_fh(struct file *filp) +{ + return container_of(file_to_v4l2_fh(filp), struct uvc_fh, vfh); +} + /* ------------------------------------------------------------------------ * Debugging, printing and logging */ @@ -667,7 +667,7 @@ extern unsigned int uvc_hw_timestamps_param; #define uvc_dbg(_dev, flag, fmt, ...) \ do { \ if (uvc_dbg_param & UVC_DBG_##flag) \ - dev_printk(KERN_DEBUG, &(_dev)->udev->dev, fmt, \ + dev_printk(KERN_DEBUG, &(_dev)->intf->dev, fmt, \ ##__VA_ARGS__); \ } while (0) @@ -680,7 +680,7 @@ do { \ #define uvc_warn_once(_dev, warn, fmt, ...) \ do { \ if (!test_and_set_bit(warn, &(_dev)->warnings)) \ - dev_info(&(_dev)->udev->dev, fmt, ##__VA_ARGS__); \ + dev_info(&(_dev)->intf->dev, fmt, ##__VA_ARGS__); \ } while (0) /* -------------------------------------------------------------------------- @@ -733,7 +733,6 @@ int uvc_meta_register(struct uvc_streaming *stream); int uvc_register_video_device(struct uvc_device *dev, struct uvc_streaming *stream, - struct video_device *vdev, struct uvc_video_queue *queue, enum v4l2_buf_type type, const struct v4l2_file_operations *fops, @@ -798,8 +797,6 @@ void uvc_ctrl_cleanup_fh(struct uvc_fh *handle); /* Utility functions */ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, u8 epaddr); -u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep); - /* Quirks support */ void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 331b8e535e5b..d50ccac9733c 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -82,3 +82,7 @@ config V4L2_CCI_I2C depends on I2C select REGMAP_I2C select V4L2_CCI + +config V4L2_ISP + tristate + depends on VIDEOBUF2_CORE diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index 2177b9d63a8f..329f0eadce99 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_V4L2_CCI) += v4l2-cci.o obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o obj-$(CONFIG_V4L2_H264) += v4l2-h264.o +obj-$(CONFIG_V4L2_ISP) += v4l2-isp.o obj-$(CONFIG_V4L2_JPEG_HELPER) += v4l2-jpeg.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o obj-$(CONFIG_V4L2_VP9) += v4l2-vp9.o diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 6e585bc76367..554c591e1113 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -34,6 +34,9 @@ * Added Gerd Knorrs v4l1 enhancements (Justin Schoeman) */ +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/clk-provider.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> @@ -509,8 +512,9 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, } EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); -s64 __v4l2_get_link_freq_ctrl(struct v4l2_ctrl_handler *handler, - unsigned int mul, unsigned int div) +#ifdef CONFIG_MEDIA_CONTROLLER +static s64 v4l2_get_link_freq_ctrl(struct v4l2_ctrl_handler *handler, + unsigned int mul, unsigned int div) { struct v4l2_ctrl *ctrl; s64 freq; @@ -545,11 +549,9 @@ s64 __v4l2_get_link_freq_ctrl(struct v4l2_ctrl_handler *handler, return freq > 0 ? freq : -EINVAL; } -EXPORT_SYMBOL_GPL(__v4l2_get_link_freq_ctrl); -#ifdef CONFIG_MEDIA_CONTROLLER -s64 __v4l2_get_link_freq_pad(struct media_pad *pad, unsigned int mul, - unsigned int div) +s64 v4l2_get_link_freq(const struct media_pad *pad, unsigned int mul, + unsigned int div) { struct v4l2_mbus_config mbus_config = {}; struct v4l2_subdev *sd; @@ -568,10 +570,39 @@ s64 __v4l2_get_link_freq_pad(struct media_pad *pad, unsigned int mul, * Fall back to using the link frequency control if the media bus config * doesn't provide a link frequency. */ - return __v4l2_get_link_freq_ctrl(sd->ctrl_handler, mul, div); + return v4l2_get_link_freq_ctrl(sd->ctrl_handler, mul, div); +} +EXPORT_SYMBOL_GPL(v4l2_get_link_freq); + +int v4l2_get_active_data_lanes(const struct media_pad *pad, + unsigned int max_data_lanes) +{ + struct v4l2_mbus_config mbus_config = {}; + struct v4l2_subdev *sd; + unsigned int lanes; + int ret; + + sd = media_entity_to_v4l2_subdev(pad->entity); + ret = v4l2_subdev_call(sd, pad, get_mbus_config, pad->index, + &mbus_config); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + + /* This relies on the mbus_config being zeroed at init time */ + lanes = mbus_config.bus.mipi_csi2.num_data_lanes; + if (!lanes) + return max_data_lanes; + + if (lanes > max_data_lanes) { + dev_dbg(sd->dev, "Active data lanes (%u) exceeds max (%u)\n", + lanes, max_data_lanes); + return -EINVAL; + } + + return lanes; } -EXPORT_SYMBOL_GPL(__v4l2_get_link_freq_pad); -#endif /* CONFIG_MEDIA_CONTROLLER */ +EXPORT_SYMBOL_GPL(v4l2_get_active_data_lanes); +#endif /* * Simplify a fraction using a simple continued fraction decomposition. The @@ -705,3 +736,73 @@ int v4l2_link_freq_to_bitmap(struct device *dev, const u64 *fw_link_freqs, return 0; } EXPORT_SYMBOL_GPL(v4l2_link_freq_to_bitmap); + +struct clk *__devm_v4l2_sensor_clk_get(struct device *dev, const char *id, + bool legacy, bool fixed_rate, + unsigned long clk_rate) +{ + bool of_node = is_of_node(dev_fwnode(dev)); + const char *clk_id __free(kfree) = NULL; + struct clk_hw *clk_hw; + struct clk *clk; + u32 rate = clk_rate; + int ret = 0; + + clk = devm_clk_get_optional(dev, id); + if (IS_ERR(clk)) + return clk; + + /* + * If the caller didn't request a fixed rate, retrieve it from the + * clock-frequency property. -EINVAL indicates the property is absent, + * and is not a failure. Other errors, or success with a clock-frequency + * value of 0, are hard failures. + */ + if (!fixed_rate || !clk_rate) { + ret = device_property_read_u32(dev, "clock-frequency", &rate); + if ((ret && ret != -EINVAL) || (!ret && !rate)) + return ERR_PTR(-EINVAL); + } + + if (clk) { + /* + * On non-OF platforms, or when legacy behaviour is requested, + * set the clock rate if a rate has been specified by the caller + * or by the clock-frequency property. + */ + if (rate && (!of_node || legacy)) { + ret = clk_set_rate(clk, rate); + if (ret) { + dev_err(dev, "Failed to set clock rate: %u\n", + rate); + return ERR_PTR(ret); + } + } + return clk; + } + + /* + * Register a dummy fixed clock on non-OF platforms or when legacy + * behaviour is requested. This required the common clock framework. + */ + if (!IS_ENABLED(CONFIG_COMMON_CLK) || (of_node && !legacy)) + return ERR_PTR(-ENOENT); + + /* We need a rate to create a clock. */ + if (ret) + return ERR_PTR(ret == -EINVAL ? -EPROBE_DEFER : ret); + + if (!id) { + clk_id = kasprintf(GFP_KERNEL, "clk-%s", dev_name(dev)); + if (!clk_id) + return ERR_PTR(-ENOMEM); + id = clk_id; + } + + clk_hw = devm_clk_hw_register_fixed_rate(dev, id, NULL, 0, rate); + if (IS_ERR(clk_hw)) + return ERR_CAST(clk_hw); + + return clk_hw->clk; +} +EXPORT_SYMBOL_GPL(__devm_v4l2_sensor_clk_get); diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 8c07400bd280..2c88e1175a10 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -8,7 +8,7 @@ * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz) * Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be) - * Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> * * These routines maintain argument size conversion between 32bit and 64bit * ioctls. @@ -672,15 +672,12 @@ struct v4l2_ext_control32 { static inline bool ctrl_is_pointer(struct file *file, u32 id) { struct video_device *vdev = video_devdata(file); - struct v4l2_fh *fh = NULL; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct v4l2_ctrl_handler *hdl = NULL; struct v4l2_query_ext_ctrl qec = { id }; const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; - if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) - fh = file->private_data; - - if (fh && fh->ctrl_handler) + if (fh->ctrl_handler) hdl = fh->ctrl_handler; else if (vdev->ctrl_handler) hdl = vdev->ctrl_handler; @@ -694,7 +691,7 @@ static inline bool ctrl_is_pointer(struct file *file, u32 id) if (!ops || !ops->vidioc_query_ext_ctrl) return false; - return !ops->vidioc_query_ext_ctrl(file, fh, &qec) && + return !ops->vidioc_query_ext_ctrl(file, NULL, &qec) && (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD); } diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c index d49a68b36c28..0078a04c5445 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-api.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c @@ -2,7 +2,7 @@ /* * V4L2 controls framework uAPI implementation: * - * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl> + * Copyright (C) 2010-2021 Hans Verkuil <hverkuil@kernel.org> */ #define pr_fmt(fmt) "v4l2-ctrls: " fmt @@ -1250,14 +1250,17 @@ EXPORT_SYMBOL(v4l2_querymenu); * VIDIOC_LOG_STATUS helpers */ -int v4l2_ctrl_log_status(struct file *file, void *fh) +int v4l2_ctrl_log_status(struct file *file, void *priv) { struct video_device *vfd = video_devdata(file); - struct v4l2_fh *vfh = file->private_data; - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) && vfd->v4l2_dev) + if (vfd->v4l2_dev) { + struct v4l2_fh *vfh = file_to_v4l2_fh(file); + v4l2_ctrl_handler_log_status(vfh->ctrl_handler, vfd->v4l2_dev->name); + } + return 0; } EXPORT_SYMBOL(v4l2_ctrl_log_status); @@ -1348,7 +1351,7 @@ EXPORT_SYMBOL(v4l2_ctrl_subdev_subscribe_event); */ __poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); poll_wait(file, &fh->wait, wait); if (v4l2_event_pending(fh)) diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index 98b960775e87..209bc05883bb 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -2,7 +2,7 @@ /* * V4L2 controls framework core implementation. * - * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl> + * Copyright (C) 2010-2021 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/export.h> @@ -160,7 +160,13 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, break; case V4L2_CTRL_TYPE_AV1_SEQUENCE: p_av1_sequence = p; + /* + * The initial profile is 0 which only allows YUV 420 subsampled + * data. Set the subsampling flags accordingly. + */ p_av1_sequence->bit_depth = 8; + p_av1_sequence->flags |= V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X | + V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y; break; case V4L2_CTRL_TYPE_FWHT_PARAMS: p_fwht_params = p; @@ -827,39 +833,114 @@ static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f) return 0; } +/** + * validate_av1_sequence - validate AV1 sequence header fields + * @s: control struct from userspace + * + * Implements AV1 spec §5.5.2 color_config() checks that are + * possible with the current v4l2_ctrl_av1_sequence definition. + * + * TODO: extend validation once additional fields such as + * color_primaries, transfer_characteristics, + * matrix_coefficients, and chroma_sample_position + * are added to the uAPI. + * + * Returns 0 if valid, -EINVAL otherwise. + */ static int validate_av1_sequence(struct v4l2_ctrl_av1_sequence *s) { - if (s->flags & - ~(V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE | - V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF | - V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION | - V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME | - V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE | - V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X | - V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y | - V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT | - V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q)) - return -EINVAL; + const bool mono = s->flags & V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME; + const bool sx = s->flags & V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X; + const bool sy = s->flags & V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y; + const bool uv_dq = s->flags & V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q; - if (s->seq_profile == 1 && s->flags & V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME) + /* 1. Reject unknown flags */ + if (s->flags & + ~(V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE | + V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF | + V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION | + V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME | + V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE | + V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X | + V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y | + V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT | + V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q)) return -EINVAL; - /* reserved */ + /* 2. Profile range */ if (s->seq_profile > 2) return -EINVAL; - /* TODO: PROFILES */ + /* 3. Monochrome shortcut */ + if (mono) { + /* Profile 1 forbids monochrome */ + if (s->seq_profile == 1) + return -EINVAL; + + /* Mono → subsampling must look like 4:0:0: sx=1, sy=1 */ + if (!sx || !sy) + return -EINVAL; + + /* separate_uv_delta_q must be 0 */ + if (uv_dq) + return -EINVAL; + + return 0; + } + + /* 4. Profile-specific rules */ + switch (s->seq_profile) { + case 0: + /* Profile 0: only 8/10-bit, subsampling=4:2:0 (sx=1, sy=1) */ + if (s->bit_depth != 8 && s->bit_depth != 10) + return -EINVAL; + if (!(sx && sy)) + return -EINVAL; + break; + + case 1: + /* Profile 1: only 8/10-bit, subsampling=4:4:4 (sx=0, sy=0) */ + if (s->bit_depth != 8 && s->bit_depth != 10) + return -EINVAL; + if (sx || sy) + return -EINVAL; + break; + + case 2: + /* Profile 2: 8/10/12-bit allowed */ + if (s->bit_depth != 8 && s->bit_depth != 10 && + s->bit_depth != 12) + return -EINVAL; + + if (s->bit_depth == 12) { + if (!sx) { + /* 4:4:4 → sy must be 0 */ + if (sy) + return -EINVAL; + } else { + /* sx=1 → sy=0 (4:2:2) or sy=1 (4:2:0) */ + if (sy != 0 && sy != 1) + return -EINVAL; + } + } else { + /* 8/10-bit → only 4:2:2 allowed (sx=1, sy=0) */ + if (!(sx && !sy)) + return -EINVAL; + } + break; + } + return 0; } diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index 1ea52011247a..ad41f65374e2 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -2,7 +2,7 @@ /* * V4L2 controls framework control definitions. * - * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl> + * Copyright (C) 2010-2021 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/export.h> diff --git a/drivers/media/v4l2-core/v4l2-ctrls-priv.h b/drivers/media/v4l2-core/v4l2-ctrls-priv.h index aba6176fab6c..f4cf273ecf30 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-priv.h +++ b/drivers/media/v4l2-core/v4l2-ctrls-priv.h @@ -2,7 +2,7 @@ /* * V4L2 controls framework private header. * - * Copyright (C) 2010-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl> + * Copyright (C) 2010-2021 Hans Verkuil <hverkuil@kernel.org> */ #ifndef _V4L2_CTRLS_PRIV_H_ diff --git a/drivers/media/v4l2-core/v4l2-ctrls-request.c b/drivers/media/v4l2-core/v4l2-ctrls-request.c index c637049d7a2b..e77f722b36a4 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-request.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-request.c @@ -2,7 +2,7 @@ /* * V4L2 controls framework Request API implementation. * - * Copyright (C) 2018-2021 Hans Verkuil <hverkuil-cisco@xs4all.nl> + * Copyright (C) 2018-2021 Hans Verkuil <hverkuil@kernel.org> */ #define pr_fmt(fmt) "v4l2-ctrls: " fmt diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index c369235113d9..10a126e50c1c 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -411,7 +411,7 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) static int v4l2_open(struct inode *inode, struct file *filp) { struct video_device *vdev; - int ret = 0; + int ret; /* Check if the video device is available */ mutex_lock(&videodev_lock); @@ -424,16 +424,27 @@ static int v4l2_open(struct inode *inode, struct file *filp) /* and increase the device refcount */ video_get(vdev); mutex_unlock(&videodev_lock); - if (vdev->fops->open) { - if (video_is_registered(vdev)) - ret = vdev->fops->open(filp); - else - ret = -ENODEV; + + if (!video_is_registered(vdev)) { + ret = -ENODEV; + goto done; + } + + ret = vdev->fops->open(filp); + if (ret) + goto done; + + /* All drivers must use v4l2_fh. */ + if (WARN_ON(!test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))) { + vdev->fops->release(filp); + ret = -ENODEV; } +done: if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) dprintk("%s: open (%d)\n", video_device_node_name(vdev), ret); + /* decrease the refcount in case of an error */ if (ret) video_put(vdev); @@ -444,7 +455,7 @@ static int v4l2_open(struct inode *inode, struct file *filp) static int v4l2_release(struct inode *inode, struct file *filp) { struct video_device *vdev = video_devdata(filp); - int ret = 0; + int ret; /* * We need to serialize the release() with queueing new requests. @@ -452,14 +463,12 @@ static int v4l2_release(struct inode *inode, struct file *filp) * operation, and that should not be mixed with queueing a new * request at the same time. */ - if (vdev->fops->release) { - if (v4l2_device_supports_requests(vdev->v4l2_dev)) { - mutex_lock(&vdev->v4l2_dev->mdev->req_queue_mutex); - ret = vdev->fops->release(filp); - mutex_unlock(&vdev->v4l2_dev->mdev->req_queue_mutex); - } else { - ret = vdev->fops->release(filp); - } + if (v4l2_device_supports_requests(vdev->v4l2_dev)) { + mutex_lock(&vdev->v4l2_dev->mdev->req_queue_mutex); + ret = vdev->fops->release(filp); + mutex_unlock(&vdev->v4l2_dev->mdev->req_queue_mutex); + } else { + ret = vdev->fops->release(filp); } if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) @@ -922,6 +931,9 @@ int __video_register_device(struct video_device *vdev, /* the device_caps field MUST be set for all but subdevs */ if (WARN_ON(type != VFL_TYPE_SUBDEV && !vdev->device_caps)) return -EINVAL; + /* the open and release file operations are mandatory */ + if (WARN_ON(!vdev->fops || !vdev->fops->open || !vdev->fops->release)) + return -EINVAL; /* v4l2_fh support */ spin_lock_init(&vdev->fh_lock); @@ -1114,8 +1126,7 @@ void video_unregister_device(struct video_device *vdev) */ clear_bit(V4L2_FL_REGISTERED, &vdev->flags); mutex_unlock(&videodev_lock); - if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) - v4l2_event_wake_all(vdev); + v4l2_event_wake_all(vdev); device_unregister(&vdev->dev); } EXPORT_SYMBOL(video_unregister_device); diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index 5e537454f5cd..63b12ef9d4d9 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -2,7 +2,7 @@ /* V4L2 device support. - Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 7710cb26bea0..346d1b0e10ce 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -1226,6 +1226,7 @@ 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); +DEBUGFS_FOPS(drm, V4L2_DEBUGFS_IF_DRM); struct v4l2_debugfs_if *v4l2_debugfs_if_alloc(struct dentry *root, u32 if_types, void *priv, @@ -1255,6 +1256,9 @@ struct v4l2_debugfs_if *v4l2_debugfs_if_alloc(struct dentry *root, u32 if_types, if (if_types & V4L2_DEBUGFS_IF_HDMI) debugfs_create_file("hdmi", 0400, infoframes->if_dir, infoframes, &infoframe_hdmi_fops); + if (if_types & V4L2_DEBUGFS_IF_DRM) + debugfs_create_file("hdr_drm", 0400, infoframes->if_dir, + infoframes, &infoframe_drm_fops); return infoframes; } EXPORT_SYMBOL_GPL(v4l2_debugfs_if_alloc); diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c index 90eec79ee995..df3ba9d4674b 100644 --- a/drivers/media/v4l2-core/v4l2-fh.c +++ b/drivers/media/v4l2-core/v4l2-fh.c @@ -41,10 +41,12 @@ void v4l2_fh_init(struct v4l2_fh *fh, struct video_device *vdev) } EXPORT_SYMBOL_GPL(v4l2_fh_init); -void v4l2_fh_add(struct v4l2_fh *fh) +void v4l2_fh_add(struct v4l2_fh *fh, struct file *filp) { unsigned long flags; + filp->private_data = fh; + v4l2_prio_open(fh->vdev->prio, &fh->prio); spin_lock_irqsave(&fh->vdev->fh_lock, flags); list_add(&fh->list, &fh->vdev->fh_list); @@ -57,16 +59,15 @@ int v4l2_fh_open(struct file *filp) struct video_device *vdev = video_devdata(filp); struct v4l2_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); - filp->private_data = fh; if (fh == NULL) return -ENOMEM; v4l2_fh_init(fh, vdev); - v4l2_fh_add(fh); + v4l2_fh_add(fh, filp); return 0; } EXPORT_SYMBOL_GPL(v4l2_fh_open); -void v4l2_fh_del(struct v4l2_fh *fh) +void v4l2_fh_del(struct v4l2_fh *fh, struct file *filp) { unsigned long flags; @@ -74,6 +75,8 @@ void v4l2_fh_del(struct v4l2_fh *fh) list_del_init(&fh->list); spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); v4l2_prio_close(fh->vdev->prio, fh->prio); + + filp->private_data = NULL; } EXPORT_SYMBOL_GPL(v4l2_fh_del); @@ -90,13 +93,12 @@ EXPORT_SYMBOL_GPL(v4l2_fh_exit); int v4l2_fh_release(struct file *filp) { - struct v4l2_fh *fh = filp->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(filp); if (fh) { - v4l2_fh_del(fh); + v4l2_fh_del(fh, filp); v4l2_fh_exit(fh); kfree(fh); - filp->private_data = NULL; } return 0; } diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 46da373066f4..98512ea4cc5b 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1089,8 +1089,8 @@ static void v4l_sanitize_format(struct v4l2_format *fmt) } } -static int v4l_querycap(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_querycap(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_capability *cap = (struct v4l2_capability *)arg; struct video_device *vfd = video_devdata(file); @@ -1103,7 +1103,7 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops, media_set_bus_info(cap->bus_info, sizeof(cap->bus_info), vfd->dev_parent); - ret = ops->vidioc_querycap(file, fh, cap); + ret = ops->vidioc_querycap(file, NULL, cap); /* * Drivers must not change device_caps, so check for this and @@ -1123,8 +1123,8 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops, return ret; } -static int v4l_g_input(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_input(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); @@ -1133,11 +1133,11 @@ static int v4l_g_input(const struct v4l2_ioctl_ops *ops, return 0; } - return ops->vidioc_g_input(file, fh, arg); + return ops->vidioc_g_input(file, NULL, arg); } -static int v4l_g_output(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_output(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); @@ -1146,11 +1146,11 @@ static int v4l_g_output(const struct v4l2_ioctl_ops *ops, return 0; } - return ops->vidioc_g_output(file, fh, arg); + return ops->vidioc_g_output(file, NULL, arg); } -static int v4l_s_input(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_input(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); int ret; @@ -1162,22 +1162,22 @@ static int v4l_s_input(const struct v4l2_ioctl_ops *ops, if (vfd->device_caps & V4L2_CAP_IO_MC) return *(int *)arg ? -EINVAL : 0; - return ops->vidioc_s_input(file, fh, *(unsigned int *)arg); + return ops->vidioc_s_input(file, NULL, *(unsigned int *)arg); } -static int v4l_s_output(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_output(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); if (vfd->device_caps & V4L2_CAP_IO_MC) return *(int *)arg ? -EINVAL : 0; - return ops->vidioc_s_output(file, fh, *(unsigned int *)arg); + return ops->vidioc_s_output(file, NULL, *(unsigned int *)arg); } -static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd; u32 *p = arg; @@ -1187,22 +1187,20 @@ static int v4l_g_priority(const struct v4l2_ioctl_ops *ops, return 0; } -static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_priority(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd; struct v4l2_fh *vfh; u32 *p = arg; vfd = video_devdata(file); - if (!test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) - return -ENOTTY; - vfh = file->private_data; + vfh = file_to_v4l2_fh(file); return v4l2_prio_change(vfd->prio, &vfh->prio, *p); } -static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_input *p = arg; @@ -1224,11 +1222,11 @@ static int v4l_enuminput(const struct v4l2_ioctl_ops *ops, return 0; } - return ops->vidioc_enum_input(file, fh, p); + return ops->vidioc_enum_input(file, NULL, p); } -static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_output *p = arg; @@ -1250,7 +1248,7 @@ static int v4l_enumoutput(const struct v4l2_ioctl_ops *ops, return 0; } - return ops->vidioc_enum_output(file, fh, p); + return ops->vidioc_enum_output(file, NULL, p); } static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) @@ -1471,6 +1469,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_META_FMT_RK_ISP1_EXT_PARAMS: descr = "Rockchip ISP1 Ext 3A Params"; break; case V4L2_META_FMT_C3ISP_PARAMS: descr = "Amlogic C3 ISP Parameters"; break; case V4L2_META_FMT_C3ISP_STATS: descr = "Amlogic C3 ISP Statistics"; break; + case V4L2_META_FMT_MALI_C55_PARAMS: descr = "ARM Mali-C55 ISP Parameters"; break; + case V4L2_META_FMT_MALI_C55_STATS: descr = "ARM Mali-C55 ISP 3A Statistics"; break; case V4L2_PIX_FMT_NV12_8L128: descr = "NV12 (8x128 Linear)"; break; case V4L2_PIX_FMT_NV12M_8L128: descr = "NV12M (8x128 Linear)"; break; case V4L2_PIX_FMT_NV12_10BE_8L128: descr = "10-bit NV12 (8x128 Linear, BE)"; break; @@ -1589,8 +1589,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) fmt->flags |= flags; } -static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vdev = video_devdata(file); struct v4l2_fmtdesc *p = arg; @@ -1620,12 +1620,12 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_enum_fmt_vid_cap)) break; - ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_cap(file, NULL, arg); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_enum_fmt_vid_overlay)) break; - ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_overlay(file, NULL, arg); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: @@ -1637,27 +1637,27 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_enum_fmt_vid_out)) break; - ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg); + ret = ops->vidioc_enum_fmt_vid_out(file, NULL, arg); break; case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_enum_fmt_sdr_cap)) break; - ret = ops->vidioc_enum_fmt_sdr_cap(file, fh, arg); + ret = ops->vidioc_enum_fmt_sdr_cap(file, NULL, arg); break; case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_enum_fmt_sdr_out)) break; - ret = ops->vidioc_enum_fmt_sdr_out(file, fh, arg); + ret = ops->vidioc_enum_fmt_sdr_out(file, NULL, arg); break; case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_enum_fmt_meta_cap)) break; - ret = ops->vidioc_enum_fmt_meta_cap(file, fh, arg); + ret = ops->vidioc_enum_fmt_meta_cap(file, NULL, arg); break; case V4L2_BUF_TYPE_META_OUTPUT: if (unlikely(!ops->vidioc_enum_fmt_meta_out)) break; - ret = ops->vidioc_enum_fmt_meta_out(file, fh, arg); + ret = ops->vidioc_enum_fmt_meta_out(file, NULL, arg); break; } if (ret == 0) @@ -1680,8 +1680,8 @@ static void v4l_pix_format_touch(struct v4l2_pix_format *p) p->xfer_func = 0; } -static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); @@ -1697,50 +1697,50 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_g_fmt_vid_cap)) break; p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - ret = ops->vidioc_g_fmt_vid_cap(file, fh, arg); + ret = ops->vidioc_g_fmt_vid_cap(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; if (vfd->vfl_type == VFL_TYPE_TOUCH) v4l_pix_format_touch(&p->fmt.pix); return ret; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - return ops->vidioc_g_fmt_vid_cap_mplane(file, fh, arg); + return ops->vidioc_g_fmt_vid_cap_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: - return ops->vidioc_g_fmt_vid_overlay(file, fh, arg); + return ops->vidioc_g_fmt_vid_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_CAPTURE: - return ops->vidioc_g_fmt_vbi_cap(file, fh, arg); + return ops->vidioc_g_fmt_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - return ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, arg); + return ops->vidioc_g_fmt_sliced_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_g_fmt_vid_out)) break; p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; - ret = ops->vidioc_g_fmt_vid_out(file, fh, arg); + ret = ops->vidioc_g_fmt_vid_out(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; return ret; case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return ops->vidioc_g_fmt_vid_out_mplane(file, fh, arg); + return ops->vidioc_g_fmt_vid_out_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - return ops->vidioc_g_fmt_vid_out_overlay(file, fh, arg); + return ops->vidioc_g_fmt_vid_out_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_OUTPUT: - return ops->vidioc_g_fmt_vbi_out(file, fh, arg); + return ops->vidioc_g_fmt_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - return ops->vidioc_g_fmt_sliced_vbi_out(file, fh, arg); + return ops->vidioc_g_fmt_sliced_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: - return ops->vidioc_g_fmt_sdr_cap(file, fh, arg); + return ops->vidioc_g_fmt_sdr_cap(file, NULL, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: - return ops->vidioc_g_fmt_sdr_out(file, fh, arg); + return ops->vidioc_g_fmt_sdr_out(file, NULL, arg); case V4L2_BUF_TYPE_META_CAPTURE: - return ops->vidioc_g_fmt_meta_cap(file, fh, arg); + return ops->vidioc_g_fmt_meta_cap(file, NULL, arg); case V4L2_BUF_TYPE_META_OUTPUT: - return ops->vidioc_g_fmt_meta_out(file, fh, arg); + return ops->vidioc_g_fmt_meta_out(file, NULL, arg); } return -EINVAL; } -static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); @@ -1760,7 +1760,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_s_fmt_vid_cap)) break; memset_after(p, 0, fmt.pix); - ret = ops->vidioc_s_fmt_vid_cap(file, fh, arg); + ret = ops->vidioc_s_fmt_vid_cap(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; if (vfd->vfl_type == VFL_TYPE_TOUCH) @@ -1773,7 +1773,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, for (i = 0; i < p->fmt.pix_mp.num_planes; i++) memset_after(&p->fmt.pix_mp.plane_fmt[i], 0, bytesperline); - return ops->vidioc_s_fmt_vid_cap_mplane(file, fh, arg); + return ops->vidioc_s_fmt_vid_cap_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_overlay)) break; @@ -1781,22 +1781,22 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, p->fmt.win.clips = NULL; p->fmt.win.clipcount = 0; p->fmt.win.bitmap = NULL; - return ops->vidioc_s_fmt_vid_overlay(file, fh, arg); + return ops->vidioc_s_fmt_vid_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_vbi_cap)) break; memset_after(p, 0, fmt.vbi.flags); - return ops->vidioc_s_fmt_vbi_cap(file, fh, arg); + return ops->vidioc_s_fmt_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap)) break; memset_after(p, 0, fmt.sliced.io_size); - return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg); + return ops->vidioc_s_fmt_sliced_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vid_out)) break; memset_after(p, 0, fmt.pix); - ret = ops->vidioc_s_fmt_vid_out(file, fh, arg); + ret = ops->vidioc_s_fmt_vid_out(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; return ret; @@ -1807,7 +1807,7 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, for (i = 0; i < p->fmt.pix_mp.num_planes; i++) memset_after(&p->fmt.pix_mp.plane_fmt[i], 0, bytesperline); - return ops->vidioc_s_fmt_vid_out_mplane(file, fh, arg); + return ops->vidioc_s_fmt_vid_out_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_s_fmt_vid_out_overlay)) break; @@ -1815,43 +1815,43 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops, p->fmt.win.clips = NULL; p->fmt.win.clipcount = 0; p->fmt.win.bitmap = NULL; - return ops->vidioc_s_fmt_vid_out_overlay(file, fh, arg); + return ops->vidioc_s_fmt_vid_out_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_vbi_out)) break; memset_after(p, 0, fmt.vbi.flags); - return ops->vidioc_s_fmt_vbi_out(file, fh, arg); + return ops->vidioc_s_fmt_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out)) break; memset_after(p, 0, fmt.sliced.io_size); - return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg); + return ops->vidioc_s_fmt_sliced_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_sdr_cap)) break; memset_after(p, 0, fmt.sdr.buffersize); - return ops->vidioc_s_fmt_sdr_cap(file, fh, arg); + return ops->vidioc_s_fmt_sdr_cap(file, NULL, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_sdr_out)) break; memset_after(p, 0, fmt.sdr.buffersize); - return ops->vidioc_s_fmt_sdr_out(file, fh, arg); + return ops->vidioc_s_fmt_sdr_out(file, NULL, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_s_fmt_meta_cap)) break; memset_after(p, 0, fmt.meta); - return ops->vidioc_s_fmt_meta_cap(file, fh, arg); + return ops->vidioc_s_fmt_meta_cap(file, NULL, arg); case V4L2_BUF_TYPE_META_OUTPUT: if (unlikely(!ops->vidioc_s_fmt_meta_out)) break; memset_after(p, 0, fmt.meta); - return ops->vidioc_s_fmt_meta_out(file, fh, arg); + return ops->vidioc_s_fmt_meta_out(file, NULL, arg); } return -EINVAL; } -static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_format *p = arg; struct video_device *vfd = video_devdata(file); @@ -1868,7 +1868,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, if (unlikely(!ops->vidioc_try_fmt_vid_cap)) break; memset_after(p, 0, fmt.pix); - ret = ops->vidioc_try_fmt_vid_cap(file, fh, arg); + ret = ops->vidioc_try_fmt_vid_cap(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; if (vfd->vfl_type == VFL_TYPE_TOUCH) @@ -1881,7 +1881,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, for (i = 0; i < p->fmt.pix_mp.num_planes; i++) memset_after(&p->fmt.pix_mp.plane_fmt[i], 0, bytesperline); - return ops->vidioc_try_fmt_vid_cap_mplane(file, fh, arg); + return ops->vidioc_try_fmt_vid_cap_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_overlay)) break; @@ -1889,22 +1889,22 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, p->fmt.win.clips = NULL; p->fmt.win.clipcount = 0; p->fmt.win.bitmap = NULL; - return ops->vidioc_try_fmt_vid_overlay(file, fh, arg); + return ops->vidioc_try_fmt_vid_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_vbi_cap)) break; memset_after(p, 0, fmt.vbi.flags); - return ops->vidioc_try_fmt_vbi_cap(file, fh, arg); + return ops->vidioc_try_fmt_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap)) break; memset_after(p, 0, fmt.sliced.io_size); - return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg); + return ops->vidioc_try_fmt_sliced_vbi_cap(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vid_out)) break; memset_after(p, 0, fmt.pix); - ret = ops->vidioc_try_fmt_vid_out(file, fh, arg); + ret = ops->vidioc_try_fmt_vid_out(file, NULL, arg); /* just in case the driver zeroed it again */ p->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC; return ret; @@ -1915,7 +1915,7 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, for (i = 0; i < p->fmt.pix_mp.num_planes; i++) memset_after(&p->fmt.pix_mp.plane_fmt[i], 0, bytesperline); - return ops->vidioc_try_fmt_vid_out_mplane(file, fh, arg); + return ops->vidioc_try_fmt_vid_out_mplane(file, NULL, arg); case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: if (unlikely(!ops->vidioc_try_fmt_vid_out_overlay)) break; @@ -1923,55 +1923,55 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops, p->fmt.win.clips = NULL; p->fmt.win.clipcount = 0; p->fmt.win.bitmap = NULL; - return ops->vidioc_try_fmt_vid_out_overlay(file, fh, arg); + return ops->vidioc_try_fmt_vid_out_overlay(file, NULL, arg); case V4L2_BUF_TYPE_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_vbi_out)) break; memset_after(p, 0, fmt.vbi.flags); - return ops->vidioc_try_fmt_vbi_out(file, fh, arg); + return ops->vidioc_try_fmt_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out)) break; memset_after(p, 0, fmt.sliced.io_size); - return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg); + return ops->vidioc_try_fmt_sliced_vbi_out(file, NULL, arg); case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_sdr_cap)) break; memset_after(p, 0, fmt.sdr.buffersize); - return ops->vidioc_try_fmt_sdr_cap(file, fh, arg); + return ops->vidioc_try_fmt_sdr_cap(file, NULL, arg); case V4L2_BUF_TYPE_SDR_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_sdr_out)) break; memset_after(p, 0, fmt.sdr.buffersize); - return ops->vidioc_try_fmt_sdr_out(file, fh, arg); + return ops->vidioc_try_fmt_sdr_out(file, NULL, arg); case V4L2_BUF_TYPE_META_CAPTURE: if (unlikely(!ops->vidioc_try_fmt_meta_cap)) break; memset_after(p, 0, fmt.meta); - return ops->vidioc_try_fmt_meta_cap(file, fh, arg); + return ops->vidioc_try_fmt_meta_cap(file, NULL, arg); case V4L2_BUF_TYPE_META_OUTPUT: if (unlikely(!ops->vidioc_try_fmt_meta_out)) break; memset_after(p, 0, fmt.meta); - return ops->vidioc_try_fmt_meta_out(file, fh, arg); + return ops->vidioc_try_fmt_meta_out(file, NULL, arg); } return -EINVAL; } -static int v4l_streamon(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_streamon(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { - return ops->vidioc_streamon(file, fh, *(unsigned int *)arg); + return ops->vidioc_streamon(file, NULL, *(unsigned int *)arg); } -static int v4l_streamoff(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_streamoff(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { - return ops->vidioc_streamoff(file, fh, *(unsigned int *)arg); + return ops->vidioc_streamoff(file, NULL, *(unsigned int *)arg); } -static int v4l_g_tuner(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_tuner(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_tuner *p = arg; @@ -1979,14 +1979,14 @@ static int v4l_g_tuner(const struct v4l2_ioctl_ops *ops, p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - err = ops->vidioc_g_tuner(file, fh, p); + err = ops->vidioc_g_tuner(file, NULL, p); if (!err) p->capability |= V4L2_TUNER_CAP_FREQ_BANDS; return err; } -static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_tuner *p = arg; @@ -1997,11 +1997,11 @@ static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops, return ret; p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - return ops->vidioc_s_tuner(file, fh, p); + return ops->vidioc_s_tuner(file, NULL, p); } static int v4l_g_modulator(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_modulator *p = arg; @@ -2010,14 +2010,14 @@ static int v4l_g_modulator(const struct v4l2_ioctl_ops *ops, if (vfd->vfl_type == VFL_TYPE_RADIO) p->type = V4L2_TUNER_RADIO; - err = ops->vidioc_g_modulator(file, fh, p); + err = ops->vidioc_g_modulator(file, NULL, p); if (!err) p->capability |= V4L2_TUNER_CAP_FREQ_BANDS; return err; } static int v4l_s_modulator(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_modulator *p = arg; @@ -2025,11 +2025,11 @@ static int v4l_s_modulator(const struct v4l2_ioctl_ops *ops, if (vfd->vfl_type == VFL_TYPE_RADIO) p->type = V4L2_TUNER_RADIO; - return ops->vidioc_s_modulator(file, fh, p); + return ops->vidioc_s_modulator(file, NULL, p); } static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_frequency *p = arg; @@ -2039,11 +2039,11 @@ static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops, else p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - return ops->vidioc_g_frequency(file, fh, p); + return ops->vidioc_g_frequency(file, NULL, p); } static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); const struct v4l2_frequency *p = arg; @@ -2062,11 +2062,11 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops, if (type != p->type) return -EINVAL; } - return ops->vidioc_s_frequency(file, fh, p); + return ops->vidioc_s_frequency(file, NULL, p); } -static int v4l_enumstd(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_enumstd(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_standard *p = arg; @@ -2074,8 +2074,8 @@ static int v4l_enumstd(const struct v4l2_ioctl_ops *ops, return v4l_video_std_enumstd(p, vfd->tvnorms); } -static int v4l_s_std(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_std(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); v4l2_std_id id = *(v4l2_std_id *)arg, norm; @@ -2089,11 +2089,11 @@ static int v4l_s_std(const struct v4l2_ioctl_ops *ops, return -EINVAL; /* Calls the specific handler */ - return ops->vidioc_s_std(file, fh, norm); + return ops->vidioc_s_std(file, NULL, norm); } -static int v4l_querystd(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_querystd(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); v4l2_std_id *p = arg; @@ -2111,11 +2111,11 @@ static int v4l_querystd(const struct v4l2_ioctl_ops *ops, * their efforts to improve the standards detection. */ *p = vfd->tvnorms; - return ops->vidioc_querystd(file, fh, arg); + return ops->vidioc_querystd(file, NULL, arg); } static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_hw_freq_seek *p = arg; @@ -2133,26 +2133,26 @@ static int v4l_s_hw_freq_seek(const struct v4l2_ioctl_ops *ops, V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; if (p->type != type) return -EINVAL; - return ops->vidioc_s_hw_freq_seek(file, fh, p); + return ops->vidioc_s_hw_freq_seek(file, NULL, p); } -static int v4l_s_fbuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_fbuf(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_framebuffer *p = arg; p->base = NULL; - return ops->vidioc_s_fbuf(file, fh, p); + return ops->vidioc_s_fbuf(file, NULL, p); } -static int v4l_overlay(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_overlay(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { - return ops->vidioc_overlay(file, fh, *(unsigned int *)arg); + return ops->vidioc_overlay(file, NULL, *(unsigned int *)arg); } -static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_requestbuffers *p = arg; @@ -2167,38 +2167,38 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops, if (is_valid_ioctl(vfd, VIDIOC_REMOVE_BUFS)) p->capabilities = V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS; - return ops->vidioc_reqbufs(file, fh, p); + return ops->vidioc_reqbufs(file, NULL, p); } -static int v4l_querybuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_querybuf(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_buffer *p = arg; int ret = check_fmt(file, p->type); - return ret ? ret : ops->vidioc_querybuf(file, fh, p); + return ret ? ret : ops->vidioc_querybuf(file, NULL, p); } -static int v4l_qbuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_qbuf(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_buffer *p = arg; int ret = check_fmt(file, p->type); - return ret ? ret : ops->vidioc_qbuf(file, fh, p); + return ret ? ret : ops->vidioc_qbuf(file, NULL, p); } -static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_dqbuf(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_buffer *p = arg; int ret = check_fmt(file, p->type); - return ret ? ret : ops->vidioc_dqbuf(file, fh, p); + return ret ? ret : ops->vidioc_dqbuf(file, NULL, p); } static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_create_buffers *create = arg; @@ -2215,7 +2215,7 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, if (is_valid_ioctl(vfd, VIDIOC_REMOVE_BUFS)) create->capabilities = V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS; - ret = ops->vidioc_create_bufs(file, fh, create); + ret = ops->vidioc_create_bufs(file, NULL, create); if (create->format.type == V4L2_BUF_TYPE_VIDEO_CAPTURE || create->format.type == V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -2225,27 +2225,27 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops, } static int v4l_prepare_buf(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_buffer *b = arg; int ret = check_fmt(file, b->type); - return ret ? ret : ops->vidioc_prepare_buf(file, fh, b); + return ret ? ret : ops->vidioc_prepare_buf(file, NULL, b); } static int v4l_remove_bufs(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_remove_buffers *remove = arg; if (ops->vidioc_remove_bufs) - return ops->vidioc_remove_bufs(file, fh, remove); + return ops->vidioc_remove_bufs(file, NULL, remove); return -ENOTTY; } -static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_streamparm *p = arg; @@ -2255,20 +2255,20 @@ static int v4l_g_parm(const struct v4l2_ioctl_ops *ops, if (ret) return ret; if (ops->vidioc_g_parm) - return ops->vidioc_g_parm(file, fh, p); + return ops->vidioc_g_parm(file, NULL, p); if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) return -EINVAL; if (vfd->device_caps & V4L2_CAP_READWRITE) p->parm.capture.readbuffers = 2; - ret = ops->vidioc_g_std(file, fh, &std); + ret = ops->vidioc_g_std(file, NULL, &std); if (ret == 0) v4l2_video_std_frame_period(std, &p->parm.capture.timeperframe); return ret; } -static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct v4l2_streamparm *p = arg; int ret = check_fmt(file, p->type); @@ -2288,17 +2288,16 @@ static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, p->parm.capture.extendedmode = 0; p->parm.capture.capturemode &= V4L2_MODE_HIGHQUALITY; } - return ops->vidioc_s_parm(file, fh, p); + return ops->vidioc_s_parm(file, NULL, p); } -static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_query_ext_ctrl qec = {}; struct v4l2_queryctrl *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); int ret; if (vfh && vfh->ctrl_handler) @@ -2310,7 +2309,7 @@ static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, /* Simulate query_ext_ctr using query_ctrl. */ qec.id = p->id; - ret = ops->vidioc_query_ext_ctrl(file, fh, &qec); + ret = ops->vidioc_query_ext_ctrl(file, NULL, &qec); if (ret) return ret; v4l2_query_ext_ctrl_to_v4l2_queryctrl(p, &qec); @@ -2318,46 +2317,43 @@ static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops, } static int v4l_query_ext_ctrl(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_query_ext_ctrl *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); if (vfh && vfh->ctrl_handler) return v4l2_query_ext_ctrl(vfh->ctrl_handler, p); if (vfd->ctrl_handler) return v4l2_query_ext_ctrl(vfd->ctrl_handler, p); if (ops->vidioc_query_ext_ctrl) - return ops->vidioc_query_ext_ctrl(file, fh, p); + return ops->vidioc_query_ext_ctrl(file, NULL, p); return -ENOTTY; } -static int v4l_querymenu(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_querymenu(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_querymenu *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); if (vfh && vfh->ctrl_handler) return v4l2_querymenu(vfh->ctrl_handler, p); if (vfd->ctrl_handler) return v4l2_querymenu(vfd->ctrl_handler, p); if (ops->vidioc_querymenu) - return ops->vidioc_querymenu(file, fh, p); + return ops->vidioc_querymenu(file, NULL, p); return -ENOTTY; } -static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_control *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; @@ -2374,7 +2370,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, ctrl.id = p->id; ctrl.value = p->value; if (check_ext_ctrls(&ctrls, VIDIOC_G_CTRL)) { - int ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); + int ret = ops->vidioc_g_ext_ctrls(file, NULL, &ctrls); if (ret == 0) p->value = ctrl.value; @@ -2383,13 +2379,12 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops, return -EINVAL; } -static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_control *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; int ret; @@ -2408,18 +2403,17 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops, ctrl.value = p->value; if (!check_ext_ctrls(&ctrls, VIDIOC_S_CTRL)) return -EINVAL; - ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); + ret = ops->vidioc_s_ext_ctrls(file, NULL, &ctrls); p->value = ctrl.value; return ret; } static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); p->error_idx = p->count; if (vfh && vfh->ctrl_handler) @@ -2431,16 +2425,15 @@ static int v4l_g_ext_ctrls(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_g_ext_ctrls == NULL) return -ENOTTY; return check_ext_ctrls(p, VIDIOC_G_EXT_CTRLS) ? - ops->vidioc_g_ext_ctrls(file, fh, p) : -EINVAL; + ops->vidioc_g_ext_ctrls(file, NULL, p) : -EINVAL; } static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); p->error_idx = p->count; if (vfh && vfh->ctrl_handler) @@ -2452,16 +2445,15 @@ static int v4l_s_ext_ctrls(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_s_ext_ctrls == NULL) return -ENOTTY; return check_ext_ctrls(p, VIDIOC_S_EXT_CTRLS) ? - ops->vidioc_s_ext_ctrls(file, fh, p) : -EINVAL; + ops->vidioc_s_ext_ctrls(file, NULL, p) : -EINVAL; } static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_ext_controls *p = arg; - struct v4l2_fh *vfh = - test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); p->error_idx = p->count; if (vfh && vfh->ctrl_handler) @@ -2473,7 +2465,7 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, if (ops->vidioc_try_ext_ctrls == NULL) return -ENOTTY; return check_ext_ctrls(p, VIDIOC_TRY_EXT_CTRLS) ? - ops->vidioc_try_ext_ctrls(file, fh, p) : -EINVAL; + ops->vidioc_try_ext_ctrls(file, NULL, p) : -EINVAL; } /* @@ -2486,7 +2478,7 @@ static int v4l_try_ext_ctrls(const struct v4l2_ioctl_ops *ops, * type and drivers don't need to check for both. */ static int v4l_g_selection(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_selection *p = arg; u32 old_type = p->type; @@ -2496,13 +2488,13 @@ static int v4l_g_selection(const struct v4l2_ioctl_ops *ops, p->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; else if (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) p->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ret = ops->vidioc_g_selection(file, fh, p); + ret = ops->vidioc_g_selection(file, NULL, p); p->type = old_type; return ret; } static int v4l_s_selection(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_selection *p = arg; u32 old_type = p->type; @@ -2512,13 +2504,13 @@ static int v4l_s_selection(const struct v4l2_ioctl_ops *ops, p->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; else if (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) p->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - ret = ops->vidioc_s_selection(file, fh, p); + ret = ops->vidioc_s_selection(file, NULL, p); p->type = old_type; return ret; } -static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_crop *p = arg; @@ -2539,7 +2531,7 @@ static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, s.target = s.target == V4L2_SEL_TGT_COMPOSE ? V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE; - ret = v4l_g_selection(ops, file, fh, &s); + ret = v4l_g_selection(ops, file, &s); /* copying results to old structure on success */ if (!ret) @@ -2547,8 +2539,8 @@ static int v4l_g_crop(const struct v4l2_ioctl_ops *ops, return ret; } -static int v4l_s_crop(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_s_crop(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_crop *p = arg; @@ -2569,11 +2561,11 @@ static int v4l_s_crop(const struct v4l2_ioctl_ops *ops, s.target = s.target == V4L2_SEL_TGT_COMPOSE ? V4L2_SEL_TGT_CROP : V4L2_SEL_TGT_COMPOSE; - return v4l_s_selection(ops, file, fh, &s); + return v4l_s_selection(ops, file, &s); } -static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_cropcap *p = arg; @@ -2597,7 +2589,7 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, return -ENOTTY; if (ops->vidioc_g_pixelaspect) - ret = ops->vidioc_g_pixelaspect(file, fh, s.type, + ret = ops->vidioc_g_pixelaspect(file, NULL, s.type, &p->pixelaspect); /* @@ -2619,7 +2611,7 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, s.target = s.target == V4L2_SEL_TGT_COMPOSE_BOUNDS ? V4L2_SEL_TGT_CROP_BOUNDS : V4L2_SEL_TGT_COMPOSE_BOUNDS; - ret = v4l_g_selection(ops, file, fh, &s); + ret = v4l_g_selection(ops, file, &s); if (ret) return ret; p->bounds = s.r; @@ -2630,7 +2622,7 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, else s.target = V4L2_SEL_TGT_CROP_DEFAULT; - ret = v4l_g_selection(ops, file, fh, &s); + ret = v4l_g_selection(ops, file, &s); if (ret) return ret; p->defrect = s.r; @@ -2638,8 +2630,8 @@ static int v4l_cropcap(const struct v4l2_ioctl_ops *ops, return 0; } -static int v4l_log_status(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_log_status(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { struct video_device *vfd = video_devdata(file); int ret; @@ -2647,7 +2639,7 @@ static int v4l_log_status(const struct v4l2_ioctl_ops *ops, if (vfd->v4l2_dev) pr_info("%s: ================= START STATUS =================\n", vfd->v4l2_dev->name); - ret = ops->vidioc_log_status(file, fh); + ret = ops->vidioc_log_status(file, NULL); if (vfd->v4l2_dev) pr_info("%s: ================== END STATUS ==================\n", vfd->v4l2_dev->name); @@ -2655,7 +2647,7 @@ static int v4l_log_status(const struct v4l2_ioctl_ops *ops, } static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG struct v4l2_dbg_register *p = arg; @@ -2675,7 +2667,7 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, } if (ops->vidioc_g_register && p->match.type == V4L2_CHIP_MATCH_BRIDGE && (ops->vidioc_g_chip_info || p->match.addr == 0)) - return ops->vidioc_g_register(file, fh, p); + return ops->vidioc_g_register(file, NULL, p); return -EINVAL; #else return -ENOTTY; @@ -2683,7 +2675,7 @@ static int v4l_dbg_g_register(const struct v4l2_ioctl_ops *ops, } static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG const struct v4l2_dbg_register *p = arg; @@ -2703,7 +2695,7 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, } if (ops->vidioc_s_register && p->match.type == V4L2_CHIP_MATCH_BRIDGE && (ops->vidioc_g_chip_info || p->match.addr == 0)) - return ops->vidioc_s_register(file, fh, p); + return ops->vidioc_s_register(file, NULL, p); return -EINVAL; #else return -ENOTTY; @@ -2711,7 +2703,7 @@ static int v4l_dbg_s_register(const struct v4l2_ioctl_ops *ops, } static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { #ifdef CONFIG_VIDEO_ADV_DEBUG struct video_device *vfd = video_devdata(file); @@ -2727,7 +2719,7 @@ static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, p->flags |= V4L2_CHIP_FL_READABLE; strscpy(p->name, vfd->v4l2_dev->name, sizeof(p->name)); if (ops->vidioc_g_chip_info) - return ops->vidioc_g_chip_info(file, fh, arg); + return ops->vidioc_g_chip_info(file, NULL, arg); if (p->match.addr) return -EINVAL; return 0; @@ -2753,26 +2745,32 @@ static int v4l_dbg_g_chip_info(const struct v4l2_ioctl_ops *ops, #endif } -static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) +static int v4l_dqevent(const struct v4l2_ioctl_ops *ops, struct file *file, + void *arg) { - return v4l2_event_dequeue(fh, arg, file->f_flags & O_NONBLOCK); + struct v4l2_fh *vfh = file_to_v4l2_fh(file); + + return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK); } static int v4l_subscribe_event(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { - return ops->vidioc_subscribe_event(fh, arg); + struct v4l2_fh *vfh = file_to_v4l2_fh(file); + + return ops->vidioc_subscribe_event(vfh, arg); } static int v4l_unsubscribe_event(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { - return ops->vidioc_unsubscribe_event(fh, arg); + struct v4l2_fh *vfh = file_to_v4l2_fh(file); + + return ops->vidioc_unsubscribe_event(vfh, arg); } static int v4l_g_sliced_vbi_cap(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct v4l2_sliced_vbi_cap *p = arg; int ret = check_fmt(file, p->type); @@ -2783,11 +2781,11 @@ static int v4l_g_sliced_vbi_cap(const struct v4l2_ioctl_ops *ops, /* Clear up to type, everything after type is zeroed already */ memset(p, 0, offsetof(struct v4l2_sliced_vbi_cap, type)); - return ops->vidioc_g_sliced_vbi_cap(file, fh, p); + return ops->vidioc_g_sliced_vbi_cap(file, NULL, p); } static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *arg) + struct file *file, void *arg) { struct video_device *vfd = video_devdata(file); struct v4l2_frequency_band *p = arg; @@ -2805,7 +2803,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, return -EINVAL; } if (ops->vidioc_enum_freq_bands) { - err = ops->vidioc_enum_freq_bands(file, fh, p); + err = ops->vidioc_enum_freq_bands(file, NULL, p); if (err != -ENOTTY) return err; } @@ -2817,7 +2815,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, if (p->index) return -EINVAL; - err = ops->vidioc_g_tuner(file, fh, &t); + err = ops->vidioc_g_tuner(file, NULL, &t); if (err) return err; p->capability = t.capability | V4L2_TUNER_CAP_FREQ_BANDS; @@ -2836,7 +2834,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops, return -EINVAL; if (p->index) return -EINVAL; - err = ops->vidioc_g_modulator(file, fh, &m); + err = ops->vidioc_g_modulator(file, NULL, &m); if (err) return err; p->capability = m.capability | V4L2_TUNER_CAP_FREQ_BANDS; @@ -2853,7 +2851,7 @@ struct v4l2_ioctl_info { u32 flags; const char * const name; int (*func)(const struct v4l2_ioctl_ops *ops, struct file *file, - void *fh, void *p); + void *p); void (*debug)(const void *arg, bool write_only); }; @@ -2874,9 +2872,9 @@ struct v4l2_ioctl_info { #define DEFINE_V4L_STUB_FUNC(_vidioc) \ static int v4l_stub_ ## _vidioc( \ const struct v4l2_ioctl_ops *ops, \ - struct file *file, void *fh, void *p) \ + struct file *file, void *p) \ { \ - return ops->vidioc_ ## _vidioc(file, fh, p); \ + return ops->vidioc_ ## _vidioc(file, NULL, p); \ } #define IOCTL_INFO(_ioctl, _func, _debug, _flags) \ @@ -3072,8 +3070,7 @@ static long __video_do_ioctl(struct file *file, bool write_only = false; struct v4l2_ioctl_info default_info; const struct v4l2_ioctl_info *info; - void *fh = file->private_data; - struct v4l2_fh *vfh = NULL; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); int dev_debug = vfd->dev_debug; long ret = -ENOTTY; @@ -3083,9 +3080,6 @@ static long __video_do_ioctl(struct file *file, return ret; } - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) - vfh = file->private_data; - /* * We need to serialize streamon/off with queueing new requests. * These ioctls may trigger the cancellation of a streaming @@ -3117,10 +3111,10 @@ static long __video_do_ioctl(struct file *file, info = &v4l2_ioctls[_IOC_NR(cmd)]; if (!is_valid_ioctl(vfd, cmd) && - !((info->flags & INFO_FL_CTRL) && vfh && vfh->ctrl_handler)) + !((info->flags & INFO_FL_CTRL) && vfh->ctrl_handler)) goto done; - if (vfh && (info->flags & INFO_FL_PRIO)) { + if (info->flags & INFO_FL_PRIO) { ret = v4l2_prio_check(vfd->prio, vfh->prio); if (ret) goto done; @@ -3134,12 +3128,12 @@ static long __video_do_ioctl(struct file *file, write_only = _IOC_DIR(cmd) == _IOC_WRITE; if (info != &default_info) { - ret = info->func(ops, file, fh, arg); + ret = info->func(ops, file, arg); } else if (!ops->vidioc_default) { ret = -ENOTTY; } else { - ret = ops->vidioc_default(file, fh, - vfh ? v4l2_prio_check(vfd->prio, vfh->prio) >= 0 : 0, + ret = ops->vidioc_default(file, NULL, + v4l2_prio_check(vfd->prio, vfh->prio) >= 0, cmd, arg); } diff --git a/drivers/media/v4l2-core/v4l2-isp.c b/drivers/media/v4l2-core/v4l2-isp.c new file mode 100644 index 000000000000..29831f7032e9 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-isp.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Video4Linux2 generic ISP parameters and statistics support + * + * Copyright (C) 2025 Ideas On Board Oy + * Author: Jacopo Mondi <jacopo.mondi@ideasonboard.com> + */ + +#include <media/v4l2-isp.h> + +#include <linux/bitops.h> +#include <linux/device.h> + +#include <media/videobuf2-core.h> + +int v4l2_isp_params_validate_buffer_size(struct device *dev, + struct vb2_buffer *vb, + size_t max_size) +{ + size_t header_size = offsetof(struct v4l2_isp_params_buffer, data); + size_t payload_size = vb2_get_plane_payload(vb, 0); + + /* Payload size can't be greater than the destination buffer size */ + if (payload_size > max_size) { + dev_dbg(dev, "Payload size is too large: %zu\n", payload_size); + return -EINVAL; + } + + /* Payload size can't be smaller than the header size */ + if (payload_size < header_size) { + dev_dbg(dev, "Payload size is too small: %zu\n", payload_size); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_isp_params_validate_buffer_size); + +int v4l2_isp_params_validate_buffer(struct device *dev, struct vb2_buffer *vb, + const struct v4l2_isp_params_buffer *buffer, + const struct v4l2_isp_params_block_type_info *type_info, + size_t num_block_types) +{ + size_t header_size = offsetof(struct v4l2_isp_params_buffer, data); + size_t payload_size = vb2_get_plane_payload(vb, 0); + size_t block_offset = 0; + size_t buffer_size; + + /* + * Currently only the first version of the V4L2 ISP parameters format is + * supported. We accept both V0 and V1 to support existing drivers + * compatible with V4L2 ISP that use either 0 or 1 as their "first + * version" identifiers. + */ + if (buffer->version != V4L2_ISP_PARAMS_VERSION_V0 && + buffer->version != V4L2_ISP_PARAMS_VERSION_V1) { + dev_dbg(dev, + "Unsupported V4L2 ISP parameters format version: %u\n", + buffer->version); + return -EINVAL; + } + + /* Validate the size reported in the header */ + buffer_size = header_size + buffer->data_size; + if (buffer_size != payload_size) { + dev_dbg(dev, "Data size %zu and payload size %zu are different\n", + buffer_size, payload_size); + return -EINVAL; + } + + /* Walk the list of ISP configuration blocks and validate them. */ + buffer_size = buffer->data_size; + while (buffer_size >= sizeof(struct v4l2_isp_params_block_header)) { + const struct v4l2_isp_params_block_type_info *info; + const struct v4l2_isp_params_block_header *block; + + block = (const struct v4l2_isp_params_block_header *) + (buffer->data + block_offset); + + if (block->type >= num_block_types) { + dev_dbg(dev, + "Invalid block type %u at offset %zu\n", + block->type, block_offset); + return -EINVAL; + } + + if (block->size > buffer_size) { + dev_dbg(dev, "Premature end of parameters data\n"); + return -EINVAL; + } + + /* It's invalid to specify both ENABLE and DISABLE. */ + if ((block->flags & (V4L2_ISP_PARAMS_FL_BLOCK_ENABLE | + V4L2_ISP_PARAMS_FL_BLOCK_DISABLE)) == + (V4L2_ISP_PARAMS_FL_BLOCK_ENABLE | + V4L2_ISP_PARAMS_FL_BLOCK_DISABLE)) { + dev_dbg(dev, "Invalid block flags %x at offset %zu\n", + block->flags, block_offset); + return -EINVAL; + } + + /* + * Match the block reported size against the type info provided + * one, but allow the block to only contain the header in + * case it is going to be disabled. + */ + info = &type_info[block->type]; + if (block->size != info->size && + (!(block->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) || + block->size != sizeof(*block))) { + dev_dbg(dev, + "Invalid block size %u (expected %zu) at offset %zu\n", + block->size, info->size, block_offset); + return -EINVAL; + } + + block_offset += block->size; + buffer_size -= block->size; + } + + if (buffer_size) { + dev_dbg(dev, "Unexpected data after the parameters buffer end\n"); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_isp_params_validate_buffer); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jacopo Mondi <jacopo.mondi@ideasonboard.com"); +MODULE_DESCRIPTION("V4L2 generic ISP parameters and statistics helpers"); diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index eb22d6172462..fec93c1a9231 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -123,13 +123,7 @@ static struct v4l2_m2m_queue_ctx *get_queue_ctx(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_queue *v4l2_m2m_get_vq(struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type) { - struct v4l2_m2m_queue_ctx *q_ctx; - - q_ctx = get_queue_ctx(m2m_ctx, type); - if (!q_ctx) - return NULL; - - return &q_ctx->q; + return &get_queue_ctx(m2m_ctx, type)->q; } EXPORT_SYMBOL(v4l2_m2m_get_vq); @@ -951,7 +945,7 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file, __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct poll_table_struct *wait) { - struct video_device *vfd = video_devdata(file); + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct vb2_queue *src_q = v4l2_m2m_get_src_vq(m2m_ctx); struct vb2_queue *dst_q = v4l2_m2m_get_dst_vq(m2m_ctx); __poll_t req_events = poll_requested_events(wait); @@ -970,13 +964,9 @@ __poll_t v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, if (req_events & (EPOLLOUT | EPOLLWRNORM | EPOLLIN | EPOLLRDNORM)) rc = v4l2_m2m_poll_for_data(file, m2m_ctx, wait); - if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) { - struct v4l2_fh *fh = file->private_data; - - poll_wait(file, &fh->wait, wait); - if (v4l2_event_pending(fh)) - rc |= EPOLLPRI; - } + poll_wait(file, &fh->wait, wait); + if (v4l2_event_pending(fh)) + rc |= EPOLLPRI; return rc; } @@ -1004,7 +994,7 @@ unsigned long v4l2_m2m_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); unsigned long offset = pgoff << PAGE_SHIFT; struct vb2_queue *vq; @@ -1289,8 +1279,6 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, unsigned long flags; q_ctx = get_queue_ctx(m2m_ctx, vbuf->vb2_buf.vb2_queue->type); - if (!q_ctx) - return; spin_lock_irqsave(&q_ctx->rdy_spinlock, flags); list_add_tail(&b->list, &q_ctx->rdy_queue); @@ -1300,14 +1288,9 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue); void v4l2_m2m_buf_copy_metadata(const struct vb2_v4l2_buffer *out_vb, - struct vb2_v4l2_buffer *cap_vb, - bool copy_frame_flags) + struct vb2_v4l2_buffer *cap_vb) { - u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - - if (copy_frame_flags) - mask |= V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | - V4L2_BUF_FLAG_BFRAME; + const u32 mask = V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_TSTAMP_SRC_MASK; cap_vb->vb2_buf.timestamp = out_vb->vb2_buf.timestamp; @@ -1371,7 +1354,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_request_queue); int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *rb) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_reqbufs(file, fh->m2m_ctx, rb); } @@ -1380,7 +1363,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_reqbufs); int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv, struct v4l2_create_buffers *create) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_create_bufs(file, fh->m2m_ctx, create); } @@ -1389,11 +1372,9 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_create_bufs); int v4l2_m2m_ioctl_remove_bufs(struct file *file, void *priv, struct v4l2_remove_buffers *remove) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct vb2_queue *q = v4l2_m2m_get_vq(fh->m2m_ctx, remove->type); - if (!q) - return -EINVAL; if (q->type != remove->type) return -EINVAL; @@ -1404,7 +1385,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_remove_bufs); int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_querybuf(file, fh->m2m_ctx, buf); } @@ -1413,7 +1394,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_querybuf); int v4l2_m2m_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf); } @@ -1422,7 +1403,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_qbuf); int v4l2_m2m_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf); } @@ -1431,7 +1412,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_dqbuf); int v4l2_m2m_ioctl_prepare_buf(struct file *file, void *priv, struct v4l2_buffer *buf) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_prepare_buf(file, fh->m2m_ctx, buf); } @@ -1440,7 +1421,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_prepare_buf); int v4l2_m2m_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *eb) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_expbuf(file, fh->m2m_ctx, eb); } @@ -1449,7 +1430,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_expbuf); int v4l2_m2m_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type type) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_streamon(file, fh->m2m_ctx, type); } @@ -1458,13 +1439,13 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamon); int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_streamoff(file, fh->m2m_ctx, type); } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamoff); -int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec) { if (ec->cmd != V4L2_ENC_CMD_STOP && ec->cmd != V4L2_ENC_CMD_START) @@ -1475,7 +1456,7 @@ int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh, } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_encoder_cmd); -int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { if (dc->cmd != V4L2_DEC_CMD_STOP && dc->cmd != V4L2_DEC_CMD_START) @@ -1542,7 +1523,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_decoder_cmd); int v4l2_m2m_ioctl_encoder_cmd(struct file *file, void *priv, struct v4l2_encoder_cmd *ec) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_encoder_cmd(file, fh->m2m_ctx, ec); } @@ -1551,13 +1532,13 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_encoder_cmd); int v4l2_m2m_ioctl_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_decoder_cmd(file, fh->m2m_ctx, dc); } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_decoder_cmd); -int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *fh, +int v4l2_m2m_ioctl_stateless_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { if (dc->cmd != V4L2_DEC_CMD_FLUSH) @@ -1572,7 +1553,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_stateless_try_decoder_cmd); int v4l2_m2m_ioctl_stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *dc) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct vb2_v4l2_buffer *out_vb, *cap_vb; struct v4l2_m2m_dev *m2m_dev = fh->m2m_ctx->m2m_dev; unsigned long flags; @@ -1617,7 +1598,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_stateless_decoder_cmd); int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); return v4l2_m2m_mmap(file, fh->m2m_ctx, vma); } @@ -1625,7 +1606,7 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_fop_mmap); __poll_t v4l2_m2m_fop_poll(struct file *file, poll_table *wait) { - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); struct v4l2_m2m_ctx *m2m_ctx = fh->m2m_ctx; __poll_t ret; diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 4fd25fea3b58..25e66bf18f5f 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -26,6 +26,30 @@ #include <media/v4l2-fh.h> #include <media/v4l2-ioctl.h> +/** + * struct v4l2_subdev_stream_config - Used for storing stream configuration. + * + * @pad: pad number + * @stream: stream number + * @enabled: has the stream been enabled with v4l2_subdev_enable_streams() + * @fmt: &struct v4l2_mbus_framefmt + * @crop: &struct v4l2_rect to be used for crop + * @compose: &struct v4l2_rect to be used for compose + * @interval: frame interval + * + * This structure stores configuration for a stream. + */ +struct v4l2_subdev_stream_config { + u32 pad; + u32 stream; + bool enabled; + + struct v4l2_mbus_framefmt fmt; + struct v4l2_rect crop; + struct v4l2_rect compose; + struct v4l2_fract interval; +}; + #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) /* * The Streams API is an experimental feature. To use the Streams API, set @@ -86,8 +110,7 @@ static int subdev_open(struct file *file) } v4l2_fh_init(&subdev_fh->vfh, vdev); - v4l2_fh_add(&subdev_fh->vfh); - file->private_data = &subdev_fh->vfh; + v4l2_fh_add(&subdev_fh->vfh, file); if (sd->v4l2_dev->mdev && sd->entity.graph_obj.mdev->dev) { struct module *owner; @@ -110,7 +133,7 @@ static int subdev_open(struct file *file) err: module_put(subdev_fh->owner); - v4l2_fh_del(&subdev_fh->vfh); + v4l2_fh_del(&subdev_fh->vfh, file); v4l2_fh_exit(&subdev_fh->vfh); subdev_fh_free(subdev_fh); kfree(subdev_fh); @@ -122,17 +145,16 @@ static int subdev_close(struct file *file) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); if (sd->internal_ops && sd->internal_ops->close) sd->internal_ops->close(sd, subdev_fh); module_put(subdev_fh->owner); - v4l2_fh_del(vfh); + v4l2_fh_del(vfh, file); v4l2_fh_exit(vfh); subdev_fh_free(subdev_fh); kfree(subdev_fh); - file->private_data = NULL; return 0; } @@ -612,7 +634,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags); bool streams_subdev = sd->flags & V4L2_SUBDEV_FL_STREAMS; @@ -1135,7 +1157,7 @@ static long subdev_do_ioctl_lock(struct file *file, unsigned int cmd, void *arg) if (video_is_registered(vdev)) { struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *vfh = file->private_data; + struct v4l2_fh *vfh = file_to_v4l2_fh(file); struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); struct v4l2_subdev_state *state; @@ -1192,7 +1214,7 @@ static __poll_t subdev_poll(struct file *file, poll_table *wait) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); - struct v4l2_fh *fh = file->private_data; + struct v4l2_fh *fh = file_to_v4l2_fh(file); if (!(sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)) return EPOLLERR; @@ -2586,7 +2608,7 @@ EXPORT_SYMBOL_GPL(v4l2_subdev_is_streaming); int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd) { #if IS_REACHABLE(CONFIG_LEDS_CLASS) - sd->privacy_led = led_get(sd->dev, "privacy-led"); + sd->privacy_led = led_get(sd->dev, "privacy"); if (IS_ERR(sd->privacy_led) && PTR_ERR(sd->privacy_led) != -ENOENT) return dev_err_probe(sd->dev, PTR_ERR(sd->privacy_led), "getting privacy LED\n"); |
