diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2021-07-19 04:56:58 +0300 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2021-07-19 04:56:58 +0300 |
commit | 320424c7d44f54c18df9812fd7c45f6963524002 (patch) | |
tree | 5853aff866a321d476f5e4f2a3de5b5e90408580 /drivers/media | |
parent | f8f84af5da9ee04ef1d271528656dac42a090d00 (diff) | |
parent | 62fb9874f5da54fdb243003b386128037319b219 (diff) | |
download | linux-320424c7d44f54c18df9812fd7c45f6963524002.tar.xz |
Merge tag 'v5.13' into next
Sync up with the mainline to get the latest parport API.
Diffstat (limited to 'drivers/media')
262 files changed, 11634 insertions, 4336 deletions
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 6222b3ae220b..b07812657cee 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -134,7 +134,7 @@ config MEDIA_PLATFORM_SUPPORT This is found on Embedded hardware (SoC), on V4L2 codecs and on some GPU and newer CPU chipsets. - Say Y when you want to be able so see such devices. + Say Y when you want to be able to see such devices. config MEDIA_TEST_SUPPORT bool diff --git a/drivers/media/cec/core/cec-notifier.c b/drivers/media/cec/core/cec-notifier.c index 95f363bb1d19..389dc664b211 100644 --- a/drivers/media/cec/core/cec-notifier.c +++ b/drivers/media/cec/core/cec-notifier.c @@ -9,6 +9,7 @@ #include <linux/export.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/i2c.h> #include <linux/list.h> #include <linux/kref.h> #include <linux/of_platform.h> @@ -221,19 +222,29 @@ struct device *cec_notifier_parse_hdmi_phandle(struct device *dev) dev_err(dev, "Failed to find HDMI node in device tree\n"); return ERR_PTR(-ENODEV); } + hdmi_pdev = of_find_device_by_node(np); - of_node_put(np); - if (hdmi_pdev) { + if (hdmi_pdev) hdmi_dev = &hdmi_pdev->dev; - /* - * Note that the device struct is only used as a key into the - * cec_notifiers list, it is never actually accessed. - * So we decrement the reference here so we don't leak - * memory. - */ - put_device(hdmi_dev); - return hdmi_dev; +#if IS_REACHABLE(CONFIG_I2C) + if (!hdmi_dev) { + struct i2c_client *hdmi_client = of_find_i2c_device_by_node(np); + + if (hdmi_client) + hdmi_dev = &hdmi_client->dev; } - return ERR_PTR(-EPROBE_DEFER); +#endif + of_node_put(np); + if (!hdmi_dev) + return ERR_PTR(-EPROBE_DEFER); + + /* + * Note that the device struct is only used as a key into the + * cec_notifiers list, it is never actually accessed. + * So we decrement the reference here so we don't leak + * memory. + */ + put_device(hdmi_dev); + return hdmi_dev; } EXPORT_SYMBOL_GPL(cec_notifier_parse_hdmi_phandle); diff --git a/drivers/media/cec/core/cec-pin-error-inj.c b/drivers/media/cec/core/cec-pin-error-inj.c index c0088d3b8e3d..fc0968b9d40e 100644 --- a/drivers/media/cec/core/cec-pin-error-inj.c +++ b/drivers/media/cec/core/cec-pin-error-inj.c @@ -277,7 +277,7 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, struct seq_file *sf) seq_puts(sf, "# <op>[,<mode>] rx-low-drive <bit> force a low-drive condition at this bit position\n"); seq_puts(sf, "# <op>[,<mode>] rx-add-byte add a spurious byte to the received CEC message\n"); seq_puts(sf, "# <op>[,<mode>] rx-remove-byte remove the last byte from the received CEC message\n"); - seq_puts(sf, "# <op>[,<mode>] rx-arb-lost <poll> generate a POLL message to trigger an arbitration lost\n"); + seq_puts(sf, "# any[,<mode>] rx-arb-lost [<poll>] generate a POLL message to trigger an arbitration lost\n"); seq_puts(sf, "#\n"); seq_puts(sf, "# TX error injection settings:\n"); seq_puts(sf, "# tx-ignore-nack-until-eom ignore early NACKs until EOM\n"); diff --git a/drivers/media/common/b2c2/flexcop-hw-filter.c b/drivers/media/common/b2c2/flexcop-hw-filter.c index 335f30a54ba8..c5a3345c99e9 100644 --- a/drivers/media/common/b2c2/flexcop-hw-filter.c +++ b/drivers/media/common/b2c2/flexcop-hw-filter.c @@ -69,7 +69,7 @@ vpid.vregname.field = onoff ? pid : 0x1fff; \ vpid.vregname.trans_field = transval; \ v208.ctrl_208.enablefield = onoff; \ fc->write_ibi_reg(fc, vregname, vpid); \ -fc->write_ibi_reg(fc, ctrl_208, v208); +fc->write_ibi_reg(fc, ctrl_208, v208) static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc, u16 pid, int onoff) diff --git a/drivers/media/common/b2c2/flexcop.h b/drivers/media/common/b2c2/flexcop.h index 486fe2380b92..05e595f896dc 100644 --- a/drivers/media/common/b2c2/flexcop.h +++ b/drivers/media/common/b2c2/flexcop.h @@ -14,10 +14,10 @@ extern int b2c2_flexcop_debug; /* debug */ #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0) +#define dprintk(level, args...) \ + do { if ((b2c2_flexcop_debug & (level))) printk(args); } while (0) #else -#define dprintk(level,args...) +#define dprintk(level, args...) no_printk(args) #endif #define deb_info(args...) dprintk(0x01, args) diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c index f2d13b71416c..e50fa0ff7c5d 100644 --- a/drivers/media/common/saa7146/saa7146_core.c +++ b/drivers/media/common/saa7146/saa7146_core.c @@ -253,7 +253,7 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt i, sg_dma_address(list), sg_dma_len(list), list->offset); */ - for (p = 0; p * 4096 < list->length; p++, ptr++) { + for (p = 0; p * 4096 < sg_dma_len(list); p++, ptr++) { *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096); nr_pages++; } diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 7b8795eca589..66215d9106a4 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -247,9 +247,8 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu /* walk all pages, copy all page addresses to ptr1 */ for (i = 0; i < length; i++, list++) { - for (p = 0; p * 4096 < list->length; p++, ptr1++) { + for (p = 0; p * 4096 < sg_dma_len(list); p++, ptr1++) *ptr1 = cpu_to_le32(sg_dma_address(list) - list->offset); - } } /* ptr1 = pt1->cpu; diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index c1511094fdc7..410cc3ac6f94 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -429,13 +429,13 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) struct smscore_registry_entry_t *entry; struct list_head *next; - kmutex_lock(&g_smscore_registrylock); + mutex_lock(&g_smscore_registrylock); for (next = g_smscore_registry.next; next != &g_smscore_registry; next = next->next) { entry = (struct smscore_registry_entry_t *) next; if (!strncmp(entry->devpath, devpath, sizeof(entry->devpath))) { - kmutex_unlock(&g_smscore_registrylock); + mutex_unlock(&g_smscore_registrylock); return entry; } } @@ -446,7 +446,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) list_add(&entry->entry, &g_smscore_registry); } else pr_err("failed to create smscore_registry.\n"); - kmutex_unlock(&g_smscore_registrylock); + mutex_unlock(&g_smscore_registrylock); return entry; } @@ -527,7 +527,7 @@ int smscore_register_hotplug(hotplug_t hotplug) struct list_head *next, *first; int rc = 0; - kmutex_lock(&g_smscore_deviceslock); + mutex_lock(&g_smscore_deviceslock); notifyee = kmalloc(sizeof(*notifyee), GFP_KERNEL); if (notifyee) { /* now notify callback about existing devices */ @@ -548,7 +548,7 @@ int smscore_register_hotplug(hotplug_t hotplug) } else rc = -ENOMEM; - kmutex_unlock(&g_smscore_deviceslock); + mutex_unlock(&g_smscore_deviceslock); return rc; } @@ -564,7 +564,7 @@ void smscore_unregister_hotplug(hotplug_t hotplug) { struct list_head *next, *first; - kmutex_lock(&g_smscore_deviceslock); + mutex_lock(&g_smscore_deviceslock); first = &g_smscore_notifyees; @@ -579,7 +579,7 @@ void smscore_unregister_hotplug(hotplug_t hotplug) } } - kmutex_unlock(&g_smscore_deviceslock); + mutex_unlock(&g_smscore_deviceslock); } EXPORT_SYMBOL_GPL(smscore_unregister_hotplug); @@ -732,9 +732,9 @@ int smscore_register_device(struct smsdevice_params_t *params, smscore_registry_settype(dev->devpath, params->device_type); /* add device to devices list */ - kmutex_lock(&g_smscore_deviceslock); + mutex_lock(&g_smscore_deviceslock); list_add(&dev->entry, &g_smscore_devices); - kmutex_unlock(&g_smscore_deviceslock); + mutex_unlock(&g_smscore_deviceslock); *coredev = dev; @@ -890,14 +890,14 @@ int smscore_start_device(struct smscore_device_t *coredev) return rc; } - kmutex_lock(&g_smscore_deviceslock); + mutex_lock(&g_smscore_deviceslock); rc = smscore_notify_callbacks(coredev, coredev->device, 1); smscore_init_ir(coredev); pr_debug("device %p started, rc %d\n", coredev, rc); - kmutex_unlock(&g_smscore_deviceslock); + mutex_unlock(&g_smscore_deviceslock); return rc; } @@ -1197,7 +1197,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev) int num_buffers = 0; int retry = 0; - kmutex_lock(&g_smscore_deviceslock); + mutex_lock(&g_smscore_deviceslock); /* Release input device (IR) resources */ sms_ir_exit(coredev); @@ -1224,9 +1224,9 @@ void smscore_unregister_device(struct smscore_device_t *coredev) pr_debug("waiting for %d buffer(s)\n", coredev->num_buffers - num_buffers); - kmutex_unlock(&g_smscore_deviceslock); + mutex_unlock(&g_smscore_deviceslock); msleep(100); - kmutex_lock(&g_smscore_deviceslock); + mutex_lock(&g_smscore_deviceslock); } pr_debug("freed %d buffers\n", num_buffers); @@ -1245,7 +1245,7 @@ void smscore_unregister_device(struct smscore_device_t *coredev) list_del(&coredev->entry); kfree(coredev); - kmutex_unlock(&g_smscore_deviceslock); + mutex_unlock(&g_smscore_deviceslock); pr_debug("device %p destroyed\n", coredev); } @@ -2123,17 +2123,17 @@ static int __init smscore_module_init(void) { INIT_LIST_HEAD(&g_smscore_notifyees); INIT_LIST_HEAD(&g_smscore_devices); - kmutex_init(&g_smscore_deviceslock); + mutex_init(&g_smscore_deviceslock); INIT_LIST_HEAD(&g_smscore_registry); - kmutex_init(&g_smscore_registrylock); + mutex_init(&g_smscore_registrylock); return 0; } static void __exit smscore_module_exit(void) { - kmutex_lock(&g_smscore_deviceslock); + mutex_lock(&g_smscore_deviceslock); while (!list_empty(&g_smscore_notifyees)) { struct smscore_device_notifyee_t *notifyee = (struct smscore_device_notifyee_t *) @@ -2142,9 +2142,9 @@ static void __exit smscore_module_exit(void) list_del(¬ifyee->entry); kfree(notifyee); } - kmutex_unlock(&g_smscore_deviceslock); + mutex_unlock(&g_smscore_deviceslock); - kmutex_lock(&g_smscore_registrylock); + mutex_lock(&g_smscore_registrylock); while (!list_empty(&g_smscore_registry)) { struct smscore_registry_entry_t *entry = (struct smscore_registry_entry_t *) @@ -2153,7 +2153,7 @@ static void __exit smscore_module_exit(void) list_del(&entry->entry); kfree(entry); } - kmutex_unlock(&g_smscore_registrylock); + mutex_unlock(&g_smscore_registrylock); pr_debug("\n"); } diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h index b3b793b5caf3..4a6b9f4c44ac 100644 --- a/drivers/media/common/siano/smscoreapi.h +++ b/drivers/media/common/siano/smscoreapi.h @@ -28,11 +28,6 @@ Copyright (C) 2006-2008, Uri Shkolnik, Anatoly Greenblat #include "smsir.h" -#define kmutex_init(_p_) mutex_init(_p_) -#define kmutex_lock(_p_) mutex_lock(_p_) -#define kmutex_trylock(_p_) mutex_trylock(_p_) -#define kmutex_unlock(_p_) mutex_unlock(_p_) - /* * Define the firmware names used by the driver. * Those should match what's used at smscoreapi.c and sms-cards.c diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index ae17407e477a..cd5bafe9a3ac 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -167,6 +167,34 @@ static inline int sms_to_mode(u32 mode) return TRANSMISSION_MODE_AUTO; } +static inline int sms_to_isdbt_mode(u32 mode) +{ + switch (mode) { + case 1: + return TRANSMISSION_MODE_2K; + case 2: + return TRANSMISSION_MODE_4K; + case 3: + return TRANSMISSION_MODE_8K; + } + return TRANSMISSION_MODE_AUTO; +} + +static inline int sms_to_isdbt_guard_interval(u32 interval) +{ + switch (interval) { + case 4: + return GUARD_INTERVAL_1_4; + case 8: + return GUARD_INTERVAL_1_8; + case 16: + return GUARD_INTERVAL_1_16; + case 32: + return GUARD_INTERVAL_1_32; + } + return GUARD_INTERVAL_AUTO; +} + static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked) { if (is_demod_locked) @@ -345,8 +373,8 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, /* Update ISDB-T transmission parameters */ c->frequency = p->frequency; c->bandwidth_hz = sms_to_bw(p->bandwidth); - c->transmission_mode = sms_to_mode(p->transmission_mode); - c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->transmission_mode = sms_to_isdbt_mode(p->transmission_mode); + c->guard_interval = sms_to_isdbt_guard_interval(p->guard_interval); c->isdbt_partial_reception = p->partial_reception ? 1 : 0; n_layers = p->num_of_layers; if (n_layers < 1) @@ -391,6 +419,10 @@ static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client, continue; } c->layer[i].modulation = sms_to_modulation(lr->constellation); + c->layer[i].fec = sms_to_code_rate(lr->code_rate); + + /* Time interleaving */ + c->layer[i].interleaving = (u8)lr->ti_ldepth_i; /* TS PER */ c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER; @@ -429,8 +461,8 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, c->frequency = p->frequency; client->fe_status = sms_to_status(p->is_demod_locked, 0); c->bandwidth_hz = sms_to_bw(p->bandwidth); - c->transmission_mode = sms_to_mode(p->transmission_mode); - c->guard_interval = sms_to_guard_interval(p->guard_interval); + c->transmission_mode = sms_to_isdbt_mode(p->transmission_mode); + c->guard_interval = sms_to_isdbt_guard_interval(p->guard_interval); c->isdbt_partial_reception = p->partial_reception ? 1 : 0; n_layers = p->num_of_layers; if (n_layers < 1) @@ -479,6 +511,10 @@ static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client, continue; } c->layer[i].modulation = sms_to_modulation(lr->constellation); + c->layer[i].fec = sms_to_code_rate(lr->code_rate); + + /* Time interleaving */ + c->layer[i].interleaving = (u8)lr->ti_ldepth_i; /* TS PER */ c->block_error.stat[i + 1].scale = FE_SCALE_COUNTER; @@ -630,11 +666,11 @@ static void smsdvb_unregister_client(struct smsdvb_client_t *client) static void smsdvb_onremove(void *context) { - kmutex_lock(&g_smsdvb_clientslock); + mutex_lock(&g_smsdvb_clientslock); smsdvb_unregister_client((struct smsdvb_client_t *) context); - kmutex_unlock(&g_smsdvb_clientslock); + mutex_unlock(&g_smsdvb_clientslock); } static int smsdvb_start_feed(struct dvb_demux_feed *feed) @@ -1151,11 +1187,11 @@ static int smsdvb_hotplug(struct smscore_device_t *coredev, init_completion(&client->tune_done); init_completion(&client->stats_done); - kmutex_lock(&g_smsdvb_clientslock); + mutex_lock(&g_smsdvb_clientslock); list_add(&client->entry, &g_smsdvb_clients); - kmutex_unlock(&g_smsdvb_clientslock); + mutex_unlock(&g_smsdvb_clientslock); client->event_fe_state = -1; client->event_unc_state = -1; @@ -1201,7 +1237,7 @@ static int __init smsdvb_module_init(void) int rc; INIT_LIST_HEAD(&g_smsdvb_clients); - kmutex_init(&g_smsdvb_clientslock); + mutex_init(&g_smsdvb_clientslock); smsdvb_debugfs_register(); @@ -1216,14 +1252,14 @@ static void __exit smsdvb_module_exit(void) { smscore_unregister_hotplug(smsdvb_hotplug); - kmutex_lock(&g_smsdvb_clientslock); + mutex_lock(&g_smsdvb_clientslock); while (!list_empty(&g_smsdvb_clients)) smsdvb_unregister_client((struct smsdvb_client_t *)g_smsdvb_clients.next); smsdvb_debugfs_unregister(); - kmutex_unlock(&g_smsdvb_clientslock); + mutex_unlock(&g_smsdvb_clientslock); } module_init(smsdvb_module_init); diff --git a/drivers/media/common/videobuf2/frame_vector.c b/drivers/media/common/videobuf2/frame_vector.c index a0e65481a201..381158320a90 100644 --- a/drivers/media/common/videobuf2/frame_vector.c +++ b/drivers/media/common/videobuf2/frame_vector.c @@ -14,7 +14,6 @@ * get_vaddr_frames() - map virtual addresses to pfns * @start: starting user address * @nr_frames: number of pages / pfns from start to map - * @gup_flags: flags modifying lookup behaviour * @vec: structure which receives pages / pfns of the addresses mapped. * It should have space for at least nr_frames entries. * diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 030e48218687..c5b06a509566 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -105,7 +105,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs, int ret; int num_pages; - if (WARN_ON(!dev)) + if (WARN_ON(!dev) || WARN_ON(!size)) return ERR_PTR(-EINVAL); buf = kzalloc(sizeof *buf, GFP_KERNEL); diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index cfc27629444f..b7e4a3371176 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -190,7 +190,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 *ebuf, int ecount); /** - * Safely find needle in haystack. + * findstr - Safely find needle in haystack. * * @haystack: Buffer to look in. * @hlen: Number of bytes in haystack. @@ -1006,7 +1006,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); /* EN50221 thread functions */ /** - * Wake up the DVB CA thread + * dvb_ca_en50221_thread_wakeup - Wake up the DVB CA thread * * @ca: CA instance. */ @@ -1020,7 +1020,7 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) } /** - * Update the delay used by the thread. + * dvb_ca_en50221_thread_update_delay - Update the delay used by the thread. * * @ca: CA instance. */ @@ -1078,7 +1078,7 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) } /** - * Poll if the CAM is gone. + * dvb_ca_en50221_poll_cam_gone - Poll if the CAM is gone. * * @ca: CA instance. * @slot: Slot to process. @@ -1109,7 +1109,8 @@ static int dvb_ca_en50221_poll_cam_gone(struct dvb_ca_private *ca, int slot) } /** - * Thread state machine for one CA slot to perform the data transfer. + * dvb_ca_en50221_thread_state_machine - Thread state machine for one CA slot + * to perform the data transfer. * * @ca: CA instance. * @slot: Slot to process. @@ -1324,13 +1325,14 @@ static int dvb_ca_en50221_thread(void *data) /* EN50221 IO interface functions */ /** - * Real ioctl implementation. - * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. + * dvb_ca_en50221_io_do_ioctl - Real ioctl implementation. * * @file: File concerned. * @cmd: IOCTL command. * @parg: Associated argument. * + * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. + * * return: 0 on success, <0 on error. */ static int dvb_ca_en50221_io_do_ioctl(struct file *file, @@ -1408,7 +1410,7 @@ out_unlock: } /** - * Wrapper for ioctl implementation. + * dvb_ca_en50221_io_ioctl - Wrapper for ioctl implementation. * * @file: File concerned. * @cmd: IOCTL command. @@ -1423,7 +1425,7 @@ static long dvb_ca_en50221_io_ioctl(struct file *file, } /** - * Implementation of write() syscall. + * dvb_ca_en50221_io_write - Implementation of write() syscall. * * @file: File structure. * @buf: Source buffer. @@ -1579,7 +1581,7 @@ nextslot: } /** - * Implementation of read() syscall. + * dvb_ca_en50221_io_read - Implementation of read() syscall. * * @file: File structure. * @buf: Destination buffer. @@ -1690,7 +1692,7 @@ exit: } /** - * Implementation of file open syscall. + * dvb_ca_en50221_io_open - Implementation of file open syscall. * * @inode: Inode concerned. * @file: File concerned. @@ -1740,7 +1742,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) } /** - * Implementation of file close syscall. + * dvb_ca_en50221_io_release - Implementation of file close syscall. * * @inode: Inode concerned. * @file: File concerned. @@ -1769,7 +1771,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) } /** - * Implementation of poll() syscall. + * dvb_ca_en50221_io_poll - Implementation of poll() syscall. * * @file: File concerned. * @wait: poll wait table. @@ -1827,7 +1829,7 @@ static const struct dvb_device dvbdev_ca = { /* Initialisation/shutdown functions */ /** - * Initialise a new DVB CA EN50221 interface device. + * dvb_ca_en50221_init - Initialise a new DVB CA EN50221 interface device. * * @dvb_adapter: DVB adapter to attach the new CA device to. * @pubca: The dvb_ca instance. @@ -1919,7 +1921,7 @@ exit: EXPORT_SYMBOL(dvb_ca_en50221_init); /** - * Release a DVB CA EN50221 interface device. + * dvb_ca_en50221_release - Release a DVB CA EN50221 interface device. * * @pubca: The associated dvb_ca instance. */ diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index fb35697dd93c..a6915582d1a6 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -481,6 +481,10 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp; + if (fepriv->max_drift) + dev_warn_once(fe->dvb->device, + "Frontend requested software zigzag, but didn't set the frequency step size\n"); + /* if we've got no parameters, just keep idling */ if (fepriv->state & FESTATE_IDLE) { fepriv->delay = 3 * HZ; @@ -1791,6 +1795,53 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) return emulate_delivery_system(fe, delsys); } +static void prepare_tuning_algo_parameters(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_frontend_tune_settings fetunesettings = { 0 }; + + /* get frontend-specific tuning settings */ + if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { + fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; + fepriv->max_drift = fetunesettings.max_drift; + fepriv->step_size = fetunesettings.step_size; + } else { + /* default values */ + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_ISDBS: + case SYS_TURBO: + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + fepriv->min_delay = HZ / 20; + fepriv->step_size = c->symbol_rate / 16000; + fepriv->max_drift = c->symbol_rate / 2000; + break; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_ISDBT: + case SYS_DTMB: + fepriv->min_delay = HZ / 20; + fepriv->step_size = dvb_frontend_get_stepsize(fe) * 2; + fepriv->max_drift = fepriv->step_size + 1; + break; + default: + /* + * FIXME: This sounds wrong! if freqency_stepsize is + * defined by the frontend, why not use it??? + */ + fepriv->min_delay = HZ / 20; + fepriv->step_size = 0; /* no zigzag */ + fepriv->max_drift = 0; + break; + } + } + if (dvb_override_tune_delay > 0) + fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; +} + /** * dtv_property_process_set - Sets a single DTV property * @fe: Pointer to &struct dvb_frontend @@ -2183,7 +2234,6 @@ static int dtv_set_frontend(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_tune_settings fetunesettings; u32 rolloff = 0; if (dvb_frontend_check_parameters(fe) < 0) @@ -2261,46 +2311,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe) if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE) c->code_rate_LP = FEC_AUTO; - /* get frontend-specific tuning settings */ - memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); - if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { - fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; - fepriv->max_drift = fetunesettings.max_drift; - fepriv->step_size = fetunesettings.step_size; - } else { - /* default values */ - switch (c->delivery_system) { - case SYS_DVBS: - case SYS_DVBS2: - case SYS_ISDBS: - case SYS_TURBO: - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - fepriv->min_delay = HZ / 20; - fepriv->step_size = c->symbol_rate / 16000; - fepriv->max_drift = c->symbol_rate / 2000; - break; - case SYS_DVBT: - case SYS_DVBT2: - case SYS_ISDBT: - case SYS_DTMB: - fepriv->min_delay = HZ / 20; - fepriv->step_size = dvb_frontend_get_stepsize(fe) * 2; - fepriv->max_drift = (dvb_frontend_get_stepsize(fe) * 2) + 1; - break; - default: - /* - * FIXME: This sounds wrong! if freqency_stepsize is - * defined by the frontend, why not use it??? - */ - fepriv->min_delay = HZ / 20; - fepriv->step_size = 0; /* no zigzag */ - fepriv->max_drift = 0; - break; - } - } - if (dvb_override_tune_delay > 0) - fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; + prepare_tuning_algo_parameters(fe); fepriv->state = FESTATE_RETUNE; diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 5ff7bedee247..3862ddc86ec4 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -241,6 +241,7 @@ static void dvb_media_device_free(struct dvb_device *dvbdev) if (dvbdev->adapter->conn) { media_device_unregister_entity(dvbdev->adapter->conn); + kfree(dvbdev->adapter->conn); dvbdev->adapter->conn = NULL; kfree(dvbdev->adapter->conn_pads); dvbdev->adapter->conn_pads = NULL; diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 37b32d9b398d..bf9e4ef35684 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -4775,7 +4775,7 @@ set_frequency(struct drx_demod_instance *demod, bool select_pos_image = false; bool rf_mirror; bool tuner_mirror; - bool image_to_select = true; + bool image_to_select; s32 fm_frequency_shift = 0; rf_mirror = (ext_attr->mirror == DRX_MIRROR_YES) ? true : false; diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 722576f1732a..136b76cb4807 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -711,39 +711,6 @@ static int lgdt3306a_set_inversion_auto(struct lgdt3306a_state *state, return ret; } -static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state, - struct dtv_frontend_properties *p, - int inversion) -{ - int ret = 0; - - dbg_info("(%d)\n", inversion); -#if 0 - /* - * FGR - spectral_inversion defaults already set for VSB and QAM; - * can enable later if desired - */ - - ret = lgdt3306a_set_inversion(state, inversion); - - switch (p->modulation) { - case VSB_8: - /* Manual only for VSB */ - ret = lgdt3306a_set_inversion_auto(state, 0); - break; - case QAM_64: - case QAM_256: - case QAM_AUTO: - /* Auto ok for QAM */ - ret = lgdt3306a_set_inversion_auto(state, 1); - break; - default: - ret = -EINVAL; - } -#endif - return ret; -} - static int lgdt3306a_set_if(struct lgdt3306a_state *state, struct dtv_frontend_properties *p) { @@ -1048,10 +1015,7 @@ static int lgdt3306a_set_parameters(struct dvb_frontend *fe) if (lg_chkerr(ret)) goto fail; - ret = lgdt3306a_spectral_inversion(state, p, - state->cfg->spectral_inversion ? 1 : 0); - if (lg_chkerr(ret)) - goto fail; + /* spectral_inversion defaults already set for VSB and QAM */ ret = lgdt3306a_mpeg_mode(state, state->cfg->mpeg_mode); if (lg_chkerr(ret)) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index cfa4cdde99d8..02e8aa11e36e 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1904,8 +1904,8 @@ static int m88ds3103_probe(struct i2c_client *client, dev->dt_client = i2c_new_dummy_device(client->adapter, dev->dt_addr); - if (!dev->dt_client) { - ret = -ENODEV; + if (IS_ERR(dev->dt_client)) { + ret = PTR_ERR(dev->dt_client); goto err_kfree; } } diff --git a/drivers/media/dvb-frontends/mxl692.c b/drivers/media/dvb-frontends/mxl692.c index 86af831c0176..83030643aba7 100644 --- a/drivers/media/dvb-frontends/mxl692.c +++ b/drivers/media/dvb-frontends/mxl692.c @@ -377,7 +377,7 @@ static int mxl692_memread(struct mxl692_dev *dev, u32 addr, static const char *mxl692_opcode_string(u8 opcode) { - if (opcode >= 0 && opcode <= MXL_EAGLE_OPCODE_INTERNAL) + if (opcode <= MXL_EAGLE_OPCODE_INTERNAL) return MXL_EAGLE_OPCODE_STRING[opcode]; return "invalid opcode"; diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index 655db8272268..9767159aeb9b 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -281,7 +281,7 @@ static int sp8870_set_frontend_parameters(struct dvb_frontend *fe) // read status reg in order to clear pending irqs err = sp8870_readreg(state, 0x200); - if (err) + if (err < 0) return err; // system controller start diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 56256c1e8b0d..31bac06d46b5 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -42,8 +42,8 @@ enum adv748x_page { ADV748X_PAGE_EOR, /* End Mark */ }; -/** - * enum adv748x_ports - Device tree port number definitions +/* + * Device tree port number definitions * * The ADV748X ports define the mapping between subdevices * and the device tree specification @@ -173,9 +173,9 @@ struct adv748x_afe { * * @endpoints: parsed device node endpoints for each port * - * @i2c_addresses I2C Page addresses - * @i2c_clients I2C clients for the page accesses - * @regmap regmap configuration pages. + * @i2c_addresses: I2C Page addresses + * @i2c_clients: I2C clients for the page accesses + * @regmap: regmap configuration pages. * * @hdmi: state of HDMI receiver context * @afe: state of AFE receiver context diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c index a3161d709015..5fc6c06edda1 100644 --- a/drivers/media/i2c/adv7511-v4l2.c +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -214,36 +214,25 @@ static inline void adv7511_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask adv7511_wr(sd, reg, (adv7511_rd(sd, reg) & clr_mask) | val_mask); } -static int adv_smbus_read_i2c_block_data(struct i2c_client *client, - u8 command, unsigned length, u8 *values) -{ - union i2c_smbus_data data; - int ret; - - if (length > I2C_SMBUS_BLOCK_MAX) - length = I2C_SMBUS_BLOCK_MAX; - data.block[0] = length; - - ret = i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_READ, command, - I2C_SMBUS_I2C_BLOCK_DATA, &data); - memcpy(values, data.block + 1, length); - return ret; -} - -static void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf) +static int adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf) { struct adv7511_state *state = get_adv7511_state(sd); int i; - int err = 0; v4l2_dbg(1, debug, sd, "%s:\n", __func__); - for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_read_i2c_block_data(state->i2c_edid, i, + for (i = 0; i < len; i += I2C_SMBUS_BLOCK_MAX) { + s32 ret; + + ret = i2c_smbus_read_i2c_block_data(state->i2c_edid, i, I2C_SMBUS_BLOCK_MAX, buf + i); - if (err) - v4l2_err(sd, "%s: i2c read error\n", __func__); + if (ret < 0) { + v4l2_err(sd, "%s: i2c read error\n", __func__); + return ret; + } + } + + return 0; } static inline int adv7511_cec_read(struct v4l2_subdev *sd, u8 reg) @@ -1207,21 +1196,21 @@ static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) return -EINVAL; if (edid->start_block == 0 && edid->blocks == 0) { - edid->blocks = state->edid.segments * 2; + edid->blocks = state->edid.blocks; return 0; } - if (state->edid.segments == 0) + if (state->edid.blocks == 0) return -ENODATA; - if (edid->start_block >= state->edid.segments * 2) + if (edid->start_block >= state->edid.blocks) return -EINVAL; - if (edid->start_block + edid->blocks > state->edid.segments * 2) - edid->blocks = state->edid.segments * 2 - edid->start_block; + if (edid->start_block + edid->blocks > state->edid.blocks) + edid->blocks = state->edid.blocks - edid->start_block; memcpy(edid->edid, &state->edid.data[edid->start_block * 128], - 128 * edid->blocks); + 128 * edid->blocks); return 0; } @@ -1668,22 +1657,27 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) if (edidRdy & MASK_ADV7511_EDID_RDY) { int segment = adv7511_rd(sd, 0xc4); struct adv7511_edid_detect ed; + int err; if (segment >= EDID_MAX_SEGM) { v4l2_err(sd, "edid segment number too big\n"); return false; } v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment); - adv7511_edid_rd(sd, 256, &state->edid.data[segment * 256]); - adv7511_dbg_dump_edid(2, debug, sd, segment, &state->edid.data[segment * 256]); - if (segment == 0) { - state->edid.blocks = state->edid.data[0x7e] + 1; - v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", __func__, state->edid.blocks); + err = adv7511_edid_rd(sd, 256, &state->edid.data[segment * 256]); + if (!err) { + adv7511_dbg_dump_edid(2, debug, sd, segment, &state->edid.data[segment * 256]); + if (segment == 0) { + state->edid.blocks = state->edid.data[0x7e] + 1; + v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", + __func__, state->edid.blocks); + } } - if (!edid_verify_crc(sd, segment) || - !edid_verify_header(sd, segment)) { - /* edid crc error, force reread of edid segment */ - v4l2_err(sd, "%s: edid crc or header error\n", __func__); + + if (err || !edid_verify_crc(sd, segment) || !edid_verify_header(sd, segment)) { + /* Couldn't read EDID or EDID is invalid. Force retry! */ + if (!err) + v4l2_err(sd, "%s: edid crc or header error\n", __func__); state->have_monitor = false; adv7511_s_power(sd, false); adv7511_s_power(sd, true); @@ -1964,7 +1958,7 @@ static int adv7511_remove(struct i2c_client *client) adv7511_set_isr(sd, false); adv7511_init_setup(sd); - cancel_delayed_work(&state->edid_handler); + cancel_delayed_work_sync(&state->edid_handler); i2c_unregister_device(state->i2c_edid); i2c_unregister_device(state->i2c_cec); i2c_unregister_device(state->i2c_pktmem); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 09004d928d11..3049aa2fd0f0 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -73,6 +73,8 @@ MODULE_LICENSE("GPL"); #define ADV76XX_MAX_ADDRS (3) +#define ADV76XX_MAX_EDID_BLOCKS 4 + enum adv76xx_type { ADV7604, ADV7611, @@ -108,6 +110,11 @@ struct adv76xx_chip_info { unsigned int edid_enable_reg; unsigned int edid_status_reg; + unsigned int edid_segment_reg; + unsigned int edid_segment_mask; + unsigned int edid_spa_loc_reg; + unsigned int edid_spa_loc_msb_mask; + unsigned int edid_spa_port_b_reg; unsigned int lcf_reg; unsigned int cable_det_mask; @@ -176,7 +183,7 @@ struct adv76xx_state { const struct adv76xx_format_info *format; struct { - u8 edid[256]; + u8 edid[ADV76XX_MAX_EDID_BLOCKS * 128]; u32 present; unsigned blocks; } edid; @@ -512,10 +519,17 @@ static inline int edid_write_block(struct v4l2_subdev *sd, static void adv76xx_set_hpd(struct adv76xx_state *state, unsigned int hpd) { + const struct adv76xx_chip_info *info = state->info; unsigned int i; - for (i = 0; i < state->info->num_dv_ports; ++i) - gpiod_set_value_cansleep(state->hpd_gpio[i], hpd & BIT(i)); + if (info->type == ADV7604) { + for (i = 0; i < state->info->num_dv_ports; ++i) + gpiod_set_value_cansleep(state->hpd_gpio[i], hpd & BIT(i)); + } else { + for (i = 0; i < state->info->num_dv_ports; ++i) + io_write_clr_set(&state->sd, 0x20, 0x80 >> i, + (!!(hpd & BIT(i))) << (7 - i)); + } v4l2_subdev_notify(&state->sd, ADV76XX_HOTPLUG, &hpd); } @@ -2298,7 +2312,7 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) struct adv76xx_state *state = to_state(sd); const struct adv76xx_chip_info *info = state->info; unsigned int spa_loc; - u16 pa; + u16 pa, parent_pa; int err; int i; @@ -2327,15 +2341,25 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) __func__, edid->pad, state->edid.present); return 0; } - if (edid->blocks > 2) { - edid->blocks = 2; + if (edid->blocks > ADV76XX_MAX_EDID_BLOCKS) { + edid->blocks = ADV76XX_MAX_EDID_BLOCKS; return -E2BIG; } + pa = v4l2_get_edid_phys_addr(edid->edid, edid->blocks * 128, &spa_loc); - err = v4l2_phys_addr_validate(pa, &pa, NULL); + err = v4l2_phys_addr_validate(pa, &parent_pa, NULL); if (err) return err; + if (!spa_loc) { + /* + * There is no SPA, so just set spa_loc to 128 and pa to whatever + * data is there. + */ + spa_loc = 128; + pa = (edid->edid[spa_loc] << 8) | edid->edid[spa_loc + 1]; + } + v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n", __func__, edid->pad, state->edid.present); @@ -2344,41 +2368,33 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) adv76xx_set_hpd(state, 0); rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); - /* - * Return an error if no location of the source physical address - * was found. - */ - if (spa_loc == 0) - return -EINVAL; - switch (edid->pad) { case ADV76XX_PAD_HDMI_PORT_A: - state->spa_port_a[0] = edid->edid[spa_loc]; - state->spa_port_a[1] = edid->edid[spa_loc + 1]; + state->spa_port_a[0] = pa >> 8; + state->spa_port_a[1] = pa & 0xff; break; case ADV7604_PAD_HDMI_PORT_B: - rep_write(sd, 0x70, edid->edid[spa_loc]); - rep_write(sd, 0x71, edid->edid[spa_loc + 1]); + rep_write(sd, info->edid_spa_port_b_reg, pa >> 8); + rep_write(sd, info->edid_spa_port_b_reg + 1, pa & 0xff); break; case ADV7604_PAD_HDMI_PORT_C: - rep_write(sd, 0x72, edid->edid[spa_loc]); - rep_write(sd, 0x73, edid->edid[spa_loc + 1]); + rep_write(sd, info->edid_spa_port_b_reg + 2, pa >> 8); + rep_write(sd, info->edid_spa_port_b_reg + 3, pa & 0xff); break; case ADV7604_PAD_HDMI_PORT_D: - rep_write(sd, 0x74, edid->edid[spa_loc]); - rep_write(sd, 0x75, edid->edid[spa_loc + 1]); + rep_write(sd, info->edid_spa_port_b_reg + 4, pa >> 8); + rep_write(sd, info->edid_spa_port_b_reg + 5, pa & 0xff); break; default: return -EINVAL; } - if (info->type == ADV7604) { - rep_write(sd, 0x76, spa_loc & 0xff); - rep_write_clr_set(sd, 0x77, 0x40, (spa_loc & 0x100) >> 2); - } else { - /* ADV7612 Software Manual Rev. A, p. 15 */ - rep_write(sd, 0x70, spa_loc & 0xff); - rep_write_clr_set(sd, 0x71, 0x01, (spa_loc & 0x100) >> 8); + if (info->edid_spa_loc_reg) { + u8 mask = info->edid_spa_loc_msb_mask; + + rep_write(sd, info->edid_spa_loc_reg, spa_loc & 0xff); + rep_write_clr_set(sd, info->edid_spa_loc_reg + 1, + mask, (spa_loc & 0x100) ? mask : 0); } edid->edid[spa_loc] = state->spa_port_a[0]; @@ -2390,11 +2406,25 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) edid->edid[0x16]); state->edid.present |= 1 << edid->pad; - err = edid_write_block(sd, 128 * edid->blocks, state->edid.edid); + rep_write_clr_set(sd, info->edid_segment_reg, + info->edid_segment_mask, 0); + err = edid_write_block(sd, 128 * min(edid->blocks, 2U), state->edid.edid); if (err < 0) { v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad); return err; } + if (edid->blocks > 2) { + rep_write_clr_set(sd, info->edid_segment_reg, + info->edid_segment_mask, + info->edid_segment_mask); + err = edid_write_block(sd, 128 * (edid->blocks - 2), + state->edid.edid + 256); + if (err < 0) { + v4l2_err(sd, "error %d writing edid pad %d\n", + err, edid->pad); + return err; + } + } /* adv76xx calculates the checksums and enables I2C access to internal EDID RAM from DDC port. */ @@ -2409,7 +2439,7 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) v4l2_err(sd, "error enabling edid (0x%x)\n", state->edid.present); return -EIO; } - cec_s_phys_addr(state->cec_adap, pa, false); + cec_s_phys_addr(state->cec_adap, parent_pa, false); /* enable hotplug after 100 ms */ schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10); @@ -2803,6 +2833,18 @@ static int adv76xx_core_init(struct v4l2_subdev *sd) io_write(sd, 0x0b, 0x44); /* Power down ESDP block */ cp_write(sd, 0xcf, 0x01); /* Power down macrovision */ + /* HPD */ + if (info->type != ADV7604) { + /* Set manual HPD values to 0 */ + io_write_clr_set(sd, 0x20, 0xc0, 0); + /* + * Set HPA_DELAY to 200 ms and set automatic HPD control + * to: internal EDID is active AND a cable is detected + * AND the manual HPD control is set to 1. + */ + hdmi_write_clr_set(sd, 0x6c, 0xf6, 0x26); + } + /* video format */ io_write_clr_set(sd, 0x02, 0x0f, pdata->alt_gamma << 3); io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 | @@ -2987,6 +3029,11 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = { .num_dv_ports = 4, .edid_enable_reg = 0x77, .edid_status_reg = 0x7d, + .edid_segment_reg = 0x77, + .edid_segment_mask = 0x10, + .edid_spa_loc_reg = 0x76, + .edid_spa_loc_msb_mask = 0x40, + .edid_spa_port_b_reg = 0x70, .lcf_reg = 0xb3, .tdms_lock_mask = 0xe0, .cable_det_mask = 0x1e, @@ -3037,6 +3084,8 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = { .num_dv_ports = 1, .edid_enable_reg = 0x74, .edid_status_reg = 0x76, + .edid_segment_reg = 0x7a, + .edid_segment_mask = 0x01, .lcf_reg = 0xa3, .tdms_lock_mask = 0x43, .cable_det_mask = 0x01, @@ -3081,6 +3130,11 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = { .num_dv_ports = 1, /* normally 2 */ .edid_enable_reg = 0x74, .edid_status_reg = 0x76, + .edid_segment_reg = 0x7a, + .edid_segment_mask = 0x01, + .edid_spa_loc_reg = 0x70, + .edid_spa_loc_msb_mask = 0x01, + .edid_spa_port_b_reg = 0x52, .lcf_reg = 0xa3, .tdms_lock_mask = 0x43, .cable_det_mask = 0x01, @@ -3616,7 +3670,7 @@ static int adv76xx_remove(struct i2c_client *client) io_write(sd, 0x6e, 0); io_write(sd, 0x73, 0); - cancel_delayed_work(&state->delayed_work_enable_hotplug); + cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); adv76xx_unregister_clients(to_state(sd)); diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 0855f648416d..ff10af757b99 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -88,7 +88,7 @@ struct adv7842_format_info { struct adv7842_state { struct adv7842_platform_data pdata; struct v4l2_subdev sd; - struct media_pad pad; + struct media_pad pads[ADV7842_PAD_SOURCE + 1]; struct v4l2_ctrl_handler hdl; enum adv7842_mode mode; struct v4l2_dv_timings timings; @@ -99,10 +99,12 @@ struct adv7842_state { v4l2_std_id norm; struct { u8 edid[256]; + u32 blocks; u32 present; } hdmi_edid; struct { u8 edid[256]; + u32 blocks; u32 present; } vga_edid; struct v4l2_fract aspect_ratio; @@ -343,20 +345,6 @@ static void adv_smbus_write_byte_no_check(struct i2c_client *client, I2C_SMBUS_BYTE_DATA, &data); } -static s32 adv_smbus_write_i2c_block_data(struct i2c_client *client, - u8 command, unsigned length, const u8 *values) -{ - union i2c_smbus_data data; - - if (length > I2C_SMBUS_BLOCK_MAX) - length = I2C_SMBUS_BLOCK_MAX; - data.block[0] = length; - memcpy(data.block + 1, values, length); - return i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_WRITE, command, - I2C_SMBUS_I2C_BLOCK_DATA, &data); -} - /* ----------------------------------------------------------------------- */ static inline int io_read(struct v4l2_subdev *sd, u8 reg) @@ -725,7 +713,8 @@ static int edid_write_vga_segment(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct adv7842_state *state = to_state(sd); - const u8 *val = state->vga_edid.edid; + const u8 *edid = state->vga_edid.edid; + u32 blocks = state->vga_edid.blocks; int err = 0; int i; @@ -740,9 +729,10 @@ static int edid_write_vga_segment(struct v4l2_subdev *sd) /* edid segment pointer '1' for VGA port */ rep_write_and_or(sd, 0x77, 0xef, 0x10); - for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, - I2C_SMBUS_BLOCK_MAX, val + i); + for (i = 0; !err && i < blocks * 128; i += I2C_SMBUS_BLOCK_MAX) + err = i2c_smbus_write_i2c_block_data(state->i2c_edid, i, + I2C_SMBUS_BLOCK_MAX, + edid + i); if (err) return err; @@ -772,8 +762,9 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) struct i2c_client *client = v4l2_get_subdevdata(sd); struct adv7842_state *state = to_state(sd); const u8 *edid = state->hdmi_edid.edid; + u32 blocks = state->hdmi_edid.blocks; int spa_loc; - u16 pa; + u16 pa, parent_pa; int err = 0; int i; @@ -791,33 +782,35 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) return 0; } - pa = v4l2_get_edid_phys_addr(edid, 256, &spa_loc); - err = v4l2_phys_addr_validate(pa, &pa, NULL); + pa = v4l2_get_edid_phys_addr(edid, blocks * 128, &spa_loc); + err = v4l2_phys_addr_validate(pa, &parent_pa, NULL); if (err) return err; - /* - * Return an error if no location of the source physical address - * was found. - */ - if (spa_loc == 0) - return -EINVAL; + if (!spa_loc) { + /* + * There is no SPA, so just set spa_loc to 128 and pa to whatever + * data is there. + */ + spa_loc = 128; + pa = (edid[spa_loc] << 8) | edid[spa_loc + 1]; + } /* edid segment pointer '0' for HDMI ports */ rep_write_and_or(sd, 0x77, 0xef, 0x00); - for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, + for (i = 0; !err && i < blocks * 128; i += I2C_SMBUS_BLOCK_MAX) + err = i2c_smbus_write_i2c_block_data(state->i2c_edid, i, I2C_SMBUS_BLOCK_MAX, edid + i); if (err) return err; if (port == ADV7842_EDID_PORT_A) { - rep_write(sd, 0x72, edid[spa_loc]); - rep_write(sd, 0x73, edid[spa_loc + 1]); + rep_write(sd, 0x72, pa >> 8); + rep_write(sd, 0x73, pa & 0xff); } else { - rep_write(sd, 0x74, edid[spa_loc]); - rep_write(sd, 0x75, edid[spa_loc + 1]); + rep_write(sd, 0x74, pa >> 8); + rep_write(sd, 0x75, pa & 0xff); } rep_write(sd, 0x76, spa_loc & 0xff); rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); @@ -837,7 +830,7 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port) (port == ADV7842_EDID_PORT_A) ? 'A' : 'B'); return -EIO; } - cec_s_phys_addr(state->cec_adap, pa, false); + cec_s_phys_addr(state->cec_adap, parent_pa, false); /* enable hotplug after 200 ms */ schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 5); @@ -1079,7 +1072,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ - if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { + if (i2c_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); break; } @@ -1135,7 +1128,7 @@ static void adv7842_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off offset_buf[3] = offset_c & 0x0ff; /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf)) + if (i2c_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); } @@ -1164,7 +1157,7 @@ static void adv7842_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, gain_buf[3] = ((gain_c & 0x0ff)); /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf)) + if (i2c_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); } @@ -2456,6 +2449,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) { struct adv7842_state *state = to_state(sd); + u32 blocks = 0; u8 *data = NULL; memset(edid->reserved, 0, sizeof(edid->reserved)); @@ -2463,30 +2457,34 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) switch (edid->pad) { case ADV7842_EDID_PORT_A: case ADV7842_EDID_PORT_B: - if (state->hdmi_edid.present & (0x04 << edid->pad)) + if (state->hdmi_edid.present & (0x04 << edid->pad)) { data = state->hdmi_edid.edid; + blocks = state->hdmi_edid.blocks; + } break; case ADV7842_EDID_PORT_VGA: - if (state->vga_edid.present) + if (state->vga_edid.present) { data = state->vga_edid.edid; + blocks = state->vga_edid.blocks; + } break; default: return -EINVAL; } if (edid->start_block == 0 && edid->blocks == 0) { - edid->blocks = data ? 2 : 0; + edid->blocks = blocks; return 0; } if (!data) return -ENODATA; - if (edid->start_block >= 2) + if (edid->start_block >= blocks) return -EINVAL; - if (edid->start_block + edid->blocks > 2) - edid->blocks = 2 - edid->start_block; + if (edid->start_block + edid->blocks > blocks) + edid->blocks = blocks - edid->start_block; memcpy(edid->edid, data + edid->start_block * 128, edid->blocks * 128); @@ -2510,26 +2508,30 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e) } /* todo, per edid */ - state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15], - e->edid[0x16]); + if (e->blocks) + state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15], + e->edid[0x16]); switch (e->pad) { case ADV7842_EDID_PORT_VGA: memset(&state->vga_edid.edid, 0, 256); + state->vga_edid.blocks = e->blocks; state->vga_edid.present = e->blocks ? 0x1 : 0x0; - memcpy(&state->vga_edid.edid, e->edid, 128 * e->blocks); + if (e->blocks) + memcpy(&state->vga_edid.edid, e->edid, 128 * e->blocks); err = edid_write_vga_segment(sd); break; case ADV7842_EDID_PORT_A: case ADV7842_EDID_PORT_B: memset(&state->hdmi_edid.edid, 0, 256); + state->hdmi_edid.blocks = e->blocks; if (e->blocks) { state->hdmi_edid.present |= 0x04 << e->pad; + memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks); } else { state->hdmi_edid.present &= ~(0x04 << e->pad); adv7842_s_detect_tx_5v_ctrl(sd); } - memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks); err = edid_write_hdmi_segment(sd, e->pad); break; default: @@ -3442,6 +3444,7 @@ static int adv7842_probe(struct i2c_client *client, struct v4l2_ctrl_handler *hdl; struct v4l2_ctrl *ctrl; struct v4l2_subdev *sd; + unsigned int i; u16 rev; int err; @@ -3545,8 +3548,11 @@ static int adv7842_probe(struct i2c_client *client, adv7842_delayed_work_enable_hotplug); sd->entity.function = MEDIA_ENT_F_DV_DECODER; - state->pad.flags = MEDIA_PAD_FL_SOURCE; - err = media_entity_pads_init(&sd->entity, 1, &state->pad); + for (i = 0; i < ADV7842_PAD_SOURCE; ++i) + state->pads[i].flags = MEDIA_PAD_FL_SINK; + state->pads[ADV7842_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + err = media_entity_pads_init(&sd->entity, ADV7842_PAD_SOURCE + 1, + state->pads); if (err) goto err_work_queues; @@ -3586,7 +3592,7 @@ static int adv7842_remove(struct i2c_client *client) struct adv7842_state *state = to_state(sd); adv7842_irq_enable(sd, false); - cancel_delayed_work(&state->delayed_work_enable_hotplug); + cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); v4l2_device_unregister_subdev(sd); media_entity_cleanup(&sd->entity); adv7842_unregister_clients(sd); diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 15afbb4f5b31..9dc3f45da3dc 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3522,11 +3522,11 @@ static int ccs_probe(struct i2c_client *client) sensor->pll.scale_n = CCS_LIM(sensor, SCALER_N_MIN); ccs_create_subdev(sensor, sensor->scaler, " scaler", 2, - MEDIA_ENT_F_CAM_SENSOR); + MEDIA_ENT_F_PROC_VIDEO_SCALER); ccs_create_subdev(sensor, sensor->binner, " binner", 2, MEDIA_ENT_F_PROC_VIDEO_SCALER); ccs_create_subdev(sensor, sensor->pixel_array, " pixel_array", 1, - MEDIA_ENT_F_PROC_VIDEO_SCALER); + MEDIA_ENT_F_CAM_SENSOR); rval = ccs_init_controls(sensor); if (rval < 0) @@ -3572,7 +3572,7 @@ static int ccs_probe(struct i2c_client *client) pm_runtime_get_noresume(&client->dev); pm_runtime_enable(&client->dev); - rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd); + rval = v4l2_async_register_subdev_sensor(&sensor->src->sd); if (rval < 0) goto out_disable_runtime_pm; diff --git a/drivers/media/i2c/ccs/ccs-data.h b/drivers/media/i2c/ccs/ccs-data.h index c75d480c8792..638df69804ec 100644 --- a/drivers/media/i2c/ccs/ccs-data.h +++ b/drivers/media/i2c/ccs/ccs-data.h @@ -132,7 +132,7 @@ struct ccs_pdaf_pix_loc_block_desc_group { }; /** - * struct ccs_pdaf_pix_loc_block_desc - PDAF pixel location block descriptor + * struct ccs_pdaf_pix_loc_pixel_desc - PDAF pixel location block descriptor * @pixel_type: Type of the pixel; CCS_DATA_PDAF_PIXEL_TYPE_* * @small_offset_x: offset X coordinate * @small_offset_y: offset Y coordinate diff --git a/drivers/media/i2c/ccs/ccs-quirk.h b/drivers/media/i2c/ccs/ccs-quirk.h index 6b4ec4beaba0..5838fcda92fd 100644 --- a/drivers/media/i2c/ccs/ccs-quirk.h +++ b/drivers/media/i2c/ccs/ccs-quirk.h @@ -21,7 +21,7 @@ struct ccs_sensor; * sensor registers. Called the first time the sensor is powered up. * @post_poweron: Called always after the sensor has been fully powered on. * @pre_streamon: Called just before streaming is enabled. - * @post_streamon: Called right after stopping streaming. + * @post_streamoff: Called right after stopping streaming. * @pll_flags: Return flags for the PLL calculator. * @init: Quirk initialisation, called the last in probe(). This is * also appropriate for adding sensor specific controls, for instance. @@ -33,6 +33,8 @@ struct ccs_sensor; * @value: Register value, set by the caller on write, or * by the quirk on read * + * @flags: Quirk flags + * * @return: 0 on success, -ENOIOCTLCMD if no register * access may be done by the caller (default read * value is zero), else negative error code on error diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index 122af761c8e3..bb3eac5e005e 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -1443,7 +1443,7 @@ static int et8ek8_probe(struct i2c_client *client) goto err_mutex; } - ret = v4l2_async_register_subdev_sensor_common(&sensor->subdev); + ret = v4l2_async_register_subdev_sensor(&sensor->subdev); if (ret < 0) goto err_entity; diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index c74736845d7a..6f05c1138e3b 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -1145,7 +1145,7 @@ static int hi556_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&hi556->sd); + ret = v4l2_async_register_subdev_sensor(&hi556->sd); if (ret < 0) { dev_err(&client->dev, "failed to register V4L2 subdev: %d", ret); diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index cee1a4817af9..e8b281e432e8 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -1061,7 +1061,7 @@ static int imx214_probe(struct i2c_client *client) imx214_entity_init_cfg(&imx214->sd, NULL); - ret = v4l2_async_register_subdev_sensor_common(&imx214->sd); + ret = v4l2_async_register_subdev_sensor(&imx214->sd); if (ret < 0) { dev_err(dev, "could not register v4l2 device\n"); goto free_entity; diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 6e3382b85a90..1054ffedaefd 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -1035,29 +1035,47 @@ static int imx219_start_streaming(struct imx219 *imx219) const struct imx219_reg_list *reg_list; int ret; + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + return ret; + } + /* Apply default values of current mode */ reg_list = &imx219->mode->reg_list; ret = imx219_write_regs(imx219, reg_list->regs, reg_list->num_of_regs); if (ret) { dev_err(&client->dev, "%s failed to set mode\n", __func__); - return ret; + goto err_rpm_put; } ret = imx219_set_framefmt(imx219); if (ret) { dev_err(&client->dev, "%s failed to set frame format: %d\n", __func__, ret); - return ret; + goto err_rpm_put; } /* Apply customized values from user */ ret = __v4l2_ctrl_handler_setup(imx219->sd.ctrl_handler); if (ret) - return ret; + goto err_rpm_put; /* set stream on register */ - return imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, - IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING); + ret = imx219_write_reg(imx219, IMX219_REG_MODE_SELECT, + IMX219_REG_VALUE_08BIT, IMX219_MODE_STREAMING); + if (ret) + goto err_rpm_put; + + /* vflip and hflip cannot change during streaming */ + __v4l2_ctrl_grab(imx219->vflip, true); + __v4l2_ctrl_grab(imx219->hflip, true); + + return 0; + +err_rpm_put: + pm_runtime_put(&client->dev); + return ret; } static void imx219_stop_streaming(struct imx219 *imx219) @@ -1070,12 +1088,16 @@ static void imx219_stop_streaming(struct imx219 *imx219) IMX219_REG_VALUE_08BIT, IMX219_MODE_STANDBY); if (ret) dev_err(&client->dev, "%s failed to set stream\n", __func__); + + __v4l2_ctrl_grab(imx219->vflip, false); + __v4l2_ctrl_grab(imx219->hflip, false); + + pm_runtime_put(&client->dev); } static int imx219_set_stream(struct v4l2_subdev *sd, int enable) { struct imx219 *imx219 = to_imx219(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&imx219->mutex); @@ -1085,36 +1107,23 @@ static int imx219_set_stream(struct v4l2_subdev *sd, int enable) } if (enable) { - ret = pm_runtime_get_sync(&client->dev); - if (ret < 0) { - pm_runtime_put_noidle(&client->dev); - goto err_unlock; - } - /* * Apply default & customized values * and then start streaming. */ ret = imx219_start_streaming(imx219); if (ret) - goto err_rpm_put; + goto err_unlock; } else { imx219_stop_streaming(imx219); - pm_runtime_put(&client->dev); } imx219->streaming = enable; - /* vflip and hflip cannot change during streaming */ - __v4l2_ctrl_grab(imx219->vflip, enable); - __v4l2_ctrl_grab(imx219->hflip, enable); - mutex_unlock(&imx219->mutex); return ret; -err_rpm_put: - pm_runtime_put(&client->dev); err_unlock: mutex_unlock(&imx219->mutex); @@ -1528,7 +1537,7 @@ static int imx219_probe(struct i2c_client *client) goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&imx219->sd); + ret = v4l2_async_register_subdev_sensor(&imx219->sd); if (ret < 0) { dev_err(dev, "failed to register sensor sub-device: %d\n", ret); goto error_media_entity; diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index 61d74b794582..a017ec4e0f50 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -61,6 +61,15 @@ #define IMX258_DGTL_GAIN_DEFAULT 1024 #define IMX258_DGTL_GAIN_STEP 1 +/* HDR control */ +#define IMX258_REG_HDR 0x0220 +#define IMX258_HDR_ON BIT(0) +#define IMX258_REG_HDR_RATIO 0x0222 +#define IMX258_HDR_RATIO_MIN 0 +#define IMX258_HDR_RATIO_MAX 5 +#define IMX258_HDR_RATIO_STEP 1 +#define IMX258_HDR_RATIO_DEFAULT 0x0 + /* Test Pattern Control */ #define IMX258_REG_TEST_PATTERN 0x0600 @@ -777,6 +786,22 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) !ctrl->val ? REG_CONFIG_MIRROR_FLIP : REG_CONFIG_FLIP_TEST_PATTERN); break; + case V4L2_CID_WIDE_DYNAMIC_RANGE: + if (!ctrl->val) { + ret = imx258_write_reg(imx258, IMX258_REG_HDR, + IMX258_REG_VALUE_08BIT, + IMX258_HDR_RATIO_MIN); + } else { + ret = imx258_write_reg(imx258, IMX258_REG_HDR, + IMX258_REG_VALUE_08BIT, + IMX258_HDR_ON); + if (ret) + break; + ret = imx258_write_reg(imx258, IMX258_REG_HDR_RATIO, + IMX258_REG_VALUE_08BIT, + BIT(IMX258_HDR_RATIO_MAX)); + } + break; default: dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", @@ -1193,6 +1218,9 @@ static int imx258_init_controls(struct imx258 *imx258) IMX258_DGTL_GAIN_STEP, IMX258_DGTL_GAIN_DEFAULT); + v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_WIDE_DYNAMIC_RANGE, + 0, 1, 1, IMX258_HDR_RATIO_DEFAULT); + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_TEST_PATTERN, ARRAY_SIZE(imx258_test_pattern_menu) - 1, @@ -1289,7 +1317,7 @@ static int imx258_probe(struct i2c_client *client) if (ret) goto error_handler_free; - ret = v4l2_async_register_subdev_sensor_common(&imx258->sd); + ret = v4l2_async_register_subdev_sensor(&imx258->sd); if (ret < 0) goto error_media_entity; diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 54642d5f2d5b..cdccaab3043a 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -697,7 +697,7 @@ static inline int imx274_write_reg(struct stimx274 *priv, u16 addr, u8 val) } /** - * Read a multibyte register. + * imx274_read_mbreg - Read a multibyte register. * * Uses a bulk read where possible. * @@ -732,7 +732,7 @@ static int imx274_read_mbreg(struct stimx274 *priv, u16 addr, u32 *val, } /** - * Write a multibyte register. + * imx274_write_mbreg - Write a multibyte register. * * Uses a bulk write where possible. * @@ -980,7 +980,8 @@ static int imx274_binning_goodness(struct stimx274 *imx274, } /** - * Helper function to change binning and set both compose and format. + * __imx274_change_compose - Helper function to change binning and set both + * compose and format. * * We have two entry points to change binning: set_fmt and * set_selection(COMPOSE). Both have to compute the new output size @@ -1380,7 +1381,8 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd, max = fi->interval.numerator * 1000000 / fi->interval.denominator; def = max; - if (__v4l2_ctrl_modify_range(ctrl, min, max, 1, def)) { + ret = __v4l2_ctrl_modify_range(ctrl, min, max, 1, def); + if (ret) { dev_err(&imx274->client->dev, "Exposure ctrl range update failed\n"); goto unlock; diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 8473c0bbb35d..38540323a156 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -2486,7 +2486,7 @@ static int imx319_probe(struct i2c_client *client) goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&imx319->sd); + ret = v4l2_async_register_subdev_sensor(&imx319->sd); if (ret < 0) goto error_media_entity; diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index ad530f0d338a..047aa7658d21 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -1057,7 +1057,7 @@ static int imx334_probe(struct i2c_client *client) goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&imx334->sd); + ret = v4l2_async_register_subdev_sensor(&imx334->sd); if (ret < 0) { dev_err(imx334->dev, "failed to register async subdev: %d", ret); diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 700f7467fb31..ccedcd4c520a 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -1786,7 +1786,7 @@ static int imx355_probe(struct i2c_client *client) goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&imx355->sd); + ret = v4l2_async_register_subdev_sensor(&imx355->sd); if (ret < 0) goto error_media_entity; diff --git a/drivers/media/i2c/m5mols/m5mols.h b/drivers/media/i2c/m5mols/m5mols.h index 4023906d273d..60c102fa7df5 100644 --- a/drivers/media/i2c/m5mols/m5mols.h +++ b/drivers/media/i2c/m5mols/m5mols.h @@ -50,6 +50,7 @@ struct m5mols_resolution { * @exposure_time: exposure time register value * @shutter_speed: speed of the shutter register value * @aperture: aperture register value + * @brightness: brightness register value * @exposure_bias: it calls also EV bias * @iso_speed: ISO register value * @flash: status register value of the flash @@ -126,6 +127,8 @@ struct m5mols_scenemode { u8 wdr; }; +#define VERSION_STRING_SIZE 22 + /** * struct m5mols_version - firmware version information * @customer: customer information @@ -144,7 +147,6 @@ struct m5mols_scenemode { * about manufacturer and the vendor of the sensor's packaging. The least * significant 2 bytes of the string indicate packaging manufacturer. */ -#define VERSION_STRING_SIZE 22 struct m5mols_version { u8 customer; u8 project; diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index 661208c9bfc5..bc46a0957b40 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -1125,7 +1125,6 @@ static int max2175_g_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *vf) { struct max2175 *ctx = max2175_from_sd(sd); - int ret = 0; if (vf->tuner != 0) return -EINVAL; @@ -1134,7 +1133,7 @@ static int max2175_g_frequency(struct v4l2_subdev *sd, vf->type = V4L2_TUNER_RF; vf->frequency = ctx->freq; - return ret; + return 0; } static int max2175_enum_freq_bands(struct v4l2_subdev *sd, diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 60b4bc645334..c47b1d45d8fd 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -700,7 +700,7 @@ static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) default: ret = -EINVAL; break; - }; + } pm_runtime_put(&client->dev); diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 2f3be7a80cef..4a2885ff0cbe 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1738,7 +1738,7 @@ static int ov13858_probe(struct i2c_client *client, goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&ov13858->sd); + ret = v4l2_async_register_subdev_sensor(&ov13858->sd); if (ret < 0) goto error_media_entity; diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index b41a90c2aed5..0f3f17f3c426 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -1154,7 +1154,7 @@ static int ov2740_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&ov2740->sd); + ret = v4l2_async_register_subdev_sensor(&ov2740->sd); if (ret < 0) { dev_err(&client->dev, "failed to register V4L2 subdev: %d", ret); diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 14f3afa7721a..5b9cc71df473 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -3162,7 +3162,7 @@ static int ov5640_probe(struct i2c_client *client) if (ret) goto entity_cleanup; - ret = v4l2_async_register_subdev_sensor_common(&sensor->sd); + ret = v4l2_async_register_subdev_sensor(&sensor->sd); if (ret) goto free_ctrls; diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c index dfe38ab8224d..3ecb4a3e8773 100644 --- a/drivers/media/i2c/ov5648.c +++ b/drivers/media/i2c/ov5648.c @@ -2559,7 +2559,7 @@ static int ov5648_probe(struct i2c_client *client) /* V4L2 subdev register */ - ret = v4l2_async_register_subdev_sensor_common(subdev); + ret = v4l2_async_register_subdev_sensor(subdev); if (ret) goto error_pm; diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 866c8c2e8f59..dee7df8dd100 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2503,7 +2503,7 @@ static int ov5670_probe(struct i2c_client *client) } /* Async register for subdev */ - ret = v4l2_async_register_subdev_sensor_common(&ov5670->sd); + ret = v4l2_async_register_subdev_sensor(&ov5670->sd); if (ret < 0) { err_msg = "v4l2_async_register_subdev() error"; goto error_entity_cleanup; diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index ae00d717e599..dea32859459a 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -1193,7 +1193,7 @@ static int ov5675_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&ov5675->sd); + ret = v4l2_async_register_subdev_sensor(&ov5675->sd); if (ret < 0) { dev_err(&client->dev, "failed to register V4L2 subdev: %d", ret); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index bbccb6f9582f..09bee57a241d 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1336,7 +1336,7 @@ static int ov5695_probe(struct i2c_client *client, goto err_power_off; #endif - ret = v4l2_async_register_subdev_sensor_common(sd); + ret = v4l2_async_register_subdev_sensor(sd); if (ret) { dev_err(dev, "v4l2 async register subdev failed\n"); goto err_clean_entity; diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index b337f729d5e3..e3af3ea277af 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1795,7 +1795,7 @@ static int ov8856_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&ov8856->sd); + ret = v4l2_async_register_subdev_sensor(&ov8856->sd); if (ret < 0) { dev_err(&client->dev, "failed to register V4L2 subdev: %d", ret); diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index 36a60fbc211d..9ecf180635ee 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -2524,7 +2524,6 @@ static int ov8865_g_frame_interval(struct v4l2_subdev *subdev, { struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); const struct ov8865_mode *mode; - int ret = 0; mutex_lock(&sensor->mutex); @@ -2533,7 +2532,7 @@ static int ov8865_g_frame_interval(struct v4l2_subdev *subdev, mutex_unlock(&sensor->mutex); - return ret; + return 0; } static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = { @@ -2905,7 +2904,7 @@ static int ov8865_probe(struct i2c_client *client) /* V4L2 subdev register */ - ret = v4l2_async_register_subdev_sensor_common(subdev); + ret = v4l2_async_register_subdev_sensor(subdev); if (ret) goto error_pm; diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index e212465489e8..b7309a551cae 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -964,7 +964,7 @@ static int ov9734_probe(struct i2c_client *client) goto probe_error_v4l2_ctrl_handler_free; } - ret = v4l2_async_register_subdev_sensor_common(&ov9734->sd); + ret = v4l2_async_register_subdev_sensor(&ov9734->sd); if (ret < 0) { dev_err(&client->dev, "failed to register V4L2 subdev: %d", ret); diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c index dcc21515e5a4..179d107f494c 100644 --- a/drivers/media/i2c/rdacm21.c +++ b/drivers/media/i2c/rdacm21.c @@ -345,7 +345,7 @@ static int ov10640_initialize(struct rdacm21_device *dev) /* Read OV10640 ID to test communications. */ ov490_write_reg(dev, OV490_SCCB_SLAVE0_DIR, OV490_SCCB_SLAVE_READ); ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_HIGH, OV10640_CHIP_ID >> 8); - ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, (u8)OV10640_CHIP_ID); + ov490_write_reg(dev, OV490_SCCB_SLAVE0_ADDR_LOW, OV10640_CHIP_ID & 0xff); /* Trigger SCCB slave transaction and give it some time to complete. */ ov490_write_reg(dev, OV490_HOST_CMD, OV490_HOST_CMD_TRIGGER); diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index ec6f22efe19a..6e702b57c37d 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -510,7 +510,7 @@ static void s5k5baf_write_arr_seq(struct s5k5baf *state, u16 addr, #define s5k5baf_write_seq(state, addr, seq...) \ s5k5baf_write_arr_seq(state, addr, sizeof((char[]){ seq }), \ - (const u16 []){ seq }); + (const u16 []){ seq }) /* add items count at the beginning of the list */ #define NSEQ(seq...) sizeof((char[]){ seq }), seq diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c index 72439fae7968..038e38500760 100644 --- a/drivers/media/i2c/s5k6aa.c +++ b/drivers/media/i2c/s5k6aa.c @@ -416,7 +416,7 @@ static int s5k6aa_set_ahb_address(struct i2c_client *client) } /** - * s5k6aa_configure_pixel_clock - apply ISP main clock/PLL configuration + * s5k6aa_configure_pixel_clocks - apply ISP main clock/PLL configuration * @s5k6aa: pointer to &struct s5k6aa describing the device * * Configure the internal ISP PLL for the required output frequency. diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 831b5b54fd78..1b309bb743c7 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -2193,7 +2193,7 @@ static int tc358743_remove(struct i2c_client *client) del_timer_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); cec_unregister_adapter(state->cec_adap); v4l2_async_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index a09bf0a39d05..89bb7e6dc7a4 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -2804,7 +2804,7 @@ static int tda1997x_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(&state->hdl); regulator_bulk_disable(TDA1997X_NUM_SUPPLIES, state->supplies); - cancel_delayed_work(&state->delayed_work_enable_hpd); + cancel_delayed_work_sync(&state->delayed_work_enable_hpd); mutex_destroy(&state->page_lock); mutex_destroy(&state->lock); diff --git a/drivers/media/i2c/tvp514x_regs.h b/drivers/media/i2c/tvp514x_regs.h index cc236c968f67..b452725d5cfb 100644 --- a/drivers/media/i2c/tvp514x_regs.h +++ b/drivers/media/i2c/tvp514x_regs.h @@ -261,9 +261,9 @@ #define TOK_SKIP (3) /* token to skip a register */ /** * struct tvp514x_reg - Structure for TVP5146/47 register initialization values - * @token - Token: TOK_WRITE, TOK_TERM etc.. - * @reg - Register offset - * @val - Register Value for TOK_WRITE or delay in ms for TOK_DELAY + * @token: Token: TOK_WRITE, TOK_TERM etc.. + * @reg: Register offset + * @val: Register Value for TOK_WRITE or delay in ms for TOK_DELAY */ struct tvp514x_reg { u8 token; diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 12b45e669bcc..678b99771cfa 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -340,6 +340,7 @@ static void media_graph_walk_iter(struct media_graph *graph) stack_push(graph, next); dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n", next->name); + lockdep_assert_held(&entity->graph_obj.mdev->graph_mutex); } struct media_entity *media_graph_walk_next(struct media_graph *graph) diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c index a9d9520a94c6..6a4c7cb0ad0f 100644 --- a/drivers/media/pci/b2c2/flexcop-pci.c +++ b/drivers/media/pci/b2c2/flexcop-pci.c @@ -18,11 +18,11 @@ module_param(irq_chk_intv, int, 0644); MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog."); #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((debug & level)) printk(args); } while (0) +#define dprintk(level, args...) \ + do { if ((debug & (level))) printk(args); } while (0) #define DEBSTATUS "" #else -#define dprintk(level,args...) +#define dprintk(level, args...) no_printk(args) #define DEBSTATUS " (debugging is not enabled)" #endif diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index ca20b806e82d..c2b5ab287dd7 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -2011,7 +2011,7 @@ struct tvcard bttv_tvcards[] = { /* .audio_inputs= 0, */ .svhs = 9, .gpiomask = 0x00, - .gpiomask2 = 0x03, /* used for external vodeo mux */ + .gpiomask2 = 0x03, /* used for external video mux */ .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 0), .muxsel_hook = phytec_muxsel, .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ @@ -2025,7 +2025,7 @@ struct tvcard bttv_tvcards[] = { /* .audio_inputs= 0, */ .svhs = 9, .gpiomask = 0x00, - .gpiomask2 = 0x03, /* used for external vodeo mux */ + .gpiomask2 = 0x03, /* used for external video mux */ .muxsel = MUXSEL(2, 2, 2, 2, 3, 3, 3, 3, 1, 1), .muxsel_hook = phytec_muxsel, .gpiomux = { 0, 0, 0, 0 }, /* card has no audio */ @@ -2180,8 +2180,8 @@ struct tvcard bttv_tvcards[] = { [BTTV_BOARD_PICOLO_TETRA_CHIP] = { /*Eric DEBIEF <debief@telemsa.com>*/ /*EURESYS Picolo Tetra : 4 Conexant Fusion 878A, no audio, video input set with analog multiplexers GPIO controlled*/ - /* adds picolo_tetra_muxsel(), picolo_tetra_init(), the following declaration strucure, and #define BTTV_BOARD_PICOLO_TETRA_CHIP*/ - /*0x79 in bttv.h*/ + /*adds picolo_tetra_muxsel(), picolo_tetra_init(), the following declaration*/ + /*structure and #define BTTV_BOARD_PICOLO_TETRA_CHIP 0x79 in bttv.h*/ .name = "Euresys Picolo Tetra", .video_inputs = 4, /* .audio_inputs= 0, */ @@ -2506,7 +2506,7 @@ struct tvcard bttv_tvcards[] = { one external BNC composite input (mux 2) three internal composite inputs (unknown muxes) an 18-bit stereo A/D (CS5331A), which has: - one external stereo unblanced (RCA) audio connection + one external stereo unbalanced (RCA) audio connection one (or 3?) internal stereo balanced (XLR) audio connection input is selected via gpio to a 14052B mux (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300) @@ -3924,7 +3924,7 @@ static void osprey_eeprom(struct bttv *btv, const u8 ee[256]) u32 serial = 0; int cardid = -1; - /* This code will nevery actually get called in this case.... */ + /* This code will never actually get called in this case.... */ if (btv->c.type == BTTV_BOARD_UNKNOWN) { /* this might be an antique... check for MMAC label in eeprom */ if (!strncmp(ee, "MMAC", 4)) { @@ -4086,7 +4086,7 @@ static void avermedia_eeprom(struct bttv *btv) /* * For Voodoo TV/FM and Voodoo 200. These cards' tuners use a TDA9880 * analog demod, which is not I2C controlled like the newer and more common - * TDA9887 series. Instead is has two tri-state input pins, S0 and S1, + * TDA9887 series. Instead it has two tri-state input pins, S0 and S1, * that control the IF for the video and audio. Apparently, bttv GPIO * 0x10000 is connected to S0. S0 low selects a 38.9 MHz VIF for B/G/D/K/I * (i.e., PAL) while high selects 45.75 MHz for M/N (i.e., NTSC). @@ -4144,7 +4144,7 @@ static void init_PXC200(struct bttv *btv) int tmp; u32 val; - /* Initialise GPIO-connevted stuff */ + /* Initialise GPIO-connected stuff */ gpio_inout(0xffffff, (1<<13)); gpio_write(0); udelay(3); @@ -4580,7 +4580,7 @@ static void xguard_muxsel(struct bttv *btv, unsigned int input) } static void picolo_tetra_init(struct bttv *btv) { - /*This is the video input redirection fonctionality : I DID NOT USED IT. */ + /*This is the video input redirection functionality : I DID NOT USE IT. */ btwrite (0x08<<16,BT848_GPIO_DATA);/*GPIO[19] [==> 4053 B+C] set to 1 */ btwrite (0x04<<16,BT848_GPIO_DATA);/*GPIO[18] [==> 4053 A] set to 1*/ } @@ -4598,7 +4598,7 @@ static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input) * ivc120_muxsel [Added by Alan Garfield <alan@fromorbit.com>] * * The IVC120G security card has 4 i2c controlled TDA8540 matrix - * swichers to provide 16 channels to MUX0. The TDA8540's have + * switchers to provide 16 channels to MUX0. The TDA8540's have * 4 independent outputs and as such the IVC120G also has the * optional "Monitor Out" bus. This allows the card to be looking * at one input while the monitor is looking at another. diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 0695078ef812..839503e654f4 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -56,19 +56,19 @@ static u8 edid[256] = { 0x45, 0x59, 0x61, 0x59, 0x81, 0x99, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, - 0x46, 0x00, 0xe0, 0x0e, 0x11, 0x00, 0x00, 0x1e, + 0x45, 0x00, 0xe0, 0x0e, 0x11, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18, 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x63, 0x6f, 0x62, 0x61, 0x6c, 0x74, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9d, - 0x02, 0x03, 0x1f, 0xf0, 0x4a, 0x90, 0x1f, 0x04, + 0x02, 0x03, 0x1f, 0xf1, 0x4a, 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21, 0x20, 0x02, 0x11, 0x01, 0x23, 0x09, 0x07, 0x07, 0x68, 0x03, 0x0c, 0x00, 0x10, - 0x00, 0x00, 0x22, 0x0f, 0xe2, 0x00, 0xea, 0x00, + 0x00, 0x00, 0x22, 0x0f, 0xe2, 0x00, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -80,7 +80,7 @@ static u8 edid[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, }; static void cobalt_set_interrupt(struct cobalt *cobalt, bool enable) @@ -572,7 +572,7 @@ static int cobalt_subdevs_hsma_init(struct cobalt *cobalt) .addr = 0x20, .platform_data = &adv7842_pdata, }; - static struct v4l2_subdev_format sd_fmt = { + struct v4l2_subdev_format sd_fmt = { .pad = ADV7842_PAD_SOURCE, .which = V4L2_SUBDEV_FORMAT_ACTIVE, .format.code = MEDIA_BUS_FMT_YUYV8_1X16, diff --git a/drivers/media/pci/cx18/cx18-av-audio.c b/drivers/media/pci/cx18/cx18-av-audio.c index ee2b802d2895..833baa934448 100644 --- a/drivers/media/pci/cx18/cx18-av-audio.c +++ b/drivers/media/pci/cx18/cx18-av-audio.c @@ -46,7 +46,7 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) * an error of less than 0.13 ppm which is way, way better than any off * the shelf crystal will have for accuracy anyway. * - * Below I aim to run the PLLs' VCOs near 400 MHz to minimze error. + * Below I aim to run the PLLs' VCOs near 400 MHz to minimize error. * * Many thanks to Jeff Campbell and Mike Bradley for their extensive * investigation, experimentation, testing, and suggested solutions of diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index b33eb08631b1..11cfe35fd730 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -89,7 +89,7 @@ static void cx18_av_init(struct cx18 *cx) /* * The crystal freq used in calculations in this driver will be * 28.636360 MHz. - * Aim to run the PLLs' VCOs near 400 MHz to minimze errors. + * Aim to run the PLLs' VCOs near 400 MHz to minimize errors. */ /* @@ -122,7 +122,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd) cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x03000000, 0x03000000, 0x13000000); - /* initallize the PLL by toggling sleep bit */ + /* initialize the PLL by toggling sleep bit */ v = cx18_av_read4(cx, CXADEC_HOST_REG1); /* enable sleep mode - register appears to be read only... */ cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v | 1, v, 0xfffe); diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c index 876b96c11290..fdac310d7477 100644 --- a/drivers/media/pci/cx18/cx18-firmware.c +++ b/drivers/media/pci/cx18/cx18-firmware.c @@ -244,7 +244,7 @@ void cx18_init_power(struct cx18 *cx, int lowpwr) * an error of less than 0.13 ppm which is way, way better than any off * the shelf crystal will have for accuracy anyway. * - * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors. + * Below I aim to run the PLLs' VCOs near 400 MHz to minimize errors. * * Many thanks to Jeff Campbell and Mike Bradley for their extensive * investigation, experimentation, testing, and suggested solutions of diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 13689c5dd47f..ab14d35214aa 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -266,7 +266,7 @@ static int dsp_buffer_free(struct cx23885_audio_dev *chip) cx23885_alsa_dma_unmap(chip); cx23885_alsa_dma_free(chip->buf); risc = &chip->buf->risc; - pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma); + dma_free_coherent(&chip->pci->dev, risc->size, risc->cpu, risc->dma); kfree(chip->buf); chip->buf = NULL; diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 03eee606af91..0160f909f38c 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -657,14 +657,11 @@ struct cx23885_board cx23885_boards[] = { .porta = CX23885_ANALOG_VIDEO, .input = {{ .type = CX23885_VMUX_COMPOSITE1, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN4_CH2 | - CX25840_VIN6_CH1, + .vmux = CX25840_VIN6_CH1, .amux = CX25840_AUDIO7, }, { .type = CX23885_VMUX_SVIDEO, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN4_CH2 | + .vmux = CX25840_VIN4_CH2 | CX25840_VIN8_CH1 | CX25840_SVIDEO_ON, .amux = CX25840_AUDIO7, @@ -715,6 +712,16 @@ struct cx23885_board cx23885_boards[] = { CX25840_VIN2_CH1 | CX25840_DIF_ON, .amux = CX25840_AUDIO8, + }, { + .type = CX23885_VMUX_COMPOSITE1, + .vmux = CX25840_VIN6_CH1, + .amux = CX25840_AUDIO7, + }, { + .type = CX23885_VMUX_SVIDEO, + .vmux = CX25840_VIN7_CH3 | + CX25840_VIN8_CH1 | + CX25840_SVIDEO_ON, + .amux = CX25840_AUDIO7, } }, }, [CX23885_BOARD_VIEWCAST_260E] = { @@ -823,16 +830,9 @@ struct cx23885_board cx23885_boards[] = { CX25840_DIF_ON, .amux = CX25840_AUDIO8, }, { - .type = CX23885_VMUX_COMPOSITE1, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN4_CH2 | - CX25840_VIN6_CH1, - .amux = CX25840_AUDIO7, - }, { .type = CX23885_VMUX_SVIDEO, - .vmux = CX25840_VIN7_CH3 | - CX25840_VIN4_CH2 | - CX25840_VIN8_CH1 | + .vmux = CX25840_VIN4_CH2 | + CX25840_VIN6_CH1 | CX25840_SVIDEO_ON, .amux = CX25840_AUDIO7, } }, diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 22f55a7840a6..f8f2ff3b00c3 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -1218,7 +1218,8 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc, / PAGE_SIZE + lines); instructions += 5; risc->size = instructions * 12; - risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma, + GFP_KERNEL); if (risc->cpu == NULL) return -ENOMEM; @@ -1255,7 +1256,8 @@ int cx23885_risc_databuffer(struct pci_dev *pci, instructions += 4; risc->size = instructions * 12; - risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma, + GFP_KERNEL); if (risc->cpu == NULL) return -ENOMEM; @@ -1293,7 +1295,8 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc, / PAGE_SIZE + lines); instructions += 5; risc->size = instructions * 12; - risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + risc->cpu = dma_alloc_coherent(&pci->dev, risc->size, &risc->dma, + GFP_KERNEL); if (risc->cpu == NULL) return -ENOMEM; /* write risc instructions */ @@ -1322,7 +1325,7 @@ void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf) { struct cx23885_riscmem *risc = &buf->risc; - pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma); + dma_free_coherent(&dev->pci->dev, risc->size, risc->cpu, risc->dma); } static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) @@ -2077,6 +2080,15 @@ static struct { * 0x1423 is the PCI ID for the IOMMU found on Kaveri */ { PCI_VENDOR_ID_AMD, 0x1423 }, + /* 0x1481 is the PCI ID for the IOMMU found on Starship/Matisse + */ + { PCI_VENDOR_ID_AMD, 0x1481 }, + /* 0x1419 is the PCI ID for the IOMMU found on 15h (Models 10h-1fh) family + */ + { PCI_VENDOR_ID_AMD, 0x1419 }, + /* 0x5a23 is the PCI ID for the IOMMU found on RD890S/RD990 + */ + { PCI_VENDOR_ID_ATI, 0x5a23 }, }; static bool cx23885_does_need_dma_reset(void) @@ -2150,7 +2162,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev, (unsigned long long)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); - err = pci_set_dma_mask(pci_dev, 0xffffffff); + err = dma_set_mask(&pci_dev->dev, 0xffffffff); if (err) { pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); goto fail_ctrl; diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 8797d85a6b0a..438fdcec6eac 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -402,7 +402,7 @@ static int dsp_buffer_free(struct cx25821_audio_dev *chip) dprintk(2, "Freeing buffer\n"); cx25821_alsa_dma_unmap(chip); cx25821_alsa_dma_free(chip->buf); - pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma); + dma_free_coherent(&chip->pci->dev, risc->size, risc->cpu, risc->dma); kfree(chip->buf); chip->buf = NULL; diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 07b6d0c49bbf..40c10ca94def 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -977,11 +977,11 @@ int cx25821_riscmem_alloc(struct pci_dev *pci, dma_addr_t dma = 0; if (risc->cpu && risc->size < size) { - pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); + dma_free_coherent(&pci->dev, risc->size, risc->cpu, risc->dma); risc->cpu = NULL; } if (NULL == risc->cpu) { - cpu = pci_zalloc_consistent(pci, size, &dma); + cpu = dma_alloc_coherent(&pci->dev, size, &dma, GFP_KERNEL); if (NULL == cpu) return -ENOMEM; risc->cpu = cpu; @@ -1202,8 +1202,8 @@ void cx25821_free_buffer(struct cx25821_dev *dev, struct cx25821_buffer *buf) { if (WARN_ON(buf->risc.size == 0)) return; - pci_free_consistent(dev->pci, - buf->risc.size, buf->risc.cpu, buf->risc.dma); + dma_free_coherent(&dev->pci->dev, buf->risc.size, buf->risc.cpu, + buf->risc.dma); memset(&buf->risc, 0, sizeof(buf->risc)); } @@ -1302,7 +1302,7 @@ static int cx25821_initdev(struct pci_dev *pci_dev, dev->pci_lat, (unsigned long long)dev->base_io_addr); pci_set_master(pci_dev); - err = pci_set_dma_mask(pci_dev, 0xffffffff); + err = dma_set_mask(&pci_dev->dev, 0xffffffff); if (err) { pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); err = -EIO; diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h index 017307984094..3aa7604fb944 100644 --- a/drivers/media/pci/cx25821/cx25821.h +++ b/drivers/media/pci/cx25821/cx25821.h @@ -28,7 +28,6 @@ #include "cx25821-sram.h" #include "cx25821-audio.h" -#include <linux/version.h> #include <linux/mutex.h> #define UNSET (-1U) diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 8e224fc0474d..f01e48c23f8e 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -3206,7 +3206,7 @@ static int cx88_xc4000_tuner_callback(struct cx88_core *core, /* * Tuner callback function. Currently only needed for the Pinnacle - * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both + * PCTV HD 800i with an xc5000 silicon tuner. This is used for both * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ static int cx88_xc5000_tuner_callback(struct cx88_core *core, diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c index c2199042d3db..e8511787c1e4 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.c +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c @@ -79,8 +79,8 @@ static void cio2_bridge_create_fwnode_properties( { sensor->prop_names = prop_names; - sensor->local_ref[0].node = &sensor->swnodes[SWNODE_CIO2_ENDPOINT]; - sensor->remote_ref[0].node = &sensor->swnodes[SWNODE_SENSOR_ENDPOINT]; + sensor->local_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_CIO2_ENDPOINT]); + sensor->remote_ref[0] = SOFTWARE_NODE_REFERENCE(&sensor->swnodes[SWNODE_SENSOR_ENDPOINT]); sensor->dev_properties[0] = PROPERTY_ENTRY_U32( sensor->prop_names.clock_frequency, diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 6e8c0c230e11..fecef85bd62e 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -302,7 +302,7 @@ static int cio2_csi2_calc_timing(struct cio2_device *cio2, struct cio2_queue *q, if (!q->sensor) return -ENODEV; - freq = v4l2_get_link_freq(q->sensor->ctrl_handler, bpp, lanes); + freq = v4l2_get_link_freq(q->sensor->ctrl_handler, bpp, lanes * 2); if (freq < 0) { dev_err(dev, "error %lld, invalid link_freq\n", freq); return freq; diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index 942b8c266f50..8ebc97ebf1a2 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -1390,7 +1390,7 @@ int ivtv_init_on_first_open(struct ivtv *itv) static void ivtv_remove(struct pci_dev *pdev) { - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); struct ivtv *itv = to_ivtv(v4l2_dev); int i; diff --git a/drivers/media/pci/mantis/mantis_ca.c b/drivers/media/pci/mantis/mantis_ca.c index f2baf5e5c921..0fad0a923e35 100644 --- a/drivers/media/pci/mantis/mantis_ca.c +++ b/drivers/media/pci/mantis/mantis_ca.c @@ -109,7 +109,6 @@ static int mantis_ts_control(struct dvb_ca_en50221 *en50221, int slot) struct mantis_pci *mantis = ca->ca_priv; dprintk(MANTIS_DEBUG, 1, "Slot(%d): TS control", slot); -/* mantis_set_direction(mantis, 1); */ /* Enable TS through CAM */ return 0; } diff --git a/drivers/media/pci/mantis/mantis_core.c b/drivers/media/pci/mantis/mantis_core.c deleted file mode 100644 index f303f68d4ef2..000000000000 --- a/drivers/media/pci/mantis/mantis_core.c +++ /dev/null @@ -1,200 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - Mantis PCI bridge driver - - Copyright (C) Manu Abraham (abraham.manu@gmail.com) - -*/ - -#include "mantis_common.h" -#include "mantis_core.h" -#include "mantis_vp1033.h" -#include "mantis_vp1034.h" -#include "mantis_vp1041.h" -#include "mantis_vp2033.h" -#include "mantis_vp2040.h" -#include "mantis_vp3030.h" - -static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length) -{ - int err; - struct i2c_msg msg[] = { - { - .addr = 0x50, - .flags = 0, - .buf = data, - .len = 1 - }, { - .addr = 0x50, - .flags = I2C_M_RD, - .buf = data, - .len = length - }, - }; - - err = i2c_transfer(&mantis->adapter, msg, 2); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, - "ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >", - err, data[0], data[1]); - - return err; - } - - return 0; -} - -static int get_mac_address(struct mantis_pci *mantis) -{ - int err; - - mantis->mac_address[0] = 0x08; - err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error"); - - return err; - } - dprintk(verbose, MANTIS_ERROR, 0, - " MAC Address=[%pM]\n", mantis->mac_address); - - return 0; -} - -#define MANTIS_MODEL_UNKNOWN "UNKNOWN" -#define MANTIS_DEV_UNKNOWN "UNKNOWN" - -struct mantis_hwconfig unknown_device = { - .model_name = MANTIS_MODEL_UNKNOWN, - .dev_type = MANTIS_DEV_UNKNOWN, -}; - -static void mantis_load_config(struct mantis_pci *mantis) -{ - switch (mantis->subsystem_device) { - case MANTIS_VP_1033_DVB_S: /* VP-1033 */ - mantis->hwconfig = &vp1033_mantis_config; - break; - case MANTIS_VP_1034_DVB_S: /* VP-1034 */ - mantis->hwconfig = &vp1034_mantis_config; - break; - case MANTIS_VP_1041_DVB_S2: /* VP-1041 */ - case TECHNISAT_SKYSTAR_HD2: - mantis->hwconfig = &vp1041_mantis_config; - break; - case MANTIS_VP_2033_DVB_C: /* VP-2033 */ - mantis->hwconfig = &vp2033_mantis_config; - break; - case MANTIS_VP_2040_DVB_C: /* VP-2040 */ - case CINERGY_C: /* VP-2040 clone */ - case TECHNISAT_CABLESTAR_HD2: - mantis->hwconfig = &vp2040_mantis_config; - break; - case MANTIS_VP_3030_DVB_T: /* VP-3030 */ - mantis->hwconfig = &vp3030_mantis_config; - break; - default: - mantis->hwconfig = &unknown_device; - break; - } -} - -int mantis_core_init(struct mantis_pci *mantis) -{ - int err = 0; - - mantis_load_config(mantis); - dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n", - mantis->hwconfig->model_name, mantis->hwconfig->dev_type, - mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn)); - dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ", - mantis->revision, - mantis->subsystem_vendor, mantis->subsystem_device); - dprintk(verbose, MANTIS_ERROR, 0, - "irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n", - mantis->pdev->irq, mantis->latency, - mantis->mantis_addr, mantis->mantis_mmio); - - err = mantis_i2c_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed"); - return err; - } - err = get_mac_address(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed"); - return err; - } - err = mantis_dma_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed"); - return err; - } - err = mantis_dvb_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed"); - return err; - } - err = mantis_uart_init(mantis); - if (err < 0) { - dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed"); - return err; - } - - return 0; -} - -int mantis_core_exit(struct mantis_pci *mantis) -{ - mantis_dma_stop(mantis); - dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping"); - - mantis_uart_exit(mantis); - dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed"); - - if (mantis_dma_exit(mantis) < 0) - dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed"); - if (mantis_dvb_exit(mantis) < 0) - dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed"); - if (mantis_i2c_exit(mantis) < 0) - dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed"); - - return 0; -} - -/* Turn the given bit on or off. */ -void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value) -{ - u32 cur; - - cur = mmread(MANTIS_GPIF_ADDR); - if (value) - mantis->gpio_status = cur | (1 << bitpos); - else - mantis->gpio_status = cur & (~(1 << bitpos)); - - mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR); - mmwrite(0x00, MANTIS_GPIF_DOUT); - udelay(100); -} - -/* direction = 0 , no CI passthrough ; 1 , CI passthrough */ -void mantis_set_direction(struct mantis_pci *mantis, int direction) -{ - u32 reg; - - reg = mmread(0x28); - dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup"); - if (direction == 0x01) { - /* to CI */ - reg |= 0x04; - mmwrite(reg, 0x28); - reg &= 0xff - 0x04; - mmwrite(reg, 0x28); - } else { - reg &= 0xff - 0x04; - mmwrite(reg, 0x28); - reg |= 0x04; - mmwrite(reg, 0x28); - } -} diff --git a/drivers/media/pci/mantis/mantis_core.h b/drivers/media/pci/mantis/mantis_core.h index 1b0468ff791c..93c89a10a2c7 100644 --- a/drivers/media/pci/mantis/mantis_core.h +++ b/drivers/media/pci/mantis/mantis_core.h @@ -39,7 +39,5 @@ extern void mantis_dma_start(struct mantis_pci *mantis); extern void mantis_dma_stop(struct mantis_pci *mantis); extern int mantis_i2c_init(struct mantis_pci *mantis); extern int mantis_i2c_exit(struct mantis_pci *mantis); -extern int mantis_core_init(struct mantis_pci *mantis); -extern int mantis_core_exit(struct mantis_pci *mantis); #endif /* __MANTIS_CORE_H */ diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c index 4df571ff272b..80c843936493 100644 --- a/drivers/media/pci/mantis/mantis_dma.c +++ b/drivers/media/pci/mantis/mantis_dma.c @@ -52,8 +52,8 @@ int mantis_dma_exit(struct mantis_pci *mantis) mantis->buf_cpu, MANTIS_BUF_SIZE); - pci_free_consistent(mantis->pdev, MANTIS_BUF_SIZE, - mantis->buf_cpu, mantis->buf_dma); + dma_free_coherent(&mantis->pdev->dev, MANTIS_BUF_SIZE, + mantis->buf_cpu, mantis->buf_dma); mantis->buf_cpu = NULL; } @@ -64,8 +64,8 @@ int mantis_dma_exit(struct mantis_pci *mantis) mantis->risc_cpu, MANTIS_RISC_SIZE); - pci_free_consistent(mantis->pdev, MANTIS_RISC_SIZE, - mantis->risc_cpu, mantis->risc_dma); + dma_free_coherent(&mantis->pdev->dev, MANTIS_RISC_SIZE, + mantis->risc_cpu, mantis->risc_dma); mantis->risc_cpu = NULL; } @@ -77,9 +77,9 @@ EXPORT_SYMBOL_GPL(mantis_dma_exit); static inline int mantis_alloc_buffers(struct mantis_pci *mantis) { if (!mantis->buf_cpu) { - mantis->buf_cpu = pci_alloc_consistent(mantis->pdev, - MANTIS_BUF_SIZE, - &mantis->buf_dma); + mantis->buf_cpu = dma_alloc_coherent(&mantis->pdev->dev, + MANTIS_BUF_SIZE, + &mantis->buf_dma, GFP_KERNEL); if (!mantis->buf_cpu) { dprintk(MANTIS_ERROR, 1, "DMA buffer allocation failed"); @@ -92,9 +92,9 @@ static inline int mantis_alloc_buffers(struct mantis_pci *mantis) mantis->buf_cpu, MANTIS_BUF_SIZE); } if (!mantis->risc_cpu) { - mantis->risc_cpu = pci_alloc_consistent(mantis->pdev, - MANTIS_RISC_SIZE, - &mantis->risc_dma); + mantis->risc_cpu = dma_alloc_coherent(&mantis->pdev->dev, + MANTIS_RISC_SIZE, + &mantis->risc_dma, GFP_KERNEL); if (!mantis->risc_cpu) { dprintk(MANTIS_ERROR, 1, diff --git a/drivers/media/pci/mantis/mantis_pci.c b/drivers/media/pci/mantis/mantis_pci.c index 3bfb3e99c93a..9fbce74b00c8 100644 --- a/drivers/media/pci/mantis/mantis_pci.c +++ b/drivers/media/pci/mantis/mantis_pci.c @@ -55,7 +55,7 @@ int mantis_pci_init(struct mantis_pci *mantis) goto fail0; } - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + err = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (err != 0) { dprintk(MANTIS_ERROR, 1, "ERROR: Unable to obtain 32 bit DMA <%i>", err); ret = -ENOMEM; diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 8bfb3d8ea610..7dbc21e1a2ca 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -934,15 +934,11 @@ static int eeprom_read_ushort(struct i2c_adapter *adapter, u16 tag, u16 *data) static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data) { - int stat; u8 buf[2]; buf[0] = data >> 8; buf[1] = data & 0xff; - stat = WriteEEProm(adapter, tag, 2, buf); - if (stat) - return stat; - return 0; + return WriteEEProm(adapter, tag, 2, buf); } static s16 osc_deviation(void *priv, s16 deviation, int flag) diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index f9f94f47d76b..07f342db6701 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -763,23 +763,22 @@ static void free_ringbuffer(struct ngene *dev, struct SRingBufferDescriptor *rb) for (j = 0; j < rb->NumBuffers; j++, Cur = Cur->Next) { if (Cur->Buffer1) - pci_free_consistent(dev->pci_dev, - rb->Buffer1Length, - Cur->Buffer1, - Cur->scList1->Address); + dma_free_coherent(&dev->pci_dev->dev, + rb->Buffer1Length, Cur->Buffer1, + Cur->scList1->Address); if (Cur->Buffer2) - pci_free_consistent(dev->pci_dev, - rb->Buffer2Length, - Cur->Buffer2, - Cur->scList2->Address); + dma_free_coherent(&dev->pci_dev->dev, + rb->Buffer2Length, Cur->Buffer2, + Cur->scList2->Address); } if (rb->SCListMem) - pci_free_consistent(dev->pci_dev, rb->SCListMemSize, - rb->SCListMem, rb->PASCListMem); + dma_free_coherent(&dev->pci_dev->dev, rb->SCListMemSize, + rb->SCListMem, rb->PASCListMem); - pci_free_consistent(dev->pci_dev, rb->MemSize, rb->Head, rb->PAHead); + dma_free_coherent(&dev->pci_dev->dev, rb->MemSize, rb->Head, + rb->PAHead); } static void free_idlebuffer(struct ngene *dev, @@ -813,15 +812,13 @@ static void free_common_buffers(struct ngene *dev) } if (dev->OverflowBuffer) - pci_free_consistent(dev->pci_dev, - OVERFLOW_BUFFER_SIZE, - dev->OverflowBuffer, dev->PAOverflowBuffer); + dma_free_coherent(&dev->pci_dev->dev, OVERFLOW_BUFFER_SIZE, + dev->OverflowBuffer, dev->PAOverflowBuffer); if (dev->FWInterfaceBuffer) - pci_free_consistent(dev->pci_dev, - 4096, - dev->FWInterfaceBuffer, - dev->PAFWInterfaceBuffer); + dma_free_coherent(&dev->pci_dev->dev, 4096, + dev->FWInterfaceBuffer, + dev->PAFWInterfaceBuffer); } /****************************************************************************/ @@ -848,7 +845,7 @@ static int create_ring_buffer(struct pci_dev *pci_dev, if (MemSize < 4096) MemSize = 4096; - Head = pci_alloc_consistent(pci_dev, MemSize, &tmp); + Head = dma_alloc_coherent(&pci_dev->dev, MemSize, &tmp, GFP_KERNEL); PARingBufferHead = tmp; if (!Head) @@ -899,7 +896,8 @@ static int AllocateRingBuffers(struct pci_dev *pci_dev, if (SCListMemSize < 4096) SCListMemSize = 4096; - SCListMem = pci_alloc_consistent(pci_dev, SCListMemSize, &tmp); + SCListMem = dma_alloc_coherent(&pci_dev->dev, SCListMemSize, &tmp, + GFP_KERNEL); PASCListMem = tmp; if (SCListMem == NULL) @@ -918,8 +916,8 @@ static int AllocateRingBuffers(struct pci_dev *pci_dev, for (i = 0; i < pRingBuffer->NumBuffers; i += 1, Cur = Cur->Next) { u64 PABuffer; - void *Buffer = pci_alloc_consistent(pci_dev, Buffer1Length, - &tmp); + void *Buffer = dma_alloc_coherent(&pci_dev->dev, + Buffer1Length, &tmp, GFP_KERNEL); PABuffer = tmp; if (Buffer == NULL) @@ -951,7 +949,8 @@ static int AllocateRingBuffers(struct pci_dev *pci_dev, if (!Buffer2Length) continue; - Buffer = pci_alloc_consistent(pci_dev, Buffer2Length, &tmp); + Buffer = dma_alloc_coherent(&pci_dev->dev, Buffer2Length, + &tmp, GFP_KERNEL); PABuffer = tmp; if (Buffer == NULL) @@ -1040,17 +1039,18 @@ static int AllocCommonBuffers(struct ngene *dev) { int status = 0, i; - dev->FWInterfaceBuffer = pci_alloc_consistent(dev->pci_dev, 4096, - &dev->PAFWInterfaceBuffer); + dev->FWInterfaceBuffer = dma_alloc_coherent(&dev->pci_dev->dev, 4096, + &dev->PAFWInterfaceBuffer, + GFP_KERNEL); if (!dev->FWInterfaceBuffer) return -ENOMEM; dev->hosttongene = dev->FWInterfaceBuffer; dev->ngenetohost = dev->FWInterfaceBuffer + 256; dev->EventBuffer = dev->FWInterfaceBuffer + 512; - dev->OverflowBuffer = pci_zalloc_consistent(dev->pci_dev, - OVERFLOW_BUFFER_SIZE, - &dev->PAOverflowBuffer); + dev->OverflowBuffer = dma_alloc_coherent(&dev->pci_dev->dev, + OVERFLOW_BUFFER_SIZE, + &dev->PAOverflowBuffer, GFP_KERNEL); if (!dev->OverflowBuffer) return -ENOMEM; diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index 72b191cfeb54..f2aa36814fba 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -334,8 +334,7 @@ static int pt1_sync(struct pt1 *pt1) static u64 pt1_identify(struct pt1 *pt1) { int i; - u64 id; - id = 0; + u64 id = 0; for (i = 0; i < 57; i++) { id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i; pt1_write_reg(pt1, 0, 0x00000008); @@ -1122,8 +1121,7 @@ static int pt1_i2c_end(struct pt1 *pt1, int addr) static void pt1_i2c_begin(struct pt1 *pt1, int *addrp) { - int addr; - addr = 0; + int addr = 0; pt1_i2c_emit(pt1, addr, 0, 0, 1, 1, addr /* itself */); addr = addr + 1; diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 391572a6ec76..efb757d5168a 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -243,7 +243,7 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, ptr = pt->cpu + startpage; for (i = 0; i < length; i++, list = sg_next(list)) { - for (p = 0; p * 4096 < list->length; p++, ptr++) + for (p = 0; p * 4096 < sg_dma_len(list); p++, ptr++) *ptr = cpu_to_le32(sg_dma_address(list) + list->offset + p * 4096); } diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 11e1eb6a6809..1d1d32e043f1 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -1008,7 +1008,7 @@ int saa7164_encoder_register(struct saa7164_port *port) printk(KERN_ERR "%s() failed (errno = %d), NO PCI configuration\n", __func__, result); result = -ENOMEM; - goto failed; + goto fail_pci; } /* Establish encoder defaults here */ @@ -1062,7 +1062,7 @@ int saa7164_encoder_register(struct saa7164_port *port) 100000, ENCODER_DEF_BITRATE); if (hdl->error) { result = hdl->error; - goto failed; + goto fail_hdl; } port->std = V4L2_STD_NTSC_M; @@ -1080,7 +1080,7 @@ int saa7164_encoder_register(struct saa7164_port *port) printk(KERN_INFO "%s: can't allocate mpeg device\n", dev->name); result = -ENOMEM; - goto failed; + goto fail_hdl; } port->v4l_device->ctrl_handler = hdl; @@ -1091,10 +1091,7 @@ int saa7164_encoder_register(struct saa7164_port *port) if (result < 0) { printk(KERN_INFO "%s: can't register mpeg device\n", dev->name); - /* TODO: We're going to leak here if we don't dealloc - The buffers above. The unreg function can't deal wit it. - */ - goto failed; + goto fail_reg; } printk(KERN_INFO "%s: registered device video%d [mpeg]\n", @@ -1116,9 +1113,14 @@ int saa7164_encoder_register(struct saa7164_port *port) saa7164_api_set_encoder(port); saa7164_api_get_encoder(port); + return 0; - result = 0; -failed: +fail_reg: + video_device_release(port->v4l_device); + port->v4l_device = NULL; +fail_hdl: + v4l2_ctrl_handler_free(hdl); +fail_pci: return result; } diff --git a/drivers/media/pci/saa7164/saa7164-types.h b/drivers/media/pci/saa7164/saa7164-types.h index 34dd2be6fce4..00f163b38d40 100644 --- a/drivers/media/pci/saa7164/saa7164-types.h +++ b/drivers/media/pci/saa7164/saa7164-types.h @@ -7,7 +7,7 @@ /* TODO: Cleanup and shorten the namespace */ -/* Some structues are passed directly to/from the firmware and +/* Some structures are passed directly to/from the firmware and * have strict alignment requirements. This is one of them. */ struct tmComResHWDescr { @@ -28,7 +28,7 @@ struct tmComResHWDescr { /* This is DWORD aligned on windows but I can't find the right * gcc syntax to match the binary data from the device. * I've manually padded with Reserved[3] bytes to match the hardware, - * but this could break if GCC decies to pack in a different way. + * but this could break if GCC decides to pack in a different way. */ struct tmComResInterfaceDescr { u8 bLength; diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index d497afc7e7b7..4a546eeefe38 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -368,7 +368,7 @@ static ssize_t sdram_show(struct file *file, struct kobject *kobj, struct bin_attribute *a, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct solo_dev *solo_dev = container_of(dev, struct solo_dev, dev); const int size = solo_dev->sdram_size; diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index 4dd98f94a91e..27bb78513631 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -3,6 +3,7 @@ config STA2X11_VIP tristate "STA2X11 VIP Video For Linux" depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS && I2C depends on STA2X11 || COMPILE_TEST + select GPIOLIB if MEDIA_SUBDRV_AUTOSELECT select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT select VIDEOBUF2_DMA_CONTIG select MEDIA_CONTROLLER diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.h b/drivers/media/pci/sta2x11/sta2x11_vip.h index a8cf140a050b..de6000e7943e 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.h +++ b/drivers/media/pci/sta2x11/sta2x11_vip.h @@ -14,6 +14,8 @@ * @pwr_pin: ADV powerdown pin * @reset_name: ADV reset name * @reset_pin: ADV reset pin + * @i2c_id: ADV i2c adapter ID + * @i2c_addr: ADV i2c address */ struct vip_config { const char *pwr_name; diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index bf15fa7c0ea1..35dd19b2427e 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -248,7 +248,7 @@ static int tw68_initdev(struct pci_dev *pci_dev, dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, (u64)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); - err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (err) { pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name); goto fail1; diff --git a/drivers/media/pci/tw68/tw68-risc.c b/drivers/media/pci/tw68/tw68-risc.c index eef0c5281f61..dacb136c4f3a 100644 --- a/drivers/media/pci/tw68/tw68-risc.c +++ b/drivers/media/pci/tw68/tw68-risc.c @@ -151,7 +151,8 @@ int tw68_risc_buffer(struct pci_dev *pci, instructions = fields * (1 + (((bpl + padding) * lines) / PAGE_SIZE) + lines) + 4; buf->size = instructions * 8; - buf->cpu = pci_alloc_consistent(pci, buf->size, &buf->dma); + buf->cpu = dma_alloc_coherent(&pci->dev, buf->size, &buf->dma, + GFP_KERNEL); if (buf->cpu == NULL) return -ENOMEM; diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 10986fcd66a5..fe94944d0531 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -485,7 +485,7 @@ static void tw68_buf_finish(struct vb2_buffer *vb) struct tw68_dev *dev = vb2_get_drv_priv(vq); struct tw68_buf *buf = container_of(vbuf, struct tw68_buf, vb); - pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma); + dma_free_coherent(&dev->pci->dev, buf->size, buf->cpu, buf->dma); } static int tw68_start_streaming(struct vb2_queue *q, unsigned int count) diff --git a/drivers/media/pci/tw686x/tw686x-audio.c b/drivers/media/pci/tw686x/tw686x-audio.c index 54144e23a487..74cba1368cfa 100644 --- a/drivers/media/pci/tw686x/tw686x-audio.c +++ b/drivers/media/pci/tw686x/tw686x-audio.c @@ -300,9 +300,9 @@ static void tw686x_audio_dma_free(struct tw686x_dev *dev, for (pb = 0; pb < 2; pb++) { if (!ac->dma_descs[pb].virt) continue; - pci_free_consistent(dev->pci_dev, ac->dma_descs[pb].size, - ac->dma_descs[pb].virt, - ac->dma_descs[pb].phys); + dma_free_coherent(&dev->pci_dev->dev, ac->dma_descs[pb].size, + ac->dma_descs[pb].virt, + ac->dma_descs[pb].phys); ac->dma_descs[pb].virt = NULL; } } @@ -313,7 +313,7 @@ static int tw686x_audio_dma_alloc(struct tw686x_dev *dev, int pb; /* - * In the memcpy DMA mode we allocate a consistent buffer + * In the memcpy DMA mode we allocate a coherent buffer * and use it for the DMA capture. Otherwise, DMA * acts on the ALSA buffers as received in pcm_prepare. */ @@ -324,8 +324,9 @@ static int tw686x_audio_dma_alloc(struct tw686x_dev *dev, u32 reg = pb ? ADMA_B_ADDR[ac->ch] : ADMA_P_ADDR[ac->ch]; void *virt; - virt = pci_alloc_consistent(dev->pci_dev, AUDIO_DMA_SIZE_MAX, - &ac->dma_descs[pb].phys); + virt = dma_alloc_coherent(&dev->pci_dev->dev, + AUDIO_DMA_SIZE_MAX, + &ac->dma_descs[pb].phys, GFP_KERNEL); if (!virt) { dev_err(&dev->pci_dev->dev, "dma%d: unable to allocate audio DMA %s-buffer\n", diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c index 74ae4f0dcee7..6676e069b515 100644 --- a/drivers/media/pci/tw686x/tw686x-core.c +++ b/drivers/media/pci/tw686x/tw686x-core.c @@ -276,7 +276,7 @@ static int tw686x_probe(struct pci_dev *pci_dev, } pci_set_master(pci_dev); - err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (err) { dev_err(&pci_dev->dev, "32-bit PCI DMA not supported\n"); err = -EIO; diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index 1ced2b0ddb24..b227e9e78ebd 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -92,8 +92,8 @@ static void tw686x_memcpy_dma_free(struct tw686x_video_channel *vc, } if (desc->virt) { - pci_free_consistent(dev->pci_dev, desc->size, - desc->virt, desc->phys); + dma_free_coherent(&dev->pci_dev->dev, desc->size, desc->virt, + desc->phys); desc->virt = NULL; } } @@ -110,8 +110,8 @@ static int tw686x_memcpy_dma_alloc(struct tw686x_video_channel *vc, "Allocating buffer but previous still here\n"); len = (vc->width * vc->height * vc->format->depth) >> 3; - virt = pci_alloc_consistent(dev->pci_dev, len, - &vc->dma_descs[pb].phys); + virt = dma_alloc_coherent(&dev->pci_dev->dev, len, + &vc->dma_descs[pb].phys, GFP_KERNEL); if (!virt) { v4l2_err(&dev->v4l2_dev, "dma%d: unable to allocate %s-buffer\n", @@ -258,8 +258,8 @@ static void tw686x_sg_dma_free(struct tw686x_video_channel *vc, struct tw686x_dev *dev = vc->dev; if (desc->size) { - pci_free_consistent(dev->pci_dev, desc->size, - desc->virt, desc->phys); + dma_free_coherent(&dev->pci_dev->dev, desc->size, desc->virt, + desc->phys); desc->virt = NULL; } @@ -276,9 +276,8 @@ static int tw686x_sg_dma_alloc(struct tw686x_video_channel *vc, void *virt; if (desc->size) { - - virt = pci_alloc_consistent(dev->pci_dev, desc->size, - &desc->phys); + virt = dma_alloc_coherent(&dev->pci_dev->dev, desc->size, + &desc->phys, GFP_KERNEL); if (!virt) { v4l2_err(&dev->v4l2_dev, "dma%d: unable to allocate %s-buffer\n", diff --git a/drivers/media/pci/tw686x/tw686x.h b/drivers/media/pci/tw686x/tw686x.h index 48dd1e03d806..21a98995065c 100644 --- a/drivers/media/pci/tw686x/tw686x.h +++ b/drivers/media/pci/tw686x/tw686x.h @@ -111,12 +111,12 @@ struct tw686x_dma_ops { u32 hw_dma_mode; }; -/** - * struct tw686x_dev - global device status - * @lock: spinlock controlling access to the - * shared device registers (DMA enable/disable). - */ +/* struct tw686x_dev - global device status */ struct tw686x_dev { + /* + * spinlock controlling access to the shared device registers + * (DMA enable/disable) + */ spinlock_t lock; struct v4l2_device v4l2_dev; diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index fd1831e97b22..157c924686e4 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -186,6 +186,20 @@ config VIDEO_TI_CAL In TI Technical Reference Manual this module is referred as Camera Interface Subsystem (CAMSS). +if VIDEO_TI_CAL + +config VIDEO_TI_CAL_MC + bool "Media Controller centric mode by default" + default n + help + Enables Media Controller centric mode by default. + + If set, CAL driver will start in Media Controller mode by + default. Note that this behavior can be overridden via + module parameter 'mc_api'. + +endif # VIDEO_TI_CAL + endif # V4L_PLATFORM_DRIVERS menuconfig V4L_MEM2MEM_DRIVERS @@ -239,11 +253,14 @@ config VIDEO_IMX_PXP The i.MX Pixel Pipeline is a memory-to-memory engine for scaling, color space conversion, and rotation. +source "drivers/media/platform/imx-jpeg/Kconfig" + config VIDEO_MEDIATEK_JPEG tristate "Mediatek JPEG Codec driver" depends on MTK_IOMMU_V1 || MTK_IOMMU || COMPILE_TEST depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_MEDIATEK || COMPILE_TEST + depends on MTK_SMI || (COMPILE_TEST && MTK_SMI=n) select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -271,6 +288,7 @@ config VIDEO_MEDIATEK_MDP depends on MTK_IOMMU || COMPILE_TEST depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_MEDIATEK || COMPILE_TEST + depends on MTK_SMI || (COMPILE_TEST && MTK_SMI=n) select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU @@ -291,6 +309,7 @@ config VIDEO_MEDIATEK_VCODEC # our dependencies, to avoid missing symbols during link. depends on VIDEO_MEDIATEK_VPU || !VIDEO_MEDIATEK_VPU depends on MTK_SCP || !MTK_SCP + depends on MTK_SMI || (COMPILE_TEST && MTK_SMI=n) select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU @@ -543,7 +562,7 @@ config VIDEO_TI_VPE_DEBUG config VIDEO_QCOM_VENUS tristate "Qualcomm Venus V4L2 encoder/decoder driver" - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV && VIDEO_V4L2 && QCOM_SMEM depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST select QCOM_MDT_LOADER if ARCH_QCOM select QCOM_SCM if ARCH_QCOM diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 9d4d6370908d..eedc14aafb32 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o obj-$(CONFIG_VIDEO_CODA) += coda/ obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o +obj-$(CONFIG_VIDEO_IMX8_JPEG) += imx-jpeg/ obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o diff --git a/drivers/media/platform/allegro-dvt/nal-h264.h b/drivers/media/platform/allegro-dvt/nal-h264.h index 2ba7cbced7a5..a19634fe8c0b 100644 --- a/drivers/media/platform/allegro-dvt/nal-h264.h +++ b/drivers/media/platform/allegro-dvt/nal-h264.h @@ -11,8 +11,8 @@ #include <linux/kernel.h> #include <linux/types.h> -/** - * struct nal_h264_hdr_parameters - HDR parameters +/* + * struct nal_h264_hrd_parameters - HRD parameters * * C struct representation of the sequence parameter set NAL unit as defined by * Rec. ITU-T H.264 (04/2017) E.1.2 HRD parameters syntax. @@ -32,7 +32,7 @@ struct nal_h264_hrd_parameters { unsigned int time_offset_length; }; -/** +/* * struct nal_h264_vui_parameters - VUI parameters * * C struct representation of the VUI parameters as defined by Rec. ITU-T @@ -87,7 +87,7 @@ struct nal_h264_vui_parameters { }; }; -/** +/* * struct nal_h264_sps - Sequence parameter set * * C struct representation of the sequence parameter set NAL unit as defined by @@ -142,7 +142,7 @@ struct nal_h264_sps { struct nal_h264_vui_parameters vui; }; -/** +/* * struct nal_h264_pps - Picture parameter set * * C struct representation of the picture parameter set NAL unit as defined by diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.h b/drivers/media/platform/allegro-dvt/nal-hevc.h index fc994d4242d8..c09bbe5446aa 100644 --- a/drivers/media/platform/allegro-dvt/nal-hevc.h +++ b/drivers/media/platform/allegro-dvt/nal-hevc.h @@ -54,7 +54,7 @@ struct nal_hevc_profile_tier_level { unsigned int general_level_idc; }; -/** +/* * struct nal_hevc_vps - Video parameter set * * C struct representation of the video parameter set NAL unit as defined by @@ -129,7 +129,7 @@ struct nal_hevc_hrd_parameters { }; }; -/** +/* * struct nal_hevc_vui_parameters - VUI parameters * * C struct representation of the VUI parameters as defined by Rec. ITU-T @@ -192,7 +192,7 @@ struct nal_hevc_vui_parameters { }; }; -/** +/* * struct nal_hevc_sps - Sequence parameter set * * C struct representation of the video parameter set NAL unit as defined by diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index f2c4dadd6a0e..7bb6babdcade 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -514,8 +514,8 @@ static void aspeed_video_off(struct aspeed_video *video) aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); /* Turn off the relevant clocks */ - clk_disable(video->vclk); clk_disable(video->eclk); + clk_disable(video->vclk); clear_bit(VIDEO_CLOCKS_ON, &video->flags); } @@ -526,8 +526,8 @@ static void aspeed_video_on(struct aspeed_video *video) return; /* Turn on the relevant clocks */ - clk_enable(video->eclk); clk_enable(video->vclk); + clk_enable(video->eclk); set_bit(VIDEO_CLOCKS_ON, &video->flags); } @@ -1719,8 +1719,11 @@ static int aspeed_video_probe(struct platform_device *pdev) return rc; rc = aspeed_video_setup_video(video); - if (rc) + if (rc) { + clk_unprepare(video->vclk); + clk_unprepare(video->eclk); return rc; + } return 0; } diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 995e95272e51..bd666c858fa1 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -2062,7 +2062,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG) ctx->params.gop_size = 1; ctx->gopcounter = ctx->params.gop_size - 1; - v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, 0); + /* Only decoders have this control */ + if (ctx->mb_err_cnt_ctrl) + v4l2_ctrl_s_ctrl(ctx->mb_err_cnt_ctrl, 0); ret = ctx->ops->start_streaming(ctx); if (ctx->inst_type == CODA_INST_DECODER) { @@ -3317,7 +3319,7 @@ static struct platform_driver coda_driver = { .remove = coda_remove, .driver = { .name = CODA_NAME, - .of_match_table = of_match_ptr(coda_dt_ids), + .of_match_table = coda_dt_ids, .pm = &coda_pm_ops, }, }; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index 8e5a9acb78aa..e894e85e84a4 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -64,14 +64,11 @@ enum gsc_irq { * enum gsc_datapath - the path of data used for G-Scaler * @GSC_CAMERA: from camera * @GSC_DMA: from/to DMA - * @GSC_LOCAL: to local path * @GSC_WRITEBACK: from FIMD */ enum gsc_datapath { GSC_CAMERA = 0x1, GSC_DMA, - GSC_MIXER, - GSC_FIMD, GSC_WRITEBACK, }; @@ -104,10 +101,11 @@ enum gsc_yuv_fmt { * struct gsc_fmt - the driver's internal color format data * @mbus_code: Media Bus pixel code, -1 if not applicable * @pixelformat: the fourcc code for this format, 0 if not applicable + * @color: color encoding * @yorder: Y/C order * @corder: Chrominance order control * @num_planes: number of physically non-contiguous data planes - * @nr_comp: number of physically contiguous data planes + * @num_comp: number of physically contiguous data planes * @depth: per plane driver's private 'number of bits per pixel' * @flags: flags indicating which operation mode format applies to */ @@ -280,7 +278,7 @@ struct gsc_pix_align { u16 target_h; }; -/** +/* * struct gsc_variant - G-Scaler variant information */ struct gsc_variant { @@ -301,6 +299,9 @@ struct gsc_variant { * * @variant: the variant information for this driver. * @num_entities: the number of g-scalers + * @clk_names: clock names + * @num_clocks: the number of clocks in @clk_names + * @num_entities: the number of g-scalers */ struct gsc_driverdata { struct gsc_variant *variant[GSC_MAX_DEVS]; @@ -316,12 +317,14 @@ struct gsc_driverdata { * @pdev: pointer to the G-Scaler platform device * @variant: the IP variant information * @id: G-Scaler device index (0..GSC_MAX_DEVS) + * @num_clocks: number of clocks required for G-Scaler operation * @clock: clocks required for G-Scaler operation * @regs: the mapped hardware registers * @irq_queue: interrupt handler waitqueue * @m2m: memory-to-memory V4L2 device information * @state: flags used to synchronize m2m and capture mode operation * @vdev: video device for G-Scaler instance + * @v4l2_dev: v4l2_device for G-Scaler instance */ struct gsc_dev { spinlock_t slock; @@ -340,7 +343,7 @@ struct gsc_dev { }; /** - * gsc_ctx - the device context data + * struct gsc_ctx - the device context data * @s_frame: source frame properties * @d_frame: destination frame properties * @in_path: input mode (DMA or camera) @@ -348,12 +351,16 @@ struct gsc_dev { * @scaler: image scaler properties * @flags: additional flags for image conversion * @state: flags to keep track of user configuration + * @rotation: rotation + * @hflip: horizontal flip + * @vflip: vertical flip * @gsc_dev: the G-Scaler device this context applies to * @m2m_ctx: memory-to-memory device context * @fh: v4l2 file handle * @ctrl_handler: v4l2 controls handler - * @gsc_ctrls G-Scaler control set + * @gsc_ctrls: G-Scaler control set * @ctrls_rdy: true if the control handler is initialized + * @out_colorspace: the colorspace of the OUTPUT queue */ struct gsc_ctx { struct gsc_frame s_frame; diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h index 58b72a052cef..7a058f3e6298 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.h +++ b/drivers/media/platform/exynos4-is/fimc-core.h @@ -242,6 +242,7 @@ struct fimc_vid_buffer { * @addr: image frame buffer DMA addresses * @dma_offset: DMA offset in bytes * @fmt: fimc color format pointer + * @alpha: alpha value */ struct fimc_frame { u32 f_width; @@ -296,6 +297,7 @@ struct fimc_m2m_device { * @buf_index: index for managing the output DMA buffers * @frame_count: the frame counter for statistics * @reqbufs_count: the number of buffers requested in REQBUFS ioctl + * @streaming: is streaming in progress? * @input: capture input type, grp_id of the attached subdev * @user_subdev_api: true if subdevs are not configured by the host driver */ @@ -400,6 +402,7 @@ struct fimc_ctx; * @pdata: pointer to the device platform data * @sysreg: pointer to the SYSREG regmap * @variant: the IP variant information + * @drv_data: driver data * @id: FIMC device index (0..FIMC_MAX_DEVS) * @clock: clocks required for FIMC operation * @regs: the mapped hardware registers @@ -408,7 +411,6 @@ struct fimc_ctx; * @m2m: memory-to-memory V4L2 device information * @vid_cap: camera capture device information * @state: flags used to synchronize m2m and capture mode operation - * @pipeline: fimc video capture pipeline data structure */ struct fimc_dev { spinlock_t slock; @@ -453,12 +455,12 @@ struct fimc_ctrls { }; /** - * fimc_ctx - the device context data + * struct fimc_ctx - the device context data * @s_frame: source frame properties * @d_frame: destination frame properties * @out_order_1p: output 1-plane YCBCR order * @out_order_2p: output 2-plane YCBCR order - * @in_order_1p input 1-plane YCBCR order + * @in_order_1p: input 1-plane YCBCR order * @in_order_2p: input 2-plane YCBCR order * @in_path: input mode (DMA or camera) * @out_path: output mode (DMA or FIFO) @@ -666,6 +668,7 @@ int fimc_capture_resume(struct fimc_dev *fimc); /** * fimc_active_queue_add - add buffer to the capture active buffers queue + * @vid_cap: camera capture device information * @buf: buffer to add to the active buffers list */ static inline void fimc_active_queue_add(struct fimc_vid_cap *vid_cap, @@ -677,6 +680,7 @@ static inline void fimc_active_queue_add(struct fimc_vid_cap *vid_cap, /** * fimc_active_queue_pop - pop buffer from the capture active buffers queue + * @vid_cap: camera capture device information * * The caller must assure the active_buf_q list is not empty. */ @@ -693,6 +697,7 @@ static inline struct fimc_vid_buffer *fimc_active_queue_pop( /** * fimc_pending_queue_add - add buffer to the capture pending buffers queue + * @vid_cap: camera capture device information * @buf: buffer to add to the pending buffers list */ static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap, @@ -703,6 +708,7 @@ static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap, /** * fimc_pending_queue_pop - pop buffer from the capture pending buffers queue + * @vid_cap: camera capture device information * * The caller must assure the pending_buf_q list is not empty. */ diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h index ce30b007bc55..06586e455b1d 100644 --- a/drivers/media/platform/exynos4-is/fimc-is.h +++ b/drivers/media/platform/exynos4-is/fimc-is.h @@ -232,15 +232,33 @@ struct chain_config { * struct fimc_is - fimc-is data structure * @pdev: pointer to FIMC-IS platform device * @pctrl: pointer to pinctrl structure for this device - * @v4l2_dev: pointer to top the level v4l2_device + * @v4l2_dev: pointer to the top level v4l2_device + * @fw: data structure describing the FIMC-IS firmware binary + * @memory: memory region assigned for the FIMC-IS (firmware) + * @isp: the ISP block data structure + * @sensor: fimc-is sensor subdevice array + * @setfile: descriptor of the imaging pipeline calibration data + * @ctrl_handler: the v4l2 controls handler * @lock: mutex serializing video device and the subdev operations * @slock: spinlock protecting this data structure and the hw registers * @clocks: FIMC-LITE gate clock * @regs: MCUCTL mmapped registers region * @pmu_regs: PMU ISP mmapped registers region + * @irq: FIMC-IS interrupt * @irq_queue: interrupt handling waitqueue * @lpm: low power mode flag * @state: internal driver's state flags + * @sensor_index: image sensor index for the firmware + * @i2h_cmd: FIMC-IS to the host (CPU) mailbox command data structure + * @h2i_cmd: the host (CPU) to FIMC-IS mailbox command data structure + * @fd_header: the face detection result data structure + * @config: shared HW pipeline configuration data + * @config_index: index to the @config entry currently in use + * @is_p_region: pointer to the shared parameter memory region + * @is_dma_p_region: DMA address of the shared parameter memory region + * @is_shared_region: pointer to the IS shared region data structure + * @af: auto focus data + * @debugfs_entry: debugfs entry for the firmware log */ struct fimc_is { struct platform_device *pdev; @@ -249,7 +267,6 @@ struct fimc_is { struct fimc_is_firmware fw; struct fimc_is_memory memory; - struct firmware *f_w; struct fimc_isp isp; struct fimc_is_sensor sensor[FIMC_IS_SENSORS_NUM]; diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h index 161fa01a8781..12017cd924d9 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp.h +++ b/drivers/media/platform/exynos4-is/fimc-isp.h @@ -110,16 +110,20 @@ struct isp_video_buf { /** * struct fimc_is_video - fimc-is video device structure - * @vdev: video_device structure + * @ve: video_device structure and media pipeline * @type: video device type (CAPTURE/OUTPUT) * @pad: video device media (sink) pad * @pending_buf_q: pending buffers queue head * @active_buf_q: a queue head of buffers scheduled in hardware * @vb_queue: vb2 buffer queue - * @active_buf_count: number of video buffers scheduled in hardware + * @reqbufs_count: the number of buffers requested in REQBUFS ioctl + * @buf_count: number of video buffers scheduled in hardware + * @buf_mask: bitmask of the queued video buffer indices * @frame_count: counter of frames dequeued to user space - * @reqbufs_count: number of buffers requested with REQBUFS ioctl - * @format: current pixel format + * @streaming: is streaming in progress? + * @buffers: buffer info + * @format: current fimc pixel format + * @pixfmt: current pixel format */ struct fimc_is_video { struct exynos_video_entity ve; @@ -147,9 +151,12 @@ struct fimc_is_video { * @pdev: pointer to FIMC-IS platform device * @subdev: ISP v4l2_subdev * @subdev_pads: the ISP subdev media pads + * @src_fmt: source mediabus format + * @sink_fmt: sink mediabus format * @test_pattern: test pattern controls * @ctrls: v4l2 controls structure - * @video_lock: mutex serializing video device and the subdev operations + * @video_lock: mutex serializing video device operations + * @subdev_lock: mutex serializing subdev operations * @cac_margin_x: horizontal CAC margin in pixels * @cac_margin_y: vertical CAC margin in pixels * @state: driver state flags diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h index e2d4d628b5aa..ddf29e0b5b1c 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/exynos4-is/fimc-lite.h @@ -137,6 +137,8 @@ struct flite_buffer { * @active_buf_count: number of video buffers scheduled in hardware * @frame_count: the captured frames counter * @reqbufs_count: the number of buffers requested with REQBUFS ioctl + * @events: event info + * @streaming: is streaming in progress? */ struct fimc_lite { struct platform_device *pdev; diff --git a/drivers/media/platform/exynos4-is/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h index d7a62465c14e..b9b33aa1f12f 100644 --- a/drivers/media/platform/exynos4-is/fimc-reg.h +++ b/drivers/media/platform/exynos4-is/fimc-reg.h @@ -324,6 +324,7 @@ void fimc_deactivate_capture(struct fimc_dev *fimc); /** * fimc_hw_set_dma_seq - configure output DMA buffer sequence + * @dev: fimc device * @mask: bitmask for the DMA output buffer registers, set to 0 to skip buffer * This function masks output DMA ring buffers, it allows to select which of * the 32 available output buffer address registers will be used by the DMA diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 8e1e892085ec..13d192ba4aa6 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -488,8 +488,10 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, for_each_child_of_node(port, ep) { ret = fimc_md_parse_one_endpoint(fmd, ep); - if (ret < 0) + if (ret < 0) { + of_node_put(ep); return ret; + } } return 0; @@ -806,7 +808,7 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd) } /** - * __fimc_md_create_fimc_links - create links to all FIMC entities + * __fimc_md_create_fimc_sink_links - create links to all FIMC entities * @fmd: fimc media device * @source: the source entity to create links to all fimc entities from * @sensor: sensor subdev linked to FIMC[fimc_id] entity, may be null diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h index a3876d668ea6..62ad5d7e035a 100644 --- a/drivers/media/platform/exynos4-is/media-dev.h +++ b/drivers/media/platform/exynos4-is/media-dev.h @@ -100,6 +100,8 @@ struct cam_clk { * @sensor: array of registered sensor subdevs * @num_sensors: actual number of registered sensors * @camclk: external sensor clock information + * @wbclk: external writeback clock information + * @fimc_lite: array of registered fimc-lite devices * @fimc: array of registered fimc devices * @fimc_is: fimc-is data structure * @use_isp: set to true when FIMC-IS subsystem is used @@ -107,9 +109,12 @@ struct cam_clk { * @media_dev: top level media device * @v4l2_dev: top level v4l2_device holding up the subdevs * @pdev: platform device this media device is hooked up into - * @cam_clk_provider: CAMCLK clock provider structure + * @clk_provider: CAMCLK clock provider structure + * @subdev_notifier: notifier for the subdevs * @user_subdev_api: true if subdevs are not configured by the host driver * @slock: spinlock protecting @sensor array + * @pipelines: list of pipelines + * @link_setup_graph: graph iterator */ struct fimc_md { struct fimc_csis_info csis[CSIS_MAX_ENTITIES]; diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 1f1042d5c865..a4bfa70b49b2 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -1529,7 +1529,7 @@ err_irq: static int viu_of_remove(struct platform_device *op) { - struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); + struct v4l2_device *v4l2_dev = platform_get_drvdata(op); struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next, struct v4l2_subdev, list); @@ -1550,7 +1550,7 @@ static int viu_of_remove(struct platform_device *op) #ifdef CONFIG_PM static int viu_suspend(struct platform_device *op, pm_message_t state) { - struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); + struct v4l2_device *v4l2_dev = platform_get_drvdata(op); struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); clk_disable(dev->clk); @@ -1559,7 +1559,7 @@ static int viu_suspend(struct platform_device *op, pm_message_t state) static int viu_resume(struct platform_device *op) { - struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev); + struct v4l2_device *v4l2_dev = platform_get_drvdata(op); struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev); clk_enable(dev->clk); diff --git a/drivers/media/platform/imx-jpeg/Kconfig b/drivers/media/platform/imx-jpeg/Kconfig new file mode 100644 index 000000000000..2fdd648cda80 --- /dev/null +++ b/drivers/media/platform/imx-jpeg/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_IMX8_JPEG + tristate "IMX8 JPEG Encoder/Decoder" + depends on ARCH_MXC || COMPILE_TEST + depends on VIDEO_DEV && VIDEO_V4L2 + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + select V4L2_JPEG_HELPER + help + This is a video4linux2 driver for the i.MX8 QXP/QM integrated + JPEG encoder/decoder. diff --git a/drivers/media/platform/imx-jpeg/Makefile b/drivers/media/platform/imx-jpeg/Makefile new file mode 100644 index 000000000000..bf19c82e61b4 --- /dev/null +++ b/drivers/media/platform/imx-jpeg/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +mxc-jpeg-encdec-objs := mxc-jpeg-hw.o mxc-jpeg.o +obj-$(CONFIG_VIDEO_IMX8_JPEG) += mxc-jpeg-encdec.o diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg-hw.c b/drivers/media/platform/imx-jpeg/mxc-jpeg-hw.c new file mode 100644 index 000000000000..29c604b1b179 --- /dev/null +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg-hw.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver + * + * Copyright 2018-2019 NXP + */ + +#include <linux/delay.h> +#include <media/videobuf2-core.h> +#include "mxc-jpeg-hw.h" + +#define print_wrapper_reg(dev, base_address, reg_offset)\ + internal_print_wrapper_reg(dev, (base_address), #reg_offset,\ + (reg_offset)) +#define internal_print_wrapper_reg(dev, base_address, reg_name, reg_offset) {\ + int val;\ + val = readl((base_address) + (reg_offset));\ + dev_dbg(dev, "Wrapper reg %s = 0x%x\n", reg_name, val);\ +} + +void print_descriptor_info(struct device *dev, struct mxc_jpeg_desc *desc) +{ + dev_dbg(dev, " MXC JPEG NEXT_DESCPT_PTR 0x%x\n", + desc->next_descpt_ptr); + dev_dbg(dev, " MXC JPEG BUF_BASE0 0x%x\n", desc->buf_base0); + dev_dbg(dev, " MXC JPEG BUF_BASE1 0x%x\n", desc->buf_base1); + dev_dbg(dev, " MXC JPEG LINE_PITCH %d\n", desc->line_pitch); + dev_dbg(dev, " MXC JPEG STM_BUFBASE 0x%x\n", desc->stm_bufbase); + dev_dbg(dev, " MXC JPEG STM_BUFSIZE %d\n", desc->stm_bufsize); + dev_dbg(dev, " MXC JPEG IMGSIZE %x (%d x %d)\n", desc->imgsize, + desc->imgsize >> 16, desc->imgsize & 0xFFFF); + dev_dbg(dev, " MXC JPEG STM_CTRL 0x%x\n", desc->stm_ctrl); +} + +void print_cast_status(struct device *dev, void __iomem *reg, + unsigned int mode) +{ + dev_dbg(dev, "CAST IP status regs:\n"); + print_wrapper_reg(dev, reg, CAST_STATUS0); + print_wrapper_reg(dev, reg, CAST_STATUS1); + print_wrapper_reg(dev, reg, CAST_STATUS2); + print_wrapper_reg(dev, reg, CAST_STATUS3); + print_wrapper_reg(dev, reg, CAST_STATUS4); + print_wrapper_reg(dev, reg, CAST_STATUS5); + print_wrapper_reg(dev, reg, CAST_STATUS6); + print_wrapper_reg(dev, reg, CAST_STATUS7); + print_wrapper_reg(dev, reg, CAST_STATUS8); + print_wrapper_reg(dev, reg, CAST_STATUS9); + print_wrapper_reg(dev, reg, CAST_STATUS10); + print_wrapper_reg(dev, reg, CAST_STATUS11); + print_wrapper_reg(dev, reg, CAST_STATUS12); + print_wrapper_reg(dev, reg, CAST_STATUS13); + if (mode == MXC_JPEG_DECODE) + return; + print_wrapper_reg(dev, reg, CAST_STATUS14); + print_wrapper_reg(dev, reg, CAST_STATUS15); + print_wrapper_reg(dev, reg, CAST_STATUS16); + print_wrapper_reg(dev, reg, CAST_STATUS17); + print_wrapper_reg(dev, reg, CAST_STATUS18); + print_wrapper_reg(dev, reg, CAST_STATUS19); +} + +void print_wrapper_info(struct device *dev, void __iomem *reg) +{ + dev_dbg(dev, "Wrapper regs:\n"); + print_wrapper_reg(dev, reg, GLB_CTRL); + print_wrapper_reg(dev, reg, COM_STATUS); + print_wrapper_reg(dev, reg, BUF_BASE0); + print_wrapper_reg(dev, reg, BUF_BASE1); + print_wrapper_reg(dev, reg, LINE_PITCH); + print_wrapper_reg(dev, reg, STM_BUFBASE); + print_wrapper_reg(dev, reg, STM_BUFSIZE); + print_wrapper_reg(dev, reg, IMGSIZE); + print_wrapper_reg(dev, reg, STM_CTRL); +} + +void mxc_jpeg_enable_irq(void __iomem *reg, int slot) +{ + writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN)); +} + +void mxc_jpeg_sw_reset(void __iomem *reg) +{ + /* + * engine soft reset, internal state machine reset + * this will not reset registers, however, it seems + * the registers may remain inconsistent with the internal state + * so, on purpose, at least let GLB_CTRL bits clear after this reset + */ + writel(GLB_CTRL_SFT_RST, reg + GLB_CTRL); +} + +void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg) +{ + dev_dbg(dev, "CAST Encoder CONFIG...\n"); + /* + * "Config_Mode" enabled, "Config_Mode auto clear enabled", + */ + writel(0xa0, reg + CAST_MODE); + + /* all markers and segments */ + writel(0x3ff, reg + CAST_CFG_MODE); + + /* quality factor */ + writel(0x4b, reg + CAST_QUALITY); +} + +void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg) +{ + dev_dbg(dev, "CAST Encoder GO...\n"); + /* + * "GO" enabled, "GO bit auto clear" enabled + */ + writel(0x140, reg + CAST_MODE); +} + +void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg) +{ + dev_dbg(dev, "CAST Decoder GO...\n"); + writel(MXC_DEC_EXIT_IDLE_MODE, reg + CAST_CTRL); +} + +int mxc_jpeg_enable(void __iomem *reg) +{ + u32 regval; + + writel(GLB_CTRL_JPG_EN, reg + GLB_CTRL); + regval = readl(reg); + return regval; +} + +void mxc_jpeg_enable_slot(void __iomem *reg, int slot) +{ + u32 regval; + + regval = readl(reg + GLB_CTRL); + writel(GLB_CTRL_SLOT_EN(slot) | regval, reg + GLB_CTRL); +} + +void mxc_jpeg_set_l_endian(void __iomem *reg, int le) +{ + u32 regval; + + regval = readl(reg + GLB_CTRL); + regval &= ~GLB_CTRL_L_ENDIAN(1); /* clear */ + writel(GLB_CTRL_L_ENDIAN(le) | regval, reg + GLB_CTRL); /* set */ +} + +void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc, u32 bufsize) +{ + desc->stm_bufsize = bufsize; +} + +void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h) +{ + desc->imgsize = w << 16 | h; +} + +void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch) +{ + desc->line_pitch = line_pitch; +} + +void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot) +{ + writel(desc | MXC_NXT_DESCPT_EN, + reg + MXC_SLOT_OFFSET(slot, SLOT_NXT_DESCPT_PTR)); +} diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/imx-jpeg/mxc-jpeg-hw.h new file mode 100644 index 000000000000..ae70d3a0dc24 --- /dev/null +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg-hw.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver + * + * Copyright 2018-2019 NXP + */ + +#ifndef _MXC_JPEG_HW_H +#define _MXC_JPEG_HW_H + +/* JPEG Decoder/Encoder Wrapper Register Map */ +#define GLB_CTRL 0x0 +#define COM_STATUS 0x4 +#define BUF_BASE0 0x14 +#define BUF_BASE1 0x18 +#define LINE_PITCH 0x1C +#define STM_BUFBASE 0x20 +#define STM_BUFSIZE 0x24 +#define IMGSIZE 0x28 +#define STM_CTRL 0x2C + +/* CAST JPEG-Decoder/Encoder Status Register Map (read-only)*/ +#define CAST_STATUS0 0x100 +#define CAST_STATUS1 0x104 +#define CAST_STATUS2 0x108 +#define CAST_STATUS3 0x10c +#define CAST_STATUS4 0x110 +#define CAST_STATUS5 0x114 +#define CAST_STATUS6 0x118 +#define CAST_STATUS7 0x11c +#define CAST_STATUS8 0x120 +#define CAST_STATUS9 0x124 +#define CAST_STATUS10 0x128 +#define CAST_STATUS11 0x12c +#define CAST_STATUS12 0x130 +#define CAST_STATUS13 0x134 +/* the following are for encoder only */ +#define CAST_STATUS14 0x138 +#define CAST_STATUS15 0x13c +#define CAST_STATUS16 0x140 +#define CAST_STATUS17 0x144 +#define CAST_STATUS18 0x148 +#define CAST_STATUS19 0x14c + +/* CAST JPEG-Decoder Control Register Map (write-only) */ +#define CAST_CTRL CAST_STATUS13 + +/* CAST JPEG-Encoder Control Register Map (write-only) */ +#define CAST_MODE CAST_STATUS0 +#define CAST_CFG_MODE CAST_STATUS1 +#define CAST_QUALITY CAST_STATUS2 +#define CAST_RSVD CAST_STATUS3 +#define CAST_REC_REGS_SEL CAST_STATUS4 +#define CAST_LUMTH CAST_STATUS5 +#define CAST_CHRTH CAST_STATUS6 +#define CAST_NOMFRSIZE_LO CAST_STATUS7 +#define CAST_NOMFRSIZE_HI CAST_STATUS8 +#define CAST_OFBSIZE_LO CAST_STATUS9 +#define CAST_OFBSIZE_HI CAST_STATUS10 + +#define MXC_MAX_SLOTS 1 /* TODO use all 4 slots*/ +/* JPEG-Decoder Wrapper Slot Registers 0..3 */ +#define SLOT_BASE 0x10000 +#define SLOT_STATUS 0x0 +#define SLOT_IRQ_EN 0x4 +#define SLOT_BUF_PTR 0x8 +#define SLOT_CUR_DESCPT_PTR 0xC +#define SLOT_NXT_DESCPT_PTR 0x10 +#define MXC_SLOT_OFFSET(slot, offset) ((SLOT_BASE * ((slot) + 1)) + (offset)) + +/* GLB_CTRL fields */ +#define GLB_CTRL_JPG_EN 0x1 +#define GLB_CTRL_SFT_RST (0x1 << 1) +#define GLB_CTRL_DEC_GO (0x1 << 2) +#define GLB_CTRL_L_ENDIAN(le) ((le) << 3) +#define GLB_CTRL_SLOT_EN(slot) (0x1 << ((slot) + 4)) + +/* COM_STAUS fields */ +#define COM_STATUS_DEC_ONGOING(r) (((r) & (1 << 31)) >> 31) +#define COM_STATUS_CUR_SLOT(r) (((r) & (0x3 << 29)) >> 29) + +/* STM_CTRL fields */ +#define STM_CTRL_PIXEL_PRECISION (0x1 << 2) +#define STM_CTRL_IMAGE_FORMAT(img_fmt) ((img_fmt) << 3) +#define STM_CTRL_IMAGE_FORMAT_MASK (0xF << 3) +#define STM_CTRL_BITBUF_PTR_CLR(clr) ((clr) << 7) +#define STM_CTRL_AUTO_START(go) ((go) << 8) +#define STM_CTRL_CONFIG_MOD(mod) ((mod) << 9) + +/* SLOT_STATUS fields for slots 0..3 */ +#define SLOT_STATUS_FRMDONE (0x1 << 3) +#define SLOT_STATUS_ENC_CONFIG_ERR (0x1 << 8) + +/* SLOT_IRQ_EN fields TBD */ + +#define MXC_NXT_DESCPT_EN 0x1 +#define MXC_DEC_EXIT_IDLE_MODE 0x4 + +/* JPEG-Decoder Wrapper - STM_CTRL Register Fields */ +#define MXC_PIXEL_PRECISION(precision) ((precision) / 8 << 2) +enum mxc_jpeg_image_format { + MXC_JPEG_INVALID = -1, + MXC_JPEG_YUV420 = 0x0, /* 2 Plannar, Y=1st plane UV=2nd plane */ + MXC_JPEG_YUV422 = 0x1, /* 1 Plannar, YUYV sequence */ + MXC_JPEG_RGB = 0x2, /* RGBRGB packed format */ + MXC_JPEG_YUV444 = 0x3, /* 1 Plannar, YUVYUV sequence */ + MXC_JPEG_GRAY = 0x4, /* Y8 or Y12 or Single Component */ + MXC_JPEG_RESERVED = 0x5, + MXC_JPEG_ARGB = 0x6, +}; + +#include "mxc-jpeg.h" +void print_descriptor_info(struct device *dev, struct mxc_jpeg_desc *desc); +void print_cast_status(struct device *dev, void __iomem *reg, + unsigned int mode); +void print_wrapper_info(struct device *dev, void __iomem *reg); +void mxc_jpeg_sw_reset(void __iomem *reg); +int mxc_jpeg_enable(void __iomem *reg); +void wait_frmdone(struct device *dev, void __iomem *reg); +void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg); +void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg); +void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg); +int mxc_jpeg_get_slot(void __iomem *reg); +u32 mxc_jpeg_get_offset(void __iomem *reg, int slot); +void mxc_jpeg_enable_slot(void __iomem *reg, int slot); +void mxc_jpeg_set_l_endian(void __iomem *reg, int le); +void mxc_jpeg_enable_irq(void __iomem *reg, int slot); +int mxc_jpeg_set_input(void __iomem *reg, u32 in_buf, u32 bufsize); +int mxc_jpeg_set_output(void __iomem *reg, u16 out_pitch, u32 out_buf, + u16 w, u16 h); +void mxc_jpeg_set_config_mode(void __iomem *reg, int config_mode); +int mxc_jpeg_set_params(struct mxc_jpeg_desc *desc, u32 bufsize, u16 + out_pitch, u32 format); +void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc, u32 bufsize); +void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h); +void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch); +void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot); +void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc, + void __iomem *reg); +#endif diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/imx-jpeg/mxc-jpeg.c new file mode 100644 index 000000000000..03b9264af068 --- /dev/null +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.c @@ -0,0 +1,2126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 driver for the JPEG encoder/decoder from i.MX8QXP/i.MX8QM application + * processors. + * + * The multi-planar buffers API is used. + * + * Baseline and extended sequential jpeg decoding is supported. + * Progressive jpeg decoding is not supported by the IP. + * Supports encode and decode of various formats: + * YUV444, YUV422, YUV420, RGB, ARGB, Gray + * YUV420 is the only multi-planar format supported. + * Minimum resolution is 64 x 64, maximum 8192 x 8192. + * To achieve 8192 x 8192, modify in defconfig: CONFIG_CMA_SIZE_MBYTES=320 + * The alignment requirements for the resolution depend on the format, + * multiple of 16 resolutions should work for all formats. + * Special workarounds are made in the driver to support NV12 1080p. + * When decoding, the driver detects image resolution and pixel format + * from the jpeg stream, by parsing the jpeg markers. + * + * The IP has 4 slots available for context switching, but only slot 0 + * was fully tested to work. Context switching is not used by the driver. + * Each driver instance (context) allocates a slot for itself, but this + * is postponed until device_run, to allow unlimited opens. + * + * The driver submits jobs to the IP by setting up a descriptor for the + * used slot, and then validating it. The encoder has an additional descriptor + * for the configuration phase. The driver expects FRM_DONE interrupt from + * IP to mark the job as finished. + * + * The decoder IP has some limitations regarding the component ID's, + * but the driver works around this by replacing them in the jpeg stream. + * + * A module parameter is available for debug purpose (jpeg_tracing), to enable + * it, enable dynamic debug for this module and: + * echo 1 > /sys/module/mxc_jpeg_encdec/parameters/jpeg_tracing + * + * This is inspired by the drivers/media/platform/s5p-jpeg driver + * + * Copyright 2018-2019 NXP + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/irqreturn.h> +#include <linux/interrupt.h> +#include <linux/pm_domain.h> +#include <linux/string.h> + +#include <media/v4l2-jpeg.h> +#include <media/v4l2-mem2mem.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-common.h> +#include <media/v4l2-event.h> +#include <media/videobuf2-dma-contig.h> + +#include "mxc-jpeg-hw.h" +#include "mxc-jpeg.h" + +static struct mxc_jpeg_fmt mxc_formats[] = { + { + .name = "JPEG", + .fourcc = V4L2_PIX_FMT_JPEG, + .subsampling = -1, + .nc = -1, + .colplanes = 1, + .flags = MXC_JPEG_FMT_TYPE_ENC, + }, + { + .name = "RGB", /*RGBRGB packed format*/ + .fourcc = V4L2_PIX_FMT_RGB24, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, + .nc = 3, + .depth = 24, + .colplanes = 1, + .h_align = 3, + .v_align = 3, + .flags = MXC_JPEG_FMT_TYPE_RAW, + }, + { + .name = "ARGB", /* ARGBARGB packed format */ + .fourcc = V4L2_PIX_FMT_ARGB32, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, + .nc = 4, + .depth = 32, + .colplanes = 1, + .h_align = 3, + .v_align = 3, + .flags = MXC_JPEG_FMT_TYPE_RAW, + }, + { + .name = "YUV420", /* 1st plane = Y, 2nd plane = UV */ + .fourcc = V4L2_PIX_FMT_NV12, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, + .nc = 3, + .depth = 12, /* 6 bytes (4Y + UV) for 4 pixels */ + .colplanes = 2, /* 1 plane Y, 1 plane UV interleaved */ + .h_align = 4, + .v_align = 4, + .flags = MXC_JPEG_FMT_TYPE_RAW, + }, + { + .name = "YUV422", /* YUYV */ + .fourcc = V4L2_PIX_FMT_YUYV, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, + .nc = 3, + .depth = 16, + .colplanes = 1, + .h_align = 4, + .v_align = 3, + .flags = MXC_JPEG_FMT_TYPE_RAW, + }, + { + .name = "YUV444", /* YUVYUV */ + .fourcc = V4L2_PIX_FMT_YUV24, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, + .nc = 3, + .depth = 24, + .colplanes = 1, + .h_align = 3, + .v_align = 3, + .flags = MXC_JPEG_FMT_TYPE_RAW, + }, + { + .name = "Gray", /* Gray (Y8/Y12) or Single Comp */ + .fourcc = V4L2_PIX_FMT_GREY, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, + .nc = 1, + .depth = 8, + .colplanes = 1, + .h_align = 3, + .v_align = 3, + .flags = MXC_JPEG_FMT_TYPE_RAW, + }, +}; + +#define MXC_JPEG_NUM_FORMATS ARRAY_SIZE(mxc_formats) + +static const int mxc_decode_mode = MXC_JPEG_DECODE; +static const int mxc_encode_mode = MXC_JPEG_ENCODE; + +static const struct of_device_id mxc_jpeg_match[] = { + { + .compatible = "nxp,imx8qxp-jpgdec", + .data = &mxc_decode_mode, + }, + { + .compatible = "nxp,imx8qxp-jpgenc", + .data = &mxc_encode_mode, + }, + { }, +}; + +/* + * default configuration stream, 64x64 yuv422 + * split by JPEG marker, so it's easier to modify & use + */ +static const unsigned char jpeg_soi[] = { + 0xFF, 0xD8 +}; + +static const unsigned char jpeg_app0[] = { + 0xFF, 0xE0, + 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00 +}; + +static const unsigned char jpeg_app14[] = { + 0xFF, 0xEE, + 0x00, 0x0E, 0x41, 0x64, 0x6F, 0x62, 0x65, + 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const unsigned char jpeg_dqt[] = { + 0xFF, 0xDB, + 0x00, 0x84, 0x00, 0x10, 0x0B, 0x0C, 0x0E, + 0x0C, 0x0A, 0x10, 0x0E, 0x0D, 0x0E, 0x12, + 0x11, 0x10, 0x13, 0x18, 0x28, 0x1A, 0x18, + 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1D, + 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33, + 0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, + 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, + 0x51, 0x57, 0x5F, 0x62, 0x67, 0x68, 0x67, + 0x3E, 0x4D, 0x71, 0x79, 0x70, 0x64, 0x78, + 0x5C, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, + 0x12, 0x18, 0x15, 0x18, 0x2F, 0x1A, 0x1A, + 0x2F, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 +}; + +static const unsigned char jpeg_sof_maximal[] = { + 0xFF, 0xC0, + 0x00, 0x14, 0x08, 0x00, 0x40, 0x00, 0x40, + 0x04, 0x01, 0x11, 0x00, 0x02, 0x11, 0x01, + 0x03, 0x11, 0x01, 0x04, 0x11, 0x01 +}; + +static const unsigned char jpeg_dht[] = { + 0xFF, 0xC4, + 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01, + 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, + 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, + 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, + 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, + 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, + 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, + 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, + 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, + 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, + 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, + 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, + 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, + 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, + 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, + 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, + 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, + 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + 0xE7, 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, + 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, + 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, + 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, + 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, + 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, + 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, + 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, + 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, + 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, + 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, + 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, + 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, + 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, + 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, + 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, + 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, + 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, + 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, + 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, + 0xF6, 0xF7, 0xF8, 0xF9, 0xFA +}; + +static const unsigned char jpeg_dri[] = { + 0xFF, 0xDD, + 0x00, 0x04, 0x00, 0x20 +}; + +static const unsigned char jpeg_sos_maximal[] = { + 0xFF, 0xDA, + 0x00, 0x0C, 0x04, 0x01, 0x00, 0x02, 0x11, 0x03, + 0x11, 0x04, 0x11, 0x00, 0x3F, 0x00 +}; + +static const unsigned char jpeg_eoi[] = { + 0xFF, 0xD9 +}; + +struct mxc_jpeg_src_buf { + /* common v4l buffer stuff -- must be first */ + struct vb2_v4l2_buffer b; + struct list_head list; + + /* mxc-jpeg specific */ + bool dht_needed; + bool jpeg_parse_error; +}; + +static inline struct mxc_jpeg_src_buf *vb2_to_mxc_buf(struct vb2_buffer *vb) +{ + return container_of(to_vb2_v4l2_buffer(vb), + struct mxc_jpeg_src_buf, b); +} + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-3)"); + +static void _bswap16(u16 *a) +{ + *a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8); +} + +static void print_mxc_buf(struct mxc_jpeg_dev *jpeg, struct vb2_buffer *buf, + unsigned long len) +{ + unsigned int plane_no; + u32 dma_addr; + void *vaddr; + unsigned long payload; + + if (debug < 3) + return; + + for (plane_no = 0; plane_no < buf->num_planes; plane_no++) { + payload = vb2_get_plane_payload(buf, plane_no); + if (len == 0) + len = payload; + dma_addr = vb2_dma_contig_plane_dma_addr(buf, plane_no); + vaddr = vb2_plane_vaddr(buf, plane_no); + v4l2_dbg(3, debug, &jpeg->v4l2_dev, + "plane %d (vaddr=%p dma_addr=%x payload=%ld):", + plane_no, vaddr, dma_addr, payload); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + vaddr, len, false); + } +} + +static inline struct mxc_jpeg_ctx *mxc_jpeg_fh_to_ctx(struct v4l2_fh *fh) +{ + return container_of(fh, struct mxc_jpeg_ctx, fh); +} + +static int enum_fmt(struct mxc_jpeg_fmt *mxc_formats, int n, + struct v4l2_fmtdesc *f, u32 type) +{ + int i, num = 0; + + for (i = 0; i < n; ++i) { + if (mxc_formats[i].flags == type) { + /* index-th format of searched type found ? */ + if (num == f->index) + break; + /* Correct type but haven't reached our index yet, + * just increment per-type index + */ + ++num; + } + } + + /* Format not found */ + if (i >= n) + return -EINVAL; + + strscpy(f->description, mxc_formats[i].name, sizeof(f->description)); + f->pixelformat = mxc_formats[i].fourcc; + + return 0; +} + +static struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx, + u32 pixelformat) +{ + unsigned int k; + + for (k = 0; k < MXC_JPEG_NUM_FORMATS; k++) { + struct mxc_jpeg_fmt *fmt = &mxc_formats[k]; + + if (fmt->fourcc == pixelformat) + return fmt; + } + return NULL; +} + +static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(u32 fourcc) +{ + switch (fourcc) { + case V4L2_PIX_FMT_GREY: + return MXC_JPEG_GRAY; + case V4L2_PIX_FMT_YUYV: + return MXC_JPEG_YUV422; + case V4L2_PIX_FMT_NV12: + return MXC_JPEG_YUV420; + case V4L2_PIX_FMT_YUV24: + return MXC_JPEG_YUV444; + case V4L2_PIX_FMT_RGB24: + return MXC_JPEG_RGB; + case V4L2_PIX_FMT_ARGB32: + return MXC_JPEG_ARGB; + default: + return MXC_JPEG_INVALID; + } +} + +static struct mxc_jpeg_q_data *mxc_jpeg_get_q_data(struct mxc_jpeg_ctx *ctx, + enum v4l2_buf_type type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return &ctx->out_q; + return &ctx->cap_q; +} + +static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc, + struct vb2_buffer *raw_buf, + struct vb2_buffer *jpeg_buf, int offset) +{ + int img_fmt = desc->stm_ctrl & STM_CTRL_IMAGE_FORMAT_MASK; + + desc->buf_base0 = vb2_dma_contig_plane_dma_addr(raw_buf, 0); + desc->buf_base1 = 0; + if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) { + WARN_ON(raw_buf->num_planes < 2); + desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1); + } + desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(jpeg_buf, 0) + + offset; +} + +static void notify_eos(struct mxc_jpeg_ctx *ctx) +{ + const struct v4l2_event ev = { + .type = V4L2_EVENT_EOS + }; + + dev_dbg(ctx->mxc_jpeg->dev, "Notify app event EOS reached"); + v4l2_event_queue_fh(&ctx->fh, &ev); +} + +static void notify_src_chg(struct mxc_jpeg_ctx *ctx) +{ + const struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = + V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + dev_dbg(ctx->mxc_jpeg->dev, "Notify app event SRC_CH_RESOLUTION"); + v4l2_event_queue_fh(&ctx->fh, &ev); +} + +static int mxc_get_free_slot(struct mxc_jpeg_slot_data slot_data[], int n) +{ + int free_slot = 0; + + while (slot_data[free_slot].used && free_slot < n) + free_slot++; + + return free_slot; /* >=n when there are no more free slots */ +} + +static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg, + unsigned int slot) +{ + struct mxc_jpeg_desc *desc; + struct mxc_jpeg_desc *cfg_desc; + void *cfg_stm; + + if (jpeg->slot_data[slot].desc) + goto skip_alloc; /* already allocated, reuse it */ + + /* allocate descriptor for decoding/encoding phase */ + desc = dma_alloc_coherent(jpeg->dev, + sizeof(struct mxc_jpeg_desc), + &jpeg->slot_data[slot].desc_handle, + GFP_ATOMIC); + if (!desc) + goto err; + jpeg->slot_data[slot].desc = desc; + + /* allocate descriptor for configuration phase (encoder only) */ + cfg_desc = dma_alloc_coherent(jpeg->dev, + sizeof(struct mxc_jpeg_desc), + &jpeg->slot_data[slot].cfg_desc_handle, + GFP_ATOMIC); + if (!cfg_desc) + goto err; + jpeg->slot_data[slot].cfg_desc = cfg_desc; + + /* allocate configuration stream */ + cfg_stm = dma_alloc_coherent(jpeg->dev, + MXC_JPEG_MAX_CFG_STREAM, + &jpeg->slot_data[slot].cfg_stream_handle, + GFP_ATOMIC); + if (!cfg_stm) + goto err; + jpeg->slot_data[slot].cfg_stream_vaddr = cfg_stm; + +skip_alloc: + jpeg->slot_data[slot].used = true; + + return true; +err: + dev_err(jpeg->dev, "Could not allocate descriptors for slot %d", slot); + + return false; +} + +static void mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg, + unsigned int slot) +{ + if (slot >= MXC_MAX_SLOTS) { + dev_err(jpeg->dev, "Invalid slot %d, nothing to free.", slot); + return; + } + + /* free descriptor for decoding/encoding phase */ + dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc), + jpeg->slot_data[slot].desc, + jpeg->slot_data[slot].desc_handle); + + /* free descriptor for encoder configuration phase / decoder DHT */ + dma_free_coherent(jpeg->dev, sizeof(struct mxc_jpeg_desc), + jpeg->slot_data[slot].cfg_desc, + jpeg->slot_data[slot].cfg_desc_handle); + + /* free configuration stream */ + dma_free_coherent(jpeg->dev, MXC_JPEG_MAX_CFG_STREAM, + jpeg->slot_data[slot].cfg_stream_vaddr, + jpeg->slot_data[slot].cfg_stream_handle); + + jpeg->slot_data[slot].used = false; +} + +static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) +{ + struct mxc_jpeg_dev *jpeg = priv; + struct mxc_jpeg_ctx *ctx; + void __iomem *reg = jpeg->base_reg; + struct device *dev = jpeg->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct mxc_jpeg_src_buf *jpeg_src_buf; + enum vb2_buffer_state buf_state; + u32 dec_ret, com_status; + unsigned long payload; + struct mxc_jpeg_q_data *q_data; + enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + unsigned int slot; + + spin_lock(&jpeg->hw_lock); + + com_status = readl(reg + COM_STATUS); + slot = COM_STATUS_CUR_SLOT(com_status); + dev_dbg(dev, "Irq %d on slot %d.\n", irq, slot); + + ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev); + if (!ctx) { + dev_err(dev, + "Instance released before the end of transaction.\n"); + /* soft reset only resets internal state, not registers */ + mxc_jpeg_sw_reset(reg); + /* clear all interrupts */ + writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); + goto job_unlock; + } + + if (slot != ctx->slot) { + /* TODO investigate when adding multi-instance support */ + dev_warn(dev, "IRQ slot %d != context slot %d.\n", + slot, ctx->slot); + goto job_unlock; + } + + dec_ret = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); + writel(dec_ret, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS)); /* w1c */ + + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + jpeg_src_buf = vb2_to_mxc_buf(&src_buf->vb2_buf); + + if (dec_ret & SLOT_STATUS_ENC_CONFIG_ERR) { + u32 ret = readl(reg + CAST_STATUS12); + + dev_err(dev, "Encoder/decoder error, status=0x%08x", ret); + mxc_jpeg_sw_reset(reg); + buf_state = VB2_BUF_STATE_ERROR; + goto buffers_done; + } + + if (!(dec_ret & SLOT_STATUS_FRMDONE)) + goto job_unlock; + + if (jpeg->mode == MXC_JPEG_ENCODE && + ctx->enc_state == MXC_JPEG_ENC_CONF) { + ctx->enc_state = MXC_JPEG_ENCODING; + dev_dbg(dev, "Encoder config finished. Start encoding...\n"); + mxc_jpeg_enc_mode_go(dev, reg); + goto job_unlock; + } + if (jpeg->mode == MXC_JPEG_DECODE && jpeg_src_buf->dht_needed) { + jpeg_src_buf->dht_needed = false; + dev_dbg(dev, "Decoder DHT cfg finished. Start decoding...\n"); + goto job_unlock; + } + if (jpeg->mode == MXC_JPEG_ENCODE) { + payload = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR)); + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload); + dev_dbg(dev, "Encoding finished, payload size: %ld\n", + payload); + } else { + q_data = mxc_jpeg_get_q_data(ctx, cap_type); + payload = q_data->sizeimage[0]; + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload); + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); + if (q_data->fmt->colplanes == 2) { + payload = q_data->sizeimage[1]; + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload); + } + dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n", + vb2_get_plane_payload(&dst_buf->vb2_buf, 0), + vb2_get_plane_payload(&dst_buf->vb2_buf, 1)); + } + + /* short preview of the results */ + dev_dbg(dev, "src_buf preview: "); + print_mxc_buf(jpeg, &src_buf->vb2_buf, 32); + dev_dbg(dev, "dst_buf preview: "); + print_mxc_buf(jpeg, &dst_buf->vb2_buf, 32); + buf_state = VB2_BUF_STATE_DONE; + +buffers_done: + jpeg->slot_data[slot].used = false; /* unused, but don't free */ + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, buf_state); + v4l2_m2m_buf_done(dst_buf, buf_state); + spin_unlock(&jpeg->hw_lock); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + return IRQ_HANDLED; +job_unlock: + spin_unlock(&jpeg->hw_lock); + return IRQ_HANDLED; +} + +static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof, + u32 fourcc, + u16 w, u16 h) +{ + int sof_length; + + sof->precision = 8; /* TODO allow 8/12 bit precision*/ + sof->height = h; + _bswap16(&sof->height); + sof->width = w; + _bswap16(&sof->width); + + switch (fourcc) { + case V4L2_PIX_FMT_NV12: + sof->components_no = 3; + sof->comp[0].v = 0x2; + sof->comp[0].h = 0x2; + break; + case V4L2_PIX_FMT_YUYV: + sof->components_no = 3; + sof->comp[0].v = 0x1; + sof->comp[0].h = 0x2; + break; + case V4L2_PIX_FMT_YUV24: + case V4L2_PIX_FMT_RGB24: + default: + sof->components_no = 3; + break; + case V4L2_PIX_FMT_ARGB32: + sof->components_no = 4; + break; + case V4L2_PIX_FMT_GREY: + sof->components_no = 1; + break; + } + sof_length = 8 + 3 * sof->components_no; + sof->length = sof_length; + _bswap16(&sof->length); + + return sof_length; /* not swaped */ +} + +static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos, + u32 fourcc) +{ + int sos_length; + u8 *sof_u8 = (u8 *)sos; + + switch (fourcc) { + case V4L2_PIX_FMT_NV12: + sos->components_no = 3; + break; + case V4L2_PIX_FMT_YUYV: + sos->components_no = 3; + break; + case V4L2_PIX_FMT_YUV24: + case V4L2_PIX_FMT_RGB24: + default: + sos->components_no = 3; + break; + case V4L2_PIX_FMT_ARGB32: + sos->components_no = 4; + break; + case V4L2_PIX_FMT_GREY: + sos->components_no = 1; + break; + } + sos_length = 6 + 2 * sos->components_no; + sos->length = sos_length; + _bswap16(&sos->length); + + /* SOS ignorable bytes, not so ignorable after all */ + sof_u8[sos_length - 1] = 0x0; + sof_u8[sos_length - 2] = 0x3f; + sof_u8[sos_length - 3] = 0x0; + + return sos_length; /* not swaped */ +} + +static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr, + u32 fourcc, + u16 w, u16 h) +{ + unsigned int offset = 0; + u8 *cfg = (u8 *)cfg_stream_vaddr; + struct mxc_jpeg_sof *sof; + struct mxc_jpeg_sos *sos; + + memcpy(cfg + offset, jpeg_soi, ARRAY_SIZE(jpeg_soi)); + offset += ARRAY_SIZE(jpeg_soi); + + if (fourcc == V4L2_PIX_FMT_RGB24 || + fourcc == V4L2_PIX_FMT_ARGB32) { + memcpy(cfg + offset, jpeg_app14, sizeof(jpeg_app14)); + offset += sizeof(jpeg_app14); + } else { + memcpy(cfg + offset, jpeg_app0, sizeof(jpeg_app0)); + offset += sizeof(jpeg_app0); + } + + memcpy(cfg + offset, jpeg_dqt, sizeof(jpeg_dqt)); + offset += sizeof(jpeg_dqt); + + memcpy(cfg + offset, jpeg_sof_maximal, sizeof(jpeg_sof_maximal)); + offset += 2; /* skip marker ID */ + sof = (struct mxc_jpeg_sof *)(cfg + offset); + offset += mxc_jpeg_fixup_sof(sof, fourcc, w, h); + + memcpy(cfg + offset, jpeg_dht, sizeof(jpeg_dht)); + offset += sizeof(jpeg_dht); + + memcpy(cfg + offset, jpeg_dri, sizeof(jpeg_dri)); + offset += sizeof(jpeg_dri); + + memcpy(cfg + offset, jpeg_sos_maximal, sizeof(jpeg_sos_maximal)); + offset += 2; /* skip marker ID */ + sos = (struct mxc_jpeg_sos *)(cfg + offset); + offset += mxc_jpeg_fixup_sos(sos, fourcc); + + memcpy(cfg + offset, jpeg_eoi, sizeof(jpeg_eoi)); + offset += sizeof(jpeg_eoi); + + return offset; +} + +static void mxc_jpeg_config_dec_desc(struct vb2_buffer *out_buf, + struct mxc_jpeg_ctx *ctx, + struct vb2_buffer *src_buf, + struct vb2_buffer *dst_buf) +{ + enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + struct mxc_jpeg_q_data *q_data_cap; + enum mxc_jpeg_image_format img_fmt; + struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; + void __iomem *reg = jpeg->base_reg; + unsigned int slot = ctx->slot; + struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc; + struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data[slot].cfg_desc; + dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle; + dma_addr_t cfg_desc_handle = jpeg->slot_data[slot].cfg_desc_handle; + dma_addr_t cfg_stream_handle = jpeg->slot_data[slot].cfg_stream_handle; + unsigned int *cfg_size = &jpeg->slot_data[slot].cfg_stream_size; + void *cfg_stream_vaddr = jpeg->slot_data[slot].cfg_stream_vaddr; + struct mxc_jpeg_src_buf *jpeg_src_buf; + + jpeg_src_buf = vb2_to_mxc_buf(src_buf); + + /* setup the decoding descriptor */ + desc->next_descpt_ptr = 0; /* end of chain */ + q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type); + desc->imgsize = q_data_cap->w_adjusted << 16 | q_data_cap->h_adjusted; + img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data_cap->fmt->fourcc); + desc->stm_ctrl &= ~STM_CTRL_IMAGE_FORMAT(0xF); /* clear image format */ + desc->stm_ctrl |= STM_CTRL_IMAGE_FORMAT(img_fmt); + desc->line_pitch = q_data_cap->bytesperline[0]; + mxc_jpeg_addrs(desc, dst_buf, src_buf, 0); + mxc_jpeg_set_bufsize(desc, ALIGN(vb2_plane_size(src_buf, 0), 1024)); + print_descriptor_info(jpeg->dev, desc); + + if (!jpeg_src_buf->dht_needed) { + /* validate the decoding descriptor */ + mxc_jpeg_set_desc(desc_handle, reg, slot); + return; + } + + /* + * if a default huffman table is needed, use the config descriptor to + * inject a DHT, by chaining it before the decoding descriptor + */ + *cfg_size = mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr, + V4L2_PIX_FMT_YUYV, + MXC_JPEG_MIN_WIDTH, + MXC_JPEG_MIN_HEIGHT); + cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN; + cfg_desc->buf_base0 = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + cfg_desc->buf_base1 = 0; + cfg_desc->imgsize = MXC_JPEG_MIN_WIDTH << 16; + cfg_desc->imgsize |= MXC_JPEG_MIN_HEIGHT; + cfg_desc->line_pitch = MXC_JPEG_MIN_WIDTH * 2; + cfg_desc->stm_ctrl = STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV422); + cfg_desc->stm_bufbase = cfg_stream_handle; + cfg_desc->stm_bufsize = ALIGN(*cfg_size, 1024); + print_descriptor_info(jpeg->dev, cfg_desc); + + /* validate the configuration descriptor */ + mxc_jpeg_set_desc(cfg_desc_handle, reg, slot); +} + +static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, + struct mxc_jpeg_ctx *ctx, + struct vb2_buffer *src_buf, + struct vb2_buffer *dst_buf) +{ + struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; + void __iomem *reg = jpeg->base_reg; + unsigned int slot = ctx->slot; + struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc; + struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data[slot].cfg_desc; + dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle; + dma_addr_t cfg_desc_handle = jpeg->slot_data[slot].cfg_desc_handle; + void *cfg_stream_vaddr = jpeg->slot_data[slot].cfg_stream_vaddr; + struct mxc_jpeg_q_data *q_data; + enum mxc_jpeg_image_format img_fmt; + int w, h; + + q_data = mxc_jpeg_get_q_data(ctx, src_buf->vb2_queue->type); + + jpeg->slot_data[slot].cfg_stream_size = + mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr, + q_data->fmt->fourcc, + q_data->w_adjusted, + q_data->h_adjusted); + + /* chain the config descriptor with the encoding descriptor */ + cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN; + + cfg_desc->buf_base0 = jpeg->slot_data[slot].cfg_stream_handle; + cfg_desc->buf_base1 = 0; + cfg_desc->line_pitch = 0; + cfg_desc->stm_bufbase = 0; /* no output expected */ + cfg_desc->stm_bufsize = 0x0; + cfg_desc->imgsize = 0; + cfg_desc->stm_ctrl = STM_CTRL_CONFIG_MOD(1); + + desc->next_descpt_ptr = 0; /* end of chain */ + + /* use adjusted resolution for CAST IP job */ + w = q_data->w_adjusted; + h = q_data->h_adjusted; + mxc_jpeg_set_res(desc, w, h); + mxc_jpeg_set_line_pitch(desc, w * (q_data->fmt->depth / 8)); + mxc_jpeg_set_bufsize(desc, desc->line_pitch * h); + img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data->fmt->fourcc); + if (img_fmt == MXC_JPEG_INVALID) + dev_err(jpeg->dev, "No valid image format detected\n"); + desc->stm_ctrl = STM_CTRL_CONFIG_MOD(0) | + STM_CTRL_IMAGE_FORMAT(img_fmt); + mxc_jpeg_addrs(desc, src_buf, dst_buf, 0); + dev_dbg(jpeg->dev, "cfg_desc:\n"); + print_descriptor_info(jpeg->dev, cfg_desc); + dev_dbg(jpeg->dev, "enc desc:\n"); + print_descriptor_info(jpeg->dev, desc); + print_wrapper_info(jpeg->dev, reg); + print_cast_status(jpeg->dev, reg, MXC_JPEG_ENCODE); + + /* validate the configuration descriptor */ + mxc_jpeg_set_desc(cfg_desc_handle, reg, slot); +} + +static void mxc_jpeg_device_run(void *priv) +{ + struct mxc_jpeg_ctx *ctx = priv; + struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; + void __iomem *reg = jpeg->base_reg; + struct device *dev = jpeg->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + unsigned long flags; + struct mxc_jpeg_q_data *q_data_cap, *q_data_out; + struct mxc_jpeg_src_buf *jpeg_src_buf; + + spin_lock_irqsave(&ctx->mxc_jpeg->hw_lock, flags); + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + if (!src_buf || !dst_buf) { + dev_err(dev, "Null src or dst buf\n"); + goto end; + } + + q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!q_data_cap) + goto end; + q_data_out = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (!q_data_out) + goto end; + src_buf->sequence = q_data_out->sequence++; + dst_buf->sequence = q_data_cap->sequence++; + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); + + jpeg_src_buf = vb2_to_mxc_buf(&src_buf->vb2_buf); + if (jpeg_src_buf->jpeg_parse_error) { + jpeg->slot_data[ctx->slot].used = false; + v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); + spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + + return; + } + + /* + * TODO: this reset should be removed, once we figure out + * how to overcome hardware issues both on encoder and decoder + */ + mxc_jpeg_sw_reset(reg); + mxc_jpeg_enable(reg); + mxc_jpeg_set_l_endian(reg, 1); + + ctx->slot = mxc_get_free_slot(jpeg->slot_data, MXC_MAX_SLOTS); + if (ctx->slot >= MXC_MAX_SLOTS) { + dev_err(dev, "No more free slots\n"); + goto end; + } + if (!mxc_jpeg_alloc_slot_data(jpeg, ctx->slot)) { + dev_err(dev, "Cannot allocate slot data\n"); + goto end; + } + + mxc_jpeg_enable_slot(reg, ctx->slot); + mxc_jpeg_enable_irq(reg, ctx->slot); + + if (jpeg->mode == MXC_JPEG_ENCODE) { + dev_dbg(dev, "Encoding on slot %d\n", ctx->slot); + ctx->enc_state = MXC_JPEG_ENC_CONF; + mxc_jpeg_config_enc_desc(&dst_buf->vb2_buf, ctx, + &src_buf->vb2_buf, &dst_buf->vb2_buf); + mxc_jpeg_enc_mode_conf(dev, reg); /* start config phase */ + } else { + dev_dbg(dev, "Decoding on slot %d\n", ctx->slot); + print_mxc_buf(jpeg, &src_buf->vb2_buf, 0); + mxc_jpeg_config_dec_desc(&dst_buf->vb2_buf, ctx, + &src_buf->vb2_buf, &dst_buf->vb2_buf); + mxc_jpeg_dec_mode_go(dev, reg); + } +end: + spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); +} + +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 device *dev = ctx->mxc_jpeg->dev; + int ret; + + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd); + if (ret < 0) + return ret; + + if (cmd->cmd == V4L2_DEC_CMD_STOP) { + dev_dbg(dev, "Received V4L2_DEC_CMD_STOP"); + if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) { + /* No more src bufs, notify app EOS */ + notify_eos(ctx); + } else { + /* will send EOS later*/ + ctx->stopping = 1; + } + } + + return 0; +} + +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 device *dev = ctx->mxc_jpeg->dev; + int ret; + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd); + if (ret < 0) + return ret; + + if (cmd->cmd == V4L2_ENC_CMD_STOP) { + dev_dbg(dev, "Received V4L2_ENC_CMD_STOP"); + if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) { + /* No more src bufs, notify app EOS */ + notify_eos(ctx); + } else { + /* will send EOS later*/ + ctx->stopping = 1; + } + } + + return 0; +} + +static int mxc_jpeg_queue_setup(struct vb2_queue *q, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_ctxs[]) +{ + struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q); + struct mxc_jpeg_q_data *q_data = NULL; + int i; + + q_data = mxc_jpeg_get_q_data(ctx, q->type); + if (!q_data) + return -EINVAL; + + /* Handle CREATE_BUFS situation - *nplanes != 0 */ + if (*nplanes) { + for (i = 0; i < *nplanes; i++) { + if (sizes[i] < q_data->sizeimage[i]) + return -EINVAL; + } + return 0; + } + + /* Handle REQBUFS situation */ + *nplanes = q_data->fmt->colplanes; + for (i = 0; i < *nplanes; i++) + sizes[i] = q_data->sizeimage[i]; + + return 0; +} + +static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q); + struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, q->type); + + dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx); + q_data->sequence = 0; + + return 0; +} + +static void mxc_jpeg_stop_streaming(struct vb2_queue *q) +{ + struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_v4l2_buffer *vbuf; + + dev_dbg(ctx->mxc_jpeg->dev, "Stop streaming ctx=%p", ctx); + + /* Release all active buffers */ + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vbuf) + return; + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + } +} + +static int mxc_jpeg_valid_comp_id(struct device *dev, + struct mxc_jpeg_sof *sof, + struct mxc_jpeg_sos *sos) +{ + int valid = 1; + int i; + + /* + * there's a limitation in the IP that the component IDs must be + * between 0..4, if they are not, let's patch them + */ + for (i = 0; i < sof->components_no; i++) + if (sof->comp[i].id > MXC_JPEG_MAX_COMPONENTS) { + valid = 0; + dev_err(dev, "Component %d has invalid ID: %d", + i, sof->comp[i].id); + } + if (!valid) + /* patch all comp IDs if at least one is invalid */ + for (i = 0; i < sof->components_no; i++) { + dev_warn(dev, "Component %d ID patched to: %d", + i, i + 1); + sof->comp[i].id = i + 1; + sos->comp[i].id = i + 1; + } + + return valid; +} + +static u32 mxc_jpeg_get_image_format(struct device *dev, + const struct v4l2_jpeg_header *header) +{ + int i; + u32 fourcc = 0; + + for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) + if (mxc_formats[i].subsampling == header->frame.subsampling && + mxc_formats[i].nc == header->frame.num_components) { + fourcc = mxc_formats[i].fourcc; + break; + } + if (fourcc == 0) { + dev_err(dev, "Could not identify image format nc=%d, subsampling=%d\n", + header->frame.num_components, + header->frame.subsampling); + return fourcc; + } + /* + * If the transform flag from APP14 marker is 0, images that are + * encoded with 3 components have RGB colorspace, see Recommendation + * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding + */ + if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_RGB24) { + if (header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB) + fourcc = V4L2_PIX_FMT_RGB24; + else + fourcc = V4L2_PIX_FMT_YUV24; + } + + return fourcc; +} + +static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, + u32 precision) +{ + /* Bytes distance between the leftmost pixels in two adjacent lines */ + if (q->fmt->fourcc == V4L2_PIX_FMT_JPEG) { + /* bytesperline unused for compressed formats */ + q->bytesperline[0] = 0; + q->bytesperline[1] = 0; + } else if (q->fmt->fourcc == V4L2_PIX_FMT_NV12) { + /* When the image format is planar the bytesperline value + * applies to the first plane and is divided by the same factor + * as the width field for the other planes + */ + q->bytesperline[0] = q->w * (precision / 8) * + (q->fmt->depth / 8); + q->bytesperline[1] = q->bytesperline[0]; + } else { + /* single plane formats */ + q->bytesperline[0] = q->w * (precision / 8) * + (q->fmt->depth / 8); + q->bytesperline[1] = 0; + } +} + +static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q) +{ + if (q->fmt->fourcc == V4L2_PIX_FMT_JPEG) { + /* if no sizeimage from user, assume worst jpeg compression */ + if (!q->sizeimage[0]) + q->sizeimage[0] = 6 * q->w * q->h; + q->sizeimage[1] = 0; + + if (q->sizeimage[0] > MXC_JPEG_MAX_SIZEIMAGE) + q->sizeimage[0] = MXC_JPEG_MAX_SIZEIMAGE; + + /* jpeg stream size must be multiple of 1K */ + q->sizeimage[0] = ALIGN(q->sizeimage[0], 1024); + } else { + q->sizeimage[0] = q->bytesperline[0] * q->h; + q->sizeimage[1] = 0; + if (q->fmt->fourcc == V4L2_PIX_FMT_NV12) + q->sizeimage[1] = q->sizeimage[0] / 2; + } +} + +static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, + u8 *src_addr, u32 size, bool *dht_needed) +{ + struct device *dev = ctx->mxc_jpeg->dev; + struct mxc_jpeg_q_data *q_data_out, *q_data_cap; + enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + bool src_chg = false; + u32 fourcc; + struct v4l2_jpeg_header header; + struct mxc_jpeg_sof *psof = NULL; + struct mxc_jpeg_sos *psos = NULL; + int ret; + + memset(&header, 0, sizeof(header)); + ret = v4l2_jpeg_parse_header((void *)src_addr, size, &header); + if (ret < 0) { + dev_err(dev, "Error parsing JPEG stream markers\n"); + return ret; + } + + /* if DHT marker present, no need to inject default one */ + *dht_needed = (header.num_dht == 0); + + q_data_out = mxc_jpeg_get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (q_data_out->w == 0 && q_data_out->h == 0) { + dev_warn(dev, "Invalid user resolution 0x0"); + dev_warn(dev, "Keeping resolution from JPEG: %dx%d", + header.frame.width, header.frame.height); + q_data_out->w = header.frame.width; + q_data_out->h = header.frame.height; + } else if (header.frame.width != q_data_out->w || + header.frame.height != q_data_out->h) { + dev_err(dev, + "Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)", + header.frame.width, header.frame.height, + q_data_out->w, q_data_out->h); + return -EINVAL; + } + if (header.frame.width % 8 != 0 || header.frame.height % 8 != 0) { + dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n", + header.frame.width, header.frame.height); + return -EINVAL; + } + if (header.frame.width > MXC_JPEG_MAX_WIDTH || + header.frame.height > MXC_JPEG_MAX_HEIGHT) { + dev_err(dev, "JPEG width or height should be <= 8192: %dx%d\n", + header.frame.width, header.frame.height); + return -EINVAL; + } + if (header.frame.width < MXC_JPEG_MIN_WIDTH || + header.frame.height < MXC_JPEG_MIN_HEIGHT) { + dev_err(dev, "JPEG width or height should be > 64: %dx%d\n", + header.frame.width, header.frame.height); + return -EINVAL; + } + if (header.frame.num_components > V4L2_JPEG_MAX_COMPONENTS) { + dev_err(dev, "JPEG number of components should be <=%d", + V4L2_JPEG_MAX_COMPONENTS); + return -EINVAL; + } + /* check and, if necessary, patch component IDs*/ + psof = (struct mxc_jpeg_sof *)header.sof.start; + psos = (struct mxc_jpeg_sos *)header.sos.start; + if (!mxc_jpeg_valid_comp_id(dev, psof, psos)) + dev_warn(dev, "JPEG component ids should be 0-3 or 1-4"); + + fourcc = mxc_jpeg_get_image_format(dev, &header); + if (fourcc == 0) + return -EINVAL; + + /* + * set-up the capture queue with the pixelformat and resolution + * detected from the jpeg output stream + */ + q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type); + if (q_data_cap->w != header.frame.width || + q_data_cap->h != header.frame.height) + src_chg = true; + q_data_cap->w = header.frame.width; + q_data_cap->h = header.frame.height; + q_data_cap->fmt = mxc_jpeg_find_format(ctx, fourcc); + q_data_cap->w_adjusted = q_data_cap->w; + q_data_cap->h_adjusted = q_data_cap->h; + /* + * align up the resolution for CAST IP, + * but leave the buffer resolution unchanged + */ + v4l_bound_align_image(&q_data_cap->w_adjusted, + q_data_cap->w_adjusted, /* adjust up */ + MXC_JPEG_MAX_WIDTH, + q_data_cap->fmt->h_align, + &q_data_cap->h_adjusted, + q_data_cap->h_adjusted, /* adjust up */ + MXC_JPEG_MAX_HEIGHT, + q_data_cap->fmt->v_align, + 0); + dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%c%c%c%c\n", + q_data_cap->w, q_data_cap->h, + q_data_cap->w_adjusted, q_data_cap->h_adjusted, + (fourcc & 0xff), + (fourcc >> 8) & 0xff, + (fourcc >> 16) & 0xff, + (fourcc >> 24) & 0xff); + + /* setup bytesperline/sizeimage for capture queue */ + mxc_jpeg_bytesperline(q_data_cap, header.frame.precision); + mxc_jpeg_sizeimage(q_data_cap); + + /* + * if the CAPTURE format was updated with new values, regardless of + * whether they match the values set by the client or not, signal + * a source change event + */ + if (src_chg) + notify_src_chg(ctx); + + return 0; +} + +static void mxc_jpeg_buf_queue(struct vb2_buffer *vb) +{ + int ret; + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct mxc_jpeg_src_buf *jpeg_src_buf; + + if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + goto end; + + /* for V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE */ + if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE) + goto end; + + jpeg_src_buf = vb2_to_mxc_buf(vb); + jpeg_src_buf->jpeg_parse_error = false; + ret = mxc_jpeg_parse(ctx, + (u8 *)vb2_plane_vaddr(vb, 0), + vb2_get_plane_payload(vb, 0), + &jpeg_src_buf->dht_needed); + if (ret) + jpeg_src_buf->jpeg_parse_error = true; + +end: + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static int mxc_jpeg_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct mxc_jpeg_q_data *q_data = NULL; + struct device *dev = ctx->mxc_jpeg->dev; + unsigned long sizeimage; + int i; + + vbuf->field = V4L2_FIELD_NONE; + + q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type); + if (!q_data) + return -EINVAL; + for (i = 0; i < q_data->fmt->colplanes; i++) { + sizeimage = q_data->sizeimage[i]; + if (vb2_plane_size(vb, i) < sizeimage) { + dev_err(dev, "plane %d too small (%lu < %lu)", + i, vb2_plane_size(vb, i), sizeimage); + return -EINVAL; + } + vb2_set_plane_payload(vb, i, sizeimage); + } + return 0; +} + +static const struct vb2_ops mxc_jpeg_qops = { + .queue_setup = mxc_jpeg_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_out_validate = mxc_jpeg_buf_out_validate, + .buf_prepare = mxc_jpeg_buf_prepare, + .start_streaming = mxc_jpeg_start_streaming, + .stop_streaming = mxc_jpeg_stop_streaming, + .buf_queue = mxc_jpeg_buf_queue, +}; + +static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct mxc_jpeg_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct mxc_jpeg_src_buf); + src_vq->ops = &mxc_jpeg_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->mxc_jpeg->lock; + src_vq->dev = ctx->mxc_jpeg->dev; + src_vq->allow_zero_bytesused = 1; /* keep old userspace apps working */ + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &mxc_jpeg_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->mxc_jpeg->lock; + dst_vq->dev = ctx->mxc_jpeg->dev; + + ret = vb2_queue_init(dst_vq); + return ret; +} + +static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx) +{ + struct mxc_jpeg_q_data *out_q = &ctx->out_q; + struct mxc_jpeg_q_data *cap_q = &ctx->cap_q; + struct mxc_jpeg_q_data *q[2] = {out_q, cap_q}; + int i; + + if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) { + out_q->fmt = mxc_jpeg_find_format(ctx, MXC_JPEG_DEFAULT_PFMT); + cap_q->fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG); + } else { + out_q->fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG); + cap_q->fmt = mxc_jpeg_find_format(ctx, MXC_JPEG_DEFAULT_PFMT); + } + + for (i = 0; i < 2; i++) { + q[i]->w = MXC_JPEG_DEFAULT_WIDTH; + q[i]->h = MXC_JPEG_DEFAULT_HEIGHT; + q[i]->w_adjusted = MXC_JPEG_DEFAULT_WIDTH; + q[i]->h_adjusted = MXC_JPEG_DEFAULT_HEIGHT; + mxc_jpeg_bytesperline(q[i], 8); + mxc_jpeg_sizeimage(q[i]); + } +} + +static int mxc_jpeg_open(struct file *file) +{ + struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file); + struct video_device *mxc_vfd = video_devdata(file); + struct device *dev = mxc_jpeg->dev; + struct mxc_jpeg_ctx *ctx; + int ret = 0; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (mutex_lock_interruptible(&mxc_jpeg->lock)) { + ret = -ERESTARTSYS; + goto free; + } + + v4l2_fh_init(&ctx->fh, mxc_vfd); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + ctx->mxc_jpeg = mxc_jpeg; + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(mxc_jpeg->m2m_dev, ctx, + mxc_jpeg_queue_init); + + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + goto error; + } + + mxc_jpeg_set_default_params(ctx); + ctx->slot = MXC_MAX_SLOTS; /* slot not allocated yet */ + + if (mxc_jpeg->mode == MXC_JPEG_DECODE) + dev_dbg(dev, "Opened JPEG decoder instance %p\n", ctx); + else + dev_dbg(dev, "Opened JPEG encoder instance %p\n", ctx); + mutex_unlock(&mxc_jpeg->lock); + + return 0; + +error: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + mutex_unlock(&mxc_jpeg->lock); +free: + kfree(ctx); + return ret; +} + +static int mxc_jpeg_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file); + + strscpy(cap->driver, MXC_JPEG_NAME " codec", sizeof(cap->driver)); + strscpy(cap->card, MXC_JPEG_NAME " codec", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(mxc_jpeg->dev)); + cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +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); + + if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) + return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, + MXC_JPEG_FMT_TYPE_ENC); + else + return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, + MXC_JPEG_FMT_TYPE_RAW); +} + +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); + + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) + return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, + MXC_JPEG_FMT_TYPE_ENC); + else + return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, + MXC_JPEG_FMT_TYPE_RAW); +} + +static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt, + struct mxc_jpeg_ctx *ctx, int q_type) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *pfmt; + u32 w = (pix_mp->width < MXC_JPEG_MAX_WIDTH) ? + pix_mp->width : MXC_JPEG_MAX_WIDTH; + u32 h = (pix_mp->height < MXC_JPEG_MAX_HEIGHT) ? + pix_mp->height : MXC_JPEG_MAX_HEIGHT; + int i; + struct mxc_jpeg_q_data tmp_q; + + memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->num_planes = fmt->colplanes; + pix_mp->pixelformat = fmt->fourcc; + + /* + * use MXC_JPEG_H_ALIGN instead of fmt->v_align, for vertical + * alignment, to loosen up the alignment to multiple of 8, + * otherwise NV12-1080p fails as 1080 is not a multiple of 16 + */ + v4l_bound_align_image(&w, + MXC_JPEG_MIN_WIDTH, + w, /* adjust downwards*/ + fmt->h_align, + &h, + MXC_JPEG_MIN_HEIGHT, + h, /* adjust downwards*/ + MXC_JPEG_H_ALIGN, + 0); + pix_mp->width = w; /* negotiate the width */ + pix_mp->height = h; /* negotiate the height */ + + /* get user input into the tmp_q */ + tmp_q.w = w; + tmp_q.h = h; + tmp_q.fmt = fmt; + for (i = 0; i < pix_mp->num_planes; i++) { + pfmt = &pix_mp->plane_fmt[i]; + tmp_q.bytesperline[i] = pfmt->bytesperline; + tmp_q.sizeimage[i] = pfmt->sizeimage; + } + + /* calculate bytesperline & sizeimage into the tmp_q */ + mxc_jpeg_bytesperline(&tmp_q, 8); + mxc_jpeg_sizeimage(&tmp_q); + + /* adjust user format according to our calculations */ + for (i = 0; i < pix_mp->num_planes; i++) { + pfmt = &pix_mp->plane_fmt[i]; + memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); + pfmt->bytesperline = tmp_q.bytesperline[i]; + pfmt->sizeimage = tmp_q.sizeimage[i]; + } + + /* fix colorspace information to sRGB for both output & capture */ + pix_mp->colorspace = V4L2_COLORSPACE_SRGB; + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix_mp->xfer_func = V4L2_XFER_FUNC_SRGB; + /* + * this hardware does not change the range of the samples + * but since inside JPEG the YUV quantization is full-range, + * this driver will always use full-range for the raw frames, too + */ + pix_mp->quantization = V4L2_QUANTIZATION_FULL_RANGE; + + return 0; +} + +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_dev *jpeg = ctx->mxc_jpeg; + struct device *dev = jpeg->dev; + struct mxc_jpeg_fmt *fmt; + u32 fourcc = f->fmt.pix_mp.pixelformat; + + int q_type = (jpeg->mode == MXC_JPEG_DECODE) ? + MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC; + + if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { + dev_err(dev, "TRY_FMT with Invalid type: %d\n", f->type); + return -EINVAL; + } + + fmt = mxc_jpeg_find_format(ctx, fourcc); + if (!fmt || fmt->flags != q_type) { + dev_warn(dev, "Format not supported: %c%c%c%c, use the default.\n", + (fourcc & 0xff), + (fourcc >> 8) & 0xff, + (fourcc >> 16) & 0xff, + (fourcc >> 24) & 0xff); + f->fmt.pix_mp.pixelformat = (jpeg->mode == MXC_JPEG_DECODE) ? + MXC_JPEG_DEFAULT_PFMT : V4L2_PIX_FMT_JPEG; + fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat); + } + return mxc_jpeg_try_fmt(f, fmt, ctx, q_type); +} + +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_dev *jpeg = ctx->mxc_jpeg; + struct device *dev = jpeg->dev; + struct mxc_jpeg_fmt *fmt; + u32 fourcc = f->fmt.pix_mp.pixelformat; + + int q_type = (jpeg->mode == MXC_JPEG_ENCODE) ? + MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC; + + if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { + dev_err(dev, "TRY_FMT with Invalid type: %d\n", f->type); + return -EINVAL; + } + + fmt = mxc_jpeg_find_format(ctx, fourcc); + if (!fmt || fmt->flags != q_type) { + dev_warn(dev, "Format not supported: %c%c%c%c, use the default.\n", + (fourcc & 0xff), + (fourcc >> 8) & 0xff, + (fourcc >> 16) & 0xff, + (fourcc >> 24) & 0xff); + f->fmt.pix_mp.pixelformat = (jpeg->mode == MXC_JPEG_ENCODE) ? + MXC_JPEG_DEFAULT_PFMT : V4L2_PIX_FMT_JPEG; + fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat); + } + return mxc_jpeg_try_fmt(f, fmt, ctx, q_type); +} + +static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx, + struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct mxc_jpeg_q_data *q_data = NULL; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg; + int i; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = mxc_jpeg_get_q_data(ctx, f->type); + + if (vb2_is_busy(vq)) { + v4l2_err(&jpeg->v4l2_dev, "queue busy\n"); + return -EBUSY; + } + + q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat); + q_data->w = pix_mp->width; + q_data->h = pix_mp->height; + + q_data->w_adjusted = q_data->w; + q_data->h_adjusted = q_data->h; + if (jpeg->mode == MXC_JPEG_DECODE) { + /* + * align up the resolution for CAST IP, + * but leave the buffer resolution unchanged + */ + v4l_bound_align_image(&q_data->w_adjusted, + q_data->w_adjusted, /* adjust upwards */ + MXC_JPEG_MAX_WIDTH, + q_data->fmt->h_align, + &q_data->h_adjusted, + q_data->h_adjusted, /* adjust upwards */ + MXC_JPEG_MAX_HEIGHT, + q_data->fmt->v_align, + 0); + } else { + /* + * align down the resolution for CAST IP, + * but leave the buffer resolution unchanged + */ + v4l_bound_align_image(&q_data->w_adjusted, + MXC_JPEG_MIN_WIDTH, + q_data->w_adjusted, /* adjust downwards*/ + q_data->fmt->h_align, + &q_data->h_adjusted, + MXC_JPEG_MIN_HEIGHT, + q_data->h_adjusted, /* adjust downwards*/ + q_data->fmt->v_align, + 0); + } + + for (i = 0; i < pix_mp->num_planes; i++) { + q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline; + q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage; + } + + return 0; +} + +static int mxc_jpeg_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = mxc_jpeg_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); +} + +static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = mxc_jpeg_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); +} + +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_dev *jpeg = ctx->mxc_jpeg; + struct device *dev = jpeg->dev; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type); + int i; + + if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { + dev_err(dev, "G_FMT with Invalid type: %d\n", f->type); + return -EINVAL; + } + + pix_mp->pixelformat = q_data->fmt->fourcc; + pix_mp->width = q_data->w; + pix_mp->height = q_data->h; + pix_mp->field = V4L2_FIELD_NONE; + + /* fix colorspace information to sRGB for both output & capture */ + pix_mp->colorspace = V4L2_COLORSPACE_SRGB; + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix_mp->xfer_func = V4L2_XFER_FUNC_SRGB; + pix_mp->quantization = V4L2_QUANTIZATION_FULL_RANGE; + + pix_mp->num_planes = q_data->fmt->colplanes; + for (i = 0; i < pix_mp->num_planes; i++) { + pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i]; + pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i]; + } + + return 0; +} + +static int mxc_jpeg_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + default: + return -EINVAL; + } +} + +static int mxc_jpeg_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct v4l2_fh *fh = file->private_data; + struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct device *dev = ctx->mxc_jpeg->dev; + int num_src_ready = v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx); + int ret; + + dev_dbg(dev, "DQBUF type=%d, index=%d", buf->type, buf->index); + if (ctx->stopping == 1 && num_src_ready == 0) { + /* No more src bufs, notify app EOS */ + notify_eos(ctx); + ctx->stopping = 0; + } + + ret = v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf); + + return ret; +} + +static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = { + .vidioc_querycap = mxc_jpeg_querycap, + .vidioc_enum_fmt_vid_cap = mxc_jpeg_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = mxc_jpeg_enum_fmt_vid_out, + + .vidioc_try_fmt_vid_cap_mplane = mxc_jpeg_try_fmt_vid_cap, + .vidioc_try_fmt_vid_out_mplane = mxc_jpeg_try_fmt_vid_out, + + .vidioc_s_fmt_vid_cap_mplane = mxc_jpeg_s_fmt_vid_cap, + .vidioc_s_fmt_vid_out_mplane = mxc_jpeg_s_fmt_vid_out, + + .vidioc_g_fmt_vid_cap_mplane = mxc_jpeg_g_fmt_vid, + .vidioc_g_fmt_vid_out_mplane = mxc_jpeg_g_fmt_vid, + + .vidioc_subscribe_event = mxc_jpeg_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, + .vidioc_decoder_cmd = mxc_jpeg_decoder_cmd, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = mxc_jpeg_encoder_cmd, + + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = mxc_jpeg_dqbuf, + + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, +}; + +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 device *dev = mxc_jpeg->dev; + + mutex_lock(&mxc_jpeg->lock); + if (mxc_jpeg->mode == MXC_JPEG_DECODE) + dev_dbg(dev, "Release JPEG decoder instance on slot %d.", + ctx->slot); + else + dev_dbg(dev, "Release JPEG encoder instance on slot %d.", + ctx->slot); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + mutex_unlock(&mxc_jpeg->lock); + + return 0; +} + +static const struct v4l2_file_operations mxc_jpeg_fops = { + .owner = THIS_MODULE, + .open = mxc_jpeg_open, + .release = mxc_jpeg_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static struct v4l2_m2m_ops mxc_jpeg_m2m_ops = { + .device_run = mxc_jpeg_device_run, +}; + +static void mxc_jpeg_detach_pm_domains(struct mxc_jpeg_dev *jpeg) +{ + int i; + + for (i = 0; i < jpeg->num_domains; i++) { + if (jpeg->pd_link[i] && !IS_ERR(jpeg->pd_link[i])) + device_link_del(jpeg->pd_link[i]); + if (jpeg->pd_dev[i] && !IS_ERR(jpeg->pd_dev[i])) + dev_pm_domain_detach(jpeg->pd_dev[i], true); + jpeg->pd_dev[i] = NULL; + jpeg->pd_link[i] = NULL; + } +} + +static int mxc_jpeg_attach_pm_domains(struct mxc_jpeg_dev *jpeg) +{ + struct device *dev = jpeg->dev; + struct device_node *np = jpeg->pdev->dev.of_node; + int i; + int ret; + + jpeg->num_domains = of_count_phandle_with_args(np, "power-domains", + "#power-domain-cells"); + if (jpeg->num_domains < 0) { + dev_err(dev, "No power domains defined for jpeg node\n"); + return jpeg->num_domains; + } + + jpeg->pd_dev = devm_kmalloc_array(dev, jpeg->num_domains, + sizeof(*jpeg->pd_dev), GFP_KERNEL); + if (!jpeg->pd_dev) + return -ENOMEM; + + jpeg->pd_link = devm_kmalloc_array(dev, jpeg->num_domains, + sizeof(*jpeg->pd_link), GFP_KERNEL); + if (!jpeg->pd_link) + return -ENOMEM; + + for (i = 0; i < jpeg->num_domains; i++) { + jpeg->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); + if (IS_ERR(jpeg->pd_dev[i])) { + ret = PTR_ERR(jpeg->pd_dev[i]); + goto fail; + } + + jpeg->pd_link[i] = device_link_add(dev, jpeg->pd_dev[i], + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!jpeg->pd_link[i]) { + ret = -EINVAL; + goto fail; + } + } + + return 0; +fail: + mxc_jpeg_detach_pm_domains(jpeg); + return ret; +} + +static int mxc_jpeg_probe(struct platform_device *pdev) +{ + struct mxc_jpeg_dev *jpeg; + struct device *dev = &pdev->dev; + struct resource *res; + int dec_irq; + int ret; + int mode; + const struct of_device_id *of_id; + unsigned int slot; + + of_id = of_match_node(mxc_jpeg_match, dev->of_node); + mode = *(const int *)of_id->data; + + jpeg = devm_kzalloc(dev, sizeof(struct mxc_jpeg_dev), GFP_KERNEL); + if (!jpeg) + return -ENOMEM; + + mutex_init(&jpeg->lock); + spin_lock_init(&jpeg->hw_lock); + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "No suitable DMA available.\n"); + goto err_irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + jpeg->base_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(jpeg->base_reg)) + return PTR_ERR(jpeg->base_reg); + + for (slot = 0; slot < MXC_MAX_SLOTS; slot++) { + dec_irq = platform_get_irq(pdev, slot); + if (dec_irq < 0) { + dev_err(&pdev->dev, "Failed to get irq %d\n", dec_irq); + ret = dec_irq; + goto err_irq; + } + ret = devm_request_irq(&pdev->dev, dec_irq, mxc_jpeg_dec_irq, + 0, pdev->name, jpeg); + if (ret) { + dev_err(&pdev->dev, "Failed to request irq %d (%d)\n", + dec_irq, ret); + goto err_irq; + } + } + + jpeg->pdev = pdev; + jpeg->dev = dev; + jpeg->mode = mode; + + ret = mxc_jpeg_attach_pm_domains(jpeg); + if (ret < 0) { + dev_err(dev, "failed to attach power domains %d\n", ret); + return ret; + } + + /* v4l2 */ + ret = v4l2_device_register(dev, &jpeg->v4l2_dev); + if (ret) { + dev_err(dev, "failed to register v4l2 device\n"); + goto err_register; + } + jpeg->m2m_dev = v4l2_m2m_init(&mxc_jpeg_m2m_ops); + if (IS_ERR(jpeg->m2m_dev)) { + dev_err(dev, "failed to register v4l2 device\n"); + ret = PTR_ERR(jpeg->m2m_dev); + goto err_m2m; + } + + jpeg->dec_vdev = video_device_alloc(); + if (!jpeg->dec_vdev) { + dev_err(dev, "failed to register v4l2 device\n"); + ret = -ENOMEM; + goto err_vdev_alloc; + } + if (mode == MXC_JPEG_ENCODE) + snprintf(jpeg->dec_vdev->name, + sizeof(jpeg->dec_vdev->name), + "%s-enc", MXC_JPEG_NAME); + else + snprintf(jpeg->dec_vdev->name, + sizeof(jpeg->dec_vdev->name), + "%s-dec", MXC_JPEG_NAME); + + jpeg->dec_vdev->fops = &mxc_jpeg_fops; + jpeg->dec_vdev->ioctl_ops = &mxc_jpeg_ioctl_ops; + jpeg->dec_vdev->minor = -1; + jpeg->dec_vdev->release = video_device_release; + jpeg->dec_vdev->lock = &jpeg->lock; /* lock for ioctl serialization */ + jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev; + jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M; + jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_M2M_MPLANE; + if (mode == MXC_JPEG_ENCODE) { + v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_TRY_DECODER_CMD); + } else { + v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_ENCODER_CMD); + v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_TRY_ENCODER_CMD); + } + ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(dev, "failed to register video device\n"); + goto err_vdev_register; + } + video_set_drvdata(jpeg->dec_vdev, jpeg); + if (mode == MXC_JPEG_ENCODE) + v4l2_info(&jpeg->v4l2_dev, + "encoder device registered as /dev/video%d (%d,%d)\n", + jpeg->dec_vdev->num, VIDEO_MAJOR, + jpeg->dec_vdev->minor); + else + v4l2_info(&jpeg->v4l2_dev, + "decoder device registered as /dev/video%d (%d,%d)\n", + jpeg->dec_vdev->num, VIDEO_MAJOR, + jpeg->dec_vdev->minor); + + platform_set_drvdata(pdev, jpeg); + + return 0; + +err_vdev_register: + video_device_release(jpeg->dec_vdev); + +err_vdev_alloc: + v4l2_m2m_release(jpeg->m2m_dev); + +err_m2m: + v4l2_device_unregister(&jpeg->v4l2_dev); + +err_register: +err_irq: + return ret; +} + +static int mxc_jpeg_remove(struct platform_device *pdev) +{ + unsigned int slot; + struct mxc_jpeg_dev *jpeg = platform_get_drvdata(pdev); + + for (slot = 0; slot < MXC_MAX_SLOTS; slot++) + mxc_jpeg_free_slot_data(jpeg, slot); + + video_unregister_device(jpeg->dec_vdev); + v4l2_m2m_release(jpeg->m2m_dev); + v4l2_device_unregister(&jpeg->v4l2_dev); + mxc_jpeg_detach_pm_domains(jpeg); + + return 0; +} + +MODULE_DEVICE_TABLE(of, mxc_jpeg_match); + +static struct platform_driver mxc_jpeg_driver = { + .probe = mxc_jpeg_probe, + .remove = mxc_jpeg_remove, + .driver = { + .name = "mxc-jpeg", + .of_match_table = mxc_jpeg_match, + }, +}; +module_platform_driver(mxc_jpeg_driver); + +MODULE_AUTHOR("Zhengyu Shen <zhengyu.shen_1@nxp.com>"); +MODULE_AUTHOR("Mirela Rabulea <mirela.rabulea@nxp.com>"); +MODULE_DESCRIPTION("V4L2 driver for i.MX8 QXP/QM JPEG encoder/decoder"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/imx-jpeg/mxc-jpeg.h new file mode 100644 index 000000000000..7697de490d2e --- /dev/null +++ b/drivers/media/platform/imx-jpeg/mxc-jpeg.h @@ -0,0 +1,180 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver + * + * Copyright 2018-2019 NXP + */ + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fh.h> + +#ifndef _MXC_JPEG_CORE_H +#define _MXC_JPEG_CORE_H + +#define MXC_JPEG_NAME "mxc-jpeg" +#define MXC_JPEG_FMT_TYPE_ENC 0 +#define MXC_JPEG_FMT_TYPE_RAW 1 +#define MXC_JPEG_DEFAULT_WIDTH 1280 +#define MXC_JPEG_DEFAULT_HEIGHT 720 +#define MXC_JPEG_DEFAULT_PFMT V4L2_PIX_FMT_RGB24 +#define MXC_JPEG_MIN_WIDTH 64 +#define MXC_JPEG_MIN_HEIGHT 64 +#define MXC_JPEG_MAX_WIDTH 0x2000 +#define MXC_JPEG_MAX_HEIGHT 0x2000 +#define MXC_JPEG_MAX_CFG_STREAM 0x1000 +#define MXC_JPEG_H_ALIGN 3 +#define MXC_JPEG_W_ALIGN 3 +#define MXC_JPEG_MAX_SIZEIMAGE 0xFFFFFC00 +#define MXC_JPEG_MAX_PLANES 2 + +enum mxc_jpeg_enc_state { + MXC_JPEG_ENCODING = 0, /* jpeg encode phase */ + MXC_JPEG_ENC_CONF = 1, /* jpeg encoder config phase */ +}; + +enum mxc_jpeg_mode { + MXC_JPEG_DECODE = 0, /* jpeg decode mode */ + MXC_JPEG_ENCODE = 1, /* jpeg encode mode */ +}; + +/** + * struct mxc_jpeg_fmt - driver's internal color format data + * @name: format description + * @fourcc: fourcc code, 0 if not applicable + * @subsampling: subsampling of jpeg components + * @nc: number of color components + * @depth: number of bits per pixel + * @colplanes: number of color planes (1 for packed formats) + * @h_align: horizontal alignment order (align to 2^h_align) + * @v_align: vertical alignment order (align to 2^v_align) + * @flags: flags describing format applicability + */ +struct mxc_jpeg_fmt { + char *name; + u32 fourcc; + enum v4l2_jpeg_chroma_subsampling subsampling; + int nc; + int depth; + int colplanes; + int h_align; + int v_align; + u32 flags; +}; + +struct mxc_jpeg_desc { + u32 next_descpt_ptr; + u32 buf_base0; + u32 buf_base1; + u32 line_pitch; + u32 stm_bufbase; + u32 stm_bufsize; + u32 imgsize; + u32 stm_ctrl; +} __packed; + +struct mxc_jpeg_q_data { + struct mxc_jpeg_fmt *fmt; + u32 sizeimage[MXC_JPEG_MAX_PLANES]; + u32 bytesperline[MXC_JPEG_MAX_PLANES]; + int w; + int w_adjusted; + int h; + int h_adjusted; + unsigned int sequence; +}; + +struct mxc_jpeg_ctx { + struct mxc_jpeg_dev *mxc_jpeg; + struct mxc_jpeg_q_data out_q; + struct mxc_jpeg_q_data cap_q; + struct v4l2_fh fh; + enum mxc_jpeg_enc_state enc_state; + unsigned int stopping; + unsigned int slot; +}; + +struct mxc_jpeg_slot_data { + bool used; + struct mxc_jpeg_desc *desc; // enc/dec descriptor + struct mxc_jpeg_desc *cfg_desc; // configuration descriptor + void *cfg_stream_vaddr; // configuration bitstream virtual address + unsigned int cfg_stream_size; + dma_addr_t desc_handle; + dma_addr_t cfg_desc_handle; // configuration descriptor dma address + dma_addr_t cfg_stream_handle; // configuration bitstream dma address +}; + +struct mxc_jpeg_dev { + spinlock_t hw_lock; /* hardware access lock */ + unsigned int mode; + struct mutex lock; /* v4l2 ioctls serialization */ + struct platform_device *pdev; + struct device *dev; + void __iomem *base_reg; + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *dec_vdev; + struct mxc_jpeg_slot_data slot_data[MXC_MAX_SLOTS]; + int num_domains; + struct device **pd_dev; + struct device_link **pd_link; +}; + +/** + * struct mxc_jpeg_sof_comp - JPEG Start Of Frame component fields + * @id: component id + * @v: vertical sampling + * @h: horizontal sampling + * @quantization_table_no: id of quantization table + */ +struct mxc_jpeg_sof_comp { + u8 id; + u8 v :4; + u8 h :4; + u8 quantization_table_no; +} __packed; + +#define MXC_JPEG_MAX_COMPONENTS 4 +/** + * struct mxc_jpeg_sof - JPEG Start Of Frame marker fields + * @length: Start of Frame length + * @precision: precision (bits per pixel per color component) + * @height: image height + * @width: image width + * @components_no: number of color components + * @comp: component fields for each color component + */ +struct mxc_jpeg_sof { + u16 length; + u8 precision; + u16 height, width; + u8 components_no; + struct mxc_jpeg_sof_comp comp[MXC_JPEG_MAX_COMPONENTS]; +} __packed; + +/** + * struct mxc_jpeg_sos_comp - JPEG Start Of Scan component fields + * @id: component id + * @huffman_table_no: id of the Huffman table + */ +struct mxc_jpeg_sos_comp { + u8 id; /*component id*/ + u8 huffman_table_no; +} __packed; + +/** + * struct mxc_jpeg_sos - JPEG Start Of Scan marker fields + * @length: Start of Frame length + * @components_no: number of color components + * @comp: SOS component fields for each color component + * @ignorable_bytes: ignorable bytes + */ +struct mxc_jpeg_sos { + u16 length; + u8 components_no; + struct mxc_jpeg_sos_comp comp[MXC_JPEG_MAX_COMPONENTS]; + u8 ignorable_bytes[3]; +} __packed; + +#endif diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c index 08d76eb05ed1..4321edc0c23d 100644 --- a/drivers/media/platform/imx-pxp.c +++ b/drivers/media/platform/imx-pxp.c @@ -1654,11 +1654,8 @@ static int pxp_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->mmio = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dev->mmio)) { - ret = PTR_ERR(dev->mmio); - dev_err(&pdev->dev, "Failed to map register space: %d\n", ret); - return ret; - } + if (IS_ERR(dev->mmio)) + return PTR_ERR(dev->mmio); irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -1755,7 +1752,7 @@ static struct platform_driver pxp_driver = { .remove = pxp_remove, .driver = { .name = MEM2MEM_NAME, - .of_match_table = of_match_ptr(pxp_dt_ids), + .of_match_table = pxp_dt_ids, }, }; diff --git a/drivers/media/platform/meson/ge2d/ge2d.c b/drivers/media/platform/meson/ge2d/ge2d.c index 153612ca96fc..a1393fefa8ae 100644 --- a/drivers/media/platform/meson/ge2d/ge2d.c +++ b/drivers/media/platform/meson/ge2d/ge2d.c @@ -757,7 +757,7 @@ static int ge2d_s_ctrl(struct v4l2_ctrl *ctrl) if (ctrl->val == 90) { ctx->hflip = 0; - ctx->vflip = 0; + ctx->vflip = 1; ctx->xy_swap = 1; } else if (ctrl->val == 180) { ctx->hflip = 1; @@ -765,7 +765,7 @@ static int ge2d_s_ctrl(struct v4l2_ctrl *ctrl) ctx->xy_swap = 0; } else if (ctrl->val == 270) { ctx->hflip = 1; - ctx->vflip = 1; + ctx->vflip = 0; ctx->xy_swap = 1; } else { ctx->hflip = 0; diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h index 68e634f02e00..595f7f10c9fd 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h @@ -45,11 +45,11 @@ enum mtk_jpeg_ctx_state { }; /** - * mtk_jpeg_variant - mtk jpeg driver variant + * struct mtk_jpeg_variant - mtk jpeg driver variant * @clks: clock names * @num_clks: numbers of clock - * @format: jpeg driver's internal color format - * @num_format: number of format + * @formats: jpeg driver's internal color format + * @num_formats: number of formats * @qops: the callback of jpeg vb2_ops * @irq_handler: jpeg irq handler callback * @hw_reset: jpeg hardware reset callback @@ -75,7 +75,7 @@ struct mtk_jpeg_variant { }; /** - * struct mt_jpeg - JPEG IP abstraction + * struct mtk_jpeg_dev - JPEG IP abstraction * @lock: the mutex protecting this structure * @hw_lock: spinlock protecting the hw device resource * @workqueue: decode work queue @@ -105,7 +105,7 @@ struct mtk_jpeg_dev { }; /** - * struct jpeg_fmt - driver's internal color format data + * struct mtk_jpeg_fmt - driver's internal color format data * @fourcc: the fourcc code, 0 if not applicable * @hw_format: hardware format value * @h_sample: horizontal sample count of plane in 4 * 4 pixel image @@ -127,7 +127,7 @@ struct mtk_jpeg_fmt { }; /** - * mtk_jpeg_q_data - parameters of one queue + * struct mtk_jpeg_q_data - parameters of one queue * @fmt: driver-specific format of this queue * @pix_mp: multiplanar format * @enc_crop_rect: jpeg encoder crop information @@ -139,7 +139,7 @@ struct mtk_jpeg_q_data { }; /** - * mtk_jpeg_ctx - the device context data + * struct mtk_jpeg_ctx - the device context data * @jpeg: JPEG IP device for this context * @out_q: source (output) queue information * @cap_q: destination (capture) queue queue information diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h index 1bf0242cce46..7897766c96bb 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h @@ -19,7 +19,6 @@ enum mtk_mdp_comp_type { MTK_MDP_RSZ, MTK_MDP_WDMA, MTK_MDP_WROT, - MTK_MDP_COMP_TYPE_MAX, }; /** diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h index a7da14b97077..a6e6dc36307b 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h @@ -52,8 +52,8 @@ struct mtk_mdp_pix_align { * @depth: per plane driver's private 'number of bits per pixel' * @row_depth: per plane driver's private 'number of bits per pixel per row' * @flags: flags indicating which operation mode format applies to - MTK_MDP_FMT_FLAG_OUTPUT is used in OUTPUT stream - MTK_MDP_FMT_FLAG_CAPTURE is used in CAPTURE stream + * MTK_MDP_FMT_FLAG_OUTPUT is used in OUTPUT stream + * MTK_MDP_FMT_FLAG_CAPTURE is used in CAPTURE stream * @align: pointer to a pixel alignment struct, NULL if using default value */ struct mtk_mdp_fmt { @@ -168,14 +168,14 @@ struct mtk_mdp_dev { }; /** - * mtk_mdp_ctx - the device context data + * struct mtk_mdp_ctx - the device context data * @list: link to ctx_list of mtk_mdp_dev * @s_frame: source frame properties * @d_frame: destination frame properties * @id: index of the context that this structure describes * @flags: additional flags for image conversion * @state: flags to keep track of user configuration - Protected by slock + * Protected by slock * @rotation: rotates the image by specified angle * @hflip: mirror the picture horizontally * @vflip: mirror the picture vertically @@ -183,7 +183,7 @@ struct mtk_mdp_dev { * @m2m_ctx: memory-to-memory device context * @fh: v4l2 file handle * @ctrl_handler: v4l2 controls handler - * @ctrls image processor control set + * @ctrls: image processor control set * @ctrls_rdy: true if the control handler is initialized * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 3dd010cba23e..d03cca95e99b 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -59,12 +59,12 @@ enum mtk_instance_type { /** * enum mtk_instance_state - The state of an MTK Vcodec instance. - * @MTK_STATE_FREE - default state when instance is created - * @MTK_STATE_INIT - vcodec instance is initialized - * @MTK_STATE_HEADER - vdec had sps/pps header parsed or venc + * @MTK_STATE_FREE: default state when instance is created + * @MTK_STATE_INIT: vcodec instance is initialized + * @MTK_STATE_HEADER: vdec had sps/pps header parsed or venc * had sps/pps header encoded - * @MTK_STATE_FLUSH - vdec is flushing. Only used by decoder - * @MTK_STATE_ABORT - vcodec should be aborted + * @MTK_STATE_FLUSH: vdec is flushing. Only used by decoder + * @MTK_STATE_ABORT: vcodec should be aborted */ enum mtk_instance_state { MTK_STATE_FREE = 0, @@ -75,7 +75,7 @@ enum mtk_instance_state { }; /** - * struct mtk_encode_param - General encoding parameters type + * enum mtk_encode_param - General encoding parameters type */ enum mtk_encode_param { MTK_ENCODE_PARAM_NONE = 0, @@ -112,7 +112,7 @@ struct mtk_codec_framesizes { }; /** - * struct mtk_q_type - Type of queue + * enum mtk_q_type - Type of queue */ enum mtk_q_type { MTK_Q_DATA_SRC = 0, @@ -193,7 +193,6 @@ struct mtk_vcodec_pm { struct mtk_vcodec_clk venc_clk; struct device *larbvenc; - struct device *larbvenclt; struct device *dev; struct mtk_vcodec_dev *mtkdev; }; @@ -311,25 +310,25 @@ enum mtk_chip { * @chip: chip this encoder is compatible with * * @uses_ext: whether the encoder uses the extended firmware messaging format - * @has_lt_irq: whether the encoder uses the LT irq * @min_birate: minimum supported encoding bitrate * @max_bitrate: maximum supported encoding bitrate * @capture_formats: array of supported capture formats * @num_capture_formats: number of entries in capture_formats * @output_formats: array of supported output formats * @num_output_formats: number of entries in output_formats + * @core_id: stand for h264 or vp8 encode index */ struct mtk_vcodec_enc_pdata { enum mtk_chip chip; bool uses_ext; - bool has_lt_irq; unsigned long min_bitrate; unsigned long max_bitrate; const struct mtk_video_fmt *capture_formats; size_t num_capture_formats; const struct mtk_video_fmt *output_formats; size_t num_output_formats; + int core_id; }; #define MTK_ENC_CTX_IS_EXT(ctx) ((ctx)->dev->venc_pdata->uses_ext) @@ -361,7 +360,6 @@ struct mtk_vcodec_enc_pdata { * * @dec_irq: decoder irq resource * @enc_irq: h264 encoder irq resource - * @enc_lt_irq: vp8 encoder irq resource * * @dec_mutex: decoder hardware lock * @enc_mutex: encoder hardware lock. @@ -397,7 +395,6 @@ struct mtk_vcodec_dev { int dec_irq; int enc_irq; - int enc_lt_irq; struct mutex dec_mutex; struct mutex enc_mutex; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index 8c917969c2f1..4831052f475d 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -9,6 +9,7 @@ #include <media/v4l2-mem2mem.h> #include <media/videobuf2-dma-contig.h> #include <soc/mediatek/smi.h> +#include <linux/pm_runtime.h> #include "mtk_vcodec_drv.h" #include "mtk_vcodec_enc.h" @@ -787,7 +788,7 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) */ if ((ctx->state == MTK_STATE_ABORT) || (ctx->state == MTK_STATE_FREE)) { ret = -EIO; - goto err_set_param; + goto err_start_stream; } /* Do the initialization when both start_streaming have been called */ @@ -799,6 +800,12 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) return 0; } + ret = pm_runtime_resume_and_get(&ctx->dev->plat_dev->dev); + if (ret < 0) { + mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret); + goto err_start_stream; + } + mtk_venc_set_param(ctx, ¶m); ret = venc_if_set_param(ctx, VENC_SET_PARAM_ENC, ¶m); if (ret) { @@ -825,6 +832,11 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) return 0; err_set_param: + ret = pm_runtime_put(&ctx->dev->plat_dev->dev); + if (ret < 0) + mtk_v4l2_err("pm_runtime_put fail %d", ret); + +err_start_stream: for (i = 0; i < q->num_buffers; ++i) { struct vb2_buffer *buf = vb2_get_buffer(q, i); @@ -878,6 +890,10 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) if (ret) mtk_v4l2_err("venc_if_deinit failed=%d", ret); + ret = pm_runtime_put(&ctx->dev->plat_dev->dev); + if (ret < 0) + mtk_v4l2_err("pm_runtime_put fail %d", ret); + ctx->state = MTK_STATE_FREE; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index be3842e6ca47..7d7b8cfc2cc5 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -49,12 +49,15 @@ static const struct mtk_video_fmt mtk_video_formats_output_mt8173[] = { }, }; -static const struct mtk_video_fmt mtk_video_formats_capture_mt8173[] = { +static const struct mtk_video_fmt mtk_video_formats_capture_mt8173_avc[] = { { .fourcc = V4L2_PIX_FMT_H264, .type = MTK_FMT_ENC, .num_planes = 1, }, +}; + +static const struct mtk_video_fmt mtk_video_formats_capture_mt8173_vp8[] = { { .fourcc = V4L2_PIX_FMT_VP8, .type = MTK_FMT_ENC, @@ -110,10 +113,11 @@ static irqreturn_t mtk_vcodec_enc_irq_handler(int irq, void *priv) ctx = dev->curr_ctx; spin_unlock_irqrestore(&dev->irqlock, flags); - mtk_v4l2_debug(1, "id=%d", ctx->id); - addr = dev->reg_base[VENC_SYS] + MTK_VENC_IRQ_ACK_OFFSET; + mtk_v4l2_debug(1, "id=%d coreid:%d", ctx->id, dev->venc_pdata->core_id); + addr = dev->reg_base[dev->venc_pdata->core_id] + + MTK_VENC_IRQ_ACK_OFFSET; - ctx->irq_status = readl(dev->reg_base[VENC_SYS] + + ctx->irq_status = readl(dev->reg_base[dev->venc_pdata->core_id] + (MTK_VENC_IRQ_STATUS_OFFSET)); clean_irq_status(ctx->irq_status, addr); @@ -122,29 +126,6 @@ static irqreturn_t mtk_vcodec_enc_irq_handler(int irq, void *priv) return IRQ_HANDLED; } -static irqreturn_t mtk_vcodec_enc_lt_irq_handler(int irq, void *priv) -{ - struct mtk_vcodec_dev *dev = priv; - struct mtk_vcodec_ctx *ctx; - unsigned long flags; - void __iomem *addr; - - spin_lock_irqsave(&dev->irqlock, flags); - ctx = dev->curr_ctx; - spin_unlock_irqrestore(&dev->irqlock, flags); - - mtk_v4l2_debug(1, "id=%d", ctx->id); - ctx->irq_status = readl(dev->reg_base[VENC_LT_SYS] + - (MTK_VENC_IRQ_STATUS_OFFSET)); - - addr = dev->reg_base[VENC_LT_SYS] + MTK_VENC_IRQ_ACK_OFFSET; - - clean_irq_status(ctx->irq_status, addr); - - wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED); - return IRQ_HANDLED; -} - static int fops_vcodec_open(struct file *file) { struct mtk_vcodec_dev *dev = video_drvdata(file); @@ -293,17 +274,18 @@ static int mtk_vcodec_probe(struct platform_device *pdev) dev->venc_pdata = of_device_get_match_data(&pdev->dev); ret = mtk_vcodec_init_enc_pm(dev); if (ret < 0) { - dev_err(&pdev->dev, "Failed to get mt vcodec clock source!"); + dev_err(&pdev->dev, "Failed to get mtk vcodec clock source!"); goto err_enc_pm; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->reg_base[VENC_SYS] = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR((__force void *)dev->reg_base[VENC_SYS])) { - ret = PTR_ERR((__force void *)dev->reg_base[VENC_SYS]); + pm_runtime_enable(&pdev->dev); + + dev->reg_base[dev->venc_pdata->core_id] = + devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->reg_base[dev->venc_pdata->core_id])) { + ret = PTR_ERR(dev->reg_base[dev->venc_pdata->core_id]); goto err_res; } - mtk_v4l2_debug(2, "reg[%d] base=0x%p", VENC_SYS, dev->reg_base[VENC_SYS]); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { @@ -318,37 +300,13 @@ static int mtk_vcodec_probe(struct platform_device *pdev) mtk_vcodec_enc_irq_handler, 0, pdev->name, dev); if (ret) { - dev_err(&pdev->dev, "Failed to install dev->enc_irq %d (%d)", - dev->enc_irq, - ret); + dev_err(&pdev->dev, + "Failed to install dev->enc_irq %d (%d) core_id (%d)", + dev->enc_irq, ret, dev->venc_pdata->core_id); ret = -EINVAL; goto err_res; } - if (dev->venc_pdata->has_lt_irq) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - dev->reg_base[VENC_LT_SYS] = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR((__force void *)dev->reg_base[VENC_LT_SYS])) { - ret = PTR_ERR((__force void *)dev->reg_base[VENC_LT_SYS]); - goto err_res; - } - mtk_v4l2_debug(2, "reg[%d] base=0x%p", VENC_LT_SYS, dev->reg_base[VENC_LT_SYS]); - - dev->enc_lt_irq = platform_get_irq(pdev, 1); - irq_set_status_flags(dev->enc_lt_irq, IRQ_NOAUTOEN); - ret = devm_request_irq(&pdev->dev, - dev->enc_lt_irq, - mtk_vcodec_enc_lt_irq_handler, - 0, pdev->name, dev); - if (ret) { - dev_err(&pdev->dev, - "Failed to install dev->enc_lt_irq %d (%d)", - dev->enc_lt_irq, ret); - ret = -EINVAL; - goto err_res; - } - } - mutex_init(&dev->enc_mutex); mutex_init(&dev->dev_mutex); spin_lock_init(&dev->irqlock); @@ -409,8 +367,8 @@ static int mtk_vcodec_probe(struct platform_device *pdev) goto err_enc_reg; } - mtk_v4l2_debug(0, "encoder registered as /dev/video%d", - vfd_enc->num); + mtk_v4l2_debug(0, "encoder %d registered as /dev/video%d", + dev->venc_pdata->core_id, vfd_enc->num); return 0; @@ -429,20 +387,30 @@ err_enc_pm: return ret; } -static const struct mtk_vcodec_enc_pdata mt8173_pdata = { +static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = { .chip = MTK_MT8173, - .has_lt_irq = true, - .capture_formats = mtk_video_formats_capture_mt8173, - .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8173), + .capture_formats = mtk_video_formats_capture_mt8173_avc, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8173_avc), .output_formats = mtk_video_formats_output_mt8173, .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173), .min_bitrate = 1, .max_bitrate = 4000000, + .core_id = VENC_SYS, +}; + +static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = { + .chip = MTK_MT8173, + .capture_formats = mtk_video_formats_capture_mt8173_vp8, + .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8173_vp8), + .output_formats = mtk_video_formats_output_mt8173, + .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173), + .min_bitrate = 64, + .max_bitrate = 4000000, + .core_id = VENC_LT_SYS, }; static const struct mtk_vcodec_enc_pdata mt8183_pdata = { .chip = MTK_MT8183, - .has_lt_irq = false, .uses_ext = true, .capture_formats = mtk_video_formats_capture_mt8183, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8183), @@ -451,10 +419,14 @@ static const struct mtk_vcodec_enc_pdata mt8183_pdata = { .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173), .min_bitrate = 64, .max_bitrate = 40000000, + .core_id = VENC_SYS, }; static const struct of_device_id mtk_vcodec_enc_match[] = { - {.compatible = "mediatek,mt8173-vcodec-enc", .data = &mt8173_pdata}, + {.compatible = "mediatek,mt8173-vcodec-enc", + .data = &mt8173_avc_pdata}, + {.compatible = "mediatek,mt8173-vcodec-enc-vp8", + .data = &mt8173_vp8_pdata}, {.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata}, {}, }; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c index 3b7c54d6aa8f..1b2e4930ed27 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c @@ -43,23 +43,6 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) return -ENODEV; } pm->larbvenc = &pdev->dev; - - node = of_parse_phandle(dev->of_node, "mediatek,larb", 1); - if (!node) { - mtk_v4l2_err("no mediatek,larb found"); - ret = -ENODEV; - goto put_larbvenc; - } - - pdev = of_find_device_by_node(node); - of_node_put(node); - if (!pdev) { - mtk_v4l2_err("no mediatek,larb device found"); - ret = -ENODEV; - goto put_larbvenc; - } - - pm->larbvenclt = &pdev->dev; pdev = mtkdev->plat_dev; pm->dev = &pdev->dev; @@ -71,12 +54,12 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) GFP_KERNEL); if (!enc_clk->clk_info) { ret = -ENOMEM; - goto put_larbvenclt; + goto put_larbvenc; } } else { mtk_v4l2_err("Failed to get venc clock count"); ret = -EINVAL; - goto put_larbvenclt; + goto put_larbvenc; } for (i = 0; i < enc_clk->clk_num; i++) { @@ -85,7 +68,7 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) "clock-names", i, &clk_info->clk_name); if (ret) { mtk_v4l2_err("venc failed to get clk name %d", i); - goto put_larbvenclt; + goto put_larbvenc; } clk_info->vcodec_clk = devm_clk_get(&pdev->dev, clk_info->clk_name); @@ -93,14 +76,12 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev) mtk_v4l2_err("venc devm_clk_get (%d)%s fail", i, clk_info->clk_name); ret = PTR_ERR(clk_info->vcodec_clk); - goto put_larbvenclt; + goto put_larbvenc; } } return 0; -put_larbvenclt: - put_device(pm->larbvenclt); put_larbvenc: put_device(pm->larbvenc); return ret; @@ -108,7 +89,7 @@ put_larbvenc: void mtk_vcodec_release_enc_pm(struct mtk_vcodec_dev *mtkdev) { - put_device(mtkdev->pm.larbvenclt); + pm_runtime_disable(mtkdev->pm.dev); put_device(mtkdev->pm.larbvenc); } @@ -130,18 +111,10 @@ void mtk_vcodec_enc_clock_on(struct mtk_vcodec_pm *pm) ret = mtk_smi_larb_get(pm->larbvenc); if (ret) { mtk_v4l2_err("mtk_smi_larb_get larb3 fail %d", ret); - goto larbvencerr; - } - ret = mtk_smi_larb_get(pm->larbvenclt); - if (ret) { - mtk_v4l2_err("mtk_smi_larb_get larb4 fail %d", ret); - goto larbvenclterr; + goto clkerr; } return; -larbvenclterr: - mtk_smi_larb_put(pm->larbvenc); -larbvencerr: clkerr: for (i -= 1; i >= 0; i--) clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk); @@ -153,7 +126,6 @@ void mtk_vcodec_enc_clock_off(struct mtk_vcodec_pm *pm) int i = 0; mtk_smi_larb_put(pm->larbvenc); - mtk_smi_larb_put(pm->larbvenclt); for (i = enc_clk->clk_num - 1; i >= 0; i--) clk_disable_unprepare(enc_clk->clk_info[i].vcodec_clk); } diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index d9880210b2ab..71cdc3ddafcb 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -61,7 +61,7 @@ struct vp9_ref_cnt_buf { }; /** - * struct vp9_fb_info - contains current frame's reference buffer information + * struct vp9_ref_buf - contains current frame's reference buffer information * @buf : reference buffer * @idx : reference buffer index to frm_bufs * @reserved : reserved field used by vpu @@ -73,7 +73,7 @@ struct vp9_ref_buf { }; /** - * struct vp9_fb_info - contains frame buffer info + * struct vp9_sf_ref_fb - contains frame buffer info * @fb : super frame reference frame buffer * @used : this reference frame info entry is used * @padding : for 64 bytes size align diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h index 270d8dc9984b..ec8f4e8d3d23 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h @@ -14,10 +14,10 @@ /** - * struct vdec_fb_status - decoder frame buffer status - * @FB_ST_NORMAL : initial state - * @FB_ST_DISPLAY : frmae buffer is ready to be displayed - * @FB_ST_FREE : frame buffer is not used by decoder any more + * enum vdec_fb_status - decoder frame buffer status + * @FB_ST_NORMAL: initial state + * @FB_ST_DISPLAY: frame buffer is ready to be displayed + * @FB_ST_FREE: frame buffer is not used by decoder any more */ enum vdec_fb_status { FB_ST_NORMAL = 0, diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c index 11abb191ada5..8267a9c4fd25 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c @@ -367,7 +367,7 @@ static int vp8_enc_encode(void *handle, mtk_vcodec_debug_enter(inst); - enable_irq(ctx->dev->enc_lt_irq); + enable_irq(ctx->dev->enc_irq); switch (opt) { case VENC_START_OPT_ENCODE_FRAME: @@ -386,7 +386,7 @@ static int vp8_enc_encode(void *handle, encode_err: - disable_irq(ctx->dev->enc_lt_irq); + disable_irq(ctx->dev->enc_irq); mtk_vcodec_debug_leave(inst); return ret; diff --git a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h index 2feb0365179f..5f53d4255c36 100644 --- a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h @@ -52,7 +52,7 @@ struct venc_ap_ipi_msg_init { * (struct venc_vp8_vsi/venc_h264_vsi *) * @param_id: parameter id (venc_set_param_type) * @data_item: number of items in the data array - * @data[8]: data array to store the set parameters + * @data: data array to store the set parameters */ struct venc_ap_ipi_msg_set_param { uint32_t msg_id; @@ -92,7 +92,7 @@ struct venc_ap_ipi_msg_enc { * * @base: base msg structure * @data_item: number of items in the data array - * @data[8]: data array to store the set parameters + * @data: data array to store the set parameters */ struct venc_ap_ipi_msg_enc_ext { struct venc_ap_ipi_msg_enc base; @@ -158,7 +158,7 @@ struct venc_vpu_ipi_msg_init { * @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *) * @param_id: parameter id (venc_set_param_type) * @data_item: number of items in the data array - * @data[6]: data array to store the return result + * @data: data array to store the return result */ struct venc_vpu_ipi_msg_set_param { uint32_t msg_id; @@ -171,10 +171,10 @@ struct venc_vpu_ipi_msg_set_param { /** * enum venc_ipi_msg_enc_state - Type of encode state - * VEN_IPI_MSG_ENC_STATE_FRAME: one frame being encoded - * VEN_IPI_MSG_ENC_STATE_PART: bit stream buffer full - * VEN_IPI_MSG_ENC_STATE_SKIP: encoded skip frame - * VEN_IPI_MSG_ENC_STATE_ERROR: encounter error + * @VEN_IPI_MSG_ENC_STATE_FRAME: one frame being encoded + * @VEN_IPI_MSG_ENC_STATE_PART: bit stream buffer full + * @VEN_IPI_MSG_ENC_STATE_SKIP: encoded skip frame + * @VEN_IPI_MSG_ENC_STATE_ERROR: encounter error */ enum venc_ipi_msg_enc_state { VEN_IPI_MSG_ENC_STATE_FRAME, diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index 043894f7188c..c8a56271b259 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -19,11 +19,11 @@ #include "mtk_vpu.h" -/** +/* * VPU (video processor unit) is a tiny processor controlling video hardware * related to video codec, scaling and color format converting. * VPU interfaces with other blocks by share memory and interrupt. - **/ + */ #define INIT_TIMEOUT_MS 2000U #define IPI_TIMEOUT_MS 2000U diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.h b/drivers/media/platform/mtk-vpu/mtk_vpu.h index ee7c552ce928..a56053ff135a 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.h +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.h @@ -10,10 +10,12 @@ #include <linux/platform_device.h> /** + * DOC: VPU + * * VPU (video processor unit) is a tiny processor controlling video hardware * related to video codec, scaling and color format converting. * VPU interfaces with other blocks by share memory and interrupt. - **/ + */ typedef void (*ipi_handler_t) (const void *data, unsigned int len, @@ -126,18 +128,18 @@ struct platform_device *vpu_get_plat_device(struct platform_device *pdev); * vpu_wdt_reg_handler - register a VPU watchdog handler * * @pdev: VPU platform device - * @vpu_wdt_reset_func: the callback reset function - * @private_data: the private data for reset function - * @rst_id: reset id + * @vpu_wdt_reset_func(): the callback reset function + * @priv: the private data for reset function + * @priv: the private data for reset function + * @id: reset id * * Register a handler performing own tasks when vpu reset by watchdog * * Return: Return 0 if the handler is added successfully, * otherwise it is failed. - * **/ int vpu_wdt_reg_handler(struct platform_device *pdev, - void vpu_wdt_reset_func(void *), + void vpu_wdt_reset_func(void *priv), void *priv, enum rst_id id); /** @@ -171,8 +173,8 @@ int vpu_load_firmware(struct platform_device *pdev); /** * vpu_mapping_dm_addr - Mapping DTCM/DMEM to kernel virtual address * - * @pdev: VPU platform device - * @dmem_addr: VPU's data memory address + * @pdev: VPU platform device + * @dtcm_dmem_addr: VPU's data memory address * * Mapping the VPU's DTCM (Data Tightly-Coupled Memory) / * DMEM (Data Extended Memory) memory address to diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index a6bb7d9bf75f..53025c8c7531 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -691,6 +691,8 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, pipe->do_propagation = false; + mutex_lock(&isp->media_dev.graph_mutex); + entity = &pipe->output->video.entity; while (1) { pad = &entity->pads[0]; @@ -705,8 +707,10 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, subdev = media_entity_to_v4l2_subdev(entity); ret = v4l2_subdev_call(subdev, video, s_stream, mode); - if (ret < 0 && ret != -ENOIOCTLCMD) + if (ret < 0 && ret != -ENOIOCTLCMD) { + mutex_unlock(&isp->media_dev.graph_mutex); return ret; + } if (subdev == &isp->isp_ccdc.subdev) { v4l2_subdev_call(&isp->isp_aewb.subdev, video, @@ -723,6 +727,8 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe, break; } + mutex_unlock(&isp->media_dev.graph_mutex); + return 0; } @@ -2028,6 +2034,8 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) struct v4l2_subdev *sd; int ret; + mutex_lock(&isp->media_dev.graph_mutex); + ret = media_entity_enum_init(&isp->crashed, &isp->media_dev); if (ret) return ret; @@ -2038,10 +2046,14 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) ret = isp_link_entity(isp, &sd->entity, v4l2_subdev_to_bus_cfg(sd)->interface); - if (ret < 0) + if (ret < 0) { + mutex_unlock(&isp->media_dev.graph_mutex); return ret; + } } + mutex_unlock(&isp->media_dev.graph_mutex); + ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); if (ret < 0) return ret; diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 14077797f5e1..dd510ee9b58a 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -2389,7 +2389,7 @@ static int pxa_camera_probe(struct platform_device *pdev) pxa_camera_activate(pcdev); - dev_set_drvdata(&pdev->dev, pcdev); + platform_set_drvdata(pdev, pcdev); err = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev); if (err) goto exit_deactivate; @@ -2421,7 +2421,7 @@ exit_free_dma_y: static int pxa_camera_remove(struct platform_device *pdev) { - struct pxa_camera_dev *pcdev = dev_get_drvdata(&pdev->dev); + struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev); pxa_camera_deactivate(pcdev); tasklet_kill(&pcdev->task_eof); diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile index 63c1b1b2943c..0752c46ea37b 100644 --- a/drivers/media/platform/qcom/camss/Makefile +++ b/drivers/media/platform/qcom/camss/Makefile @@ -4,12 +4,18 @@ qcom-camss-objs += \ camss.o \ camss-csid.o \ + camss-csid-4-1.o \ + camss-csid-4-7.o \ + camss-csid-170.o \ camss-csiphy-2ph-1-0.o \ camss-csiphy-3ph-1-0.o \ camss-csiphy.o \ camss-ispif.o \ camss-vfe-4-1.o \ camss-vfe-4-7.o \ + camss-vfe-4-8.o \ + camss-vfe-170.o \ + camss-vfe-gen1.o \ camss-vfe.o \ camss-video.o \ diff --git a/drivers/media/platform/qcom/camss/camss-csid-170.c b/drivers/media/platform/qcom/camss/camss-csid-170.c new file mode 100644 index 000000000000..ac22ff29d2a9 --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-csid-170.c @@ -0,0 +1,599 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * camss-csid-4-7.c + * + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module + * + * Copyright (C) 2020 Linaro Ltd. + */ +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/of.h> + +#include "camss-csid.h" +#include "camss-csid-gen2.h" +#include "camss.h" + +/* The CSID 2 IP-block is different from the others, + * and is of a bare-bones Lite version, with no PIX + * interface support. As a result of that it has an + * alternate register layout. + */ +#define IS_LITE (csid->id == 2 ? 1 : 0) + +#define CSID_HW_VERSION 0x0 +#define HW_VERSION_STEPPING 0 +#define HW_VERSION_REVISION 16 +#define HW_VERSION_GENERATION 28 + +#define CSID_RST_STROBES 0x10 +#define RST_STROBES 0 + +#define CSID_CSI2_RX_IRQ_STATUS 0x20 +#define CSID_CSI2_RX_IRQ_MASK 0x24 +#define CSID_CSI2_RX_IRQ_CLEAR 0x28 + +#define CSID_CSI2_RDIN_IRQ_STATUS(rdi) ((IS_LITE ? 0x30 : 0x40) \ + + 0x10 * (rdi)) +#define CSID_CSI2_RDIN_IRQ_MASK(rdi) ((IS_LITE ? 0x34 : 0x44) \ + + 0x10 * (rdi)) +#define CSID_CSI2_RDIN_IRQ_CLEAR(rdi) ((IS_LITE ? 0x38 : 0x48) \ + + 0x10 * (rdi)) +#define CSID_CSI2_RDIN_IRQ_SET(rdi) ((IS_LITE ? 0x3C : 0x4C) \ + + 0x10 * (rdi)) + +#define CSID_TOP_IRQ_STATUS 0x70 +#define TOP_IRQ_STATUS_RESET_DONE 0 +#define CSID_TOP_IRQ_MASK 0x74 +#define CSID_TOP_IRQ_CLEAR 0x78 +#define CSID_TOP_IRQ_SET 0x7C +#define CSID_IRQ_CMD 0x80 +#define IRQ_CMD_CLEAR 0 +#define IRQ_CMD_SET 4 + +#define CSID_CSI2_RX_CFG0 0x100 +#define CSI2_RX_CFG0_NUM_ACTIVE_LANES 0 +#define CSI2_RX_CFG0_DL0_INPUT_SEL 4 +#define CSI2_RX_CFG0_DL1_INPUT_SEL 8 +#define CSI2_RX_CFG0_DL2_INPUT_SEL 12 +#define CSI2_RX_CFG0_DL3_INPUT_SEL 16 +#define CSI2_RX_CFG0_PHY_NUM_SEL 20 +#define CSI2_RX_CFG0_PHY_TYPE_SEL 24 + +#define CSID_CSI2_RX_CFG1 0x104 +#define CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN 0 +#define CSI2_RX_CFG1_DE_SCRAMBLE_EN 1 +#define CSI2_RX_CFG1_VC_MODE 2 +#define CSI2_RX_CFG1_COMPLETE_STREAM_EN 4 +#define CSI2_RX_CFG1_COMPLETE_STREAM_FRAME_TIMING 5 +#define CSI2_RX_CFG1_MISR_EN 6 +#define CSI2_RX_CFG1_CGC_MODE 7 +#define CGC_MODE_DYNAMIC_GATING 0 +#define CGC_MODE_ALWAYS_ON 1 + +#define CSID_RDI_CFG0(rdi) ((IS_LITE ? 0x200 : 0x300) \ + + 0x100 * (rdi)) +#define RDI_CFG0_BYTE_CNTR_EN 0 +#define RDI_CFG0_FORMAT_MEASURE_EN 1 +#define RDI_CFG0_TIMESTAMP_EN 2 +#define RDI_CFG0_DROP_H_EN 3 +#define RDI_CFG0_DROP_V_EN 4 +#define RDI_CFG0_CROP_H_EN 5 +#define RDI_CFG0_CROP_V_EN 6 +#define RDI_CFG0_MISR_EN 7 +#define RDI_CFG0_CGC_MODE 8 +#define CGC_MODE_DYNAMIC 0 +#define CGC_MODE_ALWAYS_ON 1 +#define RDI_CFG0_PLAIN_ALIGNMENT 9 +#define PLAIN_ALIGNMENT_LSB 0 +#define PLAIN_ALIGNMENT_MSB 1 +#define RDI_CFG0_PLAIN_FORMAT 10 +#define RDI_CFG0_DECODE_FORMAT 12 +#define RDI_CFG0_DATA_TYPE 16 +#define RDI_CFG0_VIRTUAL_CHANNEL 22 +#define RDI_CFG0_DT_ID 27 +#define RDI_CFG0_EARLY_EOF_EN 29 +#define RDI_CFG0_PACKING_FORMAT 30 +#define RDI_CFG0_ENABLE 31 + +#define CSID_RDI_CFG1(rdi) ((IS_LITE ? 0x204 : 0x304)\ + + 0x100 * (rdi)) +#define RDI_CFG1_TIMESTAMP_STB_SEL 0 + +#define CSID_RDI_CTRL(rdi) ((IS_LITE ? 0x208 : 0x308)\ + + 0x100 * (rdi)) +#define RDI_CTRL_HALT_CMD 0 +#define ALT_CMD_RESUME_AT_FRAME_BOUNDARY 1 +#define RDI_CTRL_HALT_MODE 2 + +#define CSID_RDI_FRM_DROP_PATTERN(rdi) ((IS_LITE ? 0x20C : 0x30C)\ + + 0x100 * (rdi)) +#define CSID_RDI_FRM_DROP_PERIOD(rdi) ((IS_LITE ? 0x210 : 0x310)\ + + 0x100 * (rdi)) +#define CSID_RDI_IRQ_SUBSAMPLE_PATTERN(rdi) ((IS_LITE ? 0x214 : 0x314)\ + + 0x100 * (rdi)) +#define CSID_RDI_IRQ_SUBSAMPLE_PERIOD(rdi) ((IS_LITE ? 0x218 : 0x318)\ + + 0x100 * (rdi)) +#define CSID_RDI_RPP_PIX_DROP_PATTERN(rdi) ((IS_LITE ? 0x224 : 0x324)\ + + 0x100 * (rdi)) +#define CSID_RDI_RPP_PIX_DROP_PERIOD(rdi) ((IS_LITE ? 0x228 : 0x328)\ + + 0x100 * (rdi)) +#define CSID_RDI_RPP_LINE_DROP_PATTERN(rdi) ((IS_LITE ? 0x22C : 0x32C)\ + + 0x100 * (rdi)) +#define CSID_RDI_RPP_LINE_DROP_PERIOD(rdi) ((IS_LITE ? 0x230 : 0x330)\ + + 0x100 * (rdi)) + +#define CSID_TPG_CTRL 0x600 +#define TPG_CTRL_TEST_EN 0 +#define TPG_CTRL_FS_PKT_EN 1 +#define TPG_CTRL_FE_PKT_EN 2 +#define TPG_CTRL_NUM_ACTIVE_LANES 4 +#define TPG_CTRL_CYCLES_BETWEEN_PKTS 8 +#define TPG_CTRL_NUM_TRAIL_BYTES 20 + +#define CSID_TPG_VC_CFG0 0x604 +#define TPG_VC_CFG0_VC_NUM 0 +#define TPG_VC_CFG0_NUM_ACTIVE_SLOTS 8 +#define NUM_ACTIVE_SLOTS_0_ENABLED 0 +#define NUM_ACTIVE_SLOTS_0_1_ENABLED 1 +#define NUM_ACTIVE_SLOTS_0_1_2_ENABLED 2 +#define NUM_ACTIVE_SLOTS_0_1_3_ENABLED 3 +#define TPG_VC_CFG0_LINE_INTERLEAVING_MODE 10 +#define INTELEAVING_MODE_INTERLEAVED 0 +#define INTELEAVING_MODE_ONE_SHOT 1 +#define TPG_VC_CFG0_NUM_FRAMES 16 + +#define CSID_TPG_VC_CFG1 0x608 +#define TPG_VC_CFG1_H_BLANKING_COUNT 0 +#define TPG_VC_CFG1_V_BLANKING_COUNT 12 +#define TPG_VC_CFG1_V_BLANK_FRAME_WIDTH_SEL 24 + +#define CSID_TPG_LFSR_SEED 0x60C + +#define CSID_TPG_DT_n_CFG_0(n) (0x610 + (n) * 0xC) +#define TPG_DT_n_CFG_0_FRAME_HEIGHT 0 +#define TPG_DT_n_CFG_0_FRAME_WIDTH 16 + +#define CSID_TPG_DT_n_CFG_1(n) (0x614 + (n) * 0xC) +#define TPG_DT_n_CFG_1_DATA_TYPE 0 +#define TPG_DT_n_CFG_1_ECC_XOR_MASK 8 +#define TPG_DT_n_CFG_1_CRC_XOR_MASK 16 + +#define CSID_TPG_DT_n_CFG_2(n) (0x618 + (n) * 0xC) +#define TPG_DT_n_CFG_2_PAYLOAD_MODE 0 +#define TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD 4 +#define TPG_DT_n_CFG_2_ENCODE_FORMAT 16 + +#define CSID_TPG_COLOR_BARS_CFG 0x640 +#define TPG_COLOR_BARS_CFG_UNICOLOR_BAR_EN 0 +#define TPG_COLOR_BARS_CFG_UNICOLOR_BAR_SEL 4 +#define TPG_COLOR_BARS_CFG_SPLIT_EN 5 +#define TPG_COLOR_BARS_CFG_ROTATE_PERIOD 8 + +#define CSID_TPG_COLOR_BOX_CFG 0x644 +#define TPG_COLOR_BOX_CFG_MODE 0 +#define TPG_COLOR_BOX_PATTERN_SEL 2 + +static const struct csid_format csid_formats[] = { + { + MEDIA_BUS_FMT_UYVY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_VYUY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YUYV8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YVYU8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_SBGGR8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_Y10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, +}; + +static void csid_configure_stream(struct csid_device *csid, u8 enable) +{ + struct csid_testgen_config *tg = &csid->testgen; + u32 val; + u32 phy_sel = 0; + u8 lane_cnt = csid->phy.lane_cnt; + struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_SRC]; + const struct csid_format *format = csid_get_fmt_entry(csid->formats, csid->nformats, + input_format->code); + + if (!lane_cnt) + lane_cnt = 4; + + if (!tg->enabled) + phy_sel = csid->phy.csiphy_id; + + if (enable) { + u8 vc = 0; /* Virtual Channel 0 */ + u8 dt_id = vc * 4; + + if (tg->enabled) { + /* Config Test Generator */ + vc = 0xa; + + /* configure one DT, infinite frames */ + val = vc << TPG_VC_CFG0_VC_NUM; + val |= INTELEAVING_MODE_ONE_SHOT << TPG_VC_CFG0_LINE_INTERLEAVING_MODE; + val |= 0 << TPG_VC_CFG0_NUM_FRAMES; + writel_relaxed(val, csid->base + CSID_TPG_VC_CFG0); + + val = 0x740 << TPG_VC_CFG1_H_BLANKING_COUNT; + val |= 0x3ff << TPG_VC_CFG1_V_BLANKING_COUNT; + writel_relaxed(val, csid->base + CSID_TPG_VC_CFG1); + + writel_relaxed(0x12345678, csid->base + CSID_TPG_LFSR_SEED); + + val = input_format->height & 0x1fff << TPG_DT_n_CFG_0_FRAME_HEIGHT; + val |= input_format->width & 0x1fff << TPG_DT_n_CFG_0_FRAME_WIDTH; + writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_0(0)); + + val = DATA_TYPE_RAW_10BIT << TPG_DT_n_CFG_1_DATA_TYPE; + writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0)); + + val = tg->mode << TPG_DT_n_CFG_2_PAYLOAD_MODE; + val |= 0xBE << TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD; + val |= format->decode_format << TPG_DT_n_CFG_2_ENCODE_FORMAT; + writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_2(0)); + + writel_relaxed(0, csid->base + CSID_TPG_COLOR_BARS_CFG); + + writel_relaxed(0, csid->base + CSID_TPG_COLOR_BOX_CFG); + } + + val = 1 << RDI_CFG0_BYTE_CNTR_EN; + val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN; + val |= 1 << RDI_CFG0_TIMESTAMP_EN; + val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT; + val |= DATA_TYPE_RAW_10BIT << RDI_CFG0_DATA_TYPE; + val |= vc << RDI_CFG0_VIRTUAL_CHANNEL; + val |= dt_id << RDI_CFG0_DT_ID; + writel_relaxed(val, csid->base + CSID_RDI_CFG0(0)); + + /* CSID_TIMESTAMP_STB_POST_IRQ */ + val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL; + writel_relaxed(val, csid->base + CSID_RDI_CFG1(0)); + + val = 1; + writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(0)); + + val = 0; + writel_relaxed(0, csid->base + CSID_RDI_FRM_DROP_PATTERN(0)); + + val = 1; + writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(0)); + + val = 0; + writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(0)); + + val = 1; + writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(0)); + + val = 0; + writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(0)); + + val = 1; + writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(0)); + + val = 0; + writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(0)); + + val = 0; + writel_relaxed(val, csid->base + CSID_RDI_CTRL(0)); + + val = readl_relaxed(csid->base + CSID_RDI_CFG0(0)); + val |= 1 << RDI_CFG0_ENABLE; + writel_relaxed(val, csid->base + CSID_RDI_CFG0(0)); + } + + if (tg->enabled) { + val = enable << TPG_CTRL_TEST_EN; + val |= 1 << TPG_CTRL_FS_PKT_EN; + val |= 1 << TPG_CTRL_FE_PKT_EN; + val |= (lane_cnt - 1) << TPG_CTRL_NUM_ACTIVE_LANES; + val |= 0x64 << TPG_CTRL_CYCLES_BETWEEN_PKTS; + val |= 0xA << TPG_CTRL_NUM_TRAIL_BYTES; + writel_relaxed(val, csid->base + CSID_TPG_CTRL); + } + + val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES; + val |= csid->phy.lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL; + val |= phy_sel << CSI2_RX_CFG0_PHY_NUM_SEL; + writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0); + + val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN; + val |= 1 << CSI2_RX_CFG1_MISR_EN; + writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); // csi2_vc_mode_shift_val ? + + /* error irqs start at BIT(11) */ + writel_relaxed(~0u, csid->base + CSID_CSI2_RX_IRQ_MASK); + + /* RDI irq */ + writel_relaxed(~0u, csid->base + CSID_TOP_IRQ_MASK); + + val = 1 << RDI_CTRL_HALT_CMD; + writel_relaxed(val, csid->base + CSID_RDI_CTRL(0)); +} + +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val) +{ + if (val > 0 && val <= csid->testgen.nmodes) + csid->testgen.mode = val; + + return 0; +} + +/* + * csid_hw_version - CSID hardware version query + * @csid: CSID device + * + * Return HW version or error + */ +static u32 csid_hw_version(struct csid_device *csid) +{ + u32 hw_version; + u32 hw_gen; + u32 hw_rev; + u32 hw_step; + + hw_version = readl_relaxed(csid->base + CSID_HW_VERSION); + hw_gen = (hw_version >> HW_VERSION_GENERATION) & 0xF; + hw_rev = (hw_version >> HW_VERSION_REVISION) & 0xFFF; + hw_step = (hw_version >> HW_VERSION_STEPPING) & 0xFFFF; + dev_dbg(csid->camss->dev, "CSID HW Version = %u.%u.%u\n", + hw_gen, hw_rev, hw_step); + + return hw_version; +} + +/* + * csid_isr - CSID module interrupt service routine + * @irq: Interrupt line + * @dev: CSID device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t csid_isr(int irq, void *dev) +{ + struct csid_device *csid = dev; + u32 val; + u8 reset_done; + + val = readl_relaxed(csid->base + CSID_TOP_IRQ_STATUS); + writel_relaxed(val, csid->base + CSID_TOP_IRQ_CLEAR); + reset_done = val & BIT(TOP_IRQ_STATUS_RESET_DONE); + + val = readl_relaxed(csid->base + CSID_CSI2_RX_IRQ_STATUS); + writel_relaxed(val, csid->base + CSID_CSI2_RX_IRQ_CLEAR); + + val = readl_relaxed(csid->base + CSID_CSI2_RDIN_IRQ_STATUS(0)); + writel_relaxed(val, csid->base + CSID_CSI2_RDIN_IRQ_CLEAR(0)); + + val = 1 << IRQ_CMD_CLEAR; + writel_relaxed(val, csid->base + CSID_IRQ_CMD); + + if (reset_done) + complete(&csid->reset_complete); + + return IRQ_HANDLED; +} + +/* + * csid_reset - Trigger reset on CSID module and wait to complete + * @csid: CSID device + * + * Return 0 on success or a negative error code otherwise + */ +static int csid_reset(struct csid_device *csid) +{ + unsigned long time; + u32 val; + + reinit_completion(&csid->reset_complete); + + writel_relaxed(1, csid->base + CSID_TOP_IRQ_CLEAR); + writel_relaxed(1, csid->base + CSID_IRQ_CMD); + writel_relaxed(1, csid->base + CSID_TOP_IRQ_MASK); + writel_relaxed(1, csid->base + CSID_IRQ_CMD); + + /* preserve registers */ + val = 0x1e << RST_STROBES; + writel_relaxed(val, 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 reset timeout\n"); + return -EIO; + } + + return 0; +} + +static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, + unsigned int match_format_idx, u32 match_code) +{ + switch (sink_code) { + case MEDIA_BUS_FMT_SBGGR10_1X10: + { + u32 src_code[] = { + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, + }; + + return csid_find_code(src_code, ARRAY_SIZE(src_code), + match_format_idx, match_code); + } + case MEDIA_BUS_FMT_Y10_1X10: + { + u32 src_code[] = { + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, + }; + + return csid_find_code(src_code, ARRAY_SIZE(src_code), + match_format_idx, match_code); + } + default: + if (match_format_idx > 0) + return 0; + + return sink_code; + } +} + +static void csid_subdev_init(struct csid_device *csid) +{ + csid->formats = csid_formats; + csid->nformats = ARRAY_SIZE(csid_formats); + csid->testgen.modes = csid_testgen_modes; + csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2; +} + +const struct csid_hw_ops csid_ops_170 = { + .configure_stream = csid_configure_stream, + .configure_testgen_pattern = csid_configure_testgen_pattern, + .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-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c new file mode 100644 index 000000000000..d2aec0679dfc --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * camss-csid-4-1.c + * + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module + * + * Copyright (C) 2020 Linaro Ltd. + */ + +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/of.h> + +#include "camss-csid.h" +#include "camss-csid-gen1.h" +#include "camss.h" + +#define CAMSS_CSID_HW_VERSION 0x0 +#define CAMSS_CSID_CORE_CTRL_0 0x004 +#define CAMSS_CSID_CORE_CTRL_1 0x008 +#define CAMSS_CSID_RST_CMD 0x00c +#define CAMSS_CSID_CID_LUT_VC_n(n) (0x010 + 0x4 * (n)) +#define CAMSS_CSID_CID_n_CFG(n) (0x020 + 0x4 * (n)) +#define CAMSS_CSID_CID_n_CFG_ISPIF_EN BIT(0) +#define CAMSS_CSID_CID_n_CFG_RDI_EN BIT(1) +#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT 4 +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8 (PLAIN_FORMAT_PLAIN8 << 8) +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16 (PLAIN_FORMAT_PLAIN16 << 8) +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB (0 << 9) +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB (1 << 9) +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP (0 << 10) +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING (1 << 10) +#define CAMSS_CSID_IRQ_CLEAR_CMD 0x060 +#define CAMSS_CSID_IRQ_MASK 0x064 +#define CAMSS_CSID_IRQ_STATUS 0x068 +#define CAMSS_CSID_TG_CTRL 0x0a0 +#define CAMSS_CSID_TG_CTRL_DISABLE 0xa06436 +#define CAMSS_CSID_TG_CTRL_ENABLE 0xa06437 +#define CAMSS_CSID_TG_VC_CFG 0x0a4 +#define CAMSS_CSID_TG_VC_CFG_H_BLANKING 0x3ff +#define CAMSS_CSID_TG_VC_CFG_V_BLANKING 0x7f +#define CAMSS_CSID_TG_DT_n_CGG_0(n) (0x0ac + 0xc * (n)) +#define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b0 + 0xc * (n)) +#define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0b4 + 0xc * (n)) + +static const struct csid_format csid_formats[] = { + { + MEDIA_BUS_FMT_UYVY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_VYUY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YUYV8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YVYU8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_SBGGR8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_Y10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, +}; + +static void csid_configure_stream(struct csid_device *csid, u8 enable) +{ + struct csid_testgen_config *tg = &csid->testgen; + u32 val; + + if (enable) { + struct v4l2_mbus_framefmt *input_format; + const struct csid_format *format; + u8 vc = 0; /* Virtual Channel 0 */ + u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ + u8 dt_shift; + + if (tg->enabled) { + /* Config Test Generator */ + u32 num_lines, num_bytes_per_line; + + input_format = &csid->fmt[MSM_CSID_PAD_SRC]; + format = csid_get_fmt_entry(csid->formats, csid->nformats, + input_format->code); + num_bytes_per_line = input_format->width * format->bpp * format->spp / 8; + num_lines = input_format->height; + + /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */ + /* 1:0 VC */ + val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) | + ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13); + writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG); + + /* 28:16 bytes per lines, 12:0 num of lines */ + val = ((num_bytes_per_line & 0x1fff) << 16) | + (num_lines & 0x1fff); + writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0)); + + /* 5:0 data type */ + val = format->data_type; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0)); + + /* 2:0 output test pattern */ + val = tg->mode - 1; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0)); + } else { + struct csid_phy_config *phy = &csid->phy; + + input_format = &csid->fmt[MSM_CSID_PAD_SINK]; + format = csid_get_fmt_entry(csid->formats, csid->nformats, + input_format->code); + + val = phy->lane_cnt - 1; + val |= phy->lane_assign << 4; + + writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0); + + val = phy->csiphy_id << 17; + val |= 0x9; + + writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1); + } + + /* Config LUT */ + + dt_shift = (cid % 4) * 8; + val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc)); + val &= ~(0xff << dt_shift); + val |= format->data_type << dt_shift; + writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc)); + + val = CAMSS_CSID_CID_n_CFG_ISPIF_EN; + val |= CAMSS_CSID_CID_n_CFG_RDI_EN; + val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT; + val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP; + writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid)); + + if (tg->enabled) { + val = CAMSS_CSID_TG_CTRL_ENABLE; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL); + } + } else { + if (tg->enabled) { + val = CAMSS_CSID_TG_CTRL_DISABLE; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL); + } + } +} + +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val) +{ + if (val > 0 && val <= csid->testgen.nmodes) + csid->testgen.mode = val; + + return 0; +} + +static u32 csid_hw_version(struct csid_device *csid) +{ + u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION); + + dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version); + + return hw_version; +} + +static irqreturn_t csid_isr(int irq, void *dev) +{ + struct csid_device *csid = dev; + u32 value; + + value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS); + writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD); + + if ((value >> 11) & 0x1) + complete(&csid->reset_complete); + + return IRQ_HANDLED; +} + +static int csid_reset(struct csid_device *csid) +{ + unsigned long time; + + reinit_completion(&csid->reset_complete); + + writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD); + + time = wait_for_completion_timeout(&csid->reset_complete, + msecs_to_jiffies(CSID_RESET_TIMEOUT_MS)); + if (!time) { + dev_err(csid->camss->dev, "CSID reset timeout\n"); + return -EIO; + } + + return 0; +} + +static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, + unsigned int match_format_idx, u32 match_code) +{ + if (match_format_idx > 0) + return 0; + + return sink_code; +} + +static void csid_subdev_init(struct csid_device *csid) +{ + csid->formats = csid_formats; + csid->nformats = ARRAY_SIZE(csid_formats); + csid->testgen.modes = csid_testgen_modes; + csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; +} + +const struct csid_hw_ops csid_ops_4_1 = { + .configure_stream = csid_configure_stream, + .configure_testgen_pattern = csid_configure_testgen_pattern, + .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-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c new file mode 100644 index 000000000000..e7436ec6d02b --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * camss-csid-4-7.c + * + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module + * + * Copyright (C) 2020 Linaro Ltd. + */ +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/of.h> + +#include "camss-csid.h" +#include "camss-csid-gen1.h" +#include "camss.h" + +#define CAMSS_CSID_HW_VERSION 0x0 +#define CAMSS_CSID_CORE_CTRL_0 0x004 +#define CAMSS_CSID_CORE_CTRL_1 0x008 +#define CAMSS_CSID_RST_CMD 0x010 +#define CAMSS_CSID_CID_LUT_VC_n(n) (0x014 + 0x4 * (n)) +#define CAMSS_CSID_CID_n_CFG(n) (0x024 + 0x4 * (n)) +#define CAMSS_CSID_CID_n_CFG_ISPIF_EN BIT(0) +#define CAMSS_CSID_CID_n_CFG_RDI_EN BIT(1) +#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT 4 +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8 (PLAIN_FORMAT_PLAIN8 << 8) +#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16 (PLAIN_FORMAT_PLAIN16 << 8) +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB (0 << 9) +#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB (1 << 9) +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP (0 << 10) +#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING (1 << 10) +#define CAMSS_CSID_IRQ_CLEAR_CMD 0x064 +#define CAMSS_CSID_IRQ_MASK 0x068 +#define CAMSS_CSID_IRQ_STATUS 0x06c +#define CAMSS_CSID_TG_CTRL 0x0a8 +#define CAMSS_CSID_TG_CTRL_DISABLE 0xa06436 +#define CAMSS_CSID_TG_CTRL_ENABLE 0xa06437 +#define CAMSS_CSID_TG_VC_CFG 0x0ac +#define CAMSS_CSID_TG_VC_CFG_H_BLANKING 0x3ff +#define CAMSS_CSID_TG_VC_CFG_V_BLANKING 0x7f +#define CAMSS_CSID_TG_DT_n_CGG_0(n) (0x0b4 + 0xc * (n)) +#define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b8 + 0xc * (n)) +#define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0bc + 0xc * (n)) + +static const struct csid_format csid_formats[] = { + { + MEDIA_BUS_FMT_UYVY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_VYUY8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YUYV8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_YVYU8_2X8, + DATA_TYPE_YUV422_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 2, + }, + { + MEDIA_BUS_FMT_SBGGR8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB8_1X8, + DATA_TYPE_RAW_8BIT, + DECODE_FORMAT_UNCOMPRESSED_8_BIT, + 8, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB12_1X12, + DATA_TYPE_RAW_12BIT, + DECODE_FORMAT_UNCOMPRESSED_12_BIT, + 12, + 1, + }, + { + MEDIA_BUS_FMT_SBGGR14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_SGBRG14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_SGRBG14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_SRGGB14_1X14, + DATA_TYPE_RAW_14BIT, + DECODE_FORMAT_UNCOMPRESSED_14_BIT, + 14, + 1, + }, + { + MEDIA_BUS_FMT_Y10_1X10, + DATA_TYPE_RAW_10BIT, + DECODE_FORMAT_UNCOMPRESSED_10_BIT, + 10, + 1, + }, +}; + +static void csid_configure_stream(struct csid_device *csid, u8 enable) +{ + struct csid_testgen_config *tg = &csid->testgen; + u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code; + u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code; + u32 val; + + if (enable) { + struct v4l2_mbus_framefmt *input_format; + const struct csid_format *format; + u8 vc = 0; /* Virtual Channel 0 */ + u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ + u8 dt_shift; + + if (tg->enabled) { + /* Config Test Generator */ + u32 num_bytes_per_line, num_lines; + + input_format = &csid->fmt[MSM_CSID_PAD_SRC]; + format = csid_get_fmt_entry(csid->formats, csid->nformats, + input_format->code); + num_bytes_per_line = input_format->width * format->bpp * format->spp / 8; + num_lines = input_format->height; + + /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */ + /* 1:0 VC */ + val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) | + ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13); + writel_relaxed(val, csid->base + CAMSS_CSID_TG_VC_CFG); + + /* 28:16 bytes per lines, 12:0 num of lines */ + val = ((num_bytes_per_line & 0x1fff) << 16) | + (num_lines & 0x1fff); + writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_0(0)); + + /* 5:0 data type */ + val = format->data_type; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_1(0)); + + /* 2:0 output test pattern */ + val = tg->mode - 1; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_DT_n_CGG_2(0)); + } else { + struct csid_phy_config *phy = &csid->phy; + + input_format = &csid->fmt[MSM_CSID_PAD_SINK]; + format = csid_get_fmt_entry(csid->formats, csid->nformats, + input_format->code); + + val = phy->lane_cnt - 1; + val |= phy->lane_assign << 4; + + writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_0); + + val = phy->csiphy_id << 17; + val |= 0x9; + + writel_relaxed(val, csid->base + CAMSS_CSID_CORE_CTRL_1); + } + + /* Config LUT */ + + dt_shift = (cid % 4) * 8; + + val = readl_relaxed(csid->base + CAMSS_CSID_CID_LUT_VC_n(vc)); + val &= ~(0xff << dt_shift); + val |= format->data_type << dt_shift; + writel_relaxed(val, csid->base + CAMSS_CSID_CID_LUT_VC_n(vc)); + + val = CAMSS_CSID_CID_n_CFG_ISPIF_EN; + val |= CAMSS_CSID_CID_n_CFG_RDI_EN; + val |= format->decode_format << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT; + val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP; + + if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 && + src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) || + (sink_code == MEDIA_BUS_FMT_Y10_1X10 && + src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) { + val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING; + val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16; + val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB; + } + + writel_relaxed(val, csid->base + CAMSS_CSID_CID_n_CFG(cid)); + + if (tg->enabled) { + val = CAMSS_CSID_TG_CTRL_ENABLE; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL); + } + } else { + if (tg->enabled) { + val = CAMSS_CSID_TG_CTRL_DISABLE; + writel_relaxed(val, csid->base + CAMSS_CSID_TG_CTRL); + } + } +} + +static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val) +{ + if (val > 0 && val <= csid->testgen.nmodes) + csid->testgen.mode = val; + + return 0; +} + +static u32 csid_hw_version(struct csid_device *csid) +{ + u32 hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION); + + dev_dbg(csid->camss->dev, "CSID HW Version = 0x%08x\n", hw_version); + + return hw_version; +} + +/* + * isr - CSID module interrupt service routine + * @irq: Interrupt line + * @dev: CSID device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t csid_isr(int irq, void *dev) +{ + struct csid_device *csid = dev; + u32 value; + + value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS); + writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD); + + if ((value >> 11) & 0x1) + complete(&csid->reset_complete); + + return IRQ_HANDLED; +} + +/* + * csid_reset - Trigger reset on CSID module and wait to complete + * @csid: CSID device + * + * Return 0 on success or a negative error code otherwise + */ +static int csid_reset(struct csid_device *csid) +{ + unsigned long time; + + reinit_completion(&csid->reset_complete); + + writel_relaxed(0x7fff, csid->base + CAMSS_CSID_RST_CMD); + + time = wait_for_completion_timeout(&csid->reset_complete, + msecs_to_jiffies(CSID_RESET_TIMEOUT_MS)); + if (!time) { + dev_err(csid->camss->dev, "CSID reset timeout\n"); + return -EIO; + } + + return 0; +} + +static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, + unsigned int match_format_idx, u32 match_code) +{ + switch (sink_code) { + case MEDIA_BUS_FMT_SBGGR10_1X10: + { + u32 src_code[] = { + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, + }; + + return csid_find_code(src_code, ARRAY_SIZE(src_code), + match_format_idx, match_code); + } + case MEDIA_BUS_FMT_Y10_1X10: + { + u32 src_code[] = { + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, + }; + + return csid_find_code(src_code, ARRAY_SIZE(src_code), + match_format_idx, match_code); + } + default: + if (match_format_idx > 0) + return 0; + + return sink_code; + } +} + +static void csid_subdev_init(struct csid_device *csid) +{ + csid->formats = csid_formats; + csid->nformats = ARRAY_SIZE(csid_formats); + csid->testgen.modes = csid_testgen_modes; + csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; +} + +const struct csid_hw_ops csid_ops_4_7 = { + .configure_stream = csid_configure_stream, + .configure_testgen_pattern = csid_configure_testgen_pattern, + .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-gen1.h b/drivers/media/platform/qcom/camss/camss-csid-gen1.h new file mode 100644 index 000000000000..80a2bc6efff6 --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-csid-gen1.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * camss-csid-gen1.h + * + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module Generation 1 + * + * Copyright (C) 2021 Linaro Ltd. + */ +#ifndef QC_MSM_CAMSS_CSID_GEN1_H +#define QC_MSM_CAMSS_CSID_GEN1_H + +#define DECODE_FORMAT_UNCOMPRESSED_6_BIT 0x0 +#define DECODE_FORMAT_UNCOMPRESSED_8_BIT 0x1 +#define DECODE_FORMAT_UNCOMPRESSED_10_BIT 0x2 +#define DECODE_FORMAT_UNCOMPRESSED_12_BIT 0x3 +#define DECODE_FORMAT_DPCM_10_6_10 0x4 +#define DECODE_FORMAT_DPCM_10_8_10 0x5 +#define DECODE_FORMAT_DPCM_12_6_12 0x6 +#define DECODE_FORMAT_DPCM_12_8_12 0x7 +#define DECODE_FORMAT_UNCOMPRESSED_14_BIT 0x8 +#define DECODE_FORMAT_DPCM_14_8_14 0x9 +#define DECODE_FORMAT_DPCM_14_10_14 0xa + +#define PLAIN_FORMAT_PLAIN8 0x0 /* supports DPCM, UNCOMPRESSED_6/8_BIT */ +#define PLAIN_FORMAT_PLAIN16 0x1 /* supports DPCM, UNCOMPRESSED_10/16_BIT */ + +#endif /* QC_MSM_CAMSS_CSID_GEN1_H */ diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.h b/drivers/media/platform/qcom/camss/camss-csid-gen2.h new file mode 100644 index 000000000000..3a8ad001b3e8 --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * camss-csid-gen1.h + * + * Qualcomm MSM Camera Subsystem - CSID (CSI Decoder) Module Generation 1 + * + * Copyright (C) 2021 Linaro Ltd. + */ +#ifndef QC_MSM_CAMSS_CSID_GEN2_H +#define QC_MSM_CAMSS_CSID_GEN2_H + +#define DECODE_FORMAT_UNCOMPRESSED_6_BIT 0x0 +#define DECODE_FORMAT_UNCOMPRESSED_8_BIT 0x1 +#define DECODE_FORMAT_UNCOMPRESSED_10_BIT 0x2 +#define DECODE_FORMAT_UNCOMPRESSED_12_BIT 0x3 +#define DECODE_FORMAT_UNCOMPRESSED_14_BIT 0x4 +#define DECODE_FORMAT_UNCOMPRESSED_16_BIT 0x5 +#define DECODE_FORMAT_UNCOMPRESSED_20_BIT 0x6 +#define DECODE_FORMAT_DPCM_10_6_10 0x7 +#define DECODE_FORMAT_DPCM_10_8_10 0x8 +#define DECODE_FORMAT_DPCM_12_6_12 0x9 +#define DECODE_FORMAT_DPCM_12_8_12 0xa +#define DECODE_FORMAT_DPCM_14_8_14 0xb +#define DECODE_FORMAT_DPCM_14_10_14 0xc +#define DECODE_FORMAT_DPCM_12_10_12 0xd +#define DECODE_FORMAT_USER_DEFINED 0xe +#define DECODE_FORMAT_PAYLOAD_ONLY 0xf + +#define ENCODE_FORMAT_RAW_8_BIT 0x1 +#define ENCODE_FORMAT_RAW_10_BIT 0x2 +#define ENCODE_FORMAT_RAW_12_BIT 0x3 +#define ENCODE_FORMAT_RAW_14_BIT 0x4 +#define ENCODE_FORMAT_RAW_16_BIT 0x5 + +#define PLAIN_FORMAT_PLAIN8 0x0 /* supports DPCM, UNCOMPRESSED_6/8_BIT */ +#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_GEN2_H */ diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c index be3fe76f3dc3..cc11fbfdae13 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.c +++ b/drivers/media/platform/qcom/camss/camss-csid.c @@ -22,409 +22,52 @@ #include <media/v4l2-subdev.h> #include "camss-csid.h" +#include "camss-csid-gen1.h" #include "camss.h" #define MSM_CSID_NAME "msm_csid" -#define CAMSS_CSID_HW_VERSION 0x0 -#define CAMSS_CSID_CORE_CTRL_0 0x004 -#define CAMSS_CSID_CORE_CTRL_1 0x008 -#define CAMSS_CSID_RST_CMD(v) ((v) == CAMSS_8x16 ? 0x00c : 0x010) -#define CAMSS_CSID_CID_LUT_VC_n(v, n) \ - (((v) == CAMSS_8x16 ? 0x010 : 0x014) + 0x4 * (n)) -#define CAMSS_CSID_CID_n_CFG(v, n) \ - (((v) == CAMSS_8x16 ? 0x020 : 0x024) + 0x4 * (n)) -#define CAMSS_CSID_CID_n_CFG_ISPIF_EN BIT(0) -#define CAMSS_CSID_CID_n_CFG_RDI_EN BIT(1) -#define CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT 4 -#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_8 (0 << 8) -#define CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16 (1 << 8) -#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB (0 << 9) -#define CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_MSB (1 << 9) -#define CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP (0 << 10) -#define CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING (1 << 10) -#define CAMSS_CSID_IRQ_CLEAR_CMD(v) ((v) == CAMSS_8x16 ? 0x060 : 0x064) -#define CAMSS_CSID_IRQ_MASK(v) ((v) == CAMSS_8x16 ? 0x064 : 0x068) -#define CAMSS_CSID_IRQ_STATUS(v) ((v) == CAMSS_8x16 ? 0x068 : 0x06c) -#define CAMSS_CSID_TG_CTRL(v) ((v) == CAMSS_8x16 ? 0x0a0 : 0x0a8) -#define CAMSS_CSID_TG_CTRL_DISABLE 0xa06436 -#define CAMSS_CSID_TG_CTRL_ENABLE 0xa06437 -#define CAMSS_CSID_TG_VC_CFG(v) ((v) == CAMSS_8x16 ? 0x0a4 : 0x0ac) -#define CAMSS_CSID_TG_VC_CFG_H_BLANKING 0x3ff -#define CAMSS_CSID_TG_VC_CFG_V_BLANKING 0x7f -#define CAMSS_CSID_TG_DT_n_CGG_0(v, n) \ - (((v) == CAMSS_8x16 ? 0x0ac : 0x0b4) + 0xc * (n)) -#define CAMSS_CSID_TG_DT_n_CGG_1(v, n) \ - (((v) == CAMSS_8x16 ? 0x0b0 : 0x0b8) + 0xc * (n)) -#define CAMSS_CSID_TG_DT_n_CGG_2(v, n) \ - (((v) == CAMSS_8x16 ? 0x0b4 : 0x0bc) + 0xc * (n)) - -#define DATA_TYPE_EMBEDDED_DATA_8BIT 0x12 -#define DATA_TYPE_YUV422_8BIT 0x1e -#define DATA_TYPE_RAW_6BIT 0x28 -#define DATA_TYPE_RAW_8BIT 0x2a -#define DATA_TYPE_RAW_10BIT 0x2b -#define DATA_TYPE_RAW_12BIT 0x2c -#define DATA_TYPE_RAW_14BIT 0x2d - -#define DECODE_FORMAT_UNCOMPRESSED_6_BIT 0x0 -#define DECODE_FORMAT_UNCOMPRESSED_8_BIT 0x1 -#define DECODE_FORMAT_UNCOMPRESSED_10_BIT 0x2 -#define DECODE_FORMAT_UNCOMPRESSED_12_BIT 0x3 -#define DECODE_FORMAT_UNCOMPRESSED_14_BIT 0x8 - -#define CSID_RESET_TIMEOUT_MS 500 - -struct csid_format { - u32 code; - u8 data_type; - u8 decode_format; - u8 bpp; - u8 spp; /* bus samples per pixel */ -}; - -static const struct csid_format csid_formats_8x16[] = { - { - MEDIA_BUS_FMT_UYVY8_2X8, - DATA_TYPE_YUV422_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 2, - }, - { - MEDIA_BUS_FMT_VYUY8_2X8, - DATA_TYPE_YUV422_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 2, - }, - { - MEDIA_BUS_FMT_YUYV8_2X8, - DATA_TYPE_YUV422_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 2, - }, - { - MEDIA_BUS_FMT_YVYU8_2X8, - DATA_TYPE_YUV422_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 2, - }, - { - MEDIA_BUS_FMT_SBGGR8_1X8, - DATA_TYPE_RAW_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 1, - }, - { - MEDIA_BUS_FMT_SGBRG8_1X8, - DATA_TYPE_RAW_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 1, - }, - { - MEDIA_BUS_FMT_SGRBG8_1X8, - DATA_TYPE_RAW_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 1, - }, - { - MEDIA_BUS_FMT_SRGGB8_1X8, - DATA_TYPE_RAW_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 1, - }, - { - MEDIA_BUS_FMT_SBGGR10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, - { - MEDIA_BUS_FMT_SGBRG10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, - { - MEDIA_BUS_FMT_SGRBG10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, - { - MEDIA_BUS_FMT_SRGGB10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, - { - MEDIA_BUS_FMT_SBGGR12_1X12, - DATA_TYPE_RAW_12BIT, - DECODE_FORMAT_UNCOMPRESSED_12_BIT, - 12, - 1, - }, - { - MEDIA_BUS_FMT_SGBRG12_1X12, - DATA_TYPE_RAW_12BIT, - DECODE_FORMAT_UNCOMPRESSED_12_BIT, - 12, - 1, - }, - { - MEDIA_BUS_FMT_SGRBG12_1X12, - DATA_TYPE_RAW_12BIT, - DECODE_FORMAT_UNCOMPRESSED_12_BIT, - 12, - 1, - }, - { - MEDIA_BUS_FMT_SRGGB12_1X12, - DATA_TYPE_RAW_12BIT, - DECODE_FORMAT_UNCOMPRESSED_12_BIT, - 12, - 1, - }, - { - MEDIA_BUS_FMT_Y10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, -}; - -static const struct csid_format csid_formats_8x96[] = { - { - MEDIA_BUS_FMT_UYVY8_2X8, - DATA_TYPE_YUV422_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 2, - }, - { - MEDIA_BUS_FMT_VYUY8_2X8, - DATA_TYPE_YUV422_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 2, - }, - { - MEDIA_BUS_FMT_YUYV8_2X8, - DATA_TYPE_YUV422_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 2, - }, - { - MEDIA_BUS_FMT_YVYU8_2X8, - DATA_TYPE_YUV422_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 2, - }, - { - MEDIA_BUS_FMT_SBGGR8_1X8, - DATA_TYPE_RAW_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 1, - }, - { - MEDIA_BUS_FMT_SGBRG8_1X8, - DATA_TYPE_RAW_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 1, - }, - { - MEDIA_BUS_FMT_SGRBG8_1X8, - DATA_TYPE_RAW_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 1, - }, - { - MEDIA_BUS_FMT_SRGGB8_1X8, - DATA_TYPE_RAW_8BIT, - DECODE_FORMAT_UNCOMPRESSED_8_BIT, - 8, - 1, - }, - { - MEDIA_BUS_FMT_SBGGR10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, - { - MEDIA_BUS_FMT_SGBRG10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, - { - MEDIA_BUS_FMT_SGRBG10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, - { - MEDIA_BUS_FMT_SRGGB10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, - { - MEDIA_BUS_FMT_SBGGR12_1X12, - DATA_TYPE_RAW_12BIT, - DECODE_FORMAT_UNCOMPRESSED_12_BIT, - 12, - 1, - }, - { - MEDIA_BUS_FMT_SGBRG12_1X12, - DATA_TYPE_RAW_12BIT, - DECODE_FORMAT_UNCOMPRESSED_12_BIT, - 12, - 1, - }, - { - MEDIA_BUS_FMT_SGRBG12_1X12, - DATA_TYPE_RAW_12BIT, - DECODE_FORMAT_UNCOMPRESSED_12_BIT, - 12, - 1, - }, - { - MEDIA_BUS_FMT_SRGGB12_1X12, - DATA_TYPE_RAW_12BIT, - DECODE_FORMAT_UNCOMPRESSED_12_BIT, - 12, - 1, - }, - { - MEDIA_BUS_FMT_SBGGR14_1X14, - DATA_TYPE_RAW_14BIT, - DECODE_FORMAT_UNCOMPRESSED_14_BIT, - 14, - 1, - }, - { - MEDIA_BUS_FMT_SGBRG14_1X14, - DATA_TYPE_RAW_14BIT, - DECODE_FORMAT_UNCOMPRESSED_14_BIT, - 14, - 1, - }, - { - MEDIA_BUS_FMT_SGRBG14_1X14, - DATA_TYPE_RAW_14BIT, - DECODE_FORMAT_UNCOMPRESSED_14_BIT, - 14, - 1, - }, - { - MEDIA_BUS_FMT_SRGGB14_1X14, - DATA_TYPE_RAW_14BIT, - DECODE_FORMAT_UNCOMPRESSED_14_BIT, - 14, - 1, - }, - { - MEDIA_BUS_FMT_Y10_1X10, - DATA_TYPE_RAW_10BIT, - DECODE_FORMAT_UNCOMPRESSED_10_BIT, - 10, - 1, - }, +const char * const csid_testgen_modes[] = { + "Disabled", + "Incrementing", + "Alternating 0x55/0xAA", + "All Zeros 0x00", + "All Ones 0xFF", + "Pseudo-random Data", + "User Specified", + "Complex pattern", + "Color box", + "Color bars", + NULL }; -static u32 csid_find_code(u32 *code, unsigned int n_code, - unsigned int index, u32 req_code) +u32 csid_find_code(u32 *codes, unsigned int ncodes, + unsigned int match_format_idx, u32 match_code) { int i; - if (!req_code && (index >= n_code)) + if (!match_code && (match_format_idx >= ncodes)) return 0; - for (i = 0; i < n_code; i++) - if (req_code) { - if (req_code == code[i]) - return req_code; + for (i = 0; i < ncodes; i++) + if (match_code) { + if (codes[i] == match_code) + return match_code; } else { - if (i == index) - return code[i]; + if (i == match_format_idx) + return codes[i]; } - return code[0]; + return codes[0]; } -static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, - unsigned int index, u32 src_req_code) -{ - if (csid->camss->version == CAMSS_8x16) { - if (index > 0) - return 0; - - return sink_code; - } else if (csid->camss->version == CAMSS_8x96 || - csid->camss->version == CAMSS_660) { - switch (sink_code) { - case MEDIA_BUS_FMT_SBGGR10_1X10: - { - u32 src_code[] = { - MEDIA_BUS_FMT_SBGGR10_1X10, - MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, - }; - - return csid_find_code(src_code, ARRAY_SIZE(src_code), - index, src_req_code); - } - case MEDIA_BUS_FMT_Y10_1X10: - { - u32 src_code[] = { - MEDIA_BUS_FMT_Y10_1X10, - MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, - }; - - return csid_find_code(src_code, ARRAY_SIZE(src_code), - index, src_req_code); - } - default: - if (index > 0) - return 0; - - return sink_code; - } - } else { - return 0; - } -} - -static const struct csid_format *csid_get_fmt_entry( - const struct csid_format *formats, - unsigned int nformat, - u32 code) +const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats, + unsigned int nformats, + u32 code) { unsigned int i; - for (i = 0; i < nformat; i++) + for (i = 0; i < nformats; i++) if (code == formats[i].code) return &formats[i]; @@ -434,41 +77,23 @@ static const struct csid_format *csid_get_fmt_entry( } /* - * csid_isr - CSID module interrupt handler - * @irq: Interrupt line - * @dev: CSID device - * - * Return IRQ_HANDLED on success - */ -static irqreturn_t csid_isr(int irq, void *dev) -{ - struct csid_device *csid = dev; - enum camss_version ver = csid->camss->version; - u32 value; - - value = readl_relaxed(csid->base + CAMSS_CSID_IRQ_STATUS(ver)); - writel_relaxed(value, csid->base + CAMSS_CSID_IRQ_CLEAR_CMD(ver)); - - if ((value >> 11) & 0x1) - complete(&csid->reset_complete); - - return IRQ_HANDLED; -} - -/* * csid_set_clock_rates - Calculate and set clock rates on CSID module * @csiphy: CSID device */ static int csid_set_clock_rates(struct csid_device *csid) { struct device *dev = csid->camss->dev; - u32 pixel_clock; + const struct csid_format *fmt; + s64 link_freq; int i, j; int ret; - ret = camss_get_pixel_clock(&csid->subdev.entity, &pixel_clock); - if (ret) - pixel_clock = 0; + fmt = csid_get_fmt_entry(csid->formats, csid->nformats, + csid->fmt[MSM_CSIPHY_PAD_SINK].code); + link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp, + csid->phy.lane_cnt); + if (link_freq < 0) + link_freq = 0; for (i = 0; i < csid->nclocks; i++) { struct camss_clock *clock = &csid->clock[i]; @@ -477,13 +102,7 @@ static int csid_set_clock_rates(struct csid_device *csid) !strcmp(clock->name, "csi1") || !strcmp(clock->name, "csi2") || !strcmp(clock->name, "csi3")) { - const struct csid_format *f = csid_get_fmt_entry( - csid->formats, - csid->nformats, - csid->fmt[MSM_CSIPHY_PAD_SINK].code); - u8 num_lanes = csid->phy.lane_cnt; - u64 min_rate = pixel_clock * f->bpp / - (2 * num_lanes * 4); + u64 min_rate = link_freq / 4; long rate; camss_add_clock_margin(&min_rate); @@ -515,6 +134,8 @@ static int csid_set_clock_rates(struct csid_device *csid) dev_err(dev, "clk set rate failed: %d\n", ret); return ret; } + } else if (clock->nfreqs) { + clk_set_rate(clock->clk, clock->freq[0]); } } @@ -522,31 +143,6 @@ static int csid_set_clock_rates(struct csid_device *csid) } /* - * csid_reset - Trigger reset on CSID module and wait to complete - * @csid: CSID device - * - * Return 0 on success or a negative error code otherwise - */ -static int csid_reset(struct csid_device *csid) -{ - unsigned long time; - - reinit_completion(&csid->reset_complete); - - writel_relaxed(0x7fff, csid->base + - CAMSS_CSID_RST_CMD(csid->camss->version)); - - time = wait_for_completion_timeout(&csid->reset_complete, - msecs_to_jiffies(CSID_RESET_TIMEOUT_MS)); - if (!time) { - dev_err(csid->camss->dev, "CSID reset timeout\n"); - return -EIO; - } - - return 0; -} - -/* * csid_set_power - Power on/off CSID module * @sd: CSID V4L2 subdevice * @on: Requested power state @@ -560,8 +156,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) int ret; if (on) { - u32 hw_version; - ret = pm_runtime_get_sync(dev); if (ret < 0) { pm_runtime_put_sync(dev); @@ -590,7 +184,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) enable_irq(csid->irq); - ret = csid_reset(csid); + ret = csid->ops->reset(csid); if (ret < 0) { disable_irq(csid->irq); camss_disable_clocks(csid->nclocks, csid->clock); @@ -599,8 +193,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) return ret; } - hw_version = readl_relaxed(csid->base + CAMSS_CSID_HW_VERSION); - dev_dbg(dev, "CSID HW Version = 0x%08x\n", hw_version); + csid->ops->hw_version(csid); } else { disable_irq(csid->irq); camss_disable_clocks(csid->nclocks, csid->clock); @@ -623,16 +216,9 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) static int csid_set_stream(struct v4l2_subdev *sd, int enable) { struct csid_device *csid = v4l2_get_subdevdata(sd); - struct csid_testgen_config *tg = &csid->testgen; - enum camss_version ver = csid->camss->version; - u32 val; + int ret; if (enable) { - u8 vc = 0; /* Virtual Channel 0 */ - u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ - u8 dt, dt_shift, df; - int ret; - ret = v4l2_ctrl_handler_setup(&csid->ctrls); if (ret < 0) { dev_err(csid->camss->dev, @@ -640,116 +226,13 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) return ret; } - if (!tg->enabled && + if (!csid->testgen.enabled && !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK])) return -ENOLINK; - - if (tg->enabled) { - /* Config Test Generator */ - struct v4l2_mbus_framefmt *f = - &csid->fmt[MSM_CSID_PAD_SRC]; - const struct csid_format *format = csid_get_fmt_entry( - csid->formats, csid->nformats, f->code); - u32 num_bytes_per_line = - f->width * format->bpp * format->spp / 8; - u32 num_lines = f->height; - - /* 31:24 V blank, 23:13 H blank, 3:2 num of active DT */ - /* 1:0 VC */ - val = ((CAMSS_CSID_TG_VC_CFG_V_BLANKING & 0xff) << 24) | - ((CAMSS_CSID_TG_VC_CFG_H_BLANKING & 0x7ff) << 13); - writel_relaxed(val, csid->base + - CAMSS_CSID_TG_VC_CFG(ver)); - - /* 28:16 bytes per lines, 12:0 num of lines */ - val = ((num_bytes_per_line & 0x1fff) << 16) | - (num_lines & 0x1fff); - writel_relaxed(val, csid->base + - CAMSS_CSID_TG_DT_n_CGG_0(ver, 0)); - - dt = format->data_type; - - /* 5:0 data type */ - val = dt; - writel_relaxed(val, csid->base + - CAMSS_CSID_TG_DT_n_CGG_1(ver, 0)); - - /* 2:0 output test pattern */ - val = tg->payload_mode; - writel_relaxed(val, csid->base + - CAMSS_CSID_TG_DT_n_CGG_2(ver, 0)); - - df = format->decode_format; - } else { - struct v4l2_mbus_framefmt *f = - &csid->fmt[MSM_CSID_PAD_SINK]; - const struct csid_format *format = csid_get_fmt_entry( - csid->formats, csid->nformats, f->code); - struct csid_phy_config *phy = &csid->phy; - - val = phy->lane_cnt - 1; - val |= phy->lane_assign << 4; - - writel_relaxed(val, - csid->base + CAMSS_CSID_CORE_CTRL_0); - - val = phy->csiphy_id << 17; - val |= 0x9; - - writel_relaxed(val, - csid->base + CAMSS_CSID_CORE_CTRL_1); - - dt = format->data_type; - df = format->decode_format; - } - - /* Config LUT */ - - dt_shift = (cid % 4) * 8; - - val = readl_relaxed(csid->base + - CAMSS_CSID_CID_LUT_VC_n(ver, vc)); - val &= ~(0xff << dt_shift); - val |= dt << dt_shift; - writel_relaxed(val, csid->base + - CAMSS_CSID_CID_LUT_VC_n(ver, vc)); - - val = CAMSS_CSID_CID_n_CFG_ISPIF_EN; - val |= CAMSS_CSID_CID_n_CFG_RDI_EN; - val |= df << CAMSS_CSID_CID_n_CFG_DECODE_FORMAT_SHIFT; - val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_RAW_DUMP; - - if (csid->camss->version == CAMSS_8x96 || - csid->camss->version == CAMSS_660) { - u32 sink_code = csid->fmt[MSM_CSID_PAD_SINK].code; - u32 src_code = csid->fmt[MSM_CSID_PAD_SRC].code; - - if ((sink_code == MEDIA_BUS_FMT_SBGGR10_1X10 && - src_code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) || - (sink_code == MEDIA_BUS_FMT_Y10_1X10 && - src_code == MEDIA_BUS_FMT_Y10_2X8_PADHI_LE)) { - val |= CAMSS_CSID_CID_n_CFG_RDI_MODE_PLAIN_PACKING; - val |= CAMSS_CSID_CID_n_CFG_PLAIN_FORMAT_16; - val |= CAMSS_CSID_CID_n_CFG_PLAIN_ALIGNMENT_LSB; - } - } - - writel_relaxed(val, csid->base + - CAMSS_CSID_CID_n_CFG(ver, cid)); - - if (tg->enabled) { - val = CAMSS_CSID_TG_CTRL_ENABLE; - writel_relaxed(val, csid->base + - CAMSS_CSID_TG_CTRL(ver)); - } - } else { - if (tg->enabled) { - val = CAMSS_CSID_TG_CTRL_DISABLE; - writel_relaxed(val, csid->base + - CAMSS_CSID_TG_CTRL(ver)); - } } + csid->ops->configure_stream(csid, enable); + return 0; } @@ -818,7 +301,7 @@ static void csid_try_format(struct csid_device *csid, *fmt = *__csid_get_format(csid, cfg, MSM_CSID_PAD_SINK, which); - fmt->code = csid_src_pad_code(csid, fmt->code, 0, code); + fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code); } else { /* Test generator is enabled, set format on source */ /* pad to allow test generator usage */ @@ -868,7 +351,7 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd, MSM_CSID_PAD_SINK, code->which); - code->code = csid_src_pad_code(csid, sink_fmt->code, + code->code = csid->ops->src_pad_code(csid, sink_fmt->code, code->index, 0); if (!code->code) return -EINVAL; @@ -1004,15 +487,6 @@ static int csid_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) return csid_set_format(sd, fh ? fh->pad : NULL, &format); } -static const char * const csid_test_pattern_menu[] = { - "Disabled", - "Incrementing", - "Alternating 0x55/0xAA", - "All Zeros 0x00", - "All Ones 0xFF", - "Pseudo-random Data", -}; - /* * csid_set_test_pattern - Set test generator's pattern mode * @csid: CSID device @@ -1030,25 +504,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value) tg->enabled = !!value; - switch (value) { - case 1: - tg->payload_mode = CSID_PAYLOAD_MODE_INCREMENTING; - break; - case 2: - tg->payload_mode = CSID_PAYLOAD_MODE_ALTERNATING_55_AA; - break; - case 3: - tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ZEROES; - break; - case 4: - tg->payload_mode = CSID_PAYLOAD_MODE_ALL_ONES; - break; - case 5: - tg->payload_mode = CSID_PAYLOAD_MODE_RANDOM; - break; - } - - return 0; + return csid->ops->configure_testgen_pattern(csid, value); } /* @@ -1097,26 +553,23 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, csid->id = id; if (camss->version == CAMSS_8x16) { - csid->formats = csid_formats_8x16; - csid->nformats = - ARRAY_SIZE(csid_formats_8x16); + csid->ops = &csid_ops_4_1; } else if (camss->version == CAMSS_8x96 || camss->version == CAMSS_660) { - csid->formats = csid_formats_8x96; - csid->nformats = - ARRAY_SIZE(csid_formats_8x96); + csid->ops = &csid_ops_4_7; + } else if (camss->version == CAMSS_845) { + csid->ops = &csid_ops_170; } else { return -EINVAL; } + csid->ops->subdev_init(csid); /* Memory */ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]); csid->base = devm_ioremap_resource(dev, r); - if (IS_ERR(csid->base)) { - dev_err(dev, "could not map memory\n"); + if (IS_ERR(csid->base)) return PTR_ERR(csid->base); - } /* Interrupt */ @@ -1130,8 +583,8 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, csid->irq = r->start; snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d", dev_name(dev), MSM_CSID_NAME, csid->id); - ret = devm_request_irq(dev, csid->irq, csid_isr, - IRQF_TRIGGER_RISING, csid->irq_name, csid); + ret = devm_request_irq(dev, csid->irq, csid->ops->isr, + IRQF_TRIGGER_RISING, csid->irq_name, csid); if (ret < 0) { dev_err(dev, "request_irq failed: %d\n", ret); return ret; @@ -1341,8 +794,8 @@ int msm_csid_register_entity(struct csid_device *csid, csid->testgen_mode = v4l2_ctrl_new_std_menu_items(&csid->ctrls, &csid_ctrl_ops, V4L2_CID_TEST_PATTERN, - ARRAY_SIZE(csid_test_pattern_menu) - 1, 0, 0, - csid_test_pattern_menu); + csid->testgen.nmodes, 0, 0, + csid->testgen.modes); if (csid->ctrls.error) { dev_err(dev, "Failed to init ctrl: %d\n", csid->ctrls.error); diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h index 1824b3745e10..814ebc7c29d6 100644 --- a/drivers/media/platform/qcom/camss/camss-csid.h +++ b/drivers/media/platform/qcom/camss/camss-csid.h @@ -11,6 +11,7 @@ #define QC_MSM_CAMSS_CSID_H #include <linux/clk.h> +#include <linux/interrupt.h> #include <media/media-entity.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -21,18 +22,59 @@ #define MSM_CSID_PAD_SRC 1 #define MSM_CSID_PADS_NUM 2 -enum csid_payload_mode { - CSID_PAYLOAD_MODE_INCREMENTING = 0, - CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 1, - CSID_PAYLOAD_MODE_ALL_ZEROES = 2, - CSID_PAYLOAD_MODE_ALL_ONES = 3, - CSID_PAYLOAD_MODE_RANDOM = 4, - CSID_PAYLOAD_MODE_USER_SPECIFIED = 5, +#define DATA_TYPE_EMBEDDED_DATA_8BIT 0x12 +#define DATA_TYPE_YUV420_8BIT 0x18 +#define DATA_TYPE_YUV420_10BIT 0x19 +#define DATA_TYPE_YUV420_8BIT_LEGACY 0x1a +#define DATA_TYPE_YUV420_8BIT_SHIFTED 0x1c /* Chroma Shifted Pixel Sampling */ +#define DATA_TYPE_YUV420_10BIT_SHIFTED 0x1d /* Chroma Shifted Pixel Sampling */ +#define DATA_TYPE_YUV422_8BIT 0x1e +#define DATA_TYPE_YUV422_10BIT 0x1f +#define DATA_TYPE_RGB444 0x20 +#define DATA_TYPE_RGB555 0x21 +#define DATA_TYPE_RGB565 0x22 +#define DATA_TYPE_RGB666 0x23 +#define DATA_TYPE_RGB888 0x24 +#define DATA_TYPE_RAW_24BIT 0x27 +#define DATA_TYPE_RAW_6BIT 0x28 +#define DATA_TYPE_RAW_7BIT 0x29 +#define DATA_TYPE_RAW_8BIT 0x2a +#define DATA_TYPE_RAW_10BIT 0x2b +#define DATA_TYPE_RAW_12BIT 0x2c +#define DATA_TYPE_RAW_14BIT 0x2d +#define DATA_TYPE_RAW_16BIT 0x2e +#define DATA_TYPE_RAW_20BIT 0x2f + +#define CSID_RESET_TIMEOUT_MS 500 + +enum csid_testgen_mode { + CSID_PAYLOAD_MODE_DISABLED = 0, + CSID_PAYLOAD_MODE_INCREMENTING = 1, + CSID_PAYLOAD_MODE_ALTERNATING_55_AA = 2, + CSID_PAYLOAD_MODE_ALL_ZEROES = 3, + CSID_PAYLOAD_MODE_ALL_ONES = 4, + CSID_PAYLOAD_MODE_RANDOM = 5, + CSID_PAYLOAD_MODE_USER_SPECIFIED = 6, + CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1 = 6, /* excluding disabled */ + CSID_PAYLOAD_MODE_COMPLEX_PATTERN = 7, + CSID_PAYLOAD_MODE_COLOR_BOX = 8, + CSID_PAYLOAD_MODE_COLOR_BARS = 9, + CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2 = 9, /* excluding disabled */ +}; + +struct csid_format { + u32 code; + u8 data_type; + u8 decode_format; + u8 bpp; + u8 spp; /* bus samples per pixel */ }; struct csid_testgen_config { + enum csid_testgen_mode mode; + const char * const*modes; + u8 nmodes; u8 enabled; - enum csid_payload_mode payload_mode; }; struct csid_phy_config { @@ -41,6 +83,65 @@ struct csid_phy_config { u32 lane_assign; }; +struct csid_device; + +struct csid_hw_ops { + /* + * configure_stream - Configures and starts CSID input stream + * @csid: CSID device + */ + void (*configure_stream)(struct csid_device *csid, u8 enable); + + /* + * configure_testgen_pattern - Validates and configures output pattern mode + * of test pattern generator + * @csid: CSID device + */ + int (*configure_testgen_pattern)(struct csid_device *csid, s32 val); + + /* + * hw_version - Read hardware version register from hardware + * @csid: CSID device + */ + u32 (*hw_version)(struct csid_device *csid); + + /* + * isr - CSID module interrupt service routine + * @irq: Interrupt line + * @dev: CSID device + * + * Return IRQ_HANDLED on success + */ + irqreturn_t (*isr)(int irq, void *dev); + + /* + * reset - Trigger reset on CSID module and wait to complete + * @csid: CSID device + * + * Return 0 on success or a negative error code otherwise + */ + int (*reset)(struct csid_device *csid); + + /* + * src_pad_code - Pick an output/src format based on the input/sink format + * @csid: CSID device + * @sink_code: The sink format of the input + * @match_format_idx: Request preferred index, as defined by subdevice csid_format. + * Set @match_code to 0 if used. + * @match_code: Request preferred code, set @match_format_idx to 0 if used + * + * Return 0 on failure or src format code otherwise + */ + u32 (*src_pad_code)(struct csid_device *csid, u32 sink_code, + unsigned int match_format_idx, u32 match_code); + + /* + * subdev_init - Initialize CSID device according for hardware revision + * @csid: CSID device + */ + void (*subdev_init)(struct csid_device *csid); +}; + struct csid_device { struct camss *camss; u8 id; @@ -60,10 +161,36 @@ struct csid_device { struct v4l2_ctrl *testgen_mode; const struct csid_format *formats; unsigned int nformats; + const struct csid_hw_ops *ops; }; struct resources; +/* + * csid_find_code - Find a format code in an array using array index or format code + * @codes: Array of format codes + * @ncodes: Length of @code array + * @req_format_idx: Request preferred index, as defined by subdevice csid_format. + * Set @match_code to 0 if used. + * @match_code: Request preferred code, set @req_format_idx to 0 if used + * + * Return 0 on failure or format code otherwise + */ +u32 csid_find_code(u32 *codes, unsigned int ncode, + unsigned int match_format_idx, u32 match_code); + +/* + * csid_get_fmt_entry - Find csid_format entry with matching format code + * @formats: Array of format csid_format entries + * @nformats: Length of @nformats array + * @code: Desired format code + * + * Return formats[0] on failure to find code + */ +const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats, + unsigned int nformats, + u32 code); + int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, const struct resources *res, u8 id); @@ -74,4 +201,11 @@ void msm_csid_unregister_entity(struct csid_device *csid); void msm_csid_get_csid_id(struct media_entity *entity, u8 *id); +extern const char * const csid_testgen_modes[]; + +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_170; + + #endif /* QC_MSM_CAMSS_CSID_H */ diff --git a/drivers/media/platform/qcom/camss/camss-csiphy-2ph-1-0.c b/drivers/media/platform/qcom/camss/camss-csiphy-2ph-1-0.c index 12bce391d71f..30b454c369ab 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy-2ph-1-0.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy-2ph-1-0.c @@ -51,16 +51,13 @@ static void csiphy_reset(struct csiphy_device *csiphy) * * Helper function to calculate settle count value. This is * based on the CSI2 T_hs_settle parameter which in turn - * is calculated based on the CSI2 transmitter pixel clock - * frequency. + * is calculated based on the CSI2 transmitter link frequency. * - * Return settle count value or 0 if the CSI2 pixel clock - * frequency is not available + * Return settle count value or 0 if the CSI2 link frequency + * is not available */ -static u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes, - u32 timer_clk_rate) +static u8 csiphy_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate) { - u32 mipi_clock; /* Hz */ u32 ui; /* ps */ u32 timer_period; /* ps */ u32 t_hs_prepare_max; /* ps */ @@ -68,8 +65,10 @@ static u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes, u32 t_hs_settle; /* ps */ u8 settle_cnt; - mipi_clock = pixel_clock * bpp / (2 * num_lanes); - ui = div_u64(1000000000000LL, mipi_clock); + if (link_freq <= 0) + return 0; + + ui = div_u64(1000000000000LL, link_freq); ui /= 2; t_hs_prepare_max = 85000 + 6 * ui; t_hs_prepare_zero_min = 145000 + 10 * ui; @@ -83,15 +82,14 @@ static u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes, static void csiphy_lanes_enable(struct csiphy_device *csiphy, struct csiphy_config *cfg, - u32 pixel_clock, u8 bpp, u8 lane_mask) + s64 link_freq, u8 lane_mask) { struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; u8 settle_cnt; u8 val, l = 0; int i = 0; - settle_cnt = csiphy_settle_cnt_calc(pixel_clock, bpp, c->num_data, - csiphy->timer_clk_rate); + settle_cnt = csiphy_settle_cnt_calc(link_freq, csiphy->timer_clk_rate); writel_relaxed(0x1, csiphy->base + CAMSS_CSI_PHY_GLBL_T_INIT_CFG0); 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 97cb9de85031..e318c822ab04 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 @@ -47,6 +47,105 @@ #define CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_SHOW_REV_ID BIT(1) #define CSIPHY_3PH_CMN_CSI_COMMON_STATUSn(n) (0x8b0 + 0x4 * (n)) +#define CSIPHY_DEFAULT_PARAMS 0 +#define CSIPHY_LANE_ENABLE 1 +#define CSIPHY_SETTLE_CNT_LOWER_BYTE 2 +#define CSIPHY_SETTLE_CNT_HIGHER_BYTE 3 +#define CSIPHY_DNP_PARAMS 4 +#define CSIPHY_2PH_REGS 5 +#define CSIPHY_3PH_REGS 6 + +struct csiphy_reg_t { + s32 reg_addr; + s32 reg_data; + s32 delay; + u32 csiphy_param_type; +}; + +static const struct +csiphy_reg_t lane_regs_sdm845[5][14] = { + { + {0x0004, 0x0C, 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}, + {0x0028, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x003C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0000, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0008, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x000c, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0010, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0038, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0060, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0064, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0704, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x072C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0734, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x071C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0714, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0728, 0x04, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x073C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0700, 0x80, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0708, 0x14, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x070C, 0xA5, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0710, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0738, 0x1F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0760, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0764, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0204, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x022C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0234, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x021C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0214, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0228, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x023C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0200, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0208, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x020C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0210, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0238, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0260, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0264, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0404, 0x0C, 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}, + {0x0428, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x043C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0400, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0408, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x040C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0410, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0438, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0460, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0464, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, + { + {0x0604, 0x0C, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x062C, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0634, 0x0F, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x061C, 0x0A, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0614, 0x60, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0628, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x063C, 0xB8, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0600, 0x91, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0608, 0x00, 0x00, CSIPHY_SETTLE_CNT_LOWER_BYTE}, + {0x060C, 0x00, 0x00, CSIPHY_DNP_PARAMS}, + {0x0610, 0x52, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0638, 0xFE, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0660, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0664, 0x7F, 0x00, CSIPHY_DEFAULT_PARAMS}, + }, +}; + static void csiphy_hw_version_read(struct csiphy_device *csiphy, struct device *dev) { @@ -107,24 +206,23 @@ static irqreturn_t csiphy_isr(int irq, void *dev) * * Helper function to calculate settle count value. This is * based on the CSI2 T_hs_settle parameter which in turn - * is calculated based on the CSI2 transmitter pixel clock - * frequency. + * is calculated based on the CSI2 transmitter link frequency. * - * Return settle count value or 0 if the CSI2 pixel clock - * frequency is not available + * Return settle count value or 0 if the CSI2 link frequency + * is not available */ -static u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes, - u32 timer_clk_rate) +static u8 csiphy_settle_cnt_calc(s64 link_freq, u32 timer_clk_rate) { - u32 mipi_clock; /* Hz */ u32 ui; /* ps */ u32 timer_period; /* ps */ u32 t_hs_prepare_max; /* ps */ u32 t_hs_settle; /* ps */ u8 settle_cnt; - mipi_clock = pixel_clock * bpp / (2 * num_lanes); - ui = div_u64(1000000000000LL, mipi_clock); + if (link_freq <= 0) + return 0; + + ui = div_u64(1000000000000LL, link_freq); ui /= 2; t_hs_prepare_max = 85000 + 6 * ui; t_hs_settle = t_hs_prepare_max; @@ -135,26 +233,13 @@ static u8 csiphy_settle_cnt_calc(u32 pixel_clock, u8 bpp, u8 num_lanes, return settle_cnt; } -static void csiphy_lanes_enable(struct csiphy_device *csiphy, - struct csiphy_config *cfg, - u32 pixel_clock, u8 bpp, u8 lane_mask) +static void csiphy_gen1_config_lanes(struct csiphy_device *csiphy, + struct csiphy_config *cfg, + u8 settle_cnt) { struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; - u8 settle_cnt; - u8 val, l = 0; - int i; - - settle_cnt = csiphy_settle_cnt_calc(pixel_clock, bpp, c->num_data, - csiphy->timer_clk_rate); - - val = BIT(c->clk.pos); - for (i = 0; i < c->num_data; i++) - val |= BIT(c->data[i].pos * 2); - - writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(5)); - - val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B; - writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(6)); + int i, l = 0; + u8 val; for (i = 0; i <= c->num_data; i++) { if (i == c->num_data) @@ -208,6 +293,64 @@ static void csiphy_lanes_enable(struct csiphy_device *csiphy, val = CSIPHY_3PH_LNn_MISC1_IS_CLKLANE; writel_relaxed(val, csiphy->base + CSIPHY_3PH_LNn_MISC1(l)); +} + +static void csiphy_gen2_config_lanes(struct csiphy_device *csiphy, + u8 settle_cnt) +{ + int i, l; + u32 val; + + for (l = 0; l < 5; l++) { + for (i = 0; i < 14; i++) { + const struct csiphy_reg_t *r = &lane_regs_sdm845[l][i]; + + switch (r->csiphy_param_type) { + case CSIPHY_SETTLE_CNT_LOWER_BYTE: + val = settle_cnt & 0xff; + break; + case CSIPHY_DNP_PARAMS: + continue; + default: + val = r->reg_data; + break; + } + writel_relaxed(val, csiphy->base + r->reg_addr); + } + } +} + +static void csiphy_lanes_enable(struct csiphy_device *csiphy, + struct csiphy_config *cfg, + s64 link_freq, u8 lane_mask) +{ + struct csiphy_lanes_cfg *c = &cfg->csi2->lane_cfg; + u8 settle_cnt; + u8 val; + int i; + + settle_cnt = csiphy_settle_cnt_calc(link_freq, csiphy->timer_clk_rate); + + val = BIT(c->clk.pos); + for (i = 0; i < c->num_data; i++) + val |= BIT(c->data[i].pos * 2); + + writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(5)); + + val = CSIPHY_3PH_CMN_CSI_COMMON_CTRL6_COMMON_PWRDN_B; + writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(6)); + + val = 0x02; + writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(7)); + + val = 0x00; + writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(0)); + + if (csiphy->camss->version == CAMSS_8x16 || + csiphy->camss->version == CAMSS_8x96) + csiphy_gen1_config_lanes(csiphy, cfg, settle_cnt); + else if (csiphy->camss->version == CAMSS_845) + csiphy_gen2_config_lanes(csiphy, settle_cnt); val = 0xff; writel_relaxed(val, csiphy->base + CSIPHY_3PH_CMN_CSI_COMMON_CTRLn(11)); diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c index 509c9a59c09c..b3c3bf19e522 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.c +++ b/drivers/media/platform/qcom/camss/camss-csiphy.c @@ -73,6 +73,30 @@ static const struct csiphy_format csiphy_formats_8x96[] = { { MEDIA_BUS_FMT_Y10_1X10, 10 }, }; +static const struct csiphy_format csiphy_formats_sdm845[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, + { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, + { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, + { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, + { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, + { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, + { MEDIA_BUS_FMT_SRGGB8_1X8, 8 }, + { MEDIA_BUS_FMT_SBGGR10_1X10, 10 }, + { MEDIA_BUS_FMT_SGBRG10_1X10, 10 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 10 }, + { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, + { MEDIA_BUS_FMT_SBGGR12_1X12, 12 }, + { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, + { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, + { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, + { MEDIA_BUS_FMT_SBGGR14_1X14, 14 }, + { MEDIA_BUS_FMT_SGBRG14_1X14, 14 }, + { MEDIA_BUS_FMT_SGRBG14_1X14, 14 }, + { MEDIA_BUS_FMT_SRGGB14_1X14, 14 }, + { MEDIA_BUS_FMT_Y10_1X10, 10 }, +}; + /* * csiphy_get_bpp - map media bus format to bits per pixel * @formats: supported media bus formats array @@ -102,23 +126,23 @@ static u8 csiphy_get_bpp(const struct csiphy_format *formats, static int csiphy_set_clock_rates(struct csiphy_device *csiphy) { struct device *dev = csiphy->camss->dev; - u32 pixel_clock; + s64 link_freq; int i, j; int ret; - ret = camss_get_pixel_clock(&csiphy->subdev.entity, &pixel_clock); - if (ret) - pixel_clock = 0; + u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats, + csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); + u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; + + link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes); + if (link_freq < 0) + link_freq = 0; for (i = 0; i < csiphy->nclocks; i++) { struct camss_clock *clock = &csiphy->clock[i]; if (csiphy->rate_set[i]) { - u8 bpp = csiphy_get_bpp(csiphy->formats, - csiphy->nformats, - csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); - u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; - u64 min_rate = pixel_clock * bpp / (2 * num_lanes * 4); + u64 min_rate = link_freq / 4; long round_rate; camss_add_clock_margin(&min_rate); @@ -238,37 +262,37 @@ static u8 csiphy_get_lane_mask(struct csiphy_lanes_cfg *lane_cfg) static int csiphy_stream_on(struct csiphy_device *csiphy) { struct csiphy_config *cfg = &csiphy->cfg; - u32 pixel_clock; + s64 link_freq; u8 lane_mask = csiphy_get_lane_mask(&cfg->csi2->lane_cfg); u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats, csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); + u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; u8 val; - int ret; - ret = camss_get_pixel_clock(&csiphy->subdev.entity, &pixel_clock); - if (ret) { - dev_err(csiphy->camss->dev, - "Cannot get CSI2 transmitter's pixel clock\n"); - return -EINVAL; - } - if (!pixel_clock) { + link_freq = camss_get_link_freq(&csiphy->subdev.entity, bpp, num_lanes); + + if (link_freq < 0) { dev_err(csiphy->camss->dev, - "Got pixel clock == 0, cannot continue\n"); + "Cannot get CSI2 transmitter's link frequency\n"); return -EINVAL; } - val = readl_relaxed(csiphy->base_clk_mux); - if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) { - val &= ~0xf0; - val |= cfg->csid_id << 4; - } else { - val &= ~0xf; - val |= cfg->csid_id; + if (csiphy->base_clk_mux) { + val = readl_relaxed(csiphy->base_clk_mux); + if (cfg->combo_mode && (lane_mask & 0x18) == 0x18) { + val &= ~0xf0; + val |= cfg->csid_id << 4; + } else { + val &= ~0xf; + val |= cfg->csid_id; + } + writel_relaxed(val, csiphy->base_clk_mux); + + /* Enforce reg write ordering between clk mux & lane enabling */ + wmb(); } - writel_relaxed(val, csiphy->base_clk_mux); - wmb(); - csiphy->ops->lanes_enable(csiphy, cfg, pixel_clock, bpp, lane_mask); + csiphy->ops->lanes_enable(csiphy, cfg, link_freq, lane_mask); return 0; } @@ -557,6 +581,10 @@ int msm_csiphy_subdev_init(struct camss *camss, csiphy->ops = &csiphy_ops_3ph_1_0; csiphy->formats = csiphy_formats_8x96; csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96); + } else if (camss->version == CAMSS_845) { + csiphy->ops = &csiphy_ops_3ph_1_0; + csiphy->formats = csiphy_formats_sdm845; + csiphy->nformats = ARRAY_SIZE(csiphy_formats_sdm845); } else { return -EINVAL; } @@ -565,16 +593,18 @@ int msm_csiphy_subdev_init(struct camss *camss, r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]); csiphy->base = devm_ioremap_resource(dev, r); - if (IS_ERR(csiphy->base)) { - dev_err(dev, "could not map memory\n"); + if (IS_ERR(csiphy->base)) return PTR_ERR(csiphy->base); - } - r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]); - csiphy->base_clk_mux = devm_ioremap_resource(dev, r); - if (IS_ERR(csiphy->base_clk_mux)) { - dev_err(dev, "could not map memory\n"); - return PTR_ERR(csiphy->base_clk_mux); + if (camss->version == CAMSS_8x16 || + camss->version == CAMSS_8x96) { + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, + res->reg[1]); + csiphy->base_clk_mux = devm_ioremap_resource(dev, r); + if (IS_ERR(csiphy->base_clk_mux)) + return PTR_ERR(csiphy->base_clk_mux); + } else { + csiphy->base_clk_mux = NULL; } /* Interrupt */ diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h index f7967ef836dc..d71b8bc6ec00 100644 --- a/drivers/media/platform/qcom/camss/camss-csiphy.h +++ b/drivers/media/platform/qcom/camss/camss-csiphy.h @@ -50,7 +50,7 @@ struct csiphy_hw_ops { void (*reset)(struct csiphy_device *csiphy); void (*lanes_enable)(struct csiphy_device *csiphy, struct csiphy_config *cfg, - u32 pixel_clock, u8 bpp, u8 lane_mask); + s64 link_freq, u8 lane_mask); void (*lanes_disable)(struct csiphy_device *csiphy, struct csiphy_config *cfg); irqreturn_t (*isr)(int irq, void *dev); diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index adeb92808998..37611c8861da 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -161,6 +161,7 @@ static const u32 ispif_formats_8x96[] = { static irqreturn_t ispif_isr_8x96(int irq, void *dev) { struct ispif_device *ispif = dev; + struct camss *camss = ispif->camss; u32 value0, value1, value2, value3, value4, value5; value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0)); @@ -186,34 +187,34 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev) complete(&ispif->reset_complete[1]); if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n"); if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n"); if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n"); if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n"); if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n"); if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE1 pix0 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE1 pix0 overflow\n"); if (unlikely(value3 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE1 rdi0 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE1 rdi0 overflow\n"); if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE1 pix1 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE1 pix1 overflow\n"); if (unlikely(value4 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE1 rdi1 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE1 rdi1 overflow\n"); if (unlikely(value5 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE1 rdi2 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE1 rdi2 overflow\n"); return IRQ_HANDLED; } @@ -228,6 +229,7 @@ static irqreturn_t ispif_isr_8x96(int irq, void *dev) static irqreturn_t ispif_isr_8x16(int irq, void *dev) { struct ispif_device *ispif = dev; + struct camss *camss = ispif->camss; u32 value0, value1, value2; value0 = readl_relaxed(ispif->base + ISPIF_VFE_m_IRQ_STATUS_0(0)); @@ -244,30 +246,32 @@ static irqreturn_t ispif_isr_8x16(int irq, void *dev) complete(&ispif->reset_complete[0]); if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_PIX0_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 pix0 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 pix0 overflow\n"); if (unlikely(value0 & ISPIF_VFE_m_IRQ_STATUS_0_RDI0_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 rdi0 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 rdi0 overflow\n"); if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_PIX1_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 pix1 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 pix1 overflow\n"); if (unlikely(value1 & ISPIF_VFE_m_IRQ_STATUS_1_RDI1_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 rdi1 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 rdi1 overflow\n"); if (unlikely(value2 & ISPIF_VFE_m_IRQ_STATUS_2_RDI2_OVERFLOW)) - dev_err_ratelimited(to_device(ispif), "VFE0 rdi2 overflow\n"); + dev_err_ratelimited(camss->dev, "VFE0 rdi2 overflow\n"); return IRQ_HANDLED; } static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id) { + struct camss *camss = ispif->camss; + unsigned long time; u32 val; - if (vfe_id > (to_camss(ispif)->vfe_num - 1)) { - dev_err(to_device(ispif), + if (vfe_id > (camss->vfe_num - 1)) { + dev_err(camss->dev, "Error: asked reset for invalid VFE%d\n", vfe_id); return -ENOENT; } @@ -300,7 +304,7 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id) time = wait_for_completion_timeout(&ispif->reset_complete[vfe_id], msecs_to_jiffies(ISPIF_RESET_TIMEOUT_MS)); if (!time) { - dev_err(to_device(ispif), + dev_err(camss->dev, "ISPIF for VFE%d reset timeout\n", vfe_id); return -EIO; } @@ -316,30 +320,31 @@ static int ispif_vfe_reset(struct ispif_device *ispif, u8 vfe_id) */ static int ispif_reset(struct ispif_device *ispif, u8 vfe_id) { + struct camss *camss = ispif->camss; int ret; - ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE0); + ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE0); if (ret < 0) return ret; - ret = camss_pm_domain_on(to_camss(ispif), PM_DOMAIN_VFE1); + ret = camss_pm_domain_on(camss, PM_DOMAIN_VFE1); if (ret < 0) return ret; ret = camss_enable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset, - to_device(ispif)); + camss->dev); if (ret < 0) return ret; ret = ispif_vfe_reset(ispif, vfe_id); if (ret) - dev_dbg(to_device(ispif), "ISPIF Reset failed\n"); + dev_dbg(camss->dev, "ISPIF Reset failed\n"); camss_disable_clocks(ispif->nclocks_for_reset, ispif->clock_for_reset); - camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE0); - camss_pm_domain_off(to_camss(ispif), PM_DOMAIN_VFE1); + camss_pm_domain_off(camss, PM_DOMAIN_VFE0); + camss_pm_domain_off(camss, PM_DOMAIN_VFE1); return ret; } @@ -355,7 +360,7 @@ static int ispif_set_power(struct v4l2_subdev *sd, int on) { struct ispif_line *line = v4l2_get_subdevdata(sd); struct ispif_device *ispif = line->ispif; - struct device *dev = to_device(ispif); + struct device *dev = ispif->camss->dev; int ret = 0; mutex_lock(&ispif->power_lock); @@ -505,7 +510,7 @@ static int ispif_validate_intf_status(struct ispif_device *ispif, } if ((val & 0xf) != 0xf) { - dev_err(to_device(ispif), "%s: ispif is busy: 0x%x\n", + dev_err(ispif->camss->dev, "%s: ispif is busy: 0x%x\n", __func__, val); ret = -EBUSY; } @@ -552,7 +557,7 @@ static int ispif_wait_for_stop(struct ispif_device *ispif, ISPIF_TIMEOUT_SLEEP_US, ISPIF_TIMEOUT_ALL_US); if (ret < 0) - dev_err(to_device(ispif), "%s: ispif stop timeout\n", + dev_err(ispif->camss->dev, "%s: ispif stop timeout\n", __func__); return ret; @@ -800,6 +805,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) { struct ispif_line *line = v4l2_get_subdevdata(sd); struct ispif_device *ispif = line->ispif; + struct camss *camss = ispif->camss; enum ispif_intf intf = line->interface; u8 csid = line->csid_id; u8 vfe = line->vfe_id; @@ -825,8 +831,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) ispif_select_csid(ispif, intf, csid, vfe, 1); ispif_select_cid(ispif, intf, cid, vfe, 1); ispif_config_irq(ispif, intf, vfe, 1); - if (to_camss(ispif)->version == CAMSS_8x96 || - to_camss(ispif)->version == CAMSS_660) + if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, intf, cid, vfe, 1); @@ -843,8 +849,8 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable) return ret; mutex_lock(&ispif->config_lock); - if (to_camss(ispif)->version == CAMSS_8x96 || - to_camss(ispif)->version == CAMSS_660) + if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) ispif_config_pack(ispif, line->fmt[MSM_ISPIF_PAD_SINK].code, intf, cid, vfe, 0); @@ -1088,26 +1094,32 @@ static int ispif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) * * Return 0 on success or a negative error code otherwise */ -int msm_ispif_subdev_init(struct ispif_device *ispif, +int msm_ispif_subdev_init(struct camss *camss, const struct resources_ispif *res) { - struct device *dev = to_device(ispif); + struct device *dev = camss->dev; + struct ispif_device *ispif = camss->ispif; struct platform_device *pdev = to_platform_device(dev); struct resource *r; int i; int ret; + if (!camss->ispif) + return 0; + + ispif->camss = camss; + /* Number of ISPIF lines - same as number of CSID hardware modules */ - if (to_camss(ispif)->version == CAMSS_8x16) + if (camss->version == CAMSS_8x16) ispif->line_num = 2; - else if (to_camss(ispif)->version == CAMSS_8x96 || - to_camss(ispif)->version == CAMSS_660) + else if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) ispif->line_num = 4; else return -EINVAL; - ispif->line = devm_kcalloc(dev, ispif->line_num, sizeof(*ispif->line), - GFP_KERNEL); + ispif->line = devm_kcalloc(dev, ispif->line_num, + sizeof(*ispif->line), GFP_KERNEL); if (!ispif->line) return -ENOMEM; @@ -1115,12 +1127,12 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, ispif->line[i].ispif = ispif; ispif->line[i].id = i; - if (to_camss(ispif)->version == CAMSS_8x16) { + if (camss->version == CAMSS_8x16) { ispif->line[i].formats = ispif_formats_8x16; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x16); - } else if (to_camss(ispif)->version == CAMSS_8x96 || - to_camss(ispif)->version == CAMSS_660) { + } else if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) { ispif->line[i].formats = ispif_formats_8x96; ispif->line[i].nformats = ARRAY_SIZE(ispif_formats_8x96); @@ -1133,17 +1145,13 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[0]); ispif->base = devm_ioremap_resource(dev, r); - if (IS_ERR(ispif->base)) { - dev_err(dev, "could not map memory\n"); + if (IS_ERR(ispif->base)) return PTR_ERR(ispif->base); - } r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res->reg[1]); ispif->base_clk_mux = devm_ioremap_resource(dev, r); - if (IS_ERR(ispif->base_clk_mux)) { - dev_err(dev, "could not map memory\n"); + if (IS_ERR(ispif->base_clk_mux)) return PTR_ERR(ispif->base_clk_mux); - } /* Interrupt */ @@ -1157,15 +1165,16 @@ int msm_ispif_subdev_init(struct ispif_device *ispif, ispif->irq = r->start; snprintf(ispif->irq_name, sizeof(ispif->irq_name), "%s_%s", dev_name(dev), MSM_ISPIF_NAME); - if (to_camss(ispif)->version == CAMSS_8x16) + if (camss->version == CAMSS_8x16) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); - else if (to_camss(ispif)->version == CAMSS_8x96 || - to_camss(ispif)->version == CAMSS_660) + else if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96, IRQF_TRIGGER_RISING, ispif->irq_name, ispif); else ret = -EINVAL; + if (ret < 0) { dev_err(dev, "request_irq failed: %d\n", ret); return ret; @@ -1331,10 +1340,15 @@ static const struct media_entity_operations ispif_media_ops = { int msm_ispif_register_entities(struct ispif_device *ispif, struct v4l2_device *v4l2_dev) { - struct device *dev = to_device(ispif); + struct camss *camss; int ret; int i; + if (!ispif) + return 0; + + camss = ispif->camss; + for (i = 0; i < ispif->line_num; i++) { struct v4l2_subdev *sd = &ispif->line[i].subdev; struct media_pad *pads = ispif->line[i].pads; @@ -1348,7 +1362,7 @@ int msm_ispif_register_entities(struct ispif_device *ispif, ret = ispif_init_formats(sd, NULL); if (ret < 0) { - dev_err(dev, "Failed to init format: %d\n", ret); + dev_err(camss->dev, "Failed to init format: %d\n", ret); goto error; } @@ -1360,13 +1374,15 @@ int msm_ispif_register_entities(struct ispif_device *ispif, ret = media_entity_pads_init(&sd->entity, MSM_ISPIF_PADS_NUM, pads); if (ret < 0) { - dev_err(dev, "Failed to init media entity: %d\n", ret); + dev_err(camss->dev, "Failed to init media entity: %d\n", + ret); goto error; } ret = v4l2_device_register_subdev(v4l2_dev, sd); if (ret < 0) { - dev_err(dev, "Failed to register subdev: %d\n", ret); + dev_err(camss->dev, "Failed to register subdev: %d\n", + ret); media_entity_cleanup(&sd->entity); goto error; } @@ -1393,6 +1409,9 @@ void msm_ispif_unregister_entities(struct ispif_device *ispif) { int i; + if (!ispif) + return; + mutex_destroy(&ispif->power_lock); mutex_destroy(&ispif->config_lock); diff --git a/drivers/media/platform/qcom/camss/camss-ispif.h b/drivers/media/platform/qcom/camss/camss-ispif.h index 4132174f7ea1..fdf28e68cc7d 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.h +++ b/drivers/media/platform/qcom/camss/camss-ispif.h @@ -63,11 +63,12 @@ struct ispif_device { struct mutex config_lock; unsigned int line_num; struct ispif_line *line; + struct camss *camss; }; struct resources_ispif; -int msm_ispif_subdev_init(struct ispif_device *ispif, +int msm_ispif_subdev_init(struct camss *camss, const struct resources_ispif *res); int msm_ispif_register_entities(struct ispif_device *ispif, diff --git a/drivers/media/platform/qcom/camss/camss-vfe-170.c b/drivers/media/platform/qcom/camss/camss-vfe-170.c new file mode 100644 index 000000000000..8594d275b41d --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-170.c @@ -0,0 +1,786 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * camss-vfe-170.c + * + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v170 + * + * Copyright (C) 2020-2021 Linaro Ltd. + */ + +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> + +#include "camss.h" +#include "camss-vfe.h" + +#define VFE_HW_VERSION (0x000) + +#define VFE_GLOBAL_RESET_CMD (0x018) +#define GLOBAL_RESET_CMD_CORE BIT(0) +#define GLOBAL_RESET_CMD_CAMIF BIT(1) +#define GLOBAL_RESET_CMD_BUS BIT(2) +#define GLOBAL_RESET_CMD_BUS_BDG BIT(3) +#define GLOBAL_RESET_CMD_REGISTER BIT(4) +#define GLOBAL_RESET_CMD_PM BIT(5) +#define GLOBAL_RESET_CMD_BUS_MISR BIT(6) +#define GLOBAL_RESET_CMD_TESTGEN BIT(7) +#define GLOBAL_RESET_CMD_DSP BIT(8) +#define GLOBAL_RESET_CMD_IDLE_CGC BIT(9) +#define GLOBAL_RESET_CMD_RDI0 BIT(10) +#define GLOBAL_RESET_CMD_RDI1 BIT(11) +#define GLOBAL_RESET_CMD_RDI2 BIT(12) +#define GLOBAL_RESET_CMD_RDI3 BIT(13) +#define GLOBAL_RESET_CMD_VFE_DOMAIN BIT(30) +#define GLOBAL_RESET_CMD_RESET_BYPASS BIT(31) + +#define VFE_CORE_CFG (0x050) +#define CFG_PIXEL_PATTERN_YCBYCR (0x4) +#define CFG_PIXEL_PATTERN_YCRYCB (0x5) +#define CFG_PIXEL_PATTERN_CBYCRY (0x6) +#define CFG_PIXEL_PATTERN_CRYCBY (0x7) +#define CFG_COMPOSITE_REG_UPDATE_EN BIT(4) + +#define VFE_IRQ_CMD (0x058) +#define CMD_GLOBAL_CLEAR BIT(0) + +#define VFE_IRQ_MASK_0 (0x05c) +#define MASK_0_CAMIF_SOF BIT(0) +#define MASK_0_CAMIF_EOF BIT(1) +#define MASK_0_RDI_REG_UPDATE(n) BIT((n) + 5) +#define MASK_0_IMAGE_MASTER_n_PING_PONG(n) BIT((n) + 8) +#define MASK_0_IMAGE_COMPOSITE_DONE_n(n) BIT((n) + 25) +#define MASK_0_RESET_ACK BIT(31) + +#define VFE_IRQ_MASK_1 (0x060) +#define MASK_1_CAMIF_ERROR BIT(0) +#define MASK_1_VIOLATION BIT(7) +#define MASK_1_BUS_BDG_HALT_ACK BIT(8) +#define MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n) BIT((n) + 9) +#define MASK_1_RDI_SOF(n) BIT((n) + 29) + +#define VFE_IRQ_CLEAR_0 (0x064) +#define VFE_IRQ_CLEAR_1 (0x068) + +#define VFE_IRQ_STATUS_0 (0x06c) +#define STATUS_0_CAMIF_SOF BIT(0) +#define STATUS_0_RDI_REG_UPDATE(n) BIT((n) + 5) +#define STATUS_0_IMAGE_MASTER_PING_PONG(n) BIT((n) + 8) +#define STATUS_0_IMAGE_COMPOSITE_DONE(n) BIT((n) + 25) +#define STATUS_0_RESET_ACK BIT(31) + +#define VFE_IRQ_STATUS_1 (0x070) +#define STATUS_1_VIOLATION BIT(7) +#define STATUS_1_BUS_BDG_HALT_ACK BIT(8) +#define STATUS_1_RDI_SOF(n) BIT((n) + 27) + +#define VFE_VIOLATION_STATUS (0x07c) + +#define VFE_CAMIF_CMD (0x478) +#define CMD_CLEAR_CAMIF_STATUS BIT(2) + +#define VFE_CAMIF_CFG (0x47c) +#define CFG_VSYNC_SYNC_EDGE (0) +#define VSYNC_ACTIVE_HIGH (0) +#define VSYNC_ACTIVE_LOW (1) +#define CFG_HSYNC_SYNC_EDGE (1) +#define HSYNC_ACTIVE_HIGH (0) +#define HSYNC_ACTIVE_LOW (1) +#define CFG_VFE_SUBSAMPLE_ENABLE BIT(4) +#define CFG_BUS_SUBSAMPLE_ENABLE BIT(5) +#define CFG_VFE_OUTPUT_EN BIT(6) +#define CFG_BUS_OUTPUT_EN BIT(7) +#define CFG_BINNING_EN BIT(9) +#define CFG_FRAME_BASED_EN BIT(10) +#define CFG_RAW_CROP_EN BIT(22) + +#define VFE_REG_UPDATE_CMD (0x4ac) +#define REG_UPDATE_RDI(n) BIT(1 + (n)) + +#define VFE_BUS_IRQ_MASK(n) (0x2044 + (n) * 4) +#define VFE_BUS_IRQ_CLEAR(n) (0x2050 + (n) * 4) +#define VFE_BUS_IRQ_STATUS(n) (0x205c + (n) * 4) +#define STATUS0_COMP_RESET_DONE BIT(0) +#define STATUS0_COMP_REG_UPDATE0_DONE BIT(1) +#define STATUS0_COMP_REG_UPDATE1_DONE BIT(2) +#define STATUS0_COMP_REG_UPDATE2_DONE BIT(3) +#define STATUS0_COMP_REG_UPDATE3_DONE BIT(4) +#define STATUS0_COMP_REG_UPDATE_DONE(n) BIT((n) + 1) +#define STATUS0_COMP0_BUF_DONE BIT(5) +#define STATUS0_COMP1_BUF_DONE BIT(6) +#define STATUS0_COMP2_BUF_DONE BIT(7) +#define STATUS0_COMP3_BUF_DONE BIT(8) +#define STATUS0_COMP4_BUF_DONE BIT(9) +#define STATUS0_COMP5_BUF_DONE BIT(10) +#define STATUS0_COMP_BUF_DONE(n) BIT((n) + 5) +#define STATUS0_COMP_ERROR BIT(11) +#define STATUS0_COMP_OVERWRITE BIT(12) +#define STATUS0_OVERFLOW BIT(13) +#define STATUS0_VIOLATION BIT(14) +/* WM_CLIENT_BUF_DONE defined for buffers 0:19 */ +#define STATUS1_WM_CLIENT_BUF_DONE(n) BIT(n) +#define STATUS1_EARLY_DONE BIT(24) +#define STATUS2_DUAL_COMP0_BUF_DONE BIT(0) +#define STATUS2_DUAL_COMP1_BUF_DONE BIT(1) +#define STATUS2_DUAL_COMP2_BUF_DONE BIT(2) +#define STATUS2_DUAL_COMP3_BUF_DONE BIT(3) +#define STATUS2_DUAL_COMP4_BUF_DONE BIT(4) +#define STATUS2_DUAL_COMP5_BUF_DONE BIT(5) +#define STATUS2_DUAL_COMP_BUF_DONE(n) BIT(n) +#define STATUS2_DUAL_COMP_ERROR BIT(6) +#define STATUS2_DUAL_COMP_OVERWRITE BIT(7) + +#define VFE_BUS_IRQ_CLEAR_GLOBAL (0x2068) + +#define VFE_BUS_WM_DEBUG_STATUS_CFG (0x226c) +#define DEBUG_STATUS_CFG_STATUS0(n) BIT(n) +#define DEBUG_STATUS_CFG_STATUS1(n) BIT(8 + (n)) + +#define VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER (0x2080) + +#define VFE_BUS_WM_ADDR_SYNC_NO_SYNC (0x2084) +#define BUS_VER2_MAX_CLIENTS (24) +#define WM_ADDR_NO_SYNC_DEFAULT_VAL \ + ((1 << BUS_VER2_MAX_CLIENTS) - 1) + +#define VFE_BUS_WM_CGC_OVERRIDE (0x200c) +#define WM_CGC_OVERRIDE_ALL (0xFFFFF) + +#define VFE_BUS_WM_TEST_BUS_CTRL (0x211c) + +#define VFE_BUS_WM_STATUS0(n) (0x2200 + (n) * 0x100) +#define VFE_BUS_WM_STATUS1(n) (0x2204 + (n) * 0x100) +#define VFE_BUS_WM_CFG(n) (0x2208 + (n) * 0x100) +#define WM_CFG_EN (0) +#define WM_CFG_MODE (1) +#define MODE_QCOM_PLAIN (0) +#define MODE_MIPI_RAW (1) +#define WM_CFG_VIRTUALFRAME (2) +#define VFE_BUS_WM_HEADER_ADDR(n) (0x220c + (n) * 0x100) +#define VFE_BUS_WM_HEADER_CFG(n) (0x2210 + (n) * 0x100) +#define VFE_BUS_WM_IMAGE_ADDR(n) (0x2214 + (n) * 0x100) +#define VFE_BUS_WM_IMAGE_ADDR_OFFSET(n) (0x2218 + (n) * 0x100) +#define VFE_BUS_WM_BUFFER_WIDTH_CFG(n) (0x221c + (n) * 0x100) +#define WM_BUFFER_DEFAULT_WIDTH (0xFF01) + +#define VFE_BUS_WM_BUFFER_HEIGHT_CFG(n) (0x2220 + (n) * 0x100) +#define VFE_BUS_WM_PACKER_CFG(n) (0x2224 + (n) * 0x100) + +#define VFE_BUS_WM_STRIDE(n) (0x2228 + (n) * 0x100) +#define WM_STRIDE_DEFAULT_STRIDE (0xFF01) + +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PERIOD(n) (0x2248 + (n) * 0x100) +#define VFE_BUS_WM_IRQ_SUBSAMPLE_PATTERN(n) (0x224c + (n) * 0x100) +#define VFE_BUS_WM_FRAMEDROP_PERIOD(n) (0x2250 + (n) * 0x100) +#define VFE_BUS_WM_FRAMEDROP_PATTERN(n) (0x2254 + (n) * 0x100) +#define VFE_BUS_WM_FRAME_INC(n) (0x2258 + (n) * 0x100) +#define VFE_BUS_WM_BURST_LIMIT(n) (0x225c + (n) * 0x100) + +static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) +{ + u32 hw_version = readl_relaxed(vfe->base + VFE_HW_VERSION); + + u32 gen = (hw_version >> 28) & 0xF; + u32 rev = (hw_version >> 16) & 0xFFF; + u32 step = hw_version & 0xFFFF; + + dev_err(dev, "VFE HW Version = %u.%u.%u\n", gen, rev, step); +} + +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) +{ + u32 bits = readl_relaxed(vfe->base + reg); + + writel_relaxed(bits & ~clr_bits, vfe->base + reg); +} + +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits) +{ + u32 bits = readl_relaxed(vfe->base + reg); + + writel_relaxed(bits | set_bits, vfe->base + reg); +} + +static void vfe_global_reset(struct vfe_device *vfe) +{ + u32 reset_bits = GLOBAL_RESET_CMD_CORE | + GLOBAL_RESET_CMD_CAMIF | + GLOBAL_RESET_CMD_BUS | + GLOBAL_RESET_CMD_BUS_BDG | + GLOBAL_RESET_CMD_REGISTER | + GLOBAL_RESET_CMD_TESTGEN | + GLOBAL_RESET_CMD_DSP | + GLOBAL_RESET_CMD_IDLE_CGC | + GLOBAL_RESET_CMD_RDI0 | + GLOBAL_RESET_CMD_RDI1 | + GLOBAL_RESET_CMD_RDI2; + + writel_relaxed(BIT(31), vfe->base + VFE_IRQ_MASK_0); + + /* Make sure IRQ mask has been written before resetting */ + wmb(); + + writel_relaxed(reset_bits, vfe->base + VFE_GLOBAL_RESET_CMD); +} + +static void vfe_wm_start(struct vfe_device *vfe, u8 wm, struct vfe_line *line) +{ + u32 val; + + /*Set Debug Registers*/ + val = DEBUG_STATUS_CFG_STATUS0(1) | + DEBUG_STATUS_CFG_STATUS0(7); + writel_relaxed(val, vfe->base + VFE_BUS_WM_DEBUG_STATUS_CFG); + + /* BUS_WM_INPUT_IF_ADDR_SYNC_FRAME_HEADER */ + writel_relaxed(0, vfe->base + VFE_BUS_WM_ADDR_SYNC_FRAME_HEADER); + + /* no clock gating at bus input */ + val = WM_CGC_OVERRIDE_ALL; + writel_relaxed(val, vfe->base + VFE_BUS_WM_CGC_OVERRIDE); + + writel_relaxed(0x0, vfe->base + VFE_BUS_WM_TEST_BUS_CTRL); + + /* if addr_no_sync has default value then config the addr no sync reg */ + val = WM_ADDR_NO_SYNC_DEFAULT_VAL; + writel_relaxed(val, vfe->base + VFE_BUS_WM_ADDR_SYNC_NO_SYNC); + + writel_relaxed(0xf, vfe->base + VFE_BUS_WM_BURST_LIMIT(wm)); + + val = WM_BUFFER_DEFAULT_WIDTH; + writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_WIDTH_CFG(wm)); + + val = 0; + writel_relaxed(val, vfe->base + VFE_BUS_WM_BUFFER_HEIGHT_CFG(wm)); + + val = 0; + writel_relaxed(val, vfe->base + VFE_BUS_WM_PACKER_CFG(wm)); // XXX 1 for PLAIN8? + + /* Configure stride for RDIs */ + val = WM_STRIDE_DEFAULT_STRIDE; + writel_relaxed(val, vfe->base + VFE_BUS_WM_STRIDE(wm)); + + /* Enable WM */ + val = 1 << WM_CFG_EN | + MODE_MIPI_RAW << WM_CFG_MODE; + writel_relaxed(val, vfe->base + VFE_BUS_WM_CFG(wm)); +} + +static void vfe_wm_stop(struct vfe_device *vfe, u8 wm) +{ + /* Disable WM */ + writel_relaxed(0, vfe->base + VFE_BUS_WM_CFG(wm)); +} + +static void vfe_wm_update(struct vfe_device *vfe, u8 wm, u32 addr, + 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; + + writel_relaxed(addr, vfe->base + VFE_BUS_WM_IMAGE_ADDR(wm)); + writel_relaxed(stride * pix->height, vfe->base + VFE_BUS_WM_FRAME_INC(wm)); +} + +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + vfe->reg_update |= REG_UPDATE_RDI(line_id); + + /* Enforce ordering between previous reg writes and reg update */ + wmb(); + + writel_relaxed(vfe->reg_update, vfe->base + VFE_REG_UPDATE_CMD); + + /* Enforce ordering between reg update and subsequent reg writes */ + wmb(); +} + +static inline void vfe_reg_update_clear(struct vfe_device *vfe, + enum vfe_line_id line_id) +{ + vfe->reg_update &= ~REG_UPDATE_RDI(line_id); +} + +static void vfe_enable_irq_common(struct vfe_device *vfe) +{ + vfe_reg_set(vfe, VFE_IRQ_MASK_0, ~0u); + vfe_reg_set(vfe, VFE_IRQ_MASK_1, ~0u); + + writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(0)); + writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(1)); + writel_relaxed(~0u, vfe->base + VFE_BUS_IRQ_MASK(2)); +} + +static void vfe_isr_halt_ack(struct vfe_device *vfe) +{ + complete(&vfe->halt_complete); +} + +static void vfe_isr_read(struct vfe_device *vfe, u32 *status0, u32 *status1) +{ + *status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0); + *status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1); + + writel_relaxed(*status0, vfe->base + VFE_IRQ_CLEAR_0); + writel_relaxed(*status1, vfe->base + VFE_IRQ_CLEAR_1); + + /* Enforce ordering between IRQ Clear and Global IRQ Clear */ + wmb(); + writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD); +} + +static void vfe_violation_read(struct vfe_device *vfe) +{ + u32 violation = readl_relaxed(vfe->base + VFE_VIOLATION_STATUS); + + pr_err_ratelimited("VFE: violation = 0x%08x\n", violation); +} + +/* + * vfe_isr - VFE module interrupt handler + * @irq: Interrupt line + * @dev: VFE device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t vfe_isr(int irq, void *dev) +{ + struct vfe_device *vfe = dev; + u32 status0, status1, vfe_bus_status[3]; + int i, wm; + + status0 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_0); + status1 = readl_relaxed(vfe->base + VFE_IRQ_STATUS_1); + + writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0); + writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1); + + for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) { + vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i)); + writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i)); + } + + /* Enforce ordering between IRQ reading and interpretation */ + wmb(); + + writel_relaxed(CMD_GLOBAL_CLEAR, vfe->base + VFE_IRQ_CMD); + writel_relaxed(1, vfe->base + VFE_BUS_IRQ_CLEAR_GLOBAL); + + if (status0 & STATUS_0_RESET_ACK) + vfe->isr_ops.reset_ack(vfe); + + for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) + if (status0 & STATUS_0_RDI_REG_UPDATE(i)) + vfe->isr_ops.reg_update(vfe, i); + + for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) + if (status0 & STATUS_1_RDI_SOF(i)) + vfe->isr_ops.sof(vfe, i); + + for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++) + if (vfe_bus_status[0] & STATUS0_COMP_BUF_DONE(i)) + vfe->isr_ops.comp_done(vfe, i); + + for (wm = 0; wm < MSM_VFE_IMAGE_MASTERS_NUM; wm++) + if (status0 & BIT(9)) + if (vfe_bus_status[1] & STATUS1_WM_CLIENT_BUF_DONE(wm)) + vfe->isr_ops.wm_done(vfe, wm); + + return IRQ_HANDLED; +} + +/* + * vfe_halt - Trigger halt on VFE module and wait to complete + * @vfe: VFE device + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_halt(struct vfe_device *vfe) +{ + unsigned long time; + + reinit_completion(&vfe->halt_complete); + + time = wait_for_completion_timeout(&vfe->halt_complete, + msecs_to_jiffies(VFE_HALT_TIMEOUT_MS)); + if (!time) { + dev_err(vfe->camss->dev, "VFE halt timeout\n"); + return -EIO; + } + + return 0; +} + +static int vfe_get_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output; + unsigned long flags; + int wm_idx; + + spin_lock_irqsave(&vfe->output_lock, flags); + + output = &line->output; + if (output->state != VFE_OUTPUT_OFF) { + dev_err(vfe->camss->dev, "Output is running\n"); + goto error; + } + + output->wm_num = 1; + + wm_idx = vfe_reserve_wm(vfe, line->id); + if (wm_idx < 0) { + dev_err(vfe->camss->dev, "Can not reserve wm\n"); + goto error_get_wm; + } + output->wm_idx[0] = wm_idx; + + output->drop_update_idx = 0; + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; + +error_get_wm: + vfe_release_wm(vfe, output->wm_idx[0]); + output->state = VFE_OUTPUT_OFF; +error: + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return -EINVAL; +} + +static int vfe_enable_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output = &line->output; + const struct vfe_hw_ops *ops = vfe->ops; + struct media_entity *sensor; + unsigned long flags; + unsigned int frame_skip = 0; + unsigned int i; + + sensor = camss_find_sensor(&line->subdev.entity); + if (sensor) { + struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(sensor); + + v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip); + /* Max frame skip is 29 frames */ + if (frame_skip > VFE_FRAME_DROP_VAL - 1) + frame_skip = VFE_FRAME_DROP_VAL - 1; + } + + spin_lock_irqsave(&vfe->output_lock, flags); + + ops->reg_update_clear(vfe, line->id); + + if (output->state != VFE_OUTPUT_OFF) { + dev_err(vfe->camss->dev, "Output is not in reserved state %d\n", + output->state); + spin_unlock_irqrestore(&vfe->output_lock, flags); + return -EINVAL; + } + + WARN_ON(output->gen2.active_num); + + output->state = VFE_OUTPUT_ON; + + output->sequence = 0; + output->wait_reg_update = 0; + reinit_completion(&output->reg_update); + + vfe_wm_start(vfe, output->wm_idx[0], line); + + for (i = 0; i < 2; i++) { + output->buf[i] = vfe_buf_get_pending(output); + if (!output->buf[i]) + break; + output->gen2.active_num++; + vfe_wm_update(vfe, output->wm_idx[0], output->buf[i]->addr[0], line); + } + + ops->reg_update(vfe, line->id); + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; +} + +static int vfe_disable_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output = &line->output; + unsigned long flags; + unsigned int i; + bool done; + int timeout = 0; + + do { + spin_lock_irqsave(&vfe->output_lock, flags); + done = !output->gen2.active_num; + spin_unlock_irqrestore(&vfe->output_lock, flags); + usleep_range(10000, 20000); + + if (timeout++ == 100) { + dev_err(vfe->camss->dev, "VFE idle timeout - resetting\n"); + vfe_reset(vfe); + output->gen2.active_num = 0; + return 0; + } + } while (!done); + + spin_lock_irqsave(&vfe->output_lock, flags); + for (i = 0; i < output->wm_num; i++) + vfe_wm_stop(vfe, output->wm_idx[i]); + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; +} + +/* + * vfe_enable - Enable streaming on VFE line + * @line: VFE line + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_enable(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + int ret; + + mutex_lock(&vfe->stream_lock); + + if (!vfe->stream_count) + vfe_enable_irq_common(vfe); + + vfe->stream_count++; + + mutex_unlock(&vfe->stream_lock); + + ret = vfe_get_output(line); + if (ret < 0) + goto error_get_output; + + ret = vfe_enable_output(line); + if (ret < 0) + goto error_enable_output; + + vfe->was_streaming = 1; + + return 0; + +error_enable_output: + vfe_put_output(line); + +error_get_output: + mutex_lock(&vfe->stream_lock); + + vfe->stream_count--; + + mutex_unlock(&vfe->stream_lock); + + return ret; +} + +/* + * vfe_disable - Disable streaming on VFE line + * @line: VFE line + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_disable(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + + vfe_disable_output(line); + + vfe_put_output(line); + + mutex_lock(&vfe->stream_lock); + + vfe->stream_count--; + + mutex_unlock(&vfe->stream_lock); + + return 0; +} + +/* + * vfe_isr_sof - Process start of frame interrupt + * @vfe: VFE Device + * @line_id: VFE line + */ +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + /* nop */ +} + +/* + * vfe_isr_reg_update - Process reg update interrupt + * @vfe: VFE Device + * @line_id: VFE line + */ +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + struct vfe_output *output; + unsigned long flags; + + spin_lock_irqsave(&vfe->output_lock, flags); + vfe->ops->reg_update_clear(vfe, line_id); + + output = &vfe->line[line_id].output; + + if (output->wait_reg_update) { + output->wait_reg_update = 0; + complete(&output->reg_update); + } + + spin_unlock_irqrestore(&vfe->output_lock, flags); +} + +/* + * vfe_isr_wm_done - Process write master done interrupt + * @vfe: VFE Device + * @wm: Write master id + */ +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm) +{ + struct vfe_line *line = &vfe->line[vfe->wm_output_map[wm]]; + struct camss_buffer *ready_buf; + struct vfe_output *output; + unsigned long flags; + u32 index; + u64 ts = ktime_get_ns(); + + spin_lock_irqsave(&vfe->output_lock, flags); + + if (vfe->wm_output_map[wm] == VFE_LINE_NONE) { + dev_err_ratelimited(vfe->camss->dev, + "Received wm done for unmapped index\n"); + goto out_unlock; + } + output = &vfe->line[vfe->wm_output_map[wm]].output; + + ready_buf = output->buf[0]; + if (!ready_buf) { + dev_err_ratelimited(vfe->camss->dev, + "Missing ready buf %d!\n", output->state); + goto out_unlock; + } + + ready_buf->vb.vb2_buf.timestamp = ts; + ready_buf->vb.sequence = output->sequence++; + + index = 0; + output->buf[0] = output->buf[1]; + if (output->buf[0]) + index = 1; + + output->buf[index] = vfe_buf_get_pending(output); + + if (output->buf[index]) + vfe_wm_update(vfe, output->wm_idx[0], output->buf[index]->addr[0], line); + else + output->gen2.active_num--; + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + + return; + +out_unlock: + spin_unlock_irqrestore(&vfe->output_lock, flags); +} + +/* + * vfe_pm_domain_off - Disable power domains specific to this VFE. + * @vfe: VFE Device + */ +static void vfe_pm_domain_off(struct vfe_device *vfe) +{ + /* nop */ +} + +/* + * vfe_pm_domain_on - Enable power domains specific to this VFE. + * @vfe: VFE Device + */ +static int vfe_pm_domain_on(struct vfe_device *vfe) +{ + return 0; +} + +/* + * vfe_queue_buffer - Add empty buffer + * @vid: Video device structure + * @buf: Buffer to be enqueued + * + * Add an empty buffer - depending on the current number of buffers it will be + * put in pending buffer queue or directly given to the hardware to be filled. + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_queue_buffer(struct camss_video *vid, + struct camss_buffer *buf) +{ + struct vfe_line *line = container_of(vid, struct vfe_line, video_out); + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output; + unsigned long flags; + + output = &line->output; + + spin_lock_irqsave(&vfe->output_lock, flags); + + if (output->state == VFE_OUTPUT_ON && output->gen2.active_num < 2) { + output->buf[output->gen2.active_num++] = buf; + vfe_wm_update(vfe, output->wm_idx[0], buf->addr[0], line); + } else { + vfe_buf_add_pending(output, buf); + } + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; +} + +static const struct vfe_isr_ops vfe_isr_ops_170 = { + .reset_ack = vfe_isr_reset_ack, + .halt_ack = vfe_isr_halt_ack, + .reg_update = vfe_isr_reg_update, + .sof = vfe_isr_sof, + .comp_done = vfe_isr_comp_done, + .wm_done = vfe_isr_wm_done, +}; + +static const struct camss_video_ops vfe_video_ops_170 = { + .queue_buffer = vfe_queue_buffer, + .flush_buffers = vfe_flush_buffers, +}; + +static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) +{ + vfe->isr_ops = vfe_isr_ops_170; + vfe->video_ops = vfe_video_ops_170; + + vfe->line_num = VFE_LINE_NUM_GEN2; +} + +const struct vfe_hw_ops vfe_ops_170 = { + .global_reset = vfe_global_reset, + .hw_version_read = vfe_hw_version_read, + .isr_read = vfe_isr_read, + .isr = vfe_isr, + .pm_domain_off = vfe_pm_domain_off, + .pm_domain_on = vfe_pm_domain_on, + .reg_update_clear = vfe_reg_update_clear, + .reg_update = vfe_reg_update, + .subdev_init = vfe_subdev_init, + .vfe_disable = vfe_disable, + .vfe_enable = vfe_enable, + .vfe_halt = vfe_halt, + .violation_read = vfe_violation_read, +}; 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 174a36be6f5d..53c56a8d4545 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c @@ -12,7 +12,9 @@ #include <linux/io.h> #include <linux/iopoll.h> +#include "camss.h" #include "camss-vfe.h" +#include "camss-vfe-gen1.h" #define VFE_0_HW_VERSION 0x000 @@ -283,30 +285,6 @@ static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable) 1 << VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_FRM_BASED_SHIFT); } -#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N)) - -static int vfe_word_per_line(u32 format, u32 pixel_per_line) -{ - int val = 0; - - switch (format) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - val = CALC_WORD(pixel_per_line, 1, 8); - break; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - val = CALC_WORD(pixel_per_line, 2, 8); - break; - } - - return val; -} - static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane, u16 *width, u16 *height, u16 *bytesperline) { @@ -665,20 +643,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG); } -static inline u8 vfe_calc_interp_reso(u16 input, u16 output) -{ - if (input / output >= 16) - return 0; - - if (input / output >= 8) - return 1; - - if (input / output >= 4) - return 2; - - return 3; -} - static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line) { u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; @@ -922,7 +886,7 @@ static void vfe_violation_read(struct vfe_device *vfe) } /* - * vfe_isr - ISPIF module interrupt handler + * vfe_isr - VFE module interrupt handler * @irq: Interrupt line * @dev: VFE device * @@ -936,8 +900,8 @@ static irqreturn_t vfe_isr(int irq, void *dev) vfe->ops->isr_read(vfe, &value0, &value1); - trace_printk("VFE: status0 = 0x%08x, status1 = 0x%08x\n", - value0, value1); + dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n", + value0, value1); if (value0 & VFE_0_IRQ_STATUS_0_RESET_ACK) vfe->isr_ops.reset_ack(vfe); @@ -974,46 +938,82 @@ static irqreturn_t vfe_isr(int irq, void *dev) return IRQ_HANDLED; } -const struct vfe_hw_ops vfe_ops_4_1 = { - .hw_version_read = vfe_hw_version_read, +/* + * vfe_pm_domain_off - Disable power domains specific to this VFE. + * @vfe: VFE Device + */ +static void vfe_pm_domain_off(struct vfe_device *vfe) +{ + /* nop */ +} + +/* + * vfe_pm_domain_on - Enable power domains specific to this VFE. + * @vfe: VFE Device + */ +static int vfe_pm_domain_on(struct vfe_device *vfe) +{ + return 0; +} + +static const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_1 = { + .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi, + .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi, + .bus_enable_wr_if = vfe_bus_enable_wr_if, + .bus_reload_wm = vfe_bus_reload_wm, + .camif_wait_for_stop = vfe_camif_wait_for_stop, + .enable_irq_common = vfe_enable_irq_common, + .enable_irq_pix_line = vfe_enable_irq_pix_line, + .enable_irq_wm_line = vfe_enable_irq_wm_line, .get_ub_size = vfe_get_ub_size, - .global_reset = vfe_global_reset, - .halt_request = vfe_halt_request, .halt_clear = vfe_halt_clear, + .halt_request = vfe_halt_request, + .set_camif_cfg = vfe_set_camif_cfg, + .set_camif_cmd = vfe_set_camif_cmd, + .set_cgc_override = vfe_set_cgc_override, + .set_clamp_cfg = vfe_set_clamp_cfg, + .set_crop_cfg = vfe_set_crop_cfg, + .set_demux_cfg = vfe_set_demux_cfg, + .set_ds = vfe_set_ds, + .set_module_cfg = vfe_set_module_cfg, + .set_qos = vfe_set_qos, + .set_rdi_cid = vfe_set_rdi_cid, + .set_realign_cfg = vfe_set_realign_cfg, + .set_scale_cfg = vfe_set_scale_cfg, + .set_xbar_cfg = vfe_set_xbar_cfg, .wm_enable = vfe_wm_enable, .wm_frame_based = vfe_wm_frame_based, + .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status, .wm_line_based = vfe_wm_line_based, - .wm_set_framedrop_period = vfe_wm_set_framedrop_period, .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern, - .wm_set_ub_cfg = vfe_wm_set_ub_cfg, - .bus_reload_wm = vfe_bus_reload_wm, + .wm_set_framedrop_period = vfe_wm_set_framedrop_period, .wm_set_ping_addr = vfe_wm_set_ping_addr, .wm_set_pong_addr = vfe_wm_set_pong_addr, - .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status, - .bus_enable_wr_if = vfe_bus_enable_wr_if, - .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi, .wm_set_subsample = vfe_wm_set_subsample, - .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi, - .set_xbar_cfg = vfe_set_xbar_cfg, - .set_realign_cfg = vfe_set_realign_cfg, - .set_rdi_cid = vfe_set_rdi_cid, - .reg_update = vfe_reg_update, - .reg_update_clear = vfe_reg_update_clear, - .enable_irq_wm_line = vfe_enable_irq_wm_line, - .enable_irq_pix_line = vfe_enable_irq_pix_line, - .enable_irq_common = vfe_enable_irq_common, - .set_demux_cfg = vfe_set_demux_cfg, - .set_scale_cfg = vfe_set_scale_cfg, - .set_crop_cfg = vfe_set_crop_cfg, - .set_clamp_cfg = vfe_set_clamp_cfg, - .set_qos = vfe_set_qos, - .set_ds = vfe_set_ds, - .set_cgc_override = vfe_set_cgc_override, - .set_camif_cfg = vfe_set_camif_cfg, - .set_camif_cmd = vfe_set_camif_cmd, - .set_module_cfg = vfe_set_module_cfg, - .camif_wait_for_stop = vfe_camif_wait_for_stop, + .wm_set_ub_cfg = vfe_wm_set_ub_cfg, +}; + +static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) +{ + vfe->isr_ops = vfe_isr_ops_gen1; + vfe->ops_gen1 = &vfe_ops_gen1_4_1; + vfe->video_ops = vfe_video_ops_gen1; + + vfe->line_num = VFE_LINE_NUM_GEN1; +} + +const struct vfe_hw_ops vfe_ops_4_1 = { + .global_reset = vfe_global_reset, + .hw_version_read = vfe_hw_version_read, .isr_read = vfe_isr_read, - .violation_read = vfe_violation_read, .isr = vfe_isr, + .pm_domain_off = vfe_pm_domain_off, + .pm_domain_on = vfe_pm_domain_on, + .reg_update_clear = vfe_reg_update_clear, + .reg_update = vfe_reg_update, + .subdev_init = vfe_subdev_init, + .vfe_disable = vfe_gen1_disable, + .vfe_enable = vfe_gen1_enable, + .vfe_halt = vfe_gen1_halt, + .violation_read = vfe_violation_read, }; diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c index b5704a2f119b..a59635217758 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c @@ -8,11 +8,15 @@ * Copyright (C) 2015-2018 Linaro Ltd. */ +#include <linux/device.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/iopoll.h> +#include "camss.h" #include "camss-vfe.h" +#include "camss-vfe-gen1.h" + #define VFE_0_HW_VERSION 0x000 @@ -257,7 +261,7 @@ static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version); } -static u16 vfe47_get_ub_size(u8 vfe_id) +static u16 vfe_get_ub_size(u8 vfe_id) { if (vfe_id == 0) return MSM_VFE_VFE0_UB_SIZE_RDI; @@ -295,6 +299,8 @@ static void vfe_global_reset(struct vfe_device *vfe) VFE_0_GLOBAL_RESET_CMD_CORE; writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0); + + /* Enforce barrier between IRQ mask setup and global reset */ wmb(); writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD); } @@ -310,7 +316,7 @@ static void vfe_halt_clear(struct vfe_device *vfe) writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD); } -static void vfe47_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable) +static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable) { if (enable) vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(wm), @@ -459,8 +465,12 @@ static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm, static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm) { + /* Enforce barrier between any outstanding register write */ wmb(); + writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD); + + /* Use barrier to make sure bus reload is issued before anything else */ wmb(); } @@ -674,8 +684,12 @@ static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid) static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) { vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id); + + /* Enforce barrier between line update and commit */ wmb(); writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE); + + /* Make sure register update is issued before further reg writes */ wmb(); } @@ -779,20 +793,6 @@ static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG); } -static inline u8 vfe_calc_interp_reso(u16 input, u16 output) -{ - if (input / output >= 16) - return 0; - - if (input / output >= 8) - return 1; - - if (input / output >= 4) - return 2; - - return 3; -} - static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line) { u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; @@ -894,7 +894,7 @@ static void vfe_set_clamp_cfg(struct vfe_device *vfe) writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG); } -static void vfe47_set_qos(struct vfe_device *vfe) +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; @@ -909,7 +909,7 @@ static void vfe47_set_qos(struct vfe_device *vfe) writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7); } -static void vfe47_set_ds(struct vfe_device *vfe) +static void vfe_set_ds(struct vfe_device *vfe) { u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG; u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG; @@ -993,6 +993,8 @@ static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable) cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE; writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD); + + /* Make sure camif command is issued written before it is changed again */ wmb(); if (enable) @@ -1035,27 +1037,10 @@ static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev) return ret; } -static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1) -{ - *value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0); - *value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1); - writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0); - writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1); - - wmb(); - writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD); -} - -static void vfe_violation_read(struct vfe_device *vfe) -{ - u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS); - - pr_err_ratelimited("VFE: violation = 0x%08x\n", violation); -} /* - * vfe_isr - ISPIF module interrupt handler + * vfe_isr - VFE module interrupt handler * @irq: Interrupt line * @dev: VFE device * @@ -1069,8 +1054,8 @@ static irqreturn_t vfe_isr(int irq, void *dev) vfe->ops->isr_read(vfe, &value0, &value1); - trace_printk("VFE: status0 = 0x%08x, status1 = 0x%08x\n", - value0, value1); + dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n", + value0, value1); if (value0 & VFE_0_IRQ_STATUS_0_RESET_ACK) vfe->isr_ops.reset_ack(vfe); @@ -1081,7 +1066,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK) vfe->isr_ops.halt_ack(vfe); - for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i)) vfe->isr_ops.reg_update(vfe, i); @@ -1107,150 +1092,120 @@ static irqreturn_t vfe_isr(int irq, void *dev) return IRQ_HANDLED; } -const struct vfe_hw_ops vfe_ops_4_7 = { - .hw_version_read = vfe_hw_version_read, - .get_ub_size = vfe47_get_ub_size, - .global_reset = vfe_global_reset, - .halt_request = vfe_halt_request, - .halt_clear = vfe_halt_clear, - .wm_enable = vfe47_wm_enable, - .wm_frame_based = vfe_wm_frame_based, - .wm_line_based = vfe_wm_line_based, - .wm_set_framedrop_period = vfe_wm_set_framedrop_period, - .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern, - .wm_set_ub_cfg = vfe_wm_set_ub_cfg, - .bus_reload_wm = vfe_bus_reload_wm, - .wm_set_ping_addr = vfe_wm_set_ping_addr, - .wm_set_pong_addr = vfe_wm_set_pong_addr, - .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status, - .bus_enable_wr_if = vfe_bus_enable_wr_if, - .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi, - .wm_set_subsample = vfe_wm_set_subsample, - .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi, - .set_xbar_cfg = vfe_set_xbar_cfg, - .set_realign_cfg = vfe_set_realign_cfg, - .set_rdi_cid = vfe_set_rdi_cid, - .reg_update = vfe_reg_update, - .reg_update_clear = vfe_reg_update_clear, - .enable_irq_wm_line = vfe_enable_irq_wm_line, - .enable_irq_pix_line = vfe_enable_irq_pix_line, - .enable_irq_common = vfe_enable_irq_common, - .set_demux_cfg = vfe_set_demux_cfg, - .set_scale_cfg = vfe_set_scale_cfg, - .set_crop_cfg = vfe_set_crop_cfg, - .set_clamp_cfg = vfe_set_clamp_cfg, - .set_qos = vfe47_set_qos, - .set_ds = vfe47_set_ds, - .set_cgc_override = vfe_set_cgc_override, - .set_camif_cfg = vfe_set_camif_cfg, - .set_camif_cmd = vfe_set_camif_cmd, - .set_module_cfg = vfe_set_module_cfg, - .camif_wait_for_stop = vfe_camif_wait_for_stop, - .isr_read = vfe_isr_read, - .violation_read = vfe_violation_read, - .isr = vfe_isr, -}; - -static u16 vfe48_get_ub_size(u8 vfe_id) +static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1) { - /* On VFE4.8 the ub-size is the same on both instances */ - return MSM_VFE_VFE0_UB_SIZE_RDI; + *value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0); + *value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1); + + writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0); + writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1); + + /* Enforce barrier between local & global IRQ clear */ + wmb(); + writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD); } -static void vfe48_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable) +/* + * vfe_pm_domain_off - Disable power domains specific to this VFE. + * @vfe: VFE Device + */ +static void vfe_pm_domain_off(struct vfe_device *vfe) { - if (enable) - writel_relaxed(2 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm), - vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD); - else - writel_relaxed(1 << VFE48_0_BUS_IMAGE_MASTER_n_SHIFT(wm), - vfe->base + VFE48_0_BUS_IMAGE_MASTER_CMD); + struct camss *camss; - /* The WM must be enabled before sending other commands */ - wmb(); + if (!vfe) + return; + + camss = vfe->camss; + + device_link_del(camss->genpd_link[vfe->id]); } -static void vfe48_set_qos(struct vfe_device *vfe) +/* + * vfe_pm_domain_on - Enable power domains specific to this VFE. + * @vfe: VFE Device + */ +static int vfe_pm_domain_on(struct vfe_device *vfe) { - u32 val = VFE48_0_BUS_BDG_QOS_CFG_0_CFG; - u32 val3 = VFE48_0_BUS_BDG_QOS_CFG_3_CFG; - u32 val4 = VFE48_0_BUS_BDG_QOS_CFG_4_CFG; - u32 val7 = VFE48_0_BUS_BDG_QOS_CFG_7_CFG; + struct camss *camss = vfe->camss; + enum vfe_line_id id = vfe->id; - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2); - writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3); - writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4); - writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5); - writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6); - writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7); + camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); + + if (!camss->genpd_link[id]) { + dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id); + return -EINVAL; + } + + return 0; } -static void vfe48_set_ds(struct vfe_device *vfe) +static void vfe_violation_read(struct vfe_device *vfe) { - u32 val = VFE48_0_BUS_BDG_DS_CFG_0_CFG; - u32 val16 = VFE48_0_BUS_BDG_DS_CFG_16_CFG; + u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14); - writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15); - writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16); + pr_err_ratelimited("VFE: violation = 0x%08x\n", violation); } -const struct vfe_hw_ops vfe_ops_4_8 = { - .hw_version_read = vfe_hw_version_read, - .get_ub_size = vfe48_get_ub_size, - .global_reset = vfe_global_reset, - .halt_request = vfe_halt_request, +static const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_7 = { + .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi, + .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi, + .bus_enable_wr_if = vfe_bus_enable_wr_if, + .bus_reload_wm = vfe_bus_reload_wm, + .camif_wait_for_stop = vfe_camif_wait_for_stop, + .enable_irq_common = vfe_enable_irq_common, + .enable_irq_pix_line = vfe_enable_irq_pix_line, + .enable_irq_wm_line = vfe_enable_irq_wm_line, + .get_ub_size = vfe_get_ub_size, .halt_clear = vfe_halt_clear, - .wm_enable = vfe48_wm_enable, + .halt_request = vfe_halt_request, + .set_camif_cfg = vfe_set_camif_cfg, + .set_camif_cmd = vfe_set_camif_cmd, + .set_cgc_override = vfe_set_cgc_override, + .set_clamp_cfg = vfe_set_clamp_cfg, + .set_crop_cfg = vfe_set_crop_cfg, + .set_demux_cfg = vfe_set_demux_cfg, + .set_ds = vfe_set_ds, + .set_module_cfg = vfe_set_module_cfg, + .set_qos = vfe_set_qos, + .set_rdi_cid = vfe_set_rdi_cid, + .set_realign_cfg = vfe_set_realign_cfg, + .set_scale_cfg = vfe_set_scale_cfg, + .set_xbar_cfg = vfe_set_xbar_cfg, + .wm_enable = vfe_wm_enable, .wm_frame_based = vfe_wm_frame_based, + .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status, .wm_line_based = vfe_wm_line_based, - .wm_set_framedrop_period = vfe_wm_set_framedrop_period, .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern, - .wm_set_ub_cfg = vfe_wm_set_ub_cfg, - .bus_reload_wm = vfe_bus_reload_wm, + .wm_set_framedrop_period = vfe_wm_set_framedrop_period, .wm_set_ping_addr = vfe_wm_set_ping_addr, .wm_set_pong_addr = vfe_wm_set_pong_addr, - .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status, - .bus_enable_wr_if = vfe_bus_enable_wr_if, - .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi, .wm_set_subsample = vfe_wm_set_subsample, - .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi, - .set_xbar_cfg = vfe_set_xbar_cfg, - .set_realign_cfg = vfe_set_realign_cfg, - .set_rdi_cid = vfe_set_rdi_cid, - .reg_update = vfe_reg_update, - .reg_update_clear = vfe_reg_update_clear, - .enable_irq_wm_line = vfe_enable_irq_wm_line, - .enable_irq_pix_line = vfe_enable_irq_pix_line, - .enable_irq_common = vfe_enable_irq_common, - .set_demux_cfg = vfe_set_demux_cfg, - .set_scale_cfg = vfe_set_scale_cfg, - .set_crop_cfg = vfe_set_crop_cfg, - .set_clamp_cfg = vfe_set_clamp_cfg, - .set_qos = vfe48_set_qos, - .set_ds = vfe48_set_ds, - .set_cgc_override = vfe_set_cgc_override, - .set_camif_cfg = vfe_set_camif_cfg, - .set_camif_cmd = vfe_set_camif_cmd, - .set_module_cfg = vfe_set_module_cfg, - .camif_wait_for_stop = vfe_camif_wait_for_stop, + .wm_set_ub_cfg = vfe_wm_set_ub_cfg, +}; + +static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) +{ + vfe->isr_ops = vfe_isr_ops_gen1; + vfe->ops_gen1 = &vfe_ops_gen1_4_7; + vfe->video_ops = vfe_video_ops_gen1; + + vfe->line_num = VFE_LINE_NUM_GEN1; +} + +const struct vfe_hw_ops vfe_ops_4_7 = { + .global_reset = vfe_global_reset, + .hw_version_read = vfe_hw_version_read, .isr_read = vfe_isr_read, - .violation_read = vfe_violation_read, .isr = vfe_isr, + .pm_domain_off = vfe_pm_domain_off, + .pm_domain_on = vfe_pm_domain_on, + .reg_update_clear = vfe_reg_update_clear, + .reg_update = vfe_reg_update, + .subdev_init = vfe_subdev_init, + .vfe_disable = vfe_gen1_disable, + .vfe_enable = vfe_gen1_enable, + .vfe_halt = vfe_gen1_halt, + .violation_read = vfe_violation_read, }; diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c new file mode 100644 index 000000000000..998429dbb65c --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c @@ -0,0 +1,1195 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * camss-vfe-4-8.c + * + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module v4.8 + * + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2021 Linaro Ltd. + */ + +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> + +#include "camss.h" +#include "camss-vfe.h" +#include "camss-vfe-gen1.h" + +#define VFE_0_HW_VERSION 0x000 + +#define VFE_0_GLOBAL_RESET_CMD 0x018 +#define VFE_0_GLOBAL_RESET_CMD_CORE BIT(0) +#define VFE_0_GLOBAL_RESET_CMD_CAMIF BIT(1) +#define VFE_0_GLOBAL_RESET_CMD_BUS BIT(2) +#define VFE_0_GLOBAL_RESET_CMD_BUS_BDG BIT(3) +#define VFE_0_GLOBAL_RESET_CMD_REGISTER BIT(4) +#define VFE_0_GLOBAL_RESET_CMD_PM BIT(5) +#define VFE_0_GLOBAL_RESET_CMD_BUS_MISR BIT(6) +#define VFE_0_GLOBAL_RESET_CMD_TESTGEN BIT(7) +#define VFE_0_GLOBAL_RESET_CMD_DSP BIT(8) +#define VFE_0_GLOBAL_RESET_CMD_IDLE_CGC BIT(9) + +#define VFE_0_MODULE_LENS_EN 0x040 +#define VFE_0_MODULE_LENS_EN_DEMUX BIT(2) +#define VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE BIT(3) + +#define VFE_0_MODULE_ZOOM_EN 0x04c +#define VFE_0_MODULE_ZOOM_EN_SCALE_ENC BIT(1) +#define VFE_0_MODULE_ZOOM_EN_CROP_ENC BIT(2) +#define VFE_0_MODULE_ZOOM_EN_REALIGN_BUF BIT(9) + +#define VFE_0_CORE_CFG 0x050 +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR 0x4 +#define VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB 0x5 +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY 0x6 +#define VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY 0x7 +#define VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN BIT(4) + +#define VFE_0_IRQ_CMD 0x058 +#define VFE_0_IRQ_CMD_GLOBAL_CLEAR BIT(0) + +#define VFE_0_IRQ_MASK_0 0x05c +#define VFE_0_IRQ_MASK_0_CAMIF_SOF BIT(0) +#define VFE_0_IRQ_MASK_0_CAMIF_EOF BIT(1) +#define VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n) BIT((n) + 5) +#define VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(n) \ + ((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_MASK_0_RDIn_REG_UPDATE(n)) +#define VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(n) BIT((n) + 8) +#define VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(n) BIT((n) + 25) +#define VFE_0_IRQ_MASK_0_RESET_ACK BIT(31) +#define VFE_0_IRQ_MASK_1 0x060 +#define VFE_0_IRQ_MASK_1_CAMIF_ERROR BIT(0) +#define VFE_0_IRQ_MASK_1_VIOLATION BIT(7) +#define VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK BIT(8) +#define VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(n) BIT((n) + 9) +#define VFE_0_IRQ_MASK_1_RDIn_SOF(n) BIT((n) + 29) + +#define VFE_0_IRQ_CLEAR_0 0x064 +#define VFE_0_IRQ_CLEAR_1 0x068 + +#define VFE_0_IRQ_STATUS_0 0x06c +#define VFE_0_IRQ_STATUS_0_CAMIF_SOF BIT(0) +#define VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n) BIT((n) + 5) +#define VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(n) \ + ((n) == VFE_LINE_PIX ? BIT(4) : VFE_0_IRQ_STATUS_0_RDIn_REG_UPDATE(n)) +#define VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(n) BIT((n) + 8) +#define VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(n) BIT((n) + 25) +#define VFE_0_IRQ_STATUS_0_RESET_ACK BIT(31) +#define VFE_0_IRQ_STATUS_1 0x070 +#define VFE_0_IRQ_STATUS_1_VIOLATION BIT(7) +#define VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK BIT(8) +#define VFE_0_IRQ_STATUS_1_RDIn_SOF(n) BIT((n) + 29) + +#define VFE_0_IRQ_COMPOSITE_MASK_0 0x074 +#define VFE_0_VIOLATION_STATUS 0x07c + +#define VFE_0_BUS_CMD 0x80 +#define VFE_0_BUS_CMD_Mx_RLD_CMD(x) BIT(x) + +#define VFE_0_BUS_CFG 0x084 + +#define VFE_0_BUS_XBAR_CFG_x(x) (0x90 + 0x4 * ((x) / 2)) +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN BIT(2) +#define VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN BIT(3) +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTRA (0x1 << 4) +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER (0x2 << 4) +#define VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA (0x3 << 4) +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT 8 +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA 0x0 +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 0xc +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 0xd +#define VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 0xe + +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG(n) (0x0a0 + 0x2c * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_CFG_WR_PATH_SHIFT 0 +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(n) (0x0a4 + 0x2c * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(n) (0x0ac + 0x2c * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(n) (0x0b4 + 0x2c * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT 1 +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT 2 +#define VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK (0x1f << 2) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(n) (0x0b8 + 0x2c * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT 16 +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(n) (0x0bc + 0x2c * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(n) (0x0c0 + 0x2c * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(n) \ + (0x0c4 + 0x2c * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(n) \ + (0x0c8 + 0x2c * (n)) +#define VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF 0xffffffff + +#define VFE_0_BUS_PING_PONG_STATUS 0x338 + +#define VFE_0_BUS_BDG_CMD 0x400 +#define VFE_0_BUS_BDG_CMD_HALT_REQ 1 + +#define VFE_0_BUS_BDG_QOS_CFG_0 0x404 +#define VFE_0_BUS_BDG_QOS_CFG_0_CFG 0xaaa5aaa5 +#define VFE_0_BUS_BDG_QOS_CFG_1 0x408 +#define VFE_0_BUS_BDG_QOS_CFG_2 0x40c +#define VFE_0_BUS_BDG_QOS_CFG_3 0x410 +#define VFE_0_BUS_BDG_QOS_CFG_3_CFG 0xaa55aaa5 +#define VFE_0_BUS_BDG_QOS_CFG_4 0x414 +#define VFE_0_BUS_BDG_QOS_CFG_4_CFG 0xaa55aa55 +#define VFE_0_BUS_BDG_QOS_CFG_5 0x418 +#define VFE_0_BUS_BDG_QOS_CFG_6 0x41c +#define VFE_0_BUS_BDG_QOS_CFG_7 0x420 +#define VFE_0_BUS_BDG_QOS_CFG_7_CFG 0x0005aa55 + +#define VFE_0_BUS_BDG_DS_CFG_0 0x424 +#define VFE_0_BUS_BDG_DS_CFG_0_CFG 0xcccc1111 +#define VFE_0_BUS_BDG_DS_CFG_1 0x428 +#define VFE_0_BUS_BDG_DS_CFG_2 0x42c +#define VFE_0_BUS_BDG_DS_CFG_3 0x430 +#define VFE_0_BUS_BDG_DS_CFG_4 0x434 +#define VFE_0_BUS_BDG_DS_CFG_5 0x438 +#define VFE_0_BUS_BDG_DS_CFG_6 0x43c +#define VFE_0_BUS_BDG_DS_CFG_7 0x440 +#define VFE_0_BUS_BDG_DS_CFG_8 0x444 +#define VFE_0_BUS_BDG_DS_CFG_9 0x448 +#define VFE_0_BUS_BDG_DS_CFG_10 0x44c +#define VFE_0_BUS_BDG_DS_CFG_11 0x450 +#define VFE_0_BUS_BDG_DS_CFG_12 0x454 +#define VFE_0_BUS_BDG_DS_CFG_13 0x458 +#define VFE_0_BUS_BDG_DS_CFG_14 0x45c +#define VFE_0_BUS_BDG_DS_CFG_15 0x460 +#define VFE_0_BUS_BDG_DS_CFG_16 0x464 +#define VFE_0_BUS_BDG_DS_CFG_16_CFG 0x00000110 + +#define VFE_0_RDI_CFG_x(x) (0x46c + (0x4 * (x))) +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT 28 +#define VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK (0xf << 28) +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT 4 +#define VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK (0xf << 4) +#define VFE_0_RDI_CFG_x_RDI_EN_BIT BIT(2) +#define VFE_0_RDI_CFG_x_MIPI_EN_BITS 0x3 + +#define VFE_0_CAMIF_CMD 0x478 +#define VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY 0 +#define VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY 1 +#define VFE_0_CAMIF_CMD_NO_CHANGE 3 +#define VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS BIT(2) +#define VFE_0_CAMIF_CFG 0x47c +#define VFE_0_CAMIF_CFG_VFE_OUTPUT_EN BIT(6) +#define VFE_0_CAMIF_FRAME_CFG 0x484 +#define VFE_0_CAMIF_WINDOW_WIDTH_CFG 0x488 +#define VFE_0_CAMIF_WINDOW_HEIGHT_CFG 0x48c +#define VFE_0_CAMIF_SUBSAMPLE_CFG 0x490 +#define VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN 0x498 +#define VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN 0x49c +#define VFE_0_CAMIF_STATUS 0x4a4 +#define VFE_0_CAMIF_STATUS_HALT BIT(31) + +#define VFE_0_REG_UPDATE 0x4ac +#define VFE_0_REG_UPDATE_RDIn(n) BIT(1 + (n)) +#define VFE_0_REG_UPDATE_line_n(n) \ + ((n) == VFE_LINE_PIX ? 1 : VFE_0_REG_UPDATE_RDIn(n)) + +#define VFE_0_DEMUX_CFG 0x560 +#define VFE_0_DEMUX_CFG_PERIOD 0x3 +#define VFE_0_DEMUX_GAIN_0 0x564 +#define VFE_0_DEMUX_GAIN_0_CH0_EVEN (0x80 << 0) +#define VFE_0_DEMUX_GAIN_0_CH0_ODD (0x80 << 16) +#define VFE_0_DEMUX_GAIN_1 0x568 +#define VFE_0_DEMUX_GAIN_1_CH1 (0x80 << 0) +#define VFE_0_DEMUX_GAIN_1_CH2 (0x80 << 16) +#define VFE_0_DEMUX_EVEN_CFG 0x574 +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV 0x9cac +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU 0xac9c +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY 0xc9ca +#define VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY 0xcac9 +#define VFE_0_DEMUX_ODD_CFG 0x578 +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV 0x9cac +#define VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU 0xac9c +#define VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY 0xc9ca +#define VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY 0xcac9 + +#define VFE_0_SCALE_ENC_Y_CFG 0x91c +#define VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE 0x920 +#define VFE_0_SCALE_ENC_Y_H_PHASE 0x924 +#define VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE 0x934 +#define VFE_0_SCALE_ENC_Y_V_PHASE 0x938 +#define VFE_0_SCALE_ENC_CBCR_CFG 0x948 +#define VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE 0x94c +#define VFE_0_SCALE_ENC_CBCR_H_PHASE 0x950 +#define VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE 0x960 +#define VFE_0_SCALE_ENC_CBCR_V_PHASE 0x964 + +#define VFE_0_CROP_ENC_Y_WIDTH 0x974 +#define VFE_0_CROP_ENC_Y_HEIGHT 0x978 +#define VFE_0_CROP_ENC_CBCR_WIDTH 0x97c +#define VFE_0_CROP_ENC_CBCR_HEIGHT 0x980 + +#define VFE_0_CLAMP_ENC_MAX_CFG 0x984 +#define VFE_0_CLAMP_ENC_MAX_CFG_CH0 (0xff << 0) +#define VFE_0_CLAMP_ENC_MAX_CFG_CH1 (0xff << 8) +#define VFE_0_CLAMP_ENC_MAX_CFG_CH2 (0xff << 16) +#define VFE_0_CLAMP_ENC_MIN_CFG 0x988 +#define VFE_0_CLAMP_ENC_MIN_CFG_CH0 (0x0 << 0) +#define VFE_0_CLAMP_ENC_MIN_CFG_CH1 (0x0 << 8) +#define VFE_0_CLAMP_ENC_MIN_CFG_CH2 (0x0 << 16) + +#define VFE_0_REALIGN_BUF_CFG 0xaac +#define VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL BIT(2) +#define VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL BIT(3) +#define VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE BIT(4) + +#define VFE_0_BUS_IMAGE_MASTER_CMD 0xcec +#define VFE_0_BUS_IMAGE_MASTER_n_SHIFT(x) (2 * (x)) + +#define CAMIF_TIMEOUT_SLEEP_US 1000 +#define CAMIF_TIMEOUT_ALL_US 1000000 + +#define MSM_VFE_VFE0_UB_SIZE 2047 +#define MSM_VFE_VFE0_UB_SIZE_RDI (MSM_VFE_VFE0_UB_SIZE / 3) +#define MSM_VFE_VFE1_UB_SIZE 1535 +#define MSM_VFE_VFE1_UB_SIZE_RDI (MSM_VFE_VFE1_UB_SIZE / 3) + +static void vfe_hw_version_read(struct vfe_device *vfe, struct device *dev) +{ + u32 hw_version = readl_relaxed(vfe->base + VFE_0_HW_VERSION); + + dev_err(dev, "VFE HW Version = 0x%08x\n", hw_version); +} + +static inline void vfe_reg_clr(struct vfe_device *vfe, u32 reg, u32 clr_bits) +{ + u32 bits = readl_relaxed(vfe->base + reg); + + writel_relaxed(bits & ~clr_bits, vfe->base + reg); +} + +static inline void vfe_reg_set(struct vfe_device *vfe, u32 reg, u32 set_bits) +{ + u32 bits = readl_relaxed(vfe->base + reg); + + writel_relaxed(bits | set_bits, vfe->base + reg); +} + +static void vfe_global_reset(struct vfe_device *vfe) +{ + u32 reset_bits = VFE_0_GLOBAL_RESET_CMD_IDLE_CGC | + VFE_0_GLOBAL_RESET_CMD_DSP | + VFE_0_GLOBAL_RESET_CMD_TESTGEN | + VFE_0_GLOBAL_RESET_CMD_BUS_MISR | + VFE_0_GLOBAL_RESET_CMD_PM | + VFE_0_GLOBAL_RESET_CMD_REGISTER | + VFE_0_GLOBAL_RESET_CMD_BUS_BDG | + VFE_0_GLOBAL_RESET_CMD_BUS | + VFE_0_GLOBAL_RESET_CMD_CAMIF | + VFE_0_GLOBAL_RESET_CMD_CORE; + + writel_relaxed(BIT(31), vfe->base + VFE_0_IRQ_MASK_0); + + /* Enforce barrier between IRQ mask setup and global reset */ + wmb(); + writel_relaxed(reset_bits, vfe->base + VFE_0_GLOBAL_RESET_CMD); +} + +static void vfe_halt_request(struct vfe_device *vfe) +{ + writel_relaxed(VFE_0_BUS_BDG_CMD_HALT_REQ, + vfe->base + VFE_0_BUS_BDG_CMD); +} + +static void vfe_halt_clear(struct vfe_device *vfe) +{ + writel_relaxed(0x0, vfe->base + VFE_0_BUS_BDG_CMD); +} + +static void vfe_wm_frame_based(struct vfe_device *vfe, u8 wm, u8 enable) +{ + if (enable) + vfe_reg_set(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm), + 1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT); + else + vfe_reg_clr(vfe, VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm), + 1 << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_BASED_SHIFT); +} + +#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N)) + +static int vfe_word_per_line_by_pixel(u32 format, u32 pixel_per_line) +{ + int val = 0; + + switch (format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + val = CALC_WORD(pixel_per_line, 1, 8); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + val = CALC_WORD(pixel_per_line, 2, 8); + break; + } + + return val; +} + +static int vfe_word_per_line_by_bytes(u32 bytes_per_line) +{ + return CALC_WORD(bytes_per_line, 1, 8); +} + +static void vfe_get_wm_sizes(struct v4l2_pix_format_mplane *pix, u8 plane, + u16 *width, u16 *height, u16 *bytesperline) +{ + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + *width = pix->width; + *height = pix->height; + *bytesperline = pix->plane_fmt[0].bytesperline; + if (plane == 1) + *height /= 2; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + *width = pix->width; + *height = pix->height; + *bytesperline = pix->plane_fmt[0].bytesperline; + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_UYVY: + *width = pix->width; + *height = pix->height; + *bytesperline = pix->plane_fmt[plane].bytesperline; + break; + } +} + +static void vfe_wm_line_based(struct vfe_device *vfe, u32 wm, + struct v4l2_pix_format_mplane *pix, + u8 plane, u32 enable) +{ + u32 reg; + + if (enable) { + u16 width = 0, height = 0, bytesperline = 0, wpl; + + vfe_get_wm_sizes(pix, plane, &width, &height, &bytesperline); + + wpl = vfe_word_per_line_by_pixel(pix->pixelformat, width); + + reg = height - 1; + reg |= ((wpl + 3) / 4 - 1) << 16; + + writel_relaxed(reg, vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm)); + + wpl = vfe_word_per_line_by_bytes(bytesperline); + + reg = 0x3; + reg |= (height - 1) << 2; + reg |= ((wpl + 1) / 2) << 16; + + writel_relaxed(reg, vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm)); + } else { + writel_relaxed(0, vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_IMAGE_SIZE(wm)); + writel_relaxed(0, vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_BUFFER_CFG(wm)); + } +} + +static void vfe_wm_set_framedrop_period(struct vfe_device *vfe, u8 wm, u8 per) +{ + u32 reg; + + reg = readl_relaxed(vfe->base + + VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm)); + + reg &= ~(VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK); + + reg |= (per << VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_SHIFT) + & VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG_FRM_DROP_PER_MASK; + + writel_relaxed(reg, + vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_ADDR_CFG(wm)); +} + +static void vfe_wm_set_framedrop_pattern(struct vfe_device *vfe, u8 wm, + u32 pattern) +{ + writel_relaxed(pattern, vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_FRAMEDROP_PATTERN(wm)); +} + +static void vfe_wm_set_ub_cfg(struct vfe_device *vfe, u8 wm, + u16 offset, u16 depth) +{ + u32 reg; + + reg = (offset << VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG_OFFSET_SHIFT) | + depth; + writel_relaxed(reg, vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_UB_CFG(wm)); +} + +static void vfe_bus_reload_wm(struct vfe_device *vfe, u8 wm) +{ + /* Enforce barrier between any outstanding register write */ + wmb(); + + writel_relaxed(VFE_0_BUS_CMD_Mx_RLD_CMD(wm), vfe->base + VFE_0_BUS_CMD); + + /* Use barrier to make sure bus reload is issued before anything else */ + wmb(); +} + +static void vfe_wm_set_ping_addr(struct vfe_device *vfe, u8 wm, u32 addr) +{ + writel_relaxed(addr, + vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PING_ADDR(wm)); +} + +static void vfe_wm_set_pong_addr(struct vfe_device *vfe, u8 wm, u32 addr) +{ + writel_relaxed(addr, + vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_PONG_ADDR(wm)); +} + +static int vfe_wm_get_ping_pong_status(struct vfe_device *vfe, u8 wm) +{ + u32 reg; + + reg = readl_relaxed(vfe->base + VFE_0_BUS_PING_PONG_STATUS); + + return (reg >> wm) & 0x1; +} + +static void vfe_bus_enable_wr_if(struct vfe_device *vfe, u8 enable) +{ + if (enable) + writel_relaxed(0x101, vfe->base + VFE_0_BUS_CFG); + else + writel_relaxed(0, vfe->base + VFE_0_BUS_CFG); +} + +static void vfe_bus_connect_wm_to_rdi(struct vfe_device *vfe, u8 wm, + enum vfe_line_id id) +{ + u32 reg; + + reg = VFE_0_RDI_CFG_x_MIPI_EN_BITS; + vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), reg); + + reg = VFE_0_RDI_CFG_x_RDI_EN_BIT; + reg |= ((3 * id) << VFE_0_RDI_CFG_x_RDI_STREAM_SEL_SHIFT) & + VFE_0_RDI_CFG_x_RDI_STREAM_SEL_MASK; + vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id), reg); + + switch (id) { + case VFE_LINE_RDI0: + default: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + case VFE_LINE_RDI1: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + case VFE_LINE_RDI2: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + } + + if (wm % 2 == 1) + reg <<= 16; + + vfe_reg_set(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg); +} + +static void vfe_wm_set_subsample(struct vfe_device *vfe, u8 wm) +{ + writel_relaxed(VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN_DEF, + vfe->base + VFE_0_BUS_IMAGE_MASTER_n_WR_IRQ_SUBSAMPLE_PATTERN(wm)); +} + +static void vfe_bus_disconnect_wm_from_rdi(struct vfe_device *vfe, u8 wm, + enum vfe_line_id id) +{ + u32 reg; + + reg = VFE_0_RDI_CFG_x_RDI_EN_BIT; + vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), reg); + + switch (id) { + case VFE_LINE_RDI0: + default: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI0 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + case VFE_LINE_RDI1: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI1 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + case VFE_LINE_RDI2: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_VAL_RDI2 << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + break; + } + + if (wm % 2 == 1) + reg <<= 16; + + vfe_reg_clr(vfe, VFE_0_BUS_XBAR_CFG_x(wm), reg); +} + +static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output, + u8 enable) +{ + struct vfe_line *line = container_of(output, struct vfe_line, output); + u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; + u32 reg; + + switch (p) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + reg = VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_LUMA << + VFE_0_BUS_XBAR_CFG_x_M_SINGLE_STREAM_SEL_SHIFT; + + if (output->wm_idx[0] % 2 == 1) + reg <<= 16; + + if (enable) + vfe_reg_set(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]), + reg); + else + vfe_reg_clr(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]), + reg); + + reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN; + if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16) + reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA; + + if (output->wm_idx[1] % 2 == 1) + reg <<= 16; + + if (enable) + vfe_reg_set(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]), + reg); + else + vfe_reg_clr(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[1]), + reg); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + case V4L2_PIX_FMT_UYVY: + reg = VFE_0_BUS_XBAR_CFG_x_M_REALIGN_BUF_EN; + reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN; + + if (p == V4L2_PIX_FMT_YUYV || p == V4L2_PIX_FMT_YVYU) + reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA; + + if (output->wm_idx[0] % 2 == 1) + reg <<= 16; + + if (enable) + vfe_reg_set(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]), + reg); + else + vfe_reg_clr(vfe, + VFE_0_BUS_XBAR_CFG_x(output->wm_idx[0]), + reg); + break; + default: + break; + } +} + +static void vfe_set_realign_cfg(struct vfe_device *vfe, struct vfe_line *line, + u8 enable) +{ + u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; + u32 val = VFE_0_MODULE_ZOOM_EN_REALIGN_BUF; + + if (p != V4L2_PIX_FMT_YUYV && p != V4L2_PIX_FMT_YVYU && + p != V4L2_PIX_FMT_VYUY && p != V4L2_PIX_FMT_UYVY) + return; + + if (enable) { + vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val); + } else { + vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val); + return; + } + + val = VFE_0_REALIGN_BUF_CFG_HSUB_ENABLE; + + if (p == V4L2_PIX_FMT_UYVY || p == V4L2_PIX_FMT_YUYV) + val |= VFE_0_REALIGN_BUF_CFG_CR_ODD_PIXEL; + else + val |= VFE_0_REALIGN_BUF_CFG_CB_ODD_PIXEL; + + writel_relaxed(val, vfe->base + VFE_0_REALIGN_BUF_CFG); +} + +static void vfe_set_rdi_cid(struct vfe_device *vfe, enum vfe_line_id id, u8 cid) +{ + vfe_reg_clr(vfe, VFE_0_RDI_CFG_x(id), + VFE_0_RDI_CFG_x_RDI_M0_SEL_MASK); + + vfe_reg_set(vfe, VFE_0_RDI_CFG_x(id), + cid << VFE_0_RDI_CFG_x_RDI_M0_SEL_SHIFT); +} + +static void vfe_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + vfe->reg_update |= VFE_0_REG_UPDATE_line_n(line_id); + + /* Enforce barrier between line update and commit */ + wmb(); + + writel_relaxed(vfe->reg_update, vfe->base + VFE_0_REG_UPDATE); + + /* Make sure register update is issued before further reg writes */ + wmb(); +} + +static inline void vfe_reg_update_clear(struct vfe_device *vfe, + enum vfe_line_id line_id) +{ + vfe->reg_update &= ~VFE_0_REG_UPDATE_line_n(line_id); +} + +static void vfe_enable_irq_wm_line(struct vfe_device *vfe, u8 wm, + enum vfe_line_id line_id, u8 enable) +{ + u32 irq_en0 = VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(wm) | + VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id); + u32 irq_en1 = VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(wm) | + VFE_0_IRQ_MASK_1_RDIn_SOF(line_id); + + if (enable) { + vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1); + } else { + vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1); + } +} + +static void vfe_enable_irq_pix_line(struct vfe_device *vfe, u8 comp, + enum vfe_line_id line_id, u8 enable) +{ + struct vfe_output *output = &vfe->line[line_id].output; + unsigned int i; + u32 irq_en0; + u32 irq_en1; + u32 comp_mask = 0; + + irq_en0 = VFE_0_IRQ_MASK_0_CAMIF_SOF; + irq_en0 |= VFE_0_IRQ_MASK_0_CAMIF_EOF; + irq_en0 |= VFE_0_IRQ_MASK_0_IMAGE_COMPOSITE_DONE_n(comp); + irq_en0 |= VFE_0_IRQ_MASK_0_line_n_REG_UPDATE(line_id); + irq_en1 = VFE_0_IRQ_MASK_1_CAMIF_ERROR; + for (i = 0; i < output->wm_num; i++) { + irq_en1 |= VFE_0_IRQ_MASK_1_IMAGE_MASTER_n_BUS_OVERFLOW(output->wm_idx[i]); + comp_mask |= (1 << output->wm_idx[i]) << comp * 8; + } + + if (enable) { + vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1); + vfe_reg_set(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask); + } else { + vfe_reg_clr(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_clr(vfe, VFE_0_IRQ_MASK_1, irq_en1); + vfe_reg_clr(vfe, VFE_0_IRQ_COMPOSITE_MASK_0, comp_mask); + } +} + +static void vfe_enable_irq_common(struct vfe_device *vfe) +{ + u32 irq_en0 = VFE_0_IRQ_MASK_0_RESET_ACK; + u32 irq_en1 = VFE_0_IRQ_MASK_1_VIOLATION | + VFE_0_IRQ_MASK_1_BUS_BDG_HALT_ACK; + + vfe_reg_set(vfe, VFE_0_IRQ_MASK_0, irq_en0); + vfe_reg_set(vfe, VFE_0_IRQ_MASK_1, irq_en1); +} + +static void vfe_set_demux_cfg(struct vfe_device *vfe, struct vfe_line *line) +{ + u32 val, even_cfg, odd_cfg; + + writel_relaxed(VFE_0_DEMUX_CFG_PERIOD, vfe->base + VFE_0_DEMUX_CFG); + + val = VFE_0_DEMUX_GAIN_0_CH0_EVEN | VFE_0_DEMUX_GAIN_0_CH0_ODD; + writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_0); + + val = VFE_0_DEMUX_GAIN_1_CH1 | VFE_0_DEMUX_GAIN_1_CH2; + writel_relaxed(val, vfe->base + VFE_0_DEMUX_GAIN_1); + + switch (line->fmt[MSM_VFE_PAD_SINK].code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YUYV; + odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YUYV; + break; + case MEDIA_BUS_FMT_YVYU8_2X8: + even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_YVYU; + odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_YVYU; + break; + case MEDIA_BUS_FMT_UYVY8_2X8: + default: + even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_UYVY; + odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_UYVY; + break; + case MEDIA_BUS_FMT_VYUY8_2X8: + even_cfg = VFE_0_DEMUX_EVEN_CFG_PATTERN_VYUY; + odd_cfg = VFE_0_DEMUX_ODD_CFG_PATTERN_VYUY; + break; + } + + writel_relaxed(even_cfg, vfe->base + VFE_0_DEMUX_EVEN_CFG); + writel_relaxed(odd_cfg, vfe->base + VFE_0_DEMUX_ODD_CFG); +} + +static void vfe_set_scale_cfg(struct vfe_device *vfe, struct vfe_line *line) +{ + u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; + u32 reg; + u16 input, output; + u8 interp_reso; + u32 phase_mult; + + writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_Y_CFG); + + input = line->fmt[MSM_VFE_PAD_SINK].width - 1; + output = line->compose.width - 1; + reg = (output << 16) | input; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_IMAGE_SIZE); + + interp_reso = vfe_calc_interp_reso(input, output); + phase_mult = input * (1 << (14 + interp_reso)) / output; + reg = (interp_reso << 28) | phase_mult; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_H_PHASE); + + input = line->fmt[MSM_VFE_PAD_SINK].height - 1; + output = line->compose.height - 1; + reg = (output << 16) | input; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_IMAGE_SIZE); + + interp_reso = vfe_calc_interp_reso(input, output); + phase_mult = input * (1 << (14 + interp_reso)) / output; + reg = (interp_reso << 28) | phase_mult; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_Y_V_PHASE); + + writel_relaxed(0x3, vfe->base + VFE_0_SCALE_ENC_CBCR_CFG); + + input = line->fmt[MSM_VFE_PAD_SINK].width - 1; + output = line->compose.width / 2 - 1; + reg = (output << 16) | input; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_IMAGE_SIZE); + + interp_reso = vfe_calc_interp_reso(input, output); + phase_mult = input * (1 << (14 + interp_reso)) / output; + reg = (interp_reso << 28) | phase_mult; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_H_PHASE); + + input = line->fmt[MSM_VFE_PAD_SINK].height - 1; + output = line->compose.height - 1; + if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21) + output = line->compose.height / 2 - 1; + reg = (output << 16) | input; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_IMAGE_SIZE); + + interp_reso = vfe_calc_interp_reso(input, output); + phase_mult = input * (1 << (14 + interp_reso)) / output; + reg = (interp_reso << 28) | phase_mult; + writel_relaxed(reg, vfe->base + VFE_0_SCALE_ENC_CBCR_V_PHASE); +} + +static void vfe_set_crop_cfg(struct vfe_device *vfe, struct vfe_line *line) +{ + u32 p = line->video_out.active_fmt.fmt.pix_mp.pixelformat; + u32 reg; + u16 first, last; + + first = line->crop.left; + last = line->crop.left + line->crop.width - 1; + reg = (first << 16) | last; + writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_WIDTH); + + first = line->crop.top; + last = line->crop.top + line->crop.height - 1; + reg = (first << 16) | last; + writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_Y_HEIGHT); + + first = line->crop.left / 2; + last = line->crop.left / 2 + line->crop.width / 2 - 1; + reg = (first << 16) | last; + writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_WIDTH); + + first = line->crop.top; + last = line->crop.top + line->crop.height - 1; + if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV21) { + first = line->crop.top / 2; + last = line->crop.top / 2 + line->crop.height / 2 - 1; + } + reg = (first << 16) | last; + writel_relaxed(reg, vfe->base + VFE_0_CROP_ENC_CBCR_HEIGHT); +} + +static void vfe_set_clamp_cfg(struct vfe_device *vfe) +{ + u32 val = VFE_0_CLAMP_ENC_MAX_CFG_CH0 | + VFE_0_CLAMP_ENC_MAX_CFG_CH1 | + VFE_0_CLAMP_ENC_MAX_CFG_CH2; + + writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MAX_CFG); + + val = VFE_0_CLAMP_ENC_MIN_CFG_CH0 | + VFE_0_CLAMP_ENC_MIN_CFG_CH1 | + VFE_0_CLAMP_ENC_MIN_CFG_CH2; + + writel_relaxed(val, vfe->base + VFE_0_CLAMP_ENC_MIN_CFG); +} + +static void vfe_set_cgc_override(struct vfe_device *vfe, u8 wm, u8 enable) +{ + /* empty */ +} + +static void vfe_set_camif_cfg(struct vfe_device *vfe, struct vfe_line *line) +{ + u32 val; + + switch (line->fmt[MSM_VFE_PAD_SINK].code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCBYCR; + break; + case MEDIA_BUS_FMT_YVYU8_2X8: + val = VFE_0_CORE_CFG_PIXEL_PATTERN_YCRYCB; + break; + case MEDIA_BUS_FMT_UYVY8_2X8: + default: + val = VFE_0_CORE_CFG_PIXEL_PATTERN_CBYCRY; + break; + case MEDIA_BUS_FMT_VYUY8_2X8: + val = VFE_0_CORE_CFG_PIXEL_PATTERN_CRYCBY; + break; + } + + val |= VFE_0_CORE_CFG_COMPOSITE_REG_UPDATE_EN; + writel_relaxed(val, vfe->base + VFE_0_CORE_CFG); + + val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1; + val |= (line->fmt[MSM_VFE_PAD_SINK].height - 1) << 16; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_FRAME_CFG); + + val = line->fmt[MSM_VFE_PAD_SINK].width * 2 - 1; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_WIDTH_CFG); + + val = line->fmt[MSM_VFE_PAD_SINK].height - 1; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_WINDOW_HEIGHT_CFG); + + val = 0xffffffff; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_SUBSAMPLE_CFG); + + val = 0xffffffff; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_FRAMEDROP_PATTERN); + + val = 0xffffffff; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_IRQ_SUBSAMPLE_PATTERN); + + val = VFE_0_RDI_CFG_x_MIPI_EN_BITS; + vfe_reg_set(vfe, VFE_0_RDI_CFG_x(0), val); + + val = VFE_0_CAMIF_CFG_VFE_OUTPUT_EN; + writel_relaxed(val, vfe->base + VFE_0_CAMIF_CFG); +} + +static void vfe_set_camif_cmd(struct vfe_device *vfe, u8 enable) +{ + u32 cmd; + + cmd = VFE_0_CAMIF_CMD_CLEAR_CAMIF_STATUS | VFE_0_CAMIF_CMD_NO_CHANGE; + writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD); + + /* Make sure camif command is issued written before it is changed again */ + wmb(); + + if (enable) + cmd = VFE_0_CAMIF_CMD_ENABLE_FRAME_BOUNDARY; + else + cmd = VFE_0_CAMIF_CMD_DISABLE_FRAME_BOUNDARY; + + writel_relaxed(cmd, vfe->base + VFE_0_CAMIF_CMD); +} + +static void vfe_set_module_cfg(struct vfe_device *vfe, u8 enable) +{ + u32 val_lens = VFE_0_MODULE_LENS_EN_DEMUX | + VFE_0_MODULE_LENS_EN_CHROMA_UPSAMPLE; + u32 val_zoom = VFE_0_MODULE_ZOOM_EN_SCALE_ENC | + VFE_0_MODULE_ZOOM_EN_CROP_ENC; + + if (enable) { + vfe_reg_set(vfe, VFE_0_MODULE_LENS_EN, val_lens); + vfe_reg_set(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom); + } else { + vfe_reg_clr(vfe, VFE_0_MODULE_LENS_EN, val_lens); + vfe_reg_clr(vfe, VFE_0_MODULE_ZOOM_EN, val_zoom); + } +} + +static int vfe_camif_wait_for_stop(struct vfe_device *vfe, struct device *dev) +{ + u32 val; + int ret; + + ret = readl_poll_timeout(vfe->base + VFE_0_CAMIF_STATUS, + val, + (val & VFE_0_CAMIF_STATUS_HALT), + CAMIF_TIMEOUT_SLEEP_US, + CAMIF_TIMEOUT_ALL_US); + if (ret < 0) + dev_err(dev, "%s: camif stop timeout\n", __func__); + + return ret; +} + +/* + * vfe_isr - VFE module interrupt handler + * @irq: Interrupt line + * @dev: VFE device + * + * Return IRQ_HANDLED on success + */ +static irqreturn_t vfe_isr(int irq, void *dev) +{ + struct vfe_device *vfe = dev; + u32 value0, value1; + int i, j; + + vfe->ops->isr_read(vfe, &value0, &value1); + + dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n", + value0, value1); + + if (value0 & VFE_0_IRQ_STATUS_0_RESET_ACK) + vfe->isr_ops.reset_ack(vfe); + + if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION) + vfe->ops->violation_read(vfe); + + if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK) + vfe->isr_ops.halt_ack(vfe); + + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) + if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i)) + vfe->isr_ops.reg_update(vfe, i); + + if (value0 & VFE_0_IRQ_STATUS_0_CAMIF_SOF) + vfe->isr_ops.sof(vfe, VFE_LINE_PIX); + + for (i = VFE_LINE_RDI0; i <= VFE_LINE_RDI2; i++) + if (value1 & VFE_0_IRQ_STATUS_1_RDIn_SOF(i)) + vfe->isr_ops.sof(vfe, i); + + for (i = 0; i < MSM_VFE_COMPOSITE_IRQ_NUM; i++) + if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_COMPOSITE_DONE_n(i)) { + vfe->isr_ops.comp_done(vfe, i); + for (j = 0; j < ARRAY_SIZE(vfe->wm_output_map); j++) + if (vfe->wm_output_map[j] == VFE_LINE_PIX) + value0 &= ~VFE_0_IRQ_MASK_0_IMAGE_MASTER_n_PING_PONG(j); + } + + for (i = 0; i < MSM_VFE_IMAGE_MASTERS_NUM; i++) + if (value0 & VFE_0_IRQ_STATUS_0_IMAGE_MASTER_n_PING_PONG(i)) + vfe->isr_ops.wm_done(vfe, i); + + return IRQ_HANDLED; +} + +static u16 vfe_get_ub_size(u8 vfe_id) +{ + /* On VFE4.8 the ub-size is the same on both instances */ + return MSM_VFE_VFE0_UB_SIZE_RDI; +} + +static void vfe_wm_enable(struct vfe_device *vfe, u8 wm, u8 enable) +{ + if (enable) + writel_relaxed(2 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm), + vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD); + else + writel_relaxed(1 << VFE_0_BUS_IMAGE_MASTER_n_SHIFT(wm), + vfe->base + VFE_0_BUS_IMAGE_MASTER_CMD); + + /* The WM must be enabled before sending other commands */ + wmb(); +} + +static void vfe_set_qos(struct vfe_device *vfe) +{ + u32 val = VFE_0_BUS_BDG_QOS_CFG_0_CFG; + u32 val3 = VFE_0_BUS_BDG_QOS_CFG_3_CFG; + u32 val4 = VFE_0_BUS_BDG_QOS_CFG_4_CFG; + u32 val7 = VFE_0_BUS_BDG_QOS_CFG_7_CFG; + + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_0); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_1); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_QOS_CFG_2); + writel_relaxed(val3, vfe->base + VFE_0_BUS_BDG_QOS_CFG_3); + writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_4); + writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_5); + writel_relaxed(val4, vfe->base + VFE_0_BUS_BDG_QOS_CFG_6); + writel_relaxed(val7, vfe->base + VFE_0_BUS_BDG_QOS_CFG_7); +} + +static void vfe_set_ds(struct vfe_device *vfe) +{ + u32 val = VFE_0_BUS_BDG_DS_CFG_0_CFG; + u32 val16 = VFE_0_BUS_BDG_DS_CFG_16_CFG; + + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_0); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_1); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_2); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_3); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_4); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_5); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_6); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_7); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_8); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_9); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_10); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_11); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_12); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_13); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_14); + writel_relaxed(val, vfe->base + VFE_0_BUS_BDG_DS_CFG_15); + writel_relaxed(val16, vfe->base + VFE_0_BUS_BDG_DS_CFG_16); +} + +static void vfe_isr_read(struct vfe_device *vfe, u32 *value0, u32 *value1) +{ + *value0 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_0); + *value1 = readl_relaxed(vfe->base + VFE_0_IRQ_STATUS_1); + + writel_relaxed(*value0, vfe->base + VFE_0_IRQ_CLEAR_0); + writel_relaxed(*value1, vfe->base + VFE_0_IRQ_CLEAR_1); + + /* Enforce barrier between local & global IRQ clear */ + wmb(); + writel_relaxed(VFE_0_IRQ_CMD_GLOBAL_CLEAR, vfe->base + VFE_0_IRQ_CMD); +} + +/* + * vfe_pm_domain_off - Disable power domains specific to this VFE. + * @vfe: VFE Device + */ +static void vfe_pm_domain_off(struct vfe_device *vfe) +{ + struct camss *camss = vfe->camss; + + device_link_del(camss->genpd_link[vfe->id]); +} + +/* + * vfe_pm_domain_on - Enable power domains specific to this VFE. + * @vfe: VFE Device + */ +static int vfe_pm_domain_on(struct vfe_device *vfe) +{ + struct camss *camss = vfe->camss; + enum vfe_line_id id = vfe->id; + + camss->genpd_link[id] = device_link_add(camss->dev, camss->genpd[id], DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); + + if (!camss->genpd_link[id]) { + dev_err(vfe->camss->dev, "Failed to add VFE#%d to power domain\n", id); + return -EINVAL; + } + + return 0; +} + +static void vfe_violation_read(struct vfe_device *vfe) +{ + u32 violation = readl_relaxed(vfe->base + VFE_0_VIOLATION_STATUS); + + pr_err_ratelimited("VFE: violation = 0x%08x\n", violation); +} + +static const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_8 = { + .bus_connect_wm_to_rdi = vfe_bus_connect_wm_to_rdi, + .bus_disconnect_wm_from_rdi = vfe_bus_disconnect_wm_from_rdi, + .bus_enable_wr_if = vfe_bus_enable_wr_if, + .bus_reload_wm = vfe_bus_reload_wm, + .camif_wait_for_stop = vfe_camif_wait_for_stop, + .enable_irq_common = vfe_enable_irq_common, + .enable_irq_pix_line = vfe_enable_irq_pix_line, + .enable_irq_wm_line = vfe_enable_irq_wm_line, + .get_ub_size = vfe_get_ub_size, + .halt_clear = vfe_halt_clear, + .halt_request = vfe_halt_request, + .set_camif_cfg = vfe_set_camif_cfg, + .set_camif_cmd = vfe_set_camif_cmd, + .set_cgc_override = vfe_set_cgc_override, + .set_clamp_cfg = vfe_set_clamp_cfg, + .set_crop_cfg = vfe_set_crop_cfg, + .set_demux_cfg = vfe_set_demux_cfg, + .set_ds = vfe_set_ds, + .set_module_cfg = vfe_set_module_cfg, + .set_qos = vfe_set_qos, + .set_rdi_cid = vfe_set_rdi_cid, + .set_realign_cfg = vfe_set_realign_cfg, + .set_scale_cfg = vfe_set_scale_cfg, + .set_xbar_cfg = vfe_set_xbar_cfg, + .wm_enable = vfe_wm_enable, + .wm_frame_based = vfe_wm_frame_based, + .wm_get_ping_pong_status = vfe_wm_get_ping_pong_status, + .wm_line_based = vfe_wm_line_based, + .wm_set_framedrop_pattern = vfe_wm_set_framedrop_pattern, + .wm_set_framedrop_period = vfe_wm_set_framedrop_period, + .wm_set_ping_addr = vfe_wm_set_ping_addr, + .wm_set_pong_addr = vfe_wm_set_pong_addr, + .wm_set_subsample = vfe_wm_set_subsample, + .wm_set_ub_cfg = vfe_wm_set_ub_cfg, +}; + +static void vfe_subdev_init(struct device *dev, struct vfe_device *vfe) +{ + vfe->isr_ops = vfe_isr_ops_gen1; + vfe->ops_gen1 = &vfe_ops_gen1_4_8; + vfe->video_ops = vfe_video_ops_gen1; + + vfe->line_num = VFE_LINE_NUM_GEN1; +} + +const struct vfe_hw_ops vfe_ops_4_8 = { + .global_reset = vfe_global_reset, + .hw_version_read = vfe_hw_version_read, + .isr_read = vfe_isr_read, + .isr = vfe_isr, + .pm_domain_off = vfe_pm_domain_off, + .pm_domain_on = vfe_pm_domain_on, + .reg_update_clear = vfe_reg_update_clear, + .reg_update = vfe_reg_update, + .subdev_init = vfe_subdev_init, + .vfe_disable = vfe_gen1_disable, + .vfe_enable = vfe_gen1_enable, + .vfe_halt = vfe_gen1_halt, + .violation_read = vfe_violation_read, +}; diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c new file mode 100644 index 000000000000..4fd265d01883 --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c @@ -0,0 +1,742 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * camss-vfe-gen1.c + * + * Qualcomm MSM Camera Subsystem - VFE Common functionality for Gen 1 versions of hw (4.1, 4.7..) + * + * Copyright (C) 2020 Linaro Ltd. + */ + +#include "camss.h" +#include "camss-vfe.h" +#include "camss-vfe-gen1.h" + +/* Max number of frame drop updates per frame */ +#define VFE_FRAME_DROP_UPDATES 2 +#define VFE_NEXT_SOF_MS 500 + +int vfe_gen1_halt(struct vfe_device *vfe) +{ + unsigned long time; + + reinit_completion(&vfe->halt_complete); + + vfe->ops_gen1->halt_request(vfe); + + time = wait_for_completion_timeout(&vfe->halt_complete, + msecs_to_jiffies(VFE_HALT_TIMEOUT_MS)); + if (!time) { + dev_err(vfe->camss->dev, "VFE halt timeout\n"); + return -EIO; + } + + return 0; +} + +static int vfe_disable_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output = &line->output; + const struct vfe_hw_ops *ops = vfe->ops; + unsigned long flags; + unsigned long time; + unsigned int i; + + spin_lock_irqsave(&vfe->output_lock, flags); + + output->gen1.wait_sof = 1; + spin_unlock_irqrestore(&vfe->output_lock, flags); + + time = wait_for_completion_timeout(&output->sof, msecs_to_jiffies(VFE_NEXT_SOF_MS)); + if (!time) + dev_err(vfe->camss->dev, "VFE sof timeout\n"); + + spin_lock_irqsave(&vfe->output_lock, flags); + for (i = 0; i < output->wm_num; i++) + vfe->ops_gen1->wm_enable(vfe, output->wm_idx[i], 0); + + ops->reg_update(vfe, line->id); + output->wait_reg_update = 1; + spin_unlock_irqrestore(&vfe->output_lock, flags); + + time = wait_for_completion_timeout(&output->reg_update, msecs_to_jiffies(VFE_NEXT_SOF_MS)); + if (!time) + dev_err(vfe->camss->dev, "VFE reg update timeout\n"); + + spin_lock_irqsave(&vfe->output_lock, flags); + + if (line->id != VFE_LINE_PIX) { + vfe->ops_gen1->wm_frame_based(vfe, output->wm_idx[0], 0); + vfe->ops_gen1->bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0], line->id); + vfe->ops_gen1->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0); + vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[0], 0); + spin_unlock_irqrestore(&vfe->output_lock, flags); + } else { + for (i = 0; i < output->wm_num; i++) { + vfe->ops_gen1->wm_line_based(vfe, output->wm_idx[i], NULL, i, 0); + vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[i], 0); + } + + vfe->ops_gen1->enable_irq_pix_line(vfe, 0, line->id, 0); + vfe->ops_gen1->set_module_cfg(vfe, 0); + vfe->ops_gen1->set_realign_cfg(vfe, line, 0); + vfe->ops_gen1->set_xbar_cfg(vfe, output, 0); + vfe->ops_gen1->set_camif_cmd(vfe, 0); + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + vfe->ops_gen1->camif_wait_for_stop(vfe, vfe->camss->dev); + } + + return 0; +} + +/* + * vfe_gen1_disable - Disable streaming on VFE line + * @line: VFE line + * + * Return 0 on success or a negative error code otherwise + */ +int vfe_gen1_disable(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + + vfe_disable_output(line); + + vfe_put_output(line); + + mutex_lock(&vfe->stream_lock); + + if (vfe->stream_count == 1) + vfe->ops_gen1->bus_enable_wr_if(vfe, 0); + + vfe->stream_count--; + + mutex_unlock(&vfe->stream_lock); + + return 0; +} + +static void vfe_output_init_addrs(struct vfe_device *vfe, + struct vfe_output *output, u8 sync, + struct vfe_line *line) +{ + u32 ping_addr; + u32 pong_addr; + unsigned int i; + + output->gen1.active_buf = 0; + + for (i = 0; i < output->wm_num; i++) { + if (output->buf[0]) + ping_addr = output->buf[0]->addr[i]; + else + ping_addr = 0; + + if (output->buf[1]) + pong_addr = output->buf[1]->addr[i]; + else + pong_addr = ping_addr; + + vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr); + vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr); + if (sync) + vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]); + } +} + +static void vfe_output_frame_drop(struct vfe_device *vfe, + struct vfe_output *output, + u32 drop_pattern) +{ + u8 drop_period; + unsigned int i; + + /* We need to toggle update period to be valid on next frame */ + output->drop_update_idx++; + output->drop_update_idx %= VFE_FRAME_DROP_UPDATES; + drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx; + + for (i = 0; i < output->wm_num; i++) { + vfe->ops_gen1->wm_set_framedrop_period(vfe, output->wm_idx[i], drop_period); + vfe->ops_gen1->wm_set_framedrop_pattern(vfe, output->wm_idx[i], drop_pattern); + } + + vfe->ops->reg_update(vfe, container_of(output, struct vfe_line, output)->id); +} + +static int vfe_enable_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output = &line->output; + const struct vfe_hw_ops *ops = vfe->ops; + struct media_entity *sensor; + unsigned long flags; + unsigned int frame_skip = 0; + unsigned int i; + u16 ub_size; + + ub_size = vfe->ops_gen1->get_ub_size(vfe->id); + if (!ub_size) + return -EINVAL; + + sensor = camss_find_sensor(&line->subdev.entity); + if (sensor) { + struct v4l2_subdev *subdev = media_entity_to_v4l2_subdev(sensor); + + v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip); + /* Max frame skip is 29 frames */ + if (frame_skip > VFE_FRAME_DROP_VAL - 1) + frame_skip = VFE_FRAME_DROP_VAL - 1; + } + + spin_lock_irqsave(&vfe->output_lock, flags); + + ops->reg_update_clear(vfe, line->id); + + if (output->state != VFE_OUTPUT_RESERVED) { + dev_err(vfe->camss->dev, "Output is not in reserved state %d\n", output->state); + spin_unlock_irqrestore(&vfe->output_lock, flags); + return -EINVAL; + } + output->state = VFE_OUTPUT_IDLE; + + output->buf[0] = vfe_buf_get_pending(output); + output->buf[1] = vfe_buf_get_pending(output); + + if (!output->buf[0] && output->buf[1]) { + output->buf[0] = output->buf[1]; + output->buf[1] = NULL; + } + + if (output->buf[0]) + output->state = VFE_OUTPUT_SINGLE; + + if (output->buf[1]) + output->state = VFE_OUTPUT_CONTINUOUS; + + switch (output->state) { + case VFE_OUTPUT_SINGLE: + vfe_output_frame_drop(vfe, output, 1 << frame_skip); + break; + case VFE_OUTPUT_CONTINUOUS: + vfe_output_frame_drop(vfe, output, 3 << frame_skip); + break; + default: + vfe_output_frame_drop(vfe, output, 0); + break; + } + + output->sequence = 0; + output->gen1.wait_sof = 0; + output->wait_reg_update = 0; + reinit_completion(&output->sof); + reinit_completion(&output->reg_update); + + vfe_output_init_addrs(vfe, output, 0, line); + + if (line->id != VFE_LINE_PIX) { + vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[0], 1); + vfe->ops_gen1->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1); + vfe->ops_gen1->bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id); + vfe->ops_gen1->wm_set_subsample(vfe, output->wm_idx[0]); + vfe->ops_gen1->set_rdi_cid(vfe, line->id, 0); + vfe->ops_gen1->wm_set_ub_cfg(vfe, output->wm_idx[0], + (ub_size + 1) * output->wm_idx[0], ub_size); + vfe->ops_gen1->wm_frame_based(vfe, output->wm_idx[0], 1); + vfe->ops_gen1->wm_enable(vfe, output->wm_idx[0], 1); + vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[0]); + } else { + ub_size /= output->wm_num; + for (i = 0; i < output->wm_num; i++) { + vfe->ops_gen1->set_cgc_override(vfe, output->wm_idx[i], 1); + vfe->ops_gen1->wm_set_subsample(vfe, output->wm_idx[i]); + vfe->ops_gen1->wm_set_ub_cfg(vfe, output->wm_idx[i], + (ub_size + 1) * output->wm_idx[i], ub_size); + vfe->ops_gen1->wm_line_based(vfe, output->wm_idx[i], + &line->video_out.active_fmt.fmt.pix_mp, i, 1); + vfe->ops_gen1->wm_enable(vfe, output->wm_idx[i], 1); + vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]); + } + vfe->ops_gen1->enable_irq_pix_line(vfe, 0, line->id, 1); + vfe->ops_gen1->set_module_cfg(vfe, 1); + vfe->ops_gen1->set_camif_cfg(vfe, line); + vfe->ops_gen1->set_realign_cfg(vfe, line, 1); + vfe->ops_gen1->set_xbar_cfg(vfe, output, 1); + vfe->ops_gen1->set_demux_cfg(vfe, line); + vfe->ops_gen1->set_scale_cfg(vfe, line); + vfe->ops_gen1->set_crop_cfg(vfe, line); + vfe->ops_gen1->set_clamp_cfg(vfe); + vfe->ops_gen1->set_camif_cmd(vfe, 1); + } + + ops->reg_update(vfe, line->id); + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; +} + +static int vfe_get_output(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output; + struct v4l2_format *f = &line->video_out.active_fmt; + unsigned long flags; + int i; + int wm_idx; + + spin_lock_irqsave(&vfe->output_lock, flags); + + output = &line->output; + if (output->state != VFE_OUTPUT_OFF) { + dev_err(vfe->camss->dev, "Output is running\n"); + goto error; + } + output->state = VFE_OUTPUT_RESERVED; + + output->gen1.active_buf = 0; + + switch (f->fmt.pix_mp.pixelformat) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + output->wm_num = 2; + break; + default: + output->wm_num = 1; + break; + } + + for (i = 0; i < output->wm_num; i++) { + wm_idx = vfe_reserve_wm(vfe, line->id); + if (wm_idx < 0) { + dev_err(vfe->camss->dev, "Can not reserve wm\n"); + goto error_get_wm; + } + output->wm_idx[i] = wm_idx; + } + + output->drop_update_idx = 0; + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; + +error_get_wm: + for (i--; i >= 0; i--) + vfe_release_wm(vfe, output->wm_idx[i]); + output->state = VFE_OUTPUT_OFF; +error: + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return -EINVAL; +} + +int vfe_gen1_enable(struct vfe_line *line) +{ + struct vfe_device *vfe = to_vfe(line); + int ret; + + mutex_lock(&vfe->stream_lock); + + if (!vfe->stream_count) { + vfe->ops_gen1->enable_irq_common(vfe); + vfe->ops_gen1->bus_enable_wr_if(vfe, 1); + vfe->ops_gen1->set_qos(vfe); + vfe->ops_gen1->set_ds(vfe); + } + + vfe->stream_count++; + + mutex_unlock(&vfe->stream_lock); + + ret = vfe_get_output(line); + if (ret < 0) + goto error_get_output; + + ret = vfe_enable_output(line); + if (ret < 0) + goto error_enable_output; + + vfe->was_streaming = 1; + + return 0; + +error_enable_output: + vfe_put_output(line); + +error_get_output: + mutex_lock(&vfe->stream_lock); + + if (vfe->stream_count == 1) + vfe->ops_gen1->bus_enable_wr_if(vfe, 0); + + vfe->stream_count--; + + mutex_unlock(&vfe->stream_lock); + + return ret; +} + +static void vfe_output_update_ping_addr(struct vfe_device *vfe, + struct vfe_output *output, u8 sync, + struct vfe_line *line) +{ + u32 addr; + unsigned int i; + + for (i = 0; i < output->wm_num; i++) { + if (output->buf[0]) + addr = output->buf[0]->addr[i]; + else + addr = 0; + + vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], addr); + if (sync) + vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]); + } +} + +static void vfe_output_update_pong_addr(struct vfe_device *vfe, + struct vfe_output *output, u8 sync, + struct vfe_line *line) +{ + u32 addr; + unsigned int i; + + for (i = 0; i < output->wm_num; i++) { + if (output->buf[1]) + addr = output->buf[1]->addr[i]; + else + addr = 0; + + vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], addr); + if (sync) + vfe->ops_gen1->bus_reload_wm(vfe, output->wm_idx[i]); + } +} + +static void vfe_buf_update_wm_on_next(struct vfe_device *vfe, + struct vfe_output *output) +{ + switch (output->state) { + case VFE_OUTPUT_CONTINUOUS: + vfe_output_frame_drop(vfe, output, 3); + break; + case VFE_OUTPUT_SINGLE: + default: + dev_err_ratelimited(vfe->camss->dev, + "Next buf in wrong state! %d\n", + output->state); + break; + } +} + +static void vfe_buf_update_wm_on_last(struct vfe_device *vfe, + struct vfe_output *output) +{ + switch (output->state) { + case VFE_OUTPUT_CONTINUOUS: + output->state = VFE_OUTPUT_SINGLE; + vfe_output_frame_drop(vfe, output, 1); + break; + case VFE_OUTPUT_SINGLE: + output->state = VFE_OUTPUT_STOPPING; + vfe_output_frame_drop(vfe, output, 0); + break; + default: + dev_err_ratelimited(vfe->camss->dev, + "Last buff in wrong state! %d\n", + output->state); + break; + } +} + +static void vfe_buf_update_wm_on_new(struct vfe_device *vfe, + struct vfe_output *output, + struct camss_buffer *new_buf, + struct vfe_line *line) +{ + int inactive_idx; + + switch (output->state) { + case VFE_OUTPUT_SINGLE: + inactive_idx = !output->gen1.active_buf; + + if (!output->buf[inactive_idx]) { + output->buf[inactive_idx] = new_buf; + + if (inactive_idx) + vfe_output_update_pong_addr(vfe, output, 0, line); + else + vfe_output_update_ping_addr(vfe, output, 0, line); + + vfe_output_frame_drop(vfe, output, 3); + output->state = VFE_OUTPUT_CONTINUOUS; + } else { + vfe_buf_add_pending(output, new_buf); + dev_err_ratelimited(vfe->camss->dev, + "Inactive buffer is busy\n"); + } + break; + + case VFE_OUTPUT_IDLE: + if (!output->buf[0]) { + output->buf[0] = new_buf; + + vfe_output_init_addrs(vfe, output, 1, line); + vfe_output_frame_drop(vfe, output, 1); + + output->state = VFE_OUTPUT_SINGLE; + } else { + vfe_buf_add_pending(output, new_buf); + dev_err_ratelimited(vfe->camss->dev, + "Output idle with buffer set!\n"); + } + break; + + case VFE_OUTPUT_CONTINUOUS: + default: + vfe_buf_add_pending(output, new_buf); + break; + } +} + +/* + * vfe_isr_halt_ack - Process halt ack + * @vfe: VFE Device + */ +static void vfe_isr_halt_ack(struct vfe_device *vfe) +{ + complete(&vfe->halt_complete); + vfe->ops_gen1->halt_clear(vfe); +} + +/* + * vfe_isr_sof - Process start of frame interrupt + * @vfe: VFE Device + * @line_id: VFE line + */ +static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + struct vfe_output *output; + unsigned long flags; + + spin_lock_irqsave(&vfe->output_lock, flags); + output = &vfe->line[line_id].output; + if (output->gen1.wait_sof) { + output->gen1.wait_sof = 0; + complete(&output->sof); + } + spin_unlock_irqrestore(&vfe->output_lock, flags); +} + +/* + * vfe_isr_reg_update - Process reg update interrupt + * @vfe: VFE Device + * @line_id: VFE line + */ +static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) +{ + struct vfe_output *output; + struct vfe_line *line = &vfe->line[line_id]; + unsigned long flags; + + spin_lock_irqsave(&vfe->output_lock, flags); + vfe->ops->reg_update_clear(vfe, line_id); + + output = &line->output; + + if (output->wait_reg_update) { + output->wait_reg_update = 0; + complete(&output->reg_update); + spin_unlock_irqrestore(&vfe->output_lock, flags); + return; + } + + if (output->state == VFE_OUTPUT_STOPPING) { + /* Release last buffer when hw is idle */ + if (output->last_buffer) { + vb2_buffer_done(&output->last_buffer->vb.vb2_buf, + VB2_BUF_STATE_DONE); + output->last_buffer = NULL; + } + output->state = VFE_OUTPUT_IDLE; + + /* Buffers received in stopping state are queued in */ + /* dma pending queue, start next capture here */ + + output->buf[0] = vfe_buf_get_pending(output); + output->buf[1] = vfe_buf_get_pending(output); + + if (!output->buf[0] && output->buf[1]) { + output->buf[0] = output->buf[1]; + output->buf[1] = NULL; + } + + if (output->buf[0]) + output->state = VFE_OUTPUT_SINGLE; + + if (output->buf[1]) + output->state = VFE_OUTPUT_CONTINUOUS; + + switch (output->state) { + case VFE_OUTPUT_SINGLE: + vfe_output_frame_drop(vfe, output, 2); + break; + case VFE_OUTPUT_CONTINUOUS: + vfe_output_frame_drop(vfe, output, 3); + break; + default: + vfe_output_frame_drop(vfe, output, 0); + break; + } + + vfe_output_init_addrs(vfe, output, 1, &vfe->line[line_id]); + } + + spin_unlock_irqrestore(&vfe->output_lock, flags); +} + +/* + * vfe_isr_wm_done - Process write master done interrupt + * @vfe: VFE Device + * @wm: Write master id + */ +static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm) +{ + struct camss_buffer *ready_buf; + struct vfe_output *output; + dma_addr_t *new_addr; + unsigned long flags; + u32 active_index; + u64 ts = ktime_get_ns(); + unsigned int i; + + active_index = vfe->ops_gen1->wm_get_ping_pong_status(vfe, wm); + + spin_lock_irqsave(&vfe->output_lock, flags); + + if (vfe->wm_output_map[wm] == VFE_LINE_NONE) { + dev_err_ratelimited(vfe->camss->dev, + "Received wm done for unmapped index\n"); + goto out_unlock; + } + output = &vfe->line[vfe->wm_output_map[wm]].output; + + if (output->gen1.active_buf == active_index && 0) { + dev_err_ratelimited(vfe->camss->dev, + "Active buffer mismatch!\n"); + goto out_unlock; + } + output->gen1.active_buf = active_index; + + ready_buf = output->buf[!active_index]; + if (!ready_buf) { + dev_err_ratelimited(vfe->camss->dev, + "Missing ready buf %d %d!\n", + !active_index, output->state); + goto out_unlock; + } + + ready_buf->vb.vb2_buf.timestamp = ts; + ready_buf->vb.sequence = output->sequence++; + + /* Get next buffer */ + output->buf[!active_index] = vfe_buf_get_pending(output); + if (!output->buf[!active_index]) { + /* No next buffer - set same address */ + new_addr = ready_buf->addr; + vfe_buf_update_wm_on_last(vfe, output); + } else { + new_addr = output->buf[!active_index]->addr; + vfe_buf_update_wm_on_next(vfe, output); + } + + if (active_index) + for (i = 0; i < output->wm_num; i++) + vfe->ops_gen1->wm_set_ping_addr(vfe, output->wm_idx[i], new_addr[i]); + else + for (i = 0; i < output->wm_num; i++) + vfe->ops_gen1->wm_set_pong_addr(vfe, output->wm_idx[i], new_addr[i]); + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + if (output->state == VFE_OUTPUT_STOPPING) + output->last_buffer = ready_buf; + else + vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + + return; + +out_unlock: + spin_unlock_irqrestore(&vfe->output_lock, flags); +} + +/* + * vfe_queue_buffer - Add empty buffer + * @vid: Video device structure + * @buf: Buffer to be enqueued + * + * Add an empty buffer - depending on the current number of buffers it will be + * put in pending buffer queue or directly given to the hardware to be filled. + * + * Return 0 on success or a negative error code otherwise + */ +static int vfe_queue_buffer(struct camss_video *vid, struct camss_buffer *buf) +{ + struct vfe_line *line = container_of(vid, struct vfe_line, video_out); + struct vfe_device *vfe = to_vfe(line); + struct vfe_output *output; + unsigned long flags; + + output = &line->output; + + spin_lock_irqsave(&vfe->output_lock, flags); + + vfe_buf_update_wm_on_new(vfe, output, buf, line); + + spin_unlock_irqrestore(&vfe->output_lock, flags); + + return 0; +} + +#define CALC_WORD(width, M, N) (((width) * (M) + (N) - 1) / (N)) + +int vfe_word_per_line(u32 format, u32 width) +{ + int val = 0; + + switch (format) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + val = CALC_WORD(width, 1, 8); + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_VYUY: + val = CALC_WORD(width, 2, 8); + break; + } + + return val; +} + +const struct vfe_isr_ops vfe_isr_ops_gen1 = { + .reset_ack = vfe_isr_reset_ack, + .halt_ack = vfe_isr_halt_ack, + .reg_update = vfe_isr_reg_update, + .sof = vfe_isr_sof, + .comp_done = vfe_isr_comp_done, + .wm_done = vfe_isr_wm_done, +}; + +const struct camss_video_ops vfe_video_ops_gen1 = { + .queue_buffer = vfe_queue_buffer, + .flush_buffers = vfe_flush_buffers, +}; diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.h b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h new file mode 100644 index 000000000000..6d5f9656562c --- /dev/null +++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * camss-vfe.h + * + * Qualcomm MSM Camera Subsystem - VFE (Video Front End) Module + * + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015-2018 Linaro Ltd. + */ +#ifndef QC_MSM_CAMSS_VFE_GEN1_H +#define QC_MSM_CAMSS_VFE_GEN1_H + +#include "camss-vfe.h" + +enum vfe_line_id; +struct vfe_device; +struct vfe_line; +struct vfe_output; + +struct vfe_hw_ops_gen1 { + void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id); + void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm, enum vfe_line_id id); + void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable); + void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm); + int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev); + void (*enable_irq_common)(struct vfe_device *vfe); + void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm, enum vfe_line_id line_id, + u8 enable); + void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp, enum vfe_line_id line_id, + u8 enable); + u16 (*get_ub_size)(u8 vfe_id); + void (*halt_clear)(struct vfe_device *vfe); + void (*halt_request)(struct vfe_device *vfe); + void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line); + void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable); + void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable); + void (*set_clamp_cfg)(struct vfe_device *vfe); + void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line); + void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line); + void (*set_ds)(struct vfe_device *vfe); + void (*set_module_cfg)(struct vfe_device *vfe, u8 enable); + void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line); + void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id, u8 cid); + void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line, u8 enable); + void (*set_qos)(struct vfe_device *vfe); + void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output, u8 enable); + void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable); + void (*wm_line_based)(struct vfe_device *vfe, u32 wm, struct v4l2_pix_format_mplane *pix, + u8 plane, u32 enable); + void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset, u16 depth); + void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm); + void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per); + void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm, u32 pattern); + void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr); + void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr); + int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm); + void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable); +}; + +/* + * vfe_calc_interp_reso - Calculate interpolation mode + * @input: Input resolution + * @output: Output resolution + * + * Return interpolation mode + */ +static inline u8 vfe_calc_interp_reso(u16 input, u16 output) +{ + if (input / output >= 16) + return 0; + + if (input / output >= 8) + return 1; + + if (input / output >= 4) + return 2; + + return 3; +} + +/* + * vfe_gen1_disable - Disable streaming on VFE line + * @line: VFE line + * + * Return 0 on success or a negative error code otherwise + */ +int vfe_gen1_disable(struct vfe_line *line); + +/* + * vfe_gen1_enable - Enable VFE module + * @line: VFE line + * + * Return 0 on success + */ +int vfe_gen1_enable(struct vfe_line *line); + +/* + * vfe_gen1_enable - Halt VFE module + * @vfe: VFE device + * + * Return 0 on success + */ +int vfe_gen1_halt(struct vfe_device *vfe); + +/* + * vfe_word_per_line - Calculate number of words per frame width + * @format: V4L2 format + * @width: Frame width + * + * Return number of words per frame width + */ +int vfe_word_per_line(u32 format, u32 width); + +extern const struct vfe_isr_ops vfe_isr_ops_gen1; +extern const struct camss_video_ops vfe_video_ops_gen1; + +#endif /* QC_MSM_CAMSS_VFE_GEN1_H */ diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c index fae2b513b2f9..15695fd466c4 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.c +++ b/drivers/media/platform/qcom/camss/camss-vfe.c @@ -26,22 +26,8 @@ #define MSM_VFE_NAME "msm_vfe" -#define vfe_line_array(ptr_line) \ - ((const struct vfe_line (*)[]) &(ptr_line[-(ptr_line->id)])) - -#define to_vfe(ptr_line) \ - container_of(vfe_line_array(ptr_line), struct vfe_device, line) - /* VFE reset timeout */ #define VFE_RESET_TIMEOUT_MS 50 -/* VFE halt timeout */ -#define VFE_HALT_TIMEOUT_MS 100 -/* Max number of frame drop updates per frame */ -#define VFE_FRAME_DROP_UPDATES 2 -/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */ -#define VFE_FRAME_DROP_VAL 30 - -#define VFE_NEXT_SOF_MS 500 #define SCALER_RATIO_MAX 16 @@ -110,6 +96,32 @@ static const struct vfe_format formats_pix_8x96[] = { { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, }; +static const struct vfe_format formats_rdi_845[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, 8 }, + { MEDIA_BUS_FMT_VYUY8_2X8, 8 }, + { MEDIA_BUS_FMT_YUYV8_2X8, 8 }, + { MEDIA_BUS_FMT_YVYU8_2X8, 8 }, + { MEDIA_BUS_FMT_SBGGR8_1X8, 8 }, + { MEDIA_BUS_FMT_SGBRG8_1X8, 8 }, + { MEDIA_BUS_FMT_SGRBG8_1X8, 8 }, + { MEDIA_BUS_FMT_SRGGB8_1X8, 8 }, + { MEDIA_BUS_FMT_SBGGR10_1X10, 10 }, + { MEDIA_BUS_FMT_SGBRG10_1X10, 10 }, + { MEDIA_BUS_FMT_SGRBG10_1X10, 10 }, + { MEDIA_BUS_FMT_SRGGB10_1X10, 10 }, + { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 }, + { MEDIA_BUS_FMT_SBGGR12_1X12, 12 }, + { MEDIA_BUS_FMT_SGBRG12_1X12, 12 }, + { MEDIA_BUS_FMT_SGRBG12_1X12, 12 }, + { MEDIA_BUS_FMT_SRGGB12_1X12, 12 }, + { MEDIA_BUS_FMT_SBGGR14_1X14, 14 }, + { MEDIA_BUS_FMT_SGBRG14_1X14, 14 }, + { MEDIA_BUS_FMT_SGRBG14_1X14, 14 }, + { MEDIA_BUS_FMT_SRGGB14_1X14, 14 }, + { MEDIA_BUS_FMT_Y10_1X10, 10 }, + { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 }, +}; + /* * vfe_get_bpp - map media bus format to bits per pixel * @formats: supported media bus formats array @@ -206,7 +218,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, return sink_code; } else if (vfe->camss->version == CAMSS_8x96 || - vfe->camss->version == CAMSS_660) + vfe->camss->version == CAMSS_660 || + vfe->camss->version == CAMSS_845) switch (sink_code) { case MEDIA_BUS_FMT_YUYV8_2X8: { @@ -270,13 +283,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code, return 0; } -/* - * vfe_reset - Trigger reset on VFE module and wait to complete - * @vfe: VFE device - * - * Return 0 on success or a negative error code otherwise - */ -static int vfe_reset(struct vfe_device *vfe) +int vfe_reset(struct vfe_device *vfe) { unsigned long time; @@ -294,35 +301,11 @@ static int vfe_reset(struct vfe_device *vfe) return 0; } -/* - * vfe_halt - Trigger halt on VFE module and wait to complete - * @vfe: VFE device - * - * Return 0 on success or a negative error code otherwise - */ -static int vfe_halt(struct vfe_device *vfe) -{ - unsigned long time; - - reinit_completion(&vfe->halt_complete); - - vfe->ops->halt_request(vfe); - - time = wait_for_completion_timeout(&vfe->halt_complete, - msecs_to_jiffies(VFE_HALT_TIMEOUT_MS)); - if (!time) { - dev_err(vfe->camss->dev, "VFE halt timeout\n"); - return -EIO; - } - - return 0; -} - static void vfe_init_outputs(struct vfe_device *vfe) { int i; - for (i = 0; i < ARRAY_SIZE(vfe->line); i++) { + for (i = 0; i < vfe->line_num; i++) { struct vfe_output *output = &vfe->line[i].output; output->state = VFE_OUTPUT_OFF; @@ -340,71 +323,7 @@ static void vfe_reset_output_maps(struct vfe_device *vfe) vfe->wm_output_map[i] = VFE_LINE_NONE; } -static void vfe_output_init_addrs(struct vfe_device *vfe, - struct vfe_output *output, u8 sync) -{ - u32 ping_addr; - u32 pong_addr; - unsigned int i; - - output->active_buf = 0; - - for (i = 0; i < output->wm_num; i++) { - if (output->buf[0]) - ping_addr = output->buf[0]->addr[i]; - else - ping_addr = 0; - - if (output->buf[1]) - pong_addr = output->buf[1]->addr[i]; - else - pong_addr = ping_addr; - - vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], ping_addr); - vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], pong_addr); - if (sync) - vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]); - } -} - -static void vfe_output_update_ping_addr(struct vfe_device *vfe, - struct vfe_output *output, u8 sync) -{ - u32 addr; - unsigned int i; - - for (i = 0; i < output->wm_num; i++) { - if (output->buf[0]) - addr = output->buf[0]->addr[i]; - else - addr = 0; - - vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], addr); - if (sync) - vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]); - } -} - -static void vfe_output_update_pong_addr(struct vfe_device *vfe, - struct vfe_output *output, u8 sync) -{ - u32 addr; - unsigned int i; - - for (i = 0; i < output->wm_num; i++) { - if (output->buf[1]) - addr = output->buf[1]->addr[i]; - else - addr = 0; - - vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], addr); - if (sync) - vfe->ops->bus_reload_wm(vfe, output->wm_idx[i]); - } - -} - -static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id) +int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id) { int ret = -EBUSY; int i; @@ -420,7 +339,7 @@ static int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id) return ret; } -static int vfe_release_wm(struct vfe_device *vfe, u8 wm) +int vfe_release_wm(struct vfe_device *vfe, u8 wm) { if (wm >= ARRAY_SIZE(vfe->wm_output_map)) return -EINVAL; @@ -430,29 +349,7 @@ static int vfe_release_wm(struct vfe_device *vfe, u8 wm) return 0; } -static void vfe_output_frame_drop(struct vfe_device *vfe, - struct vfe_output *output, - u32 drop_pattern) -{ - u8 drop_period; - unsigned int i; - - /* We need to toggle update period to be valid on next frame */ - output->drop_update_idx++; - output->drop_update_idx %= VFE_FRAME_DROP_UPDATES; - drop_period = VFE_FRAME_DROP_VAL + output->drop_update_idx; - - for (i = 0; i < output->wm_num; i++) { - vfe->ops->wm_set_framedrop_period(vfe, output->wm_idx[i], - drop_period); - vfe->ops->wm_set_framedrop_pattern(vfe, output->wm_idx[i], - drop_pattern); - } - vfe->ops->reg_update(vfe, - container_of(output, struct vfe_line, output)->id); -} - -static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output) +struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output) { struct camss_buffer *buffer = NULL; @@ -466,13 +363,8 @@ static struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output) return buffer; } -/* - * vfe_buf_add_pending - Add output buffer to list of pending - * @output: VFE output - * @buffer: Video buffer - */ -static void vfe_buf_add_pending(struct vfe_output *output, - struct camss_buffer *buffer) +void vfe_buf_add_pending(struct vfe_output *output, + struct camss_buffer *buffer) { INIT_LIST_HEAD(&buffer->queue); list_add_tail(&buffer->queue, &output->pending_bufs); @@ -495,149 +387,7 @@ static void vfe_buf_flush_pending(struct vfe_output *output, } } -static void vfe_buf_update_wm_on_next(struct vfe_device *vfe, - struct vfe_output *output) -{ - switch (output->state) { - case VFE_OUTPUT_CONTINUOUS: - vfe_output_frame_drop(vfe, output, 3); - break; - case VFE_OUTPUT_SINGLE: - default: - dev_err_ratelimited(vfe->camss->dev, - "Next buf in wrong state! %d\n", - output->state); - break; - } -} - -static void vfe_buf_update_wm_on_last(struct vfe_device *vfe, - struct vfe_output *output) -{ - switch (output->state) { - case VFE_OUTPUT_CONTINUOUS: - output->state = VFE_OUTPUT_SINGLE; - vfe_output_frame_drop(vfe, output, 1); - break; - case VFE_OUTPUT_SINGLE: - output->state = VFE_OUTPUT_STOPPING; - vfe_output_frame_drop(vfe, output, 0); - break; - default: - dev_err_ratelimited(vfe->camss->dev, - "Last buff in wrong state! %d\n", - output->state); - break; - } -} - -static void vfe_buf_update_wm_on_new(struct vfe_device *vfe, - struct vfe_output *output, - struct camss_buffer *new_buf) -{ - int inactive_idx; - - switch (output->state) { - case VFE_OUTPUT_SINGLE: - inactive_idx = !output->active_buf; - - if (!output->buf[inactive_idx]) { - output->buf[inactive_idx] = new_buf; - - if (inactive_idx) - vfe_output_update_pong_addr(vfe, output, 0); - else - vfe_output_update_ping_addr(vfe, output, 0); - - vfe_output_frame_drop(vfe, output, 3); - output->state = VFE_OUTPUT_CONTINUOUS; - } else { - vfe_buf_add_pending(output, new_buf); - dev_err_ratelimited(vfe->camss->dev, - "Inactive buffer is busy\n"); - } - break; - - case VFE_OUTPUT_IDLE: - if (!output->buf[0]) { - output->buf[0] = new_buf; - - vfe_output_init_addrs(vfe, output, 1); - - vfe_output_frame_drop(vfe, output, 1); - output->state = VFE_OUTPUT_SINGLE; - } else { - vfe_buf_add_pending(output, new_buf); - dev_err_ratelimited(vfe->camss->dev, - "Output idle with buffer set!\n"); - } - break; - - case VFE_OUTPUT_CONTINUOUS: - default: - vfe_buf_add_pending(output, new_buf); - break; - } -} - -static int vfe_get_output(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - struct vfe_output *output; - struct v4l2_format *f = &line->video_out.active_fmt; - unsigned long flags; - int i; - int wm_idx; - - spin_lock_irqsave(&vfe->output_lock, flags); - - output = &line->output; - if (output->state != VFE_OUTPUT_OFF) { - dev_err(vfe->camss->dev, "Output is running\n"); - goto error; - } - output->state = VFE_OUTPUT_RESERVED; - - output->active_buf = 0; - - switch (f->fmt.pix_mp.pixelformat) { - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - output->wm_num = 2; - break; - default: - output->wm_num = 1; - break; - } - - for (i = 0; i < output->wm_num; i++) { - wm_idx = vfe_reserve_wm(vfe, line->id); - if (wm_idx < 0) { - dev_err(vfe->camss->dev, "Can not reserve wm\n"); - goto error_get_wm; - } - output->wm_idx[i] = wm_idx; - } - - output->drop_update_idx = 0; - - spin_unlock_irqrestore(&vfe->output_lock, flags); - - return 0; - -error_get_wm: - for (i--; i >= 0; i--) - vfe_release_wm(vfe, output->wm_idx[i]); - output->state = VFE_OUTPUT_OFF; -error: - spin_unlock_irqrestore(&vfe->output_lock, flags); - - return -EINVAL; -} - -static int vfe_put_output(struct vfe_line *line) +int vfe_put_output(struct vfe_line *line) { struct vfe_device *vfe = to_vfe(line); struct vfe_output *output = &line->output; @@ -655,454 +405,27 @@ static int vfe_put_output(struct vfe_line *line) return 0; } -static int vfe_enable_output(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - struct vfe_output *output = &line->output; - const struct vfe_hw_ops *ops = vfe->ops; - struct media_entity *sensor; - unsigned long flags; - unsigned int frame_skip = 0; - unsigned int i; - u16 ub_size; - - ub_size = ops->get_ub_size(vfe->id); - if (!ub_size) - return -EINVAL; - - sensor = camss_find_sensor(&line->subdev.entity); - if (sensor) { - struct v4l2_subdev *subdev = - media_entity_to_v4l2_subdev(sensor); - - v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip); - /* Max frame skip is 29 frames */ - if (frame_skip > VFE_FRAME_DROP_VAL - 1) - frame_skip = VFE_FRAME_DROP_VAL - 1; - } - - spin_lock_irqsave(&vfe->output_lock, flags); - - ops->reg_update_clear(vfe, line->id); - - if (output->state != VFE_OUTPUT_RESERVED) { - dev_err(vfe->camss->dev, "Output is not in reserved state %d\n", - output->state); - spin_unlock_irqrestore(&vfe->output_lock, flags); - return -EINVAL; - } - output->state = VFE_OUTPUT_IDLE; - - output->buf[0] = vfe_buf_get_pending(output); - output->buf[1] = vfe_buf_get_pending(output); - - if (!output->buf[0] && output->buf[1]) { - output->buf[0] = output->buf[1]; - output->buf[1] = NULL; - } - - if (output->buf[0]) - output->state = VFE_OUTPUT_SINGLE; - - if (output->buf[1]) - output->state = VFE_OUTPUT_CONTINUOUS; - - switch (output->state) { - case VFE_OUTPUT_SINGLE: - vfe_output_frame_drop(vfe, output, 1 << frame_skip); - break; - case VFE_OUTPUT_CONTINUOUS: - vfe_output_frame_drop(vfe, output, 3 << frame_skip); - break; - default: - vfe_output_frame_drop(vfe, output, 0); - break; - } - - output->sequence = 0; - output->wait_sof = 0; - output->wait_reg_update = 0; - reinit_completion(&output->sof); - reinit_completion(&output->reg_update); - - vfe_output_init_addrs(vfe, output, 0); - - if (line->id != VFE_LINE_PIX) { - ops->set_cgc_override(vfe, output->wm_idx[0], 1); - ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 1); - ops->bus_connect_wm_to_rdi(vfe, output->wm_idx[0], line->id); - ops->wm_set_subsample(vfe, output->wm_idx[0]); - ops->set_rdi_cid(vfe, line->id, 0); - ops->wm_set_ub_cfg(vfe, output->wm_idx[0], - (ub_size + 1) * output->wm_idx[0], ub_size); - ops->wm_frame_based(vfe, output->wm_idx[0], 1); - ops->wm_enable(vfe, output->wm_idx[0], 1); - ops->bus_reload_wm(vfe, output->wm_idx[0]); - } else { - ub_size /= output->wm_num; - for (i = 0; i < output->wm_num; i++) { - ops->set_cgc_override(vfe, output->wm_idx[i], 1); - ops->wm_set_subsample(vfe, output->wm_idx[i]); - ops->wm_set_ub_cfg(vfe, output->wm_idx[i], - (ub_size + 1) * output->wm_idx[i], - ub_size); - ops->wm_line_based(vfe, output->wm_idx[i], - &line->video_out.active_fmt.fmt.pix_mp, - i, 1); - ops->wm_enable(vfe, output->wm_idx[i], 1); - ops->bus_reload_wm(vfe, output->wm_idx[i]); - } - ops->enable_irq_pix_line(vfe, 0, line->id, 1); - ops->set_module_cfg(vfe, 1); - ops->set_camif_cfg(vfe, line); - ops->set_realign_cfg(vfe, line, 1); - ops->set_xbar_cfg(vfe, output, 1); - ops->set_demux_cfg(vfe, line); - ops->set_scale_cfg(vfe, line); - ops->set_crop_cfg(vfe, line); - ops->set_clamp_cfg(vfe); - ops->set_camif_cmd(vfe, 1); - } - - ops->reg_update(vfe, line->id); - - spin_unlock_irqrestore(&vfe->output_lock, flags); - - return 0; -} - -static int vfe_disable_output(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - struct vfe_output *output = &line->output; - const struct vfe_hw_ops *ops = vfe->ops; - unsigned long flags; - unsigned long time; - unsigned int i; - - spin_lock_irqsave(&vfe->output_lock, flags); - - output->wait_sof = 1; - spin_unlock_irqrestore(&vfe->output_lock, flags); - - time = wait_for_completion_timeout(&output->sof, - msecs_to_jiffies(VFE_NEXT_SOF_MS)); - if (!time) - dev_err(vfe->camss->dev, "VFE sof timeout\n"); - - spin_lock_irqsave(&vfe->output_lock, flags); - for (i = 0; i < output->wm_num; i++) - ops->wm_enable(vfe, output->wm_idx[i], 0); - - ops->reg_update(vfe, line->id); - output->wait_reg_update = 1; - spin_unlock_irqrestore(&vfe->output_lock, flags); - - time = wait_for_completion_timeout(&output->reg_update, - msecs_to_jiffies(VFE_NEXT_SOF_MS)); - if (!time) - dev_err(vfe->camss->dev, "VFE reg update timeout\n"); - - spin_lock_irqsave(&vfe->output_lock, flags); - - if (line->id != VFE_LINE_PIX) { - ops->wm_frame_based(vfe, output->wm_idx[0], 0); - ops->bus_disconnect_wm_from_rdi(vfe, output->wm_idx[0], - line->id); - ops->enable_irq_wm_line(vfe, output->wm_idx[0], line->id, 0); - ops->set_cgc_override(vfe, output->wm_idx[0], 0); - spin_unlock_irqrestore(&vfe->output_lock, flags); - } else { - for (i = 0; i < output->wm_num; i++) { - ops->wm_line_based(vfe, output->wm_idx[i], NULL, i, 0); - ops->set_cgc_override(vfe, output->wm_idx[i], 0); - } - - ops->enable_irq_pix_line(vfe, 0, line->id, 0); - ops->set_module_cfg(vfe, 0); - ops->set_realign_cfg(vfe, line, 0); - ops->set_xbar_cfg(vfe, output, 0); - - ops->set_camif_cmd(vfe, 0); - spin_unlock_irqrestore(&vfe->output_lock, flags); - - ops->camif_wait_for_stop(vfe, vfe->camss->dev); - } - - return 0; -} - -/* - * vfe_enable - Enable streaming on VFE line - * @line: VFE line - * - * Return 0 on success or a negative error code otherwise - */ -static int vfe_enable(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - int ret; - - mutex_lock(&vfe->stream_lock); - - if (!vfe->stream_count) { - vfe->ops->enable_irq_common(vfe); - - vfe->ops->bus_enable_wr_if(vfe, 1); - - vfe->ops->set_qos(vfe); - - vfe->ops->set_ds(vfe); - } - - vfe->stream_count++; - - mutex_unlock(&vfe->stream_lock); - - ret = vfe_get_output(line); - if (ret < 0) - goto error_get_output; - - ret = vfe_enable_output(line); - if (ret < 0) - goto error_enable_output; - - vfe->was_streaming = 1; - - return 0; - - -error_enable_output: - vfe_put_output(line); - -error_get_output: - mutex_lock(&vfe->stream_lock); - - if (vfe->stream_count == 1) - vfe->ops->bus_enable_wr_if(vfe, 0); - - vfe->stream_count--; - - mutex_unlock(&vfe->stream_lock); - - return ret; -} - -/* - * vfe_disable - Disable streaming on VFE line - * @line: VFE line - * - * Return 0 on success or a negative error code otherwise - */ -static int vfe_disable(struct vfe_line *line) -{ - struct vfe_device *vfe = to_vfe(line); - - vfe_disable_output(line); - - vfe_put_output(line); - - mutex_lock(&vfe->stream_lock); - - if (vfe->stream_count == 1) - vfe->ops->bus_enable_wr_if(vfe, 0); - - vfe->stream_count--; - - mutex_unlock(&vfe->stream_lock); - - return 0; -} - -/* - * vfe_isr_sof - Process start of frame interrupt - * @vfe: VFE Device - * @line_id: VFE line - */ -static void vfe_isr_sof(struct vfe_device *vfe, enum vfe_line_id line_id) -{ - struct vfe_output *output; - unsigned long flags; - - spin_lock_irqsave(&vfe->output_lock, flags); - output = &vfe->line[line_id].output; - if (output->wait_sof) { - output->wait_sof = 0; - complete(&output->sof); - } - spin_unlock_irqrestore(&vfe->output_lock, flags); -} - -/* - * vfe_isr_reg_update - Process reg update interrupt - * @vfe: VFE Device - * @line_id: VFE line - */ -static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) -{ - struct vfe_output *output; - unsigned long flags; - - spin_lock_irqsave(&vfe->output_lock, flags); - vfe->ops->reg_update_clear(vfe, line_id); - - output = &vfe->line[line_id].output; - - if (output->wait_reg_update) { - output->wait_reg_update = 0; - complete(&output->reg_update); - spin_unlock_irqrestore(&vfe->output_lock, flags); - return; - } - - if (output->state == VFE_OUTPUT_STOPPING) { - /* Release last buffer when hw is idle */ - if (output->last_buffer) { - vb2_buffer_done(&output->last_buffer->vb.vb2_buf, - VB2_BUF_STATE_DONE); - output->last_buffer = NULL; - } - output->state = VFE_OUTPUT_IDLE; - - /* Buffers received in stopping state are queued in */ - /* dma pending queue, start next capture here */ - - output->buf[0] = vfe_buf_get_pending(output); - output->buf[1] = vfe_buf_get_pending(output); - - if (!output->buf[0] && output->buf[1]) { - output->buf[0] = output->buf[1]; - output->buf[1] = NULL; - } - - if (output->buf[0]) - output->state = VFE_OUTPUT_SINGLE; - - if (output->buf[1]) - output->state = VFE_OUTPUT_CONTINUOUS; - - switch (output->state) { - case VFE_OUTPUT_SINGLE: - vfe_output_frame_drop(vfe, output, 2); - break; - case VFE_OUTPUT_CONTINUOUS: - vfe_output_frame_drop(vfe, output, 3); - break; - default: - vfe_output_frame_drop(vfe, output, 0); - break; - } - - vfe_output_init_addrs(vfe, output, 1); - } - - spin_unlock_irqrestore(&vfe->output_lock, flags); -} - -/* - * vfe_isr_wm_done - Process write master done interrupt - * @vfe: VFE Device - * @wm: Write master id - */ -static void vfe_isr_wm_done(struct vfe_device *vfe, u8 wm) -{ - struct camss_buffer *ready_buf; - struct vfe_output *output; - dma_addr_t *new_addr; - unsigned long flags; - u32 active_index; - u64 ts = ktime_get_ns(); - unsigned int i; - - active_index = vfe->ops->wm_get_ping_pong_status(vfe, wm); - - spin_lock_irqsave(&vfe->output_lock, flags); - - if (vfe->wm_output_map[wm] == VFE_LINE_NONE) { - dev_err_ratelimited(vfe->camss->dev, - "Received wm done for unmapped index\n"); - goto out_unlock; - } - output = &vfe->line[vfe->wm_output_map[wm]].output; - - if (output->active_buf == active_index) { - dev_err_ratelimited(vfe->camss->dev, - "Active buffer mismatch!\n"); - goto out_unlock; - } - output->active_buf = active_index; - - ready_buf = output->buf[!active_index]; - if (!ready_buf) { - dev_err_ratelimited(vfe->camss->dev, - "Missing ready buf %d %d!\n", - !active_index, output->state); - goto out_unlock; - } - - ready_buf->vb.vb2_buf.timestamp = ts; - ready_buf->vb.sequence = output->sequence++; - - /* Get next buffer */ - output->buf[!active_index] = vfe_buf_get_pending(output); - if (!output->buf[!active_index]) { - /* No next buffer - set same address */ - new_addr = ready_buf->addr; - vfe_buf_update_wm_on_last(vfe, output); - } else { - new_addr = output->buf[!active_index]->addr; - vfe_buf_update_wm_on_next(vfe, output); - } - - if (active_index) - for (i = 0; i < output->wm_num; i++) - vfe->ops->wm_set_ping_addr(vfe, output->wm_idx[i], - new_addr[i]); - else - for (i = 0; i < output->wm_num; i++) - vfe->ops->wm_set_pong_addr(vfe, output->wm_idx[i], - new_addr[i]); - - spin_unlock_irqrestore(&vfe->output_lock, flags); - - if (output->state == VFE_OUTPUT_STOPPING) - output->last_buffer = ready_buf; - else - vb2_buffer_done(&ready_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - - return; - -out_unlock: - spin_unlock_irqrestore(&vfe->output_lock, flags); -} - -/* - * vfe_isr_wm_done - Process composite image done interrupt +/** + * vfe_isr_comp_done() - Process composite image done interrupt * @vfe: VFE Device * @comp: Composite image id */ -static void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp) +void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp) { unsigned int i; for (i = 0; i < ARRAY_SIZE(vfe->wm_output_map); i++) if (vfe->wm_output_map[i] == VFE_LINE_PIX) { - vfe_isr_wm_done(vfe, i); + vfe->isr_ops.wm_done(vfe, i); break; } } -static inline void vfe_isr_reset_ack(struct vfe_device *vfe) +void vfe_isr_reset_ack(struct vfe_device *vfe) { complete(&vfe->reset_complete); } -static inline void vfe_isr_halt_ack(struct vfe_device *vfe) -{ - complete(&vfe->halt_complete); - vfe->ops->halt_clear(vfe); -} - /* * vfe_set_clock_rates - Calculate and set clock rates on VFE module * @vfe: VFE device @@ -1112,11 +435,11 @@ static inline void vfe_isr_halt_ack(struct vfe_device *vfe) static int vfe_set_clock_rates(struct vfe_device *vfe) { struct device *dev = vfe->camss->dev; - u32 pixel_clock[MSM_VFE_LINE_NUM]; + u64 pixel_clock[VFE_LINE_NUM_MAX]; int i, j; int ret; - for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) { + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) { ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity, &pixel_clock[i]); if (ret) @@ -1127,11 +450,12 @@ static int vfe_set_clock_rates(struct vfe_device *vfe) struct camss_clock *clock = &vfe->clock[i]; if (!strcmp(clock->name, "vfe0") || - !strcmp(clock->name, "vfe1")) { + !strcmp(clock->name, "vfe1") || + !strcmp(clock->name, "vfe_lite")) { u64 min_rate = 0; long rate; - for (j = VFE_LINE_RDI0; j <= VFE_LINE_PIX; j++) { + for (j = VFE_LINE_RDI0; j < vfe->line_num; j++) { u32 tmp; u8 bpp; @@ -1194,11 +518,11 @@ static int vfe_set_clock_rates(struct vfe_device *vfe) */ static int vfe_check_clock_rates(struct vfe_device *vfe) { - u32 pixel_clock[MSM_VFE_LINE_NUM]; + u64 pixel_clock[VFE_LINE_NUM_MAX]; int i, j; int ret; - for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) { + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) { ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity, &pixel_clock[i]); if (ret) @@ -1213,7 +537,7 @@ static int vfe_check_clock_rates(struct vfe_device *vfe) u64 min_rate = 0; unsigned long rate; - for (j = VFE_LINE_RDI0; j <= VFE_LINE_PIX; j++) { + for (j = VFE_LINE_RDI0; j < vfe->line_num; j++) { u32 tmp; u8 bpp; @@ -1256,7 +580,7 @@ static int vfe_get(struct vfe_device *vfe) mutex_lock(&vfe->power_lock); if (vfe->power_count == 0) { - ret = camss_pm_domain_on(vfe->camss, vfe->id); + ret = vfe->ops->pm_domain_on(vfe); if (ret < 0) goto error_pm_domain; @@ -1296,7 +620,7 @@ error_reset: error_pm_runtime_get: pm_runtime_put_sync(vfe->camss->dev); - camss_pm_domain_off(vfe->camss, vfe->id); + vfe->ops->pm_domain_off(vfe); error_pm_domain: mutex_unlock(&vfe->power_lock); @@ -1318,11 +642,11 @@ static void vfe_put(struct vfe_device *vfe) } else if (vfe->power_count == 1) { if (vfe->was_streaming) { vfe->was_streaming = 0; - vfe_halt(vfe); + vfe->ops->vfe_halt(vfe); } camss_disable_clocks(vfe->nclocks, vfe->clock); pm_runtime_put_sync(vfe->camss->dev); - camss_pm_domain_off(vfe->camss, vfe->id); + vfe->ops->pm_domain_off(vfe); } vfe->power_count--; @@ -1332,35 +656,6 @@ exit: } /* - * vfe_queue_buffer - Add empty buffer - * @vid: Video device structure - * @buf: Buffer to be enqueued - * - * Add an empty buffer - depending on the current number of buffers it will be - * put in pending buffer queue or directly given to the hardware to be filled. - * - * Return 0 on success or a negative error code otherwise - */ -static int vfe_queue_buffer(struct camss_video *vid, - struct camss_buffer *buf) -{ - struct vfe_line *line = container_of(vid, struct vfe_line, video_out); - struct vfe_device *vfe = to_vfe(line); - struct vfe_output *output; - unsigned long flags; - - output = &line->output; - - spin_lock_irqsave(&vfe->output_lock, flags); - - vfe_buf_update_wm_on_new(vfe, output, buf); - - spin_unlock_irqrestore(&vfe->output_lock, flags); - - return 0; -} - -/* * vfe_flush_buffers - Return all vb2 buffers * @vid: Video device structure * @state: vb2 buffer state of the returned buffers @@ -1370,8 +665,8 @@ static int vfe_queue_buffer(struct camss_video *vid, * * Return 0 on success or a negative error code otherwise */ -static int vfe_flush_buffers(struct camss_video *vid, - enum vb2_buffer_state state) +int vfe_flush_buffers(struct camss_video *vid, + enum vb2_buffer_state state) { struct vfe_line *line = container_of(vid, struct vfe_line, video_out); struct vfe_device *vfe = to_vfe(line); @@ -1442,12 +737,12 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable) int ret; if (enable) { - ret = vfe_enable(line); + ret = vfe->ops->vfe_enable(line); if (ret < 0) dev_err(vfe->camss->dev, "Failed to enable vfe outputs\n"); } else { - ret = vfe_disable(line); + ret = vfe->ops->vfe_disable(line); if (ret < 0) dev_err(vfe->camss->dev, "Failed to disable vfe outputs\n"); @@ -1985,13 +1280,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, int i, j; int ret; - vfe->isr_ops.reset_ack = vfe_isr_reset_ack; - vfe->isr_ops.halt_ack = vfe_isr_halt_ack; - vfe->isr_ops.reg_update = vfe_isr_reg_update; - vfe->isr_ops.sof = vfe_isr_sof; - vfe->isr_ops.comp_done = vfe_isr_comp_done; - vfe->isr_ops.wm_done = vfe_isr_wm_done; - switch (camss->version) { case CAMSS_8x16: vfe->ops = &vfe_ops_4_1; @@ -2002,9 +1290,14 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, case CAMSS_660: vfe->ops = &vfe_ops_4_8; break; + + case CAMSS_845: + vfe->ops = &vfe_ops_170; + break; default: return -EINVAL; } + vfe->ops->subdev_init(dev, vfe); /* Memory */ @@ -2086,7 +1379,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, vfe->id = id; vfe->reg_update = 0; - for (i = VFE_LINE_RDI0; i <= VFE_LINE_PIX; i++) { + for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) { struct vfe_line *l = &vfe->line[i]; l->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; @@ -2112,6 +1405,9 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe, l->formats = formats_rdi_8x96; l->nformats = ARRAY_SIZE(formats_rdi_8x96); } + } else if (camss->version == CAMSS_845) { + l->formats = formats_rdi_845; + l->nformats = ARRAY_SIZE(formats_rdi_845); } else { return -EINVAL; } @@ -2209,11 +1505,6 @@ static const struct media_entity_operations vfe_media_ops = { .link_validate = v4l2_subdev_link_validate, }; -static const struct camss_video_ops camss_vfe_video_ops = { - .queue_buffer = vfe_queue_buffer, - .flush_buffers = vfe_flush_buffers, -}; - /* * msm_vfe_register_entities - Register subdev node for VFE module * @vfe: VFE device @@ -2236,7 +1527,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe, int ret; int i; - for (i = 0; i < ARRAY_SIZE(vfe->line); i++) { + for (i = 0; i < vfe->line_num; i++) { char name[32]; sd = &vfe->line[i].subdev; @@ -2279,7 +1570,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe, goto error_reg_subdev; } - video_out->ops = &camss_vfe_video_ops; + video_out->ops = &vfe->video_ops; video_out->bpl_alignment = 8; video_out->line_based = 0; if (i == VFE_LINE_PIX) { @@ -2343,7 +1634,7 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe) mutex_destroy(&vfe->power_lock); mutex_destroy(&vfe->stream_lock); - for (i = 0; i < ARRAY_SIZE(vfe->line); i++) { + for (i = 0; i < vfe->line_num; i++) { struct v4l2_subdev *sd = &vfe->line[i].subdev; struct camss_video *video_out = &vfe->line[i].video_out; diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h index 5bce6736e4bb..844b9275031d 100644 --- a/drivers/media/platform/qcom/camss/camss-vfe.h +++ b/drivers/media/platform/qcom/camss/camss-vfe.h @@ -17,22 +17,34 @@ #include <media/v4l2-subdev.h> #include "camss-video.h" +#include "camss-vfe-gen1.h" #define MSM_VFE_PAD_SINK 0 #define MSM_VFE_PAD_SRC 1 #define MSM_VFE_PADS_NUM 2 -#define MSM_VFE_LINE_NUM 4 #define MSM_VFE_IMAGE_MASTERS_NUM 7 #define MSM_VFE_COMPOSITE_IRQ_NUM 4 +/* VFE halt timeout */ +#define VFE_HALT_TIMEOUT_MS 100 +/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */ +#define VFE_FRAME_DROP_VAL 30 + +#define vfe_line_array(ptr_line) \ + ((const struct vfe_line (*)[]) &(ptr_line)[-(ptr_line)->id]) + +#define to_vfe(ptr_line) \ + container_of(vfe_line_array(ptr_line), struct vfe_device, line) + enum vfe_output_state { VFE_OUTPUT_OFF, VFE_OUTPUT_RESERVED, VFE_OUTPUT_SINGLE, VFE_OUTPUT_CONTINUOUS, VFE_OUTPUT_IDLE, - VFE_OUTPUT_STOPPING + VFE_OUTPUT_STOPPING, + VFE_OUTPUT_ON, }; enum vfe_line_id { @@ -40,23 +52,34 @@ enum vfe_line_id { VFE_LINE_RDI0 = 0, VFE_LINE_RDI1 = 1, VFE_LINE_RDI2 = 2, - VFE_LINE_PIX = 3 + VFE_LINE_NUM_GEN2 = 3, + VFE_LINE_PIX = 3, + VFE_LINE_NUM_GEN1 = 4, + VFE_LINE_NUM_MAX = 4 }; struct vfe_output { u8 wm_num; u8 wm_idx[3]; - int active_buf; struct camss_buffer *buf[2]; struct camss_buffer *last_buffer; struct list_head pending_bufs; unsigned int drop_update_idx; + union { + struct { + int active_buf; + int wait_sof; + } gen1; + struct { + int active_num; + } gen2; + }; enum vfe_output_state state; unsigned int sequence; - int wait_sof; + int wait_reg_update; struct completion sof; struct completion reg_update; @@ -78,59 +101,21 @@ struct vfe_line { struct vfe_device; struct vfe_hw_ops { - void (*hw_version_read)(struct vfe_device *vfe, struct device *dev); - u16 (*get_ub_size)(u8 vfe_id); + void (*enable_irq_common)(struct vfe_device *vfe); void (*global_reset)(struct vfe_device *vfe); - void (*halt_request)(struct vfe_device *vfe); - void (*halt_clear)(struct vfe_device *vfe); - void (*wm_enable)(struct vfe_device *vfe, u8 wm, u8 enable); - void (*wm_frame_based)(struct vfe_device *vfe, u8 wm, u8 enable); - void (*wm_line_based)(struct vfe_device *vfe, u32 wm, - struct v4l2_pix_format_mplane *pix, - u8 plane, u32 enable); - void (*wm_set_framedrop_period)(struct vfe_device *vfe, u8 wm, u8 per); - void (*wm_set_framedrop_pattern)(struct vfe_device *vfe, u8 wm, - u32 pattern); - void (*wm_set_ub_cfg)(struct vfe_device *vfe, u8 wm, u16 offset, - u16 depth); - void (*bus_reload_wm)(struct vfe_device *vfe, u8 wm); - void (*wm_set_ping_addr)(struct vfe_device *vfe, u8 wm, u32 addr); - void (*wm_set_pong_addr)(struct vfe_device *vfe, u8 wm, u32 addr); - int (*wm_get_ping_pong_status)(struct vfe_device *vfe, u8 wm); - void (*bus_enable_wr_if)(struct vfe_device *vfe, u8 enable); - void (*bus_connect_wm_to_rdi)(struct vfe_device *vfe, u8 wm, - enum vfe_line_id id); - void (*wm_set_subsample)(struct vfe_device *vfe, u8 wm); - void (*bus_disconnect_wm_from_rdi)(struct vfe_device *vfe, u8 wm, - enum vfe_line_id id); - void (*set_xbar_cfg)(struct vfe_device *vfe, struct vfe_output *output, - u8 enable); - void (*set_rdi_cid)(struct vfe_device *vfe, enum vfe_line_id id, - u8 cid); - void (*set_realign_cfg)(struct vfe_device *vfe, struct vfe_line *line, - u8 enable); + void (*hw_version_read)(struct vfe_device *vfe, struct device *dev); + irqreturn_t (*isr)(int irq, void *dev); + void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1); + void (*pm_domain_off)(struct vfe_device *vfe); + int (*pm_domain_on)(struct vfe_device *vfe); void (*reg_update)(struct vfe_device *vfe, enum vfe_line_id line_id); void (*reg_update_clear)(struct vfe_device *vfe, enum vfe_line_id line_id); - void (*enable_irq_wm_line)(struct vfe_device *vfe, u8 wm, - enum vfe_line_id line_id, u8 enable); - void (*enable_irq_pix_line)(struct vfe_device *vfe, u8 comp, - enum vfe_line_id line_id, u8 enable); - void (*enable_irq_common)(struct vfe_device *vfe); - void (*set_demux_cfg)(struct vfe_device *vfe, struct vfe_line *line); - void (*set_scale_cfg)(struct vfe_device *vfe, struct vfe_line *line); - void (*set_crop_cfg)(struct vfe_device *vfe, struct vfe_line *line); - void (*set_clamp_cfg)(struct vfe_device *vfe); - void (*set_qos)(struct vfe_device *vfe); - void (*set_ds)(struct vfe_device *vfe); - void (*set_cgc_override)(struct vfe_device *vfe, u8 wm, u8 enable); - void (*set_camif_cfg)(struct vfe_device *vfe, struct vfe_line *line); - void (*set_camif_cmd)(struct vfe_device *vfe, u8 enable); - void (*set_module_cfg)(struct vfe_device *vfe, u8 enable); - int (*camif_wait_for_stop)(struct vfe_device *vfe, struct device *dev); - void (*isr_read)(struct vfe_device *vfe, u32 *value0, u32 *value1); + void (*subdev_init)(struct device *dev, struct vfe_device *vfe); + int (*vfe_disable)(struct vfe_line *line); + int (*vfe_enable)(struct vfe_line *line); + int (*vfe_halt)(struct vfe_device *vfe); void (*violation_read)(struct vfe_device *vfe); - irqreturn_t (*isr)(int irq, void *dev); }; struct vfe_isr_ops { @@ -158,11 +143,14 @@ struct vfe_device { int stream_count; spinlock_t output_lock; enum vfe_line_id wm_output_map[MSM_VFE_IMAGE_MASTERS_NUM]; - struct vfe_line line[MSM_VFE_LINE_NUM]; + struct vfe_line line[VFE_LINE_NUM_MAX]; + u8 line_num; u32 reg_update; u8 was_streaming; const struct vfe_hw_ops *ops; + const struct vfe_hw_ops_gen1 *ops_gen1; struct vfe_isr_ops isr_ops; + struct camss_video_ops video_ops; }; struct resources; @@ -178,8 +166,40 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe); void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id); void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id); +/* + * vfe_buf_add_pending - Add output buffer to list of pending + * @output: VFE output + * @buffer: Video buffer + */ +void vfe_buf_add_pending(struct vfe_output *output, struct camss_buffer *buffer); + +struct camss_buffer *vfe_buf_get_pending(struct vfe_output *output); + +int vfe_flush_buffers(struct camss_video *vid, enum vb2_buffer_state state); + +/* + * vfe_isr_comp_done - Process composite image done interrupt + * @vfe: VFE Device + * @comp: Composite image id + */ +void vfe_isr_comp_done(struct vfe_device *vfe, u8 comp); + +void vfe_isr_reset_ack(struct vfe_device *vfe); +int vfe_put_output(struct vfe_line *line); +int vfe_release_wm(struct vfe_device *vfe, u8 wm); +int vfe_reserve_wm(struct vfe_device *vfe, enum vfe_line_id line_id); + +/* + * vfe_reset - Trigger reset on VFE module and wait to complete + * @vfe: VFE device + * + * Return 0 on success or a negative error code otherwise + */ +int vfe_reset(struct vfe_device *vfe); + 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; #endif /* QC_MSM_CAMSS_VFE_H */ diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 97cea7c4d769..f282275af626 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -133,6 +133,55 @@ static const struct camss_format_info formats_rdi_8x96[] = { { { 1, 1 } }, { { 1, 1 } }, { 16 } }, }; +static const struct camss_format_info formats_rdi_845[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_PIX_FMT_UYVY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_PIX_FMT_VYUY, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_PIX_FMT_YUYV, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_PIX_FMT_YVYU, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1, + { { 1, 1 } }, { { 1, 1 } }, { 8 } }, + { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, + { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 12 } }, + { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 14 } }, + { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 14 } }, + { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 14 } }, + { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 14 } }, + { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1, + { { 1, 1 } }, { { 1, 1 } }, { 10 } }, + { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1, + { { 1, 1 } }, { { 1, 1 } }, { 16 } }, +}; + static const struct camss_format_info formats_pix_8x16[] = { { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1, { { 1, 1 } }, { { 2, 3 } }, { 8 } }, @@ -960,6 +1009,9 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev, video->formats = formats_rdi_8x96; video->nformats = ARRAY_SIZE(formats_rdi_8x96); } + } else if (video->camss->version == CAMSS_845) { + video->formats = formats_rdi_845; + video->nformats = ARRAY_SIZE(formats_rdi_845); } else { ret = -EINVAL; goto error_video_register; diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index 7c0f669f8aa6..ef100d5f7763 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -465,6 +465,203 @@ static const struct resources vfe_res_660[] = { } }; +static const struct resources csiphy_res_845[] = { + /* CSIPHY0 */ + { + .regulator = { NULL }, + .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", + "cpas_ahb", "cphy_rx_src", "csiphy0", + "csiphy0_timer_src", "csiphy0_timer" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 19200000, 240000000, 269333333 } }, + .reg = { "csiphy0" }, + .interrupt = { "csiphy0" } + }, + + /* CSIPHY1 */ + { + .regulator = { NULL }, + .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", + "cpas_ahb", "cphy_rx_src", "csiphy1", + "csiphy1_timer_src", "csiphy1_timer" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 19200000, 240000000, 269333333 } }, + .reg = { "csiphy1" }, + .interrupt = { "csiphy1" } + }, + + /* CSIPHY2 */ + { + .regulator = { NULL }, + .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", + "cpas_ahb", "cphy_rx_src", "csiphy2", + "csiphy2_timer_src", "csiphy2_timer" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 19200000, 240000000, 269333333 } }, + .reg = { "csiphy2" }, + .interrupt = { "csiphy2" } + }, + + /* CSIPHY3 */ + { + .regulator = { NULL }, + .clock = { "camnoc_axi", "soc_ahb", "slow_ahb_src", + "cpas_ahb", "cphy_rx_src", "csiphy3", + "csiphy3_timer_src", "csiphy3_timer" }, + .clock_rate = { { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 0 }, + { 19200000, 240000000, 269333333 } }, + .reg = { "csiphy3" }, + .interrupt = { "csiphy3" } + } +}; + +static const struct resources csid_res_845[] = { + /* CSID0 */ + { + .regulator = { "vdda-csi0" }, + .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", + "soc_ahb", "vfe0", "vfe0_src", + "vfe0_cphy_rx", "csi0", + "csi0_src" }, + .clock_rate = { { 0 }, + { 384000000 }, + { 80000000 }, + { 0 }, + { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, + { 320000000 }, + { 0 }, + { 19200000, 75000000, 384000000, 538666667 }, + { 384000000 } }, + .reg = { "csid0" }, + .interrupt = { "csid0" } + }, + + /* CSID1 */ + { + .regulator = { "vdda-csi1" }, + .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", + "soc_ahb", "vfe1", "vfe1_src", + "vfe1_cphy_rx", "csi1", + "csi1_src" }, + .clock_rate = { { 0 }, + { 384000000 }, + { 80000000 }, + { 0 }, + { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, + { 320000000 }, + { 0 }, + { 19200000, 75000000, 384000000, 538666667 }, + { 384000000 } }, + .reg = { "csid1" }, + .interrupt = { "csid1" } + }, + + /* CSID2 */ + { + .regulator = { "vdda-csi2" }, + .clock = { "cpas_ahb", "cphy_rx_src", "slow_ahb_src", + "soc_ahb", "vfe_lite", "vfe_lite_src", + "vfe_lite_cphy_rx", "csi2", + "csi2_src" }, + .clock_rate = { { 0 }, + { 384000000 }, + { 80000000 }, + { 0 }, + { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, + { 320000000 }, + { 0 }, + { 19200000, 75000000, 384000000, 538666667 }, + { 384000000 } }, + .reg = { "csid2" }, + .interrupt = { "csid2" } + } +}; + +static const struct resources vfe_res_845[] = { + /* VFE0 */ + { + .regulator = { NULL }, + .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src", + "soc_ahb", "vfe0", "vfe0_axi", + "vfe0_src", "csi0", + "csi0_src"}, + .clock_rate = { { 0 }, + { 0 }, + { 80000000 }, + { 0 }, + { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, + { 0 }, + { 320000000 }, + { 19200000, 75000000, 384000000, 538666667 }, + { 384000000 } }, + .reg = { "vfe0" }, + .interrupt = { "vfe0" } + }, + + /* VFE1 */ + { + .regulator = { NULL }, + .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src", + "soc_ahb", "vfe1", "vfe1_axi", + "vfe1_src", "csi1", + "csi1_src"}, + .clock_rate = { { 0 }, + { 0 }, + { 80000000 }, + { 0 }, + { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, + { 0 }, + { 320000000 }, + { 19200000, 75000000, 384000000, 538666667 }, + { 384000000 } }, + .reg = { "vfe1" }, + .interrupt = { "vfe1" } + }, + + /* VFE-lite */ + { + .regulator = { NULL }, + .clock = { "camnoc_axi", "cpas_ahb", "slow_ahb_src", + "soc_ahb", "vfe_lite", + "vfe_lite_src", "csi2", + "csi2_src"}, + .clock_rate = { { 0 }, + { 0 }, + { 80000000 }, + { 0 }, + { 19200000, 100000000, 320000000, 404000000, 480000000, 600000000 }, + { 320000000 }, + { 19200000, 75000000, 384000000, 538666667 }, + { 384000000 } }, + .reg = { "vfe_lite" }, + .interrupt = { "vfe_lite" } + } +}; + /* * camss_add_clock_margin - Add margin to clock frequency rate * @rate: Clock frequency rate @@ -548,6 +745,29 @@ struct media_entity *camss_find_sensor(struct media_entity *entity) } } +/** + * camss_get_link_freq - Get link frequency from sensor + * @entity: Media entity in the current pipeline + * @bpp: Number of bits per pixel for the current format + * @lanes: Number of lanes in the link to the sensor + * + * Return link frequency on success or a negative error code otherwise + */ +s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp, + unsigned int lanes) +{ + struct media_entity *sensor; + struct v4l2_subdev *subdev; + + sensor = camss_find_sensor(entity); + if (!sensor) + return -ENODEV; + + subdev = media_entity_to_v4l2_subdev(sensor); + + return v4l2_get_link_freq(subdev->ctrl_handler, bpp, 2 * lanes); +} + /* * camss_get_pixel_clock - Get pixel clock rate from sensor * @entity: Media entity in the current pipeline @@ -555,7 +775,7 @@ struct media_entity *camss_find_sensor(struct media_entity *entity) * * Return 0 on success or a negative error code otherwise */ -int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock) +int camss_get_pixel_clock(struct media_entity *entity, u64 *pixel_clock) { struct media_entity *sensor; struct v4l2_subdev *subdev; @@ -579,24 +799,24 @@ int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock) int camss_pm_domain_on(struct camss *camss, int id) { - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { - camss->genpd_link[id] = device_link_add(camss->dev, - camss->genpd[id], DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); + int ret = 0; + + if (id < camss->vfe_num) { + struct vfe_device *vfe = &camss->vfe[id]; - if (!camss->genpd_link[id]) - return -EINVAL; + ret = vfe->ops->pm_domain_on(vfe); } - return 0; + return ret; } void camss_pm_domain_off(struct camss *camss, int id) { - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) - device_link_del(camss->genpd_link[id]); + if (id < camss->vfe_num) { + struct vfe_device *vfe = &camss->vfe[id]; + + vfe->ops->pm_domain_off(vfe); + } } /* @@ -719,6 +939,12 @@ static int camss_init_subdevices(struct camss *camss) csid_res = csid_res_660; ispif_res = &ispif_res_660; vfe_res = vfe_res_660; + } else if (camss->version == CAMSS_845) { + csiphy_res = csiphy_res_845; + csid_res = csid_res_845; + /* Titan VFEs don't have an ISPIF */ + ispif_res = NULL; + vfe_res = vfe_res_845; } else { return -EINVAL; } @@ -745,10 +971,10 @@ static int camss_init_subdevices(struct camss *camss) } } - ret = msm_ispif_subdev_init(&camss->ispif, ispif_res); + ret = msm_ispif_subdev_init(camss, ispif_res); if (ret < 0) { dev_err(camss->dev, "Failed to init ispif sub-device: %d\n", - ret); + ret); return ret; } @@ -798,10 +1024,11 @@ static int camss_register_entities(struct camss *camss) } } - ret = msm_ispif_register_entities(&camss->ispif, &camss->v4l2_dev); + ret = msm_ispif_register_entities(camss->ispif, + &camss->v4l2_dev); if (ret < 0) { dev_err(camss->dev, "Failed to register ispif entities: %d\n", - ret); + ret); goto err_reg_ispif; } @@ -835,43 +1062,68 @@ static int camss_register_entities(struct camss *camss) } } - for (i = 0; i < camss->csid_num; i++) { - for (j = 0; j < camss->ispif.line_num; j++) { - ret = media_create_pad_link( - &camss->csid[i].subdev.entity, - MSM_CSID_PAD_SRC, - &camss->ispif.line[j].subdev.entity, - MSM_ISPIF_PAD_SINK, - 0); - if (ret < 0) { - dev_err(camss->dev, - "Failed to link %s->%s entities: %d\n", - camss->csid[i].subdev.entity.name, - camss->ispif.line[j].subdev.entity.name, - ret); - goto err_link; - } - } - } - - for (i = 0; i < camss->ispif.line_num; i++) - for (k = 0; k < camss->vfe_num; k++) - for (j = 0; j < ARRAY_SIZE(camss->vfe[k].line); j++) { + if (camss->ispif) { + for (i = 0; i < camss->csid_num; i++) { + for (j = 0; j < camss->ispif->line_num; j++) { ret = media_create_pad_link( - &camss->ispif.line[i].subdev.entity, - MSM_ISPIF_PAD_SRC, - &camss->vfe[k].line[j].subdev.entity, - MSM_VFE_PAD_SINK, + &camss->csid[i].subdev.entity, + MSM_CSID_PAD_SRC, + &camss->ispif->line[j].subdev.entity, + MSM_ISPIF_PAD_SINK, 0); if (ret < 0) { dev_err(camss->dev, "Failed to link %s->%s entities: %d\n", - camss->ispif.line[i].subdev.entity.name, - camss->vfe[k].line[j].subdev.entity.name, + camss->csid[i].subdev.entity.name, + camss->ispif->line[j].subdev.entity.name, ret); goto err_link; } } + } + + for (i = 0; i < camss->ispif->line_num; i++) + for (k = 0; k < camss->vfe_num; k++) + for (j = 0; j < camss->vfe[k].line_num; j++) { + struct v4l2_subdev *ispif = &camss->ispif->line[i].subdev; + struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; + + ret = media_create_pad_link(&ispif->entity, + MSM_ISPIF_PAD_SRC, + &vfe->entity, + MSM_VFE_PAD_SINK, + 0); + if (ret < 0) { + dev_err(camss->dev, + "Failed to link %s->%s entities: %d\n", + ispif->entity.name, + vfe->entity.name, + ret); + goto err_link; + } + } + } else { + for (i = 0; i < camss->csid_num; i++) + for (k = 0; k < camss->vfe_num; k++) + for (j = 0; j < camss->vfe[k].line_num; j++) { + struct v4l2_subdev *csid = &camss->csid[i].subdev; + struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev; + + ret = media_create_pad_link(&csid->entity, + MSM_CSID_PAD_SRC, + &vfe->entity, + MSM_VFE_PAD_SINK, + 0); + if (ret < 0) { + dev_err(camss->dev, + "Failed to link %s->%s entities: %d\n", + csid->entity.name, + vfe->entity.name, + ret); + goto err_link; + } + } + } return 0; @@ -881,8 +1133,8 @@ err_reg_vfe: for (i--; i >= 0; i--) msm_vfe_unregister_entities(&camss->vfe[i]); - msm_ispif_unregister_entities(&camss->ispif); err_reg_ispif: + msm_ispif_unregister_entities(camss->ispif); i = camss->csid_num; err_reg_csid: @@ -913,7 +1165,7 @@ static void camss_unregister_entities(struct camss *camss) for (i = 0; i < camss->csid_num; i++) msm_csid_unregister_entity(&camss->csid[i]); - msm_ispif_unregister_entities(&camss->ispif); + msm_ispif_unregister_entities(camss->ispif); for (i = 0; i < camss->vfe_num; i++) msm_vfe_unregister_entities(&camss->vfe[i]); @@ -988,6 +1240,49 @@ static const struct media_device_ops camss_media_ops = { .link_notify = v4l2_pipeline_link_notify, }; +static int camss_configure_pd(struct camss *camss) +{ + int nbr_pm_domains = 0; + int last_pm_domain = 0; + int i; + int ret; + + if (camss->version == CAMSS_8x96 || + camss->version == CAMSS_660) + nbr_pm_domains = PM_DOMAIN_GEN1_COUNT; + else if (camss->version == CAMSS_845) + nbr_pm_domains = PM_DOMAIN_GEN2_COUNT; + + for (i = 0; i < nbr_pm_domains; i++) { + camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i); + if (IS_ERR(camss->genpd[i])) { + ret = PTR_ERR(camss->genpd[i]); + goto fail_pm; + } + + camss->genpd_link[i] = device_link_add(camss->dev, camss->genpd[i], + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!camss->genpd_link[i]) { + dev_pm_domain_detach(camss->genpd[i], true); + ret = -EINVAL; + goto fail_pm; + } + + last_pm_domain = i; + } + + return 0; + +fail_pm: + for (i = 0; i < last_pm_domain; i++) { + device_link_del(camss->genpd_link[i]); + dev_pm_domain_detach(camss->genpd[i], true); + } + + return ret; +} + /* * camss_probe - Probe CAMSS platform device * @pdev: Pointer to CAMSS platform device @@ -1025,6 +1320,12 @@ static int camss_probe(struct platform_device *pdev) camss->csiphy_num = 3; camss->csid_num = 4; camss->vfe_num = 2; + } else if (of_device_is_compatible(dev->of_node, + "qcom,sdm845-camss")) { + camss->version = CAMSS_845; + camss->csiphy_num = 4; + camss->csid_num = 3; + camss->vfe_num = 3; } else { ret = -EINVAL; goto err_free; @@ -1044,6 +1345,15 @@ static int camss_probe(struct platform_device *pdev) goto err_free; } + if (camss->version == CAMSS_8x16 || + camss->version == CAMSS_8x96) { + camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL); + if (!camss->ispif) { + ret = -ENOMEM; + goto err_free; + } + } + camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe), GFP_KERNEL); if (!camss->vfe) { @@ -1111,20 +1421,10 @@ static int camss_probe(struct platform_device *pdev) } } - if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { - camss->genpd[PM_DOMAIN_VFE0] = dev_pm_domain_attach_by_id( - camss->dev, PM_DOMAIN_VFE0); - if (IS_ERR(camss->genpd[PM_DOMAIN_VFE0])) - return PTR_ERR(camss->genpd[PM_DOMAIN_VFE0]); - - camss->genpd[PM_DOMAIN_VFE1] = dev_pm_domain_attach_by_id( - camss->dev, PM_DOMAIN_VFE1); - if (IS_ERR(camss->genpd[PM_DOMAIN_VFE1])) { - dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], - true); - return PTR_ERR(camss->genpd[PM_DOMAIN_VFE1]); - } + ret = camss_configure_pd(camss); + if (ret < 0) { + dev_err(dev, "Failed to configure power domains: %d\n", ret); + return ret; } pm_runtime_enable(dev); @@ -1145,6 +1445,9 @@ err_free: void camss_delete(struct camss *camss) { + int nbr_pm_domains = 0; + int i; + v4l2_device_unregister(&camss->v4l2_dev); media_device_unregister(&camss->media_dev); media_device_cleanup(&camss->media_dev); @@ -1152,9 +1455,14 @@ void camss_delete(struct camss *camss) pm_runtime_disable(camss->dev); if (camss->version == CAMSS_8x96 || - camss->version == CAMSS_660) { - dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE0], true); - dev_pm_domain_detach(camss->genpd[PM_DOMAIN_VFE1], true); + camss->version == CAMSS_660) + nbr_pm_domains = PM_DOMAIN_GEN1_COUNT; + else if (camss->version == CAMSS_845) + nbr_pm_domains = PM_DOMAIN_GEN2_COUNT; + + for (i = 0; i < nbr_pm_domains; i++) { + device_link_del(camss->genpd_link[i]); + dev_pm_domain_detach(camss->genpd[i], true); } kfree(camss); @@ -1184,6 +1492,7 @@ static const struct of_device_id camss_dt_match[] = { { .compatible = "qcom,msm8916-camss" }, { .compatible = "qcom,msm8996-camss" }, { .compatible = "qcom,sdm660-camss" }, + { .compatible = "qcom,sdm845-camss" }, { } }; diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h index 3a0484683cd6..dc8b4154f92b 100644 --- a/drivers/media/platform/qcom/camss/camss.h +++ b/drivers/media/platform/qcom/camss/camss.h @@ -57,15 +57,18 @@ struct resources_ispif { }; enum pm_domain { - PM_DOMAIN_VFE0, - PM_DOMAIN_VFE1, - PM_DOMAIN_COUNT + PM_DOMAIN_VFE0 = 0, + PM_DOMAIN_VFE1 = 1, + PM_DOMAIN_GEN1_COUNT = 2, /* CAMSS series of ISPs */ + PM_DOMAIN_VFELITE = 2, /* VFELITE / TOP GDSC */ + PM_DOMAIN_GEN2_COUNT = 3, /* Titan series of ISPs */ }; enum camss_version { CAMSS_8x16, CAMSS_8x96, CAMSS_660, + CAMSS_845, }; struct camss { @@ -78,12 +81,12 @@ struct camss { struct csiphy_device *csiphy; int csid_num; struct csid_device *csid; - struct ispif_device ispif; + struct ispif_device *ispif; int vfe_num; struct vfe_device *vfe; atomic_t ref_count; - struct device *genpd[PM_DOMAIN_COUNT]; - struct device_link *genpd_link[PM_DOMAIN_COUNT]; + struct device *genpd[PM_DOMAIN_GEN2_COUNT]; + struct device_link *genpd_link[PM_DOMAIN_GEN2_COUNT]; }; struct camss_camera_interface { @@ -108,7 +111,9 @@ int camss_enable_clocks(int nclocks, struct camss_clock *clock, struct device *dev); void camss_disable_clocks(int nclocks, struct camss_clock *clock); struct media_entity *camss_find_sensor(struct media_entity *entity); -int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock); +s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp, + unsigned int lanes); +int camss_get_pixel_clock(struct media_entity *entity, u64 *pixel_clock); int camss_pm_domain_on(struct camss *camss, int id); void camss_pm_domain_off(struct camss *camss, int id); void camss_delete(struct camss *camss); diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index f9896c121fd8..54bac7ec14c5 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -5,6 +5,7 @@ */ #include <linux/init.h> #include <linux/interconnect.h> +#include <linux/io.h> #include <linux/ioctl.h> #include <linux/delay.h> #include <linux/devcoredump.h> @@ -22,6 +23,7 @@ #include "core.h" #include "firmware.h" #include "pm_helpers.h" +#include "hfi_venus_io.h" static void venus_coredump(struct venus_core *core) { @@ -206,6 +208,27 @@ err: return ret; } +static void venus_assign_register_offsets(struct venus_core *core) +{ + if (IS_V6(core)) { + core->vbif_base = core->base + VBIF_BASE; + 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; + } else { + core->vbif_base = core->base + VBIF_BASE; + core->cpu_base = core->base + CPU_BASE; + core->cpu_cs_base = core->base + CPU_CS_BASE; + core->cpu_ic_base = core->base + CPU_IC_BASE; + core->wrapper_base = core->base + WRAPPER_BASE; + core->wrapper_tz_base = NULL; + core->aon_base = NULL; + } +} + static int venus_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -218,18 +241,17 @@ static int venus_probe(struct platform_device *pdev) return -ENOMEM; core->dev = dev; - platform_set_drvdata(pdev, core); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); core->base = devm_ioremap_resource(dev, r); if (IS_ERR(core->base)) return PTR_ERR(core->base); - core->video_path = of_icc_get(dev, "video-mem"); + core->video_path = devm_of_icc_get(dev, "video-mem"); if (IS_ERR(core->video_path)) return PTR_ERR(core->video_path); - core->cpucfg_path = of_icc_get(dev, "cpu-cfg"); + core->cpucfg_path = devm_of_icc_get(dev, "cpu-cfg"); if (IS_ERR(core->cpucfg_path)) return PTR_ERR(core->cpucfg_path); @@ -248,7 +270,7 @@ static int venus_probe(struct platform_device *pdev) return -ENODEV; if (core->pm_ops->core_get) { - ret = core->pm_ops->core_get(dev); + ret = core->pm_ops->core_get(core); if (ret) return ret; } @@ -273,6 +295,14 @@ static int venus_probe(struct platform_device *pdev) if (ret) goto err_core_put; + venus_assign_register_offsets(core); + + ret = v4l2_device_register(dev, &core->v4l2_dev); + if (ret) + goto err_core_deinit; + + platform_set_drvdata(pdev, core); + pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); @@ -307,10 +337,6 @@ static int venus_probe(struct platform_device *pdev) if (ret) goto err_venus_shutdown; - ret = v4l2_device_register(dev, &core->v4l2_dev); - if (ret) - goto err_core_deinit; - ret = pm_runtime_put_sync(dev); if (ret) { pm_runtime_get_noresume(dev); @@ -323,8 +349,6 @@ static int venus_probe(struct platform_device *pdev) err_dev_unregister: v4l2_device_unregister(&core->v4l2_dev); -err_core_deinit: - hfi_core_deinit(core, false); err_venus_shutdown: venus_shutdown(core); err_runtime_disable: @@ -332,9 +356,11 @@ err_runtime_disable: pm_runtime_set_suspended(dev); pm_runtime_disable(dev); hfi_destroy(core); +err_core_deinit: + hfi_core_deinit(core, false); err_core_put: if (core->pm_ops->core_put) - core->pm_ops->core_put(dev); + core->pm_ops->core_put(core); return ret; } @@ -360,14 +386,12 @@ static int venus_remove(struct platform_device *pdev) pm_runtime_disable(dev); if (pm_ops->core_put) - pm_ops->core_put(dev); + pm_ops->core_put(core); - hfi_destroy(core); + v4l2_device_unregister(&core->v4l2_dev); - icc_put(core->video_path); - icc_put(core->cpucfg_path); + hfi_destroy(core); - v4l2_device_unregister(&core->v4l2_dev); mutex_destroy(&core->pm_lock); mutex_destroy(&core->lock); venus_dbgfs_deinit(core); @@ -396,7 +420,7 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) return ret; if (pm_ops->core_power) { - ret = pm_ops->core_power(dev, POWER_OFF); + ret = pm_ops->core_power(core, POWER_OFF); if (ret) return ret; } @@ -414,7 +438,7 @@ static __maybe_unused int venus_runtime_suspend(struct device *dev) err_video_path: icc_set_bw(core->cpucfg_path, kbps_to_icc(1000), 0); err_cpucfg_path: - pm_ops->core_power(dev, POWER_ON); + pm_ops->core_power(core, POWER_ON); return ret; } @@ -434,7 +458,7 @@ static __maybe_unused int venus_runtime_resume(struct device *dev) return ret; if (pm_ops->core_power) { - ret = pm_ops->core_power(dev, POWER_ON); + ret = pm_ops->core_power(core, POWER_ON); if (ret) return ret; } @@ -625,12 +649,66 @@ static const struct venus_resources sc7180_res = { .fwname = "qcom/venus-5.4/venus.mdt", }; +static const struct freq_tbl sm8250_freq_table[] = { + { 0, 444000000 }, + { 0, 366000000 }, + { 0, 338000000 }, + { 0, 240000000 }, +}; + +static const struct bw_tbl sm8250_bw_table_enc[] = { + { 1944000, 1954000, 0, 3711000, 0 }, /* 3840x2160@60 */ + { 972000, 996000, 0, 1905000, 0 }, /* 3840x2160@30 */ + { 489600, 645000, 0, 977000, 0 }, /* 1920x1080@60 */ + { 244800, 332000, 0, 498000, 0 }, /* 1920x1080@30 */ +}; + +static const struct bw_tbl sm8250_bw_table_dec[] = { + { 2073600, 2403000, 0, 4113000, 0 }, /* 4096x2160@60 */ + { 1036800, 1224000, 0, 2079000, 0 }, /* 4096x2160@30 */ + { 489600, 812000, 0, 998000, 0 }, /* 1920x1080@60 */ + { 244800, 416000, 0, 509000, 0 }, /* 1920x1080@30 */ +}; + +static const struct reg_val sm8250_reg_preset[] = { + { 0xb0088, 0 }, +}; + +static const struct venus_resources sm8250_res = { + .freq_tbl = sm8250_freq_table, + .freq_tbl_size = ARRAY_SIZE(sm8250_freq_table), + .reg_tbl = sm8250_reg_preset, + .reg_tbl_size = ARRAY_SIZE(sm8250_reg_preset), + .bw_tbl_enc = sm8250_bw_table_enc, + .bw_tbl_enc_size = ARRAY_SIZE(sm8250_bw_table_enc), + .bw_tbl_dec = sm8250_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8250_bw_table_dec), + .clks = {"core", "iface"}, + .clks_num = 2, + .resets = { "bus", "core" }, + .resets_num = 2, + .vcodec0_clks = { "vcodec0_core" }, + .vcodec_clks_num = 1, + .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains_num = 2, + .opp_pmdomain = (const char *[]) { "mx", NULL }, + .vcodec_num = 1, + .max_load = 7833600, + .hfi_version = HFI_VERSION_6XX, + .vmem_id = VIDC_RESOURCE_NONE, + .vmem_size = 0, + .vmem_addr = 0, + .dma_mask = 0xe0000000 - 1, + .fwname = "qcom/vpu-1.0/venus.mdt", +}; + 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,sdm845-venus", .data = &sdm845_res, }, { .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, }, { .compatible = "qcom,sc7180-venus", .data = &sc7180_res, }, + { .compatible = "qcom,sm8250-venus", .data = &sm8250_res, }, { } }; MODULE_DEVICE_TABLE(of, venus_dt_match); diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index a252ed32cc14..745f226a523f 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -24,6 +24,7 @@ #define VIDC_CLKS_NUM_MAX 4 #define VIDC_VCODEC_CLKS_NUM_MAX 2 #define VIDC_PMDOMAINS_NUM_MAX 3 +#define VIDC_RESETS_NUM_MAX 2 extern int venus_fw_debug; @@ -64,6 +65,8 @@ struct venus_resources { unsigned int vcodec_pmdomains_num; const char **opp_pmdomain; unsigned int vcodec_num; + const char * const resets[VIDC_RESETS_NUM_MAX]; + unsigned int resets_num; enum hfi_version hfi_version; u32 max_load; unsigned int vmem_id; @@ -87,11 +90,25 @@ struct venus_format { * struct venus_core - holds core parameters valid for all instances * * @base: IO memory base address + * @vbif_base: IO memory vbif base address + * @cpu_base: IO memory cpu base address + * @cpu_cs_base: IO memory cpu_cs base address + * @cpu_ic_base: IO memory cpu_ic base address + * @wrapper_base: IO memory wrapper base address + * @wrapper_tz_base: IO memory wrapper TZ base address + * @aon_base: AON base address * @irq: Venus irq * @clks: an array of struct clk pointers * @vcodec0_clks: an array of vcodec0 struct clk pointers * @vcodec1_clks: an array of vcodec1 struct clk pointers + * @video_path: an interconnect handle to video to/from memory path + * @cpucfg_path: an interconnect handle to cpu configuration path + * @opp_table: an device OPP table handle + * @has_opp_table: does OPP table exist * @pmdomains: an array of pmdomains struct device pointers + * @opp_dl_venus: an device-link for device OPP + * @opp_pmdomain: an OPP power-domain + * @resets: an array of reset signals * @vdev_dec: a reference to video device structure for decoder instances * @vdev_enc: a reference to video device structure for encoder instances * @v4l2_dev: a holder for v4l2 device structure @@ -100,6 +117,7 @@ struct venus_format { * @dev_dec: convenience struct device pointer for decoder device * @dev_enc: convenience struct device pointer for encoder device * @use_tz: a flag that suggests presence of trustzone + * @fw: structure of firmware parameters * @lock: a lock for this strucure * @instances: a list_head of all instances * @insts_count: num of instances @@ -108,6 +126,7 @@ struct venus_format { * @error: an error returned during last HFI sync operations * @sys_error: an error flag that signal system error event * @core_ops: the core operations + * @pm_ops: a pointer to pm operations * @pm_lock: a lock for PM operations * @enc_codecs: encoders supported by this core * @dec_codecs: decoders supported by this core @@ -115,10 +134,21 @@ struct venus_format { * @priv: a private filed for HFI operations * @ops: the core HFI operations * @work: a delayed work for handling system fatal error + * @caps: an array of supported HFI capabilities + * @codecs_count: platform codecs count + * @core0_usage_count: usage counter for core0 + * @core1_usage_count: usage counter for core1 * @root: debugfs root directory */ struct venus_core { void __iomem *base; + void __iomem *vbif_base; + void __iomem *cpu_base; + void __iomem *cpu_cs_base; + void __iomem *cpu_ic_base; + void __iomem *wrapper_base; + void __iomem *wrapper_tz_base; + void __iomem *aon_base; int irq; struct clk *clks[VIDC_CLKS_NUM_MAX]; struct clk *vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX]; @@ -130,6 +160,7 @@ struct venus_core { struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; struct device_link *opp_dl_venus; struct device *opp_pmdomain; + struct reset_control *resets[VIDC_RESETS_NUM_MAX]; struct video_device *vdev_dec; struct video_device *vdev_enc; struct v4l2_device v4l2_dev; @@ -172,6 +203,9 @@ struct vdec_controls { u32 post_loop_deb_mode; u32 profile; u32 level; + u32 display_delay; + u32 display_delay_enable; + u64 conceal_color; }; struct venc_controls { @@ -222,6 +256,7 @@ struct venc_controls { u32 multi_slice_max_mb; u32 header_mode; + bool aud_enable; struct { u32 h264; @@ -238,6 +273,9 @@ struct venc_controls { } level; u32 base_priority_id; + u32 ltr_count; + struct v4l2_ctrl_hdr10_cll_info cll; + struct v4l2_ctrl_hdr10_mastering_display mastering; }; struct venus_buffer { @@ -284,10 +322,11 @@ struct venus_ts_metadata { * @list: used for attach an instance to the core * @lock: instance lock * @core: a reference to the core struct + * @clk_data: clock data per core ID * @dpbbufs: a list of decoded picture buffers * @internalbufs: a list of internal bufferes * @registeredbufs: a list of registered capture bufferes - * @delayed_process a list of delayed buffers + * @delayed_process: a list of delayed buffers * @delayed_process_work: a work_struct for process delayed buffers * @ctrl_handler: v4l control handler * @controls: a union of decoder and encoder control parameters @@ -296,22 +335,26 @@ struct venus_ts_metadata { * @streamon_out: stream on flag for output queue * @width: current capture width * @height: current capture height + * @crop: current crop rectangle * @out_width: current output width * @out_height: current output height * @colorspace: current color space + * @ycbcr_enc: current YCbCr encoding * @quantization: current quantization * @xfer_func: current xfer function * @codec_state: current codec API state (see DEC/ENC_STATE_) * @reconf_wait: wait queue for resolution change event * @subscriptions: used to hold current events subscriptions * @buf_count: used to count number of buffers (reqbuf(0)) + * @tss: timestamp metadata + * @payloads: cache plane payload to use it for clock/BW scaling * @fps: holds current FPS * @timeperframe: holds current time per frame structure * @fmt_out: a reference to output format structure * @fmt_cap: a reference to capture format structure * @num_input_bufs: holds number of input buffers * @num_output_bufs: holds number of output buffers - * @input_buf_size holds input buffer size + * @input_buf_size: holds input buffer size * @output_buf_size: holds output buffer size * @output2_buf_size: holds secondary decoder output buffer size * @dpb_buftype: decoded picture buffer type @@ -332,7 +375,11 @@ struct venus_ts_metadata { * @priv: a private for HFI operations callbacks * @session_type: the type of the session (decoder or encoder) * @hprop: a union used as a holder by get property + * @core_acquired: the Core has been acquired + * @bit_depth: current bitstream bit-depth + * @pic_struct: bitstream progressive vs interlaced * @next_buf_last: a flag to mark next queued capture buffer as last + * @drain_active: Drain sequence is in progress */ struct venus_inst { struct list_head list; @@ -403,6 +450,7 @@ struct venus_inst { #define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX) #define IS_V3(core) ((core)->res->hfi_version == HFI_VERSION_3XX) #define IS_V4(core) ((core)->res->hfi_version == HFI_VERSION_4XX) +#define IS_V6(core) ((core)->res->hfi_version == HFI_VERSION_6XX) #define ctrl_to_inst(ctrl) \ container_of((ctrl)->handler, struct venus_inst, ctrl_handler) diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 89defc21ea81..227bd3b3f84c 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -27,19 +27,19 @@ static void venus_reset_cpu(struct venus_core *core) { u32 fw_size = core->fw.mapped_mem_size; - void __iomem *base = core->base; + void __iomem *wrapper_base = core->wrapper_base; - writel(0, base + WRAPPER_FW_START_ADDR); - writel(fw_size, base + WRAPPER_FW_END_ADDR); - writel(0, base + WRAPPER_CPA_START_ADDR); - writel(fw_size, base + WRAPPER_CPA_END_ADDR); - writel(fw_size, base + WRAPPER_NONPIX_START_ADDR); - writel(fw_size, base + WRAPPER_NONPIX_END_ADDR); - writel(0x0, base + WRAPPER_CPU_CGC_DIS); - writel(0x0, base + WRAPPER_CPU_CLOCK_CONFIG); + writel(0, wrapper_base + WRAPPER_FW_START_ADDR); + writel(fw_size, wrapper_base + WRAPPER_FW_END_ADDR); + writel(0, wrapper_base + WRAPPER_CPA_START_ADDR); + writel(fw_size, wrapper_base + WRAPPER_CPA_END_ADDR); + writel(fw_size, wrapper_base + WRAPPER_NONPIX_START_ADDR); + writel(fw_size, wrapper_base + WRAPPER_NONPIX_END_ADDR); + writel(0x0, wrapper_base + WRAPPER_CPU_CGC_DIS); + writel(0x0, wrapper_base + WRAPPER_CPU_CLOCK_CONFIG); /* Bring ARM9 out of reset */ - writel(0, base + WRAPPER_A9SS_SW_RESET); + writel(0, wrapper_base + WRAPPER_A9SS_SW_RESET); } int venus_set_hw_state(struct venus_core *core, bool resume) @@ -53,10 +53,12 @@ int venus_set_hw_state(struct venus_core *core, bool resume) return ret; } - if (resume) + if (resume) { venus_reset_cpu(core); - else - writel(1, core->base + WRAPPER_A9SS_SW_RESET); + } else { + if (!IS_V6(core)) + writel(1, core->wrapper_base + WRAPPER_A9SS_SW_RESET); + } return 0; } @@ -159,12 +161,12 @@ static int venus_shutdown_no_tz(struct venus_core *core) size_t unmapped; u32 reg; struct device *dev = core->fw.dev; - void __iomem *base = core->base; + void __iomem *wrapper_base = core->wrapper_base; /* Assert the reset to ARM9 */ - reg = readl_relaxed(base + WRAPPER_A9SS_SW_RESET); + reg = readl_relaxed(wrapper_base + WRAPPER_A9SS_SW_RESET); reg |= WRAPPER_A9SS_SW_RESET_BIT; - writel_relaxed(reg, base + WRAPPER_A9SS_SW_RESET); + writel_relaxed(reg, wrapper_base + WRAPPER_A9SS_SW_RESET); /* Make sure reset is asserted before the mapping is removed */ mb(); @@ -187,6 +189,7 @@ int venus_boot(struct venus_core *core) { struct device *dev = core->dev; const struct venus_resources *res = core->res; + const char *fwpath = NULL; phys_addr_t mem_phys; size_t mem_size; int ret; @@ -195,7 +198,12 @@ int venus_boot(struct venus_core *core) (core->use_tz && !qcom_scm_is_available())) return -EPROBE_DEFER; - ret = venus_load_fw(core, core->res->fwname, &mem_phys, &mem_size); + ret = of_property_read_string_index(dev->of_node, "firmware-name", 0, + &fwpath); + if (ret) + fwpath = core->res->fwname; + + ret = venus_load_fw(core, fwpath, &mem_phys, &mem_size); if (ret) { dev_err(dev, "fail to load video firmware\n"); return -EINVAL; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 76ece2ff8d39..b813d6dba481 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -18,6 +18,9 @@ #include "hfi_platform.h" #include "hfi_parser.h" +#define NUM_MBS_720P (((1280 + 15) >> 4) * ((720 + 15) >> 4)) +#define NUM_MBS_4K (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) + struct intbuf { struct list_head list; u32 type; @@ -279,13 +282,24 @@ static const unsigned int intbuf_types_4xx[] = { HFI_BUFFER_INTERNAL_PERSIST_1, }; +static const unsigned int intbuf_types_6xx[] = { + HFI_BUFFER_INTERNAL_SCRATCH(HFI_VERSION_6XX), + HFI_BUFFER_INTERNAL_SCRATCH_1(HFI_VERSION_6XX), + HFI_BUFFER_INTERNAL_SCRATCH_2(HFI_VERSION_6XX), + HFI_BUFFER_INTERNAL_PERSIST, + HFI_BUFFER_INTERNAL_PERSIST_1, +}; + int venus_helper_intbufs_alloc(struct venus_inst *inst) { const unsigned int *intbuf; size_t arr_sz, i; int ret; - if (IS_V4(inst->core)) { + if (IS_V6(inst->core)) { + arr_sz = ARRAY_SIZE(intbuf_types_6xx); + intbuf = intbuf_types_6xx; + } else if (IS_V4(inst->core)) { arr_sz = ARRAY_SIZE(intbuf_types_4xx); intbuf = intbuf_types_4xx; } else { @@ -488,7 +502,7 @@ static bool is_dynamic_bufmode(struct venus_inst *inst) * v4 doesn't send BUFFER_ALLOC_MODE_SUPPORTED property and supports * dynamic buffer mode by default for HFI_BUFFER_OUTPUT/OUTPUT2. */ - if (IS_V4(core)) + if (IS_V4(core) || IS_V6(core)) return true; caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type); @@ -1079,20 +1093,67 @@ int venus_helper_set_output_resolution(struct venus_inst *inst, } EXPORT_SYMBOL_GPL(venus_helper_set_output_resolution); -int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode) +static u32 venus_helper_get_work_mode(struct venus_inst *inst) +{ + u32 mode; + u32 num_mbs; + + mode = VIDC_WORK_MODE_2; + if (inst->session_type == VIDC_SESSION_TYPE_DEC) { + num_mbs = (ALIGN(inst->height, 16) * ALIGN(inst->width, 16)) / 256; + if (inst->hfi_codec == HFI_VIDEO_CODEC_MPEG2 || + inst->pic_struct != HFI_INTERLACE_FRAME_PROGRESSIVE || + num_mbs <= NUM_MBS_720P) + mode = VIDC_WORK_MODE_1; + } else { + num_mbs = (ALIGN(inst->out_height, 16) * ALIGN(inst->out_width, 16)) / 256; + if (inst->hfi_codec == HFI_VIDEO_CODEC_VP8 && + num_mbs <= NUM_MBS_4K) + mode = VIDC_WORK_MODE_1; + } + + return mode; +} + +int venus_helper_set_work_mode(struct venus_inst *inst) { const u32 ptype = HFI_PROPERTY_PARAM_WORK_MODE; struct hfi_video_work_mode wm; + u32 mode; - if (!IS_V4(inst->core)) + if (!IS_V4(inst->core) && !IS_V6(inst->core)) return 0; + mode = venus_helper_get_work_mode(inst); wm.video_work_mode = mode; - return hfi_session_set_property(inst, ptype, &wm); } EXPORT_SYMBOL_GPL(venus_helper_set_work_mode); +int venus_helper_set_format_constraints(struct venus_inst *inst) +{ + const u32 ptype = HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO; + struct hfi_uncompressed_plane_actual_constraints_info pconstraint; + + if (!IS_V6(inst->core)) + return 0; + + pconstraint.buffer_type = HFI_BUFFER_OUTPUT2; + pconstraint.num_planes = 2; + pconstraint.plane_format[0].stride_multiples = 128; + pconstraint.plane_format[0].max_stride = 8192; + pconstraint.plane_format[0].min_plane_buffer_height_multiple = 32; + pconstraint.plane_format[0].buffer_alignment = 256; + + pconstraint.plane_format[1].stride_multiples = 128; + pconstraint.plane_format[1].max_stride = 8192; + pconstraint.plane_format[1].min_plane_buffer_height_multiple = 16; + pconstraint.plane_format[1].buffer_alignment = 256; + + return hfi_session_set_property(inst, ptype, &pconstraint); +} +EXPORT_SYMBOL_GPL(venus_helper_set_format_constraints); + int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs, unsigned int output_bufs, unsigned int output2_bufs) diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index 351093845499..e6269b4be3af 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -32,7 +32,8 @@ int venus_helper_set_input_resolution(struct venus_inst *inst, int venus_helper_set_output_resolution(struct venus_inst *inst, unsigned int width, unsigned int height, u32 buftype); -int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode); +int venus_helper_set_work_mode(struct venus_inst *inst); +int venus_helper_set_format_constraints(struct venus_inst *inst); int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs, unsigned int output_bufs, unsigned int output2_bufs); diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index 4f7565834469..11a8347e5f5c 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -254,7 +254,7 @@ int pkt_session_unset_buffers(struct hfi_session_release_buffer_pkt *pkt, int pkt_session_etb_decoder(struct hfi_session_empty_buffer_compressed_pkt *pkt, void *cookie, struct hfi_frame_data *in_frame) { - if (!cookie || !in_frame->device_addr) + if (!cookie) return -EINVAL; pkt->shdr.hdr.size = sizeof(*pkt); @@ -760,7 +760,9 @@ static int pkt_session_set_property_1x(struct hfi_session_set_property_pkt *pkt, struct hfi_conceal_color *color = prop_data; u32 *in = pdata; - color->conceal_color = *in; + color->conceal_color = *in & 0xff; + color->conceal_color |= ((*in >> 10) & 0xff) << 8; + color->conceal_color |= ((*in >> 20) & 0xff) << 16; pkt->shdr.hdr.size += sizeof(u32) + sizeof(*color); break; } @@ -1039,6 +1041,18 @@ static int pkt_session_set_property_1x(struct hfi_session_set_property_pkt *pkt, pkt->shdr.hdr.size += sizeof(u32) + sizeof(*hierp); break; } + case HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO: { + struct hfi_uncompressed_plane_actual_info *in = pdata; + struct hfi_uncompressed_plane_actual_info *info = prop_data; + + info->buffer_type = in->buffer_type; + info->num_planes = in->num_planes; + info->plane_format[0] = in->plane_format[0]; + if (in->num_planes > 1) + info->plane_format[1] = in->plane_format[1]; + pkt->shdr.hdr.size += sizeof(u32) + sizeof(*info); + break; + } /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */ case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: @@ -1205,18 +1219,14 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt, pkt->shdr.hdr.size += sizeof(u32) + sizeof(*cu); break; } - case HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO: { - struct hfi_uncompressed_plane_actual_info *in = pdata; - struct hfi_uncompressed_plane_actual_info *info = prop_data; + case HFI_PROPERTY_PARAM_VENC_HDR10_PQ_SEI: { + struct hfi_hdr10_pq_sei *in = pdata, *hdr10 = prop_data; - info->buffer_type = in->buffer_type; - info->num_planes = in->num_planes; - info->plane_format[0] = in->plane_format[0]; - if (in->num_planes > 1) - info->plane_format[1] = in->plane_format[1]; - pkt->shdr.hdr.size += sizeof(u32) + sizeof(*info); + memcpy(hdr10, in, sizeof(*hdr10)); + pkt->shdr.hdr.size += sizeof(u32) + sizeof(*hdr10); break; } + case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE: case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER: case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE: @@ -1249,13 +1259,38 @@ pkt_session_set_property_6xx(struct hfi_session_set_property_pkt *pkt, pkt->data[0] = ptype; switch (ptype) { + case HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO: { + struct hfi_uncompressed_plane_actual_constraints_info *in = pdata; + struct hfi_uncompressed_plane_actual_constraints_info *info = prop_data; + + info->buffer_type = in->buffer_type; + info->num_planes = in->num_planes; + info->plane_format[0] = in->plane_format[0]; + if (in->num_planes > 1) + info->plane_format[1] = in->plane_format[1]; + + pkt->shdr.hdr.size += sizeof(u32) + sizeof(*info); + break; + } case HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY: { struct hfi_heic_frame_quality *in = pdata, *cq = prop_data; cq->frame_quality = in->frame_quality; pkt->shdr.hdr.size += sizeof(u32) + sizeof(*cq); break; - } default: + } + case HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR: { + struct hfi_conceal_color_v4 *color = prop_data; + u32 *in = pdata; + + color->conceal_color_8bit = *in & 0xff; + color->conceal_color_8bit |= ((*in >> 10) & 0xff) << 8; + color->conceal_color_8bit |= ((*in >> 20) & 0xff) << 16; + color->conceal_color_10bit = *in; + pkt->shdr.hdr.size += sizeof(u32) + sizeof(*color); + break; + } + default: return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata); } diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index 6b524c7cde5f..63cd347a62da 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -395,11 +395,14 @@ #define HFI_BUFFER_INTERNAL_PERSIST 0x4 #define HFI_BUFFER_INTERNAL_PERSIST_1 0x5 #define HFI_BUFFER_INTERNAL_SCRATCH(ver) \ - (((ver) == HFI_VERSION_4XX) ? 0x6 : 0x1000001) + (((ver) == HFI_VERSION_4XX || \ + (ver) == HFI_VERSION_6XX) ? 0x6 : 0x1000001) #define HFI_BUFFER_INTERNAL_SCRATCH_1(ver) \ - (((ver) == HFI_VERSION_4XX) ? 0x7 : 0x1000005) + (((ver) == HFI_VERSION_4XX || \ + (ver) == HFI_VERSION_6XX) ? 0x7 : 0x1000005) #define HFI_BUFFER_INTERNAL_SCRATCH_2(ver) \ - (((ver) == HFI_VERSION_4XX) ? 0x8 : 0x1000006) + (((ver) == HFI_VERSION_4XX || \ + (ver) == HFI_VERSION_6XX) ? 0x8 : 0x1000006) #define HFI_BUFFER_EXTRADATA_INPUT(ver) \ (((ver) == HFI_VERSION_4XX) ? 0xc : 0x1000002) #define HFI_BUFFER_EXTRADATA_OUTPUT(ver) \ @@ -513,6 +516,7 @@ #define HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE 0x2005029 #define HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER 0x200502c #define HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE 0x200502f +#define HFI_PROPERTY_PARAM_VENC_HDR10_PQ_SEI 0x2005036 /* * HFI_PROPERTY_CONFIG_VENC_COMMON_START @@ -685,10 +689,20 @@ struct hfi_vc1e_perf_cfg_type { u32 search_range_y_subsampled[3]; }; +/* + * 0 - 7bit -> Luma (def: 16) + * 8 - 15bit -> Chroma (def: 128) + * format is valid up to v4 + */ struct hfi_conceal_color { u32 conceal_color; }; +struct hfi_conceal_color_v4 { + u32 conceal_color_8bit; + u32 conceal_color_10bit; +}; + struct hfi_intra_period { u32 pframes; u32 bframes; @@ -809,6 +823,25 @@ struct hfi_ltr_mark { u32 mark_frame; }; +struct hfi_mastering_display_colour_sei_payload { + u32 display_primaries_x[3]; + u32 display_primaries_y[3]; + u32 white_point_x; + u32 white_point_y; + u32 max_display_mastering_luminance; + u32 min_display_mastering_luminance; +}; + +struct hfi_content_light_level_sei_payload { + u32 max_content_light; + u32 max_pic_average_light; +}; + +struct hfi_hdr10_pq_sei { + struct hfi_mastering_display_colour_sei_payload mastering; + struct hfi_content_light_level_sei_payload cll; +}; + struct hfi_framesize { u32 buffer_type; u32 width; diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index 06a1908ca225..a2d436d407b2 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -6,6 +6,7 @@ #include <linux/hash.h> #include <linux/list.h> #include <linux/slab.h> +#include <linux/soc/qcom/smem.h> #include <media/videobuf2-v4l2.h> #include "core.h" @@ -14,6 +15,10 @@ #include "hfi_msgs.h" #include "hfi_parser.h" +#define SMEM_IMG_VER_TBL 469 +#define VER_STR_SZ 128 +#define SMEM_IMG_OFFSET_VENUS (14 * 128) + static void event_seq_changed(struct venus_core *core, struct venus_inst *inst, struct hfi_msg_event_notify_pkt *pkt) { @@ -239,15 +244,26 @@ static void sys_get_prop_image_version(struct device *dev, struct hfi_msg_sys_property_info_pkt *pkt) { + u8 *smem_tbl_ptr; + u8 *img_ver; int req_bytes; + size_t smem_blk_sz; req_bytes = pkt->hdr.size - sizeof(*pkt); - if (req_bytes < 128 || !pkt->data[1] || pkt->num_properties > 1) + if (req_bytes < VER_STR_SZ || !pkt->data[1] || pkt->num_properties > 1) /* bad packet */ return; - dev_dbg(dev, VDBGL "F/W version: %s\n", (u8 *)&pkt->data[1]); + img_ver = (u8 *)&pkt->data[1]; + + dev_dbg(dev, VDBGL "F/W version: %s\n", img_ver); + + smem_tbl_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY, + SMEM_IMG_VER_TBL, &smem_blk_sz); + if (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); } 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 7263c0c32695..5b8389b98299 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.c +++ b/drivers/media/platform/qcom/venus/hfi_parser.c @@ -235,13 +235,13 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst) u32 enc_codecs, dec_codecs, count = 0; unsigned int entries; - if (inst) - return 0; - plat = hfi_platform_get(core->res->hfi_version); if (!plat) return -EINVAL; + if (inst) + return 0; + if (plat->codecs) plat->codecs(&enc_codecs, &dec_codecs, &count); @@ -277,8 +277,10 @@ u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf, parser_init(inst, &codecs, &domain); - core->codecs_count = 0; - memset(core->caps, 0, sizeof(core->caps)); + if (core->res->hfi_version > HFI_VERSION_1XX) { + core->codecs_count = 0; + memset(core->caps, 0, sizeof(core->caps)); + } while (words_count) { data = word + 1; diff --git a/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c b/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c index d43d1a53e72d..479178b0600d 100644 --- a/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c +++ b/drivers/media/platform/qcom/venus/hfi_plat_bufs_v6.c @@ -40,7 +40,8 @@ #define MAX_TILE_COLUMNS 32 /* 8K/256 */ -#define NUM_HW_PIC_BUF 10 +#define VPP_CMD_MAX_SIZE BIT(20) +#define NUM_HW_PIC_BUF 32 #define BIN_BUFFER_THRESHOLD (1280 * 736) #define H264D_MAX_SLICE 1800 /* sizeof(h264d_buftab_t) aligned to 256 */ @@ -90,6 +91,7 @@ #define SIZE_SLIST_BUF_H264 512 #define LCU_MAX_SIZE_PELS 64 #define LCU_MIN_SIZE_PELS 16 +#define SIZE_SEI_USERDATA 4096 #define H265D_MAX_SLICE 600 #define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T @@ -199,7 +201,7 @@ static inline u32 size_vpxd_lb_se_left_ctrl(u32 width, u32 height) #define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO_DEN 2 #define VP8_NUM_FRAME_INFO_BUF (5 + 1) -#define VP9_NUM_FRAME_INFO_BUF (8 + 2 + 1 + 8) +#define VP9_NUM_FRAME_INFO_BUF 32 #define VP8_NUM_PROBABILITY_TABLE_BUF VP8_NUM_FRAME_INFO_BUF #define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) #define VP8_PROB_TABLE_SIZE 3840 @@ -211,7 +213,7 @@ static inline u32 size_vpxd_lb_se_left_ctrl(u32 width, u32 height) #define QMATRIX_SIZE (sizeof(u32) * 128 + 256) #define MP2D_QPDUMP_SIZE 115200 -#define HFI_IRIS2_ENC_PERSIST_SIZE 102400 +#define HFI_IRIS2_ENC_PERSIST_SIZE 204800 #define HFI_MAX_COL_FRAME 6 #define HFI_VENUS_VENC_TRE_WB_BUFF_SIZE (65 << 4) /* in Bytes */ #define HFI_VENUS_VENC_DB_LINE_BUFF_PER_MB 512 @@ -467,7 +469,7 @@ static u32 hfi_iris2_h264d_comv_size(u32 width, u32 height, { u32 frame_width_in_mbs = ((width + 15) >> 4); u32 frame_height_in_mbs = ((height + 15) >> 4); - u32 col_mv_aligned_width = (frame_width_in_mbs << 6); + u32 col_mv_aligned_width = (frame_width_in_mbs << 7); u32 col_zero_aligned_width = (frame_width_in_mbs << 2); u32 col_zero_size = 0, size_colloc = 0, comv_size = 0; @@ -500,9 +502,14 @@ static u32 size_h264d_bse_cmd_buf(u32 height) static u32 size_h264d_vpp_cmd_buf(u32 height) { u32 aligned_height = ALIGN(height, 32); + u32 size; - return min_t(u32, (((aligned_height + 15) >> 4) * 3 * 4), + size = min_t(u32, (((aligned_height + 15) >> 4) * 3 * 4), H264D_MAX_SLICE) * SIZE_H264D_VPP_CMD_PER_BUF; + if (size > VPP_CMD_MAX_SIZE) + size = VPP_CMD_MAX_SIZE; + + return size; } static u32 hfi_iris2_h264d_non_comv_size(u32 width, u32 height, @@ -559,8 +566,11 @@ static u32 size_h265d_vpp_cmd_buf(u32 width, u32 height) size = min_t(u32, size, H265D_MAX_SLICE + 1); size = ALIGN(size, 4); size = 2 * size * SIZE_H265D_VPP_CMD_PER_BUF; + size = ALIGN(size, HFI_DMA_ALIGNMENT); + if (size > VPP_CMD_MAX_SIZE) + size = VPP_CMD_MAX_SIZE; - return ALIGN(size, HFI_DMA_ALIGNMENT); + return size; } static u32 hfi_iris2_h265d_comv_size(u32 width, u32 height, @@ -1004,8 +1014,8 @@ static u32 enc_persist_size(void) static u32 h264d_persist1_size(void) { - return ALIGN((SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264), - HFI_DMA_ALIGNMENT); + return ALIGN((SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264 + + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA), HFI_DMA_ALIGNMENT); } static u32 h265d_persist1_size(void) @@ -1159,7 +1169,7 @@ static int output_buffer_count(u32 session_type, u32 codec) case V4L2_PIX_FMT_H264: case V4L2_PIX_FMT_HEVC: default: - output_min_count = 8; + output_min_count = 18; break; } } else { @@ -1233,7 +1243,7 @@ static int bufreq_dec(struct hfi_plat_buffers_params *params, u32 buftype, } else if (buftype == HFI_BUFFER_INTERNAL_PERSIST_1) { bufreq->size = dec_ops->persist1(); } else { - return -EINVAL; + bufreq->size = 0; } return 0; @@ -1301,7 +1311,7 @@ static int bufreq_enc(struct hfi_plat_buffers_params *params, u32 buftype, } else if (buftype == HFI_BUFFER_INTERNAL_PERSIST) { bufreq->size = enc_ops->persist(); } else { - return -EINVAL; + bufreq->size = 0; } return 0; diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v6.c b/drivers/media/platform/qcom/venus/hfi_platform_v6.c index 2278be13cb90..dd1a03911b6c 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform_v6.c +++ b/drivers/media/platform/qcom/venus/hfi_platform_v6.c @@ -9,15 +9,15 @@ static const struct hfi_plat_caps caps[] = { .codec = HFI_VIDEO_CODEC_H264, .domain = VIDC_SESSION_TYPE_DEC, .cap_bufs_mode_dynamic = true, - .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 5760, 1}, - .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 5760, 1}, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 1}, /* ((5760 * 2880) / 256) */ - .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 36, 64800, 1}, - .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 200000000, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 220000000, 1}, .caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1}, .caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1}, - .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 36, 1958400, 1}, - .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1}, + .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1}, + .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1}, .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, .num_caps = 9, .pl[0] = {HFI_H264_PROFILE_BASELINE, HFI_H264_LEVEL_52}, @@ -35,15 +35,15 @@ static const struct hfi_plat_caps caps[] = { .codec = HFI_VIDEO_CODEC_HEVC, .domain = VIDC_SESSION_TYPE_DEC, .cap_bufs_mode_dynamic = true, - .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1}, - .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1}, - .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1}, - .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1}, - .caps[4] = {HFI_CAPABILITY_SCALE_X, 4096, 65536, 1}, - .caps[5] = {HFI_CAPABILITY_SCALE_Y, 4096, 65536, 1}, - .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 2073600, 1}, - .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1}, - .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 2, 1}, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 220000000, 1}, + .caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1}, + .caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1}, + .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1}, + .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1}, + .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, .caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1}, .num_caps = 10, .pl[0] = {HFI_HEVC_PROFILE_MAIN, HFI_HEVC_LEVEL_6 | HFI_HEVC_TIER_HIGH0}, @@ -61,15 +61,15 @@ static const struct hfi_plat_caps caps[] = { .codec = HFI_VIDEO_CODEC_VP8, .domain = VIDC_SESSION_TYPE_DEC, .cap_bufs_mode_dynamic = true, - .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1}, - .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1}, - .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1}, - .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1}, - .caps[4] = {HFI_CAPABILITY_SCALE_X, 4096, 65536, 1}, - .caps[5] = {HFI_CAPABILITY_SCALE_Y, 4096, 65536, 1}, - .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 2073600, 1}, - .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1}, - .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 2, 1}, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 4096, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 4096, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 36864, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 100000000, 1}, + .caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1}, + .caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1}, + .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 4423680, 1}, + .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1}, + .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, .caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1}, .num_caps = 10, .pl[0] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_0}, @@ -86,15 +86,15 @@ static const struct hfi_plat_caps caps[] = { .codec = HFI_VIDEO_CODEC_VP9, .domain = VIDC_SESSION_TYPE_DEC, .cap_bufs_mode_dynamic = true, - .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1}, - .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1}, - .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1}, - .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1}, - .caps[4] = {HFI_CAPABILITY_SCALE_X, 4096, 65536, 1}, - .caps[5] = {HFI_CAPABILITY_SCALE_Y, 4096, 65536, 1}, - .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 2073600, 1}, - .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1}, - .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 2, 1}, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 220000000, 1}, + .caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1}, + .caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1}, + .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1}, + .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1}, + .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, .caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1}, .num_caps = 10, .pl[0] = {HFI_VP9_PROFILE_P0, 200}, @@ -112,15 +112,15 @@ static const struct hfi_plat_caps caps[] = { .codec = HFI_VIDEO_CODEC_MPEG2, .domain = VIDC_SESSION_TYPE_DEC, .cap_bufs_mode_dynamic = true, - .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 1920, 1}, - .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 1920, 1}, - .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 8160, 1}, + .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, 40000000, 1}, - .caps[4] = {HFI_CAPABILITY_SCALE_X, 4096, 65536, 1}, - .caps[5] = {HFI_CAPABILITY_SCALE_Y, 4096, 65536, 1}, - .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 244800, 1}, + .caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1}, + .caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1}, + .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1}, .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 30, 1}, - .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 2, 1}, + .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, .caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 1, 1}, .num_caps = 10, .pl[0] = {HFI_MPEG2_PROFILE_SIMPLE, HFI_MPEG2_LEVEL_H14}, @@ -135,21 +135,21 @@ static const struct hfi_plat_caps caps[] = { .codec = HFI_VIDEO_CODEC_H264, .domain = VIDC_SESSION_TYPE_ENC, .cap_bufs_mode_dynamic = true, - .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 16}, - .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 16}, - .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1}, - .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1}, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 1}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 1}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 220000000, 1}, .caps[4] = {HFI_CAPABILITY_SCALE_X, 8192, 65536, 1}, .caps[5] = {HFI_CAPABILITY_SCALE_Y, 8192, 65536, 1}, - .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 1036800, 1}, - .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1}, - .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 3, 1}, + .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1}, + .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1}, + .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, .caps[9] = {HFI_CAPABILITY_PEAKBITRATE, 32000, 160000000, 1}, - .caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 5, 1}, - .caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 4, 1}, + .caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 6, 1}, + .caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 2, 1}, .caps[12] = {HFI_CAPABILITY_LCU_SIZE, 16, 16, 1}, .caps[13] = {HFI_CAPABILITY_BFRAME, 0, 1, 1}, - .caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 5, 1}, + .caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 6, 1}, .caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 51, 1}, .caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 51, 1}, .caps[17] = {HFI_CAPABILITY_B_FRAME_QP, 0, 51, 1}, @@ -172,24 +172,24 @@ static const struct hfi_plat_caps caps[] = { .codec = HFI_VIDEO_CODEC_HEVC, .domain = VIDC_SESSION_TYPE_ENC, .cap_bufs_mode_dynamic = true, - .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 16}, - .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 16}, - .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1}, - .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1}, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 16}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 16}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 160000000, 1}, .caps[4] = {HFI_CAPABILITY_SCALE_X, 8192, 65536, 1}, .caps[5] = {HFI_CAPABILITY_SCALE_Y, 8192, 65536, 1}, - .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 1036800, 1}, - .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1}, - .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 3, 1}, + .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1}, + .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1}, + .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, .caps[9] = {HFI_CAPABILITY_PEAKBITRATE, 32000, 160000000, 1}, .caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 5, 1}, - .caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 4, 1}, + .caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 2, 1}, .caps[12] = {HFI_CAPABILITY_LCU_SIZE, 32, 32, 1}, .caps[13] = {HFI_CAPABILITY_BFRAME, 0, 1, 1}, .caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 5, 1}, - .caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 63, 1}, - .caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 63, 1}, - .caps[17] = {HFI_CAPABILITY_B_FRAME_QP, 0, 63, 1}, + .caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 51, 1}, + .caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 51, 1}, + .caps[17] = {HFI_CAPABILITY_B_FRAME_QP, 0, 51, 1}, .caps[18] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 2, 1}, .caps[19] = {HFI_CAPABILITY_RATE_CONTROL_MODES, 0x1000001, 0x1000005, 1}, .caps[20] = {HFI_CAPABILITY_COLOR_SPACE_CONVERSION, 0, 2, 1}, @@ -209,20 +209,20 @@ static const struct hfi_plat_caps caps[] = { .codec = HFI_VIDEO_CODEC_VP8, .domain = VIDC_SESSION_TYPE_ENC, .cap_bufs_mode_dynamic = true, - .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 16}, - .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 16}, - .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1}, - .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1}, + .caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 4096, 16}, + .caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 4096, 16}, + .caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 36864, 1}, + .caps[3] = {HFI_CAPABILITY_BITRATE, 1, 74000000, 1}, .caps[4] = {HFI_CAPABILITY_SCALE_X, 8192, 65536, 1}, .caps[5] = {HFI_CAPABILITY_SCALE_Y, 8192, 65536, 1}, - .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 1036800, 1}, - .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 240, 1}, - .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 3, 1}, + .caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 4423680, 1}, + .caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1}, + .caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1}, .caps[9] = {HFI_CAPABILITY_PEAKBITRATE, 32000, 160000000, 1}, .caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 3, 1}, .caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 2, 1}, .caps[12] = {HFI_CAPABILITY_LCU_SIZE, 16, 16, 1}, - .caps[13] = {HFI_CAPABILITY_BFRAME, 0, 1, 1}, + .caps[13] = {HFI_CAPABILITY_BFRAME, 0, 0, 1}, .caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 5, 1}, .caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 127, 1}, .caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 127, 1}, diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 50e03f8fc278..ce98c523b3c6 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -345,16 +345,6 @@ static void venus_free(struct venus_hfi_device *hdev, struct mem_desc *mem) dma_free_attrs(dev, mem->size, mem->kva, mem->da, mem->attrs); } -static void venus_writel(struct venus_hfi_device *hdev, u32 reg, u32 value) -{ - writel(value, hdev->core->base + reg); -} - -static u32 venus_readl(struct venus_hfi_device *hdev, u32 reg) -{ - return readl(hdev->core->base + reg); -} - static void venus_set_registers(struct venus_hfi_device *hdev) { const struct venus_resources *res = hdev->core->res; @@ -363,12 +353,20 @@ static void venus_set_registers(struct venus_hfi_device *hdev) unsigned int i; for (i = 0; i < count; i++) - venus_writel(hdev, tbl[i].reg, tbl[i].value); + writel(tbl[i].value, hdev->core->base + tbl[i].reg); } static void venus_soft_int(struct venus_hfi_device *hdev) { - venus_writel(hdev, CPU_IC_SOFTINT, BIT(CPU_IC_SOFTINT_H2A_SHIFT)); + void __iomem *cpu_ic_base = hdev->core->cpu_ic_base; + u32 clear_bit; + + if (IS_V6(hdev->core)) + clear_bit = BIT(CPU_IC_SOFTINT_H2A_SHIFT_V6); + else + clear_bit = BIT(CPU_IC_SOFTINT_H2A_SHIFT); + + writel(clear_bit, cpu_ic_base + CPU_IC_SOFTINT); } static int venus_iface_cmdq_write_nolock(struct venus_hfi_device *hdev, @@ -450,16 +448,25 @@ static int venus_boot_core(struct venus_hfi_device *hdev) { struct device *dev = hdev->core->dev; static const unsigned int max_tries = 100; - u32 ctrl_status = 0; + u32 ctrl_status = 0, mask_val; unsigned int count = 0; + void __iomem *cpu_cs_base = hdev->core->cpu_cs_base; + void __iomem *wrapper_base = hdev->core->wrapper_base; int ret = 0; - venus_writel(hdev, VIDC_CTRL_INIT, BIT(VIDC_CTRL_INIT_CTRL_SHIFT)); - venus_writel(hdev, WRAPPER_INTR_MASK, WRAPPER_INTR_MASK_A2HVCODEC_MASK); - venus_writel(hdev, CPU_CS_SCIACMDARG3, 1); + writel(BIT(VIDC_CTRL_INIT_CTRL_SHIFT), cpu_cs_base + VIDC_CTRL_INIT); + if (IS_V6(hdev->core)) { + mask_val = readl(wrapper_base + WRAPPER_INTR_MASK); + mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BASK_V6 | + WRAPPER_INTR_MASK_A2HCPU_MASK); + } else { + mask_val = WRAPPER_INTR_MASK_A2HVCODEC_MASK; + } + writel(mask_val, wrapper_base + WRAPPER_INTR_MASK); + writel(1, cpu_cs_base + CPU_CS_SCIACMDARG3); while (!ctrl_status && count < max_tries) { - ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0); + ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0); if ((ctrl_status & CPU_CS_SCIACMDARG0_ERROR_STATUS_MASK) == 4) { dev_err(dev, "invalid setting for UC_REGION\n"); ret = -EINVAL; @@ -473,15 +480,22 @@ static int venus_boot_core(struct venus_hfi_device *hdev) if (count >= max_tries) ret = -ETIMEDOUT; + if (IS_V6(hdev->core)) { + writel(0x1, cpu_cs_base + CPU_CS_H2XSOFTINTEN_V6); + writel(0x0, cpu_cs_base + CPU_CS_X2RPMH_V6); + } + return ret; } static u32 venus_hwversion(struct venus_hfi_device *hdev) { struct device *dev = hdev->core->dev; - u32 ver = venus_readl(hdev, WRAPPER_HW_VERSION); + void __iomem *wrapper_base = hdev->core->wrapper_base; + u32 ver; u32 major, minor, step; + ver = readl(wrapper_base + WRAPPER_HW_VERSION); major = ver & WRAPPER_HW_VERSION_MAJOR_VERSION_MASK; major = major >> WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT; minor = ver & WRAPPER_HW_VERSION_MINOR_VERSION_MASK; @@ -496,6 +510,7 @@ static u32 venus_hwversion(struct venus_hfi_device *hdev) static int venus_run(struct venus_hfi_device *hdev) { struct device *dev = hdev->core->dev; + void __iomem *cpu_cs_base = hdev->core->cpu_cs_base; int ret; /* @@ -504,12 +519,12 @@ static int venus_run(struct venus_hfi_device *hdev) */ venus_set_registers(hdev); - venus_writel(hdev, UC_REGION_ADDR, hdev->ifaceq_table.da); - venus_writel(hdev, UC_REGION_SIZE, SHARED_QSIZE); - venus_writel(hdev, CPU_CS_SCIACMDARG2, hdev->ifaceq_table.da); - venus_writel(hdev, CPU_CS_SCIACMDARG1, 0x01); + writel(hdev->ifaceq_table.da, cpu_cs_base + UC_REGION_ADDR); + writel(SHARED_QSIZE, cpu_cs_base + UC_REGION_SIZE); + writel(hdev->ifaceq_table.da, cpu_cs_base + CPU_CS_SCIACMDARG2); + writel(0x01, cpu_cs_base + CPU_CS_SCIACMDARG1); if (hdev->sfr.da) - venus_writel(hdev, SFR_ADDR, hdev->sfr.da); + writel(hdev->sfr.da, cpu_cs_base + SFR_ADDR); ret = venus_boot_core(hdev); if (ret) { @@ -524,17 +539,50 @@ static int venus_run(struct venus_hfi_device *hdev) static int venus_halt_axi(struct venus_hfi_device *hdev) { - void __iomem *base = hdev->core->base; + void __iomem *wrapper_base = hdev->core->wrapper_base; + void __iomem *vbif_base = hdev->core->vbif_base; + void __iomem *cpu_cs_base = hdev->core->cpu_cs_base; + void __iomem *aon_base = hdev->core->aon_base; struct device *dev = hdev->core->dev; u32 val; + u32 mask_val; int ret; + if (IS_V6(hdev->core)) { + writel(0x3, cpu_cs_base + CPU_CS_X2RPMH_V6); + + writel(0x1, aon_base + AON_WRAPPER_MVP_NOC_LPI_CONTROL); + ret = readl_poll_timeout(aon_base + AON_WRAPPER_MVP_NOC_LPI_STATUS, + val, + val & BIT(0), + POLL_INTERVAL_US, + VBIF_AXI_HALT_ACK_TIMEOUT_US); + if (ret) + return -ETIMEDOUT; + + mask_val = (BIT(2) | BIT(1) | BIT(0)); + writel(mask_val, wrapper_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_V6); + + writel(0x00, wrapper_base + WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_V6); + ret = readl_poll_timeout(wrapper_base + WRAPPER_DEBUG_BRIDGE_LPI_STATUS_V6, + val, + val == 0, + POLL_INTERVAL_US, + VBIF_AXI_HALT_ACK_TIMEOUT_US); + + if (ret) { + dev_err(dev, "DBLP Release: lpi_status %x\n", val); + return -ETIMEDOUT; + } + return 0; + } + if (IS_V4(hdev->core)) { - val = venus_readl(hdev, WRAPPER_CPU_AXI_HALT); + val = readl(wrapper_base + WRAPPER_CPU_AXI_HALT); val |= WRAPPER_CPU_AXI_HALT_HALT; - venus_writel(hdev, WRAPPER_CPU_AXI_HALT, val); + writel(val, wrapper_base + WRAPPER_CPU_AXI_HALT); - ret = readl_poll_timeout(base + WRAPPER_CPU_AXI_HALT_STATUS, + ret = readl_poll_timeout(wrapper_base + WRAPPER_CPU_AXI_HALT_STATUS, val, val & WRAPPER_CPU_AXI_HALT_STATUS_IDLE, POLL_INTERVAL_US, @@ -548,12 +596,12 @@ static int venus_halt_axi(struct venus_hfi_device *hdev) } /* Halt AXI and AXI IMEM VBIF Access */ - val = venus_readl(hdev, VBIF_AXI_HALT_CTRL0); + val = readl(vbif_base + VBIF_AXI_HALT_CTRL0); val |= VBIF_AXI_HALT_CTRL0_HALT_REQ; - venus_writel(hdev, VBIF_AXI_HALT_CTRL0, val); + writel(val, vbif_base + VBIF_AXI_HALT_CTRL0); /* Request for AXI bus port halt */ - ret = readl_poll_timeout(base + VBIF_AXI_HALT_CTRL1, val, + ret = readl_poll_timeout(vbif_base + VBIF_AXI_HALT_CTRL1, val, val & VBIF_AXI_HALT_CTRL1_HALT_ACK, POLL_INTERVAL_US, VBIF_AXI_HALT_ACK_TIMEOUT_US); @@ -881,7 +929,7 @@ static int venus_sys_set_default_properties(struct venus_hfi_device *hdev) * enable it explicitly in order to make suspend functional by checking * WFI (wait-for-interrupt) bit. */ - if (IS_V4(hdev->core)) + if (IS_V4(hdev->core) || IS_V6(hdev->core)) venus_sys_idle_indicator = true; ret = venus_sys_set_idle_message(hdev, venus_sys_idle_indicator); @@ -1046,19 +1094,30 @@ static irqreturn_t venus_isr(struct venus_core *core) { struct venus_hfi_device *hdev = to_hfi_priv(core); u32 status; + void __iomem *cpu_cs_base; + void __iomem *wrapper_base; if (!hdev) return IRQ_NONE; - status = venus_readl(hdev, WRAPPER_INTR_STATUS); - - if (status & WRAPPER_INTR_STATUS_A2H_MASK || - status & WRAPPER_INTR_STATUS_A2HWD_MASK || - status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK) - hdev->irq_status = status; + cpu_cs_base = hdev->core->cpu_cs_base; + wrapper_base = hdev->core->wrapper_base; - venus_writel(hdev, CPU_CS_A2HSOFTINTCLR, 1); - venus_writel(hdev, WRAPPER_INTR_CLEAR, status); + status = readl(wrapper_base + WRAPPER_INTR_STATUS); + if (IS_V6(core)) { + if (status & WRAPPER_INTR_STATUS_A2H_MASK || + status & WRAPPER_INTR_STATUS_A2HWD_MASK_V6 || + status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK) + hdev->irq_status = status; + } else { + if (status & WRAPPER_INTR_STATUS_A2H_MASK || + status & WRAPPER_INTR_STATUS_A2HWD_MASK || + status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK) + hdev->irq_status = status; + } + writel(1, cpu_cs_base + CPU_CS_A2HSOFTINTCLR); + if (!IS_V6(core)) + writel(status, wrapper_base + WRAPPER_INTR_CLEAR); return IRQ_WAKE_THREAD; } @@ -1391,6 +1450,7 @@ static int venus_suspend_1xx(struct venus_core *core) { struct venus_hfi_device *hdev = to_hfi_priv(core); struct device *dev = core->dev; + void __iomem *cpu_cs_base = hdev->core->cpu_cs_base; u32 ctrl_status; int ret; @@ -1425,7 +1485,7 @@ static int venus_suspend_1xx(struct venus_core *core) return -EINVAL; } - ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0); + ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0); if (!(ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)) { mutex_unlock(&hdev->lock); return -EINVAL; @@ -1446,10 +1506,16 @@ static int venus_suspend_1xx(struct venus_core *core) static bool venus_cpu_and_video_core_idle(struct venus_hfi_device *hdev) { + void __iomem *wrapper_base = hdev->core->wrapper_base; + void __iomem *wrapper_tz_base = hdev->core->wrapper_tz_base; + void __iomem *cpu_cs_base = hdev->core->cpu_cs_base; u32 ctrl_status, cpu_status; - cpu_status = venus_readl(hdev, WRAPPER_CPU_STATUS); - ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0); + if (IS_V6(hdev->core)) + cpu_status = readl(wrapper_tz_base + WRAPPER_TZ_CPU_STATUS_V6); + else + cpu_status = readl(wrapper_base + WRAPPER_CPU_STATUS); + ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0); if (cpu_status & WRAPPER_CPU_STATUS_WFI && ctrl_status & CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK) @@ -1460,10 +1526,16 @@ static bool venus_cpu_and_video_core_idle(struct venus_hfi_device *hdev) static bool venus_cpu_idle_and_pc_ready(struct venus_hfi_device *hdev) { + void __iomem *wrapper_base = hdev->core->wrapper_base; + void __iomem *wrapper_tz_base = hdev->core->wrapper_tz_base; + void __iomem *cpu_cs_base = hdev->core->cpu_cs_base; u32 ctrl_status, cpu_status; - cpu_status = venus_readl(hdev, WRAPPER_CPU_STATUS); - ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0); + if (IS_V6(hdev->core)) + cpu_status = readl(wrapper_tz_base + WRAPPER_TZ_CPU_STATUS_V6); + else + cpu_status = readl(wrapper_base + WRAPPER_CPU_STATUS); + ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0); if (cpu_status & WRAPPER_CPU_STATUS_WFI && ctrl_status & CPU_CS_SCIACMDARG0_PC_READY) @@ -1476,6 +1548,7 @@ static int venus_suspend_3xx(struct venus_core *core) { struct venus_hfi_device *hdev = to_hfi_priv(core); struct device *dev = core->dev; + void __iomem *cpu_cs_base = hdev->core->cpu_cs_base; u32 ctrl_status; bool val; int ret; @@ -1492,7 +1565,7 @@ static int venus_suspend_3xx(struct venus_core *core) return -EINVAL; } - ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0); + ctrl_status = readl(cpu_cs_base + CPU_CS_SCIACMDARG0); if (ctrl_status & CPU_CS_SCIACMDARG0_PC_READY) goto power_off; @@ -1539,7 +1612,7 @@ power_off: static int venus_suspend(struct venus_core *core) { - if (IS_V3(core) || IS_V4(core)) + if (IS_V3(core) || IS_V4(core) || IS_V6(core)) return venus_suspend_3xx(core); return venus_suspend_1xx(core); @@ -1580,10 +1653,10 @@ void venus_hfi_destroy(struct venus_core *core) { struct venus_hfi_device *hdev = to_hfi_priv(core); + core->priv = NULL; venus_interface_queues_release(hdev); mutex_destroy(&hdev->lock); kfree(hdev); - core->priv = NULL; core->ops = NULL; } diff --git a/drivers/media/platform/qcom/venus/hfi_venus_io.h b/drivers/media/platform/qcom/venus/hfi_venus_io.h index 3b52f98478db..300c6e47e72f 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus_io.h +++ b/drivers/media/platform/qcom/venus/hfi_venus_io.h @@ -8,27 +8,31 @@ #define VBIF_BASE 0x80000 -#define VBIF_AXI_HALT_CTRL0 (VBIF_BASE + 0x208) -#define VBIF_AXI_HALT_CTRL1 (VBIF_BASE + 0x20c) +#define VBIF_AXI_HALT_CTRL0 0x208 +#define VBIF_AXI_HALT_CTRL1 0x20c #define VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0) #define VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0) #define VBIF_AXI_HALT_ACK_TIMEOUT_US 500000 #define CPU_BASE 0xc0000 + #define CPU_CS_BASE (CPU_BASE + 0x12000) #define CPU_IC_BASE (CPU_BASE + 0x1f000) +#define CPU_BASE_V6 0xa0000 +#define CPU_CS_BASE_V6 CPU_BASE_V6 +#define CPU_IC_BASE_V6 (CPU_BASE_V6 + 0x138) -#define CPU_CS_A2HSOFTINTCLR (CPU_CS_BASE + 0x1c) +#define CPU_CS_A2HSOFTINTCLR 0x1c -#define VIDC_CTRL_INIT (CPU_CS_BASE + 0x48) +#define VIDC_CTRL_INIT 0x48 #define VIDC_CTRL_INIT_RESERVED_BITS31_1_MASK 0xfffffffe #define VIDC_CTRL_INIT_RESERVED_BITS31_1_SHIFT 1 #define VIDC_CTRL_INIT_CTRL_MASK 0x1 #define VIDC_CTRL_INIT_CTRL_SHIFT 0 /* HFI control status */ -#define CPU_CS_SCIACMDARG0 (CPU_CS_BASE + 0x4c) +#define CPU_CS_SCIACMDARG0 0x4c #define CPU_CS_SCIACMDARG0_MASK 0xff #define CPU_CS_SCIACMDARG0_SHIFT 0x0 #define CPU_CS_SCIACMDARG0_ERROR_STATUS_MASK 0xfe @@ -39,42 +43,56 @@ #define CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK BIT(30) /* HFI queue table info */ -#define CPU_CS_SCIACMDARG1 (CPU_CS_BASE + 0x50) +#define CPU_CS_SCIACMDARG1 0x50 /* HFI queue table address */ -#define CPU_CS_SCIACMDARG2 (CPU_CS_BASE + 0x54) +#define CPU_CS_SCIACMDARG2 0x54 /* Venus cpu */ -#define CPU_CS_SCIACMDARG3 (CPU_CS_BASE + 0x58) - -#define SFR_ADDR (CPU_CS_BASE + 0x5c) -#define MMAP_ADDR (CPU_CS_BASE + 0x60) -#define UC_REGION_ADDR (CPU_CS_BASE + 0x64) -#define UC_REGION_SIZE (CPU_CS_BASE + 0x68) - -#define CPU_IC_SOFTINT (CPU_IC_BASE + 0x18) +#define CPU_CS_SCIACMDARG3 0x58 + +#define SFR_ADDR 0x5c +#define MMAP_ADDR 0x60 +#define UC_REGION_ADDR 0x64 +#define UC_REGION_SIZE 0x68 + +#define CPU_CS_H2XSOFTINTEN_V6 0x148 + +#define CPU_CS_X2RPMH_V6 0x168 +#define CPU_CS_X2RPMH_MASK0_BMSK_V6 0x1 +#define CPU_CS_X2RPMH_MASK0_SHFT_V6 0x0 +#define CPU_CS_X2RPMH_MASK1_BMSK_V6 0x2 +#define CPU_CS_X2RPMH_MASK1_SHFT_V6 0x1 +#define CPU_CS_X2RPMH_SWOVERRIDE_BMSK_V6 0x4 +#define CPU_CS_X2RPMH_SWOVERRIDE_SHFT_V6 0x3 + +/* Relative to CPU_IC_BASE */ +#define CPU_IC_SOFTINT 0x18 +#define CPU_IC_SOFTINT_V6 0x150 #define CPU_IC_SOFTINT_H2A_MASK 0x8000 #define CPU_IC_SOFTINT_H2A_SHIFT 0xf +#define CPU_IC_SOFTINT_H2A_SHIFT_V6 0x0 /* Venus wrapper */ +#define WRAPPER_BASE_V6 0x000b0000 #define WRAPPER_BASE 0x000e0000 -#define WRAPPER_HW_VERSION (WRAPPER_BASE + 0x00) +#define WRAPPER_HW_VERSION 0x00 #define WRAPPER_HW_VERSION_MAJOR_VERSION_MASK 0x78000000 #define WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT 28 #define WRAPPER_HW_VERSION_MINOR_VERSION_MASK 0xfff0000 #define WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT 16 #define WRAPPER_HW_VERSION_STEP_VERSION_MASK 0xffff -#define WRAPPER_CLOCK_CONFIG (WRAPPER_BASE + 0x04) +#define WRAPPER_CLOCK_CONFIG 0x04 -#define WRAPPER_INTR_STATUS (WRAPPER_BASE + 0x0c) +#define WRAPPER_INTR_STATUS 0x0c #define WRAPPER_INTR_STATUS_A2HWD_MASK 0x10 #define WRAPPER_INTR_STATUS_A2HWD_SHIFT 0x4 #define WRAPPER_INTR_STATUS_A2H_MASK 0x4 #define WRAPPER_INTR_STATUS_A2H_SHIFT 0x2 -#define WRAPPER_INTR_MASK (WRAPPER_BASE + 0x10) +#define WRAPPER_INTR_MASK 0x10 #define WRAPPER_INTR_MASK_A2HWD_BASK 0x10 #define WRAPPER_INTR_MASK_A2HWD_SHIFT 0x4 #define WRAPPER_INTR_MASK_A2HVCODEC_MASK 0x8 @@ -82,41 +100,59 @@ #define WRAPPER_INTR_MASK_A2HCPU_MASK 0x4 #define WRAPPER_INTR_MASK_A2HCPU_SHIFT 0x2 -#define WRAPPER_INTR_CLEAR (WRAPPER_BASE + 0x14) +#define WRAPPER_INTR_STATUS_A2HWD_MASK_V6 0x8 +#define WRAPPER_INTR_MASK_A2HWD_BASK_V6 0x8 + +#define WRAPPER_INTR_CLEAR 0x14 #define WRAPPER_INTR_CLEAR_A2HWD_MASK 0x10 #define WRAPPER_INTR_CLEAR_A2HWD_SHIFT 0x4 #define WRAPPER_INTR_CLEAR_A2H_MASK 0x4 #define WRAPPER_INTR_CLEAR_A2H_SHIFT 0x2 -#define WRAPPER_POWER_STATUS (WRAPPER_BASE + 0x44) -#define WRAPPER_VDEC_VCODEC_POWER_CONTROL (WRAPPER_BASE + 0x48) -#define WRAPPER_VENC_VCODEC_POWER_CONTROL (WRAPPER_BASE + 0x4c) -#define WRAPPER_VDEC_VENC_AHB_BRIDGE_SYNC_RESET (WRAPPER_BASE + 0x64) +#define WRAPPER_POWER_STATUS 0x44 +#define WRAPPER_VDEC_VCODEC_POWER_CONTROL 0x48 +#define WRAPPER_VENC_VCODEC_POWER_CONTROL 0x4c +#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_V6 0x54 +#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS_V6 0x58 +#define WRAPPER_VDEC_VENC_AHB_BRIDGE_SYNC_RESET 0x64 -#define WRAPPER_CPU_CLOCK_CONFIG (WRAPPER_BASE + 0x2000) -#define WRAPPER_CPU_AXI_HALT (WRAPPER_BASE + 0x2008) +#define WRAPPER_CPU_CLOCK_CONFIG 0x2000 +#define WRAPPER_CPU_AXI_HALT 0x2008 #define WRAPPER_CPU_AXI_HALT_HALT BIT(16) -#define WRAPPER_CPU_AXI_HALT_STATUS (WRAPPER_BASE + 0x200c) +#define WRAPPER_CPU_AXI_HALT_STATUS 0x200c #define WRAPPER_CPU_AXI_HALT_STATUS_IDLE BIT(24) -#define WRAPPER_CPU_CGC_DIS (WRAPPER_BASE + 0x2010) -#define WRAPPER_CPU_STATUS (WRAPPER_BASE + 0x2014) +#define WRAPPER_CPU_CGC_DIS 0x2010 +#define WRAPPER_CPU_STATUS 0x2014 #define WRAPPER_CPU_STATUS_WFI BIT(0) -#define WRAPPER_SW_RESET (WRAPPER_BASE + 0x3000) -#define WRAPPER_CPA_START_ADDR (WRAPPER_BASE + 0x1020) -#define WRAPPER_CPA_END_ADDR (WRAPPER_BASE + 0x1024) -#define WRAPPER_FW_START_ADDR (WRAPPER_BASE + 0x1028) -#define WRAPPER_FW_END_ADDR (WRAPPER_BASE + 0x102C) -#define WRAPPER_NONPIX_START_ADDR (WRAPPER_BASE + 0x1030) -#define WRAPPER_NONPIX_END_ADDR (WRAPPER_BASE + 0x1034) -#define WRAPPER_A9SS_SW_RESET (WRAPPER_BASE + 0x3000) +#define WRAPPER_SW_RESET 0x3000 +#define WRAPPER_CPA_START_ADDR 0x1020 +#define WRAPPER_CPA_END_ADDR 0x1024 +#define WRAPPER_FW_START_ADDR 0x1028 +#define WRAPPER_FW_END_ADDR 0x102C +#define WRAPPER_NONPIX_START_ADDR 0x1030 +#define WRAPPER_NONPIX_END_ADDR 0x1034 +#define WRAPPER_A9SS_SW_RESET 0x3000 #define WRAPPER_A9SS_SW_RESET_BIT BIT(4) /* Venus 4xx */ -#define WRAPPER_VCODEC0_MMCC_POWER_STATUS (WRAPPER_BASE + 0x90) -#define WRAPPER_VCODEC0_MMCC_POWER_CONTROL (WRAPPER_BASE + 0x94) +#define WRAPPER_VCODEC0_MMCC_POWER_STATUS 0x90 +#define WRAPPER_VCODEC0_MMCC_POWER_CONTROL 0x94 + +#define WRAPPER_VCODEC1_MMCC_POWER_STATUS 0x110 +#define WRAPPER_VCODEC1_MMCC_POWER_CONTROL 0x114 + +/* Venus 6xx */ +#define WRAPPER_CORE_POWER_STATUS_V6 0x80 +#define WRAPPER_CORE_POWER_CONTROL_V6 0x84 + +/* Wrapper TZ 6xx */ +#define WRAPPER_TZ_BASE_V6 0x000c0000 +#define WRAPPER_TZ_CPU_STATUS_V6 0x10 -#define WRAPPER_VCODEC1_MMCC_POWER_STATUS (WRAPPER_BASE + 0x110) -#define WRAPPER_VCODEC1_MMCC_POWER_CONTROL (WRAPPER_BASE + 0x114) +/* Venus AON */ +#define AON_BASE_V6 0x000e0000 +#define AON_WRAPPER_MVP_NOC_LPI_CONTROL 0x00 +#define AON_WRAPPER_MVP_NOC_LPI_STATUS 0x04 #endif diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 43c4e3d9e281..c7e1ebec47ee 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -11,6 +11,7 @@ #include <linux/pm_domain.h> #include <linux/pm_opp.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/types.h> #include <media/v4l2-mem2mem.h> @@ -40,10 +41,24 @@ static int core_clks_get(struct venus_core *core) static int core_clks_enable(struct venus_core *core) { const struct venus_resources *res = core->res; + const struct freq_tbl *freq_tbl = core->res->freq_tbl; + unsigned int freq_tbl_size = core->res->freq_tbl_size; + unsigned long freq; unsigned int i; int ret; + if (!freq_tbl) + return -EINVAL; + + freq = freq_tbl[freq_tbl_size - 1].freq; + for (i = 0; i < res->clks_num; i++) { + if (IS_V6(core)) { + ret = clk_set_rate(core->clks[i], freq); + if (ret) + goto err; + } + ret = clk_prepare_enable(core->clks[i]); if (ret) goto err; @@ -186,7 +201,7 @@ static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak) return; for (i = 0; i < num_rows; i++) { - if (mbs > bw_tbl[i].mbs_per_sec) + if (i != 0 && mbs > bw_tbl[i].mbs_per_sec) break; if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) { @@ -277,16 +292,28 @@ set_freq: return 0; } -static int core_get_v1(struct device *dev) +static int core_get_v1(struct venus_core *core) { - struct venus_core *core = dev_get_drvdata(dev); + int ret; + + ret = core_clks_get(core); + if (ret) + return ret; + + core->opp_table = dev_pm_opp_set_clkname(core->dev, "core"); + if (IS_ERR(core->opp_table)) + return PTR_ERR(core->opp_table); - return core_clks_get(core); + return 0; } -static int core_power_v1(struct device *dev, int on) +static void core_put_v1(struct venus_core *core) +{ + dev_pm_opp_put_clkname(core->opp_table); +} + +static int core_power_v1(struct venus_core *core, int on) { - struct venus_core *core = dev_get_drvdata(dev); int ret = 0; if (on == POWER_ON) @@ -299,6 +326,7 @@ static int core_power_v1(struct device *dev, int on) static const struct venus_pm_ops pm_ops_v1 = { .core_get = core_get_v1, + .core_put = core_put_v1, .core_power = core_power_v1, .load_scale = load_scale_v1, }; @@ -309,9 +337,9 @@ vcodec_control_v3(struct venus_core *core, u32 session_type, bool enable) void __iomem *ctrl; if (session_type == VIDC_SESSION_TYPE_DEC) - ctrl = core->base + WRAPPER_VDEC_VCODEC_POWER_CONTROL; + ctrl = core->wrapper_base + WRAPPER_VDEC_VCODEC_POWER_CONTROL; else - ctrl = core->base + WRAPPER_VENC_VCODEC_POWER_CONTROL; + ctrl = core->wrapper_base + WRAPPER_VENC_VCODEC_POWER_CONTROL; if (enable) writel(0, ctrl); @@ -371,6 +399,7 @@ static int venc_power_v3(struct device *dev, int on) static const struct venus_pm_ops pm_ops_v3 = { .core_get = core_get_v1, + .core_put = core_put_v1, .core_power = core_power_v1, .vdec_get = vdec_get_v3, .vdec_power = vdec_power_v3, @@ -385,12 +414,15 @@ static int vcodec_control_v4(struct venus_core *core, u32 coreid, bool enable) u32 val; int ret; - if (coreid == VIDC_CORE_ID_1) { - ctrl = core->base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL; - stat = core->base + WRAPPER_VCODEC0_MMCC_POWER_STATUS; + if (IS_V6(core)) { + ctrl = core->wrapper_base + WRAPPER_CORE_POWER_CONTROL_V6; + stat = core->wrapper_base + WRAPPER_CORE_POWER_STATUS_V6; + } else if (coreid == VIDC_CORE_ID_1) { + ctrl = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_CONTROL; + stat = core->wrapper_base + WRAPPER_VCODEC0_MMCC_POWER_STATUS; } else { - ctrl = core->base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL; - stat = core->base + WRAPPER_VCODEC1_MMCC_POWER_STATUS; + ctrl = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_CONTROL; + stat = core->wrapper_base + WRAPPER_VCODEC1_MMCC_POWER_STATUS; } if (enable) { @@ -753,12 +785,12 @@ static int venc_power_v4(struct device *dev, int on) return ret; } -static int vcodec_domains_get(struct device *dev) +static int vcodec_domains_get(struct venus_core *core) { int ret; struct opp_table *opp_table; struct device **opp_virt_dev; - struct venus_core *core = dev_get_drvdata(dev); + struct device *dev = core->dev; const struct venus_resources *res = core->res; struct device *pd; unsigned int i; @@ -809,9 +841,8 @@ opp_attach_err: return ret; } -static void vcodec_domains_put(struct device *dev) +static void vcodec_domains_put(struct venus_core *core) { - struct venus_core *core = dev_get_drvdata(dev); const struct venus_resources *res = core->res; unsigned int i; @@ -834,9 +865,55 @@ skip_pmdomains: dev_pm_opp_detach_genpd(core->opp_table); } -static int core_get_v4(struct device *dev) +static int core_resets_reset(struct venus_core *core) { - struct venus_core *core = dev_get_drvdata(dev); + const struct venus_resources *res = core->res; + unsigned int i; + int ret; + + if (!res->resets_num) + return 0; + + for (i = 0; i < res->resets_num; i++) { + ret = reset_control_assert(core->resets[i]); + if (ret) + goto err; + + usleep_range(150, 250); + ret = reset_control_deassert(core->resets[i]); + if (ret) + goto err; + } + +err: + return ret; +} + +static int core_resets_get(struct venus_core *core) +{ + struct device *dev = core->dev; + const struct venus_resources *res = core->res; + unsigned int i; + int ret; + + if (!res->resets_num) + return 0; + + for (i = 0; i < res->resets_num; i++) { + core->resets[i] = + devm_reset_control_get_exclusive(dev, res->resets[i]); + if (IS_ERR(core->resets[i])) { + ret = PTR_ERR(core->resets[i]); + return ret; + } + } + + return 0; +} + +static int core_get_v4(struct venus_core *core) +{ + struct device *dev = core->dev; const struct venus_resources *res = core->res; int ret; @@ -857,6 +934,10 @@ static int core_get_v4(struct device *dev) if (ret) return ret; + ret = core_resets_get(core); + if (ret) + return ret; + if (legacy_binding) return 0; @@ -875,7 +956,7 @@ static int core_get_v4(struct device *dev) } } - ret = vcodec_domains_get(dev); + ret = vcodec_domains_get(core); if (ret) { if (core->has_opp_table) dev_pm_opp_of_remove_table(dev); @@ -886,14 +967,14 @@ static int core_get_v4(struct device *dev) return 0; } -static void core_put_v4(struct device *dev) +static void core_put_v4(struct venus_core *core) { - struct venus_core *core = dev_get_drvdata(dev); + struct device *dev = core->dev; if (legacy_binding) return; - vcodec_domains_put(dev); + vcodec_domains_put(core); if (core->has_opp_table) dev_pm_opp_of_remove_table(dev); @@ -901,9 +982,9 @@ static void core_put_v4(struct device *dev) } -static int core_power_v4(struct device *dev, int on) +static int core_power_v4(struct venus_core *core, int on) { - struct venus_core *core = dev_get_drvdata(dev); + struct device *dev = core->dev; struct device *pmctrl = core->pmdomains[0]; int ret = 0; @@ -916,6 +997,13 @@ static int core_power_v4(struct device *dev, int on) } } + ret = core_resets_reset(core); + if (ret) { + if (pmctrl) + pm_runtime_put_sync(pmctrl); + return ret; + } + ret = core_clks_enable(core); if (ret < 0 && pmctrl) pm_runtime_put_sync(pmctrl); @@ -926,6 +1014,8 @@ static int core_power_v4(struct device *dev, int on) core_clks_disable(core); + ret = core_resets_reset(core); + if (pmctrl) pm_runtime_put_sync(pmctrl); } @@ -993,7 +1083,7 @@ static int load_scale_v4(struct venus_inst *inst) freq = max(freq_core1, freq_core2); - if (freq >= table[0].freq) { + if (freq > table[0].freq) { freq = table[0].freq; dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n", freq, table[0].freq); @@ -1049,6 +1139,7 @@ const struct venus_pm_ops *venus_pm_get(enum hfi_version version) case HFI_VERSION_3XX: return &pm_ops_v3; case HFI_VERSION_4XX: + case HFI_VERSION_6XX: return &pm_ops_v4; } diff --git a/drivers/media/platform/qcom/venus/pm_helpers.h b/drivers/media/platform/qcom/venus/pm_helpers.h index aa2f6afa2354..a492c50c5543 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.h +++ b/drivers/media/platform/qcom/venus/pm_helpers.h @@ -4,14 +4,15 @@ #define __VENUS_PM_HELPERS_H__ struct device; +struct venus_core; #define POWER_ON 1 #define POWER_OFF 0 struct venus_pm_ops { - int (*core_get)(struct device *dev); - void (*core_put)(struct device *dev); - int (*core_power)(struct device *dev, int on); + int (*core_get)(struct venus_core *core); + void (*core_put)(struct venus_core *core); + int (*core_power)(struct venus_core *core, int on); int (*vdec_get)(struct device *dev); void (*vdec_put)(struct device *dev); diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index e4dc97f00fc3..ddb7cd39424e 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -515,7 +515,10 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) fdata.buffer_type = HFI_BUFFER_INPUT; fdata.flags |= HFI_BUFFERFLAG_EOS; - fdata.device_addr = 0xdeadb000; + if (IS_V6(inst->core)) + fdata.device_addr = 0; + else + fdata.device_addr = 0xdeadb000; ret = hfi_session_process_buf(inst, &fdata); @@ -620,7 +623,7 @@ static int vdec_set_properties(struct venus_inst *inst) { struct vdec_controls *ctr = &inst->controls.dec; struct hfi_enable en = { .enable = 1 }; - u32 ptype; + u32 ptype, decode_order, conceal; int ret; if (ctr->post_loop_deb_mode) { @@ -630,6 +633,23 @@ static int vdec_set_properties(struct venus_inst *inst) return ret; } + if (ctr->display_delay_enable && ctr->display_delay == 0) { + ptype = HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER; + decode_order = HFI_OUTPUT_ORDER_DECODE; + ret = hfi_session_set_property(inst, ptype, &decode_order); + if (ret) + return ret; + } + + ptype = HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR; + conceal = ctr->conceal_color & 0xffff; + conceal |= ((ctr->conceal_color >> 16) & 0xffff) << 10; + conceal |= ((ctr->conceal_color >> 32) & 0xffff) << 20; + + ret = hfi_session_set_property(inst, ptype, &conceal); + if (ret) + return ret; + return 0; } @@ -647,7 +667,7 @@ static int vdec_output_conf(struct venus_inst *inst) u32 ptype; int ret; - ret = venus_helper_set_work_mode(inst, VIDC_WORK_MODE_2); + ret = venus_helper_set_work_mode(inst); if (ret) return ret; @@ -662,8 +682,8 @@ static int vdec_output_conf(struct venus_inst *inst) if (width > 1920 && height > ALIGN(1080, 32)) ubwc = true; - /* For Venus v4 UBWC format is mandatory */ - if (IS_V4(core)) + /* For Venus v4/v6 UBWC format is mandatory */ + if (IS_V4(core) || IS_V6(core)) ubwc = true; ret = venus_helper_get_out_fmts(inst, inst->fmt_cap->pixfmt, &out_fmt, @@ -698,6 +718,10 @@ static int vdec_output_conf(struct venus_inst *inst) if (ret) return ret; + ret = venus_helper_set_format_constraints(inst); + if (ret) + return ret; + if (inst->dpb_fmt) { ret = venus_helper_set_multistream(inst, false, true); if (ret) @@ -714,7 +738,7 @@ static int vdec_output_conf(struct venus_inst *inst) return ret; } - if (IS_V3(core) || IS_V4(core)) { + if (IS_V3(core) || IS_V4(core) || IS_V6(core)) { ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq); if (ret) return ret; diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c index 974110b75b93..fbe12a608b21 100644 --- a/drivers/media/platform/qcom/venus/vdec_ctrls.c +++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c @@ -30,6 +30,15 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: ctr->level = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: + ctr->display_delay = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: + ctr->display_delay_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: + ctr->conceal_color = *ctrl->p_new.p_s64; + break; default: return -EINVAL; } @@ -89,7 +98,7 @@ int vdec_ctrl_init(struct venus_inst *inst) struct v4l2_ctrl *ctrl; int ret; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 9); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 12); if (ret) return ret; @@ -158,6 +167,18 @@ int vdec_ctrl_init(struct venus_inst *inst) if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + 0, 16383, 1, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + 0, 1, 1, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops, + V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR, 0, + 0xffffffffffffLL, 1, 0x8000800010LL); + ret = inst->ctrl_handler.error; if (ret) { v4l2_ctrl_handler_free(&inst->ctrl_handler); diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 6976ed553647..4a7291f934b6 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -546,11 +546,12 @@ static int venc_set_properties(struct venus_inst *inst) struct hfi_quantization quant; struct hfi_quantization_range quant_range; struct hfi_enable en; + struct hfi_ltr_mode ltr_mode; u32 ptype, rate_control, bitrate; u32 profile, level; int ret; - ret = venus_helper_set_work_mode(inst, VIDC_WORK_MODE_2); + ret = venus_helper_set_work_mode(inst); if (ret) return ret; @@ -612,6 +613,35 @@ static int venc_set_properties(struct venus_inst *inst) return ret; } + if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { + struct hfi_hdr10_pq_sei hdr10; + unsigned int c; + + ptype = HFI_PROPERTY_PARAM_VENC_HDR10_PQ_SEI; + + for (c = 0; c < 3; c++) { + hdr10.mastering.display_primaries_x[c] = + ctr->mastering.display_primaries_x[c]; + hdr10.mastering.display_primaries_y[c] = + ctr->mastering.display_primaries_y[c]; + } + + hdr10.mastering.white_point_x = ctr->mastering.white_point_x; + hdr10.mastering.white_point_y = ctr->mastering.white_point_y; + hdr10.mastering.max_display_mastering_luminance = + ctr->mastering.max_display_mastering_luminance; + hdr10.mastering.min_display_mastering_luminance = + ctr->mastering.min_display_mastering_luminance; + + hdr10.cll.max_content_light = ctr->cll.max_content_light_level; + hdr10.cll.max_pic_average_light = + ctr->cll.max_pic_average_light_level; + + ret = hfi_session_set_property(inst, ptype, &hdr10); + if (ret) + return ret; + } + if (ctr->num_b_frames) { u32 max_num_b_frames = NUM_B_FRAMES_MAX; @@ -722,6 +752,14 @@ static int venc_set_properties(struct venus_inst *inst) if (ret) return ret; + ptype = HFI_PROPERTY_PARAM_VENC_LTRMODE; + ltr_mode.ltr_count = ctr->ltr_count; + ltr_mode.ltr_mode = HFI_LTR_MODE_MANUAL; + ltr_mode.trust_mode = 1; + ret = hfi_session_set_property(inst, ptype, <r_mode); + if (ret) + return ret; + switch (inst->hfi_codec) { case HFI_VIDEO_CODEC_H264: profile = ctr->profile.h264; @@ -754,6 +792,20 @@ static int venc_set_properties(struct venus_inst *inst) if (ret) return ret; + if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || + inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { + struct hfi_enable en = {}; + + ptype = HFI_PROPERTY_PARAM_VENC_H264_GENERATE_AUDNAL; + + if (ctr->aud_enable) + en.enable = 1; + + ret = hfi_session_set_property(inst, ptype, &en); + if (ret) + return ret; + } + return 0; } diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index a52b80055173..637c92f6c5be 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -20,6 +20,7 @@ #define INTRA_REFRESH_MBS_MAX 300 #define AT_SLICE_BOUNDARY \ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY +#define MAX_LTR_FRAME_COUNT 4 static int venc_calc_bpframes(u32 gop_size, u32 conseq_b, u32 *bf, u32 *pf) { @@ -72,6 +73,8 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) struct venc_controls *ctr = &inst->controls.enc; struct hfi_enable en = { .enable = 1 }; struct hfi_bitrate brate; + struct hfi_ltr_use ltr_use; + struct hfi_ltr_mark ltr_mark; u32 bframes; u32 ptype; int ret; @@ -276,6 +279,46 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID: ctr->base_priority_id = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: + ctr->aud_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_LTR_COUNT: + ctr->ltr_count = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: + mutex_lock(&inst->lock); + if (inst->streamon_out && inst->streamon_cap) { + ptype = HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME; + ltr_mark.mark_frame = ctrl->val; + ret = hfi_session_set_property(inst, ptype, <r_mark); + if (ret) { + mutex_unlock(&inst->lock); + return ret; + } + } + mutex_unlock(&inst->lock); + break; + case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: + mutex_lock(&inst->lock); + if (inst->streamon_out && inst->streamon_cap) { + ptype = HFI_PROPERTY_CONFIG_VENC_USELTRFRAME; + ltr_use.ref_ltr = ctrl->val; + ltr_use.use_constrnt = true; + ltr_use.frames = 0; + ret = hfi_session_set_property(inst, ptype, <r_use); + if (ret) { + mutex_unlock(&inst->lock); + return ret; + } + } + mutex_unlock(&inst->lock); + break; + case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: + ctr->cll = *ctrl->p_new.p_hdr10_cll; + break; + case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: + ctr->mastering = *ctrl->p_new.p_hdr10_mastering; + break; default: return -EINVAL; } @@ -291,7 +334,7 @@ int venc_ctrl_init(struct venus_inst *inst) { int ret; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 51); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 57); if (ret) return ret; @@ -359,7 +402,7 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, ~((1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | (1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME)), - V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE); + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, @@ -498,6 +541,29 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, 0, 6, 1, 0); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, 0, + ((1 << MAX_LTR_FRAME_COUNT) - 1), 0, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, 0, + MAX_LTR_FRAME_COUNT, 1, 0); + + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, 0, + (MAX_LTR_FRAME_COUNT - 1), 1, 0); + + v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_COLORIMETRY_HDR10_CLL_INFO, + v4l2_ctrl_ptr_create(NULL)); + + v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY, + v4l2_ctrl_ptr_create(NULL)); + ret = inst->ctrl_handler.error; if (ret) goto err; diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 0ee9d402f5ac..b263ead4db2b 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -49,11 +49,12 @@ enum rvin_csi_id { }; /** - * STOPPED - No operation in progress - * STARTING - Capture starting up - * RUNNING - Operation in progress have buffers - * STOPPING - Stopping operation - * SUSPENDED - Capture is suspended + * enum rvin_dma_state - DMA states + * @STOPPED: No operation in progress + * @STARTING: Capture starting up + * @RUNNING: Operation in progress have buffers + * @STOPPING: Stopping operation + * @SUSPENDED: Capture is suspended */ enum rvin_dma_state { STOPPED = 0, @@ -70,9 +71,9 @@ enum rvin_dma_state { * to capture SEQ_TB/BT it's needed to capture to the same vb2 * buffer twice so the type of buffer needs to be kept. * - * FULL - One capture fills the whole vb2 buffer - * HALF_TOP - One capture fills the top half of the vb2 buffer - * HALF_BOTTOM - One capture fills the bottom half of the vb2 buffer + * @FULL: One capture fills the whole vb2 buffer + * @HALF_TOP: One capture fills the top half of the vb2 buffer + * @HALF_BOTTOM: One capture fills the bottom half of the vb2 buffer */ enum rvin_buffer_type { FULL, @@ -191,7 +192,7 @@ struct rvin_info { * @state: keeps track of operation state * * @is_csi: flag to mark the VIN as using a CSI-2 subdevice - * @chsel Cached value of the current CSI-2 channel selection + * @chsel: Cached value of the current CSI-2 channel selection * * @mbus_code: media bus format code * @format: active V4L2 pixel format diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index 83bd9a412a56..1e3b68a8743a 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -915,7 +915,6 @@ static int rcar_drif_g_fmt_sdr_cap(struct file *file, void *priv, { struct rcar_drif_sdr *sdr = video_drvdata(file); - memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); f->fmt.sdr.pixelformat = sdr->fmt->pixelformat; f->fmt.sdr.buffersize = sdr->fmt->buffersize; diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index a60c302ef267..b6beddd988d0 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -889,219 +889,177 @@ rkisp1_isp_isr_other_config(struct rkisp1_params *params, module_cfg_update = new_params->module_cfg_update; module_ens = new_params->module_ens; - if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC)) { - /*update dpc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC) - rkisp1_dpcc_config(params, - &new_params->others.dpcc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_DPCC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_DPCC_MODE, - RKISP1_CIF_ISP_DPCC_ENA); - } + /* update dpc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPCC) + rkisp1_dpcc_config(params, + &new_params->others.dpcc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_DPCC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_DPCC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_DPCC_MODE, + RKISP1_CIF_ISP_DPCC_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_DPCC_MODE, + RKISP1_CIF_ISP_DPCC_ENA); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_BLS) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS)) { - /* update bls config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS) - rkisp1_bls_config(params, - &new_params->others.bls_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_BLS) { - if (module_ens & RKISP1_CIF_ISP_MODULE_BLS) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_BLS_CTRL, - RKISP1_CIF_ISP_BLS_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_BLS_CTRL, - RKISP1_CIF_ISP_BLS_ENA); - } - } + /* update bls config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BLS) + rkisp1_bls_config(params, + &new_params->others.bls_config); - if ((module_en_update & RKISP1_CIF_ISP_MODULE_SDG) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG)) { - /* update sdg config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG) - rkisp1_sdg_config(params, - &new_params->others.sdg_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_SDG) { - if (module_ens & RKISP1_CIF_ISP_MODULE_SDG) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); - } + if (module_en_update & RKISP1_CIF_ISP_MODULE_BLS) { + if (module_ens & RKISP1_CIF_ISP_MODULE_BLS) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_BLS_CTRL, + RKISP1_CIF_ISP_BLS_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_BLS_CTRL, + RKISP1_CIF_ISP_BLS_ENA); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_LSC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC)) { - /* update lsc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) - rkisp1_lsc_config(params, - &new_params->others.lsc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_LSC_CTRL, - RKISP1_CIF_ISP_LSC_CTRL_ENA); - } - } + /* update sdg config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_SDG) + rkisp1_sdg_config(params, + &new_params->others.sdg_config); - if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN)) { - /* update awb gains */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) - rkisp1_awb_gain_config(params, - &new_params->others.awb_gain_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) { - if (module_ens & RKISP1_CIF_ISP_MODULE_AWB_GAIN) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); - } + if (module_en_update & RKISP1_CIF_ISP_MODULE_SDG) { + if (module_ens & RKISP1_CIF_ISP_MODULE_SDG) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_IN_ENA); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_BDM) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM)) { - /* update bdm config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM) - rkisp1_bdm_config(params, - &new_params->others.bdm_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_BDM) { - if (module_ens & RKISP1_CIF_ISP_MODULE_BDM) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_DEMOSAIC, - RKISP1_CIF_ISP_DEMOSAIC_BYPASS); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_DEMOSAIC, - RKISP1_CIF_ISP_DEMOSAIC_BYPASS); - } + /* update lsc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_LSC) + rkisp1_lsc_config(params, + &new_params->others.lsc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_LSC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_LSC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_LSC_CTRL, + RKISP1_CIF_ISP_LSC_CTRL_ENA); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_FLT) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT)) { - /* update filter config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT) - rkisp1_flt_config(params, - &new_params->others.flt_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_FLT) { - if (module_ens & RKISP1_CIF_ISP_MODULE_FLT) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_FILT_MODE, - RKISP1_CIF_ISP_FLT_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_FILT_MODE, - RKISP1_CIF_ISP_FLT_ENA); - } + /* update awb gains */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) + rkisp1_awb_gain_config(params, &new_params->others.awb_gain_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB_GAIN) { + if (module_ens & RKISP1_CIF_ISP_MODULE_AWB_GAIN) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_CTK) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK)) { - /* update ctk config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK) - rkisp1_ctk_config(params, - &new_params->others.ctk_config); + /* update bdm config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_BDM) + rkisp1_bdm_config(params, + &new_params->others.bdm_config); - if (module_en_update & RKISP1_CIF_ISP_MODULE_CTK) - rkisp1_ctk_enable(params, - !!(module_ens & RKISP1_CIF_ISP_MODULE_CTK)); + if (module_en_update & RKISP1_CIF_ISP_MODULE_BDM) { + if (module_ens & RKISP1_CIF_ISP_MODULE_BDM) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_BYPASS); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_DEMOSAIC, + RKISP1_CIF_ISP_DEMOSAIC_BYPASS); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_GOC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC)) { - /* update goc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC) - rkisp1_goc_config(params, - &new_params->others.goc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_GOC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_GOC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_CTRL, - RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); - } + /* update filter config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_FLT) + rkisp1_flt_config(params, + &new_params->others.flt_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_FLT) { + if (module_ens & RKISP1_CIF_ISP_MODULE_FLT) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_FILT_MODE, + RKISP1_CIF_ISP_FLT_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_FILT_MODE, + RKISP1_CIF_ISP_FLT_ENA); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC)) { - /* update cproc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC) { - rkisp1_cproc_config(params, - &new_params->others.cproc_config); - } + /* update ctk config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CTK) + rkisp1_ctk_config(params, + &new_params->others.ctk_config); - if (module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_CPROC) - rkisp1_param_set_bits(params, - RKISP1_CIF_C_PROC_CTRL, - RKISP1_CIF_C_PROC_CTR_ENABLE); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_C_PROC_CTRL, - RKISP1_CIF_C_PROC_CTR_ENABLE); - } + if (module_en_update & RKISP1_CIF_ISP_MODULE_CTK) + rkisp1_ctk_enable(params, !!(module_ens & RKISP1_CIF_ISP_MODULE_CTK)); + + /* update goc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_GOC) + rkisp1_goc_config(params, + &new_params->others.goc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_GOC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_GOC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_CTRL, + RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_IE) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE)) { - /* update ie config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE) - rkisp1_ie_config(params, - &new_params->others.ie_config); + /* update cproc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_CPROC) + rkisp1_cproc_config(params, + &new_params->others.cproc_config); - if (module_en_update & RKISP1_CIF_ISP_MODULE_IE) - rkisp1_ie_enable(params, - !!(module_ens & RKISP1_CIF_ISP_MODULE_IE)); + if (module_en_update & RKISP1_CIF_ISP_MODULE_CPROC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_CPROC) + rkisp1_param_set_bits(params, + RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_CTR_ENABLE); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_C_PROC_CTRL, + RKISP1_CIF_C_PROC_CTR_ENABLE); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF)) { - /* update dpf config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF) - rkisp1_dpf_config(params, - &new_params->others.dpf_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_DPF) { - if (module_ens & RKISP1_CIF_ISP_MODULE_DPF) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_DPF_MODE, - RKISP1_CIF_ISP_DPF_MODE_EN); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_DPF_MODE, - RKISP1_CIF_ISP_DPF_MODE_EN); - } + /* update ie config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_IE) + rkisp1_ie_config(params, &new_params->others.ie_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_IE) + rkisp1_ie_enable(params, !!(module_ens & RKISP1_CIF_ISP_MODULE_IE)); + + /* update dpf config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_DPF) + rkisp1_dpf_config(params, &new_params->others.dpf_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_DPF) { + if (module_ens & RKISP1_CIF_ISP_MODULE_DPF) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_DPF_MODE, + RKISP1_CIF_ISP_DPF_MODE_EN); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_DPF_MODE, + RKISP1_CIF_ISP_DPF_MODE_EN); } if ((module_en_update & RKISP1_CIF_ISP_MODULE_DPF_STRENGTH) || @@ -1121,68 +1079,55 @@ static void rkisp1_isp_isr_meas_config(struct rkisp1_params *params, module_cfg_update = new_params->module_cfg_update; module_ens = new_params->module_ens; - if ((module_en_update & RKISP1_CIF_ISP_MODULE_AWB) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB)) { - /* update awb config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB) - rkisp1_awb_meas_config(params, - &new_params->meas.awb_meas_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB) - rkisp1_awb_meas_enable(params, - &new_params->meas.awb_meas_config, - !!(module_ens & RKISP1_CIF_ISP_MODULE_AWB)); - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_AFC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC)) { - /* update afc config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC) - rkisp1_afm_config(params, - &new_params->meas.afc_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_AFC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_AFC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_AFM_CTRL, - RKISP1_CIF_ISP_AFM_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_AFM_CTRL, - RKISP1_CIF_ISP_AFM_ENA); - } - } - - if ((module_en_update & RKISP1_CIF_ISP_MODULE_HST) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST)) { - /* update hst config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST) - rkisp1_hst_config(params, - &new_params->meas.hst_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_HST) - rkisp1_hst_enable(params, - &new_params->meas.hst_config, - !!(module_ens & RKISP1_CIF_ISP_MODULE_HST)); + /* update awb config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AWB) + rkisp1_awb_meas_config(params, &new_params->meas.awb_meas_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AWB) + rkisp1_awb_meas_enable(params, + &new_params->meas.awb_meas_config, + !!(module_ens & RKISP1_CIF_ISP_MODULE_AWB)); + + /* update afc config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AFC) + rkisp1_afm_config(params, + &new_params->meas.afc_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AFC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_AFC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_AFM_CTRL, + RKISP1_CIF_ISP_AFM_ENA); } - if ((module_en_update & RKISP1_CIF_ISP_MODULE_AEC) || - (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC)) { - /* update aec config */ - if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC) - rkisp1_aec_config(params, - &new_params->meas.aec_config); - - if (module_en_update & RKISP1_CIF_ISP_MODULE_AEC) { - if (module_ens & RKISP1_CIF_ISP_MODULE_AEC) - rkisp1_param_set_bits(params, - RKISP1_CIF_ISP_EXP_CTRL, - RKISP1_CIF_ISP_EXP_ENA); - else - rkisp1_param_clear_bits(params, - RKISP1_CIF_ISP_EXP_CTRL, - RKISP1_CIF_ISP_EXP_ENA); - } + /* update hst config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_HST) + rkisp1_hst_config(params, + &new_params->meas.hst_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_HST) + rkisp1_hst_enable(params, + &new_params->meas.hst_config, + !!(module_ens & RKISP1_CIF_ISP_MODULE_HST)); + + /* update aec config */ + if (module_cfg_update & RKISP1_CIF_ISP_MODULE_AEC) + rkisp1_aec_config(params, + &new_params->meas.aec_config); + + if (module_en_update & RKISP1_CIF_ISP_MODULE_AEC) { + if (module_ens & RKISP1_CIF_ISP_MODULE_AEC) + rkisp1_param_set_bits(params, + RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); + else + rkisp1_param_clear_bits(params, + RKISP1_CIF_ISP_EXP_CTRL, + RKISP1_CIF_ISP_EXP_ENA); } } diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index 813670ed9577..79deed8adcea 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -520,14 +520,15 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz, struct v4l2_mbus_framefmt *format, unsigned int which) { - const struct rkisp1_isp_mbus_info *mbus_info; - struct v4l2_mbus_framefmt *src_fmt; + const struct rkisp1_isp_mbus_info *sink_mbus_info; + struct v4l2_mbus_framefmt *src_fmt, *sink_fmt; + sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SINK, which); src_fmt = rkisp1_rsz_get_pad_fmt(rsz, cfg, RKISP1_RSZ_PAD_SRC, which); - mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code); + sink_mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code); /* for YUV formats, userspace can change the mbus code on the src pad if it is supported */ - if (mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV && + if (sink_mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV && rkisp1_rsz_get_yuv_mbus_info(format->code)) src_fmt->code = format->code; diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h index f937e638490f..f3442e251bc9 100644 --- a/drivers/media/platform/s3c-camif/camif-core.h +++ b/drivers/media/platform/s3c-camif/camif-core.h @@ -144,8 +144,10 @@ struct camif_pix_limits { /** * struct s3c_camif_variant - CAMIF variant structure * @vp_pix_limits: pixel limits for the codec and preview paths - * @camif_pix_limits: pixel limits for the camera input interface + * @pix_limits: pixel limits for the camera input interface * @ip_revision: the CAMIF IP revision: 0x20 for s3c244x, 0x32 for s3c6410 + * @has_img_effect: supports image effects + * @vp_offset: register offset */ struct s3c_camif_variant { struct vp_pix_limits vp_pix_limits[2]; @@ -183,9 +185,10 @@ struct camif_dev; * @irq: interrupt number for this data path * @camif: pointer to the camif structure * @pad: media pad for the video node - * @vdev video device + * @vdev: video device * @ctrl_handler: video node controls handler * @owner: file handle that own the streaming + * @vb_queue: vb2 buffer queue * @pending_buf_q: pending (empty) buffers queue head * @active_buf_q: active (being written) buffers queue head * @active_buffers: counter of buffer set up at the DMA engine @@ -202,6 +205,7 @@ struct camif_dev; * @rotation: current image rotation value * @hflip: apply horizontal flip if set * @vflip: apply vertical flip if set + * @offset: register offset */ struct camif_vp { wait_queue_head_t irq_queue; @@ -248,7 +252,13 @@ struct camif_vp { * @sensor: image sensor data structure * @m_pipeline: video entity pipeline description * @ctrl_handler: v4l2 control handler (owned by @subdev) - * @test_pattern: test pattern controls + * @ctrl_test_pattern: V4L2_CID_TEST_PATTERN control + * @ctrl_colorfx: V4L2_CID_COLORFX control + * @ctrl_colorfx_cbcr: V4L2_CID_COLORFX_CBCR control + * @test_pattern: test pattern + * @colorfx: color effect + * @colorfx_cb: Cb value for V4L2_COLORFX_SET_CBCR + * @colorfx_cr: Cr value for V4L2_COLORFX_SET_CBCR * @vp: video path (DMA) description (codec/preview) * @variant: variant information for this device * @dev: pointer to the CAMIF device struct diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h index 4407fe775afa..a77d93c098ce 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-core.h +++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h @@ -111,12 +111,12 @@ enum s5p_jpeg_ctx_state { * @m2m_dev: v4l2 mem2mem device data * @regs: JPEG IP registers mapping * @irq: JPEG IP irq + * @irq_ret: JPEG IP irq result value * @clocks: JPEG IP clock(s) * @dev: JPEG IP struct device * @variant: driver variant to be used - * @irq_status interrupt flags set during single encode/decode - operation - + * @irq_status: interrupt flags set during single encode/decode + * operation */ struct s5p_jpeg { struct mutex lock; @@ -149,12 +149,14 @@ struct s5p_jpeg_variant { }; /** - * struct jpeg_fmt - driver's internal color format data + * struct s5p_jpeg_fmt - driver's internal color format data * @fourcc: the fourcc code, 0 if not applicable * @depth: number of bits per pixel * @colplanes: number of color planes (1 for packed formats) + * @memplanes: number of memory planes (1 for packed formats) * @h_align: horizontal alignment order (align to 2^h_align) * @v_align: vertical alignment order (align to 2^v_align) + * @subsampling:subsampling of a raw format or a JPEG * @flags: flags describing format applicability */ struct s5p_jpeg_fmt { @@ -169,7 +171,7 @@ struct s5p_jpeg_fmt { }; /** - * s5p_jpeg_marker - collection of markers from jpeg header + * struct s5p_jpeg_marker - collection of markers from jpeg header * @marker: markers' positions relative to the buffer beginning * @len: markers' payload lengths (without length field) * @n: number of markers in collection @@ -181,7 +183,7 @@ struct s5p_jpeg_marker { }; /** - * s5p_jpeg_q_data - parameters of one queue + * struct s5p_jpeg_q_data - parameters of one queue * @fmt: driver-specific format of this queue * @w: image width * @h: image height @@ -205,7 +207,7 @@ struct s5p_jpeg_q_data { }; /** - * s5p_jpeg_ctx - the device context data + * struct s5p_jpeg_ctx - the device context data * @jpeg: JPEG IP device for this context * @mode: compression (encode) operation or decompression (decode) * @compr_quality: destination image quality in compression (encode) mode @@ -239,7 +241,7 @@ struct s5p_jpeg_ctx { }; /** - * s5p_jpeg_buffer - description of memory containing input JPEG data + * struct s5p_jpeg_buffer - description of memory containing input JPEG data * @size: buffer size * @curr: current position in the buffer * @data: pointer to the data diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 96d1ecd1521b..c3ef4f6a42d2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -102,7 +102,7 @@ #define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ (offset)) -/** +/* * enum s5p_mfc_fmt_type - type of the pixelformat */ enum s5p_mfc_fmt_type { @@ -111,7 +111,7 @@ enum s5p_mfc_fmt_type { MFC_FMT_RAW, }; -/** +/* * enum s5p_mfc_inst_type - The type of an MFC instance. */ enum s5p_mfc_inst_type { @@ -120,7 +120,7 @@ enum s5p_mfc_inst_type { MFCINST_ENCODER, }; -/** +/* * enum s5p_mfc_inst_state - The state of an MFC instance. */ enum s5p_mfc_inst_state { @@ -142,7 +142,7 @@ enum s5p_mfc_inst_state { MFCINST_RES_CHANGE_END, }; -/** +/* * enum s5p_mfc_queue_state - The state of buffer queue. */ enum s5p_mfc_queue_state { @@ -152,7 +152,7 @@ enum s5p_mfc_queue_state { QUEUE_BUFS_MMAPED, }; -/** +/* * enum s5p_mfc_decode_arg - type of frame decoding */ enum s5p_mfc_decode_arg { @@ -171,7 +171,7 @@ enum s5p_mfc_fw_ver { struct s5p_mfc_ctx; -/** +/* * struct s5p_mfc_buf - MFC buffer */ struct s5p_mfc_buf { @@ -187,7 +187,7 @@ struct s5p_mfc_buf { int flags; }; -/** +/* * struct s5p_mfc_pm - power management data structure */ struct s5p_mfc_pm { @@ -257,7 +257,7 @@ struct s5p_mfc_priv_buf { * @vfd_dec: video device for decoding * @vfd_enc: video device for encoding * @plat_dev: platform device - * @mem_dev[]: child devices of the memory banks + * @mem_dev: child devices of the memory banks * @regs_base: base address of the MFC hw registers * @irq: irq resource * @dec_ctrl_handler: control framework handler for decoding @@ -273,14 +273,18 @@ struct s5p_mfc_priv_buf { * @int_type: type of last interrupt * @int_err: error number for last interrupt * @queue: waitqueue for waiting for completion of device commands - * @fw_size: size of firmware - * @fw_virt_addr: virtual firmware address - * @dma_base[]: address of the beginning of memory banks + * @fw_buf: the firmware buffer data structure + * @mem_size: size of the firmware operation memory + * @mem_base: base DMA address of the firmware operation memory + * @mem_bitmap: bitmap for managing MFC internal buffer allocations + * @mem_virt: virtual address of the firmware operation memory + * @dma_base: address of the beginning of memory banks * @hw_lock: used for hardware locking * @ctx: array of driver contexts * @curr_ctx: number of the currently running context * @ctx_work_bits: used to mark which contexts are waiting for hardware * @watchdog_cnt: counter for the watchdog + * @watchdog_timer: timer for the watchdog * @watchdog_workqueue: workqueue for the watchdog * @watchdog_work: worker for the watchdog * @enter_suspend: flag set when entering suspend @@ -290,9 +294,9 @@ struct s5p_mfc_priv_buf { * @mfc_cmds: cmd structure holding HW commands function pointers * @mfc_regs: structure holding MFC registers * @fw_ver: loaded firmware sub-version - * @fw_get_done flag set when request_firmware() is complete and + * @fw_get_done: flag set when request_firmware() is complete and * copied into fw_buf - * risc_on: flag indicates RISC is on or off + * @risc_on: flag indicates RISC is on or off * */ struct s5p_mfc_dev { @@ -342,7 +346,7 @@ struct s5p_mfc_dev { bool risc_on; /* indicates if RISC is on or off */ }; -/** +/* * struct s5p_mfc_h264_enc_params - encoding parameters for h264 */ struct s5p_mfc_h264_enc_params { @@ -391,7 +395,7 @@ struct s5p_mfc_h264_enc_params { u32 aso_slice_order[8]; }; -/** +/* * struct s5p_mfc_mpeg4_enc_params - encoding parameters for h263 and mpeg4 */ struct s5p_mfc_mpeg4_enc_params { @@ -410,7 +414,7 @@ struct s5p_mfc_mpeg4_enc_params { int level; }; -/** +/* * struct s5p_mfc_vp8_enc_params - encoding parameters for vp8 */ struct s5p_mfc_vp8_enc_params { @@ -479,7 +483,7 @@ struct s5p_mfc_hevc_enc_params { u8 prepend_sps_pps_to_idr; }; -/** +/* * struct s5p_mfc_enc_params - general encoding parameters */ struct s5p_mfc_enc_params { @@ -521,7 +525,7 @@ struct s5p_mfc_enc_params { }; -/** +/* * struct s5p_mfc_codec_ops - codec ops, used by encoding */ struct s5p_mfc_codec_ops { @@ -579,7 +583,9 @@ struct s5p_mfc_codec_ops { * @capture_state: state of the capture buffers queue * @output_state: state of the output buffers queue * @src_bufs: information on allocated source buffers + * @src_bufs_cnt: number of allocated source buffers * @dst_bufs: information on allocated destination buffers + * @dst_bufs_cnt: number of allocated destination buffers * @sequence: counter for the sequence number for v4l2 * @dec_dst_flag: flags for buffers queued in the hardware * @dec_src_buf_size: size of the buffer for source buffers in decoding @@ -591,7 +597,7 @@ struct s5p_mfc_codec_ops { * @after_packed_pb: flag used to track buffer when stream is in * Packed PB format * @sei_fp_parse: enable/disable parsing of frame packing SEI information - * @dpb_count: count of the DPB buffers required by MFC hw + * @pb_count: count of the DPB buffers required by MFC hw * @total_dpb_count: count of DPB buffers with additional buffers * requested by the application * @ctx: context buffer information @@ -606,11 +612,15 @@ struct s5p_mfc_codec_ops { * @tmv_buffer_size: size of temporal predictor motion vector buffer * @frame_type: used to force the type of the next encoded frame * @ref_queue: list of the reference buffers for encoding + * @force_frame_type: encoder's frame type forcing control * @ref_queue_cnt: number of the buffers in the reference list + * @slice_size: slice size + * @slice_mode: mode of dividing frames into slices * @c_ops: ops for encoding * @ctrls: array of controls, used when adding controls to the * v4l2 control framework * @ctrl_handler: handler for v4l2 framework + * @scratch_buf_size: scratch buffer size */ struct s5p_mfc_ctx { struct s5p_mfc_dev *dev; @@ -709,7 +719,6 @@ struct s5p_mfc_ctx { struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; struct v4l2_ctrl_handler ctrl_handler; - unsigned int frame_tag; size_t scratch_buf_size; }; @@ -725,7 +734,7 @@ struct s5p_mfc_fmt { u32 versions; }; -/** +/* * struct mfc_control - structure used to store information about MFC controls * it is used to initialize the control framework. */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index a71753d459ba..a92a9ca6e87e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -168,6 +168,13 @@ static struct mfc_control controls[] = { .default_value = 0, }, { + .id = V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 16383, + .default_value = 0, + }, + { .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "H264 Display Delay Enable", @@ -177,6 +184,13 @@ static struct mfc_control controls[] = { .default_value = 0, }, { + .id = V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .default_value = 0, + }, + { .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, .type = V4L2_CTRL_TYPE_BOOLEAN, .name = "Mpeg4 Loop Filter Enable", @@ -690,9 +704,11 @@ static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY: + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: ctx->display_delay = ctrl->val; break; case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE: + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: ctx->display_delay_enable = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: diff --git a/drivers/media/platform/sti/bdisp/bdisp-debug.c b/drivers/media/platform/sti/bdisp/bdisp-debug.c index 2b270093009c..a27f638df11c 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-debug.c +++ b/drivers/media/platform/sti/bdisp/bdisp-debug.c @@ -480,7 +480,7 @@ static int regs_show(struct seq_file *s, void *data) int ret; unsigned int i; - ret = pm_runtime_get_sync(bdisp->dev); + ret = pm_runtime_resume_and_get(bdisp->dev); if (ret < 0) { seq_puts(s, "Cannot wake up IP\n"); return 0; diff --git a/drivers/media/platform/sti/bdisp/bdisp-filter.h b/drivers/media/platform/sti/bdisp/bdisp-filter.h index d25adb57e3d0..9e1a95fd27ed 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-filter.h +++ b/drivers/media/platform/sti/bdisp/bdisp-filter.h @@ -12,7 +12,7 @@ * * @min: min scale factor for this filter (6.10 fixed point) * @max: max scale factor for this filter (6.10 fixed point) - * coef: filter coefficients + * @coef: filter coefficients */ struct bdisp_filter_h_spec { const u16 min; @@ -24,7 +24,7 @@ struct bdisp_filter_h_spec { * * @min: min scale factor for this filter (6.10 fixed point) * @max: max scale factor for this filter (6.10 fixed point) - * coef: filter coefficients + * @coef: filter coefficients */ struct bdisp_filter_v_spec { const u16 min; diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index a7a6ea666740..338b205ae3a7 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -655,7 +655,7 @@ static irqreturn_t c8sectpfe_error_irq_handler(int irq, void *priv) /* * TODO FIXME we should detect some error conditions here - * and ideally so something about them! + * and ideally do something about them! */ return IRQ_HANDLED; diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.h b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.h index b8c30bcc8df9..d2c35fb32d7e 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.h +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.h @@ -1,11 +1,10 @@ /* 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 diff --git a/drivers/media/platform/sti/hva/hva-h264.c b/drivers/media/platform/sti/hva/hva-h264.c index c34f7cf5aed2..98cb00d2d868 100644 --- a/drivers/media/platform/sti/hva/hva-h264.c +++ b/drivers/media/platform/sti/hva/hva-h264.c @@ -428,8 +428,10 @@ static int hva_h264_fill_slice_header(struct hva_ctx *pctx, */ struct device *dev = ctx_to_dev(pctx); int cabac = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC; - const unsigned char slice_header[] = { 0x00, 0x00, 0x00, 0x01, - 0x41, 0x34, 0x07, 0x00}; + static const unsigned char slice_header[] = { + 0x00, 0x00, 0x00, 0x01, + 0x41, 0x34, 0x07, 0x00 + }; int idr_pic_id = frame_num % 2; enum hva_picture_coding_type type; u32 frame_order = frame_num % ctrls->gop_size; @@ -488,7 +490,7 @@ static int hva_h264_fill_data_nal(struct hva_ctx *pctx, unsigned int stream_size, unsigned int *size) { struct device *dev = ctx_to_dev(pctx); - const u8 start[] = { 0x00, 0x00, 0x00, 0x01 }; + static const u8 start[] = { 0x00, 0x00, 0x00, 0x01 }; dev_dbg(dev, "%s %s stuffing bytes %d\n", pctx->name, __func__, stuffing_bytes); @@ -521,7 +523,7 @@ static int hva_h264_fill_sei_nal(struct hva_ctx *pctx, u8 *addr, u32 *size) { struct device *dev = ctx_to_dev(pctx); - const u8 start[] = { 0x00, 0x00, 0x00, 0x01 }; + static const u8 start[] = { 0x00, 0x00, 0x00, 0x01 }; struct hva_h264_stereo_video_sei info; u8 offset = 7; u8 msg = 0; diff --git a/drivers/media/platform/sti/hva/hva.h b/drivers/media/platform/sti/hva/hva.h index 1226d60cc367..ba6b893416ec 100644 --- a/drivers/media/platform/sti/hva/hva.h +++ b/drivers/media/platform/sti/hva/hva.h @@ -130,7 +130,7 @@ struct hva_frame { /** * struct hva_stream - hva stream buffer (capture) * - * @v4l2: video buffer information for V4L2 + * @vbuf: video buffer information for V4L2 * @list: V4L2 m2m list that the frame belongs to * @paddr: physical address (for hardware) * @vaddr: virtual address (kernel can read/write) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index b55de9ab64d8..3181d0781b61 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -151,8 +151,10 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) } subdev = sun6i_video_remote_subdev(video, NULL); - if (!subdev) + if (!subdev) { + ret = -EINVAL; goto stop_media_pipeline; + } config.pixelformat = video->fmt.fmt.pix.pixelformat; config.code = video->mbus_code; diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index ed863bf5ea80..671e4a928993 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -589,7 +589,7 @@ static int deinterlace_start_streaming(struct vb2_queue *vq, unsigned int count) int ret; if (V4L2_TYPE_IS_OUTPUT(vq->type)) { - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) { dev_err(dev, "Failed to enable module\n"); diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index dd48017859cd..cbe6114908de 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -830,6 +830,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, sd = &phy->subdev; v4l2_subdev_init(sd, &cal_camerarx_subdev_ops); sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; snprintf(sd->name, sizeof(sd->name), "CAMERARX%u", instance); sd->dev = cal->dev; diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index 779f1e1bc529..7b7436a355ee 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -40,7 +40,35 @@ static char *fourcc_to_str(u32 fmt) } /* ------------------------------------------------------------------ - * V4L2 Video IOCTLs + * V4L2 Common IOCTLs + * ------------------------------------------------------------------ + */ + +static int cal_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct cal_ctx *ctx = video_drvdata(file); + + strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card)); + + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev_name(ctx->cal->dev)); + return 0; +} + +static int cal_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cal_ctx *ctx = video_drvdata(file); + + *f = ctx->v_fmt; + + return 0; +} + +/* ------------------------------------------------------------------ + * V4L2 Video Node Centric IOCTLs * ------------------------------------------------------------------ */ @@ -74,19 +102,6 @@ static const struct cal_format_info *find_format_by_code(struct cal_ctx *ctx, return NULL; } -static int cal_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct cal_ctx *ctx = video_drvdata(file); - - strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver)); - strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card)); - - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev_name(ctx->cal->dev)); - return 0; -} - static int cal_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -174,16 +189,6 @@ static void cal_calc_format_size(struct cal_ctx *ctx, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); } -static int cal_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct cal_ctx *ctx = video_drvdata(file); - - *f = ctx->v_fmt; - - return 0; -} - static int cal_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { @@ -383,16 +388,7 @@ static int cal_enum_frameintervals(struct file *file, void *priv, return 0; } -static const struct v4l2_file_operations cal_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ - .mmap = vb2_fop_mmap, -}; - -static const struct v4l2_ioctl_ops cal_ioctl_ops = { +static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { .vidioc_querycap = cal_querycap, .vidioc_enum_fmt_vid_cap = cal_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, @@ -418,7 +414,155 @@ static const struct v4l2_ioctl_ops cal_ioctl_ops = { }; /* ------------------------------------------------------------------ - * videobuf2 Operations + * V4L2 Media Controller Centric IOCTLs + * ------------------------------------------------------------------ + */ + +static int cal_mc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index >= cal_num_formats) + return -EINVAL; + + f->pixelformat = cal_formats[f->index].fourcc; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + return 0; +} + +static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f, + const struct cal_format_info **info) +{ + struct v4l2_pix_format *format = &f->fmt.pix; + const struct cal_format_info *fmtinfo; + unsigned int bpp; + + /* + * Default to the first format if the requested pixel format code isn't + * supported. + */ + fmtinfo = cal_format_by_fourcc(f->fmt.pix.pixelformat); + if (!fmtinfo) + fmtinfo = &cal_formats[0]; + + /* + * Clamp the size, update the pixel format. The field and colorspace are + * accepted as-is, except for V4L2_FIELD_ANY that is turned into + * V4L2_FIELD_NONE. + */ + bpp = ALIGN(fmtinfo->bpp, 8); + + format->width = clamp_t(unsigned int, format->width, + CAL_MIN_WIDTH_BYTES * 8 / bpp, + CAL_MAX_WIDTH_BYTES * 8 / bpp); + format->height = clamp_t(unsigned int, format->height, + CAL_MIN_HEIGHT_LINES, CAL_MAX_HEIGHT_LINES); + format->pixelformat = fmtinfo->fourcc; + + if (format->field == V4L2_FIELD_ANY) + format->field = V4L2_FIELD_NONE; + + /* + * Calculate the number of bytes per line and the image size. The + * hardware stores the stride as a number of 16 bytes words, in a + * signed 15-bit value. Only 14 bits are thus usable. + */ + format->bytesperline = ALIGN(clamp(format->bytesperline, + format->width * bpp / 8, + ((1U << 14) - 1) * 16), 16); + + format->sizeimage = format->height * format->bytesperline; + + format->colorspace = ctx->v_fmt.fmt.pix.colorspace; + + if (info) + *info = fmtinfo; + + ctx_dbg(3, ctx, "%s: %s %ux%u (bytesperline %u sizeimage %u)\n", + __func__, fourcc_to_str(format->pixelformat), + format->width, format->height, + format->bytesperline, format->sizeimage); +} + +static int cal_mc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cal_ctx *ctx = video_drvdata(file); + + cal_mc_try_fmt(ctx, f, NULL); + return 0; +} + +static int cal_mc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct cal_ctx *ctx = video_drvdata(file); + const struct cal_format_info *fmtinfo; + + if (vb2_is_busy(&ctx->vb_vidq)) { + ctx_dbg(3, ctx, "%s device busy\n", __func__); + return -EBUSY; + } + + cal_mc_try_fmt(ctx, f, &fmtinfo); + + ctx->v_fmt = *f; + ctx->fmtinfo = fmtinfo; + + return 0; +} + +static int cal_mc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct cal_ctx *ctx = video_drvdata(file); + const struct cal_format_info *fmtinfo; + unsigned int bpp; + + if (fsize->index > 0) + return -EINVAL; + + fmtinfo = cal_format_by_fourcc(fsize->pixel_format); + if (!fmtinfo) { + ctx_dbg(3, ctx, "Invalid pixel format 0x%08x\n", + fsize->pixel_format); + return -EINVAL; + } + + bpp = ALIGN(fmtinfo->bpp, 8); + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = CAL_MIN_WIDTH_BYTES * 8 / bpp; + fsize->stepwise.max_width = CAL_MAX_WIDTH_BYTES * 8 / bpp; + fsize->stepwise.step_width = 64 / bpp; + fsize->stepwise.min_height = CAL_MIN_HEIGHT_LINES; + fsize->stepwise.max_height = CAL_MAX_HEIGHT_LINES; + fsize->stepwise.step_height = 1; + + return 0; +} + +static const struct v4l2_ioctl_ops cal_ioctl_mc_ops = { + .vidioc_querycap = cal_querycap, + .vidioc_enum_fmt_vid_cap = cal_mc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cal_mc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cal_mc_s_fmt_vid_cap, + .vidioc_enum_framesizes = cal_mc_enum_framesizes, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_log_status = v4l2_ctrl_log_status, +}; + +/* ------------------------------------------------------------------ + * videobuf2 Common Operations * ------------------------------------------------------------------ */ @@ -504,6 +648,26 @@ static void cal_release_buffers(struct cal_ctx *ctx, spin_unlock_irq(&ctx->dma.lock); } +/* ------------------------------------------------------------------ + * videobuf2 Operations + * ------------------------------------------------------------------ + */ + +static int cal_video_check_format(struct cal_ctx *ctx) +{ + const struct v4l2_mbus_framefmt *format; + + format = &ctx->phy->formats[CAL_CAMERARX_PAD_SOURCE]; + + if (ctx->fmtinfo->code != format->code || + ctx->v_fmt.fmt.pix.height != format->height || + ctx->v_fmt.fmt.pix.width != format->width || + ctx->v_fmt.fmt.pix.field != format->field) + return -EPIPE; + + return 0; +} + static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) { struct cal_ctx *ctx = vb2_get_drv_priv(vq); @@ -511,6 +675,23 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) dma_addr_t addr; int ret; + ret = media_pipeline_start(&ctx->vdev.entity, &ctx->phy->pipe); + if (ret < 0) { + ctx_err(ctx, "Failed to start media pipeline: %d\n", ret); + goto error_release_buffers; + } + + /* + * Verify that the currently configured format matches the output of + * the connected CAMERARX. + */ + ret = cal_video_check_format(ctx); + if (ret < 0) { + ctx_dbg(3, ctx, + "Format mismatch between CAMERARX and video node\n"); + goto error_pipeline; + } + spin_lock_irq(&ctx->dma.lock); buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list); ctx->dma.pending = buf; @@ -526,18 +707,22 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) ret = v4l2_subdev_call(&ctx->phy->subdev, video, s_stream, 1); if (ret) - goto err; + goto error_stop; if (cal_debug >= 4) cal_quickdump_regs(ctx->cal); return 0; -err: +error_stop: cal_ctx_stop(ctx); pm_runtime_put_sync(ctx->cal->dev); +error_pipeline: + media_pipeline_stop(&ctx->vdev.entity); +error_release_buffers: cal_release_buffers(ctx, VB2_BUF_STATE_QUEUED); + return ret; } @@ -552,6 +737,8 @@ static void cal_stop_streaming(struct vb2_queue *vq) pm_runtime_put_sync(ctx->cal->dev); cal_release_buffers(ctx, VB2_BUF_STATE_ERROR); + + media_pipeline_stop(&ctx->vdev.entity); } static const struct vb2_ops cal_video_qops = { @@ -569,13 +756,13 @@ static const struct vb2_ops cal_video_qops = { * ------------------------------------------------------------------ */ -static const struct video_device cal_videodev = { - .name = CAL_MODULE_NAME, - .fops = &cal_fops, - .ioctl_ops = &cal_ioctl_ops, - .minor = -1, - .release = video_device_release_empty, - .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING, +static const struct v4l2_file_operations cal_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */ + .mmap = vb2_fop_mmap, }; static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) @@ -591,15 +778,21 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) sizeof(*ctx->active_fmt), GFP_KERNEL); ctx->num_active_fmt = 0; - for (j = 0, i = 0; ret != -EINVAL; ++j) { + for (j = 0, i = 0; ; ++j) { memset(&mbus_code, 0, sizeof(mbus_code)); mbus_code.index = j; mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_mbus_code, NULL, &mbus_code); - if (ret) - continue; + if (ret == -EINVAL) + break; + + if (ret) { + ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n", + ctx->phy->sensor->name, ret); + return ret; + } ctx_dbg(2, ctx, "subdev %s: code: %04x idx: %u\n", @@ -640,7 +833,6 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) v4l2_fill_pix_format(&ctx->v_fmt.fmt.pix, &mbus_fmt); ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ctx->v_fmt.fmt.pix.pixelformat = fmtinfo->fourcc; - ctx->v_fmt.fmt.pix.field = mbus_fmt.field; cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt); ctx->fmtinfo = fmtinfo; @@ -649,7 +841,6 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) int cal_ctx_v4l2_register(struct cal_ctx *ctx) { - struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; struct video_device *vfd = &ctx->vdev; int ret; @@ -657,11 +848,15 @@ int cal_ctx_v4l2_register(struct cal_ctx *ctx) if (ret) return ret; - ret = v4l2_ctrl_add_handler(hdl, ctx->phy->sensor->ctrl_handler, NULL, - true); - if (ret < 0) { - ctx_err(ctx, "Failed to add sensor ctrl handler\n"); - return ret; + if (!cal_mc_api) { + struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; + + ret = v4l2_ctrl_add_handler(hdl, ctx->phy->sensor->ctrl_handler, + NULL, true); + if (ret < 0) { + ctx_err(ctx, "Failed to add sensor ctrl handler\n"); + return ret; + } } ret = video_register_device(vfd, VFL_TYPE_VIDEO, cal_video_nr); @@ -698,7 +893,6 @@ void cal_ctx_v4l2_unregister(struct cal_ctx *ctx) int cal_ctx_v4l2_init(struct cal_ctx *ctx) { - struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; struct video_device *vfd = &ctx->vdev; struct vb2_queue *q = &ctx->vb_vidq; int ret; @@ -725,10 +919,14 @@ int cal_ctx_v4l2_init(struct cal_ctx *ctx) return ret; /* Initialize the video device and media entity. */ - *vfd = cal_videodev; + vfd->fops = &cal_fops; + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING + | (cal_mc_api ? V4L2_CAP_IO_MC : 0); vfd->v4l2_dev = &ctx->cal->v4l2_dev; vfd->queue = q; snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->index); + vfd->release = video_device_release_empty; + vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_video_ops; vfd->lock = &ctx->mutex; video_set_drvdata(vfd, ctx); @@ -737,14 +935,18 @@ int cal_ctx_v4l2_init(struct cal_ctx *ctx) if (ret < 0) return ret; - /* Initialize the control handler. */ - ret = v4l2_ctrl_handler_init(hdl, 11); - if (ret < 0) { - ctx_err(ctx, "Failed to init ctrl handler\n"); - goto error; - } + if (!cal_mc_api) { + /* Initialize the control handler. */ + struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; - vfd->ctrl_handler = hdl; + ret = v4l2_ctrl_handler_init(hdl, 11); + if (ret < 0) { + ctx_err(ctx, "Failed to init ctrl handler\n"); + goto error; + } + + vfd->ctrl_handler = hdl; + } return 0; @@ -755,6 +957,8 @@ error: void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx) { - v4l2_ctrl_handler_free(&ctx->ctrl_handler); + if (!cal_mc_api) + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + media_entity_cleanup(&ctx->vdev.entity); } diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index fa0931788040..2e2bef91b2b0 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -43,6 +43,16 @@ unsigned int cal_debug; module_param_named(debug, cal_debug, uint, 0644); MODULE_PARM_DESC(debug, "activates debug info"); +#ifdef CONFIG_VIDEO_TI_CAL_MC +#define CAL_MC_API_DEFAULT 1 +#else +#define CAL_MC_API_DEFAULT 0 +#endif + +bool cal_mc_api = CAL_MC_API_DEFAULT; +module_param_named(mc_api, cal_mc_api, bool, 0444); +MODULE_PARM_DESC(mc_api, "activates the MC API"); + /* ------------------------------------------------------------------ * Format Handling * ------------------------------------------------------------------ @@ -660,13 +670,17 @@ static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier) { struct cal_dev *cal = container_of(notifier, struct cal_dev, notifier); unsigned int i; + int ret = 0; for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { if (cal->ctx[i]) cal_ctx_v4l2_register(cal->ctx[i]); } - return 0; + if (cal_mc_api) + ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev); + + return ret; } static const struct v4l2_async_notifier_operations cal_async_notifier_ops = { diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index d471b7f82519..db0e408eaa94 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -84,35 +84,34 @@ struct cal_buffer { /** * struct cal_dmaqueue - Queue of DMA buffers - * @active: Buffer being DMA'ed to for the current frame */ struct cal_dmaqueue { /** - * Protects all fields in the cal_dmaqueue. + * @lock: Protects all fields in the cal_dmaqueue. */ spinlock_t lock; /** - * Buffers queued to the driver and waiting for DMA processing. + * @queue: Buffers queued to the driver and waiting for DMA processing. * Buffers are added to the list by the vb2 .buffer_queue() operation, * and move to @pending when they are scheduled for the next frame. */ struct list_head queue; /** - * Buffer provided to the hardware to DMA the next frame. Will move to - * @active at the end of the current frame. + * @pending: Buffer provided to the hardware to DMA the next frame. + * Will move to @active at the end of the current frame. */ struct cal_buffer *pending; /** - * Buffer being DMA'ed to for the current frame. Will be retired and - * given back to vb2 at the end of the current frame if a @pending - * buffer has been scheduled to replace it. + * @active: Buffer being DMA'ed to for the current frame. Will be + * retired and given back to vb2 at the end of the current frame if + * a @pending buffer has been scheduled to replace it. */ struct cal_buffer *active; - /** State of the DMA engine. */ + /** @state: State of the DMA engine. */ enum cal_dma_state state; - /** Wait queue to signal a @state transition to CAL_DMA_STOPPED. */ + /** @wait: Wait queue to signal a @state transition to CAL_DMA_STOPPED. */ struct wait_queue_head wait; }; @@ -160,6 +159,7 @@ struct cal_camerarx { struct device_node *sensor_ep_node; struct device_node *sensor_node; struct v4l2_subdev *sensor; + struct media_pipeline pipe; struct v4l2_subdev subdev; struct media_pad pads[2]; @@ -224,6 +224,7 @@ struct cal_ctx { extern unsigned int cal_debug; extern int cal_video_nr; +extern bool cal_mc_api; #define cal_dbg(level, cal, fmt, arg...) \ do { \ diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c index f4e0cf72d1cf..ff15bc589f1b 100644 --- a/drivers/media/platform/ti-vpe/csc.c +++ b/drivers/media/platform/ti-vpe/csc.c @@ -267,10 +267,8 @@ struct csc_data *csc_create(struct platform_device *pdev, const char *res_name) } csc->base = devm_ioremap_resource(&pdev->dev, csc->res); - if (IS_ERR(csc->base)) { - dev_err(&pdev->dev, "failed to ioremap\n"); + if (IS_ERR(csc->base)) return ERR_CAST(csc->base); - } return csc; } diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c index 98f95082a6fd..0202d278523f 100644 --- a/drivers/media/platform/ti-vpe/sc.c +++ b/drivers/media/platform/ti-vpe/sc.c @@ -294,10 +294,8 @@ struct sc_data *sc_create(struct platform_device *pdev, const char *res_name) } sc->base = devm_ioremap_resource(&pdev->dev, sc->res); - if (IS_ERR(sc->base)) { - dev_err(&pdev->dev, "failed to ioremap\n"); + if (IS_ERR(sc->base)) return ERR_CAST(sc->base); - } return sc; } diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 2e5148ae7a0f..f8998a8ad371 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -942,8 +942,7 @@ int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv) unsigned long flags; spin_lock_irqsave(&vpdma->lock, flags); - for (i = 0; i < VPDMA_MAX_NUM_LIST && - vpdma->hwlist_used[i] == true; i++) + for (i = 0; i < VPDMA_MAX_NUM_LIST && vpdma->hwlist_used[i]; i++) ; if (i < VPDMA_MAX_NUM_LIST) { diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index e07b135613eb..ad3fa1c9cc73 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c @@ -142,7 +142,7 @@ struct vsp1_dl_body_pool { }; /** - * struct vsp1_cmd_pool - Display List commands pool + * struct vsp1_dl_cmd_pool - Display List commands pool * @dma: DMA address of the entries * @size: size of the full DMA memory pool in bytes * @mem: CPU memory pointer for the pool diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h index e85ad4366fbb..ab8b7e3161a2 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.h +++ b/drivers/media/platform/vsp1/vsp1_drm.h @@ -18,7 +18,7 @@ #include "vsp1_pipe.h" /** - * vsp1_drm_pipeline - State for the API exposed to the DRM driver + * struct vsp1_drm_pipeline - State for the API exposed to the DRM driver * @pipe: the VSP1 pipeline used for display * @width: output display width * @height: output display height @@ -47,7 +47,7 @@ struct vsp1_drm_pipeline { }; /** - * vsp1_drm - State for the API exposed to the DRM driver + * struct vsp1_drm - State for the API exposed to the DRM driver * @pipe: the VSP1 DRM pipeline used for display * @lock: protects the BRU and BRS allocation * @inputs: source crop rectangle, destination compose rectangle and z-order diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index bf4015d852e3..2ce31d7ce1a6 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -525,6 +525,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev) if (list_empty(&xdev->notifier.asd_list)) { dev_err(xdev->dev, "no subdev found in graph\n"); + ret = -ENOENT; goto done; } diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index ad488ecbd16c..de107e2cbcd6 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -176,7 +176,7 @@ errfr: static void maxiradio_remove(struct pci_dev *pdev) { - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev); struct maxiradio *dev = to_maxiradio(v4l2_dev); snd_tea575x_exit(&dev->tea); diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 23997425bdb5..b39a68f83c5f 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -152,7 +152,7 @@ static struct v4l2_ctrl_config si476x_ctrls[] = { /* * SI476X during its station seeking(or tuning) process uses several - * parameters to detrmine if "the station" is valid: + * parameters to determine if "the station" is valid: * * - Signal's SNR(in dBuV) must be lower than * #V4L2_CID_SI476X_SNR_THRESHOLD @@ -255,7 +255,7 @@ struct si476x_radio; * * This table holds pointers to functions implementing particular * operations depending on the mode in which the tuner chip was - * configured to start in. If the function is not supported + * configured to start. If the function is not supported * corresponding element is set to #NULL. * * @tune_freq: Tune chip to a specific frequency @@ -917,7 +917,7 @@ static int si476x_radio_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_RDS_RECEPTION: /* * It looks like RDS related properties are - * inaccesable when tuner is in AM mode, so cache the + * inaccessible when tuner is in AM mode, so cache the * changes */ if (si476x_core_is_in_am_receiver_mode(radio->core)) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 8a4b4040be45..f016b35c2b17 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -521,17 +521,6 @@ config RC_XBOX_DVD To compile this driver as a module, choose M here: the module will be called xbox_remote. -config IR_ZX - tristate "ZTE ZX IR remote control" - depends on RC_CORE - depends on ARCH_ZX || COMPILE_TEST - help - Say Y if you want to use the IR remote control available - on ZTE ZX family SoCs. - - To compile this driver as a module, choose M here: the - module will be called zx-irdec. - config IR_TOY tristate "Infrared Toy and IR Droid" depends on RC_CORE diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index ff6a8fc4c38e..f31002288f7c 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -48,7 +48,6 @@ obj-$(CONFIG_IR_IMG) += img-ir/ obj-$(CONFIG_IR_SERIAL) += serial_ir.o obj-$(CONFIG_IR_SIR) += sir_ir.o obj-$(CONFIG_IR_MTK) += mtk-cir.o -obj-$(CONFIG_IR_ZX) += zx-irdec.o obj-$(CONFIG_IR_TANGO) += tango-ir.o obj-$(CONFIG_RC_XBOX_DVD) += xbox_remote.o obj-$(CONFIG_IR_TOY) += ir_toy.o diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index d3af7bca26f5..5da7479c1793 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -617,7 +617,7 @@ unlock: } /** - * img_ir_decoder_compatable() - Find whether a decoder will work with a device. + * img_ir_decoder_compatible() - Find whether a decoder will work with a device. * @priv: IR private data. * @dec: Decoder to check. * diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index 0ffc27514fab..4609fb4519e9 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 Linaro Ltd. - * Copyright (c) 2014 Hisilicon Limited. + * Copyright (c) 2014 HiSilicon Limited. */ #include <linux/clk.h> diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 0c6229592e13..5bc23e8c6d91 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -33,35 +33,10 @@ /* module parameters */ -/* debug level */ -static int debug; -module_param(debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debugging output"); - -/* low limit for RX carrier freq, Hz, 0 for no RX demodulation */ -static int rx_low_carrier_freq; -module_param(rx_low_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, 0 for no RX demodulation"); - -/* high limit for RX carrier freq, Hz, 0 for no RX demodulation */ -static int rx_high_carrier_freq; -module_param(rx_high_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, Hz, 0 for no RX demodulation"); - -/* override tx carrier frequency */ -static int tx_carrier_freq; -module_param(tx_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(tx_carrier_freq, "Override TX carrier frequency, Hz"); - -/* override tx duty cycle */ -static int tx_duty_cycle; -module_param(tx_duty_cycle, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(tx_duty_cycle, "Override TX duty cycle, 1-100"); - -/* override default sample period */ -static long sample_period; +/* default sample period */ +static long sample_period = NSEC_PER_SEC / 115200; module_param(sample_period, long, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(sample_period, "Override carrier sample period, us"); +MODULE_PARM_DESC(sample_period, "sample period"); /* override detected model id */ static int model_number = -1; @@ -101,9 +76,7 @@ static u8 ite_get_carrier_freq_bits(unsigned int freq) freq = ITE_LCF_MAX_CARRIER_FREQ; /* convert to kHz and subtract the base freq */ - freq = - DIV_ROUND_CLOSEST(freq - ITE_LCF_MIN_CARRIER_FREQ, - 1000); + freq = DIV_ROUND_CLOSEST(freq - ITE_LCF_MIN_CARRIER_FREQ, 1000); return (u8) freq; } @@ -161,7 +134,6 @@ static u8 ite_get_pulse_width_bits(unsigned int freq, int duty_cycle) static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int length) { - u32 sample_period; unsigned long *ldata; unsigned int next_one, next_zero, size; struct ir_raw_event ev = {}; @@ -169,14 +141,12 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int if (length == 0) return; - sample_period = dev->params.sample_period; ldata = (unsigned long *)data; size = length << 3; next_one = find_next_bit_le(ldata, size, 0); if (next_one > 0) { ev.pulse = true; - ev.duration = - ITE_BITS_TO_US(next_one, sample_period); + ev.duration = ITE_BITS_TO_US(next_one, sample_period); ir_raw_event_store_with_filter(dev->rdev, &ev); } @@ -187,23 +157,18 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int ir_raw_event_store_with_filter(dev->rdev, &ev); if (next_zero < size) { - next_one = - find_next_bit_le(ldata, - size, - next_zero + 1); + next_one = find_next_bit_le(ldata, size, next_zero + 1); ev.pulse = true; - ev.duration = - ITE_BITS_TO_US(next_one - next_zero, - sample_period); - ir_raw_event_store_with_filter - (dev->rdev, &ev); + ev.duration = ITE_BITS_TO_US(next_one - next_zero, + sample_period); + ir_raw_event_store_with_filter(dev->rdev, &ev); } else next_one = size; } ir_raw_event_handle(dev->rdev); - ite_dbg_verbose("decoded %d bytes.", length); + dev_dbg(&dev->rdev->dev, "decoded %d bytes\n", length); } /* set all the rx/tx carrier parameters; this must be called with the device @@ -215,21 +180,18 @@ static void ite_set_carrier_params(struct ite_dev *dev) bool use_demodulator; bool for_tx = dev->transmitting; - ite_dbg("%s called", __func__); - if (for_tx) { /* we don't need no stinking calculations */ - freq = dev->params.tx_carrier_freq; + freq = dev->tx_carrier_freq; allowance = ITE_RXDCR_DEFAULT; use_demodulator = false; } else { - low_freq = dev->params.rx_low_carrier_freq; - high_freq = dev->params.rx_high_carrier_freq; + low_freq = dev->rx_low_carrier_freq; + high_freq = dev->rx_high_carrier_freq; if (low_freq == 0) { /* don't demodulate */ - freq = - ITE_DEFAULT_CARRIER_FREQ; + freq = ITE_DEFAULT_CARRIER_FREQ; allowance = ITE_RXDCR_DEFAULT; use_demodulator = false; } else { @@ -253,58 +215,58 @@ static void ite_set_carrier_params(struct ite_dev *dev) } /* set the carrier parameters in a device-dependent way */ - dev->params.set_carrier_params(dev, ite_is_high_carrier_freq(freq), + dev->params->set_carrier_params(dev, ite_is_high_carrier_freq(freq), use_demodulator, ite_get_carrier_freq_bits(freq), allowance, - ite_get_pulse_width_bits(freq, dev->params.tx_duty_cycle)); + ite_get_pulse_width_bits(freq, dev->tx_duty_cycle)); } /* interrupt service routine for incoming and outgoing CIR data */ static irqreturn_t ite_cir_isr(int irq, void *data) { struct ite_dev *dev = data; - unsigned long flags; irqreturn_t ret = IRQ_RETVAL(IRQ_NONE); u8 rx_buf[ITE_RX_FIFO_LEN]; int rx_bytes; int iflags; - ite_dbg_verbose("%s firing", __func__); - /* grab the spinlock */ - spin_lock_irqsave(&dev->lock, flags); + spin_lock(&dev->lock); /* read the interrupt flags */ - iflags = dev->params.get_irq_causes(dev); + iflags = dev->params->get_irq_causes(dev); + + /* Check for RX overflow */ + if (iflags & ITE_IRQ_RX_FIFO_OVERRUN) { + dev_warn(&dev->rdev->dev, "receive overflow\n"); + ir_raw_event_reset(dev->rdev); + } /* check for the receive interrupt */ - if (iflags & (ITE_IRQ_RX_FIFO | ITE_IRQ_RX_FIFO_OVERRUN)) { + if (iflags & ITE_IRQ_RX_FIFO) { /* read the FIFO bytes */ - rx_bytes = - dev->params.get_rx_bytes(dev, rx_buf, - ITE_RX_FIFO_LEN); + rx_bytes = dev->params->get_rx_bytes(dev, rx_buf, + ITE_RX_FIFO_LEN); + + dev_dbg(&dev->rdev->dev, "interrupt %d RX bytes\n", rx_bytes); if (rx_bytes > 0) { /* drop the spinlock, since the ir-core layer * may call us back again through * ite_s_idle() */ - spin_unlock_irqrestore(&dev-> - lock, - flags); + spin_unlock(&dev->lock); /* decode the data we've just received */ - ite_decode_bytes(dev, rx_buf, - rx_bytes); + ite_decode_bytes(dev, rx_buf, rx_bytes); /* reacquire the spinlock */ - spin_lock_irqsave(&dev->lock, - flags); + spin_lock(&dev->lock); /* mark the interrupt as serviced */ ret = IRQ_RETVAL(IRQ_HANDLED); } } else if (iflags & ITE_IRQ_TX_FIFO) { /* FIFO space available interrupt */ - ite_dbg_verbose("got interrupt for TX FIFO"); + dev_dbg(&dev->rdev->dev, "interrupt TX FIFO\n"); /* wake any sleeping transmitter */ wake_up_interruptible(&dev->tx_queue); @@ -314,9 +276,7 @@ static irqreturn_t ite_cir_isr(int irq, void *data) } /* drop the spinlock */ - spin_unlock_irqrestore(&dev->lock, flags); - - ite_dbg_verbose("%s done returning %d", __func__, (int)ret); + spin_unlock(&dev->lock); return ret; } @@ -329,8 +289,8 @@ static int ite_set_rx_carrier_range(struct rc_dev *rcdev, u32 carrier_low, u32 struct ite_dev *dev = rcdev->priv; spin_lock_irqsave(&dev->lock, flags); - dev->params.rx_low_carrier_freq = carrier_low; - dev->params.rx_high_carrier_freq = carrier_high; + dev->rx_low_carrier_freq = carrier_low; + dev->rx_high_carrier_freq = carrier_high; ite_set_carrier_params(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -344,7 +304,7 @@ static int ite_set_tx_carrier(struct rc_dev *rcdev, u32 carrier) struct ite_dev *dev = rcdev->priv; spin_lock_irqsave(&dev->lock, flags); - dev->params.tx_carrier_freq = carrier; + dev->tx_carrier_freq = carrier; ite_set_carrier_params(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -358,7 +318,7 @@ static int ite_set_tx_duty_cycle(struct rc_dev *rcdev, u32 duty_cycle) struct ite_dev *dev = rcdev->priv; spin_lock_irqsave(&dev->lock, flags); - dev->params.tx_duty_cycle = duty_cycle; + dev->tx_duty_cycle = duty_cycle; ite_set_carrier_params(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -379,8 +339,6 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) u8 last_sent[ITE_TX_FIFO_LEN]; u8 val; - ite_dbg("%s called", __func__); - /* clear the array just in case */ memset(last_sent, 0, sizeof(last_sent)); @@ -394,32 +352,29 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) /* calculate how much time we can send in one byte */ max_rle_us = - (ITE_BAUDRATE_DIVISOR * dev->params.sample_period * + (ITE_BAUDRATE_DIVISOR * sample_period * ITE_TX_MAX_RLE) / 1000; /* disable the receiver */ - dev->params.disable_rx(dev); + dev->params->disable_rx(dev); /* this is where we'll begin filling in the FIFO, until it's full. * then we'll just activate the interrupt, wait for it to wake us up * again, disable it, continue filling the FIFO... until everything * has been pushed out */ - fifo_avail = - ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); + fifo_avail = ITE_TX_FIFO_LEN - dev->params->get_tx_used_slots(dev); - while (n > 0 && dev->in_use) { + while (n > 0) { /* transmit the next sample */ is_pulse = !is_pulse; remaining_us = *(txbuf++); n--; - ite_dbg("%s: %ld", - ((is_pulse) ? "pulse" : "space"), - (long int) - remaining_us); + dev_dbg(&dev->rdev->dev, "%s: %d\n", + is_pulse ? "pulse" : "space", remaining_us); /* repeat while the pulse is non-zero length */ - while (remaining_us > 0 && dev->in_use) { + while (remaining_us > 0) { if (remaining_us > max_rle_us) next_rle_us = max_rle_us; @@ -450,30 +405,29 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) * some other slot got freed */ if (fifo_avail <= 0) - fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev); + fifo_avail = ITE_TX_FIFO_LEN - dev->params->get_tx_used_slots(dev); /* if it's still full */ if (fifo_avail <= 0) { /* enable the tx interrupt */ - dev->params. - enable_tx_interrupt(dev); + dev->params->enable_tx_interrupt(dev); /* drop the spinlock */ spin_unlock_irqrestore(&dev->lock, flags); /* wait for the FIFO to empty enough */ - wait_event_interruptible(dev->tx_queue, (fifo_avail = ITE_TX_FIFO_LEN - dev->params.get_tx_used_slots(dev)) >= 8); + wait_event_interruptible(dev->tx_queue, + (fifo_avail = ITE_TX_FIFO_LEN - dev->params->get_tx_used_slots(dev)) >= 8); /* get the spinlock again */ spin_lock_irqsave(&dev->lock, flags); /* disable the tx interrupt again. */ - dev->params. - disable_tx_interrupt(dev); + dev->params->disable_tx_interrupt(dev); } /* now send the byte through the FIFO */ - dev->params.put_tx_byte(dev, val); + dev->params->put_tx_byte(dev, val); fifo_avail--; } } @@ -481,7 +435,7 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) /* wait and don't return until the whole FIFO has been sent out; * otherwise we could configure the RX carrier params instead of the * TX ones while the transmission is still being performed! */ - fifo_remaining = dev->params.get_tx_used_slots(dev); + fifo_remaining = dev->params->get_tx_used_slots(dev); remaining_us = 0; while (fifo_remaining > 0) { fifo_remaining--; @@ -507,8 +461,7 @@ static int ite_tx_ir(struct rc_dev *rcdev, unsigned *txbuf, unsigned n) ite_set_carrier_params(dev); /* re-enable the receiver */ - if (dev->in_use) - dev->params.enable_rx(dev); + dev->params->enable_rx(dev); /* notify transmission end */ wake_up_interruptible(&dev->tx_ended); @@ -524,11 +477,9 @@ static void ite_s_idle(struct rc_dev *rcdev, bool enable) unsigned long flags; struct ite_dev *dev = rcdev->priv; - ite_dbg("%s called", __func__); - if (enable) { spin_lock_irqsave(&dev->lock, flags); - dev->params.idle_rx(dev); + dev->params->idle_rx(dev); spin_unlock_irqrestore(&dev->lock, flags); } } @@ -544,8 +495,6 @@ static int it87_get_irq_causes(struct ite_dev *dev) u8 iflags; int ret = 0; - ite_dbg("%s called", __func__); - /* read the interrupt flags */ iflags = inb(dev->cir_addr + IT87_IIR) & IT87_II; @@ -572,8 +521,6 @@ static void it87_set_carrier_params(struct ite_dev *dev, bool high_freq, { u8 val; - ite_dbg("%s called", __func__); - /* program the RCR register */ val = inb(dev->cir_addr + IT87_RCR) & ~(IT87_HCFS | IT87_RXEND | IT87_RXDCR); @@ -599,8 +546,6 @@ static int it87_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) { int fifo, read = 0; - ite_dbg("%s called", __func__); - /* read how many bytes are still in the FIFO */ fifo = inb(dev->cir_addr + IT87_RSR) & IT87_RXFBC; @@ -619,8 +564,6 @@ static int it87_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) * empty; let's expect this won't be a problem */ static int it87_get_tx_used_slots(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - return inb(dev->cir_addr + IT87_TSR) & IT87_TXFBC; } @@ -634,8 +577,6 @@ static void it87_put_tx_byte(struct ite_dev *dev, u8 value) pulse is detected; this must be called with the device spinlock held */ static void it87_idle_rx(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable streaming by clearing RXACT writing it as 1 */ outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXACT, dev->cir_addr + IT87_RCR); @@ -648,8 +589,6 @@ static void it87_idle_rx(struct ite_dev *dev) /* disable the receiver; this must be called with the device spinlock held */ static void it87_disable_rx(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable the receiver interrupts */ outb(inb(dev->cir_addr + IT87_IER) & ~(IT87_RDAIE | IT87_RFOIE), dev->cir_addr + IT87_IER); @@ -666,8 +605,6 @@ static void it87_disable_rx(struct ite_dev *dev) /* enable the receiver; this must be called with the device spinlock held */ static void it87_enable_rx(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* enable the receiver by setting RXEN */ outb(inb(dev->cir_addr + IT87_RCR) | IT87_RXEN, dev->cir_addr + IT87_RCR); @@ -684,8 +621,6 @@ static void it87_enable_rx(struct ite_dev *dev) * spinlock held */ static void it87_disable_tx_interrupt(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable the transmitter interrupts */ outb(inb(dev->cir_addr + IT87_IER) & ~IT87_TLDLIE, dev->cir_addr + IT87_IER); @@ -695,8 +630,6 @@ static void it87_disable_tx_interrupt(struct ite_dev *dev) * spinlock held */ static void it87_enable_tx_interrupt(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* enable the transmitter interrupts and master enable flag */ outb(inb(dev->cir_addr + IT87_IER) | IT87_TLDLIE | IT87_IEC, dev->cir_addr + IT87_IER); @@ -705,8 +638,6 @@ static void it87_enable_tx_interrupt(struct ite_dev *dev) /* disable the device; this must be called with the device spinlock held */ static void it87_disable(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* clear out all interrupt enable flags */ outb(inb(dev->cir_addr + IT87_IER) & ~(IT87_IEC | IT87_RFOIE | IT87_RDAIE | IT87_TLDLIE), @@ -723,8 +654,6 @@ static void it87_disable(struct ite_dev *dev) /* initialize the hardware */ static void it87_init_hardware(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* enable just the baud rate divisor register, disabling all the interrupts at the same time */ outb((inb(dev->cir_addr + IT87_IER) & @@ -761,8 +690,6 @@ static int it8708_get_irq_causes(struct ite_dev *dev) u8 iflags; int ret = 0; - ite_dbg("%s called", __func__); - /* read the interrupt flags */ iflags = inb(dev->cir_addr + IT8708_C0IIR); @@ -784,8 +711,6 @@ static void it8708_set_carrier_params(struct ite_dev *dev, bool high_freq, { u8 val; - ite_dbg("%s called", __func__); - /* program the C0CFR register, with HRAE=1 */ outb(inb(dev->cir_addr + IT8708_BANKSEL) | IT8708_HRAE, dev->cir_addr + IT8708_BANKSEL); @@ -824,8 +749,6 @@ static int it8708_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) { int fifo, read = 0; - ite_dbg("%s called", __func__); - /* read how many bytes are still in the FIFO */ fifo = inb(dev->cir_addr + IT8708_C0RFSR) & IT85_RXFBC; @@ -844,8 +767,6 @@ static int it8708_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) * empty; let's expect this won't be a problem */ static int it8708_get_tx_used_slots(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - return inb(dev->cir_addr + IT8708_C0TFSR) & IT85_TXFBC; } @@ -859,8 +780,6 @@ static void it8708_put_tx_byte(struct ite_dev *dev, u8 value) pulse is detected; this must be called with the device spinlock held */ static void it8708_idle_rx(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable streaming by clearing RXACT writing it as 1 */ outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXACT, dev->cir_addr + IT8708_C0RCR); @@ -873,8 +792,6 @@ static void it8708_idle_rx(struct ite_dev *dev) /* disable the receiver; this must be called with the device spinlock held */ static void it8708_disable_rx(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable the receiver interrupts */ outb(inb(dev->cir_addr + IT8708_C0IER) & ~(IT85_RDAIE | IT85_RFOIE), @@ -892,8 +809,6 @@ static void it8708_disable_rx(struct ite_dev *dev) /* enable the receiver; this must be called with the device spinlock held */ static void it8708_enable_rx(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* enable the receiver by setting RXEN */ outb(inb(dev->cir_addr + IT8708_C0RCR) | IT85_RXEN, dev->cir_addr + IT8708_C0RCR); @@ -911,8 +826,6 @@ static void it8708_enable_rx(struct ite_dev *dev) * spinlock held */ static void it8708_disable_tx_interrupt(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable the transmitter interrupts */ outb(inb(dev->cir_addr + IT8708_C0IER) & ~IT85_TLDLIE, dev->cir_addr + IT8708_C0IER); @@ -922,8 +835,6 @@ static void it8708_disable_tx_interrupt(struct ite_dev *dev) * spinlock held */ static void it8708_enable_tx_interrupt(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* enable the transmitter interrupts and master enable flag */ outb(inb(dev->cir_addr + IT8708_C0IER) |IT85_TLDLIE | IT85_IEC, @@ -933,8 +844,6 @@ static void it8708_enable_tx_interrupt(struct ite_dev *dev) /* disable the device; this must be called with the device spinlock held */ static void it8708_disable(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* clear out all interrupt enable flags */ outb(inb(dev->cir_addr + IT8708_C0IER) & ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), @@ -951,8 +860,6 @@ static void it8708_disable(struct ite_dev *dev) /* initialize the hardware */ static void it8708_init_hardware(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable all the interrupts */ outb(inb(dev->cir_addr + IT8708_C0IER) & ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), @@ -1058,8 +965,6 @@ static int it8709_get_irq_causes(struct ite_dev *dev) u8 iflags; int ret = 0; - ite_dbg("%s called", __func__); - /* read the interrupt flags */ iflags = it8709_rm(dev, IT8709_IIR); @@ -1081,8 +986,6 @@ static void it8709_set_carrier_params(struct ite_dev *dev, bool high_freq, { u8 val; - ite_dbg("%s called", __func__); - val = (it8709_rr(dev, IT85_C0CFR) &~(IT85_HCFS | IT85_CFQ)) | carrier_freq_bits; @@ -1115,8 +1018,6 @@ static int it8709_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) { int fifo, read = 0; - ite_dbg("%s called", __func__); - /* read how many bytes are still in the FIFO */ fifo = it8709_rm(dev, IT8709_RFSR) & IT85_RXFBC; @@ -1140,8 +1041,6 @@ static int it8709_get_rx_bytes(struct ite_dev *dev, u8 * buf, int buf_size) * empty; let's expect this won't be a problem */ static int it8709_get_tx_used_slots(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - return it8709_rr(dev, IT85_C0TFSR) & IT85_TXFBC; } @@ -1155,8 +1054,6 @@ static void it8709_put_tx_byte(struct ite_dev *dev, u8 value) pulse is detected; this must be called with the device spinlock held */ static void it8709_idle_rx(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable streaming by clearing RXACT writing it as 1 */ it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXACT, IT85_C0RCR); @@ -1169,8 +1066,6 @@ static void it8709_idle_rx(struct ite_dev *dev) /* disable the receiver; this must be called with the device spinlock held */ static void it8709_disable_rx(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable the receiver interrupts */ it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & ~(IT85_RDAIE | IT85_RFOIE), @@ -1188,8 +1083,6 @@ static void it8709_disable_rx(struct ite_dev *dev) /* enable the receiver; this must be called with the device spinlock held */ static void it8709_enable_rx(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* enable the receiver by setting RXEN */ it8709_wr(dev, it8709_rr(dev, IT85_C0RCR) | IT85_RXEN, IT85_C0RCR); @@ -1207,8 +1100,6 @@ static void it8709_enable_rx(struct ite_dev *dev) * spinlock held */ static void it8709_disable_tx_interrupt(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable the transmitter interrupts */ it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & ~IT85_TLDLIE, IT85_C0IER); @@ -1218,8 +1109,6 @@ static void it8709_disable_tx_interrupt(struct ite_dev *dev) * spinlock held */ static void it8709_enable_tx_interrupt(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* enable the transmitter interrupts and master enable flag */ it8709_wr(dev, it8709_rr(dev, IT85_C0IER) |IT85_TLDLIE | IT85_IEC, @@ -1229,8 +1118,6 @@ static void it8709_enable_tx_interrupt(struct ite_dev *dev) /* disable the device; this must be called with the device spinlock held */ static void it8709_disable(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* clear out all interrupt enable flags */ it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), @@ -1247,8 +1134,6 @@ static void it8709_disable(struct ite_dev *dev) /* initialize the hardware */ static void it8709_init_hardware(struct ite_dev *dev) { - ite_dbg("%s called", __func__); - /* disable all the interrupts */ it8709_wr(dev, it8709_rr(dev, IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE), @@ -1290,13 +1175,10 @@ static int ite_open(struct rc_dev *rcdev) struct ite_dev *dev = rcdev->priv; unsigned long flags; - ite_dbg("%s called", __func__); - spin_lock_irqsave(&dev->lock, flags); - dev->in_use = true; /* enable the receiver */ - dev->params.enable_rx(dev); + dev->params->enable_rx(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -1309,17 +1191,14 @@ static void ite_close(struct rc_dev *rcdev) struct ite_dev *dev = rcdev->priv; unsigned long flags; - ite_dbg("%s called", __func__); - spin_lock_irqsave(&dev->lock, flags); - dev->in_use = false; /* wait for any transmission to end */ spin_unlock_irqrestore(&dev->lock, flags); wait_event_interruptible(dev->tx_ended, !dev->transmitting); spin_lock_irqsave(&dev->lock, flags); - dev->params.disable(dev); + dev->params->disable(dev); spin_unlock_irqrestore(&dev->lock, flags); } @@ -1330,12 +1209,6 @@ static const struct ite_dev_params ite_dev_descs[] = { .model = "ITE8704 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, .io_rsrc_no = 0, - .hw_tx_capable = true, - .sample_period = (u32) (1000000000ULL / 115200), - .tx_carrier_freq = 38000, - .tx_duty_cycle = 33, - .rx_low_carrier_freq = 0, - .rx_high_carrier_freq = 0, /* operations */ .get_irq_causes = it87_get_irq_causes, @@ -1355,12 +1228,6 @@ static const struct ite_dev_params ite_dev_descs[] = { .model = "ITE8713 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, .io_rsrc_no = 0, - .hw_tx_capable = true, - .sample_period = (u32) (1000000000ULL / 115200), - .tx_carrier_freq = 38000, - .tx_duty_cycle = 33, - .rx_low_carrier_freq = 0, - .rx_high_carrier_freq = 0, /* operations */ .get_irq_causes = it87_get_irq_causes, @@ -1380,12 +1247,6 @@ static const struct ite_dev_params ite_dev_descs[] = { .model = "ITE8708 CIR transceiver", .io_region_size = IT8708_IOREG_LENGTH, .io_rsrc_no = 0, - .hw_tx_capable = true, - .sample_period = (u32) (1000000000ULL / 115200), - .tx_carrier_freq = 38000, - .tx_duty_cycle = 33, - .rx_low_carrier_freq = 0, - .rx_high_carrier_freq = 0, /* operations */ .get_irq_causes = it8708_get_irq_causes, @@ -1406,12 +1267,6 @@ static const struct ite_dev_params ite_dev_descs[] = { .model = "ITE8709 CIR transceiver", .io_region_size = IT8709_IOREG_LENGTH, .io_rsrc_no = 2, - .hw_tx_capable = true, - .sample_period = (u32) (1000000000ULL / 115200), - .tx_carrier_freq = 38000, - .tx_duty_cycle = 33, - .rx_low_carrier_freq = 0, - .rx_high_carrier_freq = 0, /* operations */ .get_irq_causes = it8709_get_irq_causes, @@ -1449,8 +1304,6 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id int model_no; int io_rsrc_no; - ite_dbg("%s called", __func__); - itdev = kzalloc(sizeof(struct ite_dev), GFP_KERNEL); if (!itdev) return ret; @@ -1465,23 +1318,22 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* get the model number */ model_no = (int)dev_id->driver_data; - ite_pr(KERN_NOTICE, "Auto-detected model: %s\n", + dev_dbg(&pdev->dev, "Auto-detected model: %s\n", ite_dev_descs[model_no].model); if (model_number >= 0 && model_number < ARRAY_SIZE(ite_dev_descs)) { model_no = model_number; - ite_pr(KERN_NOTICE, "The model has been fixed by a module parameter."); + dev_info(&pdev->dev, "model has been forced to: %s", + ite_dev_descs[model_no].model); } - ite_pr(KERN_NOTICE, "Using model: %s\n", ite_dev_descs[model_no].model); - /* get the description for the device */ dev_desc = &ite_dev_descs[model_no]; io_rsrc_no = dev_desc->io_rsrc_no; /* validate pnp resources */ if (!pnp_port_valid(pdev, io_rsrc_no) || - pnp_port_len(pdev, io_rsrc_no) != dev_desc->io_region_size) { + pnp_port_len(pdev, io_rsrc_no) < dev_desc->io_region_size) { dev_err(&pdev->dev, "IR PNP Port not valid!\n"); goto exit_free_dev_rdev; } @@ -1506,44 +1358,17 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id init_waitqueue_head(&itdev->tx_queue); init_waitqueue_head(&itdev->tx_ended); - /* copy model-specific parameters */ - itdev->params = *dev_desc; - - /* apply any overrides */ - if (sample_period > 0) - itdev->params.sample_period = sample_period; - - if (tx_carrier_freq > 0) - itdev->params.tx_carrier_freq = tx_carrier_freq; - - if (tx_duty_cycle > 0 && tx_duty_cycle <= 100) - itdev->params.tx_duty_cycle = tx_duty_cycle; - - if (rx_low_carrier_freq > 0) - itdev->params.rx_low_carrier_freq = rx_low_carrier_freq; - - if (rx_high_carrier_freq > 0) - itdev->params.rx_high_carrier_freq = rx_high_carrier_freq; - - /* print out parameters */ - ite_pr(KERN_NOTICE, "TX-capable: %d\n", (int) - itdev->params.hw_tx_capable); - ite_pr(KERN_NOTICE, "Sample period (ns): %ld\n", (long) - itdev->params.sample_period); - ite_pr(KERN_NOTICE, "TX carrier frequency (Hz): %d\n", (int) - itdev->params.tx_carrier_freq); - ite_pr(KERN_NOTICE, "TX duty cycle (%%): %d\n", (int) - itdev->params.tx_duty_cycle); - ite_pr(KERN_NOTICE, "RX low carrier frequency (Hz): %d\n", (int) - itdev->params.rx_low_carrier_freq); - ite_pr(KERN_NOTICE, "RX high carrier frequency (Hz): %d\n", (int) - itdev->params.rx_high_carrier_freq); + /* Set model-specific parameters */ + itdev->params = dev_desc; /* set up hardware initial state */ - itdev->params.init_hardware(itdev); + itdev->tx_duty_cycle = 33; + itdev->tx_carrier_freq = ITE_DEFAULT_CARRIER_FREQ; + itdev->params->init_hardware(itdev); /* set up ir-core props */ rdev->priv = itdev; + rdev->dev.parent = &pdev->dev; rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rdev->open = ite_open; rdev->close = ite_close; @@ -1551,20 +1376,16 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id rdev->s_rx_carrier_range = ite_set_rx_carrier_range; /* FIFO threshold is 17 bytes, so 17 * 8 samples minimum */ rdev->min_timeout = 17 * 8 * ITE_BAUDRATE_DIVISOR * - itdev->params.sample_period / 1000; + sample_period / 1000; rdev->timeout = IR_DEFAULT_TIMEOUT; rdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; - rdev->rx_resolution = ITE_BAUDRATE_DIVISOR * - itdev->params.sample_period / 1000; - rdev->tx_resolution = ITE_BAUDRATE_DIVISOR * - itdev->params.sample_period / 1000; - - /* set up transmitter related values if needed */ - if (itdev->params.hw_tx_capable) { - rdev->tx_ir = ite_tx_ir; - rdev->s_tx_carrier = ite_set_tx_carrier; - rdev->s_tx_duty_cycle = ite_set_tx_duty_cycle; - } + rdev->rx_resolution = ITE_BAUDRATE_DIVISOR * sample_period / 1000; + rdev->tx_resolution = ITE_BAUDRATE_DIVISOR * sample_period / 1000; + + /* set up transmitter related values */ + rdev->tx_ir = ite_tx_ir; + rdev->s_tx_carrier = ite_set_tx_carrier; + rdev->s_tx_duty_cycle = ite_set_tx_duty_cycle; rdev->device_name = dev_desc->model; rdev->input_id.bustype = BUS_HOST; @@ -1588,12 +1409,10 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id ITE_DRIVER_NAME, (void *)itdev)) goto exit_release_cir_addr; - ite_pr(KERN_NOTICE, "driver has been successfully loaded\n"); - return 0; exit_release_cir_addr: - release_region(itdev->cir_addr, itdev->params.io_region_size); + release_region(itdev->cir_addr, itdev->params->io_region_size); exit_unregister_device: rc_unregister_device(rdev); rdev = NULL; @@ -1609,18 +1428,16 @@ static void ite_remove(struct pnp_dev *pdev) struct ite_dev *dev = pnp_get_drvdata(pdev); unsigned long flags; - ite_dbg("%s called", __func__); - spin_lock_irqsave(&dev->lock, flags); /* disable hardware */ - dev->params.disable(dev); + dev->params->disable(dev); spin_unlock_irqrestore(&dev->lock, flags); /* free resources */ free_irq(dev->cir_irq, dev); - release_region(dev->cir_addr, dev->params.io_region_size); + release_region(dev->cir_addr, dev->params->io_region_size); rc_unregister_device(dev->rdev); @@ -1632,15 +1449,13 @@ static int ite_suspend(struct pnp_dev *pdev, pm_message_t state) struct ite_dev *dev = pnp_get_drvdata(pdev); unsigned long flags; - ite_dbg("%s called", __func__); - /* wait for any transmission to end */ wait_event_interruptible(dev->tx_ended, !dev->transmitting); spin_lock_irqsave(&dev->lock, flags); /* disable all interrupts */ - dev->params.disable(dev); + dev->params->disable(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -1652,14 +1467,12 @@ static int ite_resume(struct pnp_dev *pdev) struct ite_dev *dev = pnp_get_drvdata(pdev); unsigned long flags; - ite_dbg("%s called", __func__); - spin_lock_irqsave(&dev->lock, flags); /* reinitialize hardware config registers */ - dev->params.init_hardware(dev); + dev->params->init_hardware(dev); /* enable the receiver */ - dev->params.enable_rx(dev); + dev->params->enable_rx(dev); spin_unlock_irqrestore(&dev->lock, flags); @@ -1671,12 +1484,10 @@ static void ite_shutdown(struct pnp_dev *pdev) struct ite_dev *dev = pnp_get_drvdata(pdev); unsigned long flags; - ite_dbg("%s called", __func__); - spin_lock_irqsave(&dev->lock, flags); /* disable all interrupts */ - dev->params.disable(dev); + dev->params->disable(dev); spin_unlock_irqrestore(&dev->lock, flags); } diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h index 4954470448a7..ce7a40b10828 100644 --- a/drivers/media/rc/ite-cir.h +++ b/drivers/media/rc/ite-cir.h @@ -8,21 +8,6 @@ /* platform driver name to register */ #define ITE_DRIVER_NAME "ite-cir" -/* logging macros */ -#define ite_pr(level, text, ...) \ - printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) -#define ite_dbg(text, ...) do { \ - if (debug) \ - printk(KERN_DEBUG \ - KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \ -} while (0) - -#define ite_dbg_verbose(text, ...) do {\ - if (debug > 1) \ - printk(KERN_DEBUG \ - KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__); \ -} while (0) - /* FIFO sizes */ #define ITE_TX_FIFO_LEN 32 #define ITE_RX_FIFO_LEN 32 @@ -46,24 +31,6 @@ struct ite_dev_params { /* IR pnp I/O resource number */ int io_rsrc_no; - /* true if the hardware supports transmission */ - bool hw_tx_capable; - - /* base sampling period, in ns */ - u32 sample_period; - - /* rx low carrier frequency, in Hz, 0 means no demodulation */ - unsigned int rx_low_carrier_freq; - - /* tx high carrier frequency, in Hz, 0 means no demodulation */ - unsigned int rx_high_carrier_freq; - - /* tx carrier frequency, in Hz */ - unsigned int tx_carrier_freq; - - /* duty cycle, 0-100 */ - int tx_duty_cycle; - /* hw-specific operation function pointers; most of these must be * called while holding the spin lock, except for the TX FIFO length * one */ @@ -111,22 +78,32 @@ struct ite_dev_params { struct ite_dev { struct pnp_dev *pdev; struct rc_dev *rdev; - struct ir_raw_event rawir; /* sync data */ spinlock_t lock; - bool in_use, transmitting; + bool transmitting; /* transmit support */ - int tx_fifo_allowance; wait_queue_head_t tx_queue, tx_ended; + /* rx low carrier frequency, in Hz, 0 means no demodulation */ + unsigned int rx_low_carrier_freq; + + /* tx high carrier frequency, in Hz, 0 means no demodulation */ + unsigned int rx_high_carrier_freq; + + /* tx carrier frequency, in Hz */ + unsigned int tx_carrier_freq; + + /* duty cycle, 0-100 */ + int tx_duty_cycle; + /* hardware I/O settings */ unsigned long cir_addr; int cir_irq; /* overridable copy of model parameters */ - struct ite_dev_params params; + const struct ite_dev_params *params; }; /* common values for all kinds of hardware */ diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index cc6662e1903f..50b2833dbe4f 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -66,9 +66,12 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-leadtek-y04g0051.o \ rc-lme2510.o \ rc-manli.o \ + rc-mecool-kii-pro.o \ + rc-mecool-kiii-pro.o \ rc-medion-x10.o \ rc-medion-x10-digitainer.o \ rc-medion-x10-or2x.o \ + rc-minix-neo.o \ rc-msi-digivox-ii.o \ rc-msi-digivox-iii.o \ rc-msi-tvanywhere.o \ @@ -126,6 +129,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-winfast.o \ rc-winfast-usbii-deluxe.o \ rc-su3000.o \ + rc-xbox-360.o \ rc-xbox-dvd.o \ rc-x96max.o \ rc-zx-irdec.o diff --git a/drivers/media/rc/keymaps/rc-mecool-kii-pro.c b/drivers/media/rc/keymaps/rc-mecool-kii-pro.c new file mode 100644 index 000000000000..77ca8a8fade8 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-mecool-kii-pro.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2021 Christian Hewitt <christianshewitt@gmail.com> + +#include <media/rc-map.h> +#include <linux/module.h> + +// +// Keytable for the Mecool Kii Pro remote control +// + +static struct rc_map_table mecool_kii_pro[] = { + { 0x59, KEY_POWER }, + { 0x19, KEY_MUTE }, + + { 0x42, KEY_RED }, + { 0x40, KEY_GREEN }, + { 0x00, KEY_YELLOW}, + { 0x03, KEY_BLUE }, + + { 0x4a, KEY_REWIND }, + { 0x48, KEY_FORWARD }, + { 0x08, KEY_PREVIOUSSONG}, + { 0x0b, KEY_NEXTSONG}, + + { 0x46, KEY_PLAYPAUSE }, + { 0x44, KEY_STOP }, + { 0x1f, KEY_FAVORITES}, + { 0x04, KEY_PVR }, + + { 0x4d, KEY_EPG }, + { 0x02, KEY_INFO }, + { 0x09, KEY_SUBTITLE }, + { 0x01, KEY_LANGUAGE }, // AUDIO + + { 0x0d, KEY_HOME }, + { 0x11, KEY_TV }, + { 0x45, KEY_MENU }, + { 0x05, KEY_EXIT }, + + { 0x5a, KEY_LEFT }, + { 0x1b, KEY_RIGHT }, + { 0x06, KEY_UP }, + { 0x16, KEY_DOWN }, + { 0x1a, KEY_OK }, + + { 0x13, KEY_VOLUMEUP }, + { 0x17, KEY_VOLUMEDOWN }, + { 0x58, KEY_APPSELECT }, // APPS + { 0x12, KEY_CONTEXT_MENU }, // MOUSE + { 0x55, KEY_CHANNELUP }, // PAGE_UP + { 0x15, KEY_CHANNELDOWN }, // PAGE_DOWN + + { 0x52, KEY_1 }, + { 0x50, KEY_2 }, + { 0x10, KEY_3 }, + { 0x56, KEY_4 }, + { 0x54, KEY_5 }, + { 0x14, KEY_6 }, + { 0x4e, KEY_7 }, + { 0x4c, KEY_8 }, + { 0x0c, KEY_9 }, + { 0x18, KEY_WWW }, + { 0x0f, KEY_0 }, + { 0x51, KEY_DELETE }, +}; + +static struct rc_map_list mecool_kii_pro_map = { + .map = { + .scan = mecool_kii_pro, + .size = ARRAY_SIZE(mecool_kii_pro), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_MECOOL_KII_PRO, + } +}; + +static int __init init_rc_map_mecool_kii_pro(void) +{ + return rc_map_register(&mecool_kii_pro_map); +} + +static void __exit exit_rc_map_mecool_kii_pro(void) +{ + rc_map_unregister(&mecool_kii_pro_map); +} + +module_init(init_rc_map_mecool_kii_pro) +module_exit(exit_rc_map_mecool_kii_pro) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); diff --git a/drivers/media/rc/keymaps/rc-mecool-kiii-pro.c b/drivers/media/rc/keymaps/rc-mecool-kiii-pro.c new file mode 100644 index 000000000000..8e99686fd6b1 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-mecool-kiii-pro.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2021 Christian Hewitt <christianshewitt@gmail.com> + +#include <media/rc-map.h> +#include <linux/module.h> + +// +// Keytable for the Mecool Kiii Pro remote control +// + +static struct rc_map_table mecool_kiii_pro[] = { + { 0x59, KEY_POWER }, + + { 0x52, KEY_1 }, + { 0x50, KEY_2 }, + { 0x10, KEY_3 }, + { 0x56, KEY_4 }, + { 0x54, KEY_5 }, + { 0x14, KEY_6 }, + { 0x4e, KEY_7 }, + { 0x4c, KEY_8 }, + { 0x0c, KEY_9 }, + { 0x02, KEY_INFO }, + { 0x0f, KEY_0 }, + { 0x51, KEY_DELETE }, + { 0x1f, KEY_FAVORITES}, + { 0x09, KEY_SUBTITLE }, + { 0x01, KEY_LANGUAGE }, // AUDIO + + { 0x42, KEY_RED }, + { 0x40, KEY_GREEN }, + { 0x00, KEY_YELLOW}, + { 0x03, KEY_BLUE }, // RADIO + + { 0x0d, KEY_HOME }, + { 0x4d, KEY_EPG }, + { 0x45, KEY_MENU }, + { 0x05, KEY_EXIT }, + + { 0x5a, KEY_LEFT }, + { 0x1b, KEY_RIGHT }, + { 0x06, KEY_UP }, + { 0x16, KEY_DOWN }, + { 0x1a, KEY_OK }, + + { 0x13, KEY_VOLUMEUP }, + { 0x17, KEY_VOLUMEDOWN }, + { 0x19, KEY_MUTE }, + { 0x12, KEY_CONTEXT_MENU }, // MOUSE + { 0x55, KEY_CHANNELUP }, // PAGE_UP + { 0x15, KEY_CHANNELDOWN }, // PAGE_DOWN + + { 0x4a, KEY_REWIND }, + { 0x48, KEY_FORWARD }, + { 0x46, KEY_PLAYPAUSE }, + { 0x44, KEY_STOP }, + + { 0x08, KEY_PREVIOUSSONG}, + { 0x0b, KEY_NEXTSONG}, + { 0x04, KEY_PVR }, + { 0x64, KEY_RECORD }, +}; + +static struct rc_map_list mecool_kiii_pro_map = { + .map = { + .scan = mecool_kiii_pro, + .size = ARRAY_SIZE(mecool_kiii_pro), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_MECOOL_KIII_PRO, + } +}; + +static int __init init_rc_map_mecool_kiii_pro(void) +{ + return rc_map_register(&mecool_kiii_pro_map); +} + +static void __exit exit_rc_map_mecool_kiii_pro(void) +{ + rc_map_unregister(&mecool_kiii_pro_map); +} + +module_init(init_rc_map_mecool_kiii_pro) +module_exit(exit_rc_map_mecool_kiii_pro) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); diff --git a/drivers/media/rc/keymaps/rc-minix-neo.c b/drivers/media/rc/keymaps/rc-minix-neo.c new file mode 100644 index 000000000000..9165af548ff1 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-minix-neo.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2021 Christian Hewitt <christianshewitt@gmail.com> + +#include <media/rc-map.h> +#include <linux/module.h> + +// +// Keytable for the Minix NEO remote control +// + +static struct rc_map_table minix_neo[] = { + + { 0x118, KEY_POWER }, + + { 0x146, KEY_UP }, + { 0x116, KEY_DOWN }, + { 0x147, KEY_LEFT }, + { 0x115, KEY_RIGHT }, + { 0x155, KEY_ENTER }, + + { 0x110, KEY_VOLUMEDOWN }, + { 0x140, KEY_BACK }, + { 0x114, KEY_VOLUMEUP }, + + { 0x10d, KEY_HOME }, + { 0x104, KEY_MENU }, + { 0x112, KEY_CONFIG }, + +}; + +static struct rc_map_list minix_neo_map = { + .map = { + .scan = minix_neo, + .size = ARRAY_SIZE(minix_neo), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_MINIX_NEO, + } +}; + +static int __init init_rc_map_minix_neo(void) +{ + return rc_map_register(&minix_neo_map); +} + +static void __exit exit_rc_map_minix_neo(void) +{ + rc_map_unregister(&minix_neo_map); +} + +module_init(init_rc_map_minix_neo) +module_exit(exit_rc_map_minix_neo) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Hewitt <christianshewitt@gmail.com"); diff --git a/drivers/media/rc/keymaps/rc-xbox-360.c b/drivers/media/rc/keymaps/rc-xbox-360.c new file mode 100644 index 000000000000..231aa00514af --- /dev/null +++ b/drivers/media/rc/keymaps/rc-xbox-360.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Keytable for Xbox 360 Universal Media remote +// Copyright (c) 2021 Bastien Nocera <hadess@hadess.net> + +#include <media/rc-map.h> +#include <linux/module.h> + +/* + * Manual for remote available at: + * http://download.microsoft.com/download/b/c/e/bce76f3f-db51-4c98-b79d-b3d21e90ccc1/universalmediaremote_na_0609.pdf + */ +static struct rc_map_table xbox_360[] = { + {KEY_EJECTCD, 0x800f7428}, + {KEY_HOMEPAGE, 0x800f7464}, + {KEY_POWER, 0x800f740c}, + {KEY_STOP, 0x800f7419}, + {KEY_PAUSE, 0x800f7418}, + {KEY_REWIND, 0x800f7415}, + {KEY_FASTFORWARD, 0x800f7414}, + {KEY_PREVIOUS, 0x800f741b}, + {KEY_NEXT, 0x800f741a}, + {KEY_PLAY, 0x800f7416}, + {KEY_PROPS, 0x800f744f}, /* "Display" */ + {KEY_BACK, 0x800f7423}, + {KEY_MEDIA_TOP_MENU, 0x800f7424}, /* "DVD Menu" */ + {KEY_ROOT_MENU, 0x800f7451}, /* "Title" */ + {KEY_INFO, 0x800f740f}, + {KEY_UP, 0x800f741e}, + {KEY_LEFT, 0x800f7420}, + {KEY_RIGHT, 0x800f7421}, + {KEY_DOWN, 0x800f741f}, + {KEY_OK, 0x800f7422}, + {KEY_YELLOW, 0x800f7426}, + {KEY_BLUE, 0x800f7468}, + {KEY_GREEN, 0x800f7466}, + {KEY_RED, 0x800f7425}, + {KEY_VOLUMEUP, 0x800f7410}, + {KEY_VOLUMEDOWN, 0x800f7411}, + /* TV key doesn't light the IR LED */ + {KEY_MUTE, 0x800f740e}, + {KEY_CHANNELUP, 0x800f746c}, + {KEY_CHANNELDOWN, 0x800f746d}, + {KEY_LEFTMETA, 0x800f740d}, + {KEY_ENTER, 0x800f740b}, + {KEY_RECORD, 0x800f7417}, + {KEY_CLEAR, 0x800f740a}, + {KEY_NUMERIC_1, 0x800f7401}, + {KEY_NUMERIC_2, 0x800f7402}, + {KEY_NUMERIC_3, 0x800f7403}, + {KEY_NUMERIC_4, 0x800f7404}, + {KEY_NUMERIC_5, 0x800f7405}, + {KEY_NUMERIC_6, 0x800f7406}, + {KEY_NUMERIC_7, 0x800f7407}, + {KEY_NUMERIC_8, 0x800f7408}, + {KEY_NUMERIC_9, 0x800f7409}, + {KEY_NUMERIC_0, 0x800f7400}, + {KEY_102ND, 0x800f741d}, /* "100" */ + {KEY_CANCEL, 0x800f741c}, +}; + +static struct rc_map_list xbox_360_map = { + .map = { + .scan = xbox_360, + .size = ARRAY_SIZE(xbox_360), + .rc_proto = RC_PROTO_RC6_MCE, + .name = RC_MAP_XBOX_360, + } +}; + +static int __init init_rc_map(void) +{ + return rc_map_register(&xbox_360_map); +} + +static void __exit exit_rc_map(void) +{ + rc_map_unregister(&xbox_360_map); +} + +module_init(init_rc_map) +module_exit(exit_rc_map) + +MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/zx-irdec.c b/drivers/media/rc/zx-irdec.c deleted file mode 100644 index 948ad90ae5d8..000000000000 --- a/drivers/media/rc/zx-irdec.c +++ /dev/null @@ -1,181 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2017 Sanechips Technology Co., Ltd. - * Copyright 2017 Linaro Ltd. - */ - -#include <linux/device.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of_platform.h> -#include <linux/platform_device.h> - -#include <media/rc-core.h> - -#define DRIVER_NAME "zx-irdec" - -#define ZX_IR_ENABLE 0x04 -#define ZX_IREN BIT(0) -#define ZX_IR_CTRL 0x08 -#define ZX_DEGL_MASK GENMASK(21, 20) -#define ZX_DEGL_VALUE(x) (((x) << 20) & ZX_DEGL_MASK) -#define ZX_WDBEGIN_MASK GENMASK(18, 8) -#define ZX_WDBEGIN_VALUE(x) (((x) << 8) & ZX_WDBEGIN_MASK) -#define ZX_IR_INTEN 0x10 -#define ZX_IR_INTSTCLR 0x14 -#define ZX_IR_CODE 0x30 -#define ZX_IR_CNUM 0x34 -#define ZX_NECRPT BIT(16) - -struct zx_irdec { - void __iomem *base; - struct rc_dev *rcd; -}; - -static void zx_irdec_set_mask(struct zx_irdec *irdec, unsigned int reg, - u32 mask, u32 value) -{ - u32 data; - - data = readl(irdec->base + reg); - data &= ~mask; - data |= value & mask; - writel(data, irdec->base + reg); -} - -static irqreturn_t zx_irdec_irq(int irq, void *dev_id) -{ - struct zx_irdec *irdec = dev_id; - u8 address, not_address; - u8 command, not_command; - u32 rawcode, scancode; - enum rc_proto rc_proto; - - /* Clear interrupt */ - writel(1, irdec->base + ZX_IR_INTSTCLR); - - /* Check repeat frame */ - if (readl(irdec->base + ZX_IR_CNUM) & ZX_NECRPT) { - rc_repeat(irdec->rcd); - goto done; - } - - rawcode = readl(irdec->base + ZX_IR_CODE); - not_command = (rawcode >> 24) & 0xff; - command = (rawcode >> 16) & 0xff; - not_address = (rawcode >> 8) & 0xff; - address = rawcode & 0xff; - - scancode = ir_nec_bytes_to_scancode(address, not_address, - command, not_command, - &rc_proto); - rc_keydown(irdec->rcd, rc_proto, scancode, 0); - -done: - return IRQ_HANDLED; -} - -static int zx_irdec_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct zx_irdec *irdec; - struct resource *res; - struct rc_dev *rcd; - int irq; - int ret; - - irdec = devm_kzalloc(dev, sizeof(*irdec), GFP_KERNEL); - if (!irdec) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - irdec->base = devm_ioremap_resource(dev, res); - if (IS_ERR(irdec->base)) - return PTR_ERR(irdec->base); - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - rcd = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE); - if (!rcd) { - dev_err(dev, "failed to allocate rc device\n"); - return -ENOMEM; - } - - irdec->rcd = rcd; - - rcd->priv = irdec; - rcd->input_phys = DRIVER_NAME "/input0"; - rcd->input_id.bustype = BUS_HOST; - rcd->map_name = RC_MAP_ZX_IRDEC; - rcd->allowed_protocols = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | - RC_PROTO_BIT_NEC32; - rcd->driver_name = DRIVER_NAME; - rcd->device_name = DRIVER_NAME; - - platform_set_drvdata(pdev, irdec); - - ret = devm_rc_register_device(dev, rcd); - if (ret) { - dev_err(dev, "failed to register rc device\n"); - return ret; - } - - ret = devm_request_irq(dev, irq, zx_irdec_irq, 0, NULL, irdec); - if (ret) { - dev_err(dev, "failed to request irq\n"); - return ret; - } - - /* - * Initialize deglitch level and watchdog counter beginner as - * recommended by vendor BSP code. - */ - zx_irdec_set_mask(irdec, ZX_IR_CTRL, ZX_DEGL_MASK, ZX_DEGL_VALUE(0)); - zx_irdec_set_mask(irdec, ZX_IR_CTRL, ZX_WDBEGIN_MASK, - ZX_WDBEGIN_VALUE(0x21c)); - - /* Enable interrupt */ - writel(1, irdec->base + ZX_IR_INTEN); - - /* Enable the decoder */ - zx_irdec_set_mask(irdec, ZX_IR_ENABLE, ZX_IREN, ZX_IREN); - - return 0; -} - -static int zx_irdec_remove(struct platform_device *pdev) -{ - struct zx_irdec *irdec = platform_get_drvdata(pdev); - - /* Disable the decoder */ - zx_irdec_set_mask(irdec, ZX_IR_ENABLE, ZX_IREN, 0); - - /* Disable interrupt */ - writel(0, irdec->base + ZX_IR_INTEN); - - return 0; -} - -static const struct of_device_id zx_irdec_match[] = { - { .compatible = "zte,zx296718-irdec" }, - { }, -}; -MODULE_DEVICE_TABLE(of, zx_irdec_match); - -static struct platform_driver zx_irdec_driver = { - .probe = zx_irdec_probe, - .remove = zx_irdec_remove, - .driver = { - .name = DRIVER_NAME, - .of_match_table = zx_irdec_match, - }, -}; -module_platform_driver(zx_irdec_driver); - -MODULE_DESCRIPTION("ZTE ZX IR remote control driver"); -MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index 4077217777f9..931ec0727cd3 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -535,7 +535,7 @@ cxd2880_spi_probe(struct spi_device *spi) dvb_spi->spi = spi; mutex_init(&dvb_spi->spi_mutex); - dev_set_drvdata(&spi->dev, dvb_spi); + spi_set_drvdata(spi, dvb_spi); config.spi = spi; config.spi_mutex = &dvb_spi->spi_mutex; @@ -632,7 +632,7 @@ cxd2880_spi_remove(struct spi_device *spi) return -EINVAL; } - dvb_spi = dev_get_drvdata(&spi->dev); + dvb_spi = spi_get_drvdata(spi); if (!dvb_spi) { pr_err("failed\n"); diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c b/drivers/media/test-drivers/vidtv/vidtv_psi.c index 47ed7907db8d..c11ac8dca73d 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_psi.c +++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c @@ -19,7 +19,6 @@ #include <linux/ratelimit.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/string.h> #include <linux/time.h> #include <linux/types.h> diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c index 331a9053a0ed..a24624353f9e 100644 --- a/drivers/media/test-drivers/vim2m.c +++ b/drivers/media/test-drivers/vim2m.c @@ -1339,12 +1339,6 @@ static int vim2m_probe(struct platform_device *pdev) goto error_dev; } - ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto error_m2m; - } - #ifdef CONFIG_MEDIA_CONTROLLER dev->mdev.dev = &pdev->dev; strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model)); @@ -1353,7 +1347,15 @@ 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) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto error_m2m; + } + +#ifdef CONFIG_MEDIA_CONTROLLER ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret) { diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index 0dc65ef3aa14..ca0ebf6ad9cc 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -205,13 +205,13 @@ static const u8 vivid_hdmi_edid[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7b, - 0x02, 0x03, 0x3f, 0xf0, 0x51, 0x61, 0x60, 0x5f, + 0x02, 0x03, 0x3f, 0xf1, 0x51, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21, 0x20, 0x05, 0x14, 0x02, 0x11, 0x01, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03, 0x0c, 0x00, 0x10, 0x00, 0x00, 0x3c, 0x21, 0x00, 0x60, 0x01, 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4, - 0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xea, 0xe3, + 0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3, 0x05, 0x00, 0x00, 0xe3, 0x06, 0x01, 0x00, 0x4d, 0xd0, 0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80, 0x30, 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, @@ -220,7 +220,7 @@ static const u8 vivid_hdmi_edid[256] = { 0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80, 0x51, 0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, }; static int vidioc_querycap(struct file *file, void *priv, diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h index 9c2d1470b597..cdff6cd264d0 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.h +++ b/drivers/media/test-drivers/vivid/vivid-core.h @@ -230,6 +230,7 @@ struct vivid_dev { struct v4l2_ctrl *string; struct v4l2_ctrl *bitmask; struct v4l2_ctrl *int_menu; + struct v4l2_ctrl *ro_int32; struct v4l2_ctrl *test_pattern; struct v4l2_ctrl *colorspace; struct v4l2_ctrl *rgb_range_cap; diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c index 7957eadf3e2b..8dc50fe22972 100644 --- a/drivers/media/test-drivers/vivid/vivid-ctrls.c +++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c @@ -33,6 +33,7 @@ #define VIVID_CID_U16_MATRIX (VIVID_CID_CUSTOM_BASE + 9) #define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10) #define VIVID_CID_AREA (VIVID_CID_CUSTOM_BASE + 11) +#define VIVID_CID_RO_INTEGER (VIVID_CID_CUSTOM_BASE + 12) #define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000) #define VIVID_CID_VIVID_CLASS (0x00f00000 | 1) @@ -291,6 +292,17 @@ static const struct v4l2_ctrl_config vivid_ctrl_area = { .p_def.p_const = &area, }; +static const struct v4l2_ctrl_config vivid_ctrl_ro_int32 = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_RO_INTEGER, + .name = "Read-Only Integer 32 Bits", + .type = V4L2_CTRL_TYPE_INTEGER, + .flags = V4L2_CTRL_FLAG_READ_ONLY, + .min = 0, + .max = 255, + .step = 1, +}; + /* Framebuffer Controls */ static int vivid_fb_s_ctrl(struct v4l2_ctrl *ctrl) @@ -1601,6 +1613,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL); dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL); dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL); + dev->ro_int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_ro_int32, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_area, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL); v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL); diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c index 67fb3c00f9ad..c0dc609c1358 100644 --- a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c +++ b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c @@ -426,6 +426,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) is_loop = true; buf->vb.sequence = dev->vid_cap_seq_count; + v4l2_ctrl_s_ctrl(dev->ro_int32, buf->vb.sequence & 0xff); if (dev->field_cap == V4L2_FIELD_ALTERNATE) { /* * 60 Hz standards start with the bottom field, 50 Hz standards @@ -515,10 +516,11 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) mutex_unlock(dev->ctrl_hdl_user_aud.lock); tpg_gen_text(tpg, basep, line++ * line_height, 16, str); mutex_lock(dev->ctrl_hdl_user_gen.lock); - snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", - dev->int32->cur.val, - *dev->int64->p_cur.p_s64, - dev->bitmask->cur.val); + snprintf(str, sizeof(str), " int32 %d, ro_int32 %d, int64 %lld, bitmask %08x ", + dev->int32->cur.val, + dev->ro_int32->cur.val, + *dev->int64->p_cur.p_s64, + dev->bitmask->cur.val); tpg_gen_text(tpg, basep, line++ * line_height, 16, str); snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", dev->boolean->cur.val, diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c index ac1e981e8342..9f731f085179 100644 --- a/drivers/media/test-drivers/vivid/vivid-vid-out.c +++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c @@ -1021,7 +1021,7 @@ int vivid_vid_out_s_fbuf(struct file *file, void *fh, return -EINVAL; } dev->fbuf_out_flags &= ~(chroma_flags | alpha_flags); - dev->fbuf_out_flags = a->flags & (chroma_flags | alpha_flags); + dev->fbuf_out_flags |= a->flags & (chroma_flags | alpha_flags); return 0; } diff --git a/drivers/media/tuners/it913x.h b/drivers/media/tuners/it913x.h index 600268816d98..bb45637abea9 100644 --- a/drivers/media/tuners/it913x.h +++ b/drivers/media/tuners/it913x.h @@ -14,7 +14,7 @@ /** * struct it913x_platform_data - Platform data for the it913x driver * @regmap: af9033 demod driver regmap. - * @dvb_frontend: af9033 demod driver DVB frontend. + * @fe: af9033 demod driver DVB frontend. * @role: Chip role, single or dual configuration. */ diff --git a/drivers/media/tuners/m88rs6000t.c b/drivers/media/tuners/m88rs6000t.c index b3505f402476..8647c50b66e5 100644 --- a/drivers/media/tuners/m88rs6000t.c +++ b/drivers/media/tuners/m88rs6000t.c @@ -525,7 +525,7 @@ static int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength) PGA2_cri = PGA2_GC >> 2; PGA2_crf = PGA2_GC & 0x03; - for (i = 0; i <= RF_GC; i++) + for (i = 0; i <= RF_GC && i < ARRAY_SIZE(RFGS); i++) RFG += RFGS[i]; if (RF_GC == 0) @@ -537,12 +537,12 @@ static int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength) if (RF_GC == 3) RFG += 100; - for (i = 0; i <= IF_GC; i++) + for (i = 0; i <= IF_GC && i < ARRAY_SIZE(IFGS); i++) IFG += IFGS[i]; TIAG = TIA_GC * TIA_GS; - for (i = 0; i <= BB_GC; i++) + for (i = 0; i <= BB_GC && i < ARRAY_SIZE(BBGS); i++) BBG += BBGS[i]; PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS; diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index d105431a2e2d..6afef11a49cb 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -1383,7 +1383,7 @@ static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) } /** - * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom. + * MT2063_fLO_FractionalTerm - Calculates the portion contributed by FracN / denom. * This function preserves maximum precision without * risk of overflow. It accurately calculates * f_ref * num / denom to within 1 HZ with fixed math. @@ -1411,7 +1411,7 @@ static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom) } /* - * CalcLO1Mult()- Calculates Integer divider value and the numerator + * MT2063_CalcLO1Mult - Calculates Integer divider value and the numerator * value for a FracN PLL. * * This function assumes that the f_LO and f_Ref are @@ -1444,7 +1444,7 @@ static u32 MT2063_CalcLO1Mult(u32 *Div, } /** - * CalcLO2Mult() - Calculates Integer divider value and the numerator + * MT2063_CalcLO2Mult - Calculates Integer divider value and the numerator * value for a FracN PLL. * * This function assumes that the f_LO and f_Ref are diff --git a/drivers/media/tuners/qt1010.h b/drivers/media/tuners/qt1010.h index 559c12b97dbb..8db874334210 100644 --- a/drivers/media/tuners/qt1010.h +++ b/drivers/media/tuners/qt1010.h @@ -16,11 +16,11 @@ struct qt1010_config { }; /** - * Attach a qt1010 tuner to the supplied frontend structure. + * qt1010_attach() - Attach a qt1010 tuner to the supplied frontend structure * - * @param fe frontend to attach to - * @param i2c i2c adapter to use - * @param cfg tuner hw based configuration + * @fe: frontend to attach to + * @i2c: i2c adapter to use + * @cfg: tuner hw based configuration * @return fe pointer on success, NULL on failure */ #if IS_REACHABLE(CONFIG_MEDIA_TUNER_QT1010) diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h index 30ac9214487f..d3c2f00ada8f 100644 --- a/drivers/media/tuners/tda827x.h +++ b/drivers/media/tuners/tda827x.h @@ -30,12 +30,12 @@ struct tda827x_config /** - * Attach a tda827x tuner to the supplied frontend structure. + * tda827x_attach() - Attach a tda827x tuner to the supplied frontend structure * - * @param fe Frontend to attach to. - * @param addr i2c address of the tuner. - * @param i2c i2c adapter to use. - * @param cfg optional callback function pointers. + * @fe: Frontend to attach to. + * @addr: i2c address of the tuner. + * @i2c: i2c adapter to use. + * @cfg: optional callback function pointers. * @return FE pointer on success, NULL on failure. */ #if IS_REACHABLE(CONFIG_MEDIA_TUNER_TDA827X) diff --git a/drivers/media/tuners/tuner-i2c.h b/drivers/media/tuners/tuner-i2c.h index 724952e001cd..07aeead0644a 100644 --- a/drivers/media/tuners/tuner-i2c.h +++ b/drivers/media/tuners/tuner-i2c.h @@ -133,8 +133,10 @@ static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, } \ if (0 == __ret) { \ state = kzalloc(sizeof(type), GFP_KERNEL); \ - if (NULL == state) \ + if (!state) { \ + __ret = -ENOMEM; \ goto __fail; \ + } \ state->i2c_props.addr = i2caddr; \ state->i2c_props.adap = i2cadap; \ state->i2c_props.name = devname; \ diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index e731243267e4..5d38171b7638 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -15,8 +15,8 @@ /* debug */ #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG -#define dprintk(level,args...) \ - do { if ((debug & level)) printk(args); } while (0) +#define dprintk(level, args...) \ + do { if ((debug & (level))) printk(args); } while (0) #define debug_dump(b, l, method) do {\ int i; \ @@ -27,8 +27,8 @@ #define DEBSTATUS "" #else -#define dprintk(level, args...) -#define debug_dump(b, l, method) +#define dprintk(level, args...) no_printk(args) +#define debug_dump(b, l, method) do { } while (0) #define DEBSTATUS " (debugging is not enabled)" #endif @@ -195,7 +195,6 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb, break; default: return -EINVAL; - break; } for (i = 0; i < len;) { pagechunk = diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h index b32eab641793..6929e4d97067 100644 --- a/drivers/media/usb/cx231xx/cx231xx.h +++ b/drivers/media/usb/cx231xx/cx231xx.h @@ -425,8 +425,6 @@ struct cx231xx_audio { u16 end_point_addr; }; -struct cx231xx; - /*****************************************************************/ /* set/get i2c */ /* 00--1Mb/s, 01-400kb/s, 10--100kb/s, 11--5Mb/s */ diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index 89a1b204b90c..aa45b5d263f6 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -1171,14 +1171,9 @@ static int anysee_ci_write_attribute_mem(struct dvb_ca_en50221 *ci, int slot, int addr, u8 val) { struct dvb_usb_device *d = ci->data; - int ret; u8 buf[] = {CMD_CI, 0x03, 0x40 | addr >> 8, addr & 0xff, 0x00, 1, val}; - ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); - if (ret) - return ret; - - return 0; + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); } static int anysee_ci_read_cam_control(struct dvb_ca_en50221 *ci, int slot, @@ -1200,14 +1195,9 @@ static int anysee_ci_write_cam_control(struct dvb_ca_en50221 *ci, int slot, u8 addr, u8 val) { struct dvb_usb_device *d = ci->data; - int ret; u8 buf[] = {CMD_CI, 0x05, 0x40, addr, 0x00, 1, val}; - ret = anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); - if (ret) - return ret; - - return 0; + return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0); } static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot) @@ -1252,13 +1242,8 @@ static int anysee_ci_slot_shutdown(struct dvb_ca_en50221 *ci, int slot) static int anysee_ci_slot_ts_enable(struct dvb_ca_en50221 *ci, int slot) { struct dvb_usb_device *d = ci->data; - int ret; - ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); - if (ret) - return ret; - - return 0; + return anysee_wr_reg_mask(d, REG_IOD, (0 << 1), 0x02); } static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index 52bcc2d2efe5..288c15a7d72b 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -100,7 +100,8 @@ struct dvb_usb_device; struct dvb_usb_adapter; /** - * structure for carrying all needed data from the device driver to the general + * struct dvb_usb_driver_info - structure for carrying all needed data from the + * device driver to the general * dvb usb routines * @name: device name * @rc_map: name of rc codes table @@ -113,7 +114,7 @@ struct dvb_usb_driver_info { }; /** - * structure for remote controller configuration + * struct dvb_usb_rc - structure for remote controller configuration * @map_name: name of rc codes table * @allowed_protos: protocol(s) supported by the driver * @change_protocol: callback to change protocol @@ -135,10 +136,11 @@ struct dvb_usb_rc { }; /** - * usb streaming configuration for adapter + * struct usb_data_stream_properties - usb streaming configuration for adapter * @type: urb type * @count: count of used urbs * @endpoint: stream usb endpoint number + * @u: union for @bulk and @isoc */ struct usb_data_stream_properties { #define USB_BULK 1 @@ -160,15 +162,15 @@ struct usb_data_stream_properties { }; /** - * properties of dvb usb device adapter + * struct dvb_usb_adapter_properties - properties of dvb usb device adapter * @caps: adapter capabilities * @pid_filter_count: pid count of adapter pid-filter * @pid_filter_ctrl: called to enable/disable pid-filter * @pid_filter: called to set/unset pid for filtering * @stream: adapter usb stream configuration */ -#define MAX_NO_OF_FE_PER_ADAP 3 struct dvb_usb_adapter_properties { +#define MAX_NO_OF_FE_PER_ADAP 3 #define DVB_USB_ADAP_HAS_PID_FILTER 0x01 #define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02 #define DVB_USB_ADAP_NEED_PID_FILTERING 0x04 @@ -208,6 +210,7 @@ struct dvb_usb_adapter_properties { * @frontend_attach: called to attach the possible frontends * @frontend_detach: called to detach the possible frontends * @tuner_attach: called to attach the possible tuners + * @tuner_detach: called to detach the possible tuners * @frontend_ctrl: called to power on/off active frontend * @streaming_ctrl: called to start/stop the usb streaming of adapter * @init: called after adapters are created in order to finalize device @@ -218,8 +221,8 @@ struct dvb_usb_adapter_properties { * of the adapter just before streaming is started. input stream is transport * stream from the demodulator and output stream is usb stream to host. */ -#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 struct dvb_usb_device_properties { +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 const char *driver_name; struct module *owner; short *adapter_nr; @@ -265,7 +268,12 @@ struct dvb_usb_device_properties { }; /** - * generic object of an usb stream + * struct usb_data_stream - generic object of an usb stream + * @udev: USB device + * @props: properties + * @state: state of the data stream + * @complete: complete callback + * @urb_list: list of URBs * @buf_num: number of buffer allocated * @buf_size: size of each buffer in buf_list * @buf_list: array containing all allocate buffers for streaming @@ -273,9 +281,10 @@ struct dvb_usb_device_properties { * * @urbs_initialized: number of URBs initialized * @urbs_submitted: number of URBs submitted + * @user_priv: private pointer */ -#define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_data_stream { +#define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_device *udev; struct usb_data_stream_properties props; @@ -298,7 +307,7 @@ struct usb_data_stream { }; /** - * dvb adapter object on dvb usb device + * struct dvb_usb_adapter - dvb adapter object on dvb usb device * @props: pointer to adapter properties * @stream: adapter the usb data stream * @id: index of this adapter (starting with 0) @@ -307,11 +316,12 @@ struct usb_data_stream { * @pid_filtering: is hardware pid_filtering used or not * @feed_count: current feed count * @max_feed_count: maimum feed count device can handle + * @active_fe: active frontend + * @state_bits: status bits * @dvb_adap: adapter dvb_adapter * @dmxdev: adapter dmxdev * @demux: adapter software demuxer * @dvb_net: adapter dvb_net interfaces - * @sync_mutex: mutex used to sync control and streaming of the adapter * @fe: adapter frontends * @fe_init: rerouted frontend-init function * @fe_sleep: rerouted frontend-sleep function @@ -343,7 +353,7 @@ struct dvb_usb_adapter { }; /** - * dvb usb device object + * struct dvb_usb_device - dvb usb device object * @props: device properties * @name: device name * @rc_map: name of rc codes table @@ -355,7 +365,9 @@ struct dvb_usb_adapter { * @usb_mutex: mutex for usb control messages * @i2c_mutex: mutex for i2c-transfers * @i2c_adap: device's i2c-adapter + * @adapter: adapters * @rc_dev: rc device for the remote control + * @rc_phys: rc path * @rc_query_work: work for polling remote * @priv: private data of the actual driver (allocate by dvb usb, size defined * in size_of_priv of dvb_usb_properties). diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c index c1a7634e27b4..28e1fd64dd3c 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c @@ -79,11 +79,17 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) } } - if ((ret = dvb_usb_adapter_stream_init(adap)) || - (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || - (ret = dvb_usb_adapter_frontend_init(adap))) { + ret = dvb_usb_adapter_stream_init(adap); + if (ret) return ret; - } + + ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs); + if (ret) + goto dvb_init_err; + + ret = dvb_usb_adapter_frontend_init(adap); + if (ret) + goto frontend_init_err; /* use exclusive FE lock if there is multiple shared FEs */ if (adap->fe_adap[1].fe) @@ -103,6 +109,12 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) } return 0; + +frontend_init_err: + dvb_usb_adapter_dvb_exit(adap); +dvb_init_err: + dvb_usb_adapter_stream_exit(adap); + return ret; } static int dvb_usb_adapter_exit(struct dvb_usb_device *d) @@ -158,22 +170,20 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) if (d->props.priv_init != NULL) { ret = d->props.priv_init(d); - if (ret != 0) { - kfree(d->priv); - d->priv = NULL; - return ret; - } + if (ret != 0) + goto err_priv_init; } } /* check the capabilities and set appropriate variables */ dvb_usb_device_power_ctrl(d, 1); - if ((ret = dvb_usb_i2c_init(d)) || - (ret = dvb_usb_adapter_init(d, adapter_nums))) { - dvb_usb_exit(d); - return ret; - } + ret = dvb_usb_i2c_init(d); + if (ret) + goto err_i2c_init; + ret = dvb_usb_adapter_init(d, adapter_nums); + if (ret) + goto err_adapter_init; if ((ret = dvb_usb_remote_init(d))) err("could not initialize remote control."); @@ -181,6 +191,17 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) dvb_usb_device_power_ctrl(d, 0); return 0; + +err_adapter_init: + dvb_usb_adapter_exit(d); +err_i2c_init: + dvb_usb_i2c_exit(d); + if (d->priv && d->props.priv_destroy) + d->props.priv_destroy(d); +err_priv_init: + kfree(d->priv); + d->priv = NULL; + return ret; } /* determine the name and the state of the just found USB device */ @@ -255,41 +276,50 @@ int dvb_usb_device_init(struct usb_interface *intf, if (du != NULL) *du = NULL; - if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) { + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + err("no memory for 'struct dvb_usb_device'"); + return -ENOMEM; + } + + memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); + + desc = dvb_usb_find_device(udev, &d->props, &cold); + if (!desc) { deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n"); - return -ENODEV; + ret = -ENODEV; + goto error; } if (cold) { info("found a '%s' in cold state, will try to load a firmware", desc->name); ret = dvb_usb_download_firmware(udev, props); if (!props->no_reconnect || ret != 0) - return ret; + goto error; } info("found a '%s' in warm state.", desc->name); - d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); - if (d == NULL) { - err("no memory for 'struct dvb_usb_device'"); - return -ENOMEM; - } - d->udev = udev; - memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties)); d->desc = desc; d->owner = owner; usb_set_intfdata(intf, d); - if (du != NULL) + ret = dvb_usb_init(d, adapter_nums); + if (ret) { + info("%s error while loading driver (%d)", desc->name, ret); + goto error; + } + + if (du) *du = d; - ret = dvb_usb_init(d, adapter_nums); + info("%s successfully initialized and connected.", desc->name); + return 0; - if (ret == 0) - info("%s successfully initialized and connected.", desc->name); - else - info("%s error while loading driver (%d)", desc->name, ret); + error: + usb_set_intfdata(intf, NULL); + kfree(d); return ret; } EXPORT_SYMBOL(dvb_usb_device_init); diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 741be0e69447..0990aa4a17bb 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -28,18 +28,19 @@ /* debug */ #ifdef CONFIG_DVB_USB_DEBUG -#define dprintk(var,level,args...) \ - do { if ((var & level)) { printk(args); } } while (0) +#define dprintk(var, level, args...) \ + do { if (((var) & (level))) { printk(args); } } while (0) -#define debug_dump(b,l,func) {\ +#define debug_dump(b, l, func) {\ int loop_; \ - for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \ + for (loop_ = 0; loop_ < (l); loop_++) \ + func("%02x ", b[loop_]); \ func("\n");\ } #define DVB_USB_DEBUG_STATUS #else -#define dprintk(args...) -#define debug_dump(b,l,func) +#define dprintk(var, level, args...) no_printk(args) +#define debug_dump(b, l, func) do { } while (0) #define DVB_USB_DEBUG_STATUS " (debugging is not enabled)" @@ -95,7 +96,7 @@ struct dvb_usb_device; struct dvb_usb_adapter; struct usb_data_stream; -/** +/* * Properties of USB streaming - TODO this structure should be somewhere else * describes the kind of USB transfer used for data-streaming. * (BULK or ISOC) @@ -120,7 +121,7 @@ struct usb_data_stream_properties { }; /** - * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter. + * struct dvb_usb_adapter_fe_properties - properties of a dvb-usb-adapter. * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device. * @caps: capabilities of the DVB USB device. * @pid_filter_count: number of PID filter position in the optional hardware @@ -139,6 +140,7 @@ struct usb_data_stream_properties { * @tuner_attach: called to attach the correct tuner and to fill pll_addr, * pll_desc and pll_init_buf of struct dvb_usb_device). * @stream: configuration of the USB streaming + * @size_of_priv: size of the priv memory in struct dvb_usb_adapter */ struct dvb_usb_adapter_fe_properties { #define DVB_USB_ADAP_HAS_PID_FILTER 0x01 @@ -191,15 +193,17 @@ struct dvb_rc_legacy { }; /** - * struct dvb_rc properties of remote controller, using rc-core + * struct dvb_rc - properties of remote controller, using rc-core * @rc_codes: name of rc codes table * @protocol: type of protocol(s) currently used by the driver * @allowed_protos: protocol(s) supported by the driver * @driver_type: Used to point if a device supports raw mode * @change_protocol: callback to change protocol + * @module_name: module name * @rc_query: called to query an event event. * @rc_interval: time in ms between two queries. * @bulk_mode: device supports bulk mode for RC (disable polling mode) + * @scancode_mask: scancode mask */ struct dvb_rc { char *rc_codes; @@ -219,6 +223,9 @@ struct dvb_rc { * based on rc-core * This is initialized/used only inside dvb-usb-remote.c. * It shouldn't be set by the drivers. + * + * @DVB_RC_LEGACY: legacy driver + * @DVB_RC_CORE: rc-core driver */ enum dvb_usb_mode { DVB_RC_LEGACY, @@ -227,6 +234,7 @@ enum dvb_usb_mode { /** * struct dvb_usb_device_properties - properties of a dvb-usb-device + * @caps: capabilities * @usb_ctrl: which USB device-side controller is in use. Needed for firmware * download. * @firmware: name of the firmware file. @@ -243,6 +251,8 @@ enum dvb_usb_mode { * @priv_destroy: just like priv_init, only called before deallocating * the memory pointed by private field of struct dvb_usb_device. * + * @num_adapters: the number of adapters in @adapters + * @adapter: the adapters * @power_ctrl: called to enable/disable power of the device. * @read_mac_address: called to read the MAC address of the device. * @identify_state: called to determine the state (cold or warm), when it @@ -267,9 +277,8 @@ enum dvb_usb_mode { * @devices: array of struct dvb_usb_device_description compatibles with these * properties. */ -#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 struct dvb_usb_device_properties { - +#define MAX_NO_OF_ADAPTER_PER_DEVICE 2 #define DVB_USB_IS_AN_I2C_ADAPTER 0x01 int caps; @@ -313,6 +322,11 @@ struct dvb_usb_device_properties { /** * struct usb_data_stream - generic object of an USB stream + * @udev: the USB device + * @props: data stream properties + * @state: state of the stream + * @complete: complete callback + * @urb_list: list of URBs * @buf_num: number of buffer allocated. * @buf_size: size of each buffer in buf_list. * @buf_list: array containing all allocate buffers for streaming. @@ -320,9 +334,10 @@ struct dvb_usb_device_properties { * * @urbs_initialized: number of URBs initialized. * @urbs_submitted: number of URBs submitted. + * @user_priv: for private use. */ -#define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_data_stream { +#define MAX_NO_URBS_FOR_DATA_STREAM 10 struct usb_device *udev; struct usb_data_stream_properties props; @@ -345,29 +360,15 @@ struct usb_data_stream { }; /** - * struct dvb_usb_adapter - a DVB adapter on a USB device - * @id: index of this adapter (starting with 0). - * - * @feedcount: number of requested feeds (used for streaming-activation) - * @pid_filtering: is hardware pid_filtering used or not. - * - * @pll_addr: I2C address of the tuner for programming - * @pll_init: array containing the initialization buffer - * @pll_desc: pointer to the appropriate struct dvb_pll_desc - * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board - * - * @dvb_adap: device's dvb_adapter. - * @dmxdev: device's dmxdev. - * @demux: device's software demuxer. - * @dvb_net: device's dvb_net interfaces. - * @dvb_frontend: device's frontend. - * @max_feed_count: how many feeds can be handled simultaneously by this - * device - * + * struct dvb_usb_fe_adapter - a DVB adapter on a USB device + * @fe: frontend * @fe_init: rerouted frontend-init (wakeup) function. * @fe_sleep: rerouted frontend-sleep function. - * * @stream: the usb data stream. + * @pid_filtering: is hardware pid_filtering used or not. + * @max_feed_count: how many feeds can be handled simultaneously by this + * device + * @priv: private pointer */ struct dvb_usb_fe_adapter { struct dvb_frontend *fe; @@ -383,6 +384,25 @@ struct dvb_usb_fe_adapter { void *priv; }; +/** + * struct dvb_usb_adapter - a DVB adapter on a USB device + * @dev: DVB USB device pointer + * @props: properties + * @state: status + * @id: index of this adapter (starting with 0). + * + * @feedcount: number of requested feeds (used for streaming-activation) + * + * @dvb_adap: device's dvb_adapter. + * @dmxdev: device's dmxdev. + * @demux: device's software demuxer. + * @dvb_net: device's dvb_net interfaces. + * + * @fe_adap: frontend adapters + * @active_fe: active frontend + * @num_frontends_initialized: number of initialized frontends + * @priv: private pointer + */ struct dvb_usb_adapter { struct dvb_usb_device *dev; struct dvb_usb_adapter_properties props; @@ -427,8 +447,12 @@ struct dvb_usb_adapter { * * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB * + * @num_adapters_initialized: number of initialized adapters + * @adapter: adapters + * * @rc_dev: rc device for the remote control (rc-core mode) * @input_dev: input device for the remote control (legacy mode) + * @rc_phys: rc device path * @rc_query_work: struct work_struct frequent rc queries * @last_event: last triggered event * @last_state: last state (no, pressed, repeat) @@ -487,7 +511,8 @@ extern int __must_check dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); /* commonly used remote control parsing */ -extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); +int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d, u8 keybuf[5], + u32 *event, int *state); /* commonly used firmware download types and function */ struct hexline { diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index d6c8ae213914..ba9292e2a587 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2778,8 +2778,12 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE }, { USB_DEVICE(0x2013, 0x0258), .driver_info = EM28178_BOARD_PCTV_461E }, + { USB_DEVICE(0x2013, 0x8258), /* Bulk transport 461e */ + .driver_info = EM28178_BOARD_PCTV_461E }, { USB_DEVICE(0x2013, 0x0461), .driver_info = EM28178_BOARD_PCTV_461E_V2 }, + { USB_DEVICE(0x2013, 0x8461), /* Bulk transport 461e v2 */ + .driver_info = EM28178_BOARD_PCTV_461E_V2 }, { USB_DEVICE(0x2013, 0x0259), .driver_info = EM28178_BOARD_PCTV_461E_V2 }, { USB_DEVICE(0x2013, 0x025f), diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 526424279637..471bd74667e3 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -2010,6 +2010,7 @@ ret: return result; out_free: + em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE); kfree(dvb); dev->dvb = NULL; goto ret; diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 6648e11f1271..ab167cd1f400 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -335,7 +335,7 @@ enum em28xx_usb_audio_type { }; /** - * em28xx_amux - describes the type of audio input used by em28xx + * enum em28xx_amux - describes the type of audio input used by em28xx * * @EM28XX_AMUX_UNUSED: * Used only on em28xx dev->map field, in order to mark an entry @@ -628,8 +628,6 @@ struct em28xx_audio { atomic_t stream_started; /* stream should be running if true */ }; -struct em28xx; - enum em28xx_i2c_algo_type { EM28XX_I2C_ALGO_EM28XX = 0, EM28XX_I2C_ALGO_EM2800, diff --git a/drivers/media/usb/gspca/cpia1.c b/drivers/media/usb/gspca/cpia1.c index a4f7431486f3..d93d384286c1 100644 --- a/drivers/media/usb/gspca/cpia1.c +++ b/drivers/media/usb/gspca/cpia1.c @@ -1424,7 +1424,6 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - int ret; sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ; reset_camera_params(gspca_dev); @@ -1436,10 +1435,7 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = mode; cam->nmodes = ARRAY_SIZE(mode); - ret = goto_low_power(gspca_dev); - if (ret) - gspca_err(gspca_dev, "Cannot go to low power mode: %d\n", - ret); + goto_low_power(gspca_dev); /* Check the firmware version. */ sd->params.version.firmwareVersion = 0; get_version_information(gspca_dev); diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 158c8e28ed2c..47d8f28bfdfc 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1576,6 +1576,8 @@ out: #endif v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler); v4l2_device_unregister(&gspca_dev->v4l2_dev); + if (sd_desc->probe_error) + sd_desc->probe_error(gspca_dev); kfree(gspca_dev->usb_buf); kfree(gspca_dev); return ret; diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index b0ced2e14006..a6554d5e9e1a 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -105,6 +105,7 @@ struct sd_desc { cam_cf_op config; /* called on probe */ cam_op init; /* called on probe and resume */ cam_op init_controls; /* called on probe */ + cam_v_op probe_error; /* called if probe failed, do cleanup here */ cam_op start; /* called on stream on after URBs creation */ cam_pkt_op pkt_scan; /* optional operations */ diff --git a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c index bfa3b381d8a2..bf1af6ed9131 100644 --- a/drivers/media/usb/gspca/m5602/m5602_mt9m111.c +++ b/drivers/media/usb/gspca/m5602/m5602_mt9m111.c @@ -195,7 +195,7 @@ static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = { int mt9m111_probe(struct sd *sd) { u8 data[2] = {0x00, 0x00}; - int i, rc = 0; + int i, err; struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { @@ -213,18 +213,18 @@ int mt9m111_probe(struct sd *sd) /* Do the preinit */ for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { if (preinit_mt9m111[i][0] == BRIDGE) { - rc |= m5602_write_bridge(sd, - preinit_mt9m111[i][1], - preinit_mt9m111[i][2]); + err = m5602_write_bridge(sd, + preinit_mt9m111[i][1], + preinit_mt9m111[i][2]); } else { data[0] = preinit_mt9m111[i][2]; data[1] = preinit_mt9m111[i][3]; - rc |= m5602_write_sensor(sd, - preinit_mt9m111[i][1], data, 2); + err = m5602_write_sensor(sd, + preinit_mt9m111[i][1], data, 2); } + if (err < 0) + return err; } - if (rc < 0) - return rc; if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) return -ENODEV; diff --git a/drivers/media/usb/gspca/m5602/m5602_po1030.c b/drivers/media/usb/gspca/m5602/m5602_po1030.c index d680b777f097..8fd99ceee4b6 100644 --- a/drivers/media/usb/gspca/m5602/m5602_po1030.c +++ b/drivers/media/usb/gspca/m5602/m5602_po1030.c @@ -154,8 +154,8 @@ static const struct v4l2_ctrl_config po1030_greenbal_cfg = { int po1030_probe(struct sd *sd) { - int rc = 0; u8 dev_id_h = 0, i; + int err; struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; if (force_sensor) { @@ -174,14 +174,14 @@ int po1030_probe(struct sd *sd) for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { u8 data = preinit_po1030[i][2]; if (preinit_po1030[i][0] == SENSOR) - rc |= m5602_write_sensor(sd, - preinit_po1030[i][1], &data, 1); + err = m5602_write_sensor(sd, preinit_po1030[i][1], + &data, 1); else - rc |= m5602_write_bridge(sd, preinit_po1030[i][1], - data); + err = m5602_write_bridge(sd, preinit_po1030[i][1], + data); + if (err < 0) + return err; } - if (rc < 0) - return rc; if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1)) return -ENODEV; diff --git a/drivers/media/usb/gspca/sq905.c b/drivers/media/usb/gspca/sq905.c index 97799cfb832e..949111070971 100644 --- a/drivers/media/usb/gspca/sq905.c +++ b/drivers/media/usb/gspca/sq905.c @@ -158,7 +158,7 @@ static int sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock) { int ret; - int act_len; + int act_len = 0; gspca_dev->usb_buf[0] = '\0'; if (need_lock) diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c index 95673fc0a99c..d9bc2aacc885 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c @@ -529,12 +529,21 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, static int stv06xx_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id); +static void stv06xx_probe_error(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + + kfree(sd->sensor_priv); + sd->sensor_priv = NULL; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, .config = stv06xx_config, .init = stv06xx_init, .init_controls = stv06xx_init_controls, + .probe_error = stv06xx_probe_error, .start = stv06xx_start, .stopN = stv06xx_stopN, .pkt_scan = stv06xx_pkt_scan, diff --git a/drivers/media/usb/gspca/w996Xcf.c b/drivers/media/usb/gspca/w996Xcf.c index a8350ee9712f..79baa0c1a031 100644 --- a/drivers/media/usb/gspca/w996Xcf.c +++ b/drivers/media/usb/gspca/w996Xcf.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/** - * +/* * GSPCA sub driver for W996[78]CF JPEG USB Dual Mode Camera Chip. * * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> diff --git a/drivers/media/usb/pwc/pwc-dec23.c b/drivers/media/usb/pwc/pwc-dec23.c index 4e26ada87f7b..a3aa8c7174b9 100644 --- a/drivers/media/usb/pwc/pwc-dec23.c +++ b/drivers/media/usb/pwc/pwc-dec23.c @@ -637,7 +637,7 @@ static void DecompressBand23(struct pwc_dec23_private *pdec, } /** - * Uncompress a pwc23 buffer. + * pwc_dec23_decompress - Uncompress a pwc23 buffer. * @pdev: pointer to pwc device's internal struct * @src: raw data * @dst: image output diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 5e3339cc31c0..e342199711d3 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -861,7 +861,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x069A) { @@ -873,7 +872,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x046d) { @@ -932,7 +930,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x055d) { @@ -958,7 +955,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x041e) { @@ -977,7 +973,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x04cc) { @@ -989,7 +984,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else if (vendor_id == 0x06be) { @@ -1002,7 +996,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } @@ -1020,7 +1013,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; default: return -ENODEV; - break; } } else diff --git a/drivers/media/usb/pwc/pwc-uncompress.c b/drivers/media/usb/pwc/pwc-uncompress.c index abfc88391036..68bc3829c6b3 100644 --- a/drivers/media/usb/pwc/pwc-uncompress.c +++ b/drivers/media/usb/pwc/pwc-uncompress.c @@ -9,9 +9,6 @@ Please send bug reports and support requests to <luc@saillard.org>. The decompression routines have been implemented by reverse-engineering the Nemosoft binary pwcx module. Caveat emptor. - - - vim: set ts=8: */ #include <asm/current.h> diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index df6c5e4a0f05..a852ee5f7ac9 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -1102,11 +1102,9 @@ static int ttusb_dec_start_feed(struct dvb_demux_feed *dvbdmxfeed) case DMX_TYPE_TS: return ttusb_dec_start_ts_feed(dvbdmxfeed); - break; case DMX_TYPE_SEC: return ttusb_dec_start_sec_feed(dvbdmxfeed); - break; default: dprintk(" type: unknown (%d)\n", dvbdmxfeed->type); @@ -1157,11 +1155,9 @@ static int ttusb_dec_stop_feed(struct dvb_demux_feed *dvbdmxfeed) switch (dvbdmxfeed->type) { case DMX_TYPE_TS: return ttusb_dec_stop_ts_feed(dvbdmxfeed); - break; case DMX_TYPE_SEC: return ttusb_dec_stop_sec_feed(dvbdmxfeed); - break; } return 0; diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 3b4a2e769230..a714ad77ca8e 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -47,7 +47,7 @@ #include "usbtv.h" -static struct usbtv_norm_params norm_params[] = { +static const struct usbtv_norm_params norm_params[] = { { .norm = V4L2_STD_525_60, .cap_width = 720, @@ -63,7 +63,7 @@ static struct usbtv_norm_params norm_params[] = { static int usbtv_configure_for_norm(struct usbtv *usbtv, v4l2_std_id norm) { int i, ret = 0; - struct usbtv_norm_params *params = NULL; + const struct usbtv_norm_params *params = NULL; for (i = 0; i < ARRAY_SIZE(norm_params); i++) { if (norm_params[i].norm & norm) { @@ -685,7 +685,7 @@ static int usbtv_s_input(struct file *file, void *priv, unsigned int i) return usbtv_select_input(usbtv, i); } -static struct v4l2_ioctl_ops usbtv_ioctl_ops = { +static const struct v4l2_ioctl_ops usbtv_ioctl_ops = { .vidioc_querycap = usbtv_querycap, .vidioc_enum_input = usbtv_enum_input, .vidioc_enum_fmt_vid_cap = usbtv_enum_fmt_vid_cap, diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 30ef2a3110f7..9a791d8ef200 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1712,10 +1712,35 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, if (forward->bNrInPins != 1) { uvc_dbg(chain->dev, DESCR, "Extension unit %d has more than 1 input pin\n", - entity->id); + forward->id); return -EINVAL; } + /* + * Some devices reference an output terminal as the + * source of extension units. This is incorrect, as + * output terminals only have an input pin, and thus + * can't be connected to any entity in the forward + * direction. The resulting topology would cause issues + * when registering the media controller graph. To + * avoid this problem, connect the extension unit to + * the source of the output terminal instead. + */ + if (UVC_ENTITY_IS_OTERM(entity)) { + struct uvc_entity *source; + + source = uvc_entity_by_id(chain->dev, + entity->baSourceID[0]); + if (!source) { + uvc_dbg(chain->dev, DESCR, + "Can't connect extension unit %u in chain\n", + forward->id); + break; + } + + forward->baSourceID[0] = source->id; + } + list_add_tail(&forward->chain, &chain->entities); if (!found) uvc_dbg_cont(PROBE, " (->"); @@ -1735,6 +1760,13 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, return -EINVAL; } + if (UVC_ENTITY_IS_OTERM(entity)) { + uvc_dbg(chain->dev, DESCR, + "Unsupported connection between output terminals %u and %u\n", + entity->id, forward->id); + break; + } + list_add_tail(&forward->chain, &chain->entities); if (!found) uvc_dbg_cont(PROBE, " (->"); diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index f2f565281e63..a777b389a66e 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -6,11 +6,14 @@ * Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ +#include <linux/dma-mapping.h> +#include <linux/highmem.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/usb.h> +#include <linux/usb/hcd.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> #include <linux/wait.h> @@ -1096,6 +1099,29 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return data[0]; } +static inline enum dma_data_direction uvc_stream_dir( + struct uvc_streaming *stream) +{ + if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + return DMA_FROM_DEVICE; + else + return DMA_TO_DEVICE; +} + +static inline struct device *uvc_stream_to_dmadev(struct uvc_streaming *stream) +{ + return bus_to_hcd(stream->dev->udev->bus)->self.sysdev; +} + +static int uvc_submit_urb(struct uvc_urb *uvc_urb, gfp_t mem_flags) +{ + /* Sync DMA. */ + dma_sync_sgtable_for_device(uvc_stream_to_dmadev(uvc_urb->stream), + uvc_urb->sgt, + uvc_stream_dir(uvc_urb->stream)); + return usb_submit_urb(uvc_urb->urb, mem_flags); +} + /* * uvc_video_decode_data_work: Asynchronous memcpy processing * @@ -1117,7 +1143,7 @@ static void uvc_video_copy_data_work(struct work_struct *work) uvc_queue_buffer_release(op->buf); } - ret = usb_submit_urb(uvc_urb->urb, GFP_KERNEL); + ret = uvc_submit_urb(uvc_urb, GFP_KERNEL); if (ret < 0) dev_err(&uvc_urb->stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1537,6 +1563,12 @@ static void uvc_video_complete(struct urb *urb) /* Re-initialise the URB async work. */ uvc_urb->async_operations = 0; + /* Sync DMA and invalidate vmap range. */ + dma_sync_sgtable_for_cpu(uvc_stream_to_dmadev(uvc_urb->stream), + uvc_urb->sgt, uvc_stream_dir(stream)); + invalidate_kernel_vmap_range(uvc_urb->buffer, + uvc_urb->stream->urb_size); + /* * Process the URB headers, and optionally queue expensive memcpy tasks * to be deferred to a work queue. @@ -1545,7 +1577,7 @@ static void uvc_video_complete(struct urb *urb) /* If no async work is needed, resubmit the URB immediately. */ if (!uvc_urb->async_operations) { - ret = usb_submit_urb(uvc_urb->urb, GFP_ATOMIC); + ret = uvc_submit_urb(uvc_urb, GFP_ATOMIC); if (ret < 0) dev_err(&stream->intf->dev, "Failed to resubmit video URB (%d).\n", ret); @@ -1560,24 +1592,49 @@ static void uvc_video_complete(struct urb *urb) */ static void uvc_free_urb_buffers(struct uvc_streaming *stream) { + struct device *dma_dev = uvc_stream_to_dmadev(stream); struct uvc_urb *uvc_urb; for_each_uvc_urb(uvc_urb, stream) { if (!uvc_urb->buffer) continue; -#ifndef CONFIG_DMA_NONCOHERENT - usb_free_coherent(stream->dev->udev, stream->urb_size, - uvc_urb->buffer, uvc_urb->dma); -#else - kfree(uvc_urb->buffer); -#endif + dma_vunmap_noncontiguous(dma_dev, uvc_urb->buffer); + dma_free_noncontiguous(dma_dev, stream->urb_size, uvc_urb->sgt, + uvc_stream_dir(stream)); + uvc_urb->buffer = NULL; + uvc_urb->sgt = NULL; } stream->urb_size = 0; } +static bool uvc_alloc_urb_buffer(struct uvc_streaming *stream, + struct uvc_urb *uvc_urb, gfp_t gfp_flags) +{ + struct device *dma_dev = uvc_stream_to_dmadev(stream); + + uvc_urb->sgt = dma_alloc_noncontiguous(dma_dev, stream->urb_size, + uvc_stream_dir(stream), + gfp_flags, 0); + if (!uvc_urb->sgt) + return false; + uvc_urb->dma = uvc_urb->sgt->sgl->dma_address; + + uvc_urb->buffer = dma_vmap_noncontiguous(dma_dev, stream->urb_size, + uvc_urb->sgt); + if (!uvc_urb->buffer) { + dma_free_noncontiguous(dma_dev, stream->urb_size, + uvc_urb->sgt, + uvc_stream_dir(stream)); + uvc_urb->sgt = NULL; + return false; + } + + return true; +} + /* * Allocate transfer buffers. This function can be called with buffers * already allocated when resuming from suspend, in which case it will @@ -1608,19 +1665,12 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, /* Retry allocations until one succeed. */ for (; npackets > 1; npackets /= 2) { + stream->urb_size = psize * npackets; + for (i = 0; i < UVC_URBS; ++i) { struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; - stream->urb_size = psize * npackets; -#ifndef CONFIG_DMA_NONCOHERENT - uvc_urb->buffer = usb_alloc_coherent( - stream->dev->udev, stream->urb_size, - gfp_flags | __GFP_NOWARN, &uvc_urb->dma); -#else - uvc_urb->buffer = - kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN); -#endif - if (!uvc_urb->buffer) { + if (!uvc_alloc_urb_buffer(stream, uvc_urb, gfp_flags)) { uvc_free_urb_buffers(stream); break; } @@ -1730,12 +1780,8 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, urb->context = uvc_urb; urb->pipe = usb_rcvisocpipe(stream->dev->udev, ep->desc.bEndpointAddress); -#ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = uvc_urb->dma; -#else - urb->transfer_flags = URB_ISO_ASAP; -#endif urb->interval = ep->desc.bInterval; urb->transfer_buffer = uvc_urb->buffer; urb->complete = uvc_video_complete; @@ -1795,10 +1841,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, usb_fill_bulk_urb(urb, stream->dev->udev, pipe, uvc_urb->buffer, size, uvc_video_complete, uvc_urb); -#ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = uvc_urb->dma; -#endif uvc_urb->urb = urb; } @@ -1895,7 +1939,7 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream, /* Submit the URBs. */ for_each_uvc_urb(uvc_urb, stream) { - ret = usb_submit_urb(uvc_urb->urb, gfp_flags); + ret = uvc_submit_urb(uvc_urb, gfp_flags); if (ret < 0) { dev_err(&stream->intf->dev, "Failed to submit URB %u (%d).\n", diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 97df5ecd66c9..cce5e38133cd 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -219,6 +219,7 @@ */ struct gpio_desc; +struct sg_table; struct uvc_device; /* TODO: Put the most frequently accessed fields at the beginning of @@ -545,7 +546,8 @@ struct uvc_copy_op { * @urb: the URB described by this context structure * @stream: UVC streaming context * @buffer: memory storage for the URB - * @dma: DMA coherent addressing for the urb_buffer + * @dma: Allocated DMA handle + * @sgt: sgt_table with the urb locations in memory * @async_operations: counter to indicate the number of copy operations * @copy_operations: work descriptors for asynchronous copy operations * @work: work queue entry for asynchronous decode @@ -556,6 +558,7 @@ struct uvc_urb { char *buffer; dma_addr_t dma; + struct sg_table *sgt; unsigned int async_operations; struct uvc_copy_op copy_operations[UVC_MAX_PACKETS]; diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index d29b861367ea..1ef611e08323 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1430,7 +1430,7 @@ static int zr364xx_probe(struct usb_interface *intf, if (hdl->error) { err = hdl->error; dev_err(&udev->dev, "couldn't register control\n"); - goto unregister; + goto free_hdlr_and_unreg_dev; } /* save the init method used by this camera */ cam->method = id->driver_info; @@ -1503,7 +1503,7 @@ static int zr364xx_probe(struct usb_interface *intf, if (!cam->read_endpoint) { err = -ENOMEM; dev_err(&intf->dev, "Could not find bulk-in endpoint\n"); - goto unregister; + goto free_hdlr_and_unreg_dev; } /* v4l */ @@ -1515,7 +1515,7 @@ static int zr364xx_probe(struct usb_interface *intf, /* load zr364xx board specific */ err = zr364xx_board_init(cam); if (err) - goto unregister; + goto free_hdlr_and_unreg_dev; err = v4l2_ctrl_handler_setup(hdl); if (err) goto board_uninit; @@ -1533,7 +1533,7 @@ static int zr364xx_probe(struct usb_interface *intf, err = video_register_device(&cam->vdev, VFL_TYPE_VIDEO, -1); if (err) { dev_err(&udev->dev, "video_register_device failed\n"); - goto free_handler; + goto board_uninit; } cam->v4l2_dev.release = zr364xx_release; @@ -1541,11 +1541,10 @@ static int zr364xx_probe(struct usb_interface *intf, video_device_node_name(&cam->vdev)); return 0; -free_handler: - v4l2_ctrl_handler_free(hdl); board_uninit: zr364xx_board_uninit(cam); -unregister: +free_hdlr_and_unreg_dev: + v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&cam->v4l2_dev); free_cam: kfree(cam); diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 133d20e40f82..04af03285a20 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -469,6 +469,11 @@ s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul, return -ENOENT; freq = div_u64(v4l2_ctrl_g_ctrl_int64(ctrl) * mul, div); + + pr_warn("%s: Link frequency estimated using pixel rate: result might be inaccurate\n", + __func__); + pr_warn("%s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver\n", + __func__); } return freq > 0 ? freq : -EINVAL; diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 016cf6204cbb..0d7fe1bd975a 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -421,6 +421,11 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Annex B Start Code", NULL, }; + static const char * const h264_hierarchical_coding_type[] = { + "Hier Coding B", + "Hier Coding P", + NULL, + }; static const char * const mpeg_mpeg2_level[] = { "Low", "Main", @@ -697,6 +702,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return h264_decode_mode; case V4L2_CID_STATELESS_H264_START_CODE: return h264_start_code; + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: + return h264_hierarchical_coding_type; case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return mpeg_mpeg2_level; case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: @@ -874,6 +881,9 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode"; case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "Max Number of Reference Pics"; case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: return "Frame Skip Mode"; + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: return "Display Delay"; + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: return "Display Delay Enable"; + case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: return "Generate Access Unit Delimiters"; case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: return "H263 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B-Frame QP Value"; @@ -945,12 +955,16 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_VBV_SIZE: return "VBV Buffer Size"; case V4L2_CID_MPEG_VIDEO_DEC_PTS: return "Video Decoder PTS"; case V4L2_CID_MPEG_VIDEO_DEC_FRAME: return "Video Decoder Frame Count"; + case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: return "Video Decoder Conceal Color"; case V4L2_CID_MPEG_VIDEO_VBV_DELAY: return "Initial Delay for VBV Control"; case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: return "Horizontal MV Search Range"; case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: return "Vertical MV Search Range"; case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: return "Repeat Sequence Header"; case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame"; case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID: return "Base Layer Priority ID"; + case V4L2_CID_MPEG_VIDEO_LTR_COUNT: return "LTR Count"; + case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: return "Frame LTR Index"; + case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames"; case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters"; case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: return "MPEG-2 Quantization Matrices"; case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; @@ -971,7 +985,6 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile"; case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile"; case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: return "VP9 Level"; - case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: return "VP8 Frame Header"; /* HEVC controls */ case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: return "HEVC I-Frame QP Value"; @@ -1201,6 +1214,13 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_STATELESS_H264_SLICE_PARAMS: return "H264 Slice Parameters"; case V4L2_CID_STATELESS_H264_DECODE_PARAMS: return "H264 Decode Parameters"; case V4L2_CID_STATELESS_FWHT_PARAMS: return "FWHT Stateless Parameters"; + case V4L2_CID_STATELESS_VP8_FRAME: return "VP8 Frame Parameters"; + + /* Colorimetry controls */ + /* Keep the order of the 'case's the same as in v4l2-controls.h! */ + case V4L2_CID_COLORIMETRY_CLASS: return "Colorimetry Controls"; + case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: return "HDR10 Content Light Info"; + case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: return "HDR10 Mastering Display"; default: return NULL; } @@ -1241,12 +1261,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_FLASH_READY: case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: case V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: + case V4L2_CID_MPEG_VIDEO_AU_DELIMITER: case V4L2_CID_WIDE_DYNAMIC_RANGE: case V4L2_CID_IMAGE_STABILIZATION: case V4L2_CID_RDS_RECEPTION: @@ -1276,7 +1298,19 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, break; case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: + *type = V4L2_CTRL_TYPE_INTEGER; + break; + case V4L2_CID_MPEG_VIDEO_LTR_COUNT: + *type = V4L2_CTRL_TYPE_INTEGER; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: *type = V4L2_CTRL_TYPE_INTEGER; + *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + break; + case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: + *type = V4L2_CTRL_TYPE_BITMASK; + *flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; break; case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: case V4L2_CID_PAN_RESET: @@ -1326,6 +1360,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: + case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: @@ -1389,8 +1424,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_RF_TUNER_CLASS: case V4L2_CID_DETECT_CLASS: case V4L2_CID_CODEC_STATELESS_CLASS: + case V4L2_CID_COLORIMETRY_CLASS: *type = V4L2_CTRL_TYPE_CTRL_CLASS; - /* You can neither read not write these */ + /* You can neither read nor write these */ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY; *min = *max = *step = *def = 0; break; @@ -1430,6 +1466,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, *max = 0x7fffffffffffffffLL; *step = 1; break; + case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: + *type = V4L2_CTRL_TYPE_INTEGER64; + *min = 0; + /* default for 8 bit black, luma is 16, chroma is 128 */ + *def = 0x8000800010LL; + *max = 0xffffffffffffLL; + *step = 1; + break; case V4L2_CID_PIXEL_RATE: *type = V4L2_CTRL_TYPE_INTEGER64; *flags |= V4L2_CTRL_FLAG_READ_ONLY; @@ -1470,8 +1514,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_STATELESS_H264_PRED_WEIGHTS: *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS; break; - case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: - *type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER; + case V4L2_CID_STATELESS_VP8_FRAME: + *type = V4L2_CTRL_TYPE_VP8_FRAME; break; case V4L2_CID_MPEG_VIDEO_HEVC_SPS: *type = V4L2_CTRL_TYPE_HEVC_SPS; @@ -1486,6 +1530,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, *type = V4L2_CTRL_TYPE_AREA; *flags |= V4L2_CTRL_FLAG_READ_ONLY; break; + case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: + *type = V4L2_CTRL_TYPE_HDR10_CLL_INFO; + break; + case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: + *type = V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY; + break; default: *type = V4L2_CTRL_TYPE_INTEGER; break; @@ -1642,7 +1692,7 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; - struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + struct v4l2_ctrl_vp8_frame *p_vp8_frame; struct v4l2_ctrl_fwht_params *p_fwht_params; void *p = ptr.p + idx * ctrl->elem_size; @@ -1666,15 +1716,17 @@ static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, p_mpeg2_slice_params->picture.picture_coding_type = V4L2_MPEG2_PICTURE_CODING_TYPE_I; break; - case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: - p_vp8_frame_header = p; - p_vp8_frame_header->num_dct_parts = 1; + case V4L2_CTRL_TYPE_VP8_FRAME: + p_vp8_frame = p; + p_vp8_frame->num_dct_parts = 1; break; case V4L2_CTRL_TYPE_FWHT_PARAMS: p_fwht_params = p; p_fwht_params->version = V4L2_FWHT_VERSION; p_fwht_params->width = 1280; p_fwht_params->height = 720; + p_fwht_params->flags = V4L2_FWHT_FL_PIXENC_YUV | + (2 << V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET); break; } } @@ -1781,6 +1833,15 @@ static void std_log(const struct v4l2_ctrl *ctrl) case V4L2_CTRL_TYPE_FWHT_PARAMS: pr_cont("FWHT_PARAMS"); break; + case V4L2_CTRL_TYPE_VP8_FRAME: + pr_cont("VP8_FRAME"); + break; + case V4L2_CTRL_TYPE_HDR10_CLL_INFO: + pr_cont("HDR10_CLL_INFO"); + break; + case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: + pr_cont("HDR10_MASTERING_DISPLAY"); + break; default: pr_cont("unknown type %d", ctrl->type); break; @@ -1823,7 +1884,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; - struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header; + struct v4l2_ctrl_vp8_frame *p_vp8_frame; struct v4l2_ctrl_fwht_params *p_fwht_params; struct v4l2_ctrl_h264_sps *p_h264_sps; struct v4l2_ctrl_h264_pps *p_h264_pps; @@ -1833,6 +1894,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, struct v4l2_ctrl_hevc_sps *p_hevc_sps; struct v4l2_ctrl_hevc_pps *p_hevc_pps; struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params; + struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering; struct v4l2_area *area; void *p = ptr.p + idx * ctrl->elem_size; unsigned int i; @@ -2046,10 +2108,10 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, zero_reserved(*p_h264_dec_params); break; - case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: - p_vp8_frame_header = p; + case V4L2_CTRL_TYPE_VP8_FRAME: + p_vp8_frame = p; - switch (p_vp8_frame_header->num_dct_parts) { + switch (p_vp8_frame->num_dct_parts) { case 1: case 2: case 4: @@ -2058,11 +2120,11 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, default: return -EINVAL; } - zero_padding(p_vp8_frame_header->segment_header); - zero_padding(p_vp8_frame_header->lf_header); - zero_padding(p_vp8_frame_header->quant_header); - zero_padding(p_vp8_frame_header->entropy_header); - zero_padding(p_vp8_frame_header->coder_state); + zero_padding(p_vp8_frame->segment); + zero_padding(p_vp8_frame->lf); + zero_padding(p_vp8_frame->quant); + zero_padding(p_vp8_frame->entropy); + zero_padding(p_vp8_frame->coder_state); break; case V4L2_CTRL_TYPE_HEVC_SPS: @@ -2128,6 +2190,53 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, zero_padding(*p_hevc_slice_params); break; + case V4L2_CTRL_TYPE_HDR10_CLL_INFO: + break; + + case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: + p_hdr10_mastering = p; + + for (i = 0; i < 3; ++i) { + if (p_hdr10_mastering->display_primaries_x[i] < + V4L2_HDR10_MASTERING_PRIMARIES_X_LOW || + p_hdr10_mastering->display_primaries_x[i] > + V4L2_HDR10_MASTERING_PRIMARIES_X_HIGH || + p_hdr10_mastering->display_primaries_y[i] < + V4L2_HDR10_MASTERING_PRIMARIES_Y_LOW || + p_hdr10_mastering->display_primaries_y[i] > + V4L2_HDR10_MASTERING_PRIMARIES_Y_HIGH) + return -EINVAL; + } + + if (p_hdr10_mastering->white_point_x < + V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW || + p_hdr10_mastering->white_point_x > + V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH || + p_hdr10_mastering->white_point_y < + V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW || + p_hdr10_mastering->white_point_y > + V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH) + return -EINVAL; + + if (p_hdr10_mastering->max_display_mastering_luminance < + V4L2_HDR10_MASTERING_MAX_LUMA_LOW || + p_hdr10_mastering->max_display_mastering_luminance > + V4L2_HDR10_MASTERING_MAX_LUMA_HIGH || + p_hdr10_mastering->min_display_mastering_luminance < + V4L2_HDR10_MASTERING_MIN_LUMA_LOW || + p_hdr10_mastering->min_display_mastering_luminance > + V4L2_HDR10_MASTERING_MIN_LUMA_HIGH) + return -EINVAL; + + /* The following restriction comes from ITU-T Rec. H.265 spec */ + if (p_hdr10_mastering->max_display_mastering_luminance == + V4L2_HDR10_MASTERING_MAX_LUMA_LOW && + p_hdr10_mastering->min_display_mastering_luminance == + V4L2_HDR10_MASTERING_MIN_LUMA_HIGH) + return -EINVAL; + + break; + case V4L2_CTRL_TYPE_AREA: area = p; if (!area->width || !area->height) @@ -2395,7 +2504,16 @@ static void new_to_req(struct v4l2_ctrl_ref *ref) if (!ref) return; ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req); - ref->req = ref; + ref->valid_p_req = true; +} + +/* Copy the current value to the request value */ +static void cur_to_req(struct v4l2_ctrl_ref *ref) +{ + if (!ref) + return; + ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req); + ref->valid_p_req = true; } /* Copy the request value to the new value */ @@ -2403,8 +2521,8 @@ static void req_to_new(struct v4l2_ctrl_ref *ref) { if (!ref) return; - if (ref->req) - ptr_to_ptr(ref->ctrl, ref->req->p_req, ref->ctrl->p_new); + if (ref->valid_p_req) + ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new); else ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new); } @@ -2541,7 +2659,15 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl) if (hdl == NULL || hdl->buckets == NULL) return; - if (!hdl->req_obj.req && !list_empty(&hdl->requests)) { + /* + * If the main handler is freed and it is used by handler objects in + * outstanding requests, then unbind and put those objects before + * freeing the main handler. + * + * The main handler can be identified by having a NULL ops pointer in + * the request object. + */ + if (!hdl->req_obj.ops && !list_empty(&hdl->requests)) { struct v4l2_ctrl_handler *req, *next_req; list_for_each_entry_safe(req, next_req, &hdl->requests, requests) { @@ -2809,8 +2935,8 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights); break; - case V4L2_CTRL_TYPE_VP8_FRAME_HEADER: - elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header); + case V4L2_CTRL_TYPE_VP8_FRAME: + elem_size = sizeof(struct v4l2_ctrl_vp8_frame); break; case V4L2_CTRL_TYPE_HEVC_SPS: elem_size = sizeof(struct v4l2_ctrl_hevc_sps); @@ -2821,6 +2947,12 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: elem_size = sizeof(struct v4l2_ctrl_hevc_slice_params); break; + case V4L2_CTRL_TYPE_HDR10_CLL_INFO: + elem_size = sizeof(struct v4l2_ctrl_hdr10_cll_info); + break; + case V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: + elem_size = sizeof(struct v4l2_ctrl_hdr10_mastering_display); + break; case V4L2_CTRL_TYPE_AREA: elem_size = sizeof(struct v4l2_area); break; @@ -3571,39 +3703,8 @@ static void v4l2_ctrl_request_queue(struct media_request_object *obj) struct v4l2_ctrl_handler *hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); struct v4l2_ctrl_handler *main_hdl = obj->priv; - struct v4l2_ctrl_handler *prev_hdl = NULL; - struct v4l2_ctrl_ref *ref_ctrl, *ref_ctrl_prev = NULL; mutex_lock(main_hdl->lock); - if (list_empty(&main_hdl->requests_queued)) - goto queue; - - prev_hdl = list_last_entry(&main_hdl->requests_queued, - struct v4l2_ctrl_handler, requests_queued); - /* - * Note: prev_hdl and hdl must contain the same list of control - * references, so if any differences are detected then that is a - * driver bug and the WARN_ON is triggered. - */ - mutex_lock(prev_hdl->lock); - ref_ctrl_prev = list_first_entry(&prev_hdl->ctrl_refs, - struct v4l2_ctrl_ref, node); - list_for_each_entry(ref_ctrl, &hdl->ctrl_refs, node) { - if (ref_ctrl->req) - continue; - while (ref_ctrl_prev->ctrl->id < ref_ctrl->ctrl->id) { - /* Should never happen, but just in case... */ - if (list_is_last(&ref_ctrl_prev->node, - &prev_hdl->ctrl_refs)) - break; - ref_ctrl_prev = list_next_entry(ref_ctrl_prev, node); - } - if (WARN_ON(ref_ctrl_prev->ctrl->id != ref_ctrl->ctrl->id)) - break; - ref_ctrl->req = ref_ctrl_prev->req; - } - mutex_unlock(prev_hdl->lock); -queue: list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued); hdl->request_is_queued = true; mutex_unlock(main_hdl->lock); @@ -3615,8 +3716,8 @@ static void v4l2_ctrl_request_unbind(struct media_request_object *obj) container_of(obj, struct v4l2_ctrl_handler, req_obj); struct v4l2_ctrl_handler *main_hdl = obj->priv; - list_del_init(&hdl->requests); mutex_lock(main_hdl->lock); + list_del_init(&hdl->requests); if (hdl->request_is_queued) { list_del_init(&hdl->requests_queued); hdl->request_is_queued = false; @@ -3660,7 +3761,7 @@ v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id) { struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id); - return (ref && ref->req == ref) ? ref->ctrl : NULL; + return (ref && ref->valid_p_req) ? ref->ctrl : NULL; } EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find); @@ -3675,8 +3776,11 @@ static int v4l2_ctrl_request_bind(struct media_request *req, if (!ret) { ret = media_request_object_bind(req, &req_ops, from, false, &hdl->req_obj); - if (!ret) + if (!ret) { + mutex_lock(from->lock); list_add_tail(&hdl->requests, &from->requests); + mutex_unlock(from->lock); + } } return ret; } @@ -3846,7 +3950,13 @@ static int class_check(struct v4l2_ctrl_handler *hdl, u32 which) return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL; } -/* Get extended controls. Allocates the helpers array if needed. */ +/* + * Get extended controls. Allocates the helpers array if needed. + * + * Note that v4l2_g_ext_ctrls_common() with 'which' set to + * V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was + * completed, and in that case valid_p_req is true for all controls. + */ static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs, struct video_device *vdev) @@ -3855,9 +3965,10 @@ static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, struct v4l2_ctrl_helper *helpers = helper; int ret; int i, j; - bool def_value; + bool is_default, is_request; - def_value = (cs->which == V4L2_CTRL_WHICH_DEF_VAL); + is_default = (cs->which == V4L2_CTRL_WHICH_DEF_VAL); + is_request = (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL); cs->error_idx = cs->count; cs->which = V4L2_CTRL_ID2WHICH(cs->which); @@ -3883,11 +3994,9 @@ static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, ret = -EACCES; for (i = 0; !ret && i < cs->count; i++) { - int (*ctrl_to_user)(struct v4l2_ext_control *c, - struct v4l2_ctrl *ctrl); struct v4l2_ctrl *master; - - ctrl_to_user = def_value ? def_to_user : cur_to_user; + bool is_volatile = false; + u32 idx = i; if (helpers[i].mref == NULL) continue; @@ -3897,31 +4006,48 @@ static int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl, v4l2_ctrl_lock(master); - /* g_volatile_ctrl will update the new control values */ - if (!def_value && + /* + * g_volatile_ctrl will update the new control values. + * This makes no sense for V4L2_CTRL_WHICH_DEF_VAL and + * V4L2_CTRL_WHICH_REQUEST_VAL. In the case of requests + * it is v4l2_ctrl_request_complete() that copies the + * volatile controls at the time of request completion + * to the request, so you don't want to do that again. + */ + if (!is_default && !is_request && ((master->flags & V4L2_CTRL_FLAG_VOLATILE) || (master->has_volatiles && !is_cur_manual(master)))) { for (j = 0; j < master->ncontrols; j++) cur_to_new(master->cluster[j]); ret = call_op(master, g_volatile_ctrl); - ctrl_to_user = new_to_user; + is_volatile = true; } - /* If OK, then copy the current (for non-volatile controls) - or the new (for volatile controls) control values to the - caller */ - if (!ret) { - u32 idx = i; - do { - if (helpers[idx].ref->req) - ret = req_to_user(cs->controls + idx, - helpers[idx].ref->req); - else - ret = ctrl_to_user(cs->controls + idx, - helpers[idx].ref->ctrl); - idx = helpers[idx].next; - } while (!ret && idx); + if (ret) { + v4l2_ctrl_unlock(master); + break; } + + /* + * Copy the default value (if is_default is true), the + * request value (if is_request is true and p_req is valid), + * the new volatile value (if is_volatile is true) or the + * current value. + */ + do { + struct v4l2_ctrl_ref *ref = helpers[idx].ref; + + if (is_default) + ret = def_to_user(cs->controls + idx, ref->ctrl); + else if (is_request && ref->valid_p_req) + ret = req_to_user(cs->controls + idx, ref); + else if (is_volatile) + ret = new_to_user(cs->controls + idx, ref->ctrl); + else + ret = cur_to_user(cs->controls + idx, ref->ctrl); + idx = helpers[idx].next; + } while (!ret && idx); + v4l2_ctrl_unlock(master); } @@ -4564,8 +4690,6 @@ void v4l2_ctrl_request_complete(struct media_request *req, unsigned int i; if (ctrl->flags & V4L2_CTRL_FLAG_VOLATILE) { - ref->req = ref; - v4l2_ctrl_lock(master); /* g_volatile_ctrl will update the current control values */ for (i = 0; i < master->ncontrols; i++) @@ -4575,21 +4699,12 @@ void v4l2_ctrl_request_complete(struct media_request *req, v4l2_ctrl_unlock(master); continue; } - if (ref->req == ref) + if (ref->valid_p_req) continue; + /* Copy the current control value into the request */ v4l2_ctrl_lock(ctrl); - if (ref->req) { - ptr_to_ptr(ctrl, ref->req->p_req, ref->p_req); - } else { - ptr_to_ptr(ctrl, ctrl->p_cur, ref->p_req); - /* - * Set ref->req to ensure that when userspace wants to - * obtain the controls of this request it will take - * this value and not the current value of the control. - */ - ref->req = ref; - } + cur_to_req(ref); v4l2_ctrl_unlock(ctrl); } @@ -4653,7 +4768,7 @@ int v4l2_ctrl_request_setup(struct media_request *req, struct v4l2_ctrl_ref *r = find_ref(hdl, master->cluster[i]->id); - if (r->req && r == r->req) { + if (r->valid_p_req) { have_new_data = true; break; } diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index b6a72d297775..7d0edf3530be 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -350,8 +350,9 @@ static __poll_t v4l2_poll(struct file *filp, struct poll_table_struct *poll) res = vdev->fops->poll(filp, poll); } if (vdev->dev_debug & V4L2_DEV_DEBUG_POLL) - dprintk("%s: poll: %08x\n", - video_device_node_name(vdev), res); + dprintk("%s: poll: %08x %08x\n", + video_device_node_name(vdev), res, + poll_requested_events(poll)); return res; } diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 2283ff3b8e1d..843259c304bb 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1259,8 +1259,27 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode); } -int v4l2_async_notifier_parse_fwnode_sensor_common(struct device *dev, - struct v4l2_async_notifier *notifier) +/** + * v4l2_async_notifier_parse_fwnode_sensor - parse common references on + * sensors for async sub-devices + * @dev: the device node the properties of which are parsed for references + * @notifier: the async notifier where the async subdevs will be added + * + * Parse common sensor properties for remote devices related to the + * sensor and set up async sub-devices for them. + * + * Any notifier populated using this function must be released with a call to + * v4l2_async_notifier_release() after it has been unregistered and the async + * sub-devices are no longer in use, even in the case the function returned an + * error. + * + * Return: 0 on success + * -ENOMEM if memory allocation failed + * -EINVAL if property parsing failed + */ +static int +v4l2_async_notifier_parse_fwnode_sensor(struct device *dev, + struct v4l2_async_notifier *notifier) { static const char * const led_props[] = { "led" }; static const struct v4l2_fwnode_int_props props[] = { @@ -1288,9 +1307,8 @@ int v4l2_async_notifier_parse_fwnode_sensor_common(struct device *dev, return 0; } -EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common); -int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd) +int v4l2_async_register_subdev_sensor(struct v4l2_subdev *sd) { struct v4l2_async_notifier *notifier; int ret; @@ -1304,8 +1322,7 @@ int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd) v4l2_async_notifier_init(notifier); - ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev, - notifier); + ret = v4l2_async_notifier_parse_fwnode_sensor(sd->dev, notifier); if (ret < 0) goto out_cleanup; @@ -1330,7 +1347,7 @@ out_cleanup: return ret; } -EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common); +EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>"); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 31d1342e61e8..2673f51aafa4 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -265,13 +265,9 @@ static void v4l_print_fmtdesc(const void *arg, bool write_only) { const struct v4l2_fmtdesc *p = arg; - pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%c%c%c%c, mbus_code=0x%04x, description='%.*s'\n", + pr_cont("index=%u, type=%s, flags=0x%x, pixelformat=%p4cc, mbus_code=0x%04x, description='%.*s'\n", p->index, prt_names(p->type, v4l2_type_names), - p->flags, (p->pixelformat & 0xff), - (p->pixelformat >> 8) & 0xff, - (p->pixelformat >> 16) & 0xff, - (p->pixelformat >> 24) & 0xff, - p->mbus_code, + p->flags, &p->pixelformat, p->mbus_code, (int)sizeof(p->description), p->description); } @@ -293,12 +289,8 @@ static void v4l_print_format(const void *arg, bool write_only) case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: pix = &p->fmt.pix; - pr_cont(", width=%u, height=%u, pixelformat=%c%c%c%c, field=%s, bytesperline=%u, sizeimage=%u, colorspace=%d, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n", - pix->width, pix->height, - (pix->pixelformat & 0xff), - (pix->pixelformat >> 8) & 0xff, - (pix->pixelformat >> 16) & 0xff, - (pix->pixelformat >> 24) & 0xff, + pr_cont(", width=%u, height=%u, pixelformat=%p4cc, field=%s, bytesperline=%u, sizeimage=%u, colorspace=%d, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n", + pix->width, pix->height, &pix->pixelformat, prt_names(pix->field, v4l2_field_names), pix->bytesperline, pix->sizeimage, pix->colorspace, pix->flags, pix->ycbcr_enc, @@ -307,12 +299,8 @@ static void v4l_print_format(const void *arg, bool write_only) case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: mp = &p->fmt.pix_mp; - pr_cont(", width=%u, height=%u, format=%c%c%c%c, field=%s, colorspace=%d, num_planes=%u, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n", - mp->width, mp->height, - (mp->pixelformat & 0xff), - (mp->pixelformat >> 8) & 0xff, - (mp->pixelformat >> 16) & 0xff, - (mp->pixelformat >> 24) & 0xff, + pr_cont(", width=%u, height=%u, format=%p4cc, field=%s, colorspace=%d, num_planes=%u, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n", + mp->width, mp->height, &mp->pixelformat, prt_names(mp->field, v4l2_field_names), mp->colorspace, mp->num_planes, mp->flags, mp->ycbcr_enc, mp->quantization, mp->xfer_func); @@ -337,13 +325,9 @@ static void v4l_print_format(const void *arg, bool write_only) case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: vbi = &p->fmt.vbi; - pr_cont(", sampling_rate=%u, offset=%u, samples_per_line=%u, sample_format=%c%c%c%c, start=%u,%u, count=%u,%u\n", + pr_cont(", sampling_rate=%u, offset=%u, samples_per_line=%u, sample_format=%p4cc, start=%u,%u, count=%u,%u\n", vbi->sampling_rate, vbi->offset, - vbi->samples_per_line, - (vbi->sample_format & 0xff), - (vbi->sample_format >> 8) & 0xff, - (vbi->sample_format >> 16) & 0xff, - (vbi->sample_format >> 24) & 0xff, + vbi->samples_per_line, &vbi->sample_format, vbi->start[0], vbi->start[1], vbi->count[0], vbi->count[1]); break; @@ -360,21 +344,13 @@ static void v4l_print_format(const void *arg, bool write_only) case V4L2_BUF_TYPE_SDR_CAPTURE: case V4L2_BUF_TYPE_SDR_OUTPUT: sdr = &p->fmt.sdr; - pr_cont(", pixelformat=%c%c%c%c\n", - (sdr->pixelformat >> 0) & 0xff, - (sdr->pixelformat >> 8) & 0xff, - (sdr->pixelformat >> 16) & 0xff, - (sdr->pixelformat >> 24) & 0xff); + pr_cont(", pixelformat=%p4cc\n", &sdr->pixelformat); break; case V4L2_BUF_TYPE_META_CAPTURE: case V4L2_BUF_TYPE_META_OUTPUT: meta = &p->fmt.meta; - pr_cont(", dataformat=%c%c%c%c, buffersize=%u\n", - (meta->dataformat >> 0) & 0xff, - (meta->dataformat >> 8) & 0xff, - (meta->dataformat >> 16) & 0xff, - (meta->dataformat >> 24) & 0xff, - meta->buffersize); + pr_cont(", dataformat=%p4cc, buffersize=%u\n", + &meta->dataformat, meta->buffersize); break; } } @@ -383,15 +359,10 @@ static void v4l_print_framebuffer(const void *arg, bool write_only) { const struct v4l2_framebuffer *p = arg; - pr_cont("capability=0x%x, flags=0x%x, base=0x%p, width=%u, height=%u, pixelformat=%c%c%c%c, bytesperline=%u, sizeimage=%u, colorspace=%d\n", - p->capability, p->flags, p->base, - p->fmt.width, p->fmt.height, - (p->fmt.pixelformat & 0xff), - (p->fmt.pixelformat >> 8) & 0xff, - (p->fmt.pixelformat >> 16) & 0xff, - (p->fmt.pixelformat >> 24) & 0xff, - p->fmt.bytesperline, p->fmt.sizeimage, - p->fmt.colorspace); + pr_cont("capability=0x%x, flags=0x%x, base=0x%p, width=%u, height=%u, pixelformat=%p4cc, bytesperline=%u, sizeimage=%u, colorspace=%d\n", + p->capability, p->flags, p->base, p->fmt.width, p->fmt.height, + &p->fmt.pixelformat, p->fmt.bytesperline, p->fmt.sizeimage, + p->fmt.colorspace); } static void v4l_print_buftype(const void *arg, bool write_only) @@ -476,7 +447,7 @@ static void v4l_print_buffer(const void *arg, bool write_only) const struct v4l2_plane *plane; int i; - pr_cont("%02d:%02d:%02d.%09ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s", + pr_cont("%02d:%02d:%02d.%06ld index=%d, type=%s, request_fd=%d, flags=0x%08x, field=%s, sequence=%d, memory=%s", (int)p->timestamp.tv_sec / 3600, ((int)p->timestamp.tv_sec / 60) % 60, ((int)p->timestamp.tv_sec % 60), @@ -761,13 +732,8 @@ static void v4l_print_frmsizeenum(const void *arg, bool write_only) { const struct v4l2_frmsizeenum *p = arg; - pr_cont("index=%u, pixelformat=%c%c%c%c, type=%u", - p->index, - (p->pixel_format & 0xff), - (p->pixel_format >> 8) & 0xff, - (p->pixel_format >> 16) & 0xff, - (p->pixel_format >> 24) & 0xff, - p->type); + pr_cont("index=%u, pixelformat=%p4cc, type=%u", + p->index, &p->pixel_format, p->type); switch (p->type) { case V4L2_FRMSIZE_TYPE_DISCRETE: pr_cont(", wxh=%ux%u\n", @@ -793,13 +759,8 @@ static void v4l_print_frmivalenum(const void *arg, bool write_only) { const struct v4l2_frmivalenum *p = arg; - pr_cont("index=%u, pixelformat=%c%c%c%c, wxh=%ux%u, type=%u", - p->index, - (p->pixel_format & 0xff), - (p->pixel_format >> 8) & 0xff, - (p->pixel_format >> 16) & 0xff, - (p->pixel_format >> 24) & 0xff, - p->width, p->height, p->type); + pr_cont("index=%u, pixelformat=%p4cc, wxh=%ux%u, type=%u", + p->index, &p->pixel_format, p->width, p->height, p->type); switch (p->type) { case V4L2_FRMIVAL_TYPE_DISCRETE: pr_cont(", fps=%d/%d\n", @@ -1304,6 +1265,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_YUV444: descr = "16-bit A/XYUV 4-4-4-4"; break; case V4L2_PIX_FMT_YUV555: descr = "16-bit A/XYUV 1-5-5-5"; break; case V4L2_PIX_FMT_YUV565: descr = "16-bit YUV 5-6-5"; break; + case V4L2_PIX_FMT_YUV24: descr = "24-bit YUV 4:4:4 8-8-8"; break; case V4L2_PIX_FMT_YUV32: descr = "32-bit A/XYUV 8-8-8-8"; break; case V4L2_PIX_FMT_AYUV32: descr = "32-bit AYUV 8-8-8-8"; break; case V4L2_PIX_FMT_XYUV32: descr = "32-bit XYUV 8-8-8-8"; break; @@ -1459,12 +1421,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) return; WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat); flags = 0; - snprintf(fmt->description, sz, "%c%c%c%c%s", - (char)(fmt->pixelformat & 0x7f), - (char)((fmt->pixelformat >> 8) & 0x7f), - (char)((fmt->pixelformat >> 16) & 0x7f), - (char)((fmt->pixelformat >> 24) & 0x7f), - (fmt->pixelformat & (1UL << 31)) ? "-BE" : ""); + snprintf(fmt->description, sz, "%p4cc", + &fmt->pixelformat); break; } } diff --git a/drivers/media/v4l2-core/v4l2-jpeg.c b/drivers/media/v4l2-core/v4l2-jpeg.c index 8947fd95c6f1..c2513b775f6a 100644 --- a/drivers/media/v4l2-core/v4l2-jpeg.c +++ b/drivers/media/v4l2-core/v4l2-jpeg.c @@ -45,6 +45,7 @@ MODULE_LICENSE("GPL"); #define DHP 0xffde /* hierarchical progression */ #define EXP 0xffdf /* expand reference */ #define APP0 0xffe0 /* application data */ +#define APP14 0xffee /* application data for colour encoding */ #define APP15 0xffef #define JPG0 0xfff0 /* extensions */ #define JPG13 0xfffd @@ -444,8 +445,41 @@ static int jpeg_skip_segment(struct jpeg_stream *stream) return jpeg_skip(stream, len - 2); } +/* Rec. ITU-T T.872 (06/2012) 6.5.3 */ +static int jpeg_parse_app14_data(struct jpeg_stream *stream, + enum v4l2_jpeg_app14_tf *tf) +{ + int ret; + int lp; + int skip; + + lp = jpeg_get_word_be(stream); + if (lp < 0) + return lp; + + /* Check for "Adobe\0" in Ap1..6 */ + if (stream->curr + 6 > stream->end || + strncmp(stream->curr, "Adobe\0", 6)) + return -EINVAL; + + /* get to Ap12 */ + ret = jpeg_skip(stream, 11); + if (ret < 0) + return ret; + + ret = jpeg_get_byte(stream); + if (ret < 0) + return ret; + + *tf = ret; + + /* skip the rest of the segment, this ensures at least it is complete */ + skip = lp - 2 - 11; + return jpeg_skip(stream, skip); +} + /** - * jpeg_parse_header - locate marker segments and optionally parse headers + * v4l2_jpeg_parse_header - locate marker segments and optionally parse headers * @buf: address of the JPEG buffer, should start with a SOI marker * @len: length of the JPEG buffer * @out: returns marker segment positions and optionally parsed headers @@ -469,13 +503,13 @@ int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out) out->num_dht = 0; out->num_dqt = 0; - /* the first marker must be SOI */ - marker = jpeg_next_marker(&stream); - if (marker < 0) - return marker; - if (marker != SOI) + /* the first bytes must be SOI, B.2.1 High-level syntax */ + if (jpeg_get_word_be(&stream) != SOI) return -EINVAL; + /* init value to signal if this marker is not present */ + out->app14_tf = V4L2_JPEG_APP14_TF_UNKNOWN; + /* loop through marker segments */ while ((marker = jpeg_next_marker(&stream)) >= 0) { switch (marker) { @@ -503,6 +537,10 @@ int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out) &out->dht[out->num_dht++ % 4]); if (ret < 0) return ret; + if (!out->huffman_tables) { + ret = jpeg_skip_segment(&stream); + break; + } ret = jpeg_parse_huffman_tables(&stream, out->huffman_tables); break; @@ -511,6 +549,10 @@ int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out) &out->dqt[out->num_dqt++ % 4]); if (ret < 0) return ret; + if (!out->quantization_tables) { + ret = jpeg_skip_segment(&stream); + break; + } ret = jpeg_parse_quantization_tables(&stream, out->frame.precision, out->quantization_tables); @@ -519,7 +561,10 @@ int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out) ret = jpeg_parse_restart_interval(&stream, &out->restart_interval); break; - + case APP14: + ret = jpeg_parse_app14_data(&stream, + &out->app14_tf); + break; case SOS: ret = jpeg_reference_segment(&stream, &out->sos); if (ret < 0) diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c index ba2f2b8dcc8c..b01474717dca 100644 --- a/drivers/media/v4l2-core/v4l2-mc.c +++ b/drivers/media/v4l2-core/v4l2-mc.c @@ -246,7 +246,7 @@ int v4l2_mc_create_media_graph(struct media_device *mdev) pad_sink = media_get_pad_index(decoder, true, PAD_SIGNAL_ANALOG); if (pad_sink < 0) { - dev_warn(mdev->dev, "couldn't get tuner analog pad sink\n"); + dev_warn(mdev->dev, "couldn't get decoder analog pad sink\n"); return -EINVAL; } ret = media_create_pad_link(entity, 0, decoder, @@ -310,7 +310,7 @@ int v4l_vb2q_enable_media_source(struct vb2_queue *q) EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source); int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd, - struct media_pad *sink) + struct media_pad *sink, u32 flags) { struct fwnode_handle *endpoint; struct v4l2_subdev *sink_sd; @@ -367,7 +367,7 @@ int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd, sink_sd->entity.name, sink_idx); ret = media_create_pad_link(&src_sd->entity, src_idx, - &sink_sd->entity, sink_idx, 0); + &sink_sd->entity, sink_idx, flags); if (ret) { dev_err(sink_sd->dev, "link %s:%d -> %s:%d failed with %d\n", @@ -395,7 +395,7 @@ int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd, if (!(pad->flags & MEDIA_PAD_FL_SINK)) continue; - ret = v4l2_create_fwnode_links_to_pad(src_sd, pad); + ret = v4l2_create_fwnode_links_to_pad(src_sd, pad, 0); if (ret) return ret; } |