diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:09:22 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-19 10:09:22 -0700 |
| commit | f4cdf7ca9a1fdcca413157df19753f388a5a224e (patch) | |
| tree | 60a31895b2446cd7fa27514e8c2843534a0de0da /drivers | |
| parent | e5c91aac491def6ab3f90c4cc246e3fcb0f8f058 (diff) | |
| parent | 4900cad020c0580dfb1be27776ff10a4ef110cfa (diff) | |
Merge tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- v4l2-core: added ISP statistics support and per-block validation
- v4l2-core: Allow unknown HDR10 white point and luminance
- New camera sensors: Sony IMX678 and IMX471m, Himax HM1092 IR sensor
- New codec: Milos: VPU v2.0 codec support
- isp driver: gained support for Dreamchip RPPX1 ISP framework
- vsp1 driver: gained support for RZ/T2H and RZ/N2H
- Novalake driver: gained CVS support for new NVL hardware
- dvb-core: fix feed leak on failed DMX_ADD_PID
- several driver fixes, cleanups and minor improvements
* tag 'media/v7.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits)
media: ipu-bridge: check all DMI entries when overriding sensor rotation
media: v4l2-async: avoid deleting unlinked ASC entry on link error
media: rzg2l-cru: Align bytesperline to hardware DMA stride requirement
media: intel/ipu6: fix async notifier cleanup leak on parse error
media: staging/ipu7: fix async notifier UAF on probe error path
media: amd: isp4: fix self-deadlock in isp4sd_pwron_and_init() error path
media: amd: isp4: release partial allocations in isp4if_alloc_fw_gpumem()
media: rcar-isp: Fix VSPX reference leaks
media: rcar-isp: Release ISPCORE resources
media: i2c: imx415: Release runtime PM reference on VBLANK error
media: i2c: imx415: Return test pattern write errors
media: renesas: vsp1: Declare index variables in for loop statement
media: renesas: vsp1: Make reset control optional to support platforms without a reset line
media: dt-bindings: media: renesas,vsp1: Document RZ/T2H and RZ/N2H SoCs
media: dt-bindings: media: renesas,fcp: Document RZ/T2H and RZ/N2H SoCs
media: nxp: imx8-isi: Add additional 32-bit RGB format support
media: nxp: imx8-isi: Add 16-bit raw Bayer format support
media: nxp: imx8-isi: Implement per-stream reference counting for multiplexed streams
media: nxp: imx8-isi: Use BIT_ULL() for 64-bit stream masks
media: nxp: imx8-isi: Correct color map between V4L2 and ISI
...
Diffstat (limited to 'drivers')
314 files changed, 12873 insertions, 4419 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fce86b1b2fae..9df1d76fbf2b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -859,6 +859,7 @@ static const char * const acpi_honor_dep_ids[] = { "INTC10DE", /* CVS (LNL) driver must be loaded to allow camera streaming */ "INTC10E0", /* CVS (ARL) driver must be loaded to allow camera streaming */ "INTC10E1", /* CVS (PTL) driver must be loaded to allow camera streaming */ + "INTC10FA", /* CVS (NVL) driver must be loaded to allow camera streaming */ "RSCV0001", /* RISC-V PLIC */ "RSCV0002", /* RISC-V APLIC */ "RSCV0005", /* RISC-V SBI MPXY MBOX */ diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index a90cb84a4b4d..ee8a200b9803 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -80,9 +80,9 @@ void cec_queue_event_fh(struct cec_fh *fh, const struct cec_event *new_ev, u64 ts) { static const u16 max_events[CEC_NUM_EVENTS] = { - 1, 1, 800, 800, 8, 8, 8, 8 + 3, 1, 800, 800, 8, 8, 8, 8 }; - struct cec_event_entry *entry; + struct cec_event_entry *new_entry, *entry; unsigned int ev_idx = new_ev->event - 1; if (WARN_ON(ev_idx >= ARRAY_SIZE(fh->events))) @@ -92,36 +92,57 @@ void cec_queue_event_fh(struct cec_fh *fh, ts = ktime_get_ns(); mutex_lock(&fh->lock); - if (ev_idx < CEC_NUM_CORE_EVENTS) - entry = &fh->core_events[ev_idx]; - else - entry = kmalloc_obj(*entry); - if (entry) { + new_entry = kmalloc_obj(*new_entry); + if (new_entry) { if (new_ev->event == CEC_EVENT_LOST_MSGS && fh->queued_events[ev_idx]) { + entry = list_first_entry(&fh->events[ev_idx], + struct cec_event_entry, list); entry->ev.lost_msgs.lost_msgs += new_ev->lost_msgs.lost_msgs; + kfree(new_entry); goto unlock; } - entry->ev = *new_ev; - entry->ev.ts = ts; + + new_entry->ev = *new_ev; + new_entry->ev.ts = ts; + + /* + * If the physical address becomes invalid (HPD went low), + * then just flush all pending STATE_CHANGE events since + * those are all obsoleted. + * + * This ensures you will not see stale STATE_CHANGE events. + */ + if (new_ev->event == CEC_EVENT_STATE_CHANGE && + new_ev->state_change.phys_addr == CEC_PHYS_ADDR_INVALID && + fh->queued_events[ev_idx]) { + /* drop all events */ + while (!list_empty(&fh->events[ev_idx])) { + entry = list_first_entry(&fh->events[ev_idx], + struct cec_event_entry, list); + list_del(&entry->list); + kfree(entry); + fh->total_queued_events--; + fh->queued_events[ev_idx]--; + } + new_entry->ev.flags |= CEC_EVENT_FL_DROPPED_EVENTS; + } if (fh->queued_events[ev_idx] < max_events[ev_idx]) { /* Add new msg at the end of the queue */ - list_add_tail(&entry->list, &fh->events[ev_idx]); + list_add_tail(&new_entry->list, &fh->events[ev_idx]); fh->queued_events[ev_idx]++; fh->total_queued_events++; goto unlock; } - if (ev_idx >= CEC_NUM_CORE_EVENTS) { - list_add_tail(&entry->list, &fh->events[ev_idx]); - /* drop the oldest event */ - entry = list_first_entry(&fh->events[ev_idx], - struct cec_event_entry, list); - list_del(&entry->list); - kfree(entry); - } + list_add_tail(&new_entry->list, &fh->events[ev_idx]); + /* drop the oldest event */ + entry = list_first_entry(&fh->events[ev_idx], + struct cec_event_entry, list); + list_del(&entry->list); + kfree(entry); } /* Mark that events were lost */ entry = list_first_entry_or_null(&fh->events[ev_idx], @@ -608,6 +629,13 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, attempts_made = 1; mutex_lock(&adap->lock); + if (adap->error_inj_tx_timeouts) { + dprintk(2, "%s: error_inj_tx_timeouts %u\n", + __func__, adap->error_inj_tx_timeouts); + adap->error_inj_tx_timeouts--; + mutex_unlock(&adap->lock); + return; + } data = adap->transmitting; if (!data) { /* @@ -965,7 +993,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, */ mutex_unlock(&adap->lock); err = wait_for_completion_killable(&data->c); - cancel_delayed_work_sync(&data->work); + disable_delayed_work_sync(&data->work); mutex_lock(&adap->lock); if (err) @@ -1317,7 +1345,7 @@ static int cec_config_log_addr(struct cec_adapter *adap, { struct cec_log_addrs *las = &adap->log_addrs; struct cec_msg msg = { }; - const unsigned int max_retries = 2; + const unsigned int max_attempts = 3; unsigned int i; int err; @@ -1328,7 +1356,7 @@ static int cec_config_log_addr(struct cec_adapter *adap, msg.len = 1; msg.msg[0] = (log_addr << 4) | log_addr; - for (i = 0; i < max_retries; i++) { + for (i = 0; i < max_attempts; i++) { err = cec_transmit_msg_fh(adap, &msg, NULL, true); /* @@ -1345,31 +1373,24 @@ static int cec_config_log_addr(struct cec_adapter *adap, if (err) return err; - /* - * The message was aborted or timed out due to a disconnect or - * unconfigure, just bail out. - */ - if (msg.tx_status & - (CEC_TX_STATUS_ABORTED | CEC_TX_STATUS_TIMEOUT)) - return -EINTR; if (msg.tx_status & CEC_TX_STATUS_OK) return 0; if (msg.tx_status & CEC_TX_STATUS_NACK) break; /* - * Retry up to max_retries times if the message was neither + * Do up to max_attempts if the message was neither * OKed or NACKed. This can happen due to e.g. a Lost * Arbitration condition. */ } /* - * If we are unable to get an OK or a NACK after max_retries attempts + * If we are unable to get an OK or a NACK after max_attempts * (and note that each attempt already consists of four polls), then * we assume that something is really weird and that it is not a * good idea to try and claim this logical address. */ - if (i == max_retries) { + if (i == max_attempts) { dprintk(0, "polling for LA %u failed with tx_status=0x%04x\n", log_addr, msg.tx_status); return 0; @@ -1468,6 +1489,7 @@ static int cec_config_thread_func(void *arg) dprintk(1, "physical address: %x.%x.%x.%x, claim %d logical addresses\n", cec_phys_addr_exp(adap->phys_addr), las->num_log_addrs); las->log_addr_mask = 0; + las->flags &= ~CEC_LOG_ADDRS_FL_CONFIG_FAILED; if (las->log_addr_type[0] == CEC_LOG_ADDR_TYPE_UNREGISTERED) goto configured; @@ -1600,6 +1622,8 @@ configured: unconfigure: for (i = 0; i < las->num_log_addrs; i++) las->log_addr[i] = CEC_LOG_ADDR_INVALID; + if (adap->phys_addr != CEC_PHYS_ADDR_INVALID) + las->flags |= CEC_LOG_ADDRS_FL_CONFIG_FAILED; cec_adap_unconfigure(adap); adap->is_configuring = false; adap->must_reconfigure = false; @@ -1717,7 +1741,6 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) cec_phys_addr_exp(phys_addr)); if (becomes_invalid || !is_invalid) { adap->phys_addr = CEC_PHYS_ADDR_INVALID; - cec_post_state_event(adap); cec_adap_unconfigure(adap); if (becomes_invalid) { cec_adap_enable(adap); @@ -2219,9 +2242,13 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, * Unprocessed messages are aborted if userspace isn't doing * any processing either. */ + mutex_lock(&adap->lock); if (!is_broadcast && !is_reply && !adap->follower_cnt && - !adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT) + !adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT) { + mutex_unlock(&adap->lock); return cec_feature_abort(adap, msg); + } + mutex_unlock(&adap->lock); break; } @@ -2234,10 +2261,12 @@ skip_processing: * Send to the exclusive follower if there is one, otherwise send * to all followers. */ + mutex_lock(&adap->lock); if (adap->cec_follower) cec_queue_msg_fh(adap->cec_follower, msg); else cec_queue_msg_followers(adap, msg); + mutex_unlock(&adap->lock); return 0; } diff --git a/drivers/media/cec/core/cec-api.c b/drivers/media/cec/core/cec-api.c index 103ded79526f..a491d7fc8a71 100644 --- a/drivers/media/cec/core/cec-api.c +++ b/drivers/media/cec/core/cec-api.c @@ -345,8 +345,7 @@ static long cec_dqevent(struct cec_adapter *adap, struct cec_fh *fh, if (copy_to_user(parg, &ev->ev, sizeof(ev->ev))) err = -EFAULT; - if (ev_idx >= CEC_NUM_CORE_EVENTS) - kfree(ev); + kfree(ev); fh->queued_events[ev_idx]--; fh->total_queued_events--; @@ -673,7 +672,7 @@ static int cec_release(struct inode *inode, struct file *filp) list_del(&entry->list); kfree(entry); } - for (i = CEC_NUM_CORE_EVENTS; i < CEC_NUM_EVENTS; i++) { + for (i = 0; i < CEC_NUM_EVENTS; i++) { while (!list_empty(&fh->events[i])) { struct cec_event_entry *entry = list_first_entry(&fh->events[i], diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index 0fcd3b5e60c8..230f8a413e74 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -5,16 +5,33 @@ * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/bitops.h> +#include <linux/bug.h> +#include <linux/cdev.h> +#include <linux/container_of.h> #include <linux/debugfs.h> -#include <linux/errno.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/fs.h> #include <linux/init.h> -#include <linux/kernel.h> -#include <linux/kmod.h> -#include <linux/mm.h> +#include <linux/kobject.h> +#include <linux/kthread.h> +#include <linux/list.h> +#include <linux/minmax.h> #include <linux/module.h> +#include <linux/mutex.h> +#include <linux/printk.h> +#include <linux/seq_file.h> #include <linux/slab.h> +#include <linux/sprintf.h> #include <linux/string.h> +#include <linux/time.h> #include <linux/types.h> +#include <linux/wait.h> + +#include <asm/page.h> #include "cec-priv.h" @@ -93,7 +110,7 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, minor = find_first_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES); if (minor == CEC_NUM_DEVICES) { mutex_unlock(&cec_devnode_lock); - pr_err("could not get a free minor\n"); + pr_err("Could not get a free minor\n"); return -ENFILE; } @@ -104,19 +121,19 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, devnode->dev.bus = &cec_bus_type; devnode->dev.devt = MKDEV(MAJOR(cec_dev_t), minor); devnode->dev.release = cec_devnode_release; - dev_set_name(&devnode->dev, "cec%d", devnode->minor); + dev_set_name(&devnode->dev, "%s%d", CEC_NAME, devnode->minor); device_initialize(&devnode->dev); /* Part 2: Initialize and register the character device */ cdev_init(&devnode->cdev, &cec_devnode_fops); devnode->cdev.owner = owner; - kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor); + kobject_set_name(&devnode->cdev.kobj, "%s%d", CEC_NAME, devnode->minor); devnode->registered = true; ret = cdev_device_add(&devnode->cdev, &devnode->dev); if (ret) { devnode->registered = false; - pr_err("%s: cdev_device_add failed\n", __func__); + pr_err("cdev_device_add() failed\n"); goto clr_bit; } @@ -205,19 +222,35 @@ static int cec_error_inj_show(struct seq_file *sf, void *unused) return call_op(adap, error_inj_show, sf); } +DEFINE_SHOW_STORE_ATTRIBUTE(cec_error_inj); -static int cec_error_inj_open(struct inode *inode, struct file *file) +static ssize_t cec_error_inj_tx_timeouts_write(struct file *file, + const char __user *ubuf, size_t count, loff_t *ppos) { - return single_open(file, cec_error_inj_show, inode->i_private); + struct seq_file *sf = file->private_data; + struct cec_adapter *adap = sf->private; + int ret; + + if (count > 5) + return -EINVAL; + + mutex_lock(&adap->lock); + ret = kstrtou32_from_user(ubuf, count, 0, &adap->error_inj_tx_timeouts); + if (ret) + adap->error_inj_tx_timeouts = 0; + mutex_unlock(&adap->lock); + return ret ? : count; } -static const struct file_operations cec_error_inj_fops = { - .open = cec_error_inj_open, - .write = cec_error_inj_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +static int cec_error_inj_tx_timeouts_show(struct seq_file *sf, void *unused) +{ + struct cec_adapter *adap = sf->private; + + seq_printf(sf, "%u", adap->error_inj_tx_timeouts); + return 0; +} + +DEFINE_SHOW_STORE_ATTRIBUTE(cec_error_inj_tx_timeouts); #endif struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, @@ -263,12 +296,11 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, mutex_init(&adap->devnode.lock_fhs); mutex_init(&adap->devnode.lock); - adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name); + adap->kthread = kthread_run(cec_thread_func, adap, "%s-%s", CEC_NAME, name); if (IS_ERR(adap->kthread)) { - pr_err("cec-%s: kernel_thread() failed\n", name); + pr_err("%s: kthread_run() failed\n", name); res = PTR_ERR(adap->kthread); - kfree(adap); - return ERR_PTR(res); + goto err_free_adap; } #ifdef CONFIG_MEDIA_CEC_RC @@ -278,11 +310,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, /* Prepare the RC input device */ adap->rc = rc_allocate_device(RC_DRIVER_SCANCODE); if (!adap->rc) { - pr_err("cec-%s: failed to allocate memory for rc_dev\n", - name); + pr_err("%s: failed to allocate memory for rc_dev\n", name); kthread_stop(adap->kthread); - kfree(adap); - return ERR_PTR(-ENOMEM); + res = -ENOMEM; + goto err_free_adap; } snprintf(adap->input_phys, sizeof(adap->input_phys), @@ -298,9 +329,18 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, adap->rc->allowed_protocols = RC_PROTO_BIT_CEC; adap->rc->priv = adap; adap->rc->map_name = RC_MAP_CEC; - adap->rc->timeout = MS_TO_US(550); + adap->rc->timeout = 550 * USEC_PER_MSEC; #endif return adap; + +err_free_adap: + mutex_destroy(&adap->devnode.lock); + mutex_destroy(&adap->devnode.lock_fhs); + + mutex_destroy(&adap->lock); + + kfree(adap); + return ERR_PTR(res); } EXPORT_SYMBOL_GPL(cec_allocate_adapter); @@ -326,8 +366,7 @@ int cec_register_adapter(struct cec_adapter *adap, res = rc_register_device(adap->rc); if (res) { - pr_err("cec-%s: failed to prepare input device\n", - adap->name); + pr_err("%s: failed to prepare input device\n", adap->name); rc_free_device(adap->rc); adap->rc = NULL; return res; @@ -356,6 +395,9 @@ int cec_register_adapter(struct cec_adapter *adap, debugfs_create_devm_seqfile(&adap->devnode.dev, "status", adap->cec_dir, cec_adap_status); + debugfs_create_file("error-inj-tx-timeouts", 0644, adap->cec_dir, adap, + &cec_error_inj_tx_timeouts_fops); + if (!adap->ops->error_inj_show || !adap->ops->error_inj_parse_line) return 0; debugfs_create_file("error-inj", 0644, adap->cec_dir, adap, @@ -371,9 +413,7 @@ void cec_unregister_adapter(struct cec_adapter *adap) return; #ifdef CONFIG_MEDIA_CEC_RC - /* Note: rc_unregister also calls rc_free */ rc_unregister_device(adap->rc); - adap->rc = NULL; #endif debugfs_remove_recursive(adap->cec_dir); #ifdef CONFIG_CEC_NOTIFIER @@ -387,14 +427,23 @@ void cec_delete_adapter(struct cec_adapter *adap) { if (IS_ERR_OR_NULL(adap)) return; + if (adap->kthread_config) kthread_stop(adap->kthread_config); kthread_stop(adap->kthread); + if (adap->ops->adap_free) adap->ops->adap_free(adap); + #ifdef CONFIG_MEDIA_CEC_RC rc_free_device(adap->rc); #endif + + mutex_destroy(&adap->devnode.lock); + mutex_destroy(&adap->devnode.lock_fhs); + + mutex_destroy(&adap->lock); + kfree(adap); } EXPORT_SYMBOL_GPL(cec_delete_adapter); @@ -407,14 +456,14 @@ static int __init cec_devnode_init(void) int ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES, CEC_NAME); if (ret < 0) { - pr_warn("cec: unable to allocate major\n"); + pr_warn("Unable to allocate major\n"); return ret; } #ifdef CONFIG_DEBUG_FS - top_cec_dir = debugfs_create_dir("cec", NULL); + top_cec_dir = debugfs_create_dir(CEC_NAME, NULL); if (IS_ERR_OR_NULL(top_cec_dir)) { - pr_warn("cec: Failed to create debugfs cec dir\n"); + pr_warn("Failed to create debugfs " CEC_NAME " dir\n"); top_cec_dir = NULL; } #endif @@ -423,7 +472,7 @@ static int __init cec_devnode_init(void) if (ret < 0) { debugfs_remove_recursive(top_cec_dir); unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); - pr_warn("cec: bus_register failed\n"); + pr_warn("bus_register() failed\n"); return -EIO; } diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c index 6e1c39102832..6a0ee32e8401 100644 --- a/drivers/media/cec/core/cec-pin.c +++ b/drivers/media/cec/core/cec-pin.c @@ -115,7 +115,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) return; pin->adap->cec_pin_is_high = v; - if (atomic_read(&pin->work_pin_num_events) < CEC_NUM_PIN_EVENTS) { + if (atomic_read_acquire(&pin->work_pin_num_events) < CEC_NUM_PIN_EVENTS) { u8 ev = v; if (pin->work_pin_events_dropped) { @@ -126,7 +126,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) pin->work_pin_ts[pin->work_pin_events_wr] = ktime_get(); pin->work_pin_events_wr = (pin->work_pin_events_wr + 1) % CEC_NUM_PIN_EVENTS; - atomic_inc(&pin->work_pin_num_events); + atomic_inc_return_release(&pin->work_pin_num_events); } else { pin->work_pin_events_dropped = true; pin->work_pin_events_dropped_cnt++; @@ -692,7 +692,6 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) v = cec_pin_read(pin); if (!v) break; - pin->state = CEC_ST_RX_START_BIT_HIGH; delta = ktime_us_delta(ts, pin->ts); /* Start bit low is too short, go back to idle */ if (delta < CEC_TIM_START_BIT_LOW_MIN - CEC_TIM_IDLE_SAMPLE) { @@ -703,7 +702,16 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) cec_pin_to_idle(pin); break; } + pin->state = CEC_ST_RX_START_BIT_HIGH; if (rx_arb_lost(pin, &poll)) { + /* + * Normally rx_toggle is toggled in cec_pin_to_idle() + * when we're in an RX state, but here we switch to TX + * mode, so cec_pin_to_idle() sees a TX mode and never + * toggles rx_toggle. So toggle it here as a special + * corner case. + */ + pin->rx_toggle ^= 1; cec_msg_init(&pin->tx_msg, poll >> 4, poll & 0xf); pin->tx_generated_poll = true; pin->tx_extra_bytes = 0; @@ -1101,7 +1109,7 @@ static int cec_pin_thread_func(void *_adap) pin->work_tx_ts); } - while (atomic_read(&pin->work_pin_num_events)) { + while (atomic_read_acquire(&pin->work_pin_num_events)) { unsigned int idx = pin->work_pin_events_rd; u8 v = pin->work_pin_events[idx]; @@ -1110,7 +1118,7 @@ static int cec_pin_thread_func(void *_adap) v & CEC_PIN_EVENT_FL_DROPPED, pin->work_pin_ts[idx]); pin->work_pin_events_rd = (idx + 1) % CEC_NUM_PIN_EVENTS; - atomic_dec(&pin->work_pin_num_events); + atomic_dec_return_release(&pin->work_pin_num_events); } switch (atomic_xchg(&pin->work_irq_change, diff --git a/drivers/media/cec/platform/meson/ao-cec-g12a.c b/drivers/media/cec/platform/meson/ao-cec-g12a.c index 41f5b8669cb0..b175be3f2bf4 100644 --- a/drivers/media/cec/platform/meson/ao-cec-g12a.c +++ b/drivers/media/cec/platform/meson/ao-cec-g12a.c @@ -405,6 +405,7 @@ static int meson_ao_cec_g12a_write(void *context, unsigned int addr, } static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { + .name = "core", .reg_bits = 8, .val_bits = 8, .reg_read = meson_ao_cec_g12a_read, @@ -688,10 +689,8 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev) meson_ao_cec_g12a_irq, meson_ao_cec_g12a_irq_thread, 0, NULL, ao_cec); - if (ret) { - dev_err(&pdev->dev, "irq request failed\n"); + if (ret) goto out_probe_adapter; - } ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); if (IS_ERR(ao_cec->oscin)) { diff --git a/drivers/media/cec/platform/meson/ao-cec.c b/drivers/media/cec/platform/meson/ao-cec.c index 145efd9af6ac..2df0d3743077 100644 --- a/drivers/media/cec/platform/meson/ao-cec.c +++ b/drivers/media/cec/platform/meson/ao-cec.c @@ -636,10 +636,8 @@ static int meson_ao_cec_probe(struct platform_device *pdev) meson_ao_cec_irq, meson_ao_cec_irq_thread, 0, NULL, ao_cec); - if (ret) { - dev_err(&pdev->dev, "irq request failed\n"); + if (ret) goto out_probe_adapter; - } ao_cec->core = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(ao_cec->core)) { diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c index 97ed9654c78a..12db6dca602b 100644 --- a/drivers/media/cec/platform/seco/seco-cec.c +++ b/drivers/media/cec/platform/seco/seco-cec.c @@ -7,14 +7,15 @@ * Copyright (C) 2018, Aidilab Srl. */ -#include <linux/module.h> #include <linux/acpi.h> #include <linux/delay.h> #include <linux/dmi.h> #include <linux/gpio/consumer.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/pci.h> #include <linux/platform_device.h> +#include <linux/time.h> /* CEC Framework */ #include <media/cec-notifier.h> @@ -356,7 +357,7 @@ static int secocec_ir_probe(void *priv) cec->ir->allowed_protocols = RC_PROTO_BIT_RC5; cec->ir->priv = cec; cec->ir->map_name = RC_MAP_HAUPPAUGE; - cec->ir->timeout = MS_TO_US(100); + cec->ir->timeout = 100 * USEC_PER_MSEC; /* Clear the status register */ status = smb_rd16(SECOCEC_STATUS_REG_1, &val); @@ -618,7 +619,6 @@ static int secocec_probe(struct platform_device *pdev) dev_name(&pdev->dev), secocec); if (ret) { - dev_err(dev, "Cannot request IRQ %d\n", secocec->irq); ret = -EIO; goto err; } diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c index 1ec0cece0a5b..29418966a98e 100644 --- a/drivers/media/cec/platform/stm32/stm32-cec.c +++ b/drivers/media/cec/platform/stm32/stm32-cec.c @@ -132,7 +132,8 @@ static void stm32_rx_done(struct stm32_cec *cec, u32 status) u32 val; regmap_read(cec->regmap, CEC_RXDR, &val); - cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF; + if (cec->rx_msg.len < CEC_MAX_MSG_SIZE) + cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF; } if (cec->irq_status & RXEND) { @@ -193,18 +194,24 @@ static int stm32_cec_adap_enable(struct cec_adapter *adap, bool enable) static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) { struct stm32_cec *cec = adap->priv; - u32 oar = (1 << logical_addr) << 16; u32 val; + int ret; /* Poll every 100µs the register CEC_CR to wait end of transmission */ - regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM), - 100, CEC_XFER_TIMEOUT_MS * 1000); + ret = regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM), + 100, CEC_XFER_TIMEOUT_MS * 1000); + if (ret) + return ret; + regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0); - if (logical_addr == CEC_LOG_ADDR_INVALID) + if (logical_addr == CEC_LOG_ADDR_INVALID) { regmap_update_bits(cec->regmap, CEC_CFGR, OAR, 0); - else + } else { + u32 oar = BIT(logical_addr) << 16; + regmap_update_bits(cec->regmap, CEC_CFGR, oar, oar); + } regmap_update_bits(cec->regmap, CEC_CR, CECEN, CECEN); diff --git a/drivers/media/cec/platform/tegra/tegra_cec.c b/drivers/media/cec/platform/tegra/tegra_cec.c index 3ed50097262f..d64e1662249e 100644 --- a/drivers/media/cec/platform/tegra/tegra_cec.c +++ b/drivers/media/cec/platform/tegra/tegra_cec.c @@ -24,6 +24,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/seq_file.h> #include <linux/clk/tegra.h> #include <media/cec-notifier.h> @@ -47,6 +48,7 @@ struct tegra_cec { u32 tx_buf[CEC_MAX_MSG_SIZE]; u8 tx_buf_cur; u8 tx_buf_cnt; + u32 rx_total_low_drives; }; static inline u32 cec_read(struct tegra_cec *cec, u32 reg) @@ -116,6 +118,13 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data) return IRQ_WAKE_THREAD; } + if (status & TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED) { + dev_warn_ratelimited(dev, "RX bus error detected, generated low drive\n"); + cec->rx_total_low_drives++; + cec_write(cec, TEGRA_CEC_INT_STAT, + TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED); + } + if ((status & TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED) || (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)) { tegra_cec_error_recovery(cec); @@ -241,9 +250,21 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable) TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED | TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED | TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | + TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED | TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED); - cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE); + /* + * TX_NAK_MODE ensures that the whole message is transmitted even + * if each byte is NACKed. Without this flag the retransmit of the + * messages after a NACK can be corrupt. This is a bug in the hardware. + * + * While less efficient, in practice you rarely transmit messages + * that can be NACKed, with the exception of POLL messages which + * are just one byte anyway. + */ + cec_write(cec, TEGRA_CEC_HW_CONTROL, + TEGRA_CEC_HWCTRL_TX_RX_MODE | + TEGRA_CEC_HWCTRL_TX_NAK_MODE); return 0; } @@ -307,11 +328,20 @@ static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, return 0; } +static void tegra_cec_adap_status(struct cec_adapter *adap, struct seq_file *file) +{ + struct tegra_cec *cec = adap->priv; + + seq_printf(file, "receive low drive count: %u\n", + cec->rx_total_low_drives); +} + static const struct cec_adap_ops tegra_cec_ops = { .adap_enable = tegra_cec_adap_enable, .adap_log_addr = tegra_cec_adap_log_addr, .adap_transmit = tegra_cec_adap_transmit, .adap_monitor_all_enable = tegra_cec_adap_monitor_all_enable, + .adap_status = tegra_cec_adap_status, }; static int tegra_cec_probe(struct platform_device *pdev) @@ -381,11 +411,8 @@ static int tegra_cec_probe(struct platform_device *pdev) tegra_cec_irq_handler, tegra_cec_irq_thread_handler, 0, "cec_irq", &pdev->dev); - if (ret) { - dev_err(&pdev->dev, - "Unable to request interrupt for device\n"); + if (ret) goto err_clk; - } cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME, CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | @@ -458,6 +485,7 @@ static const struct of_device_id tegra_cec_of_match[] = { { .compatible = "nvidia,tegra210-cec", }, {}, }; +MODULE_DEVICE_TABLE(of, tegra_cec_of_match); static struct platform_driver tegra_cec_driver = { .driver = { diff --git a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c index 3381d86096a1..3c6ce6f3d93e 100644 --- a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c +++ b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c @@ -657,7 +657,8 @@ static void extron_process_received(struct extron_port *port, const char *data) if (!port || port->disconnected) return; - if (len < 5 || (len - 2) % 3 || data[len - 2] != '*') + if (len < 5 || ((len - 2) / 3 > sizeof(msg.msg)) || + (len - 2) % 3 || data[len - 2] != '*') goto malformed; while (*data != '*') { diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 931e5dc453b9..e1d5c220f738 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -2346,9 +2346,11 @@ static void tpg_fill_params_extras(const struct tpg_data *tpg, (params->is_60hz ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); } -static void tpg_fill_plane_extras(const struct tpg_data *tpg, - const struct tpg_draw_params *params, - unsigned p, unsigned h, u8 *vbuf) +/* noinline to work around clang KASAN issues */ +static noinline_for_stack void +tpg_fill_plane_extras(const struct tpg_data *tpg, + const struct tpg_draw_params *params, + unsigned p, unsigned h, u8 *vbuf) { unsigned twopixsize = params->twopixsize; unsigned img_width = params->img_width; @@ -2483,9 +2485,9 @@ static void tpg_fill_plane_extras(const struct tpg_data *tpg, } } -static void tpg_fill_plane_pattern(const struct tpg_data *tpg, - const struct tpg_draw_params *params, - unsigned p, unsigned h, u8 *vbuf) +static noinline_for_stack void +tpg_fill_plane_pattern(const struct tpg_data *tpg, const struct tpg_draw_params *params, + unsigned p, unsigned h, u8 *vbuf) { unsigned twopixsize = params->twopixsize; unsigned img_width = params->img_width; diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 4baded4fd3b8..5a1ee5eb9c0f 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -635,19 +635,6 @@ struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp) } EXPORT_SYMBOL_GPL(vb2_find_buffer); -/* - * vb2_querybuf() - query video buffer information - * @q: vb2 queue - * @b: buffer struct passed from userspace to vidioc_querybuf handler - * in driver - * - * Should be called from vidioc_querybuf ioctl handler in driver. - * This function will verify the passed v4l2_buffer structure and fill the - * relevant information for the userspace. - * - * The return values from this function are intended to be directly returned - * from vidioc_querybuf handler in driver. - */ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b) { struct vb2_buffer *vb; diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 3c8bc75e4d6c..6a825d9bae43 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -884,6 +884,7 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, struct dmxdev_filter *filter, u16 pid) { struct dmxdev_feed *feed; + int ret; if ((filter->type != DMXDEV_TYPE_PES) || (filter->state < DMXDEV_STATE_SET)) @@ -901,8 +902,14 @@ static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, feed->pid = pid; list_add(&feed->next, &filter->feed.ts); - if (filter->state >= DMXDEV_STATE_GO) - return dvb_dmxdev_start_feed(dmxdev, filter, feed); + if (filter->state >= DMXDEV_STATE_GO) { + ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); + if (ret < 0) { + list_del(&feed->next); + kfree(feed); + return ret; + } + } return 0; } diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index d082b6c57c76..0286da57f382 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -30,6 +30,7 @@ #include <linux/kthread.h> #include <linux/ktime.h> #include <linux/compat.h> +#include <linux/lockdep.h> #include <asm/processor.h> #include <media/dvb_frontend.h> @@ -2760,77 +2761,25 @@ static __poll_t dvb_frontend_poll(struct file *file, struct poll_table_struct *w return 0; } -static int dvb_frontend_open(struct inode *inode, struct file *file) +static int __dvb_frontend_open(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dvb_adapter *adapter = fe->dvb; int ret; - dev_dbg(fe->dvb->device, "%s:\n", __func__); - if (fe->exit == DVB_FE_DEVICE_REMOVED) - return -ENODEV; - - if (adapter->mfe_shared == 2) { - mutex_lock(&adapter->mfe_lock); - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - if (adapter->mfe_dvbdev && - !adapter->mfe_dvbdev->writers) { - mutex_unlock(&adapter->mfe_lock); - return -EBUSY; - } - adapter->mfe_dvbdev = dvbdev; - } - } else if (adapter->mfe_shared) { - mutex_lock(&adapter->mfe_lock); - - if (!adapter->mfe_dvbdev) - adapter->mfe_dvbdev = dvbdev; - - else if (adapter->mfe_dvbdev != dvbdev) { - struct dvb_device - *mfedev = adapter->mfe_dvbdev; - struct dvb_frontend - *mfe = mfedev->priv; - struct dvb_frontend_private - *mfepriv = mfe->frontend_priv; - int mferetry = (dvb_mfe_wait_time << 1); - - mutex_unlock(&adapter->mfe_lock); - while (mferetry-- && (mfedev->users != -1 || - mfepriv->thread)) { - if (msleep_interruptible(500)) { - if (signal_pending(current)) - return -EINTR; - } - } - - mutex_lock(&adapter->mfe_lock); - if (adapter->mfe_dvbdev != dvbdev) { - mfedev = adapter->mfe_dvbdev; - mfe = mfedev->priv; - mfepriv = mfe->frontend_priv; - if (mfedev->users != -1 || - mfepriv->thread) { - mutex_unlock(&adapter->mfe_lock); - return -EBUSY; - } - adapter->mfe_dvbdev = dvbdev; - } - } - } - if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) - goto err0; + return ret; - /* If we took control of the bus, we need to force - reinitialization. This is because many ts_bus_ctrl() - functions strobe the RESET pin on the demod, and if the - frontend thread already exists then the dvb_init() routine - won't get called (which is what usually does initial - register configuration). */ + /* + * If we took control of the bus, we need to force + * reinitialization. This is because many ts_bus_ctrl() + * functions strobe the RESET pin on the demod, and if the + * frontend thread already exists then the dvb_init() routine + * won't get called (which is what usually does initial + * register configuration). + */ fepriv->reinitialise = 1; } @@ -2871,8 +2820,6 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) dvb_frontend_get(fe); - if (adapter->mfe_shared) - mutex_unlock(&adapter->mfe_lock); return ret; err3: @@ -2891,12 +2838,88 @@ err2: err1: if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) fe->ops.ts_bus_ctrl(fe, 0); -err0: - if (adapter->mfe_shared) - mutex_unlock(&adapter->mfe_lock); + + return ret; +} + +static int wait_dvb_frontend(struct dvb_adapter *adapter, + struct dvb_device *mfedev) +{ + struct dvb_frontend *mfe = mfedev->priv; + struct dvb_frontend_private *mfepriv = mfe->frontend_priv; + int mferetry = (dvb_mfe_wait_time << 1); + int ret = 0; + + lockdep_assert_held(&adapter->mfe_lock); + + if (mfedev->users == -1 && !mfepriv->thread) + return 0; + + mutex_unlock(&adapter->mfe_lock); + + while (mferetry-- && (mfedev->users != -1 || mfepriv->thread)) { + if (msleep_interruptible(500)) + if (signal_pending(current)) { + ret = -EINTR; + break; + } + } + + mutex_lock(&adapter->mfe_lock); + return ret; } +static int dvb_frontend_open(struct inode *inode, struct file *file) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dvb_adapter *adapter = fe->dvb; + + dev_dbg(fe->dvb->device, "%s:\n", __func__); + if (fe->exit == DVB_FE_DEVICE_REMOVED) + return -ENODEV; + + if (!adapter->mfe_shared) + return __dvb_frontend_open(inode, file); + + guard(mutex)(&adapter->mfe_lock); + + if (adapter->mfe_shared == 2) { + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if (adapter->mfe_dvbdev && + !adapter->mfe_dvbdev->writers) + return -EBUSY; + adapter->mfe_dvbdev = dvbdev; + } + return __dvb_frontend_open(inode, file); + } + + if (!adapter->mfe_dvbdev) { + adapter->mfe_dvbdev = dvbdev; + } else if (adapter->mfe_dvbdev != dvbdev) { + struct dvb_device *mfedev = adapter->mfe_dvbdev; + struct dvb_frontend *mfe = mfedev->priv; + struct dvb_frontend_private *mfepriv = mfe->frontend_priv; + int ret; + + ret = wait_dvb_frontend(adapter, mfedev); + if (ret) + return ret; + + if (adapter->mfe_dvbdev != dvbdev) { + mfedev = adapter->mfe_dvbdev; + mfe = mfedev->priv; + mfepriv = mfe->frontend_priv; + if (mfedev->users != -1 || mfepriv->thread) + return -EBUSY; + adapter->mfe_dvbdev = dvbdev; + } + } + + return __dvb_frontend_open(inode, file); +} + static int dvb_frontend_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c index 993280fefc2c..5fbb466cc8af 100644 --- a/drivers/media/dvb-frontends/helene.c +++ b/drivers/media/dvb-frontends/helene.c @@ -995,22 +995,22 @@ struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, const struct helene_config *config, struct i2c_adapter *i2c) { - struct helene_priv *priv = NULL; + struct helene_priv *pr = NULL; - priv = kzalloc_obj(struct helene_priv); - if (priv == NULL) + pr = kzalloc_obj(struct helene_priv); + if (!pr) return NULL; - priv->i2c_address = (config->i2c_address >> 1); - priv->i2c = i2c; - priv->set_tuner_data = config->set_tuner_priv; - priv->set_tuner = config->set_tuner_callback; - priv->xtal = config->xtal; + pr->i2c_address = (config->i2c_address >> 1); + pr->i2c = i2c; + pr->set_tuner_data = config->set_tuner_priv; + pr->set_tuner = config->set_tuner_callback; + pr->xtal = config->xtal; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - if (helene_x_pon(priv) != 0) { - kfree(priv); + if (helene_x_pon(pr) != 0) { + kfree(pr); return NULL; } @@ -1019,10 +1019,10 @@ struct dvb_frontend *helene_attach_s(struct dvb_frontend *fe, memcpy(&fe->ops.tuner_ops, &helene_tuner_ops_s, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - dev_info(&priv->i2c->dev, - "Sony HELENE Sat attached on addr=%x at I2C adapter %p\n", - priv->i2c_address, priv->i2c); + fe->tuner_priv = pr; + dev_info(&pr->i2c->dev, + "Sony HELENE Sat attached on addr=%x at I2C adapter %p\n", + pr->i2c_address, pr->i2c); return fe; } EXPORT_SYMBOL_GPL(helene_attach_s); @@ -1031,22 +1031,22 @@ struct dvb_frontend *helene_attach(struct dvb_frontend *fe, const struct helene_config *config, struct i2c_adapter *i2c) { - struct helene_priv *priv = NULL; + struct helene_priv *pr = NULL; - priv = kzalloc_obj(struct helene_priv); - if (priv == NULL) + pr = kzalloc_obj(struct helene_priv); + if (!pr) return NULL; - priv->i2c_address = (config->i2c_address >> 1); - priv->i2c = i2c; - priv->set_tuner_data = config->set_tuner_priv; - priv->set_tuner = config->set_tuner_callback; - priv->xtal = config->xtal; + pr->i2c_address = (config->i2c_address >> 1); + pr->i2c = i2c; + pr->set_tuner_data = config->set_tuner_priv; + pr->set_tuner = config->set_tuner_callback; + pr->xtal = config->xtal; if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1); - if (helene_x_pon(priv) != 0) { - kfree(priv); + if (helene_x_pon(pr) != 0) { + kfree(pr); return NULL; } @@ -1055,10 +1055,10 @@ struct dvb_frontend *helene_attach(struct dvb_frontend *fe, memcpy(&fe->ops.tuner_ops, &helene_tuner_ops_t, sizeof(struct dvb_tuner_ops)); - fe->tuner_priv = priv; - dev_info(&priv->i2c->dev, - "Sony HELENE Ter attached on addr=%x at I2C adapter %p\n", - priv->i2c_address, priv->i2c); + fe->tuner_priv = pr; + dev_info(&pr->i2c->dev, + "Sony HELENE Ter attached on addr=%x at I2C adapter %p\n", + pr->i2c_address, pr->i2c); return fe; } EXPORT_SYMBOL_GPL(helene_attach); diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index c564485e3bbb..0330e7f0881a 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -906,9 +906,12 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) goto err; mutex_unlock(&dev->v4l2_lock); + return 0; err: + rtl2832_sdr_free_urbs(dev); + rtl2832_sdr_free_stream_bufs(dev); rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED); mutex_unlock(&dev->v4l2_lock); @@ -1477,14 +1480,22 @@ static void rtl2832_sdr_remove(struct platform_device *pdev) dev_dbg(&pdev->dev, "\n"); - mutex_lock(&dev->vb_queue_lock); + /* + * vb2_video_unregister_device() releases the vb2 queue, which + * triggers rtl2832_sdr_stop_streaming() if streaming is active. + * stop_streaming() uses dev->udev to free URBs and coherent DMA + * stream buffers via usb_free_coherent(), so it must run before + * dev->udev is cleared. vb2_video_unregister_device() locks + * vb_queue_lock internally and stop_streaming() locks v4l2_lock, + * so neither may be held by the caller. + */ + v4l2_device_disconnect(&dev->v4l2_dev); + vb2_video_unregister_device(&dev->vdev); + mutex_lock(&dev->v4l2_lock); - /* No need to keep the urbs around after disconnection */ dev->udev = NULL; - v4l2_device_disconnect(&dev->v4l2_dev); - video_unregister_device(&dev->vdev); mutex_unlock(&dev->v4l2_lock); - mutex_unlock(&dev->vb_queue_lock); + v4l2_device_put(&dev->v4l2_dev); module_put(pdev->dev.parent->driver->owner); } diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 5d173e0ecf42..5c52007f9cbe 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -259,6 +259,7 @@ config VIDEO_IMX335 config VIDEO_IMX355 tristate "Sony IMX355 sensor support" + select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the Sony IMX355 camera. @@ -269,6 +270,7 @@ config VIDEO_IMX355 config VIDEO_IMX412 tristate "Sony IMX412 sensor support" depends on OF + select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the Sony IMX412 camera. @@ -287,6 +289,27 @@ config VIDEO_IMX415 To compile this driver as a module, choose M here: the module will be called imx415. +config VIDEO_IMX471 + tristate "Sony IMX471 sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor driver for the Sony + IMX471 camera. + + To compile this driver as a module, choose M here: the + module will be called imx471. + +config VIDEO_IMX678 + tristate "Sony IMX678 sensor support" + depends on GPIOLIB + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor driver for the Sony + IMX678 camera. + + To compile this driver as a module, choose M here: the + module will be called imx678. + config VIDEO_MAX9271_LIB tristate diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index e45359efe0e4..d04bd5724552 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -61,6 +61,8 @@ obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_VIDEO_IMX412) += imx412.o obj-$(CONFIG_VIDEO_IMX415) += imx415.o +obj-$(CONFIG_VIDEO_IMX678) += imx678.o +obj-$(CONFIG_VIDEO_IMX471) += imx471.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_ISL7998X) += isl7998x.o obj-$(CONFIG_VIDEO_KS0127) += ks0127.o diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c index dd991c2ee700..f51f9b987759 100644 --- a/drivers/media/i2c/alvium-csi2.c +++ b/drivers/media/i2c/alvium-csi2.c @@ -1290,7 +1290,7 @@ static int alvium_set_ctrl_auto_exposure(struct alvium_dev *alvium, bool on) struct device *dev = &alvium->i2c_client->dev; int ret; - ret = alvium_write_hshake(alvium, REG_BCRM_WHITE_BALANCE_AUTO_RW, + ret = alvium_write_hshake(alvium, REG_BCRM_EXPOSURE_AUTO_RW, on ? 0x02 : 0x00); if (ret) { dev_err(dev, "Fail to set autoexposure reg\n"); diff --git a/drivers/media/i2c/cvs/core.c b/drivers/media/i2c/cvs/core.c index fe9e59ac311c..d4a3b9c3bab1 100644 --- a/drivers/media/i2c/cvs/core.c +++ b/drivers/media/i2c/cvs/core.c @@ -31,6 +31,7 @@ #define PCI_DEVICE_ID_INTEL_IPU7 0x645d /* MTL / LNL */ #define PCI_DEVICE_ID_INTEL_IPU7P5 0xb05d /* ARL / PTL */ +#define PCI_DEVICE_ID_INTEL_IPU8 0xd719 /* NVL */ /* * IPU7 PCI device IDs not covered by ipu6_pci_tbl in ipu6-pci-table.h. @@ -39,6 +40,7 @@ static const struct pci_device_id icvs_ipu7_tbl[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7P5) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU8) }, { } }; @@ -962,6 +964,7 @@ static const struct acpi_device_id intel_cvs_acpi_match[] = { { "INTC10DE" }, /* LNL */ { "INTC10E0" }, /* ARL */ { "INTC10E1" }, /* PTL */ + { "INTC10FA" }, /* NVL */ { } }; MODULE_DEVICE_TABLE(acpi, intel_cvs_acpi_match); diff --git a/drivers/media/i2c/cvs/icvs.h b/drivers/media/i2c/cvs/icvs.h index cfa8ef5d975c..17beb0920dd2 100644 --- a/drivers/media/i2c/cvs/icvs.h +++ b/drivers/media/i2c/cvs/icvs.h @@ -432,7 +432,6 @@ enum icvs_state { * @freq_ctrl: (future) frequency control pointer * @pads: Local media pads (sink/source) * @nr_of_lanes: Active CSI-2 lane count - * @link_freq: Current link frequency (Hz) * @ipu_link: PM runtime device link (IPU consumer, CVS supplier) * @res: Resource capability (light/full) * @caps: Reported device protocol capabilities @@ -458,7 +457,6 @@ struct icvs { struct v4l2_ctrl *freq_ctrl; struct media_pad pads[ICVS_CSI_NUM_PADS]; u32 nr_of_lanes; - u64 link_freq; struct device_link *ipu_link; enum icvs_resources res; struct icvs_dev_capabilities caps; diff --git a/drivers/media/i2c/cvs/v4l2.c b/drivers/media/i2c/cvs/v4l2.c index 3a1ec0059ef7..9fadca7a3bee 100644 --- a/drivers/media/i2c/cvs/v4l2.c +++ b/drivers/media/i2c/cvs/v4l2.c @@ -46,6 +46,7 @@ static const struct v4l2_mbus_framefmt cvs_csi_format_mbus_default = { /** * csi_set_link_cfg - Program default CSI-2 link parameters * @ctx: CVS device context + * @link_freq: Link frequency (Hz) * * Populates a HOST_SET_MIPI_CONFIG command using current lane count and * link frequency, then submits it to the device. @@ -53,12 +54,12 @@ static const struct v4l2_mbus_framefmt cvs_csi_format_mbus_default = { * * Return: 0 on success or negative errno. */ -static int csi_set_link_cfg(struct icvs *ctx) +static int csi_set_link_cfg(struct icvs *ctx, u64 link_freq) { struct icvs_cmd cmd = { .cmd_id = cpu_to_be16(ICVS_HOST_SET_MIPI_CONFIG), .param.conf.nr_of_lanes = ctx->nr_of_lanes, - .param.conf.link_freq = ctx->link_freq, + .param.conf.link_freq = link_freq, }; size_t cmd_size = sizeof(cmd.cmd_id) + sizeof(cmd.param.conf); @@ -91,7 +92,7 @@ static int cvs_csi_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev *remote_sd = media_entity_to_v4l2_subdev(ctx->remote->entity); struct device *dev = cvs_dev(ctx); - s64 freq; + s64 link_freq; int ret; /* cvs_set_link_owner(ICVS_CSI_LINK_HOST) */ @@ -99,15 +100,14 @@ static int cvs_csi_enable_streams(struct v4l2_subdev *sd, if (ret < 0) return ret; - freq = v4l2_get_link_freq(ctx->remote, 0, 0); - if (freq < 0) { - ret = freq; + link_freq = v4l2_get_link_freq(ctx->remote, 0, 0); + if (link_freq < 0) { + ret = link_freq; goto err_rpm_put; } - ctx->link_freq = freq; if (ctx->i2c_client) { - ret = csi_set_link_cfg(ctx); + ret = csi_set_link_cfg(ctx, link_freq); if (ret < 0) goto err_rpm_put_sync; } @@ -345,7 +345,6 @@ static int cvs_csi_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, if (freq < 0) return -EINVAL; - ctx->link_freq = freq; cfg->link_freq = freq; return 0; diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 8110d40931d9..8b7dd43ed208 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -3962,6 +3962,7 @@ static int cx25840_probe(struct i2c_client *client) int err = state->hdl.error; v4l2_ctrl_handler_free(&state->hdl); + media_entity_cleanup(&sd->entity); return err; } if (!is_cx2583x(state)) @@ -3986,6 +3987,7 @@ static void cx25840_remove(struct i2c_client *client) cx25840_ir_remove(sd); v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&state->hdl); + media_entity_cleanup(&sd->entity); } static const struct i2c_device_id cx25840_id[] = { diff --git a/drivers/media/i2c/gc0310.c b/drivers/media/i2c/gc0310.c index 7af4d66f42a0..754e82ad50ae 100644 --- a/drivers/media/i2c/gc0310.c +++ b/drivers/media/i2c/gc0310.c @@ -6,6 +6,7 @@ * Copyright (c) 2023-2025 Hans de Goede <hansg@kernel.org> */ +#include <linux/clk.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/gpio/consumer.h> @@ -84,6 +85,8 @@ #define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd) struct gc0310_device { + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; @@ -635,7 +638,6 @@ static int gc0310_check_hwcfg(struct device *dev) }; struct fwnode_handle *ep_fwnode; unsigned long link_freq_bitmap; - u32 mclk; int ret; /* @@ -647,21 +649,6 @@ static int gc0310_check_hwcfg(struct device *dev) return dev_err_probe(dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n"); - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &mclk); - if (ret) { - fwnode_handle_put(ep_fwnode); - return dev_err_probe(dev, ret, - "reading clock-frequency property\n"); - } - - if (mclk != GC0310_MCLK_FREQ) { - fwnode_handle_put(ep_fwnode); - return dev_err_probe(dev, -EINVAL, - "external clock %u is not supported\n", - mclk); - } - ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &bus_cfg); fwnode_handle_put(ep_fwnode); if (ret) @@ -685,6 +672,7 @@ static int gc0310_check_hwcfg(struct device *dev) static int gc0310_probe(struct i2c_client *client) { struct gc0310_device *sensor; + unsigned long freq; int ret; ret = gc0310_check_hwcfg(&client->dev); @@ -695,6 +683,16 @@ static int gc0310_probe(struct i2c_client *client) if (!sensor) return -ENOMEM; + sensor->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); + if (IS_ERR(sensor->clk)) + return dev_err_probe(&client->dev, PTR_ERR(sensor->clk), + "failed to get clock\n"); + + freq = clk_get_rate(sensor->clk); + if (freq != GC0310_MCLK_FREQ) + return dev_err_probe(&client->dev, -EINVAL, + "external clock %lu is not supported\n", freq); + sensor->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(sensor->reset)) { return dev_err_probe(&client->dev, PTR_ERR(sensor->reset), diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 223d3753cc93..9571f3622d2d 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -110,11 +110,16 @@ /* Test Pattern Control */ #define IMX219_REG_TEST_PATTERN CCI_REG16(0x0600) -#define IMX219_TEST_PATTERN_DISABLE 0 -#define IMX219_TEST_PATTERN_SOLID_COLOR 1 -#define IMX219_TEST_PATTERN_COLOR_BARS 2 -#define IMX219_TEST_PATTERN_GREY_COLOR 3 -#define IMX219_TEST_PATTERN_PN9 4 +#define IMX219_TEST_PATTERN_DISABLE 0 +#define IMX219_TEST_PATTERN_SOLID_COLOR 1 +#define IMX219_TEST_PATTERN_COLOR_BARS 2 +#define IMX219_TEST_PATTERN_GREY_COLOR 3 +#define IMX219_TEST_PATTERN_PN9 4 +#define IMX219_TEST_PATTERN_16SPLIT_COLOR_BARS 5 +#define IMX219_TEST_PATTERN_16SPLIT_INV_COLOR_BARS 6 +#define IMX219_TEST_PATTERN_COLUMN_COUNTER 7 +#define IMX219_TEST_PATTERN_INV_COLUMN_COUNTER 8 +#define IMX219_TEST_PATTERN_PN31 9 /* Test pattern colour components */ #define IMX219_REG_TESTP_RED CCI_REG16(0x0602) @@ -238,7 +243,12 @@ static const char * const imx219_test_pattern_menu[] = { "Color Bars", "Solid Color", "Grey Color Bars", - "PN9" + "PN9", + "16 Split Color Bars", + "16 Split Inverted Color Bars", + "Column Counter", + "Inverted Column Counter", + "PN31" }; static const int imx219_test_pattern_val[] = { @@ -247,6 +257,11 @@ static const int imx219_test_pattern_val[] = { IMX219_TEST_PATTERN_SOLID_COLOR, IMX219_TEST_PATTERN_GREY_COLOR, IMX219_TEST_PATTERN_PN9, + IMX219_TEST_PATTERN_16SPLIT_COLOR_BARS, + IMX219_TEST_PATTERN_16SPLIT_INV_COLOR_BARS, + IMX219_TEST_PATTERN_COLUMN_COUNTER, + IMX219_TEST_PATTERN_INV_COLUMN_COUNTER, + IMX219_TEST_PATTERN_PN31 }; /* regulator supplies */ diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 27a5c212a527..8eb8588cb71b 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -9,74 +9,97 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/unaligned.h> +#include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> #include <media/v4l2-fwnode.h> -#define IMX355_REG_MODE_SELECT 0x0100 +#define IMX355_REG_MODE_SELECT CCI_REG8(0x0100) #define IMX355_MODE_STANDBY 0x00 #define IMX355_MODE_STREAMING 0x01 /* Chip ID */ -#define IMX355_REG_CHIP_ID 0x0016 +#define IMX355_REG_CHIP_ID CCI_REG16(0x0016) #define IMX355_CHIP_ID 0x0355 +#define IMX355_REG_LANE_SEL CCI_REG8(0x0114) + +/* PLL registers that depend on the external clock frequency */ +#define IMX355_REG_EXTCLK_FREQ CCI_REG16(0x0136) +#define IMX355_REG_PLL_OP_PREDIV CCI_REG8(0x030d) +#define IMX355_REG_PLL_OP_MUL CCI_REG16(0x030e) +#define IMX355_REG_PLL_IVT_PCK_DIV CCI_REG8(0x0301) +#define IMX355_REG_PLL_IVT_SYSCK_DIV CCI_REG8(0x0303) +#define IMX355_PLL_OP_PREDIV 2 +#define IMX355_PLL_IVT_PCK_DIV 5 + /* V_TIMING internal */ -#define IMX355_REG_FLL 0x0340 +#define IMX355_REG_FLL CCI_REG16(0x0340) #define IMX355_FLL_MAX 0xffff +#define IMX355_VBLANK_MIN 20 + +#define IMX355_REG_LLP CCI_REG16(0x0342) +#define IMX355_LLP_MAX 0xffff + +#define IMX355_REG_X_ADD_START CCI_REG16(0x0344) +#define IMX355_REG_Y_ADD_START CCI_REG16(0x0346) +#define IMX355_REG_X_ADD_END CCI_REG16(0x0348) +#define IMX355_REG_Y_ADD_END CCI_REG16(0x034a) +#define IMX355_REG_X_OUT_SIZE CCI_REG16(0x034c) +#define IMX355_REG_Y_OUT_SIZE CCI_REG16(0x034e) /* Exposure control */ -#define IMX355_REG_EXPOSURE 0x0202 +#define IMX355_REG_EXPOSURE CCI_REG16(0x0202) #define IMX355_EXPOSURE_MIN 1 #define IMX355_EXPOSURE_STEP 1 #define IMX355_EXPOSURE_DEFAULT 0x0282 +#define IMX355_EXPOSURE_OFFSET 10 /* Analog gain control */ -#define IMX355_REG_ANALOG_GAIN 0x0204 +#define IMX355_REG_ANALOG_GAIN CCI_REG16(0x0204) #define IMX355_ANA_GAIN_MIN 0 #define IMX355_ANA_GAIN_MAX 960 #define IMX355_ANA_GAIN_STEP 1 #define IMX355_ANA_GAIN_DEFAULT 0 /* Digital gain control */ -#define IMX355_REG_DPGA_USE_GLOBAL_GAIN 0x3070 -#define IMX355_REG_DIG_GAIN_GLOBAL 0x020e +#define IMX355_REG_DPGA_USE_GLOBAL_GAIN CCI_REG8(0x3070) +#define IMX355_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e) #define IMX355_DGTL_GAIN_MIN 256 #define IMX355_DGTL_GAIN_MAX 4095 #define IMX355_DGTL_GAIN_STEP 1 #define IMX355_DGTL_GAIN_DEFAULT 256 /* Test Pattern Control */ -#define IMX355_REG_TEST_PATTERN 0x0600 +#define IMX355_REG_TEST_PATTERN CCI_REG16(0x0600) #define IMX355_TEST_PATTERN_DISABLED 0 #define IMX355_TEST_PATTERN_SOLID_COLOR 1 #define IMX355_TEST_PATTERN_COLOR_BARS 2 #define IMX355_TEST_PATTERN_GRAY_COLOR_BARS 3 #define IMX355_TEST_PATTERN_PN9 4 -/* Flip Control */ -#define IMX355_REG_ORIENTATION 0x0101 +#define IMX355_REG_REQ_LINK_BIT_RATE CCI_REG16(0x0820) -/* default link frequency and external clock */ -#define IMX355_LINK_FREQ_DEFAULT 360000000LL -#define IMX355_EXT_CLK 19200000 -#define IMX355_LINK_FREQ_INDEX 0 +#define IMX355_REG_BINNING_MODE CCI_REG8(0x0900) +#define IMX355_REG_BINNING_TYPE CCI_REG8(0x0901) +#define IMX355_REG_BINNING_WEIGHTING CCI_REG8(0x0902) -/* number of data lanes */ -#define IMX355_DATA_LANES 4 +/* Flip Control */ +#define IMX355_REG_ORIENTATION CCI_REG8(0x0101) -struct imx355_reg { - u16 address; - u8 val; -}; +#define IMX355_PIXEL_ARRAY_TOP 0 +#define IMX355_PIXEL_ARRAY_LEFT 0 +#define IMX355_PIXEL_ARRAY_WIDTH 3280 +#define IMX355_PIXEL_ARRAY_HEIGHT 2464 struct imx355_reg_list { u32 num_of_regs; - const struct imx355_reg *regs; + const struct cci_reg_sequence *regs; }; /* Mode : resolution and related config&values */ @@ -85,28 +108,58 @@ struct imx355_mode { u32 width; /* Frame height */ u32 height; + struct v4l2_rect crop; /* V-timing */ u32 fll_def; - u32 fll_min; /* H-timing */ u32 llp; - /* index of link frequency */ - u32 link_freq_index; - /* Default register values */ struct imx355_reg_list reg_list; }; +struct imx355_clk_params { + u32 ext_clk; + u16 extclk_freq; /* External clock (MHz) in 8.8 fixed point) */ + u16 pll_op_mpy[2]; /* OP system PLL multiplier */ + u8 pll_op_prediv[2]; /* OP system pre PLL d */ +}; + +/* + * The clock tree is in single PLL mode, so PREDIV_VT and MPY_IVT do nothing. + * In 4 lane mode the MIPI rate is 360Mhz (720Mbit/s) and pixel rate is + * 288MPix/s. + * In 2 lane mode the MIPI rate is 444MHz (888Mbit/s) and pixel rate + * 177.6MPix/s with a 24MHz clock, and 441.6MHz (883.2Mbit/s) and 176.6MPix/s + * with a 19.2MHz clock. + */ +static const struct imx355_clk_params imx355_clk_params[] = { + { + .ext_clk = 19200000, + .extclk_freq = 0x1333, + .pll_op_mpy = { 75, 92 }, + .pll_op_prediv = { 2, 2 } + }, + { + .ext_clk = 24000000, + .extclk_freq = 0x1800, + .pll_op_mpy = { 60, 111 }, + .pll_op_prediv = { 2, 3 } + }, +}; + struct imx355_hwcfg { + s64 link_freq_menu; unsigned long link_freq_bitmap; + unsigned int num_lanes; }; struct imx355 { struct device *dev; struct clk *clk; + struct regmap *regmap; struct v4l2_subdev sd; struct media_pad pad; @@ -114,24 +167,14 @@ struct imx355 { struct v4l2_ctrl_handler ctrl_handler; /* V4L2 Controls */ struct v4l2_ctrl *link_freq; - struct v4l2_ctrl *pixel_rate; struct v4l2_ctrl *vblank; struct v4l2_ctrl *hblank; struct v4l2_ctrl *exposure; struct v4l2_ctrl *vflip; struct v4l2_ctrl *hflip; - /* Current mode */ - const struct imx355_mode *cur_mode; - struct imx355_hwcfg *hwcfg; - - /* - * Mutex for serialized access: - * Protect sensor set pad format and start/stop streaming safely. - * Protect access to sensor v4l2 controls. - */ - struct mutex mutex; + const struct imx355_clk_params *clk_params; struct gpio_desc *reset_gpio; struct regulator_bulk_data *supplies; @@ -143,750 +186,147 @@ static const struct regulator_bulk_data imx355_supplies[] = { { .supply = "dovdd" }, }; -static const struct imx355_reg imx355_global_regs[] = { - { 0x0136, 0x13 }, - { 0x0137, 0x33 }, - { 0x304e, 0x03 }, - { 0x4348, 0x16 }, - { 0x4350, 0x19 }, - { 0x4408, 0x0a }, - { 0x440c, 0x0b }, - { 0x4411, 0x5f }, - { 0x4412, 0x2c }, - { 0x4623, 0x00 }, - { 0x462c, 0x0f }, - { 0x462d, 0x00 }, - { 0x462e, 0x00 }, - { 0x4684, 0x54 }, - { 0x480a, 0x07 }, - { 0x4908, 0x07 }, - { 0x4909, 0x07 }, - { 0x490d, 0x0a }, - { 0x491e, 0x0f }, - { 0x4921, 0x06 }, - { 0x4923, 0x28 }, - { 0x4924, 0x28 }, - { 0x4925, 0x29 }, - { 0x4926, 0x29 }, - { 0x4927, 0x1f }, - { 0x4928, 0x20 }, - { 0x4929, 0x20 }, - { 0x492a, 0x20 }, - { 0x492c, 0x05 }, - { 0x492d, 0x06 }, - { 0x492e, 0x06 }, - { 0x492f, 0x06 }, - { 0x4930, 0x03 }, - { 0x4931, 0x04 }, - { 0x4932, 0x04 }, - { 0x4933, 0x05 }, - { 0x595e, 0x01 }, - { 0x5963, 0x01 }, - { 0x3030, 0x01 }, - { 0x3031, 0x01 }, - { 0x3045, 0x01 }, - { 0x4010, 0x00 }, - { 0x4011, 0x00 }, - { 0x4012, 0x00 }, - { 0x4013, 0x01 }, - { 0x68a8, 0xfe }, - { 0x68a9, 0xff }, - { 0x6888, 0x00 }, - { 0x6889, 0x00 }, - { 0x68b0, 0x00 }, - { 0x3058, 0x00 }, - { 0x305a, 0x00 }, -}; - -static const struct imx355_reg_list imx355_global_setting = { - .num_of_regs = ARRAY_SIZE(imx355_global_regs), - .regs = imx355_global_regs, +static const struct cci_reg_sequence imx355_global_regs[] = { + { CCI_REG8(0x304e), 0x03 }, + { CCI_REG8(0x4348), 0x16 }, + { CCI_REG8(0x4350), 0x19 }, + { CCI_REG8(0x4408), 0x0a }, + { CCI_REG8(0x440c), 0x0b }, + { CCI_REG8(0x4411), 0x5f }, + { CCI_REG8(0x4412), 0x2c }, + { CCI_REG8(0x4623), 0x00 }, + { CCI_REG8(0x462c), 0x0f }, + { CCI_REG8(0x462d), 0x00 }, + { CCI_REG8(0x462e), 0x00 }, + { CCI_REG8(0x4684), 0x54 }, + { CCI_REG8(0x480a), 0x07 }, + { CCI_REG8(0x4908), 0x07 }, + { CCI_REG8(0x4909), 0x07 }, + { CCI_REG8(0x490d), 0x0a }, + { CCI_REG8(0x491e), 0x0f }, + { CCI_REG8(0x4921), 0x06 }, + { CCI_REG8(0x4923), 0x28 }, + { CCI_REG8(0x4924), 0x28 }, + { CCI_REG8(0x4925), 0x29 }, + { CCI_REG8(0x4926), 0x29 }, + { CCI_REG8(0x4927), 0x1f }, + { CCI_REG8(0x4928), 0x20 }, + { CCI_REG8(0x4929), 0x20 }, + { CCI_REG8(0x492a), 0x20 }, + { CCI_REG8(0x492c), 0x05 }, + { CCI_REG8(0x492d), 0x06 }, + { CCI_REG8(0x492e), 0x06 }, + { CCI_REG8(0x492f), 0x06 }, + { CCI_REG8(0x4930), 0x03 }, + { CCI_REG8(0x4931), 0x04 }, + { CCI_REG8(0x4932), 0x04 }, + { CCI_REG8(0x4933), 0x05 }, + { CCI_REG8(0x595e), 0x01 }, + { CCI_REG8(0x5963), 0x01 }, + { CCI_REG8(0x3030), 0x01 }, + { CCI_REG8(0x3031), 0x01 }, + { CCI_REG8(0x3045), 0x01 }, + { CCI_REG8(0x4010), 0x00 }, + { CCI_REG8(0x4011), 0x00 }, + { CCI_REG8(0x4012), 0x00 }, + { CCI_REG8(0x4013), 0x01 }, + { CCI_REG8(0x68a8), 0xfe }, + { CCI_REG8(0x68a9), 0xff }, + { CCI_REG8(0x6888), 0x00 }, + { CCI_REG8(0x6889), 0x00 }, + { CCI_REG8(0x68b0), 0x00 }, + { CCI_REG8(0x3058), 0x00 }, + { CCI_REG8(0x305a), 0x00 }, + { CCI_REG8(0x0112), 0x0a }, + { CCI_REG8(0x0113), 0x0a }, + { IMX355_REG_PLL_IVT_PCK_DIV, IMX355_PLL_IVT_PCK_DIV }, + { CCI_REG8(0x0303), 0x01 }, + { CCI_REG8(0x0305), 0x02 }, + { CCI_REG8(0x0306), 0x00 }, + { CCI_REG8(0x0307), 0x78 }, + { CCI_REG8(0x030b), 0x01 }, + { IMX355_REG_PLL_OP_PREDIV, IMX355_PLL_OP_PREDIV }, + { CCI_REG8(0x0310), 0x00 }, + { CCI_REG8(0x0220), 0x00 }, + { CCI_REG8(0x0222), 0x01 }, + { CCI_REG8(0x3088), 0x04 }, + { CCI_REG8(0x6813), 0x02 }, + { CCI_REG8(0x6835), 0x07 }, + { CCI_REG8(0x6836), 0x01 }, + { CCI_REG8(0x6837), 0x04 }, + { CCI_REG8(0x684d), 0x07 }, + { CCI_REG8(0x684e), 0x01 }, + { CCI_REG8(0x684f), 0x04 }, }; -static const struct imx355_reg mode_3268x2448_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x0a }, - { 0x0341, 0x37 }, - { 0x0344, 0x00 }, - { 0x0345, 0x08 }, - { 0x0346, 0x00 }, - { 0x0347, 0x08 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcb }, - { 0x034a, 0x09 }, - { 0x034b, 0x97 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x0c }, - { 0x034d, 0xc4 }, - { 0x034e, 0x09 }, - { 0x034f, 0x90 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_3268x2448_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_3264x2448_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x0a }, - { 0x0341, 0x37 }, - { 0x0344, 0x00 }, - { 0x0345, 0x08 }, - { 0x0346, 0x00 }, - { 0x0347, 0x08 }, - { 0x0348, 0x0c }, - { 0x0349, 0xc7 }, - { 0x034a, 0x09 }, - { 0x034b, 0x97 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x0c }, - { 0x034d, 0xc0 }, - { 0x034e, 0x09 }, - { 0x034f, 0x90 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_3264x2448_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_3280x2464_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x0a }, - { 0x0341, 0x37 }, - { 0x0344, 0x00 }, - { 0x0345, 0x00 }, - { 0x0346, 0x00 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcf }, - { 0x034a, 0x09 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x0c }, - { 0x034d, 0xd0 }, - { 0x034e, 0x09 }, - { 0x034f, 0xa0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_3280x2464_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1940x1096_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x02 }, - { 0x0345, 0xa0 }, - { 0x0346, 0x02 }, - { 0x0347, 0xac }, - { 0x0348, 0x0a }, - { 0x0349, 0x33 }, - { 0x034a, 0x06 }, - { 0x034b, 0xf3 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x07 }, - { 0x034d, 0x94 }, - { 0x034e, 0x04 }, - { 0x034f, 0x48 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1940x1096_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1936x1096_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x02 }, - { 0x0345, 0xa0 }, - { 0x0346, 0x02 }, - { 0x0347, 0xac }, - { 0x0348, 0x0a }, - { 0x0349, 0x2f }, - { 0x034a, 0x06 }, - { 0x034b, 0xf3 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x07 }, - { 0x034d, 0x90 }, - { 0x034e, 0x04 }, - { 0x034f, 0x48 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1936x1096_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1924x1080_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x02 }, - { 0x0345, 0xa8 }, - { 0x0346, 0x02 }, - { 0x0347, 0xb4 }, - { 0x0348, 0x0a }, - { 0x0349, 0x2b }, - { 0x034a, 0x06 }, - { 0x034b, 0xeb }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x07 }, - { 0x034d, 0x84 }, - { 0x034e, 0x04 }, - { 0x034f, 0x38 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1924x1080_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1920x1080_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x02 }, - { 0x0345, 0xa8 }, - { 0x0346, 0x02 }, - { 0x0347, 0xb4 }, - { 0x0348, 0x0a }, - { 0x0349, 0x27 }, - { 0x034a, 0x06 }, - { 0x034b, 0xeb }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x00 }, - { 0x0901, 0x11 }, - { 0x0902, 0x00 }, - { 0x034c, 0x07 }, - { 0x034d, 0x80 }, - { 0x034e, 0x04 }, - { 0x034f, 0x38 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1920x1080_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1640x1232_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x00 }, - { 0x0345, 0x00 }, - { 0x0346, 0x00 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcf }, - { 0x034a, 0x09 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x06 }, - { 0x034d, 0x68 }, - { 0x034e, 0x04 }, - { 0x034f, 0xd0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1640x1232_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1640x922_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x00 }, - { 0x0345, 0x00 }, - { 0x0346, 0x01 }, - { 0x0347, 0x30 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcf }, - { 0x034a, 0x08 }, - { 0x034b, 0x63 }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x06 }, - { 0x034d, 0x68 }, - { 0x034e, 0x03 }, - { 0x034f, 0x9a }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1640x922_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1300x736_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x01 }, - { 0x0345, 0x58 }, - { 0x0346, 0x01 }, - { 0x0347, 0xf0 }, - { 0x0348, 0x0b }, - { 0x0349, 0x7f }, - { 0x034a, 0x07 }, - { 0x034b, 0xaf }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x05 }, - { 0x034d, 0x14 }, - { 0x034e, 0x02 }, - { 0x034f, 0xe0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1300x736_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1296x736_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x01 }, - { 0x0345, 0x58 }, - { 0x0346, 0x01 }, - { 0x0347, 0xf0 }, - { 0x0348, 0x0b }, - { 0x0349, 0x77 }, - { 0x034a, 0x07 }, - { 0x034b, 0xaf }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x05 }, - { 0x034d, 0x10 }, - { 0x034e, 0x02 }, - { 0x034f, 0xe0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1296x736_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1284x720_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x01 }, - { 0x0345, 0x68 }, - { 0x0346, 0x02 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0b }, - { 0x0349, 0x6f }, - { 0x034a, 0x07 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x05 }, - { 0x034d, 0x04 }, - { 0x034e, 0x02 }, - { 0x034f, 0xd0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1284x720_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_1280x720_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x07 }, - { 0x0343, 0x2c }, - { 0x0340, 0x05 }, - { 0x0341, 0x1a }, - { 0x0344, 0x01 }, - { 0x0345, 0x68 }, - { 0x0346, 0x02 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0b }, - { 0x0349, 0x67 }, - { 0x034a, 0x07 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x22 }, - { 0x0902, 0x00 }, - { 0x034c, 0x05 }, - { 0x034d, 0x00 }, - { 0x034e, 0x02 }, - { 0x034f, 0xd0 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x00 }, - { 0x0701, 0x10 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_1280x720_regs[] = { + { CCI_REG8(0x0700), 0x00 }, + { CCI_REG8(0x0701), 0x10 }, }; -static const struct imx355_reg mode_820x616_regs[] = { - { 0x0112, 0x0a }, - { 0x0113, 0x0a }, - { 0x0114, 0x03 }, - { 0x0342, 0x0e }, - { 0x0343, 0x58 }, - { 0x0340, 0x02 }, - { 0x0341, 0x8c }, - { 0x0344, 0x00 }, - { 0x0345, 0x00 }, - { 0x0346, 0x00 }, - { 0x0347, 0x00 }, - { 0x0348, 0x0c }, - { 0x0349, 0xcf }, - { 0x034a, 0x09 }, - { 0x034b, 0x9f }, - { 0x0220, 0x00 }, - { 0x0222, 0x01 }, - { 0x0900, 0x01 }, - { 0x0901, 0x44 }, - { 0x0902, 0x00 }, - { 0x034c, 0x03 }, - { 0x034d, 0x34 }, - { 0x034e, 0x02 }, - { 0x034f, 0x68 }, - { 0x0301, 0x05 }, - { 0x0303, 0x01 }, - { 0x0305, 0x02 }, - { 0x0306, 0x00 }, - { 0x0307, 0x78 }, - { 0x030b, 0x01 }, - { 0x030d, 0x02 }, - { 0x030e, 0x00 }, - { 0x030f, 0x4b }, - { 0x0310, 0x00 }, - { 0x0700, 0x02 }, - { 0x0701, 0x78 }, - { 0x0820, 0x0b }, - { 0x0821, 0x40 }, - { 0x3088, 0x04 }, - { 0x6813, 0x02 }, - { 0x6835, 0x07 }, - { 0x6836, 0x01 }, - { 0x6837, 0x04 }, - { 0x684d, 0x07 }, - { 0x684e, 0x01 }, - { 0x684f, 0x04 }, +static const struct cci_reg_sequence mode_820x616_regs[] = { + { CCI_REG8(0x0700), 0x02 }, + { CCI_REG8(0x0701), 0x78 }, }; static const char * const imx355_test_pattern_menu[] = { @@ -897,23 +337,19 @@ static const char * const imx355_test_pattern_menu[] = { "Pseudorandom Sequence (PN9)", }; -/* - * When adding more than the one below, make sure the disallowed ones will - * actually be disabled in the LINK_FREQ control. - */ -static const s64 link_freq_menu_items[] = { - IMX355_LINK_FREQ_DEFAULT, -}; - /* Mode configs */ static const struct imx355_mode supported_modes[] = { { .width = 3280, .height = 2464, + .crop = { + .width = 3280, + .height = 2464, + .left = 0, + .top = 0, + }, .fll_def = 2615, - .fll_min = 2615, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_3280x2464_regs), .regs = mode_3280x2464_regs, @@ -922,10 +358,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 3268, .height = 2448, + .crop = { + .width = 3268, + .height = 2448, + .left = 8, + .top = 8, + }, .fll_def = 2615, - .fll_min = 2615, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_3268x2448_regs), .regs = mode_3268x2448_regs, @@ -934,10 +374,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 3264, .height = 2448, + .crop = { + .width = 3264, + .height = 2448, + .left = 8, + .top = 8, + }, .fll_def = 2615, - .fll_min = 2615, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs), .regs = mode_3264x2448_regs, @@ -946,10 +390,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1940, .height = 1096, + .crop = { + .width = 1940, + .height = 1096, + .left = 672, + .top = 684, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1940x1096_regs), .regs = mode_1940x1096_regs, @@ -958,10 +406,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1936, .height = 1096, + .crop = { + .width = 1936, + .height = 1096, + .left = 672, + .top = 684, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1936x1096_regs), .regs = mode_1936x1096_regs, @@ -970,10 +422,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1924, .height = 1080, + .crop = { + .width = 1924, + .height = 1080, + .left = 680, + .top = 692, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1924x1080_regs), .regs = mode_1924x1080_regs, @@ -982,10 +438,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1920, .height = 1080, + .crop = { + .width = 1920, + .height = 1080, + .left = 680, + .top = 692, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1920x1080_regs), .regs = mode_1920x1080_regs, @@ -994,10 +454,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1640, .height = 1232, + .crop = { + .width = 3280, + .height = 2464, + .left = 0, + .top = 0, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1640x1232_regs), .regs = mode_1640x1232_regs, @@ -1006,10 +470,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1640, .height = 922, + .crop = { + .width = 3280, + .height = 1844, + .left = 0, + .top = 304, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1640x922_regs), .regs = mode_1640x922_regs, @@ -1018,10 +486,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1300, .height = 736, + .crop = { + .width = 2600, + .height = 1472, + .left = 344, + .top = 496, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1300x736_regs), .regs = mode_1300x736_regs, @@ -1030,10 +502,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1296, .height = 736, + .crop = { + .width = 2592, + .height = 1472, + .left = 344, + .top = 496, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1296x736_regs), .regs = mode_1296x736_regs, @@ -1042,10 +518,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1284, .height = 720, + .crop = { + .width = 2568, + .height = 1440, + .left = 360, + .top = 512, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1284x720_regs), .regs = mode_1284x720_regs, @@ -1054,10 +534,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 1280, .height = 720, + .crop = { + .width = 2560, + .height = 1440, + .left = 360, + .top = 512, + }, .fll_def = 1306, - .fll_min = 1306, .llp = 1836, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), .regs = mode_1280x720_regs, @@ -1066,10 +550,14 @@ static const struct imx355_mode supported_modes[] = { { .width = 820, .height = 616, + .crop = { + .width = 3280, + .height = 2464, + .left = 0, + .top = 0, + }, .fll_def = 652, - .fll_min = 652, .llp = 3672, - .link_freq_index = IMX355_LINK_FREQ_INDEX, .reg_list = { .num_of_regs = ARRAY_SIZE(mode_820x616_regs), .regs = mode_820x616_regs, @@ -1095,116 +583,28 @@ static u32 imx355_get_format_code(struct imx355 *imx355) { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, }, }; - lockdep_assert_held(&imx355->mutex); code = codes[imx355->vflip->val][imx355->hflip->val]; return code; } -/* Read registers up to 4 at a time */ -static int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); - struct i2c_msg msgs[2]; - u8 addr_buf[2]; - u8 data_buf[4] = { 0 }; - int ret; - - if (len > 4) - return -EINVAL; - - put_unaligned_be16(reg, addr_buf); - /* Write register address */ - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = ARRAY_SIZE(addr_buf); - msgs[0].buf = addr_buf; - - /* Read data from register */ - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = &data_buf[4 - len]; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) - return -EIO; - - *val = get_unaligned_be32(data_buf); - - return 0; -} - -/* Write registers up to 4 at a time */ -static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); - u8 buf[6]; - - if (len > 4) - return -EINVAL; - - put_unaligned_be16(reg, buf); - put_unaligned_be32(val << (8 * (4 - len)), buf + 2); - if (i2c_master_send(client, buf, len + 2) != len + 2) - return -EIO; - - return 0; -} - -/* Write a list of registers */ -static int imx355_write_regs(struct imx355 *imx355, - const struct imx355_reg *regs, u32 len) -{ - int ret; - u32 i; - - for (i = 0; i < len; i++) { - ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val); - if (ret) { - dev_err_ratelimited(imx355->dev, - "write reg 0x%4.4x return err %d", - regs[i].address, ret); - - return ret; - } - } - - return 0; -} - -/* Open sub-device */ -static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - struct imx355 *imx355 = to_imx355(sd); - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_state_get_format(fh->state, 0); - - mutex_lock(&imx355->mutex); - - /* Initialize try_fmt */ - try_fmt->width = imx355->cur_mode->width; - try_fmt->height = imx355->cur_mode->height; - try_fmt->code = imx355_get_format_code(imx355); - try_fmt->field = V4L2_FIELD_NONE; - - mutex_unlock(&imx355->mutex); - - return 0; -} - static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx355 *imx355 = container_of(ctrl->handler, struct imx355, ctrl_handler); + const struct v4l2_mbus_framefmt *format = NULL; + struct v4l2_subdev_state *state; s64 max; int ret; + state = v4l2_subdev_get_locked_active_state(&imx355->sd); + format = v4l2_subdev_state_get_format(state, 0); + /* Propagate change of current control to all related controls */ switch (ctrl->id) { case V4L2_CID_VBLANK: /* Update max exposure while meeting expected vblanking */ - max = imx355->cur_mode->height + ctrl->val - 10; + max = format->height + ctrl->val - IMX355_EXPOSURE_OFFSET; __v4l2_ctrl_modify_range(imx355->exposure, imx355->exposure->minimum, max, imx355->exposure->step, max); @@ -1221,31 +621,31 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_ANALOGUE_GAIN: /* Analog gain = 1024/(1024 - ctrl->val) times */ - ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2, - ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_ANALOG_GAIN, + ctrl->val, NULL); break; case V4L2_CID_DIGITAL_GAIN: - ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2, - ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_DIG_GAIN_GLOBAL, + ctrl->val, NULL); break; case V4L2_CID_EXPOSURE: - ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2, - ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_EXPOSURE, + ctrl->val, NULL); break; case V4L2_CID_VBLANK: /* Update FLL that meets expected vertical blanking */ - ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2, - imx355->cur_mode->height + ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_FLL, + format->height + ctrl->val, NULL); break; case V4L2_CID_TEST_PATTERN: - ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN, - 2, ctrl->val); + ret = cci_write(imx355->regmap, IMX355_REG_TEST_PATTERN, + ctrl->val, NULL); break; case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: - ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1, - imx355->hflip->val | - imx355->vflip->val << 1); + ret = cci_write(imx355->regmap, IMX355_REG_ORIENTATION, + imx355->hflip->val | imx355->vflip->val << 1, + NULL); break; default: ret = -EINVAL; @@ -1272,9 +672,7 @@ static int imx355_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - mutex_lock(&imx355->mutex); code->code = imx355_get_format_code(imx355); - mutex_unlock(&imx355->mutex); return 0; } @@ -1288,12 +686,9 @@ static int imx355_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; - mutex_lock(&imx355->mutex); if (fse->code != imx355_get_format_code(imx355)) { - mutex_unlock(&imx355->mutex); return -EINVAL; } - mutex_unlock(&imx355->mutex); fse->min_width = supported_modes[fse->index].width; fse->max_width = fse->min_width; @@ -1311,36 +706,10 @@ static void imx355_update_pad_format(struct imx355 *imx355, fmt->format.height = mode->height; fmt->format.code = imx355_get_format_code(imx355); fmt->format.field = V4L2_FIELD_NONE; -} - -static int imx355_do_get_pad_format(struct imx355 *imx355, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct v4l2_mbus_framefmt *framefmt; - - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); - fmt->format = *framefmt; - } else { - imx355_update_pad_format(imx355, imx355->cur_mode, fmt); - } - - return 0; -} - -static int imx355_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *fmt) -{ - struct imx355 *imx355 = to_imx355(sd); - int ret; - - mutex_lock(&imx355->mutex); - ret = imx355_do_get_pad_format(imx355, sd_state, fmt); - mutex_unlock(&imx355->mutex); - - return ret; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601; + fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; } static int @@ -1351,13 +720,8 @@ imx355_set_pad_format(struct v4l2_subdev *sd, struct imx355 *imx355 = to_imx355(sd); const struct imx355_mode *mode; struct v4l2_mbus_framefmt *framefmt; - s32 vblank_def; - s32 vblank_min; + struct v4l2_rect *crop; s64 h_blank; - u64 pixel_rate; - u32 height; - - mutex_lock(&imx355->mutex); /* * Only one bayer order is supported. @@ -1370,23 +734,25 @@ imx355_set_pad_format(struct v4l2_subdev *sd, width, height, fmt->format.width, fmt->format.height); imx355_update_pad_format(imx355, mode, fmt); - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); - *framefmt = fmt->format; - } else { - imx355->cur_mode = mode; - pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; - do_div(pixel_rate, 10); - __v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate); + framefmt = v4l2_subdev_state_get_format(sd_state, 0); + + *framefmt = fmt->format; + + crop = v4l2_subdev_state_get_crop(sd_state, 0); + crop->width = mode->crop.width; + crop->height = mode->crop.height; + crop->left = mode->crop.left; + crop->top = mode->crop.top; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Update limits and set FPS to default */ - height = imx355->cur_mode->height; - vblank_def = imx355->cur_mode->fll_def - height; - vblank_min = imx355->cur_mode->fll_min - height; - height = IMX355_FLL_MAX - height; - __v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1, - vblank_def); - __v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def); - h_blank = mode->llp - imx355->cur_mode->width; + __v4l2_ctrl_modify_range(imx355->vblank, IMX355_VBLANK_MIN, + IMX355_FLL_MAX - mode->height, 1, + mode->fll_def - mode->height); + __v4l2_ctrl_s_ctrl(imx355->vblank, mode->fll_def - mode->height); + + h_blank = mode->llp - mode->width; + /* * Currently hblank is not changeable. * So FPS control is done only by vblank. @@ -1395,7 +761,42 @@ imx355_set_pad_format(struct v4l2_subdev *sd, h_blank, 1, h_blank); } - mutex_unlock(&imx355->mutex); + return 0; +} + +static int imx355_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = IMX355_PIXEL_ARRAY_TOP; + sel->r.left = IMX355_PIXEL_ARRAY_LEFT; + sel->r.width = IMX355_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX355_PIXEL_ARRAY_HEIGHT; + + return 0; + } + + return -EINVAL; +} + +static int imx355_entity_init_state(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_subdev_format fmt = { }; + + fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.format.code = MEDIA_BUS_FMT_SRGGB10_1X10; + fmt.format.width = supported_modes[0].width; + fmt.format.height = supported_modes[0].height; + + imx355_set_pad_format(subdev, sd_state, &fmt); return 0; } @@ -1403,52 +804,98 @@ imx355_set_pad_format(struct v4l2_subdev *sd, /* Start streaming */ static int imx355_start_streaming(struct imx355 *imx355) { - const struct imx355_reg_list *reg_list; - int ret; + const struct v4l2_mbus_framefmt *fmt; + struct v4l2_subdev_state *state; + const struct imx355_mode *mode; + int lane_idx = imx355->hwcfg->num_lanes == 4 ? 0 : 1; + struct v4l2_rect *crop; + u64 link_bitrate; + u8 binning_mode; + int ret = 0; /* Global Setting */ - reg_list = &imx355_global_setting; - ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); - if (ret) { - dev_err(imx355->dev, "failed to set global settings"); - return ret; - } + cci_multi_reg_write(imx355->regmap, imx355_global_regs, + ARRAY_SIZE(imx355_global_regs), &ret); - /* Apply default values of current mode */ - reg_list = &imx355->cur_mode->reg_list; - ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); - if (ret) { - dev_err(imx355->dev, "failed to set mode"); - return ret; - } + /* Apply values of current mode */ + state = v4l2_subdev_get_locked_active_state(&imx355->sd); + fmt = v4l2_subdev_state_get_format(state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, fmt->width, fmt->height); + cci_multi_reg_write(imx355->regmap, mode->reg_list.regs, + mode->reg_list.num_of_regs, &ret); + + /* Set readout crop and size registers */ + cci_write(imx355->regmap, IMX355_REG_X_ADD_START, crop->left, + &ret); + cci_write(imx355->regmap, IMX355_REG_Y_ADD_START, crop->top, &ret); + cci_write(imx355->regmap, IMX355_REG_X_ADD_END, + crop->width + crop->left - 1, &ret); + cci_write(imx355->regmap, IMX355_REG_Y_ADD_END, + crop->height + crop->top - 1, &ret); + cci_write(imx355->regmap, IMX355_REG_X_OUT_SIZE, fmt->width, &ret); + cci_write(imx355->regmap, IMX355_REG_Y_OUT_SIZE, fmt->height, &ret); + + binning_mode = ((crop->width / fmt->width) << 4) | + (crop->height / fmt->height); + cci_write(imx355->regmap, IMX355_REG_BINNING_MODE, + binning_mode == 0x11 ? 0x00 : 0x01, &ret); + cci_write(imx355->regmap, IMX355_REG_BINNING_TYPE, binning_mode, &ret); + cci_write(imx355->regmap, IMX355_REG_BINNING_WEIGHTING, 0x00, &ret); + + /* Set PLL registers for the external clock frequency */ + cci_write(imx355->regmap, IMX355_REG_EXTCLK_FREQ, + imx355->clk_params->extclk_freq, &ret); + cci_write(imx355->regmap, IMX355_REG_PLL_OP_MUL, + imx355->clk_params->pll_op_mpy[lane_idx], &ret); + cci_write(imx355->regmap, IMX355_REG_PLL_OP_PREDIV, + imx355->clk_params->pll_op_prediv[lane_idx], &ret); + cci_write(imx355->regmap, IMX355_REG_PLL_IVT_SYSCK_DIV, + lane_idx ? 2 : 1, &ret); + + /* Set MIPI configuration */ + cci_write(imx355->regmap, IMX355_REG_LANE_SEL, + imx355->hwcfg->num_lanes - 1, &ret); + + link_bitrate = imx355->link_freq->qmenu_int[imx355->link_freq->val] * + imx355->hwcfg->num_lanes * 2; + do_div(link_bitrate, 1000000); + cci_write(imx355->regmap, IMX355_REG_REQ_LINK_BIT_RATE, link_bitrate, + &ret); /* set digital gain control to all color mode */ - ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1); - if (ret) - return ret; + cci_write(imx355->regmap, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, &ret); + + /* set line length */ + cci_write(imx355->regmap, IMX355_REG_LLP, + imx355->hblank->val + fmt->width, &ret); /* Apply customized values from user */ - ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler); - if (ret) - return ret; + if (!ret) + ret = __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler); + + cci_write(imx355->regmap, IMX355_REG_MODE_SELECT, IMX355_MODE_STREAMING, + &ret); - return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, - 1, IMX355_MODE_STREAMING); + return ret; } /* Stop streaming */ static int imx355_stop_streaming(struct imx355 *imx355) { - return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT, - 1, IMX355_MODE_STANDBY); + return cci_write(imx355->regmap, IMX355_REG_MODE_SELECT, + IMX355_MODE_STANDBY, NULL); } static int imx355_set_stream(struct v4l2_subdev *sd, int enable) { struct imx355 *imx355 = to_imx355(sd); + struct v4l2_subdev_state *state; int ret = 0; - mutex_lock(&imx355->mutex); + state = v4l2_subdev_lock_and_get_active_state(sd); if (enable) { ret = pm_runtime_resume_and_get(imx355->dev); @@ -1464,21 +911,21 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx355_stop_streaming(imx355); - pm_runtime_put(imx355->dev); + pm_runtime_put_autosuspend(imx355->dev); } /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(imx355->vflip, enable); __v4l2_ctrl_grab(imx355->hflip, enable); - mutex_unlock(&imx355->mutex); + v4l2_subdev_unlock_state(state); return ret; err_rpm_put: - pm_runtime_put(imx355->dev); + pm_runtime_put_autosuspend(imx355->dev); err_unlock: - mutex_unlock(&imx355->mutex); + v4l2_subdev_unlock_state(state); return ret; } @@ -1487,14 +934,14 @@ err_unlock: static int imx355_identify_module(struct imx355 *imx355) { int ret; - u32 val; + u64 val; - ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val); + ret = cci_read(imx355->regmap, IMX355_REG_CHIP_ID, &val, NULL); if (ret) return ret; if (val != IMX355_CHIP_ID) { - dev_err(imx355->dev, "chip id mismatch: %x!=%x", + dev_err(imx355->dev, "chip id mismatch: %x!=%llx", IMX355_CHIP_ID, val); return -EIO; } @@ -1512,9 +959,10 @@ static const struct v4l2_subdev_video_ops imx355_video_ops = { static const struct v4l2_subdev_pad_ops imx355_pad_ops = { .enum_mbus_code = imx355_enum_mbus_code, - .get_fmt = imx355_get_pad_format, + .get_fmt = v4l2_subdev_get_fmt, .set_fmt = imx355_set_pad_format, .enum_frame_size = imx355_enum_frame_size, + .get_selection = imx355_get_selection, }; static const struct v4l2_subdev_ops imx355_subdev_ops = { @@ -1528,7 +976,7 @@ static const struct media_entity_operations imx355_subdev_entity_ops = { }; static const struct v4l2_subdev_internal_ops imx355_internal_ops = { - .open = imx355_open, + .init_state = imx355_entity_init_state, }; static int imx355_power_off(struct device *dev) @@ -1582,13 +1030,11 @@ static int imx355_init_controls(struct imx355 *imx355) { struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; + const struct imx355_mode *mode = &supported_modes[0]; s64 exposure_max; s64 vblank_def; - s64 vblank_min; s64 hblank; u64 pixel_rate; - const struct imx355_mode *mode; - u32 max; int ret; ctrl_hdlr = &imx355->ctrl_handler; @@ -1596,40 +1042,34 @@ static int imx355_init_controls(struct imx355 *imx355) if (ret) return ret; - ctrl_hdlr->lock = &imx355->mutex; - max = ARRAY_SIZE(link_freq_menu_items) - 1; imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops, - V4L2_CID_LINK_FREQ, max, 0, - link_freq_menu_items); + V4L2_CID_LINK_FREQ, 0, 0, + &imx355->hwcfg->link_freq_menu); if (imx355->link_freq) imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; + pixel_rate = imx355->hwcfg->link_freq_menu * 2 * imx355->hwcfg->num_lanes; do_div(pixel_rate, 10); - /* By default, PIXEL_RATE is read only */ - imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, - V4L2_CID_PIXEL_RATE, pixel_rate, - pixel_rate, 1, pixel_rate); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_PIXEL_RATE, + pixel_rate, pixel_rate, 1, pixel_rate); /* Initialize vblank/hblank/exposure parameters based on current mode */ - mode = imx355->cur_mode; vblank_def = mode->fll_def - mode->height; - vblank_min = mode->fll_min - mode->height; imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, - V4L2_CID_VBLANK, vblank_min, + V4L2_CID_VBLANK, IMX355_VBLANK_MIN, IMX355_FLL_MAX - mode->height, 1, vblank_def); hblank = mode->llp - mode->width; - imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, - V4L2_CID_HBLANK, hblank, hblank, - 1, hblank); + imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_HBLANK, + hblank, hblank, 1, hblank); if (imx355->hblank) imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* fll >= exposure time + adjust parameter (default value is 10) */ - exposure_max = mode->fll_def - 10; + exposure_max = mode->fll_def - IMX355_EXPOSURE_OFFSET; imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_EXPOSURE, IMX355_EXPOSURE_MIN, exposure_max, @@ -1683,14 +1123,17 @@ error: return ret; } -static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) +static struct imx355_hwcfg *imx355_get_hwcfg(struct imx355 *imx355) { + struct device *dev = imx355->dev; struct imx355_hwcfg *cfg; struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + const struct imx355_clk_params *clk = imx355->clk_params; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); + int lane_idx; int ret; if (!fwnode) @@ -1708,13 +1151,18 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) if (!cfg) goto out_err; - if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX355_DATA_LANES) + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2 && + bus_cfg.bus.mipi_csi2.num_data_lanes != 4) goto out_err; + cfg->num_lanes = bus_cfg.bus.mipi_csi2.num_data_lanes; + + lane_idx = cfg->num_lanes == 4 ? 0 : 1; + cfg->link_freq_menu = (clk->ext_clk * clk->pll_op_mpy[lane_idx]) / + (clk->pll_op_prediv[lane_idx] * 2); ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, bus_cfg.nr_of_link_frequencies, - link_freq_menu_items, - ARRAY_SIZE(link_freq_menu_items), + &cfg->link_freq_menu, 1, &cfg->link_freq_bitmap); if (ret) goto out_err; @@ -1741,7 +1189,10 @@ static int imx355_probe(struct i2c_client *client) imx355->dev = &client->dev; - mutex_init(&imx355->mutex); + imx355->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(imx355->regmap)) + return dev_err_probe(imx355->dev, PTR_ERR(imx355->regmap), + "Unable to initialize I2C\n"); imx355->clk = devm_v4l2_sensor_clk_get(imx355->dev, NULL); if (IS_ERR(imx355->clk)) @@ -1749,7 +1200,13 @@ static int imx355_probe(struct i2c_client *client) "failed to get clock\n"); freq = clk_get_rate(imx355->clk); - if (freq != IMX355_EXT_CLK) + for (unsigned int i = 0; i < ARRAY_SIZE(imx355_clk_params); i++) { + if (freq == imx355_clk_params[i].ext_clk) { + imx355->clk_params = &imx355_clk_params[i]; + break; + } + } + if (!imx355->clk_params) return dev_err_probe(imx355->dev, -EINVAL, "external clock %lu is not supported\n", freq); @@ -1760,7 +1217,7 @@ static int imx355_probe(struct i2c_client *client) &imx355->supplies); if (ret) { dev_err_probe(imx355->dev, ret, "could not get regulators"); - goto error_probe; + return ret; } imx355->reset_gpio = devm_gpiod_get_optional(imx355->dev, "reset", @@ -1768,22 +1225,21 @@ static int imx355_probe(struct i2c_client *client) if (IS_ERR(imx355->reset_gpio)) { ret = dev_err_probe(imx355->dev, PTR_ERR(imx355->reset_gpio), "failed to get gpios"); - goto error_probe; + return ret; } /* Initialize subdev */ v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops); - imx355->hwcfg = imx355_get_hwcfg(imx355->dev); + imx355->hwcfg = imx355_get_hwcfg(imx355); if (!imx355->hwcfg) { dev_err(imx355->dev, "failed to get hwcfg"); - ret = -ENODEV; - goto error_probe; + return -ENODEV; } ret = imx355_power_on(imx355->dev); if (ret) - goto error_probe; + return ret; /* Check module identity */ ret = imx355_identify_module(imx355); @@ -1792,9 +1248,6 @@ static int imx355_probe(struct i2c_client *client) goto error_power_off; } - /* Set default mode to max resolution */ - imx355->cur_mode = &supported_modes[0]; - ret = imx355_init_controls(imx355); if (ret) { dev_err(imx355->dev, "failed to init controls: %d", ret); @@ -1816,23 +1269,36 @@ static int imx355_probe(struct i2c_client *client) goto error_handler_free; } + imx355->sd.state_lock = imx355->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&imx355->sd); + if (ret < 0) { + dev_err_probe(imx355->dev, ret, "subdev init error\n"); + goto error_media_entity_free; + } + /* * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ pm_runtime_set_active(imx355->dev); pm_runtime_enable(imx355->dev); - pm_runtime_idle(imx355->dev); + pm_runtime_set_autosuspend_delay(imx355->dev, 1000); + pm_runtime_use_autosuspend(imx355->dev); ret = v4l2_async_register_subdev_sensor(&imx355->sd); if (ret < 0) - goto error_media_entity_runtime_pm; + goto error_subdev_cleanup_runtime_pm; + + pm_runtime_idle(imx355->dev); return 0; -error_media_entity_runtime_pm: +error_subdev_cleanup_runtime_pm: pm_runtime_disable(imx355->dev); pm_runtime_set_suspended(imx355->dev); + pm_runtime_dont_use_autosuspend(imx355->dev); + v4l2_subdev_cleanup(&imx355->sd); +error_media_entity_free: media_entity_cleanup(&imx355->sd.entity); error_handler_free: @@ -1841,9 +1307,6 @@ error_handler_free: error_power_off: imx355_power_off(imx355->dev); -error_probe: - mutex_destroy(&imx355->mutex); - return ret; } @@ -1853,6 +1316,7 @@ static void imx355_remove(struct i2c_client *client) struct imx355 *imx355 = to_imx355(sd); v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); @@ -1863,7 +1327,7 @@ static void imx355_remove(struct i2c_client *client) pm_runtime_set_suspended(imx355->dev); } - mutex_destroy(&imx355->mutex); + pm_runtime_dont_use_autosuspend(imx355->dev); } static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = { diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index 2705af2f16c0..d2760e9e6194 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -13,38 +13,39 @@ #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-fwnode.h> #include <media/v4l2-subdev.h> /* Streaming Mode */ -#define IMX412_REG_MODE_SELECT 0x0100 +#define IMX412_REG_MODE_SELECT CCI_REG8(0x0100) #define IMX412_MODE_STANDBY 0x00 #define IMX412_MODE_STREAMING 0x01 /* Lines per frame */ -#define IMX412_REG_LPFR 0x0340 +#define IMX412_REG_LPFR CCI_REG16(0x0340) /* Chip ID */ -#define IMX412_REG_ID 0x0016 +#define IMX412_REG_ID CCI_REG16(0x0016) #define IMX412_ID 0x577 /* Exposure control */ -#define IMX412_REG_EXPOSURE_CIT 0x0202 +#define IMX412_REG_EXPOSURE_CIT CCI_REG16(0x0202) #define IMX412_EXPOSURE_MIN 8 #define IMX412_EXPOSURE_OFFSET 22 #define IMX412_EXPOSURE_STEP 1 #define IMX412_EXPOSURE_DEFAULT 0x0648 /* Analog gain control */ -#define IMX412_REG_AGAIN 0x0204 +#define IMX412_REG_AGAIN CCI_REG16(0x0204) #define IMX412_AGAIN_MIN 0 #define IMX412_AGAIN_MAX 978 #define IMX412_AGAIN_STEP 1 #define IMX412_AGAIN_DEFAULT 0 /* Group hold register */ -#define IMX412_REG_HOLD 0x0104 +#define IMX412_REG_HOLD CCI_REG8(0x0104) /* Input clock rate */ #define IMX412_INCLK_RATE 24000000 @@ -57,23 +58,13 @@ #define IMX412_REG_MAX 0xffff /** - * struct imx412_reg - imx412 sensor register - * @address: Register address - * @val: Register value - */ -struct imx412_reg { - u16 address; - u8 val; -}; - -/** * struct imx412_reg_list - imx412 sensor register list * @num_of_regs: Number of registers in the list * @regs: Pointer to register list */ struct imx412_reg_list { u32 num_of_regs; - const struct imx412_reg *regs; + const struct cci_reg_sequence *regs; }; /** @@ -111,6 +102,7 @@ static const char * const imx412_supply_names[] = { /** * struct imx412 - imx412 sensor device structure * @dev: Pointer to generic device + * @cci: CCI register map * @client: Pointer to i2c client * @sd: V4L2 sub-device * @pad: Media pad. Only one pad supported @@ -126,10 +118,10 @@ static const char * const imx412_supply_names[] = { * @again_ctrl: Pointer to analog gain control * @vblank: Vertical blanking in lines * @cur_mode: Pointer to current selected sensor mode - * @mutex: Mutex for serializing sensor controls */ struct imx412 { struct device *dev; + struct regmap *cci; struct i2c_client *client; struct v4l2_subdev sd; struct media_pad pad; @@ -147,7 +139,6 @@ struct imx412 { }; u32 vblank; const struct imx412_mode *cur_mode; - struct mutex mutex; }; static const s64 link_freq[] = { @@ -155,238 +146,238 @@ static const s64 link_freq[] = { }; /* Sensor mode registers */ -static const struct imx412_reg mode_4056x3040_regs[] = { - {0x0136, 0x18}, - {0x0137, 0x00}, - {0x3c7e, 0x08}, - {0x3c7f, 0x02}, - {0x38a8, 0x1f}, - {0x38a9, 0xff}, - {0x38aa, 0x1f}, - {0x38ab, 0xff}, - {0x55d4, 0x00}, - {0x55d5, 0x00}, - {0x55d6, 0x07}, - {0x55d7, 0xff}, - {0x55e8, 0x07}, - {0x55e9, 0xff}, - {0x55ea, 0x00}, - {0x55eb, 0x00}, - {0x575c, 0x07}, - {0x575d, 0xff}, - {0x575e, 0x00}, - {0x575f, 0x00}, - {0x5764, 0x00}, - {0x5765, 0x00}, - {0x5766, 0x07}, - {0x5767, 0xff}, - {0x5974, 0x04}, - {0x5975, 0x01}, - {0x5f10, 0x09}, - {0x5f11, 0x92}, - {0x5f12, 0x32}, - {0x5f13, 0x72}, - {0x5f14, 0x16}, - {0x5f15, 0xba}, - {0x5f17, 0x13}, - {0x5f18, 0x24}, - {0x5f19, 0x60}, - {0x5f1a, 0xe3}, - {0x5f1b, 0xad}, - {0x5f1c, 0x74}, - {0x5f2d, 0x25}, - {0x5f5c, 0xd0}, - {0x6a22, 0x00}, - {0x6a23, 0x1d}, - {0x7ba8, 0x00}, - {0x7ba9, 0x00}, - {0x886b, 0x00}, - {0x9002, 0x0a}, - {0x9004, 0x1a}, - {0x9214, 0x93}, - {0x9215, 0x69}, - {0x9216, 0x93}, - {0x9217, 0x6b}, - {0x9218, 0x93}, - {0x9219, 0x6d}, - {0x921a, 0x57}, - {0x921b, 0x58}, - {0x921c, 0x57}, - {0x921d, 0x59}, - {0x921e, 0x57}, - {0x921f, 0x5a}, - {0x9220, 0x57}, - {0x9221, 0x5b}, - {0x9222, 0x93}, - {0x9223, 0x02}, - {0x9224, 0x93}, - {0x9225, 0x03}, - {0x9226, 0x93}, - {0x9227, 0x04}, - {0x9228, 0x93}, - {0x9229, 0x05}, - {0x922a, 0x98}, - {0x922b, 0x21}, - {0x922c, 0xb2}, - {0x922d, 0xdb}, - {0x922e, 0xb2}, - {0x922f, 0xdc}, - {0x9230, 0xb2}, - {0x9231, 0xdd}, - {0x9232, 0xe2}, - {0x9233, 0xe1}, - {0x9234, 0xb2}, - {0x9235, 0xe2}, - {0x9236, 0xb2}, - {0x9237, 0xe3}, - {0x9238, 0xb7}, - {0x9239, 0xb9}, - {0x923a, 0xb7}, - {0x923b, 0xbb}, - {0x923c, 0xb7}, - {0x923d, 0xbc}, - {0x923e, 0xb7}, - {0x923f, 0xc5}, - {0x9240, 0xb7}, - {0x9241, 0xc7}, - {0x9242, 0xb7}, - {0x9243, 0xc9}, - {0x9244, 0x98}, - {0x9245, 0x56}, - {0x9246, 0x98}, - {0x9247, 0x55}, - {0x9380, 0x00}, - {0x9381, 0x62}, - {0x9382, 0x00}, - {0x9383, 0x56}, - {0x9384, 0x00}, - {0x9385, 0x52}, - {0x9388, 0x00}, - {0x9389, 0x55}, - {0x938a, 0x00}, - {0x938b, 0x55}, - {0x938c, 0x00}, - {0x938d, 0x41}, - {0x5078, 0x01}, - {0x0112, 0x0a}, - {0x0113, 0x0a}, - {0x0114, 0x03}, - {0x0342, 0x11}, - {0x0343, 0xa0}, - {0x0340, 0x0d}, - {0x0341, 0xda}, - {0x3210, 0x00}, - {0x0344, 0x00}, - {0x0345, 0x00}, - {0x0346, 0x00}, - {0x0347, 0x00}, - {0x0348, 0x0f}, - {0x0349, 0xd7}, - {0x034a, 0x0b}, - {0x034b, 0xdf}, - {0x00e3, 0x00}, - {0x00e4, 0x00}, - {0x00e5, 0x01}, - {0x00fc, 0x0a}, - {0x00fd, 0x0a}, - {0x00fe, 0x0a}, - {0x00ff, 0x0a}, - {0xe013, 0x00}, - {0x0220, 0x00}, - {0x0221, 0x11}, - {0x0381, 0x01}, - {0x0383, 0x01}, - {0x0385, 0x01}, - {0x0387, 0x01}, - {0x0900, 0x00}, - {0x0901, 0x11}, - {0x0902, 0x00}, - {0x3140, 0x02}, - {0x3241, 0x11}, - {0x3250, 0x03}, - {0x3e10, 0x00}, - {0x3e11, 0x00}, - {0x3f0d, 0x00}, - {0x3f42, 0x00}, - {0x3f43, 0x00}, - {0x0401, 0x00}, - {0x0404, 0x00}, - {0x0405, 0x10}, - {0x0408, 0x00}, - {0x0409, 0x00}, - {0x040a, 0x00}, - {0x040b, 0x00}, - {0x040c, 0x0f}, - {0x040d, 0xd8}, - {0x040e, 0x0b}, - {0x040f, 0xe0}, - {0x034c, 0x0f}, - {0x034d, 0xd8}, - {0x034e, 0x0b}, - {0x034f, 0xe0}, - {0x0301, 0x05}, - {0x0303, 0x02}, - {0x0305, 0x04}, - {0x0306, 0x00}, - {0x0307, 0xc8}, - {0x0309, 0x0a}, - {0x030b, 0x01}, - {0x030d, 0x02}, - {0x030e, 0x01}, - {0x030f, 0x5e}, - {0x0310, 0x00}, - {0x0820, 0x12}, - {0x0821, 0xc0}, - {0x0822, 0x00}, - {0x0823, 0x00}, - {0x3e20, 0x01}, - {0x3e37, 0x00}, - {0x3f50, 0x00}, - {0x3f56, 0x00}, - {0x3f57, 0xe2}, - {0x3c0a, 0x5a}, - {0x3c0b, 0x55}, - {0x3c0c, 0x28}, - {0x3c0d, 0x07}, - {0x3c0e, 0xff}, - {0x3c0f, 0x00}, - {0x3c10, 0x00}, - {0x3c11, 0x02}, - {0x3c12, 0x00}, - {0x3c13, 0x03}, - {0x3c14, 0x00}, - {0x3c15, 0x00}, - {0x3c16, 0x0c}, - {0x3c17, 0x0c}, - {0x3c18, 0x0c}, - {0x3c19, 0x0a}, - {0x3c1a, 0x0a}, - {0x3c1b, 0x0a}, - {0x3c1c, 0x00}, - {0x3c1d, 0x00}, - {0x3c1e, 0x00}, - {0x3c1f, 0x00}, - {0x3c20, 0x00}, - {0x3c21, 0x00}, - {0x3c22, 0x3f}, - {0x3c23, 0x0a}, - {0x3e35, 0x01}, - {0x3f4a, 0x03}, - {0x3f4b, 0xbf}, - {0x3f26, 0x00}, - {0x0202, 0x0d}, - {0x0203, 0xc4}, - {0x0204, 0x00}, - {0x0205, 0x00}, - {0x020e, 0x01}, - {0x020f, 0x00}, - {0x0210, 0x01}, - {0x0211, 0x00}, - {0x0212, 0x01}, - {0x0213, 0x00}, - {0x0214, 0x01}, - {0x0215, 0x00}, - {0xbcf1, 0x00}, +static const struct cci_reg_sequence mode_4056x3040_regs[] = { + { CCI_REG8(0x0136), 0x18 }, + { CCI_REG8(0x0137), 0x00 }, + { CCI_REG8(0x3c7e), 0x08 }, + { CCI_REG8(0x3c7f), 0x02 }, + { CCI_REG8(0x38a8), 0x1f }, + { CCI_REG8(0x38a9), 0xff }, + { CCI_REG8(0x38aa), 0x1f }, + { CCI_REG8(0x38ab), 0xff }, + { CCI_REG8(0x55d4), 0x00 }, + { CCI_REG8(0x55d5), 0x00 }, + { CCI_REG8(0x55d6), 0x07 }, + { CCI_REG8(0x55d7), 0xff }, + { CCI_REG8(0x55e8), 0x07 }, + { CCI_REG8(0x55e9), 0xff }, + { CCI_REG8(0x55ea), 0x00 }, + { CCI_REG8(0x55eb), 0x00 }, + { CCI_REG8(0x575c), 0x07 }, + { CCI_REG8(0x575d), 0xff }, + { CCI_REG8(0x575e), 0x00 }, + { CCI_REG8(0x575f), 0x00 }, + { CCI_REG8(0x5764), 0x00 }, + { CCI_REG8(0x5765), 0x00 }, + { CCI_REG8(0x5766), 0x07 }, + { CCI_REG8(0x5767), 0xff }, + { CCI_REG8(0x5974), 0x04 }, + { CCI_REG8(0x5975), 0x01 }, + { CCI_REG8(0x5f10), 0x09 }, + { CCI_REG8(0x5f11), 0x92 }, + { CCI_REG8(0x5f12), 0x32 }, + { CCI_REG8(0x5f13), 0x72 }, + { CCI_REG8(0x5f14), 0x16 }, + { CCI_REG8(0x5f15), 0xba }, + { CCI_REG8(0x5f17), 0x13 }, + { CCI_REG8(0x5f18), 0x24 }, + { CCI_REG8(0x5f19), 0x60 }, + { CCI_REG8(0x5f1a), 0xe3 }, + { CCI_REG8(0x5f1b), 0xad }, + { CCI_REG8(0x5f1c), 0x74 }, + { CCI_REG8(0x5f2d), 0x25 }, + { CCI_REG8(0x5f5c), 0xd0 }, + { CCI_REG8(0x6a22), 0x00 }, + { CCI_REG8(0x6a23), 0x1d }, + { CCI_REG8(0x7ba8), 0x00 }, + { CCI_REG8(0x7ba9), 0x00 }, + { CCI_REG8(0x886b), 0x00 }, + { CCI_REG8(0x9002), 0x0a }, + { CCI_REG8(0x9004), 0x1a }, + { CCI_REG8(0x9214), 0x93 }, + { CCI_REG8(0x9215), 0x69 }, + { CCI_REG8(0x9216), 0x93 }, + { CCI_REG8(0x9217), 0x6b }, + { CCI_REG8(0x9218), 0x93 }, + { CCI_REG8(0x9219), 0x6d }, + { CCI_REG8(0x921a), 0x57 }, + { CCI_REG8(0x921b), 0x58 }, + { CCI_REG8(0x921c), 0x57 }, + { CCI_REG8(0x921d), 0x59 }, + { CCI_REG8(0x921e), 0x57 }, + { CCI_REG8(0x921f), 0x5a }, + { CCI_REG8(0x9220), 0x57 }, + { CCI_REG8(0x9221), 0x5b }, + { CCI_REG8(0x9222), 0x93 }, + { CCI_REG8(0x9223), 0x02 }, + { CCI_REG8(0x9224), 0x93 }, + { CCI_REG8(0x9225), 0x03 }, + { CCI_REG8(0x9226), 0x93 }, + { CCI_REG8(0x9227), 0x04 }, + { CCI_REG8(0x9228), 0x93 }, + { CCI_REG8(0x9229), 0x05 }, + { CCI_REG8(0x922a), 0x98 }, + { CCI_REG8(0x922b), 0x21 }, + { CCI_REG8(0x922c), 0xb2 }, + { CCI_REG8(0x922d), 0xdb }, + { CCI_REG8(0x922e), 0xb2 }, + { CCI_REG8(0x922f), 0xdc }, + { CCI_REG8(0x9230), 0xb2 }, + { CCI_REG8(0x9231), 0xdd }, + { CCI_REG8(0x9232), 0xe2 }, + { CCI_REG8(0x9233), 0xe1 }, + { CCI_REG8(0x9234), 0xb2 }, + { CCI_REG8(0x9235), 0xe2 }, + { CCI_REG8(0x9236), 0xb2 }, + { CCI_REG8(0x9237), 0xe3 }, + { CCI_REG8(0x9238), 0xb7 }, + { CCI_REG8(0x9239), 0xb9 }, + { CCI_REG8(0x923a), 0xb7 }, + { CCI_REG8(0x923b), 0xbb }, + { CCI_REG8(0x923c), 0xb7 }, + { CCI_REG8(0x923d), 0xbc }, + { CCI_REG8(0x923e), 0xb7 }, + { CCI_REG8(0x923f), 0xc5 }, + { CCI_REG8(0x9240), 0xb7 }, + { CCI_REG8(0x9241), 0xc7 }, + { CCI_REG8(0x9242), 0xb7 }, + { CCI_REG8(0x9243), 0xc9 }, + { CCI_REG8(0x9244), 0x98 }, + { CCI_REG8(0x9245), 0x56 }, + { CCI_REG8(0x9246), 0x98 }, + { CCI_REG8(0x9247), 0x55 }, + { CCI_REG8(0x9380), 0x00 }, + { CCI_REG8(0x9381), 0x62 }, + { CCI_REG8(0x9382), 0x00 }, + { CCI_REG8(0x9383), 0x56 }, + { CCI_REG8(0x9384), 0x00 }, + { CCI_REG8(0x9385), 0x52 }, + { CCI_REG8(0x9388), 0x00 }, + { CCI_REG8(0x9389), 0x55 }, + { CCI_REG8(0x938a), 0x00 }, + { CCI_REG8(0x938b), 0x55 }, + { CCI_REG8(0x938c), 0x00 }, + { CCI_REG8(0x938d), 0x41 }, + { CCI_REG8(0x5078), 0x01 }, + { CCI_REG8(0x0112), 0x0a }, + { CCI_REG8(0x0113), 0x0a }, + { CCI_REG8(0x0114), 0x03 }, + { CCI_REG8(0x0342), 0x11 }, + { CCI_REG8(0x0343), 0xa0 }, + { CCI_REG8(0x0340), 0x0d }, + { CCI_REG8(0x0341), 0xda }, + { CCI_REG8(0x3210), 0x00 }, + { CCI_REG8(0x0344), 0x00 }, + { CCI_REG8(0x0345), 0x00 }, + { CCI_REG8(0x0346), 0x00 }, + { CCI_REG8(0x0347), 0x00 }, + { CCI_REG8(0x0348), 0x0f }, + { CCI_REG8(0x0349), 0xd7 }, + { CCI_REG8(0x034a), 0x0b }, + { CCI_REG8(0x034b), 0xdf }, + { CCI_REG8(0x00e3), 0x00 }, + { CCI_REG8(0x00e4), 0x00 }, + { CCI_REG8(0x00e5), 0x01 }, + { CCI_REG8(0x00fc), 0x0a }, + { CCI_REG8(0x00fd), 0x0a }, + { CCI_REG8(0x00fe), 0x0a }, + { CCI_REG8(0x00ff), 0x0a }, + { CCI_REG8(0xe013), 0x00 }, + { CCI_REG8(0x0220), 0x00 }, + { CCI_REG8(0x0221), 0x11 }, + { CCI_REG8(0x0381), 0x01 }, + { CCI_REG8(0x0383), 0x01 }, + { CCI_REG8(0x0385), 0x01 }, + { CCI_REG8(0x0387), 0x01 }, + { CCI_REG8(0x0900), 0x00 }, + { CCI_REG8(0x0901), 0x11 }, + { CCI_REG8(0x0902), 0x00 }, + { CCI_REG8(0x3140), 0x02 }, + { CCI_REG8(0x3241), 0x11 }, + { CCI_REG8(0x3250), 0x03 }, + { CCI_REG8(0x3e10), 0x00 }, + { CCI_REG8(0x3e11), 0x00 }, + { CCI_REG8(0x3f0d), 0x00 }, + { CCI_REG8(0x3f42), 0x00 }, + { CCI_REG8(0x3f43), 0x00 }, + { CCI_REG8(0x0401), 0x00 }, + { CCI_REG8(0x0404), 0x00 }, + { CCI_REG8(0x0405), 0x10 }, + { CCI_REG8(0x0408), 0x00 }, + { CCI_REG8(0x0409), 0x00 }, + { CCI_REG8(0x040a), 0x00 }, + { CCI_REG8(0x040b), 0x00 }, + { CCI_REG8(0x040c), 0x0f }, + { CCI_REG8(0x040d), 0xd8 }, + { CCI_REG8(0x040e), 0x0b }, + { CCI_REG8(0x040f), 0xe0 }, + { CCI_REG8(0x034c), 0x0f }, + { CCI_REG8(0x034d), 0xd8 }, + { CCI_REG8(0x034e), 0x0b }, + { CCI_REG8(0x034f), 0xe0 }, + { CCI_REG8(0x0301), 0x05 }, + { CCI_REG8(0x0303), 0x02 }, + { CCI_REG8(0x0305), 0x04 }, + { CCI_REG8(0x0306), 0x00 }, + { CCI_REG8(0x0307), 0xc8 }, + { CCI_REG8(0x0309), 0x0a }, + { CCI_REG8(0x030b), 0x01 }, + { CCI_REG8(0x030d), 0x02 }, + { CCI_REG8(0x030e), 0x01 }, + { CCI_REG8(0x030f), 0x5e }, + { CCI_REG8(0x0310), 0x00 }, + { CCI_REG8(0x0820), 0x12 }, + { CCI_REG8(0x0821), 0xc0 }, + { CCI_REG8(0x0822), 0x00 }, + { CCI_REG8(0x0823), 0x00 }, + { CCI_REG8(0x3e20), 0x01 }, + { CCI_REG8(0x3e37), 0x00 }, + { CCI_REG8(0x3f50), 0x00 }, + { CCI_REG8(0x3f56), 0x00 }, + { CCI_REG8(0x3f57), 0xe2 }, + { CCI_REG8(0x3c0a), 0x5a }, + { CCI_REG8(0x3c0b), 0x55 }, + { CCI_REG8(0x3c0c), 0x28 }, + { CCI_REG8(0x3c0d), 0x07 }, + { CCI_REG8(0x3c0e), 0xff }, + { CCI_REG8(0x3c0f), 0x00 }, + { CCI_REG8(0x3c10), 0x00 }, + { CCI_REG8(0x3c11), 0x02 }, + { CCI_REG8(0x3c12), 0x00 }, + { CCI_REG8(0x3c13), 0x03 }, + { CCI_REG8(0x3c14), 0x00 }, + { CCI_REG8(0x3c15), 0x00 }, + { CCI_REG8(0x3c16), 0x0c }, + { CCI_REG8(0x3c17), 0x0c }, + { CCI_REG8(0x3c18), 0x0c }, + { CCI_REG8(0x3c19), 0x0a }, + { CCI_REG8(0x3c1a), 0x0a }, + { CCI_REG8(0x3c1b), 0x0a }, + { CCI_REG8(0x3c1c), 0x00 }, + { CCI_REG8(0x3c1d), 0x00 }, + { CCI_REG8(0x3c1e), 0x00 }, + { CCI_REG8(0x3c1f), 0x00 }, + { CCI_REG8(0x3c20), 0x00 }, + { CCI_REG8(0x3c21), 0x00 }, + { CCI_REG8(0x3c22), 0x3f }, + { CCI_REG8(0x3c23), 0x0a }, + { CCI_REG8(0x3e35), 0x01 }, + { CCI_REG8(0x3f4a), 0x03 }, + { CCI_REG8(0x3f4b), 0xbf }, + { CCI_REG8(0x3f26), 0x00 }, + { CCI_REG8(0x0202), 0x0d }, + { CCI_REG8(0x0203), 0xc4 }, + { CCI_REG8(0x0204), 0x00 }, + { CCI_REG8(0x0205), 0x00 }, + { CCI_REG8(0x020e), 0x01 }, + { CCI_REG8(0x020f), 0x00 }, + { CCI_REG8(0x0210), 0x01 }, + { CCI_REG8(0x0211), 0x00 }, + { CCI_REG8(0x0212), 0x01 }, + { CCI_REG8(0x0213), 0x00 }, + { CCI_REG8(0x0214), 0x01 }, + { CCI_REG8(0x0215), 0x00 }, + { CCI_REG8(0xbcf1), 0x00 }, }; /* Supported sensor mode configurations */ @@ -418,97 +409,6 @@ static inline struct imx412 *to_imx412(struct v4l2_subdev *subdev) } /** - * imx412_read_reg() - Read registers. - * @imx412: pointer to imx412 device - * @reg: register address - * @len: length of bytes to read. Max supported bytes is 4 - * @val: pointer to register value to be filled. - * - * Return: 0 if successful, error code otherwise. - */ -static int imx412_read_reg(struct imx412 *imx412, u16 reg, u32 len, u32 *val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd); - struct i2c_msg msgs[2] = {0}; - u8 addr_buf[2] = {0}; - u8 data_buf[4] = {0}; - int ret; - - if (WARN_ON(len > 4)) - return -EINVAL; - - put_unaligned_be16(reg, addr_buf); - - /* Write register address */ - msgs[0].addr = client->addr; - msgs[0].flags = 0; - msgs[0].len = ARRAY_SIZE(addr_buf); - msgs[0].buf = addr_buf; - - /* Read data from register */ - msgs[1].addr = client->addr; - msgs[1].flags = I2C_M_RD; - msgs[1].len = len; - msgs[1].buf = &data_buf[4 - len]; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret != ARRAY_SIZE(msgs)) - return -EIO; - - *val = get_unaligned_be32(data_buf); - - return 0; -} - -/** - * imx412_write_reg() - Write register - * @imx412: pointer to imx412 device - * @reg: register address - * @len: length of bytes. Max supported bytes is 4 - * @val: register value - * - * Return: 0 if successful, error code otherwise. - */ -static int imx412_write_reg(struct imx412 *imx412, u16 reg, u32 len, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd); - u8 buf[6] = {0}; - - if (WARN_ON(len > 4)) - return -EINVAL; - - put_unaligned_be16(reg, buf); - put_unaligned_be32(val << (8 * (4 - len)), buf + 2); - if (i2c_master_send(client, buf, len + 2) != len + 2) - return -EIO; - - return 0; -} - -/** - * imx412_write_regs() - Write a list of registers - * @imx412: pointer to imx412 device - * @regs: list of registers to be written - * @len: length of registers array - * - * Return: 0 if successful, error code otherwise. - */ -static int imx412_write_regs(struct imx412 *imx412, - const struct imx412_reg *regs, u32 len) -{ - unsigned int i; - int ret; - - for (i = 0; i < len; i++) { - ret = imx412_write_reg(imx412, regs[i].address, 1, regs[i].val); - if (ret) - return ret; - } - - return 0; -} - -/** * imx412_update_controls() - Update control ranges based on streaming mode * @imx412: pointer to imx412 device * @mode: pointer to imx412_mode sensor mode @@ -543,29 +443,25 @@ static int imx412_update_controls(struct imx412 *imx412, static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) { u32 lpfr; - int ret; + int ret = 0; + int ret_hold; lpfr = imx412->vblank + imx412->cur_mode->height; dev_dbg(imx412->dev, "Set exp %u, analog gain %u, lpfr %u\n", exposure, gain, lpfr); - ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1); - if (ret) - return ret; + cci_write(imx412->cci, IMX412_REG_HOLD, 1, &ret); - ret = imx412_write_reg(imx412, IMX412_REG_LPFR, 2, lpfr); - if (ret) - goto error_release_group_hold; + cci_write(imx412->cci, IMX412_REG_LPFR, lpfr, &ret); - ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, exposure); - if (ret) - goto error_release_group_hold; + cci_write(imx412->cci, IMX412_REG_EXPOSURE_CIT, exposure, &ret); - ret = imx412_write_reg(imx412, IMX412_REG_AGAIN, 2, gain); + cci_write(imx412->cci, IMX412_REG_AGAIN, gain, &ret); -error_release_group_hold: - imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 0); + ret_hold = cci_write(imx412->cci, IMX412_REG_HOLD, 0, NULL); + if (ret_hold) + return ret_hold; return ret; } @@ -679,8 +575,6 @@ static int imx412_get_pad_format(struct v4l2_subdev *sd, { struct imx412 *imx412 = to_imx412(sd); - mutex_lock(&imx412->mutex); - if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { struct v4l2_mbus_framefmt *framefmt; @@ -690,8 +584,6 @@ static int imx412_get_pad_format(struct v4l2_subdev *sd, imx412_fill_pad_format(imx412, imx412->cur_mode, fmt); } - mutex_unlock(&imx412->mutex); - return 0; } @@ -703,8 +595,6 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd, const struct imx412_mode *mode; int ret = 0; - mutex_lock(&imx412->mutex); - mode = &supported_mode; imx412_fill_pad_format(imx412, mode, fmt); @@ -719,8 +609,6 @@ static int imx412_set_pad_format(struct v4l2_subdev *sd, imx412->cur_mode = mode; } - mutex_unlock(&imx412->mutex); - return ret; } @@ -737,88 +625,86 @@ static int imx412_init_state(struct v4l2_subdev *sd, } /** - * imx412_start_streaming() - Start sensor stream - * @imx412: pointer to imx412 device + * imx412_enable_streams() - Enable specified streams for the sensor + * @sd: pointer to the V4L2 subdevice + * @state: pointer to the subdevice state + * @pad: pad number for which streams are enabled + * @streams_mask: bitmask specifying the streams to enable * * Return: 0 if successful, error code otherwise. */ -static int imx412_start_streaming(struct imx412 *imx412) +static int imx412_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) { const struct imx412_reg_list *reg_list; + struct imx412 *imx412 = to_imx412(sd); int ret; + ret = pm_runtime_resume_and_get(imx412->dev); + if (ret < 0) + return ret; + /* Write sensor mode registers */ reg_list = &imx412->cur_mode->reg_list; - ret = imx412_write_regs(imx412, reg_list->regs, - reg_list->num_of_regs); + ret = cci_multi_reg_write(imx412->cci, reg_list->regs, + reg_list->num_of_regs, NULL); if (ret) { dev_err(imx412->dev, "fail to write initial registers\n"); - return ret; + goto err_rpm_put; } /* Setup handler will write actual exposure and gain */ ret = __v4l2_ctrl_handler_setup(imx412->sd.ctrl_handler); if (ret) { dev_err(imx412->dev, "fail to setup handler\n"); - return ret; + goto err_rpm_put; } /* Delay is required before streaming*/ usleep_range(7400, 8000); /* Start streaming */ - ret = imx412_write_reg(imx412, IMX412_REG_MODE_SELECT, - 1, IMX412_MODE_STREAMING); + ret = cci_write(imx412->cci, IMX412_REG_MODE_SELECT, + IMX412_MODE_STREAMING, NULL); if (ret) { dev_err(imx412->dev, "fail to start streaming\n"); - return ret; + goto err_rpm_put; } return 0; + +err_rpm_put: + pm_runtime_put(imx412->dev); + + return ret; } /** - * imx412_stop_streaming() - Stop sensor stream - * @imx412: pointer to imx412 device + * imx412_disable_streams() - Enable specified streams for the sensor + * @sd: pointer to the V4L2 subdevice + * @state: pointer to the subdevice state + * @pad: pad number for which streams are disabled + * @streams_mask: bitmask specifying the streams to disable * * Return: 0 if successful, error code otherwise. */ -static int imx412_stop_streaming(struct imx412 *imx412) -{ - return imx412_write_reg(imx412, IMX412_REG_MODE_SELECT, - 1, IMX412_MODE_STANDBY); -} - -static int imx412_set_stream(struct v4l2_subdev *sd, int enable) +static int imx412_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) { struct imx412 *imx412 = to_imx412(sd); int ret; - mutex_lock(&imx412->mutex); + ret = cci_write(imx412->cci, IMX412_REG_MODE_SELECT, + IMX412_MODE_STANDBY, NULL); - if (enable) { - ret = pm_runtime_resume_and_get(imx412->dev); - if (ret) - goto error_unlock; - - ret = imx412_start_streaming(imx412); - if (ret) - goto error_power_off; - } else { - imx412_stop_streaming(imx412); - pm_runtime_put(imx412->dev); - } - - mutex_unlock(&imx412->mutex); - - return 0; + if (ret) + dev_err(imx412->dev, "failed to set stream off\n"); -error_power_off: pm_runtime_put(imx412->dev); -error_unlock: - mutex_unlock(&imx412->mutex); - return ret; + return 0; } /** @@ -830,16 +716,18 @@ error_unlock: static int imx412_detect(struct imx412 *imx412) { int ret; - u32 val; + u64 val; - ret = imx412_read_reg(imx412, IMX412_REG_ID, 2, &val); + ret = cci_read(imx412->cci, IMX412_REG_ID, &val, NULL); if (ret) - return ret; + return dev_err_probe(imx412->dev, ret, + "failed to read chip id %x\n", + IMX412_ID); if (val != IMX412_ID) { - dev_err(imx412->dev, "chip id mismatch: %x!=%x\n", - IMX412_ID, val); - return -ENXIO; + return dev_err_probe(imx412->dev, -ENODEV, + "chip id mismatch: %x!=%llx", + IMX412_ID, val); } return 0; @@ -933,7 +821,7 @@ done_endpoint_free: /* V4l2 subdevice ops */ static const struct v4l2_subdev_video_ops imx412_video_ops = { - .s_stream = imx412_set_stream, + .s_stream = v4l2_subdev_s_stream_helper, }; static const struct v4l2_subdev_pad_ops imx412_pad_ops = { @@ -941,6 +829,8 @@ static const struct v4l2_subdev_pad_ops imx412_pad_ops = { .enum_frame_size = imx412_enum_frame_size, .get_fmt = imx412_get_pad_format, .set_fmt = imx412_set_pad_format, + .enable_streams = imx412_enable_streams, + .disable_streams = imx412_disable_streams, }; static const struct v4l2_subdev_ops imx412_subdev_ops = { @@ -1021,9 +911,6 @@ static int imx412_init_controls(struct imx412 *imx412) if (ret) return ret; - /* Serialize controls with sensor device */ - ctrl_hdlr->lock = &imx412->mutex; - /* Initialize exposure and gain */ lpfr = mode->vblank + mode->height; imx412->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, @@ -1104,6 +991,11 @@ static int imx412_probe(struct i2c_client *client) if (!name) return -ENODEV; + imx412->cci = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(imx412->cci)) + return dev_err_probe(imx412->dev, PTR_ERR(imx412->cci), + "Failed to init CCI\n"); + /* Initialize subdev */ v4l2_i2c_subdev_init(&imx412->sd, client, &imx412_subdev_ops); imx412->sd.internal_ops = &imx412_internal_ops; @@ -1114,13 +1006,10 @@ static int imx412_probe(struct i2c_client *client) return ret; } - mutex_init(&imx412->mutex); - ret = imx412_power_on(imx412->dev); - if (ret) { - dev_err(imx412->dev, "failed to power-on the sensor\n"); - goto error_mutex_destroy; - } + if (ret) + return dev_err_probe(imx412->dev, ret, + "failed to power-on the sensor\n"); /* Check module identity */ ret = imx412_detect(imx412); @@ -1153,27 +1042,37 @@ static int imx412_probe(struct i2c_client *client) goto error_handler_free; } - ret = v4l2_async_register_subdev_sensor(&imx412->sd); + imx412->sd.state_lock = imx412->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&imx412->sd); if (ret < 0) { - dev_err(imx412->dev, - "failed to register async subdev: %d\n", ret); + dev_err_probe(imx412->dev, ret, "subdev init error\n"); goto error_media_entity; } pm_runtime_set_active(imx412->dev); pm_runtime_enable(imx412->dev); + + ret = v4l2_async_register_subdev_sensor(&imx412->sd); + if (ret < 0) { + dev_err_probe(imx412->dev, ret, + "failed to register sub-device\n"); + goto error_subdev_cleanup; + } + pm_runtime_idle(imx412->dev); return 0; +error_subdev_cleanup: + v4l2_subdev_cleanup(&imx412->sd); + pm_runtime_disable(imx412->dev); + pm_runtime_set_suspended(imx412->dev); error_media_entity: media_entity_cleanup(&imx412->sd.entity); error_handler_free: v4l2_ctrl_handler_free(imx412->sd.ctrl_handler); error_power_off: imx412_power_off(imx412->dev); -error_mutex_destroy: - mutex_destroy(&imx412->mutex); return ret; } @@ -1181,9 +1080,9 @@ error_mutex_destroy: static void imx412_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx412 *imx412 = to_imx412(sd); v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); @@ -1191,8 +1090,6 @@ static void imx412_remove(struct i2c_client *client) if (!pm_runtime_status_suspended(&client->dev)) imx412_power_off(&client->dev); pm_runtime_set_suspended(&client->dev); - - mutex_destroy(&imx412->mutex); } static const struct dev_pm_ops imx412_pm_ops = { diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 0b424c17e880..c3b22b238ea0 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -686,7 +686,7 @@ static int imx415_set_testpattern(struct imx415 *sensor, int val) cci_write(sensor->regmap, IMX415_DIG_CLP_MODE, 0x01, &ret); cci_write(sensor->regmap, IMX415_WRJ_OPEN, 0x01, &ret); } - return 0; + return ret; } static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) @@ -720,7 +720,7 @@ static int imx415_s_ctrl(struct v4l2_ctrl *ctrl) ret = cci_write(sensor->regmap, IMX415_VMAX, format->height + ctrl->val, NULL); if (ret) - return ret; + break; /* * Exposure is set based on VMAX which has just changed, so * program exposure register as well diff --git a/drivers/media/i2c/imx471.c b/drivers/media/i2c/imx471.c new file mode 100644 index 000000000000..4053aed84340 --- /dev/null +++ b/drivers/media/i2c/imx471.c @@ -0,0 +1,957 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * imx471.c - imx471 sensor driver + * + * Copyright (C) 2025 Intel Corporation + * Copyright (C) 2026 Kate Hsuan <hpa@redhat.com> + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-subdev.h> +#include <media/v4l2-fwnode.h> + +#define IMX471_REG_MODE_SELECT CCI_REG8(0x0100) +#define IMX471_MODE_STANDBY 0x00 +#define IMX471_MODE_STREAMING 0x01 + +/* Chip ID */ +#define IMX471_REG_CHIP_ID CCI_REG16(0x0016) +#define IMX471_CHIP_ID 0x0471 + +/* V_TIMING internal */ +#define IMX471_REG_FLL CCI_REG16(0x0340) +#define IMX471_FLL_MAX 0xffff + +/* Exposure control */ +#define IMX471_REG_EXPOSURE CCI_REG16(0x0202) +#define IMX471_EXPOSURE_MIN 1 +#define IMX471_EXPOSURE_STEP 1 +#define IMX471_EXPOSURE_DEFAULT 1270 + +/* Default exposure margin */ +#define IMX471_EXPOSURE_MARGIN 18 + +/* Analog gain control */ +#define IMX471_REG_ANALOG_GAIN CCI_REG16(0x0204) +#define IMX471_ANA_GAIN_MIN 0 +#define IMX471_ANA_GAIN_MAX 800 +#define IMX471_ANA_GAIN_STEP 1 +#define IMX471_ANA_GAIN_DEFAULT 0 + +/* Digital gain control */ +#define IMX471_REG_DPGA_USE_GLOBAL_GAIN CCI_REG16(0x3ff9) +#define IMX471_REG_DIG_GAIN_GLOBAL CCI_REG16(0x020e) +#define IMX471_DGTL_GAIN_MIN 256 +#define IMX471_DGTL_GAIN_MAX 4095 +#define IMX471_DGTL_GAIN_STEP 1 +#define IMX471_DGTL_GAIN_DEFAULT 256 + +/* HFLIP and VFLIP control */ +#define IMX471_REG_ORIENTATION CCI_REG8(0x0101) + +/* Test Pattern Control */ +#define IMX471_REG_TEST_PATTERN CCI_REG8(0x0600) + +/* default link frequency and external clock */ +#define IMX471_LINK_FREQ_DEFAULT 200000000LL +#define IMX471_EXT_CLK 19200000 + +/* PLL */ +#define IMX471_REG_VTPXCK_DIV CCI_REG8(0x0301) +#define IMX471_REG_VTSYCK_DIV CCI_REG8(0x0303) +#define IMX471_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305) +#define IMX471_REG_PLL_VT_MPY CCI_REG16(0x0306) +#define IMX471_REG_OPPXCK_DIV CCI_REG8(0x0309) +#define IMX471_REG_OPSYCK_DIV CCI_REG8(0x030b) +#define IMX471_REG_PLL_MULT_DRIV CCI_REG8(0x0310) +#define IMX471_PLL_SINGLE 0 +#define IMX471_PLL_DUAL 1 + +/* IMX471 native and active pixel array size */ +#define IMX471_NATIVE_WIDTH 4672 +#define IMX471_NATIVE_HEIGHT 3512 +#define IMX471_PIXEL_ARRAY_LEFT 8 +#define IMX471_PIXEL_ARRAY_TOP 8 +#define IMX471_PIXEL_ARRAY_WIDTH 4656 +#define IMX471_PIXEL_ARRAY_HEIGHT 3496 + +#define IMX471_REG_EXCK_FREQ CCI_REG16(0x0136) + +#define IMX471_REG_CSI_DATA_FORMAT CCI_REG16(0x0112) +#define IMX471_CSI_DATA_FORMAT_RAW10 0x0a0a + +#define IMX471_REG_CSI_LANE_MODE CCI_REG8(0x0114) +#define IMX471_CSI_2_LANE_MODE 1 +#define IMX471_CSI_4_LANE_MODE 3 + +#define IMX471_REG_X_ADD_STA CCI_REG16(0x0344) +#define IMX471_REG_Y_ADD_STA CCI_REG16(0x0346) +#define IMX471_REG_X_ADD_END CCI_REG16(0x0348) +#define IMX471_REG_Y_ADD_END CCI_REG16(0x034a) +#define IMX471_REG_X_OUTPUT_SIZE CCI_REG16(0x034c) +#define IMX471_REG_Y_OUTPUT_SIZE CCI_REG16(0x034e) +#define IMX471_REG_X_EVEN_INC CCI_REG8(0x0381) +#define IMX471_REG_X_ODD_INC CCI_REG8(0x0383) +#define IMX471_REG_Y_EVEN_INC CCI_REG8(0x0385) +#define IMX471_REG_Y_ODD_INC CCI_REG8(0x0387) + +#define IMX471_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408) +#define IMX471_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a) +#define IMX471_REG_DIG_CROP_WIDTH CCI_REG16(0x040c) +#define IMX471_REG_DIG_CROP_HEIGHT CCI_REG16(0x040e) + +/* Binning mode */ +#define IMX471_REG_BINNING_MODE CCI_REG8(0x0900) +#define IMX471_BINNING_NONE 0 +#define IMX471_BINNING_ENABLE 1 +#define IMX471_REG_BINNING_TYPE CCI_REG8(0x0901) +#define IMX471_REG_BINNING_WEIGHTING CCI_REG8(0x0902) + +#define to_imx471(_sd) container_of_const(_sd, struct imx471, sd) + +static const char * const imx471_supply_name[] = { + "vana", +}; + +struct imx471_mode { + u32 width; + u32 height; + + /* V-timing */ + u32 fll_def; + u32 fll_min; + + /* H-timing */ + u32 llp; + + const struct cci_reg_sequence *default_mode_regs; + unsigned int default_mode_regs_length; +}; + +struct imx471 { + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *exposure; + + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx471_supply_name)]; + struct clk *img_clk; + + struct device *dev; + struct regmap *regmap; +}; + +static const struct cci_reg_sequence imx471_global_regs[] = { + { IMX471_REG_EXCK_FREQ, 0x1333 }, + { CCI_REG8(0x3c7e), 0x08 }, + { CCI_REG8(0x3c7f), 0x05 }, + { CCI_REG8(0x3e35), 0x00 }, + { CCI_REG8(0x3e36), 0x00 }, + { CCI_REG8(0x3e37), 0x00 }, + { CCI_REG8(0x3f7f), 0x01 }, + { CCI_REG8(0x4431), 0x04 }, + { CCI_REG8(0x531c), 0x01 }, + { CCI_REG8(0x531d), 0x02 }, + { CCI_REG8(0x531e), 0x04 }, + { CCI_REG8(0x5928), 0x00 }, + { CCI_REG8(0x5929), 0x2f }, + { CCI_REG8(0x592a), 0x00 }, + { CCI_REG8(0x592b), 0x85 }, + { CCI_REG8(0x592c), 0x00 }, + { CCI_REG8(0x592d), 0x32 }, + { CCI_REG8(0x592e), 0x00 }, + { CCI_REG8(0x592f), 0x88 }, + { CCI_REG8(0x5930), 0x00 }, + { CCI_REG8(0x5931), 0x3d }, + { CCI_REG8(0x5932), 0x00 }, + { CCI_REG8(0x5933), 0x93 }, + { CCI_REG8(0x5938), 0x00 }, + { CCI_REG8(0x5939), 0x24 }, + { CCI_REG8(0x593a), 0x00 }, + { CCI_REG8(0x593b), 0x7a }, + { CCI_REG8(0x593c), 0x00 }, + { CCI_REG8(0x593d), 0x24 }, + { CCI_REG8(0x593e), 0x00 }, + { CCI_REG8(0x593f), 0x7a }, + { CCI_REG8(0x5940), 0x00 }, + { CCI_REG8(0x5941), 0x2f }, + { CCI_REG8(0x5942), 0x00 }, + { CCI_REG8(0x5943), 0x85 }, + { CCI_REG8(0x5f0e), 0x6e }, + { CCI_REG8(0x5f11), 0xc6 }, + { CCI_REG8(0x5f17), 0x5e }, + { CCI_REG8(0x7990), 0x01 }, + { CCI_REG8(0x7993), 0x5d }, + { CCI_REG8(0x7994), 0x5d }, + { CCI_REG8(0x7995), 0xa1 }, + { CCI_REG8(0x799a), 0x01 }, + { CCI_REG8(0x799d), 0x00 }, + { CCI_REG8(0x8169), 0x01 }, + { CCI_REG8(0x8359), 0x01 }, + { CCI_REG8(0x9302), 0x1e }, + { CCI_REG8(0x9306), 0x1f }, + { CCI_REG8(0x930a), 0x26 }, + { CCI_REG8(0x930e), 0x23 }, + { CCI_REG8(0x9312), 0x23 }, + { CCI_REG8(0x9316), 0x2c }, + { CCI_REG8(0x9317), 0x19 }, + { CCI_REG8(0xb046), 0x01 }, + { CCI_REG8(0xb048), 0x01 }, +}; + +static const struct cci_reg_sequence mode_1928x1088_regs[] = { + { IMX471_REG_CSI_DATA_FORMAT, IMX471_CSI_DATA_FORMAT_RAW10 }, + { IMX471_REG_CSI_LANE_MODE, IMX471_CSI_4_LANE_MODE }, + { IMX471_REG_X_ADD_STA, 8 }, + { IMX471_REG_Y_ADD_STA, 408 }, + { IMX471_REG_X_ADD_END, 4647 }, + { IMX471_REG_Y_ADD_END, 3051 }, + { IMX471_REG_X_EVEN_INC, 1 }, + { IMX471_REG_X_ODD_INC, 1 }, + { IMX471_REG_Y_EVEN_INC, 1 }, + { IMX471_REG_Y_ODD_INC, 1 }, + { IMX471_REG_BINNING_MODE, IMX471_BINNING_ENABLE }, + { IMX471_REG_BINNING_TYPE, 0x22 }, + { IMX471_REG_BINNING_WEIGHTING, 0x08 }, + { IMX471_REG_DIG_CROP_X_OFFSET, 208 }, + { IMX471_REG_DIG_CROP_Y_OFFSET, 108 }, + { IMX471_REG_DIG_CROP_WIDTH, 1928 }, + { IMX471_REG_DIG_CROP_HEIGHT, 1088 }, + { IMX471_REG_X_OUTPUT_SIZE, 1928 }, + { IMX471_REG_Y_OUTPUT_SIZE, 1088 }, + { IMX471_REG_VTPXCK_DIV, 0x06 }, + { IMX471_REG_VTSYCK_DIV, 0x02 }, + { IMX471_REG_PREPLLCK_VT_DIV, 0x02 }, + { IMX471_REG_PLL_VT_MPY, 0x0079 }, + { IMX471_REG_OPSYCK_DIV, 0x01 }, + { CCI_REG8(0x030d), 0x02 }, + { CCI_REG8(0x030e), 0x00 }, + { CCI_REG8(0x030f), 0x53 }, + { IMX471_REG_PLL_MULT_DRIV, IMX471_PLL_DUAL }, + { CCI_REG8(0x3f4c), 0x81 }, + { CCI_REG8(0x3f4d), 0x81 }, + { CCI_REG8(0x3f78), 0x01 }, + { CCI_REG8(0x3f79), 0x31 }, + { CCI_REG8(0x3ffe), 0x00 }, + { CCI_REG8(0x3fff), 0x8a }, + { CCI_REG8(0x5f0a), 0xb6 }, +}; + +static const char * const imx471_test_pattern_menu[] = { + "Disabled", + "Solid Colour", + "Eight Vertical Colour Bars", + "Colour Bars With Fade to Grey", + "Pseudorandom Sequence (PN9)", +}; + +static const s64 link_freq_menu_items[] = { + IMX471_LINK_FREQ_DEFAULT, +}; + +/* + * The Bayer formats for the flipping. + * - no flip + * - h flip + * - v flip + * - h and v flips + */ +static const u32 imx471_hv_flips_bayer_order[] = { + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SBGGR10_1X10, +}; + +static const struct imx471_mode imx471_modes[] = { + { + .width = 1928, + .height = 1088, + .fll_def = 1308, + .fll_min = 1308, + .llp = 2328, + .default_mode_regs = mode_1928x1088_regs, + .default_mode_regs_length = ARRAY_SIZE(mode_1928x1088_regs), + }, +}; + +static int imx471_get_regulators(struct device *dev, struct imx471 *sensor) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(imx471_supply_name); i++) + sensor->supplies[i].supply = imx471_supply_name[i]; + + return devm_regulator_bulk_get(dev, ARRAY_SIZE(imx471_supply_name), + sensor->supplies); +} + +static int imx471_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx471 *sensor = container_of_const(ctrl->handler, + struct imx471, + ctrl_handler); + struct v4l2_subdev_state *state = + v4l2_subdev_get_locked_active_state(&sensor->sd); + const struct v4l2_mbus_framefmt *format = + v4l2_subdev_state_get_format(state, 0); + int ret; + + if (ctrl->id == V4L2_CID_VBLANK) { + s64 exposure_max = format->height + ctrl->val - + IMX471_EXPOSURE_MARGIN; + ret = __v4l2_ctrl_modify_range(sensor->exposure, + sensor->exposure->minimum, + exposure_max, + sensor->exposure->step, + exposure_max); + if (ret) + return ret; + } + + if (!pm_runtime_get_if_in_use(sensor->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = cci_write(sensor->regmap, IMX471_REG_ANALOG_GAIN, + ctrl->val, NULL); + break; + case V4L2_CID_DIGITAL_GAIN: + ret = cci_write(sensor->regmap, IMX471_REG_DIG_GAIN_GLOBAL, + ctrl->val, NULL); + break; + case V4L2_CID_EXPOSURE: + ret = cci_write(sensor->regmap, IMX471_REG_EXPOSURE, + ctrl->val, NULL); + break; + case V4L2_CID_VBLANK: + /* Update FLL that meets expected vertical blanking */ + ret = cci_write(sensor->regmap, IMX471_REG_FLL, + format->height + ctrl->val, NULL); + break; + case V4L2_CID_TEST_PATTERN: + ret = cci_write(sensor->regmap, IMX471_REG_TEST_PATTERN, + ctrl->val, NULL); + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + ret = cci_write(sensor->regmap, IMX471_REG_ORIENTATION, + sensor->hflip->val | sensor->vflip->val << 1, + NULL); + break; + default: + ret = -EINVAL; + dev_err(sensor->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", + ctrl->id, ctrl->val); + break; + } + + pm_runtime_put(sensor->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops imx471_ctrl_ops = { + .s_ctrl = imx471_set_ctrl, +}; + +static u32 imx471_get_format_code(struct imx471 *sensor) +{ + unsigned int i; + + i = (sensor->vflip->val ? 2 : 0) | (sensor->hflip->val ? 1 : 0); + + return imx471_hv_flips_bayer_order[i]; +} + +static int imx471_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx471 *sensor = to_imx471(sd); + + if (code->index >= (ARRAY_SIZE(imx471_hv_flips_bayer_order) / 4)) + return -EINVAL; + + code->code = imx471_get_format_code(sensor); + + return 0; +} + +static int imx471_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(imx471_modes)) + return -EINVAL; + + fse->min_width = imx471_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = imx471_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static void imx471_update_pad_format(struct imx471 *sensor, + const struct imx471_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.code = imx471_get_format_code(sensor); + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.field = V4L2_FIELD_NONE; +} + +static int imx471_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx471 *sensor = to_imx471(sd); + const struct imx471_mode *mode; + int h_blank, ret; + + mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes), + width, height, fmt->format.width, + fmt->format.height); + + imx471_update_pad_format(sensor, mode, fmt); + + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + + if (media_entity_is_streaming(&sensor->sd.entity)) + return -EBUSY; + + ret = __v4l2_ctrl_modify_range(sensor->vblank, + mode->fll_min - mode->height, + IMX471_FLL_MAX - mode->height, + 1, + mode->fll_def - mode->height); + if (ret) + return ret; + + h_blank = mode->llp - mode->width; + /* + * Currently hblank is not changeable. + * So FPS control is done only by vblank. + */ + return __v4l2_ctrl_modify_range(sensor->hblank, h_blank, + h_blank, 1, h_blank); +} + +static int imx471_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); + break; + + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = IMX471_NATIVE_WIDTH; + sel->r.height = IMX471_NATIVE_HEIGHT; + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = IMX471_PIXEL_ARRAY_TOP; + sel->r.left = IMX471_PIXEL_ARRAY_LEFT; + sel->r.width = IMX471_PIXEL_ARRAY_WIDTH; + sel->r.height = IMX471_PIXEL_ARRAY_HEIGHT; + return 0; + } + + return -EINVAL; +} + +static int imx471_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .format = { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = imx471_modes[0].width, + .height = imx471_modes[0].height, + }, + }; + + return imx471_set_pad_format(sd, sd_state, &fmt); +} + +static int imx471_identify_module(struct imx471 *sensor) +{ + int ret; + u64 val; + + ret = cci_read(sensor->regmap, IMX471_REG_CHIP_ID, &val, NULL); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to read chip id\n"); + + if (val != IMX471_CHIP_ID) + return dev_err_probe(sensor->dev, -EIO, + "chip id mismatch: %x!=%llx\n", + IMX471_CHIP_ID, val); + + return 0; +} + +static int imx471_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx471 *sensor = to_imx471(sd); + + clk_disable_unprepare(sensor->img_clk); + gpiod_set_value_cansleep(sensor->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name), + sensor->supplies); + + return 0; +} + +static int imx471_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx471 *sensor = to_imx471(sd); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(imx471_supply_name), + sensor->supplies); + if (ret < 0) { + dev_err(dev, "failed to enable regulators: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(sensor->img_clk); + if (ret < 0) { + regulator_bulk_disable(ARRAY_SIZE(imx471_supply_name), + sensor->supplies); + dev_err(dev, "failed to enable imaging clock: %d\n", ret); + return ret; + } + + gpiod_set_value_cansleep(sensor->reset_gpio, 0); + + usleep_range(10000, 15000); + + return 0; +} + +static int imx471_enable_stream(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct imx471 *sensor = to_imx471(sd); + const struct imx471_mode *mode; + struct v4l2_mbus_framefmt *fmt; + int ret; + + ret = pm_runtime_resume_and_get(sensor->dev); + if (ret) + return ret; + + ret = imx471_identify_module(sensor); + if (ret) + goto error_powerdown; + + ret = cci_multi_reg_write(sensor->regmap, imx471_global_regs, + ARRAY_SIZE(imx471_global_regs), NULL); + if (ret) { + dev_err(sensor->dev, "failed to set global settings: %d\n", + ret); + goto error_powerdown; + } + + fmt = v4l2_subdev_state_get_format(state, 0); + mode = v4l2_find_nearest_size(imx471_modes, ARRAY_SIZE(imx471_modes), + width, height, fmt->width, fmt->height); + + ret = cci_multi_reg_write(sensor->regmap, mode->default_mode_regs, + mode->default_mode_regs_length, NULL); + if (ret) { + dev_err(sensor->dev, "failed to set mode: %d\n", ret); + goto error_powerdown; + } + + ret = cci_write(sensor->regmap, IMX471_REG_DPGA_USE_GLOBAL_GAIN, 1, + NULL); + if (ret) + goto error_powerdown; + + ret = __v4l2_ctrl_handler_setup(&sensor->ctrl_handler); + if (ret) + goto error_powerdown; + + ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT, + IMX471_MODE_STREAMING, NULL); + if (ret) + goto error_powerdown; + + __v4l2_ctrl_grab(sensor->vflip, true); + __v4l2_ctrl_grab(sensor->hflip, true); + + return ret; + +error_powerdown: + pm_runtime_put(sensor->dev); + + return ret; +} + +static int imx471_disable_stream(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct imx471 *sensor = to_imx471(sd); + int ret; + + ret = cci_write(sensor->regmap, IMX471_REG_MODE_SELECT, + IMX471_MODE_STANDBY, NULL); + pm_runtime_put(sensor->dev); + + if (ret) + dev_err(sensor->dev, + "failed to disable stream with return value: %d\n", + ret); + + __v4l2_ctrl_grab(sensor->vflip, false); + __v4l2_ctrl_grab(sensor->hflip, false); + + return 0; +} + +static const struct v4l2_subdev_video_ops imx471_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops imx471_pad_ops = { + .enum_mbus_code = imx471_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = imx471_set_pad_format, + .get_selection = imx471_get_selection, + .enum_frame_size = imx471_enum_frame_size, + .enable_streams = imx471_enable_stream, + .disable_streams = imx471_disable_stream, +}; + +static const struct v4l2_subdev_ops imx471_subdev_ops = { + .video = &imx471_video_ops, + .pad = &imx471_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops imx471_internal_ops = { + .init_state = imx471_init_state, +}; + +static int imx471_init_controls(struct imx471 *sensor) +{ + const struct imx471_mode *mode = &imx471_modes[0]; + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl_handler *ctrl_hdlr; + struct v4l2_ctrl *link_freq; + s64 exposure_max, hblank; + u64 pixel_rate; + int ret; + + ret = v4l2_fwnode_device_parse(sensor->dev, &props); + if (ret) { + dev_err(sensor->dev, "failed to parse fwnode: %d\n", ret); + return ret; + } + + ctrl_hdlr = &sensor->ctrl_handler; + v4l2_ctrl_handler_init(ctrl_hdlr, 12); + + v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx471_ctrl_ops, &props); + + link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &imx471_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq_menu_items) - 1, + 0, + link_freq_menu_items); + + /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ + pixel_rate = div_u64(IMX471_LINK_FREQ_DEFAULT * 2 * 4, 10); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_PIXEL_RATE, pixel_rate, + pixel_rate, 1, pixel_rate); + + sensor->vblank = v4l2_ctrl_new_std(ctrl_hdlr, + &imx471_ctrl_ops, + V4L2_CID_VBLANK, + mode->fll_min - mode->height, + IMX471_FLL_MAX - mode->height, + 1, + mode->fll_def - mode->height); + + hblank = mode->llp - mode->width; + sensor->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, + 1, hblank); + + /* fll >= exposure time + adjust parameter (default value is 18) */ + exposure_max = mode->fll_def - IMX471_EXPOSURE_MARGIN; + sensor->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX471_EXPOSURE_MIN, exposure_max, + IMX471_EXPOSURE_STEP, + IMX471_EXPOSURE_DEFAULT); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + IMX471_ANA_GAIN_MIN, IMX471_ANA_GAIN_MAX, + IMX471_ANA_GAIN_STEP, IMX471_ANA_GAIN_DEFAULT); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, V4L2_CID_DIGITAL_GAIN, + IMX471_DGTL_GAIN_MIN, IMX471_DGTL_GAIN_MAX, + IMX471_DGTL_GAIN_STEP, IMX471_DGTL_GAIN_DEFAULT); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx471_test_pattern_menu) - 1, + 0, 0, imx471_test_pattern_menu); + + sensor->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + sensor->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx471_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + if (ctrl_hdlr->error) { + dev_err(sensor->dev, "%s control init failed: %d\n", + __func__, ctrl_hdlr->error); + goto error; + } + + link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + sensor->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; + + sensor->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ctrl_hdlr->error; +} + +static int imx471_check_hwcfg(struct imx471 *sensor) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct fwnode_handle *ep, *fwnode = dev_fwnode(sensor->dev); + unsigned long link_freq_bitmap; + struct clk *clk; + int ret; + + clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(sensor->dev, PTR_ERR(clk), + "can't get clock frequency\n"); + + if (clk_get_rate(clk) != IMX471_EXT_CLK) + return dev_err_probe(sensor->dev, -EINVAL, + "external clock %lu is not supported\n", + clk_get_rate(clk)); + + ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0); + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return dev_err_probe(sensor->dev, ret, + "parsing endpoint failed\n"); + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) { + ret = dev_err_probe(sensor->dev, -EINVAL, + "number of CSI2 data lanes %u is not supported\n", + bus_cfg.bus.mipi_csi2.num_data_lanes); + goto done_endpoint_free; + } + + ret = v4l2_link_freq_to_bitmap(sensor->dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq_menu_items, + ARRAY_SIZE(link_freq_menu_items), + &link_freq_bitmap); + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int imx471_probe(struct i2c_client *client) +{ + struct imx471 *sensor; + int ret; + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return dev_err_probe(&client->dev, -ENOMEM, + "failed to allocate memory\n"); + + sensor->dev = &client->dev; + + ret = imx471_check_hwcfg(sensor); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to check hwcfg: %d\n", ret); + + ret = imx471_get_regulators(sensor->dev, sensor); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to get regulators\n"); + + sensor->reset_gpio = devm_gpiod_get_optional(sensor->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset_gpio)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset_gpio), + "failed to get reset gpio\n"); + + sensor->img_clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); + if (IS_ERR(sensor->img_clk)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->img_clk), + "failed to get imaging clock\n"); + + v4l2_i2c_subdev_init(&sensor->sd, client, &imx471_subdev_ops); + + sensor->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(sensor->regmap)) + return dev_err_probe(sensor->dev, PTR_ERR(sensor->regmap), + "failed to initialize CCI\n"); + + ret = imx471_power_on(sensor->dev); + if (ret) + return dev_err_probe(sensor->dev, ret, + "failed to power on\n"); + + ret = imx471_identify_module(sensor); + if (ret) { + dev_err_probe(sensor->dev, ret, "failed to find sensor: %d\n", + ret); + goto error_power_off; + } + + ret = imx471_init_controls(sensor); + if (ret) { + dev_err_probe(sensor->dev, ret, "failed to init controls: %d\n", + ret); + goto error_power_off; + } + + sensor->sd.internal_ops = &imx471_internal_ops; + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); + if (ret) { + dev_err_probe(sensor->dev, ret, + "failed to init entity pads: %d\n", ret); + goto error_v4l2_ctrl_handler_free; + } + + sensor->sd.state_lock = sensor->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&sensor->sd); + if (ret < 0) { + dev_err_probe(sensor->dev, ret, "failed to init subdev: %d\n", + ret); + goto error_media_entity_pm; + } + + pm_runtime_set_active(sensor->dev); + pm_runtime_enable(sensor->dev); + + ret = v4l2_async_register_subdev_sensor(&sensor->sd); + if (ret < 0) + goto error_v4l2_subdev_cleanup; + + pm_runtime_idle(sensor->dev); + + return 0; + +error_v4l2_subdev_cleanup: + pm_runtime_disable(sensor->dev); + pm_runtime_set_suspended(sensor->dev); + v4l2_subdev_cleanup(&sensor->sd); + +error_media_entity_pm: + media_entity_cleanup(&sensor->sd.entity); + +error_v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(sensor->sd.ctrl_handler); + +error_power_off: + imx471_power_off(sensor->dev); + + return ret; +} + +static void imx471_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + + if (!pm_runtime_status_suspended(&client->dev)) { + imx471_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + } +} + +static DEFINE_RUNTIME_DEV_PM_OPS(imx471_pm_ops, imx471_power_off, + imx471_power_on, NULL); + +static const struct acpi_device_id imx471_acpi_ids[] __maybe_unused = { + { "SONY471A" }, + { "TBE20A0" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(acpi, imx471_acpi_ids); + +static struct i2c_driver imx471_i2c_driver = { + .driver = { + .name = "imx471", + .acpi_match_table = ACPI_PTR(imx471_acpi_ids), + .pm = pm_sleep_ptr(&imx471_pm_ops), + }, + .probe = imx471_probe, + .remove = imx471_remove, +}; +module_i2c_driver(imx471_i2c_driver); + +MODULE_AUTHOR("Jimmy Su <jimmy.su@intel.com>"); +MODULE_AUTHOR("Serin Yeh <serin.yeh@intel.com>"); +MODULE_AUTHOR("Kate Hsuan <hpa@redhat.com>"); +MODULE_DESCRIPTION("Sony imx471 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/imx678.c b/drivers/media/i2c/imx678.c new file mode 100644 index 000000000000..0efbf43d2fe6 --- /dev/null +++ b/drivers/media/i2c/imx678.c @@ -0,0 +1,1447 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 driver for Sony IMX678 + * + * Diagonal 8.86 mm (Type 1/1.8) CMOS image sensor with 8.40 M effective pixels. + * + * Copyright (C) 2026 Ideas On Board Oy. + * + * Based on Sony IMX678 driver prepared by Will Whang & Soho Enterprise Ltd. + */ +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/media-bus-format.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mediabus.h> +#include <media/v4l2-rect.h> +#include <media/v4l2-subdev.h> + +/* Standby or streaming mode */ +#define IMX678_REG_MODE_SELECT CCI_REG8(0x3000) +#define IMX678_MODE_STANDBY 0x01 +#define IMX678_MODE_STREAMING 0x00 +#define IMX678_STREAM_DELAY_US 25000 +#define IMX678_STREAM_DELAY_RANGE_US 1000 + +/* XVS/XHS sync control */ +#define IMX678_REG_XMSTA CCI_REG8(0x3002) +#define IMX678_REG_XXS_DRV CCI_REG8(0x30a6) +#define IMX678_REG_XXS_OUTSEL CCI_REG8(0x30a4) + +/* Clk selection */ +#define IMX678_REG_INCK_SEL CCI_REG8(0x3014) + +/* Link Speed */ +#define IMX678_REG_DATARATE_SEL CCI_REG8(0x3015) + +/* Lane Count */ +#define IMX678_REG_LANEMODE CCI_REG8(0x3040) + +/* + * The internal readout clock runs at 74.25 MHz. In one cycle the AD reads 8 + * pixels, thus giving us a rate of 74.25 * 8 = 594 MPix/s + */ +#define IMX678_PIXEL_RATE 594000000 +#define IMX678_PIX_PER_CLK 8 + +/* VMAX - Frame Length in Lines */ +#define IMX678_REG_VMAX CCI_REG24_LE(0x3028) +#define IMX678_VMAX_MAX 0xfffff +#define IMX678_VMAX_DEFAULT 2250 + +/* HMAX - Line Length in Cycles (8 Pixels) */ +#define IMX678_REG_HMAX CCI_REG16_LE(0x302c) +#define IMX678_HMAX_MAX 0xffff + +/* SHR internal */ +#define IMX678_REG_SHR CCI_REG24_LE(0x3050) +#define IMX678_SHR_MIN 8 + +/* Exposure control */ +#define IMX678_EXPOSURE_MIN 2 +#define IMX678_EXPOSURE_STEP 1 +#define IMX678_EXPOSURE_DEFAULT 1000 + +/* + * Analogue gain control + * Range is from 0 to 100 (0dB - 30dB) with 0.3dB step size + * Values from 101 to 240 are valid but correspond to additional digital gain + * (0.3dB - 42dB) so don't expose it to userspace + */ +#define IMX678_REG_GAIN CCI_REG16_LE(0x3070) +#define IMX678_ANA_GAIN_MIN_NORMAL 0 +#define IMX678_ANA_GAIN_MAX_NORMAL 100 +#define IMX678_ANA_GAIN_STEP 1 +#define IMX678_ANA_GAIN_DEFAULT 0 + +/* Crop */ +#define IMX678_REG_WINMODE CCI_REG8(0x3018) +#define IMX678_REG_PIX_HST CCI_REG16_LE(0x303c) +#define IMX678_REG_PIX_HWIDTH CCI_REG16_LE(0x303e) +#define IMX678_REG_PIX_VST CCI_REG16_LE(0x3044) +#define IMX678_REG_PIX_VWIDTH CCI_REG16_LE(0x3046) + +/* Flip */ +#define IMX678_REG_WINMODEH CCI_REG8(0x3020) +#define IMX678_REG_WINMODEV CCI_REG8(0x3021) + +/* Sensor Identification */ +#define IMX678_REG_MONOCHROME CCI_REG8(0x4d18) +#define IMX678_TYPE BIT(0) +#define IMX678_REG_MODULE_ID CCI_REG16_LE(0x4d1c) +#define IMX678_ID 0x02a6 +#define IMX678_MODULE_ID_DELAY 80000 + +/* Common configuration registers */ +#define IMX678_REG_WDMODE CCI_REG8(0x301a) +#define IMX678_REG_ADDMODE CCI_REG8(0x301b) +#define IMX678_REG_THIN_V_EN CCI_REG8(0x301c) +#define IMX678_REG_VCMODE CCI_REG8(0x301e) +#define IMX678_REG_ADBIT CCI_REG8(0x3022) +#define IMX678_REG_MDBIT CCI_REG8(0x3023) +#define IMX678_REG_GAIN_PGC_FIDMD CCI_REG8(0x3400) + +/* Test pattern generator */ +#define IMX678_REG_TPG_EN_DUOUT CCI_REG8(0x30e0) +#define IMX678_REG_TPG_PATSEL_DUOUT CCI_REG8(0x30e2) +#define IMX678_TPG_ALL_000 0 +#define IMX678_TPG_ALL_FFF 1 +#define IMX678_TPG_ALL_555 2 +#define IMX678_TPG_ALL_AAA 3 +#define IMX678_TPG_TOG_555_AAA 4 +#define IMX678_TPG_TOG_AAA_555 5 +#define IMX678_TPG_TOG_000_555 6 +#define IMX678_TPG_TOG_555_000 7 +#define IMX678_TPG_TOG_000_FFF 8 +#define IMX678_TPG_TOG_FFF_000 9 +#define IMX678_TPG_H_COLOR_BARS 10 +#define IMX678_TPG_V_COLOR_BARS 11 +#define IMX678_REG_TPG_COLORWIDTH CCI_REG8(0x30e4) +#define IMX678_TPG_COLORWIDTH_80PIX 0 +#define IMX678_TPG_COLORWIDTH_160PIX 1 +#define IMX678_TPG_COLORWIDTH_320PIX 2 +#define IMX678_TPG_COLORWIDTH_640PIX 3 + +#define IMX678_REG_INTERFACE_SEL CCI_REG8(0x4e3c) +#define IMX678_INTERFACE_2L_4L 0x07 +#define IMX678_INTERFACE_8L_2x4L 0x7f + +/* Minimum output resolution */ +#define IMX678_PIXEL_ARRAY_MIN_WIDTH 1040 +#define IMX678_PIXEL_ARRAY_MIN_HEIGHT 956 + +/* Sensor windowing register alignment */ +#define IMX678_CROP_HWIDTH_ALIGN 16 +#define IMX678_CROP_VWIDTH_ALIGN 4 +#define IMX678_CROP_HST_ALIGN 4 +#define IMX678_CROP_VST_ALIGN 4 + +/* Subdev pads */ +#define IMX678_SOURCE_PAD 0 + +/* IMX678 native and active pixel array size. */ +static const struct v4l2_rect imx678_native_area = { + .top = 0, + .left = 0, + .width = 3857, + .height = 2201, +}; + +static const struct v4l2_rect imx678_active_area = { + .top = 20, + .left = 0, + .width = 3856, + .height = 2180, +}; + +enum imx678_type { + IMX678_COLOR = 0, + IMX678_MONOCHROME = 1, +}; + +struct imx678_model_info { + enum imx678_type type; + const u32 *codes; + unsigned int num_codes; +}; + +enum imx678_lanemode { + IMX678_LANEMODE_2L = 1, + IMX678_LANEMODE_4L = 3, +}; + +/* Link frequency setup (DDR: lane rate = 2 x link freq) */ +enum { + IMX678_LINK_FREQ_297MHZ, + IMX678_LINK_FREQ_360MHZ, + IMX678_LINK_FREQ_445MHZ, + IMX678_LINK_FREQ_594MHZ, + IMX678_LINK_FREQ_720MHZ, + IMX678_LINK_FREQ_891MHZ, + IMX678_LINK_FREQ_1039MHZ, + IMX678_LINK_FREQ_1188MHZ, +}; + +static const u8 link_freqs_reg_value[] = { + [IMX678_LINK_FREQ_297MHZ] = 0x07, + [IMX678_LINK_FREQ_360MHZ] = 0x06, + [IMX678_LINK_FREQ_445MHZ] = 0x05, + [IMX678_LINK_FREQ_594MHZ] = 0x04, + [IMX678_LINK_FREQ_720MHZ] = 0x03, + [IMX678_LINK_FREQ_891MHZ] = 0x02, + [IMX678_LINK_FREQ_1039MHZ] = 0x01, + [IMX678_LINK_FREQ_1188MHZ] = 0x00, +}; + +static const u64 link_freqs[] = { + [IMX678_LINK_FREQ_297MHZ] = 297000000, + [IMX678_LINK_FREQ_360MHZ] = 360000000, + [IMX678_LINK_FREQ_445MHZ] = 445500000, + [IMX678_LINK_FREQ_594MHZ] = 594000000, + [IMX678_LINK_FREQ_720MHZ] = 720000000, + [IMX678_LINK_FREQ_891MHZ] = 891000000, + [IMX678_LINK_FREQ_1039MHZ] = 1039500000, + [IMX678_LINK_FREQ_1188MHZ] = 1188000000, +}; + +static const u16 min_hmax_4lane[] = { + [IMX678_LINK_FREQ_297MHZ] = 1584, + [IMX678_LINK_FREQ_360MHZ] = 1320, + [IMX678_LINK_FREQ_445MHZ] = 1100, + [IMX678_LINK_FREQ_594MHZ] = 792, + [IMX678_LINK_FREQ_720MHZ] = 660, + [IMX678_LINK_FREQ_891MHZ] = 550, + [IMX678_LINK_FREQ_1039MHZ] = 550, + [IMX678_LINK_FREQ_1188MHZ] = 550, +}; + +struct imx678_inck_cfg { + u32 xclk_hz; /* platform clock rate */ + u8 inck_sel; /* value for reg */ +}; + +static const struct imx678_inck_cfg imx678_inck_table[] = { + { 74250000, 0x00 }, + { 37125000, 0x01 }, + { 72000000, 0x02 }, + { 27000000, 0x03 }, + { 24000000, 0x04 }, + { 36000000, 0x05 }, + { 18000000, 0x06 }, + { 13500000, 0x07 }, +}; + +static const char * const imx678_tpg_menu[] = { + "Disabled", + "All 000h", + "All FFFh", + "All 555h", + "All AAAh", + "Toggle 555/AAAh", + "Toggle AAA/555h", + "Toggle 000/555h", + "Toggle 555/000h", + "Toggle 000/FFFh", + "Toggle FFF/000h", + "Horizontal color bars", + "Vertical color bars", +}; + +static const int imx678_tpg_val[] = { + IMX678_TPG_ALL_000, + IMX678_TPG_ALL_000, + IMX678_TPG_ALL_FFF, + IMX678_TPG_ALL_555, + IMX678_TPG_ALL_AAA, + IMX678_TPG_TOG_555_AAA, + IMX678_TPG_TOG_AAA_555, + IMX678_TPG_TOG_000_555, + IMX678_TPG_TOG_555_000, + IMX678_TPG_TOG_000_FFF, + IMX678_TPG_TOG_FFF_000, + IMX678_TPG_H_COLOR_BARS, + IMX678_TPG_V_COLOR_BARS, +}; + +/* Common configuration */ +static const struct cci_reg_sequence common_regs[] = { + { IMX678_REG_THIN_V_EN, 0x00 }, + { IMX678_REG_VCMODE, 0x01 }, + { CCI_REG8(0x306b), 0x00 }, + { IMX678_REG_GAIN_PGC_FIDMD, 0x01 }, + { CCI_REG8(0x3460), 0x22 }, + { CCI_REG8(0x355a), 0x64 }, + { CCI_REG8(0x3a02), 0x7a }, + { CCI_REG8(0x3a10), 0xec }, + { CCI_REG8(0x3a12), 0x71 }, + { CCI_REG8(0x3a14), 0xde }, + { CCI_REG8(0x3a20), 0x2b }, + { CCI_REG8(0x3a24), 0x22 }, + { CCI_REG8(0x3a25), 0x25 }, + { CCI_REG8(0x3a26), 0x2a }, + { CCI_REG8(0x3a27), 0x2c }, + { CCI_REG8(0x3a28), 0x39 }, + { CCI_REG8(0x3a29), 0x38 }, + { CCI_REG8(0x3a30), 0x04 }, + { CCI_REG8(0x3a31), 0x04 }, + { CCI_REG8(0x3a32), 0x03 }, + { CCI_REG8(0x3a33), 0x03 }, + { CCI_REG8(0x3a34), 0x09 }, + { CCI_REG8(0x3a35), 0x06 }, + { CCI_REG8(0x3a38), 0xcd }, + { CCI_REG8(0x3a3a), 0x4c }, + { CCI_REG8(0x3a3c), 0xb9 }, + { CCI_REG8(0x3a3e), 0x30 }, + { CCI_REG8(0x3a40), 0x2c }, + { CCI_REG8(0x3a42), 0x39 }, + { CCI_REG8(0x3a4e), 0x00 }, + { CCI_REG8(0x3a52), 0x00 }, + { CCI_REG8(0x3a56), 0x00 }, + { CCI_REG8(0x3a5a), 0x00 }, + { CCI_REG8(0x3a5e), 0x00 }, + { CCI_REG8(0x3a62), 0x00 }, + { CCI_REG8(0x3a64), 0x00 }, + { CCI_REG8(0x3a6e), 0xa0 }, + { CCI_REG8(0x3a70), 0x50 }, + { CCI_REG8(0x3a8c), 0x04 }, + { CCI_REG8(0x3a8d), 0x03 }, + { CCI_REG8(0x3a8e), 0x09 }, + { CCI_REG8(0x3a90), 0x38 }, + { CCI_REG8(0x3a91), 0x42 }, + { CCI_REG8(0x3a92), 0x3c }, + { CCI_REG8(0x3b0e), 0xf3 }, + { CCI_REG8(0x3b12), 0xe5 }, + { CCI_REG8(0x3b27), 0xc0 }, + { CCI_REG8(0x3b2e), 0xef }, + { CCI_REG8(0x3b30), 0x6a }, + { CCI_REG8(0x3b32), 0xf6 }, + { CCI_REG8(0x3b36), 0xe1 }, + { CCI_REG8(0x3b3a), 0xe8 }, + { CCI_REG8(0x3b5a), 0x17 }, + { CCI_REG8(0x3b5e), 0xef }, + { CCI_REG8(0x3b60), 0x6a }, + { CCI_REG8(0x3b62), 0xf6 }, + { CCI_REG8(0x3b66), 0xe1 }, + { CCI_REG8(0x3b6a), 0xe8 }, + { CCI_REG8(0x3b88), 0xec }, + { CCI_REG8(0x3b8a), 0xed }, + { CCI_REG8(0x3b94), 0x71 }, + { CCI_REG8(0x3b96), 0x72 }, + { CCI_REG8(0x3b98), 0xde }, + { CCI_REG8(0x3b9a), 0xdf }, + { CCI_REG8(0x3c0f), 0x06 }, + { CCI_REG8(0x3c10), 0x06 }, + { CCI_REG8(0x3c11), 0x06 }, + { CCI_REG8(0x3c12), 0x06 }, + { CCI_REG8(0x3c13), 0x06 }, + { CCI_REG8(0x3c18), 0x20 }, + { CCI_REG8(0x3c37), 0x10 }, + { CCI_REG8(0x3c3a), 0x7a }, + { CCI_REG8(0x3c40), 0xf4 }, + { CCI_REG8(0x3c48), 0xe6 }, + { CCI_REG8(0x3c54), 0xce }, + { CCI_REG8(0x3c56), 0xd0 }, + { CCI_REG8(0x3c6c), 0x53 }, + { CCI_REG8(0x3c6e), 0x55 }, + { CCI_REG8(0x3c70), 0xc0 }, + { CCI_REG8(0x3c72), 0xc2 }, + { CCI_REG8(0x3c7e), 0xce }, + { CCI_REG8(0x3c8c), 0xcf }, + { CCI_REG8(0x3c8e), 0xeb }, + { CCI_REG8(0x3c98), 0x54 }, + { CCI_REG8(0x3c9a), 0x70 }, + { CCI_REG8(0x3c9c), 0xc1 }, + { CCI_REG8(0x3c9e), 0xdd }, + { CCI_REG8(0x3cb0), 0x7a }, + { CCI_REG8(0x3cb2), 0xba }, + { CCI_REG8(0x3cc8), 0xbc }, + { CCI_REG8(0x3cca), 0x7c }, + { CCI_REG8(0x3cd4), 0xea }, + { CCI_REG8(0x3cd5), 0x01 }, + { CCI_REG8(0x3cd6), 0x4a }, + { CCI_REG8(0x3cd8), 0x00 }, + { CCI_REG8(0x3cd9), 0x00 }, + { CCI_REG8(0x3cda), 0xff }, + { CCI_REG8(0x3cdb), 0x03 }, + { CCI_REG8(0x3cdc), 0x00 }, + { CCI_REG8(0x3cdd), 0x00 }, + { CCI_REG8(0x3cde), 0xff }, + { CCI_REG8(0x3cdf), 0x03 }, + { CCI_REG8(0x3ce4), 0x4c }, + { CCI_REG8(0x3ce6), 0xec }, + { CCI_REG8(0x3ce7), 0x01 }, + { CCI_REG8(0x3ce8), 0xff }, + { CCI_REG8(0x3ce9), 0x03 }, + { CCI_REG8(0x3cea), 0x00 }, + { CCI_REG8(0x3ceb), 0x00 }, + { CCI_REG8(0x3cec), 0xff }, + { CCI_REG8(0x3ced), 0x03 }, + { CCI_REG8(0x3cee), 0x00 }, + { CCI_REG8(0x3cef), 0x00 }, + { CCI_REG8(0x3cf2), 0xff }, + { CCI_REG8(0x3cf3), 0x03 }, + { CCI_REG8(0x3cf4), 0x00 }, + { CCI_REG8(0x3e28), 0x82 }, + { CCI_REG8(0x3e2a), 0x80 }, + { CCI_REG8(0x3e30), 0x85 }, + { CCI_REG8(0x3e32), 0x7d }, + { CCI_REG8(0x3e5c), 0xce }, + { CCI_REG8(0x3e5e), 0xd3 }, + { CCI_REG8(0x3e70), 0x53 }, + { CCI_REG8(0x3e72), 0x58 }, + { CCI_REG8(0x3e74), 0xc0 }, + { CCI_REG8(0x3e76), 0xc5 }, + { CCI_REG8(0x3e78), 0xc0 }, + { CCI_REG8(0x3e79), 0x01 }, + { CCI_REG8(0x3e7a), 0xd4 }, + { CCI_REG8(0x3e7b), 0x01 }, + { CCI_REG8(0x3eb4), 0x0b }, + { CCI_REG8(0x3eb5), 0x02 }, + { CCI_REG8(0x3eb6), 0x4d }, + { CCI_REG8(0x3eb7), 0x42 }, + { CCI_REG8(0x3eec), 0xf3 }, + { CCI_REG8(0x3eee), 0xe7 }, + { CCI_REG8(0x3f01), 0x01 }, + { CCI_REG8(0x3f24), 0x10 }, + { CCI_REG8(0x3f28), 0x2d }, + { CCI_REG8(0x3f2a), 0x2d }, + { CCI_REG8(0x3f2c), 0x2d }, + { CCI_REG8(0x3f2e), 0x2d }, + { CCI_REG8(0x3f30), 0x23 }, + { CCI_REG8(0x3f38), 0x2d }, + { CCI_REG8(0x3f3a), 0x2d }, + { CCI_REG8(0x3f3c), 0x2d }, + { CCI_REG8(0x3f3e), 0x28 }, + { CCI_REG8(0x3f40), 0x1e }, + { CCI_REG8(0x3f48), 0x2d }, + { CCI_REG8(0x3f4a), 0x2d }, + { CCI_REG8(0x3f4c), 0x00 }, + { CCI_REG8(0x4004), 0xe4 }, + { CCI_REG8(0x4006), 0xff }, + { CCI_REG8(0x4018), 0x69 }, + { CCI_REG8(0x401a), 0x84 }, + { CCI_REG8(0x401c), 0xd6 }, + { CCI_REG8(0x401e), 0xf1 }, + { CCI_REG8(0x4038), 0xde }, + { CCI_REG8(0x403a), 0x00 }, + { CCI_REG8(0x403b), 0x01 }, + { CCI_REG8(0x404c), 0x63 }, + { CCI_REG8(0x404e), 0x85 }, + { CCI_REG8(0x4050), 0xd0 }, + { CCI_REG8(0x4052), 0xf2 }, + { CCI_REG8(0x4108), 0xdd }, + { CCI_REG8(0x410a), 0xf7 }, + { CCI_REG8(0x411c), 0x62 }, + { CCI_REG8(0x411e), 0x7c }, + { CCI_REG8(0x4120), 0xcf }, + { CCI_REG8(0x4122), 0xe9 }, + { CCI_REG8(0x4138), 0xe6 }, + { CCI_REG8(0x413a), 0xf1 }, + { CCI_REG8(0x414c), 0x6b }, + { CCI_REG8(0x414e), 0x76 }, + { CCI_REG8(0x4150), 0xd8 }, + { CCI_REG8(0x4152), 0xe3 }, + { CCI_REG8(0x417e), 0x03 }, + { CCI_REG8(0x417f), 0x01 }, + { CCI_REG8(0x4186), 0xe0 }, + { CCI_REG8(0x4190), 0xf3 }, + { CCI_REG8(0x4192), 0xf7 }, + { CCI_REG8(0x419c), 0x78 }, + { CCI_REG8(0x419e), 0x7c }, + { CCI_REG8(0x41a0), 0xe5 }, + { CCI_REG8(0x41a2), 0xe9 }, + { CCI_REG8(0x41c8), 0xe2 }, + { CCI_REG8(0x41ca), 0xfd }, + { CCI_REG8(0x41dc), 0x67 }, + { CCI_REG8(0x41de), 0x82 }, + { CCI_REG8(0x41e0), 0xd4 }, + { CCI_REG8(0x41e2), 0xef }, + { CCI_REG8(0x4200), 0xde }, + { CCI_REG8(0x4202), 0xda }, + { CCI_REG8(0x4218), 0x63 }, + { CCI_REG8(0x421a), 0x5f }, + { CCI_REG8(0x421c), 0xd0 }, + { CCI_REG8(0x421e), 0xcc }, + { CCI_REG8(0x425a), 0x82 }, + { CCI_REG8(0x425c), 0xef }, + { CCI_REG8(0x4348), 0xfe }, + { CCI_REG8(0x4349), 0x06 }, + { CCI_REG8(0x4352), 0xce }, + { CCI_REG8(0x4420), 0x0b }, + { CCI_REG8(0x4421), 0x02 }, + { CCI_REG8(0x4422), 0x4d }, + { CCI_REG8(0x4423), 0x0a }, + { CCI_REG8(0x4426), 0xf5 }, + { CCI_REG8(0x442a), 0xe7 }, + { CCI_REG8(0x4432), 0xf5 }, + { CCI_REG8(0x4436), 0xe7 }, + { CCI_REG8(0x4466), 0xb4 }, + { CCI_REG8(0x446e), 0x32 }, + { CCI_REG8(0x449f), 0x1c }, + { CCI_REG8(0x44a4), 0x2c }, + { CCI_REG8(0x44a6), 0x2c }, + { CCI_REG8(0x44a8), 0x2c }, + { CCI_REG8(0x44aa), 0x2c }, + { CCI_REG8(0x44b4), 0x2c }, + { CCI_REG8(0x44b6), 0x2c }, + { CCI_REG8(0x44b8), 0x2c }, + { CCI_REG8(0x44ba), 0x2c }, + { CCI_REG8(0x44c4), 0x2c }, + { CCI_REG8(0x44c6), 0x2c }, + { CCI_REG8(0x44c8), 0x2c }, + { CCI_REG8(0x4506), 0xf3 }, + { CCI_REG8(0x450e), 0xe5 }, + { CCI_REG8(0x4516), 0xf3 }, + { CCI_REG8(0x4522), 0xe5 }, + { CCI_REG8(0x4524), 0xf3 }, + { CCI_REG8(0x452c), 0xe5 }, + { CCI_REG8(0x453c), 0x22 }, + { CCI_REG8(0x453d), 0x1b }, + { CCI_REG8(0x453e), 0x1b }, + { CCI_REG8(0x453f), 0x15 }, + { CCI_REG8(0x4540), 0x15 }, + { CCI_REG8(0x4541), 0x15 }, + { CCI_REG8(0x4542), 0x15 }, + { CCI_REG8(0x4543), 0x15 }, + { CCI_REG8(0x4544), 0x15 }, + { CCI_REG8(0x4548), 0x00 }, + { CCI_REG8(0x4549), 0x01 }, + { CCI_REG8(0x454a), 0x01 }, + { CCI_REG8(0x454b), 0x06 }, + { CCI_REG8(0x454c), 0x06 }, + { CCI_REG8(0x454d), 0x06 }, + { CCI_REG8(0x454e), 0x06 }, + { CCI_REG8(0x454f), 0x06 }, + { CCI_REG8(0x4550), 0x06 }, + { CCI_REG8(0x4554), 0x55 }, + { CCI_REG8(0x4555), 0x02 }, + { CCI_REG8(0x4556), 0x42 }, + { CCI_REG8(0x4557), 0x05 }, + { CCI_REG8(0x4558), 0xfd }, + { CCI_REG8(0x4559), 0x05 }, + { CCI_REG8(0x455a), 0x94 }, + { CCI_REG8(0x455b), 0x06 }, + { CCI_REG8(0x455d), 0x06 }, + { CCI_REG8(0x455e), 0x49 }, + { CCI_REG8(0x455f), 0x07 }, + { CCI_REG8(0x4560), 0x7f }, + { CCI_REG8(0x4561), 0x07 }, + { CCI_REG8(0x4562), 0xa5 }, + { CCI_REG8(0x4564), 0x55 }, + { CCI_REG8(0x4565), 0x02 }, + { CCI_REG8(0x4566), 0x42 }, + { CCI_REG8(0x4567), 0x05 }, + { CCI_REG8(0x4568), 0xfd }, + { CCI_REG8(0x4569), 0x05 }, + { CCI_REG8(0x456a), 0x94 }, + { CCI_REG8(0x456b), 0x06 }, + { CCI_REG8(0x456d), 0x06 }, + { CCI_REG8(0x456e), 0x49 }, + { CCI_REG8(0x456f), 0x07 }, + { CCI_REG8(0x4572), 0xa5 }, + { CCI_REG8(0x460c), 0x7d }, + { CCI_REG8(0x460e), 0xb1 }, + { CCI_REG8(0x4614), 0xa8 }, + { CCI_REG8(0x4616), 0xb2 }, + { CCI_REG8(0x461c), 0x7e }, + { CCI_REG8(0x461e), 0xa7 }, + { CCI_REG8(0x4624), 0xa8 }, + { CCI_REG8(0x4626), 0xb2 }, + { CCI_REG8(0x462c), 0x7e }, + { CCI_REG8(0x462e), 0x8a }, + { CCI_REG8(0x4630), 0x94 }, + { CCI_REG8(0x4632), 0xa7 }, + { CCI_REG8(0x4634), 0xfb }, + { CCI_REG8(0x4636), 0x2f }, + { CCI_REG8(0x4638), 0x81 }, + { CCI_REG8(0x4639), 0x01 }, + { CCI_REG8(0x463a), 0xb5 }, + { CCI_REG8(0x463b), 0x01 }, + { CCI_REG8(0x463c), 0x26 }, + { CCI_REG8(0x463e), 0x30 }, + { CCI_REG8(0x4640), 0xac }, + { CCI_REG8(0x4641), 0x01 }, + { CCI_REG8(0x4642), 0xb6 }, + { CCI_REG8(0x4643), 0x01 }, + { CCI_REG8(0x4644), 0xfc }, + { CCI_REG8(0x4646), 0x25 }, + { CCI_REG8(0x4648), 0x82 }, + { CCI_REG8(0x4649), 0x01 }, + { CCI_REG8(0x464a), 0xab }, + { CCI_REG8(0x464b), 0x01 }, + { CCI_REG8(0x464c), 0x26 }, + { CCI_REG8(0x464e), 0x30 }, + { CCI_REG8(0x4654), 0xfc }, + { CCI_REG8(0x4656), 0x08 }, + { CCI_REG8(0x4658), 0x12 }, + { CCI_REG8(0x465a), 0x25 }, + { CCI_REG8(0x4662), 0xfc }, + { CCI_REG8(0x46a2), 0xfb }, + { CCI_REG8(0x46d6), 0xf3 }, + { CCI_REG8(0x46e6), 0x00 }, + { CCI_REG8(0x46e8), 0xff }, + { CCI_REG8(0x46e9), 0x03 }, + { CCI_REG8(0x46ec), 0x7a }, + { CCI_REG8(0x46ee), 0xe5 }, + { CCI_REG8(0x46f4), 0xee }, + { CCI_REG8(0x46f6), 0xf2 }, + { CCI_REG8(0x470c), 0xff }, + { CCI_REG8(0x470d), 0x03 }, + { CCI_REG8(0x470e), 0x00 }, + { CCI_REG8(0x4714), 0xe0 }, + { CCI_REG8(0x4716), 0xe4 }, + { CCI_REG8(0x471e), 0xed }, + { CCI_REG8(0x472e), 0x00 }, + { CCI_REG8(0x4730), 0xff }, + { CCI_REG8(0x4731), 0x03 }, + { CCI_REG8(0x4734), 0x7b }, + { CCI_REG8(0x4736), 0xdf }, + { CCI_REG8(0x4754), 0x7d }, + { CCI_REG8(0x4756), 0x8b }, + { CCI_REG8(0x4758), 0x93 }, + { CCI_REG8(0x475a), 0xb1 }, + { CCI_REG8(0x475c), 0xfb }, + { CCI_REG8(0x475e), 0x09 }, + { CCI_REG8(0x4760), 0x11 }, + { CCI_REG8(0x4762), 0x2f }, + { CCI_REG8(0x4766), 0xcc }, + { CCI_REG8(0x4776), 0xcb }, + { CCI_REG8(0x477e), 0x4a }, + { CCI_REG8(0x478e), 0x49 }, + { CCI_REG8(0x4794), 0x7c }, + { CCI_REG8(0x4796), 0x8f }, + { CCI_REG8(0x4798), 0xb3 }, + { CCI_REG8(0x4799), 0x00 }, + { CCI_REG8(0x479a), 0xcc }, + { CCI_REG8(0x479c), 0xc1 }, + { CCI_REG8(0x479e), 0xcb }, + { CCI_REG8(0x47a4), 0x7d }, + { CCI_REG8(0x47a6), 0x8e }, + { CCI_REG8(0x47a8), 0xb4 }, + { CCI_REG8(0x47a9), 0x00 }, + { CCI_REG8(0x47aa), 0xc0 }, + { CCI_REG8(0x47ac), 0xfa }, + { CCI_REG8(0x47ae), 0x0d }, + { CCI_REG8(0x47b0), 0x31 }, + { CCI_REG8(0x47b1), 0x01 }, + { CCI_REG8(0x47b2), 0x4a }, + { CCI_REG8(0x47b3), 0x01 }, + { CCI_REG8(0x47b4), 0x3f }, + { CCI_REG8(0x47b6), 0x49 }, + { CCI_REG8(0x47bc), 0xfb }, + { CCI_REG8(0x47be), 0x0c }, + { CCI_REG8(0x47c0), 0x32 }, + { CCI_REG8(0x47c1), 0x01 }, + { CCI_REG8(0x47c2), 0x3e }, + { CCI_REG8(0x47c3), 0x01 }, + { IMX678_REG_WDMODE, 0x00 }, + { IMX678_REG_MDBIT, 0x01 }, + { IMX678_REG_XXS_DRV, 0x00 }, +}; + +static const u32 codes_bayer[] = { + MEDIA_BUS_FMT_SRGGB12_1X12, +}; + +static const u32 codes_monochrome[] = { + MEDIA_BUS_FMT_Y12_1X12, +}; + +static const struct imx678_model_info imx678_aaqr_info = { + .type = IMX678_COLOR, + .codes = codes_bayer, + .num_codes = ARRAY_SIZE(codes_bayer), +}; + +static const struct imx678_model_info imx678_aamr_info = { + .type = IMX678_MONOCHROME, + .codes = codes_monochrome, + .num_codes = ARRAY_SIZE(codes_monochrome), +}; + +static const char * const imx678_supply_name[] = { + "avdd", /* Analog (3.3V) supply */ + "dvdd", /* Digital Core (1.1V) supply */ + "ovdd", /* IF (1.8V) supply */ +}; + +struct imx678 { + struct v4l2_subdev sd; + struct media_pad pad; + struct regmap *cci; + + const struct imx678_model_info *info; + + struct clk *xclk; + u32 xclk_freq; + + /* chosen INCK_SEL register value */ + u8 inck_sel_val; + + /* Link configurations */ + enum imx678_lanemode lane_mode; + unsigned long link_freq_bitmap; + + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx678_supply_name)]; + + struct v4l2_ctrl_handler ctrl_handler; + + /* V4L2 Controls */ + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + + /* Track VMAX for exposure updates */ + u32 vmax; +}; + +static inline struct imx678 *to_imx678(struct v4l2_subdev *_sd) +{ + return container_of_const(_sd, struct imx678, sd); +} + +static u32 imx678_default_mbus_code(struct imx678 *imx678) +{ + return imx678->info->codes[0]; +} + +static bool imx678_mbus_code_supported(struct imx678 *imx678, u32 code) +{ + for (unsigned int i = 0; i < imx678->info->num_codes; i++) { + if (imx678->info->codes[i] == code) + return true; + } + + return false; +} + +static int imx678_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx678 *imx678 = container_of_const(ctrl->handler, struct + imx678, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd); + const struct v4l2_mbus_framefmt *format; + struct v4l2_subdev_state *state; + int ret = 0; + + state = v4l2_subdev_get_locked_active_state(&imx678->sd); + format = v4l2_subdev_state_get_format(state, IMX678_SOURCE_PAD); + + if (ctrl->id == V4L2_CID_VBLANK) { + u32 current_exposure = imx678->exposure->cur.val; + + imx678->vmax = format->height + ctrl->val; + + current_exposure = clamp_t(u32, current_exposure, + IMX678_EXPOSURE_MIN, + imx678->vmax - IMX678_SHR_MIN); + ret = __v4l2_ctrl_modify_range(imx678->exposure, + IMX678_EXPOSURE_MIN, + imx678->vmax - IMX678_SHR_MIN, + 1, current_exposure); + if (ret) + return ret; + } + + /* + * Only apply control values when device is powered on (RPM ACTIVE) + * and streaming (usage count != 0) + */ + if (!pm_runtime_get_if_in_use(&client->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_VBLANK: + cci_write(imx678->cci, IMX678_REG_VMAX, imx678->vmax, &ret); + fallthrough; /* SHR = VMAX - exposure, so update it */ + case V4L2_CID_EXPOSURE: { + u32 shr = imx678->vmax - imx678->exposure->val; + + cci_write(imx678->cci, IMX678_REG_SHR, shr, &ret); + break; + } + case V4L2_CID_ANALOGUE_GAIN: + cci_write(imx678->cci, IMX678_REG_GAIN, ctrl->val, &ret); + break; + case V4L2_CID_HBLANK: { + u32 hmax = (format->width + ctrl->val) / IMX678_PIX_PER_CLK; + + cci_write(imx678->cci, IMX678_REG_HMAX, hmax, &ret); + break; + } + case V4L2_CID_TEST_PATTERN: { + cci_write(imx678->cci, IMX678_REG_TPG_COLORWIDTH, + IMX678_TPG_COLORWIDTH_160PIX, &ret); + cci_write(imx678->cci, IMX678_REG_TPG_PATSEL_DUOUT, + imx678_tpg_val[ctrl->val], &ret); + cci_write(imx678->cci, IMX678_REG_TPG_EN_DUOUT, + (ctrl->val) ? 1 : 0, + &ret); + break; + } + case V4L2_CID_HFLIP: + cci_write(imx678->cci, IMX678_REG_WINMODEH, ctrl->val, &ret); + break; + case V4L2_CID_VFLIP: + cci_write(imx678->cci, IMX678_REG_WINMODEV, ctrl->val, &ret); + break; + default: + dev_warn(&client->dev, + "ctrl(id:0x%x,val:0x%x) is not handled\n", + ctrl->id, ctrl->val); + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops imx678_ctrl_ops = { + .s_ctrl = imx678_set_ctrl, +}; + +static int imx678_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct imx678 *imx678 = to_imx678(sd); + + if (code->index >= imx678->info->num_codes) + return -EINVAL; + + code->code = imx678->info->codes[code->index]; + + return 0; +} + +static int imx678_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct imx678 *imx678 = to_imx678(sd); + const struct v4l2_rect *crop; + + if (fse->index) + return -EINVAL; + + if (!imx678_mbus_code_supported(imx678, fse->code)) + return -EINVAL; + + crop = v4l2_subdev_state_get_crop(sd_state, fse->pad); + + fse->min_width = crop->width; + fse->max_width = fse->min_width; + fse->min_height = crop->height; + fse->max_height = fse->min_height; + + return 0; +} + +static int imx678_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); + return 0; + + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r = imx678_native_area; + return 0; + + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r = imx678_active_area; + return 0; + } + + return -EINVAL; +} + +static int imx678_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct imx678 *imx678 = to_imx678(sd); + struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; + + crop = v4l2_subdev_state_get_crop(state, IMX678_SOURCE_PAD); + *crop = imx678_active_area; + + format = v4l2_subdev_state_get_format(state, IMX678_SOURCE_PAD); + format->code = imx678_default_mbus_code(imx678); + format->width = imx678_active_area.width; + format->height = imx678_active_area.height; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_RAW; + format->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + format->quantization = V4L2_QUANTIZATION_FULL_RANGE; + format->xfer_func = V4L2_XFER_FUNC_NONE; + + return 0; +} + +static int imx678_write_common(struct imx678 *imx678) +{ + int ret = 0; + + cci_multi_reg_write(imx678->cci, common_regs, ARRAY_SIZE(common_regs), + &ret); + + cci_write(imx678->cci, IMX678_REG_INCK_SEL, imx678->inck_sel_val, &ret); + cci_write(imx678->cci, IMX678_REG_DATARATE_SEL, + link_freqs_reg_value[__ffs(imx678->link_freq_bitmap)], &ret); + cci_write(imx678->cci, IMX678_REG_LANEMODE, imx678->lane_mode, &ret); + + cci_write(imx678->cci, IMX678_REG_INTERFACE_SEL, IMX678_INTERFACE_2L_4L, + &ret); + + return ret; +} + +static int imx678_program_window(struct imx678 *imx678, + const struct v4l2_rect *crop) +{ + int ret = 0; + + cci_write(imx678->cci, IMX678_REG_ADDMODE, 0x00, &ret); + cci_write(imx678->cci, IMX678_REG_WINMODE, + v4l2_rect_equal(crop, &imx678_active_area) ? 0x00 : 0x04, + &ret); + cci_write(imx678->cci, IMX678_REG_PIX_HST, + crop->left - imx678_active_area.left, &ret); + cci_write(imx678->cci, IMX678_REG_PIX_HWIDTH, crop->width, &ret); + cci_write(imx678->cci, IMX678_REG_PIX_VST, + crop->top - imx678_active_area.top, &ret); + cci_write(imx678->cci, IMX678_REG_PIX_VWIDTH, crop->height, &ret); + cci_write(imx678->cci, IMX678_REG_ADBIT, 0x01, &ret); + + return ret; +} + +static int imx678_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 mask) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct imx678 *imx678 = to_imx678(sd); + const struct v4l2_rect *crop; + int ret; + + ret = pm_runtime_resume_and_get(&client->dev); + if (ret < 0) + return ret; + + crop = v4l2_subdev_state_get_crop(state, pad); + ret = imx678_program_window(imx678, crop); + if (ret) { + dev_err(&client->dev, "%s failed to set mode\n", __func__); + goto err_rpm_put; + } + + ret = __v4l2_ctrl_handler_setup(imx678->sd.ctrl_handler); + if (ret) { + dev_err(&client->dev, "%s failed to apply user values\n", + __func__); + goto err_rpm_put; + } + + cci_write(imx678->cci, IMX678_REG_MODE_SELECT, IMX678_MODE_STREAMING, + &ret); + usleep_range(IMX678_STREAM_DELAY_US, IMX678_STREAM_DELAY_US + + IMX678_STREAM_DELAY_RANGE_US); + cci_write(imx678->cci, IMX678_REG_XMSTA, 0x00, &ret); + + if (ret) { + dev_err(&client->dev, "%s failed to start streaming\n", + __func__); + goto err_rpm_put; + } + + return 0; + +err_rpm_put: + pm_runtime_put(&client->dev); + + return ret; +} + +static int imx678_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 mask) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct imx678 *imx678 = to_imx678(sd); + int ret = 0; + + /* Master mode disable */ + cci_write(imx678->cci, IMX678_REG_XMSTA, 0x01, &ret); + /* Standby */ + cci_write(imx678->cci, IMX678_REG_MODE_SELECT, IMX678_MODE_STANDBY, + &ret); + if (ret) + dev_err(&client->dev, "%s failed to stop stream\n", __func__); + + pm_runtime_put(&client->dev); + + return ret; +} + +static int imx678_power_on(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx678 *imx678 = to_imx678(sd); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(imx678_supply_name), + imx678->supplies); + if (ret) { + dev_err(&client->dev, "%s: failed to enable regulators\n", + __func__); + return ret; + } + + fsleep(1); /* Tlow > 500ns */ + + gpiod_set_value_cansleep(imx678->reset_gpio, 0); + + fsleep(1); /* T3 > 1us */ + + ret = clk_prepare_enable(imx678->xclk); + if (ret) { + dev_err(&client->dev, "%s: failed to enable clock\n", + __func__); + goto reg_off; + } + + fsleep(20); /* T4 > 20us */ + + ret = imx678_write_common(imx678); + if (ret) { + dev_err(&client->dev, "%s failed to write registers\n", + __func__); + goto clk_off; + } + + return 0; + +clk_off: + clk_disable_unprepare(imx678->xclk); + +reg_off: + gpiod_set_value_cansleep(imx678->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(imx678_supply_name), + imx678->supplies); + + return ret; +} + +static int imx678_power_off(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx678 *imx678 = to_imx678(sd); + + clk_disable_unprepare(imx678->xclk); + gpiod_set_value_cansleep(imx678->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(imx678_supply_name), + imx678->supplies); + + return 0; +} + +static int imx678_identify_model(struct imx678 *imx678) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd); + const struct imx678_model_info *info; + enum imx678_type detected; + int ret = 0; + u64 val = 0; + + info = device_get_match_data(&client->dev); + + /* + * This sensor's ID registers become accessible 80ms after coming out + * of STANDBY mode. + */ + cci_write(imx678->cci, IMX678_REG_MODE_SELECT, 0, &ret); + fsleep(IMX678_MODULE_ID_DELAY); + + cci_read(imx678->cci, IMX678_REG_MODULE_ID, &val, &ret); + + if (ret) { + dev_err(&client->dev, + "I2C transaction failed ret = %d\n", ret); + return ret; + } + + if (val != IMX678_ID) { + dev_err(&client->dev, + "Chip ID mismatch: %x!=%llx\n", IMX678_ID, val); + return -ENXIO; + } + + cci_read(imx678->cci, IMX678_REG_MONOCHROME, &val, &ret); + + if (ret) { + dev_err(&client->dev, + "I2C transaction failed ret = %d\n", ret); + return ret; + } + + detected = val & IMX678_TYPE; + + /* Prefer to use sensor type specified in device tree */ + if (info) { + imx678->info = info; + if (detected != info->type) + dev_err(&client->dev, + "detected %s sensor, DT specifies %s; using DT value\n", + detected == IMX678_COLOR ? "color" : "mono", + info->type == IMX678_COLOR ? "color" : "mono"); + } else { + imx678->info = detected == IMX678_MONOCHROME ? + &imx678_aamr_info : &imx678_aaqr_info; + dev_info(&client->dev, + "sensor type missing in DT; detected %s sensor\n", + detected == IMX678_MONOCHROME ? "mono" : "color"); + } + + return 0; +} + +static const struct v4l2_subdev_video_ops imx678_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops imx678_pad_ops = { + .enum_mbus_code = imx678_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = v4l2_subdev_get_fmt, + .get_selection = imx678_get_selection, + .enum_frame_size = imx678_enum_frame_size, + .enable_streams = imx678_enable_streams, + .disable_streams = imx678_disable_streams, +}; + +static const struct v4l2_subdev_ops imx678_subdev_ops = { + .video = &imx678_video_ops, + .pad = &imx678_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops imx678_internal_ops = { + .init_state = imx678_init_state, +}; + +static int imx678_init_controls(struct imx678 *imx678) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + const u32 hmax_4lane = min_hmax_4lane[__ffs(imx678->link_freq_bitmap)]; + const u32 lane_scale = imx678->lane_mode == IMX678_LANEMODE_2L ? 2 : 1; + struct i2c_client *client = v4l2_get_subdevdata(&imx678->sd); + struct v4l2_fwnode_device_properties props; + struct v4l2_ctrl *link_freq; + s32 hblank, max_hblank, vblank, max_vblank; + u32 hmax; + int ret; + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret < 0) + return ret; + + ctrl_hdlr = &imx678->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 11); + if (ret) + return ret; + + imx678->vmax = IMX678_VMAX_DEFAULT; + hmax = hmax_4lane * lane_scale; + + /* PIXEL_RATE is fixed and read-only */ + v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_PIXEL_RATE, + IMX678_PIXEL_RATE, IMX678_PIXEL_RATE, 1, + IMX678_PIXEL_RATE); + + /* LINK_FREQ is also read only */ + link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freqs) - 1, + __ffs(imx678->link_freq_bitmap), + link_freqs); + + if (link_freq) + link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vblank = imx678->vmax - imx678_active_area.height; + max_vblank = IMX678_VMAX_MAX - imx678_active_area.height; + imx678->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_VBLANK, vblank, max_vblank, + 2, vblank); + + hblank = hmax * IMX678_PIX_PER_CLK - imx678_active_area.width; + max_hblank = IMX678_HMAX_MAX * IMX678_PIX_PER_CLK - + imx678_active_area.width; + imx678->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_HBLANK, hblank, max_hblank, + IMX678_PIX_PER_CLK, hblank); + + imx678->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX678_EXPOSURE_MIN, + IMX678_VMAX_DEFAULT - + IMX678_SHR_MIN, + IMX678_EXPOSURE_STEP, + IMX678_EXPOSURE_DEFAULT); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + IMX678_ANA_GAIN_MIN_NORMAL, + IMX678_ANA_GAIN_MAX_NORMAL, IMX678_ANA_GAIN_STEP, + IMX678_ANA_GAIN_DEFAULT); + + v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_HFLIP, + 0, 1, 1, 0); + v4l2_ctrl_new_std(ctrl_hdlr, &imx678_ctrl_ops, V4L2_CID_VFLIP, + 0, 1, 1, 0); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx678_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(imx678_tpg_menu) - 1, 0, 0, + imx678_tpg_menu); + + v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx678_ctrl_ops, &props); + + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + dev_err(&client->dev, "%s control init failed (%d)\n", + __func__, ret); + v4l2_ctrl_handler_free(ctrl_hdlr); + return ret; + } + + imx678->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +static int imx678_check_hwcfg(struct device *dev, struct imx678 *imx678) +{ + struct fwnode_handle *endpoint; + struct v4l2_fwnode_endpoint ep_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + int ret = -EINVAL; + + endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); + if (!endpoint) { + dev_err(dev, "endpoint node not found\n"); + return -EINVAL; + } + + if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep_cfg)) { + dev_err(dev, "could not parse endpoint\n"); + goto error_out; + } + + switch (ep_cfg.bus.mipi_csi2.num_data_lanes) { + case 2: + imx678->lane_mode = IMX678_LANEMODE_2L; + break; + case 4: + imx678->lane_mode = IMX678_LANEMODE_4L; + break; + default: + dev_err(dev, + "only 2 or 4 CSI2 data lanes are currently supported\n"); + goto error_out; + } + + ret = v4l2_link_freq_to_bitmap(dev, ep_cfg.link_frequencies, + ep_cfg.nr_of_link_frequencies, + link_freqs, ARRAY_SIZE(link_freqs), + &imx678->link_freq_bitmap); + +error_out: + v4l2_fwnode_endpoint_free(&ep_cfg); + fwnode_handle_put(endpoint); + + return ret; +} + +static int imx678_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct imx678 *imx678; + int ret, i; + + imx678 = devm_kzalloc(&client->dev, sizeof(*imx678), GFP_KERNEL); + if (!imx678) + return -ENOMEM; + + v4l2_i2c_subdev_init(&imx678->sd, client, &imx678_subdev_ops); + + imx678->cci = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(imx678->cci)) + return dev_err_probe(dev, PTR_ERR(imx678->cci), + "failed to init CCI\n"); + + if (imx678_check_hwcfg(dev, imx678)) + return -EINVAL; + + imx678->xclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(imx678->xclk)) + return dev_err_probe(dev, PTR_ERR(imx678->xclk), + "failed to get xclk\n"); + + imx678->xclk_freq = clk_get_rate(imx678->xclk); + + for (i = 0; i < ARRAY_SIZE(imx678_inck_table); ++i) { + if (imx678_inck_table[i].xclk_hz == imx678->xclk_freq) { + imx678->inck_sel_val = imx678_inck_table[i].inck_sel; + break; + } + } + + if (i == ARRAY_SIZE(imx678_inck_table)) + return dev_err_probe(dev, -EINVAL, + "unsupported XCLK rate %u Hz\n", + imx678->xclk_freq); + + for (i = 0; i < ARRAY_SIZE(imx678_supply_name); i++) + imx678->supplies[i].supply = imx678_supply_name[i]; + + ret = devm_regulator_bulk_get(&client->dev, + ARRAY_SIZE(imx678_supply_name), + imx678->supplies); + if (ret) + return dev_err_probe(dev, ret, "failed to get regulators\n"); + + imx678->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(imx678->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(imx678->reset_gpio), + "failed to get reset GPIO\n"); + + ret = imx678_power_on(dev); + if (ret) + return ret; + + ret = imx678_identify_model(imx678); + if (ret) + goto error_power_off; + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + ret = imx678_init_controls(imx678); + if (ret) + goto error_pm_runtime; + + imx678->sd.internal_ops = &imx678_internal_ops; + imx678->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx678->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + imx678->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&imx678->sd.entity, 1, &imx678->pad); + if (ret) { + dev_err_probe(dev, ret, "failed to init entity pads\n"); + goto error_handler_free; + } + + imx678->sd.state_lock = imx678->ctrl_handler.lock; + ret = v4l2_subdev_init_finalize(&imx678->sd); + if (ret < 0) { + dev_err_probe(dev, ret, "subdev init error\n"); + goto error_media_entity; + } + + ret = v4l2_async_register_subdev_sensor(&imx678->sd); + if (ret < 0) { + dev_err_probe(dev, ret, + "failed to register sensor sub-device\n"); + goto error_subdev_cleanup; + } + + pm_runtime_idle(dev); + + return 0; + +error_subdev_cleanup: + v4l2_subdev_cleanup(&imx678->sd); + +error_media_entity: + media_entity_cleanup(&imx678->sd.entity); + +error_handler_free: + v4l2_ctrl_handler_free(imx678->sd.ctrl_handler); + +error_pm_runtime: + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + +error_power_off: + imx678_power_off(&client->dev); + + return ret; +} + +static void imx678_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx678 *imx678 = to_imx678(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(imx678->sd.ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + imx678_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); +} + +static const struct dev_pm_ops imx678_pm_ops = { + SET_RUNTIME_PM_OPS(imx678_power_off, imx678_power_on, NULL) +}; + +static const struct of_device_id imx678_of_match[] = { + { .compatible = "sony,imx678-aamr", .data = &imx678_aamr_info }, + { .compatible = "sony,imx678-aaqr", .data = &imx678_aaqr_info }, + /* for non-conforming DTs that rely on runtime check */ + { .compatible = "sony,imx678" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, imx678_of_match); + +static struct i2c_driver imx678_i2c_driver = { + .driver = { + .name = "imx678", + .of_match_table = imx678_of_match, + .pm = pm_ptr(&imx678_pm_ops), + }, + .probe = imx678_probe, + .remove = imx678_remove, +}; + +module_i2c_driver(imx678_i2c_driver); + +MODULE_AUTHOR("Will Whang <will@willwhang.com>"); +MODULE_AUTHOR("Tetsuya NOMURA <tetsuya.nomura@soho-enterprise.com>"); +MODULE_AUTHOR("Jai Luthra <jai.luthra@ideasonboard.com>"); +MODULE_DESCRIPTION("Sony imx678 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index ac0712ce1e65..79eab9045e24 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -1062,7 +1062,7 @@ static int max9286_v4l2_register(struct max9286_priv *priv) priv->sd.state_lock = priv->ctrls.lock; ret = v4l2_subdev_init_finalize(&priv->sd); if (ret) - goto err_async; + goto err_entity; ret = v4l2_async_register_subdev(&priv->sd); if (ret < 0) { @@ -1074,6 +1074,8 @@ static int max9286_v4l2_register(struct max9286_priv *priv) err_subdev: v4l2_subdev_cleanup(&priv->sd); +err_entity: + media_entity_cleanup(&priv->sd.entity); err_async: v4l2_ctrl_handler_free(&priv->ctrls); max9286_v4l2_notifier_unregister(priv); @@ -1084,6 +1086,7 @@ err_async: static void max9286_v4l2_unregister(struct max9286_priv *priv) { v4l2_subdev_cleanup(&priv->sd); + media_entity_cleanup(&priv->sd.entity); v4l2_ctrl_handler_free(&priv->ctrls); v4l2_async_unregister_subdev(&priv->sd); max9286_v4l2_notifier_unregister(priv); diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 413cfbc2dd94..a540b211f7d7 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -717,6 +717,7 @@ static int msp_probe(struct i2c_client *client) if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { dev_dbg_lvl(&client->dev, 1, msp_debug, "not an msp3400 (cannot read chip version)\n"); + media_entity_cleanup(&sd->entity); return -ENODEV; } @@ -812,6 +813,7 @@ static int msp_probe(struct i2c_client *client) int err = hdl->error; v4l2_ctrl_handler_free(hdl); + media_entity_cleanup(&sd->entity); return err; } @@ -865,6 +867,7 @@ static void msp_remove(struct i2c_client *client) msp_reset(client); v4l2_ctrl_handler_free(&state->hdl); + media_entity_cleanup(&state->sd.entity); } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index d21510caf45a..2b09e8315c8e 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -452,11 +452,7 @@ static int mt9p031_set_params(struct mt9p031 *mt9p031) ret = mt9p031_write(client, MT9P031_HORIZONTAL_BLANK, hblank - 1); if (ret < 0) return ret; - ret = mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank - 1); - if (ret < 0) - return ret; - - return ret; + return mt9p031_write(client, MT9P031_VERTICAL_BLANK, vblank - 1); } static int mt9p031_s_stream(struct v4l2_subdev *subdev, int enable) diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index bd2268154ca7..b3a6c6d76632 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -1079,11 +1079,12 @@ static int mt9t112_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); priv->clk = devm_v4l2_sensor_clk_get(&client->dev, "extclk"); - if (PTR_ERR(priv->clk) == -ENOENT) + if (IS_ERR(priv->clk)) { + if (PTR_ERR(priv->clk) != -ENOENT) + return dev_err_probe(&client->dev, PTR_ERR(priv->clk), + "Unable to get clock \"extclk\"\n"); priv->clk = NULL; - else if (IS_ERR(priv->clk)) - return dev_err_probe(&client->dev, PTR_ERR(priv->clk), - "Unable to get clock \"extclk\"\n"); + } priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", GPIOD_OUT_HIGH); diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 985517f1cff7..ff55a8ff32b4 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -520,6 +520,7 @@ static int mt9v011_probe(struct i2c_client *c) (version != MT9V011_REV_B_VERSION)) { v4l2_info(sd, "*** unknown micron chip detected (0x%04x).\n", version); + media_entity_cleanup(&sd->entity); return -EINVAL; } @@ -542,6 +543,7 @@ static int mt9v011_probe(struct i2c_client *c) v4l2_err(sd, "control initialization error %d\n", ret); v4l2_ctrl_handler_free(&core->ctrls); + media_entity_cleanup(&sd->entity); return ret; } core->sd.ctrl_handler = &core->ctrls; @@ -577,6 +579,7 @@ static void mt9v011_remove(struct i2c_client *c) v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&core->ctrls); + media_entity_cleanup(&sd->entity); } /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 143dcfe10445..0150e4d296af 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -820,18 +820,16 @@ static int ov02a10_check_hwcfg(struct device *dev, struct ov02a10 *ov02a10) if (!ep) return -ENXIO; + /* Optional indication of MIPI clock voltage unit */ + if (!fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage", + &clk_volt)) + ov02a10->mipi_clock_voltage = clk_volt; + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); if (ret) return ret; - /* Optional indication of MIPI clock voltage unit */ - ret = fwnode_property_read_u32(ep, "ovti,mipi-clock-voltage", - &clk_volt); - - if (!ret) - ov02a10->mipi_clock_voltage = clk_volt; - for (i = 0; i < ARRAY_SIZE(link_freq_menu_items); i++) { for (j = 0; j < bus_cfg.nr_of_link_frequencies; j++) { if (link_freq_menu_items[i] == diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index fb590dfadda1..39003c1632ad 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -1241,41 +1241,42 @@ exit: return ret; } +static const struct regmap_config regmap_config = { + .val_bits = 8, + .reg_bits = 16, + .disable_locking = true, +}; + static int ov2740_register_nvmem(struct i2c_client *client, struct ov2740 *ov2740) { struct nvm_data *nvm; - struct regmap_config regmap_config = { }; - struct nvmem_config nvmem_config = { }; struct regmap *regmap; struct device *dev = ov2740->dev; + struct nvmem_config nvmem_config = { + .name = dev_name(dev), + .dev = dev, + .read_only = true, + .root_only = true, + .owner = THIS_MODULE, + .compat = true, + .base_dev = dev, + .reg_read = ov2740_nvmem_read, + .stride = 1, + .word_size = 1, + .size = CUSTOMER_USE_OTP_SIZE, + }; nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL); if (!nvm) return -ENOMEM; - regmap_config.val_bits = 8; - regmap_config.reg_bits = 16; - regmap_config.disable_locking = true; regmap = devm_regmap_init_i2c(client, ®map_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); nvm->regmap = regmap; - - nvmem_config.name = dev_name(dev); - nvmem_config.dev = dev; - nvmem_config.read_only = true; - nvmem_config.root_only = true; - nvmem_config.owner = THIS_MODULE; - nvmem_config.compat = true; - nvmem_config.base_dev = dev; - nvmem_config.reg_read = ov2740_nvmem_read; - nvmem_config.reg_write = NULL; nvmem_config.priv = nvm; - nvmem_config.stride = 1; - nvmem_config.word_size = 1; - nvmem_config.size = CUSTOMER_USE_OTP_SIZE; nvm->nvmem = devm_nvmem_register(dev, &nvmem_config); if (IS_ERR(nvm->nvmem)) diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index c2e02f191816..b4e14171556f 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -1116,18 +1116,14 @@ static void ov7740_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); - mutex_destroy(&ov7740->mutex); - v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); - media_entity_cleanup(&ov7740->subdev.entity); v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&ov7740->subdev.entity); ov7740_free_controls(ov7740); - pm_runtime_get_sync(&client->dev); pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ov7740_set_power(ov7740, 0); pm_runtime_set_suspended(&client->dev); - pm_runtime_put_noidle(&client->dev); - - ov7740_set_power(ov7740, 0); } static int __maybe_unused ov7740_runtime_suspend(struct device *dev) diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index 8c9cd769fa01..289a34a3eeb1 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -2608,7 +2608,7 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable) { struct ov8865_sensor *sensor = ov8865_subdev_sensor(subdev); struct ov8865_state *state = &sensor->state; - int ret; + int ret = 0; if (enable) { ret = pm_runtime_resume_and_get(sensor->dev); @@ -2617,18 +2617,32 @@ static int ov8865_s_stream(struct v4l2_subdev *subdev, int enable) } mutex_lock(&sensor->mutex); - ret = ov8865_sw_standby(sensor, !enable); - mutex_unlock(&sensor->mutex); - if (ret) - return ret; + /* + * The sensor may have been kept powered by something else (e.g. the + * VCM's runtime PM device link on IPU3 platforms), in which case + * runtime resume did not run and the hardware may still be + * configured for a previous mode. Always program the negotiated + * configuration on stream start. + */ + if (enable) { + ret = ov8865_sensor_init(sensor); + if (!ret) + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + } - state->streaming = !!enable; + if (!ret) + ret = ov8865_sw_standby(sensor, !enable); + + mutex_unlock(&sensor->mutex); - if (!enable) + if (ret || !enable) pm_runtime_put(sensor->dev); - return 0; + if (!ret) + state->streaming = enable; + + return ret; } static const struct v4l2_subdev_video_ops ov8865_subdev_video_ops = { @@ -2915,15 +2929,15 @@ static int ov8865_resume(struct device *dev) if (ret) goto complete; - ret = ov8865_sensor_init(sensor); - if (ret) - goto error_power; + if (state->streaming) { + ret = ov8865_sensor_init(sensor); + if (ret) + goto error_power; - ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); - if (ret) - goto error_power; + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + if (ret) + goto error_power; - if (state->streaming) { ret = ov8865_sw_standby(sensor, false); if (ret) goto error_power; diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index 5b6f897a74fc..5d301660a87d 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -197,7 +197,6 @@ struct ov9282_mode { * @noncontinuous_clock: Selection of CSI2 noncontinuous clock mode * @cur_mode: Pointer to current selected sensor mode * @code: Mbus code currently selected - * @mutex: Mutex for serializing sensor controls */ struct ov9282 { struct device *dev; @@ -648,7 +647,8 @@ static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl) ctrl->val ? OV9282_OUTPUT_ENABLE6_STROBE : 0, NULL); break; case V4L2_CID_FLASH_DURATION: - ret = cci_write(ov9282->regmap, OV9282_REG_STROBE_FRAME_SPAN, ctrl->val, NULL); + ret = cci_write(ov9282->regmap, OV9282_REG_STROBE_FRAME_SPAN, + ov9282_us_to_flash_duration(ov9282, ctrl->val), NULL); break; default: dev_err(ov9282->dev, "Invalid control %d", ctrl->id); diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c index bcab462708c7..ece8a410e7ce 100644 --- a/drivers/media/i2c/rdacm21.c +++ b/drivers/media/i2c/rdacm21.c @@ -588,10 +588,12 @@ static int rdacm21_probe(struct i2c_client *client) ret = v4l2_async_register_subdev(&dev->sd); if (ret) - goto error_free_ctrls; + goto error_entity_cleanup; return 0; +error_entity_cleanup: + media_entity_cleanup(&dev->sd.entity); error_free_ctrls: v4l2_ctrl_handler_free(&dev->ctrls); error: @@ -606,6 +608,7 @@ static void rdacm21_remove(struct i2c_client *client) v4l2_async_unregister_subdev(&dev->sd); v4l2_ctrl_handler_free(&dev->ctrls); + media_entity_cleanup(&dev->sd.entity); i2c_unregister_device(dev->isp); } diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index 7cce90750c93..d20695238b48 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1867,6 +1867,7 @@ static int saa711x_probe(struct i2c_client *client) int err = hdl->error; v4l2_ctrl_handler_free(hdl); + media_entity_cleanup(&sd->entity); return err; } v4l2_ctrl_auto_cluster(2, &state->agc, 0, true); @@ -1925,6 +1926,7 @@ static void saa711x_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(sd->ctrl_handler); + media_entity_cleanup(&sd->entity); } static const struct i2c_device_id saa711x_id[] = { diff --git a/drivers/media/i2c/vd55g1.c b/drivers/media/i2c/vd55g1.c index 78d18c028154..6f458f611f63 100644 --- a/drivers/media/i2c/vd55g1.c +++ b/drivers/media/i2c/vd55g1.c @@ -29,11 +29,7 @@ /* Register Map */ #define VD55G1_REG_MODEL_ID CCI_REG32_LE(0x0000) -#define VD55G1_MODEL_ID_VD55G1 0x53354731 /* Mono */ -#define VD55G1_MODEL_ID_VD65G4 0x53354733 /* RGB */ -#define VD55G1_REG_REVISION CCI_REG16_LE(0x0004) -#define VD55G1_REVISION_CCB 0x2020 -#define VD55G1_REVISION_BAYER 0x3030 +#define VD55G1_REG_COLOR_VERSION CCI_REG32_LE(0x0670) #define VD55G1_REG_FWPATCH_REVISION CCI_REG16_LE(0x0012) #define VD55G1_REG_FWPATCH_START_ADDR CCI_REG8(0x2000) #define VD55G1_REG_SYSTEM_FSM CCI_REG8(0x001c) @@ -60,7 +56,10 @@ #define VD55G1_PATGEN_ENABLE BIT(0) #define VD55G1_REG_MANUAL_ANALOG_GAIN CCI_REG8(0x0501) #define VD55G1_REG_MANUAL_COARSE_EXPOSURE CCI_REG16_LE(0x0502) -#define VD55G1_REG_MANUAL_DIGITAL_GAIN CCI_REG16_LE(0x0504) +#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH0 CCI_REG16_LE(0x0504) +#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH1 CCI_REG16_LE(0x0506) +#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH2 CCI_REG16_LE(0x0508) +#define VD55G1_REG_MANUAL_DIGITAL_GAIN_CH3 CCI_REG16_LE(0x050a) #define VD55G1_REG_APPLIED_COARSE_EXPOSURE CCI_REG16_LE(0x00e8) #define VD55G1_REG_APPLIED_ANALOG_GAIN CCI_REG16_LE(0x00ea) #define VD55G1_REG_APPLIED_DIGITAL_GAIN CCI_REG16_LE(0x00ec) @@ -114,9 +113,8 @@ #define VD55G1_WIDTH 804 #define VD55G1_HEIGHT 704 -#define VD55G1_MODE_DEF 0 +#define VD55G1_MODE_IDX_DEF 0 #define VD55G1_NB_GPIOS 4 -#define VD55G1_MBUS_CODE_DEF 0 #define VD55G1_DGAIN_DEF 256 #define VD55G1_AGAIN_DEF 19 #define VD55G1_EXPO_MAX_TERM 64 @@ -135,8 +133,39 @@ #define VD55G1_MIPI_RATE_MIN (250 * MEGA) #define VD55G1_MIPI_RATE_MAX (1200 * MEGA) -#define VD55G1_MODEL_ID_NAME(id) \ - ((id) == VD55G1_MODEL_ID_VD55G1 ? "vd55g1" : "vd65g4") +enum vd55g1_model_id { + VD55G1_MODEL_ID_2 = 0x53354731, + VD55G1_MODEL_ID_3 = 0x53354733, +}; + +enum vd55g1_color_version { + VD55G1_COLOR_VERSION_MONO, + VD55G1_COLOR_VERSION_BAYER, +}; + +struct vd55g1_version { + char *name; + enum vd55g1_model_id id; + enum vd55g1_color_version color; +}; + +static const struct vd55g1_version vd55g1_versions[] = { + { + .name = "vd55g1", + .id = VD55G1_MODEL_ID_2, + .color = VD55G1_COLOR_VERSION_MONO, + }, + { + .name = "vd55g4", + .id = VD55G1_MODEL_ID_3, + .color = VD55G1_COLOR_VERSION_MONO, + }, + { + .name = "vd65g4", + .id = VD55G1_MODEL_ID_3, + .color = VD55G1_COLOR_VERSION_BAYER, + }, +}; static const u8 vd55g1_patch_array[] = { 0x44, 0x03, 0x09, 0x02, 0xe6, 0x01, 0x42, 0x00, 0xea, 0x01, 0x42, 0x00, @@ -532,7 +561,7 @@ struct vd55g1_vblank_limits { struct vd55g1 { struct device *dev; - unsigned int id; + const struct vd55g1_version *version; struct v4l2_subdev sd; struct media_pad pad; struct regulator_bulk_data supplies[ARRAY_SIZE(vd55g1_supply_name)]; @@ -623,20 +652,28 @@ static unsigned int vd55g1_get_fmt_data_type(u32 code) static u32 vd55g1_get_fmt_code(struct vd55g1 *sensor, u32 code) { + u32 fallback_code; unsigned int i, j; - if (sensor->id == VD55G1_MODEL_ID_VD55G1) - return code; - - for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_bayer); i++) { - for (j = 0; j < ARRAY_SIZE(vd55g1_mbus_formats_bayer[i]); j++) { - if (vd55g1_mbus_formats_bayer[i][j] == code) - goto adapt_bayer_pattern; + if (sensor->version->color == VD55G1_COLOR_VERSION_MONO) { + fallback_code = vd55g1_mbus_formats_mono[0]; + for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_mono); i++) + if (vd55g1_mbus_formats_mono[i] == code) + return code; + } else { + fallback_code = vd55g1_mbus_formats_bayer[0][0]; + for (i = 0; i < ARRAY_SIZE(vd55g1_mbus_formats_bayer); i++) { + for (j = 0; + j < ARRAY_SIZE(vd55g1_mbus_formats_bayer[i]); + j++) { + if (vd55g1_mbus_formats_bayer[i][j] == code) + goto adapt_bayer_pattern; + } } } - dev_warn(sensor->dev, "Unsupported mbus format\n"); + dev_warn(sensor->dev, "Unsupported mbus format: 0x%x\n", code); - return code; + return fallback_code; adapt_bayer_pattern: j = 0; @@ -649,12 +686,6 @@ adapt_bayer_pattern: return vd55g1_mbus_formats_bayer[i][j]; } -static s32 vd55g1_get_pixel_rate(struct vd55g1 *sensor, - struct v4l2_mbus_framefmt *format) -{ - return sensor->mipi_rate / vd55g1_get_fmt_bpp(format->code); -} - static unsigned int vd55g1_get_hblank_min(struct vd55g1 *sensor, struct v4l2_mbus_framefmt *format, struct v4l2_rect *crop) @@ -850,9 +881,16 @@ static int vd55g1_update_expo_cluster(struct vd55g1 *sensor, bool is_auto) vd55g1_write(sensor, VD55G1_REG_MANUAL_ANALOG_GAIN, sensor->again_ctrl->val, &ret); - if (!is_auto && sensor->dgain_ctrl->is_new) - vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN, + if (!is_auto && sensor->dgain_ctrl->is_new) { + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH0, sensor->dgain_ctrl->val, &ret); + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH1, + sensor->dgain_ctrl->val, &ret); + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH2, + sensor->dgain_ctrl->val, &ret); + vd55g1_write(sensor, VD55G1_REG_MANUAL_DIGITAL_GAIN_CH3, + sensor->dgain_ctrl->val, &ret); + } return ret; } @@ -1173,8 +1211,8 @@ static int vd55g1_patch(struct vd55g1 *sensor) u64 patch; int ret = 0; - /* vd55g1 needs a patch while vd65g4 does not */ - if (sensor->id == VD55G1_MODEL_ID_VD55G1) { + /* Version 2 needs a patch while version 3 does not */ + if (sensor->version->id == VD55G1_MODEL_ID_2) { vd55g1_write_array(sensor, VD55G1_REG_FWPATCH_START_ADDR, sizeof(vd55g1_patch_array), vd55g1_patch_array, &ret); @@ -1246,7 +1284,7 @@ static int vd55g1_enum_mbus_code(struct v4l2_subdev *sd, struct vd55g1 *sensor = to_vd55g1(sd); u32 base_code; - if (sensor->id == VD55G1_MODEL_ID_VD55G1) { + if (sensor->version->color != VD55G1_COLOR_VERSION_BAYER) { if (code->index >= ARRAY_SIZE(vd55g1_mbus_formats_mono)) return -EINVAL; base_code = vd55g1_mbus_formats_mono[code->index]; @@ -1285,12 +1323,6 @@ static int vd55g1_new_format_change_controls(struct vd55g1 *sensor, if (ret) return ret; - /* Update pixel rate to reflect new bpp */ - ret = __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_ctrl, - vd55g1_get_pixel_rate(sensor, format)); - if (ret) - return ret; - /* Update hblank according to new width */ hblank = vd55g1_get_hblank_min(sensor, format, crop); ret = __v4l2_ctrl_modify_range(sensor->hblank_ctrl, hblank, hblank, 1, @@ -1347,6 +1379,7 @@ static int vd55g1_init_state(struct v4l2_subdev *sd, { struct vd55g1 *sensor = to_vd55g1(sd); struct v4l2_subdev_format fmt = { 0 }; + int code; struct v4l2_subdev_route routes[] = { { .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE } }; @@ -1361,9 +1394,13 @@ static int vd55g1_init_state(struct v4l2_subdev *sd, if (ret) return ret; - vd55g1_update_pad_fmt(sensor, &vd55g1_supported_modes[VD55G1_MODE_DEF], - vd55g1_get_fmt_code(sensor, VD55G1_MBUS_CODE_DEF), - &fmt.format); + if (sensor->version->color != VD55G1_COLOR_VERSION_BAYER) + code = vd55g1_mbus_formats_mono[0]; + else + code = vd55g1_mbus_formats_bayer[0][0]; + fmt.format.code = vd55g1_get_fmt_code(sensor, code); + fmt.format.width = vd55g1_supported_modes[VD55G1_MODE_IDX_DEF].width; + fmt.format.height = vd55g1_supported_modes[VD55G1_MODE_IDX_DEF].height; return vd55g1_set_pad_fmt(sd, sd_state, &fmt); } @@ -1549,7 +1586,6 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor) v4l2_subdev_state_get_crop(state, 0); struct v4l2_mbus_framefmt *format = v4l2_subdev_state_get_format(state, 0); - s32 pixel_rate = vd55g1_get_pixel_rate(sensor, format); int ret; v4l2_ctrl_handler_init(hdl, 16); @@ -1591,7 +1627,7 @@ static int vd55g1_init_ctrls(struct vd55g1 *sensor) sensor->pixel_rate_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, - pixel_rate); + sensor->pixel_clock); if (sensor->pixel_rate_ctrl) sensor->pixel_rate_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; sensor->ae_lock_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_3A_LOCK, @@ -1644,38 +1680,46 @@ unlock_state: return ret; } +static const struct vd55g1_version * +vd55g1_get_version(enum vd55g1_model_id id, + enum vd55g1_color_version color) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(vd55g1_versions); i++) { + if (vd55g1_versions[i].id == id && + vd55g1_versions[i].color == color) + return &vd55g1_versions[i]; + } + + return NULL; +} + static int vd55g1_detect(struct vd55g1 *sensor) { - unsigned int dt_id = (uintptr_t)device_get_match_data(sensor->dev); - u64 rev, id; - int ret; + const struct vd55g1_version *dt_version = + device_get_match_data(sensor->dev); + const struct vd55g1_version *version; + u64 color, id; + int ret = 0; - ret = vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, NULL); + vd55g1_read(sensor, VD55G1_REG_MODEL_ID, &id, &ret); + vd55g1_read(sensor, VD55G1_REG_COLOR_VERSION, &color, &ret); if (ret) return ret; - if (id != VD55G1_MODEL_ID_VD55G1 && id != VD55G1_MODEL_ID_VD65G4) { - dev_warn(sensor->dev, "Unsupported sensor id 0x%x\n", - (u32)id); + version = vd55g1_get_version(id, color); + if (!version) { + dev_warn(sensor->dev, "Unsupported sensor version, expected %s\n", + dt_version->name); return -ENODEV; } - if (id != dt_id) { - dev_err(sensor->dev, "Probed sensor %s and device tree definition (%s) mismatch", - VD55G1_MODEL_ID_NAME(id), VD55G1_MODEL_ID_NAME(dt_id)); + if (version->id != dt_version->id || + version->color != dt_version->color) { + dev_err(sensor->dev, "Probed sensor version %s and device tree definition %s mismatch", + version->name, dt_version->name); return -ENODEV; } - sensor->id = id; - ret = vd55g1_read(sensor, VD55G1_REG_REVISION, &rev, NULL); - if (ret) - return ret; - - if ((id == VD55G1_MODEL_ID_VD55G1 && rev != VD55G1_REVISION_CCB) && - (id == VD55G1_MODEL_ID_VD65G4 && rev != VD55G1_REVISION_BAYER)) { - dev_err(sensor->dev, "Unsupported sensor revision 0x%x for sensor %s\n", - (u16)rev, VD55G1_MODEL_ID_NAME(id)); - return -ENODEV; - } + sensor->version = version; return 0; } @@ -2033,8 +2077,9 @@ static void vd55g1_remove(struct i2c_client *client) } static const struct of_device_id vd55g1_dt_ids[] = { - { .compatible = "st,vd55g1", .data = (void *)VD55G1_MODEL_ID_VD55G1 }, - { .compatible = "st,vd65g4", .data = (void *)VD55G1_MODEL_ID_VD65G4 }, + { .compatible = "st,vd55g1", .data = (void *)&vd55g1_versions[0] }, + { .compatible = "st,vd55g4", .data = (void *)&vd55g1_versions[1] }, + { .compatible = "st,vd65g4", .data = (void *)&vd55g1_versions[2] }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, vd55g1_dt_ids); diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 6b50fb422a61..4811a0489524 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -522,8 +522,12 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) data->kthread_vid_cap = kthread_run(video_i2c_thread_vid_cap, data, "%s-vid-cap", data->v4l2_dev.name); ret = PTR_ERR_OR_ZERO(data->kthread_vid_cap); - if (!ret) - return 0; + if (ret) { + data->kthread_vid_cap = NULL; + goto error_rpm_put; + } + + return 0; error_rpm_put: pm_runtime_put_autosuspend(dev); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 663469208271..c631b8bbd386 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3563,12 +3563,12 @@ static int __maybe_unused bttv_resume(struct device *dev) } static const struct pci_device_id bttv_pci_tbl[] = { - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879), 0}, - {PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879), 0}, - {0,} + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT848) }, + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT849) }, + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT878) }, + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_BT879) }, + { PCI_VDEVICE(BROOKTREE, PCI_DEVICE_ID_FUSION879) }, + { } }; MODULE_DEVICE_TABLE(pci, bttv_pci_tbl); diff --git a/drivers/media/pci/cobalt/cobalt-alsa-main.c b/drivers/media/pci/cobalt/cobalt-alsa-main.c index 7bb7f13c70c0..9ed547cd40af 100644 --- a/drivers/media/pci/cobalt/cobalt-alsa-main.c +++ b/drivers/media/pci/cobalt/cobalt-alsa-main.c @@ -135,7 +135,6 @@ int cobalt_alsa_init(struct cobalt_stream *s) err_exit_free: if (sc != NULL) snd_card_free(sc); - kfree(cobsc); err_exit: return ret; } diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 9b9f69ff4016..7b1ca1238c8d 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -26,9 +26,8 @@ /* add your revision and whatnot here */ static const struct pci_device_id cobalt_pci_tbl[] = { - {PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_COBALT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} + { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_COBALT) }, + { } }; MODULE_DEVICE_TABLE(pci, cobalt_pci_tbl); diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index f778f79b921d..214fac7af61e 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -40,9 +40,8 @@ EXPORT_SYMBOL(cx18_ext_init); /* add your revision and whatnot here */ static const struct pci_device_id cx18_pci_tbl[] = { - {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} + { PCI_VDEVICE(CX, PCI_DEVICE_ID_CX23418) }, + { } }; MODULE_DEVICE_TABLE(pci, cx18_pci_tbl); diff --git a/drivers/media/pci/cx18/cx18-vbi.c b/drivers/media/pci/cx18/cx18-vbi.c index 8dc4ce325935..3a8430f3259e 100644 --- a/drivers/media/pci/cx18/cx18-vbi.c +++ b/drivers/media/pci/cx18/cx18-vbi.c @@ -135,7 +135,7 @@ static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size, : VBI_HBLANK_SAMPLES_50HZ; /* find the first valid line */ - for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) { + for (i = hdr_size, buf += hdr_size; i + 3 < size; i++, buf++) { if (buf[0] == 0xff && !buf[1] && !buf[2] && (buf[3] == sliced_vbi_eav_rp[0] || buf[3] == sliced_vbi_eav_rp[1])) diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index 154918984534..723509fa1e06 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -528,6 +528,7 @@ void netup_ci_exit(struct cx23885_tsport *port) if (NULL == state->ca.data) return; + cancel_work_sync(&state->work); dvb_ca_en50221_release(&state->ca); kfree(state); } diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 9b92e8db494c..5fb26285e4af 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2279,16 +2279,10 @@ static int __maybe_unused cx23885_resume(struct device *dev_d) static const struct pci_device_id cx23885_pci_tbl[] = { { /* CX23885 */ - .vendor = 0x14f1, - .device = 0x8852, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x14f1, 0x8852), }, { /* CX23887 Rev 2 */ - .vendor = 0x14f1, - .device = 0x8880, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x14f1, 0x8880), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 4fdc59aaed8e..f963ae79f685 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -681,8 +681,8 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device, */ static const struct pci_device_id __maybe_unused cx25821_audio_pci_tbl[] = { - {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} + { PCI_DEVICE(0x14f1, 0x0920) }, + { } }; MODULE_DEVICE_TABLE(pci, cx25821_audio_pci_tbl); diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 5acb1dc00ae8..f883a779b570 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -1347,16 +1347,10 @@ static void cx25821_finidev(struct pci_dev *pci_dev) static const struct pci_device_id cx25821_pci_tbl[] = { { /* CX25821 Athena */ - .vendor = 0x14f1, - .device = 0x8210, - .subvendor = 0x14f1, - .subdevice = 0x0920, + PCI_DEVICE_SUB(0x14f1, 0x8210, 0x14f1, 0x0920), }, { /* CX25821 No Brand */ - .vendor = 0x14f1, - .device = 0x8210, - .subvendor = 0x0000, - .subdevice = 0x0000, + PCI_DEVICE_SUB(0x14f1, 0x8210, 0x0000, 0x0000), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index dce041a5e47a..d2534f90cfba 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -809,9 +809,9 @@ static const struct snd_kcontrol_new snd_cx88_alc_switch = { */ static const struct pci_device_id cx88_audio_pci_tbl[] = { - {0x14f1, 0x8801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x14f1, 0x8811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0, } + { PCI_DEVICE(0x14f1, 0x8801) }, + { PCI_DEVICE(0x14f1, 0x8811) }, + { } }; MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl); diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 676160e9554d..0c07ad335799 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -640,6 +640,7 @@ int cx8802_register_driver(struct cx8802_driver *drv) list_add_tail(&driver->drvlist, &dev->drvlist); } else { pr_err("cx8802 probe failed, err = %d\n", err); + kfree(driver); } mutex_unlock(&drv->core->lock); } @@ -787,10 +788,7 @@ static void cx8802_remove(struct pci_dev *pci_dev) static const struct pci_device_id cx8802_pci_tbl[] = { { - .vendor = 0x14f1, - .device = 0x8802, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x14f1, 0x8802), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index c78b156c5cda..eaa46a2f92e7 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1610,10 +1610,7 @@ static int __maybe_unused cx8800_resume(struct device *dev_d) static const struct pci_device_id cx8800_pci_tbl[] = { { - .vendor = 0x14f1, - .device = 0x8800, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x14f1, 0x8800), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c index 363badab7cf0..248ace29e5c8 100644 --- a/drivers/media/pci/ddbridge/ddbridge-main.c +++ b/drivers/media/pci/ddbridge/ddbridge-main.c @@ -269,7 +269,7 @@ static const struct pci_device_id ddb_id_table[] = { DDB_DEVICE_ANY(0x0323), DDB_DEVICE_ANY(0x0328), DDB_DEVICE_ANY(0x0329), - {0} + { } }; MODULE_DEVICE_TABLE(pci, ddb_id_table); diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index f01ecdb0b627..cf50898f9a92 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -14,7 +14,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/dvb/ca.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index 80d2e143384b..ae4544042a74 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -1209,15 +1209,9 @@ static void dm1105_remove(struct pci_dev *pdev) static const struct pci_device_id dm1105_id_table[] = { { - .vendor = PCI_VENDOR_ID_TRIGEM, - .device = PCI_DEVICE_ID_DM1105, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_VDEVICE(TRIGEM, PCI_DEVICE_ID_DM1105), }, { - .vendor = PCI_VENDOR_ID_AXESS, - .device = PCI_DEVICE_ID_DM05, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_VDEVICE(AXESS, PCI_DEVICE_ID_DM05), }, { /* empty */ }, diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index 7bddcbba4cf1..660aab6b62e0 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -577,8 +577,8 @@ static void dt3155_remove(struct pci_dev *pdev) } static const struct pci_device_id pci_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, DT3155_DEVICE_ID) }, - { 0, /* zero marks the end */ }, + { PCI_VDEVICE(INTEL, DT3155_DEVICE_ID) }, + { /* zero marks the end */ }, }; MODULE_DEVICE_TABLE(pci, pci_ids); diff --git a/drivers/media/pci/hws/hws_v4l2_ioctl.h b/drivers/media/pci/hws/hws_v4l2_ioctl.h index 53044f78d6fa..9a81e940e33e 100644 --- a/drivers/media/pci/hws/hws_v4l2_ioctl.h +++ b/drivers/media/pci/hws/hws_v4l2_ioctl.h @@ -17,14 +17,10 @@ int hws_vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *setfp int hws_vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i); int hws_vidioc_g_input(struct file *file, void *priv, unsigned int *i); int hws_vidioc_s_input(struct file *file, void *priv, unsigned int i); -int hws_vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *a); -int hws_vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a); int hws_vidioc_dv_timings_cap(struct file *file, void *fh, struct v4l2_dv_timings_cap *cap); int hws_vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings); - -int hws_vidioc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a); int hws_vidioc_g_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings); int hws_vidioc_enum_dv_timings(struct file *file, void *fh, diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c index 88581a4c081d..1bb3a3e98d6b 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -49,6 +49,8 @@ * Please keep the list sorted by ACPI HID. */ static const struct ipu_sensor_config ipu_supported_sensors[] = { + /* Himax HM1092 */ + IPU_SENSOR_CONFIG("HIMX1092", 2, 180000000, 180480000), /* Himax HM11B1 */ IPU_SENSOR_CONFIG("HIMX11B1", 1, 384000000), /* Himax HM2170 */ @@ -97,6 +99,8 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = { IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), /* Sony IMX471 */ IPU_SENSOR_CONFIG("SONY471A", 1, 200000000), + /* Sony IMX471 (found on Lenovo X1 Carbon G14) */ + IPU_SENSOR_CONFIG("TBE20A0", 1, 200000000), /* Toshiba T4KA3 */ IPU_SENSOR_CONFIG("XMCC0003", 1, 321468000), }; @@ -134,6 +138,60 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = { }, .driver_data = "OVTI02C1", }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 16 (Dell 16 Premium) DA16250"), + }, + .driver_data = "OVTI02C1", + }, + /* + * The first four characters of DMI_BOARD_NAME identify the Lenovo + * machine type/model. For example, a DMI_BOARD_NAME starting with + * "21Q6" indicates a ThinkPad X9-15. + * + * Reference: https://psref.lenovo.com/ + */ + { + /* Lenovo X9-14 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "21QA"), + }, + .driver_data = "SONY471A", + }, + { + /* Lenovo X9-14 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "21QB"), + }, + .driver_data = "SONY471A", + }, + { + /* Lenovo X9-15 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "21Q6"), + }, + .driver_data = "SONY471A", + }, + { + /* Lenovo X9-15 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_BOARD_NAME, "21Q7"), + }, + .driver_data = "SONY471A", + }, + { + /* Samsung Galaxy Book5 Pro 360 */ + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "960QHA"), + }, + .driver_data = "OVTI02E1", + }, {} /* Terminating entry */ }; @@ -171,6 +229,7 @@ static const struct acpi_device_id ivsc_acpi_ids[] = { { "INTC10DE" }, /* LNL */ { "INTC10E0" }, /* ARL */ { "INTC10E1" }, /* PTL */ + { "INTC10FA" }, /* NVL */ }; static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev) @@ -180,8 +239,8 @@ static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev for (i = 0; i < ARRAY_SIZE(ivsc_acpi_ids); i++) { const struct acpi_device_id *acpi_id = &ivsc_acpi_ids[i]; struct acpi_device *consumer, *ivsc_adev; - acpi_handle handle = acpi_device_handle(ACPI_PTR(adev)); + for_each_acpi_dev_match(ivsc_adev, acpi_id->id, NULL, -1) /* camera sensor depends on IVSC in DSDT if exist */ for_each_acpi_consumer_dev(ivsc_adev, consumer) @@ -298,9 +357,11 @@ static u32 ipu_bridge_parse_rotation(struct acpi_device *adev, { const struct dmi_system_id *dmi_id; - dmi_id = dmi_first_match(upside_down_sensor_dmi_ids); - if (dmi_id && acpi_dev_hid_match(adev, dmi_id->driver_data)) - return 180; + /* A machine may have one entry per sensor, so check all matches. */ + for (dmi_id = dmi_first_match(upside_down_sensor_dmi_ids); dmi_id; + dmi_id = dmi_first_match(dmi_id + 1)) + if (acpi_dev_hid_match(adev, dmi_id->driver_data)) + return 180; switch (ssdb->degree) { case IPU_SENSOR_ROTATION_NORMAL: diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 986b9afd7cb5..eb1824ee86fd 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1961,7 +1961,7 @@ static const struct dev_pm_ops cio2_pm_ops = { }; static const struct pci_device_id cio2_pci_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, CIO2_PCI_ID) }, + { PCI_VDEVICE(INTEL, CIO2_PCI_ID) }, { } }; diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c index c9cdeb7054d7..24db2763de54 100644 --- a/drivers/media/pci/intel/ipu6/ipu6-isys.c +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c @@ -761,6 +761,7 @@ static int isys_notifier_init(struct ipu6_isys *isys) err_parse: fwnode_handle_put(ep); + v4l2_async_nf_cleanup(&isys->notifier); return ret; } diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c index d033d4618169..5449a2006bcc 100644 --- a/drivers/media/pci/intel/ipu6/ipu6.c +++ b/drivers/media/pci/intel/ipu6/ipu6.c @@ -400,7 +400,6 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent, &ipdata->hw_variant); if (IS_ERR(isys_adev->mmu)) { put_device(&isys_adev->auxdev.dev); - kfree(pdata); return dev_err_cast_probe(dev, isys_adev->mmu, "ipu6_mmu_init(isys_adev->mmu) failed\n"); } @@ -408,10 +407,8 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent, isys_adev->mmu->dev = &isys_adev->auxdev.dev; ret = ipu6_bus_add_device(isys_adev); - if (ret) { - kfree(pdata); + if (ret) return ERR_PTR(ret); - } return isys_adev; } @@ -444,7 +441,6 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent, &ipdata->hw_variant); if (IS_ERR(psys_adev->mmu)) { put_device(&psys_adev->auxdev.dev); - kfree(pdata); return dev_err_cast_probe(&pdev->dev, psys_adev->mmu, "ipu6_mmu_init(psys_adev->mmu) failed\n"); } @@ -452,10 +448,8 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent, psys_adev->mmu->dev = &psys_adev->auxdev.dev; ret = ipu6_bus_add_device(psys_adev); - if (ret) { - kfree(pdata); + if (ret) return ERR_PTR(ret); - } return psys_adev; } diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index e0091a8e5c88..b9ea56ec9593 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -60,11 +60,9 @@ EXPORT_SYMBOL(ivtv_ext_init); /* add your revision and whatnot here */ static const struct pci_device_id ivtv_pci_tbl[] = { - {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV15, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_ICOMP, PCI_DEVICE_ID_IVTV16, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} + { PCI_VDEVICE(ICOMP, PCI_DEVICE_ID_IVTV15) }, + { PCI_VDEVICE(ICOMP, PCI_DEVICE_ID_IVTV16) }, + { } }; MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl); diff --git a/drivers/media/pci/ivtv/ivtv-vbi.c b/drivers/media/pci/ivtv/ivtv-vbi.c index ae7a00f46257..af086c4cbe1a 100644 --- a/drivers/media/pci/ivtv/ivtv-vbi.c +++ b/drivers/media/pci/ivtv/ivtv-vbi.c @@ -330,7 +330,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 unsigned lines = 0; /* find the first valid line */ - for (i = 0; i < size; i++, buf++) { + for (i = 0; i + 3 < size; i++, buf++) { if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) break; } diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h index 6e563ecd94e8..f357ca268dd1 100644 --- a/drivers/media/pci/mantis/mantis_common.h +++ b/drivers/media/pci/mantis/mantis_common.h @@ -58,11 +58,9 @@ #define TERRATEC 0x153b #define MAKE_ENTRY(__subven, __subdev, __configptr, __rc) { \ - .vendor = TWINHAN_TECHNOLOGIES, \ - .device = MANTIS, \ - .subvendor = (__subven), \ - .subdevice = (__subdev), \ - .driver_data = (unsigned long) \ + PCI_DEVICE_SUB(TWINHAN_TECHNOLOGIES, MANTIS, \ + (__subven), (__subdev)), \ + .driver_data = (unsigned long) \ &(struct mantis_pci_drvdata){__configptr, __rc} \ } diff --git a/drivers/media/pci/mgb4/mgb4_core.c b/drivers/media/pci/mgb4/mgb4_core.c index d23d854581c5..cbd193e06536 100644 --- a/drivers/media/pci/mgb4/mgb4_core.c +++ b/drivers/media/pci/mgb4/mgb4_core.c @@ -694,9 +694,9 @@ static void mgb4_remove(struct pci_dev *pdev) } static const struct pci_device_id mgb4_pci_ids[] = { - { PCI_DEVICE(DIGITEQ_VID, T100_DID), }, - { PCI_DEVICE(DIGITEQ_VID, T200_DID), }, - { 0, } + { PCI_DEVICE(DIGITEQ_VID, T100_DID) }, + { PCI_DEVICE(DIGITEQ_VID, T200_DID) }, + { } }; MODULE_DEVICE_TABLE(pci, mgb4_pci_ids); diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index ec08023b5d5e..00f81e4c8e8d 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -1014,7 +1014,7 @@ static void netup_unidvb_finidev(struct pci_dev *pci_dev) static const struct pci_device_id netup_unidvb_pci_tbl[] = { { PCI_DEVICE(0x1b55, 0x18f6) }, /* hw rev. 1.3 */ { PCI_DEVICE(0x1b55, 0x18f7) }, /* hw rev. 1.4 */ - { 0, } + { } }; MODULE_DEVICE_TABLE(pci, netup_unidvb_pci_tbl); diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 7dbc21e1a2ca..a1a83f3bb6b4 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -1155,8 +1155,7 @@ static const struct ngene_info ngene_info_terratec = { /****************************************************************************/ #define NGENE_ID(_subvend, _subdev, _driverdata) { \ - .vendor = NGENE_VID, .device = NGENE_PID, \ - .subvendor = _subvend, .subdevice = _subdev, \ + PCI_DEVICE_SUB(NGENE_VID, NGENE_PID, (_subvend), (_subdev)), \ .driver_data = (unsigned long) &_driverdata } /****************************************************************************/ @@ -1173,7 +1172,7 @@ static const struct pci_device_id ngene_id_tbl[] = { NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex), NGENE_ID(0x1461, 0x062e, ngene_info_m780), NGENE_ID(0x153b, 0x1167, ngene_info_terratec), - {0} + { } }; MODULE_DEVICE_TABLE(pci, ngene_id_tbl); diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c index 22c2222d5c4d..77b3e4eec54d 100644 --- a/drivers/media/pci/pluto2/pluto2.c +++ b/drivers/media/pci/pluto2/pluto2.c @@ -762,10 +762,7 @@ static void pluto2_remove(struct pci_dev *pdev) static const struct pci_device_id pluto2_id_table[] = { { - .vendor = PCI_VENDOR_ID_SCM, - .device = PCI_DEVICE_ID_PLUTO2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_VDEVICE(SCM, PCI_DEVICE_ID_PLUTO2), }, { /* empty */ }, diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index e80fb4ebfda6..a7d665407460 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -5800,1317 +5800,758 @@ const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); struct pci_device_id saa7134_pci_tbl[] = { { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, - .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, - .driver_data = SAA7134_BOARD_PROTEUS_PRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x6752, - .driver_data = SAA7134_BOARD_EMPRESS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x4e85, - .driver_data = SAA7134_BOARD_MONSTERTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153b, - .subdevice = 0x1142, - .driver_data = SAA7134_BOARD_CINERGY400, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153b, - .subdevice = 0x1143, - .driver_data = SAA7134_BOARD_CINERGY600, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x153b, - .subdevice = 0x1158, - .driver_data = SAA7134_BOARD_CINERGY600_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1162, - .driver_data = SAA7134_BOARD_CINERGY400_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5169, - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000_NTSC, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5168, - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x4e42, /* "Typhoon PCI Capture TV Card" Art.No. 50673 */ - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO3000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x5168, - .subdevice = 0x0138, - .driver_data = SAA7134_BOARD_FLYVIDEO2000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x4e42, /* Typhoon */ - .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */ - .driver_data = SAA7134_BOARD_FLYVIDEO2000, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x0212, /* minipci, LR212 */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x14c0, - .subdevice = 0x1212, /* minipci, LR1212 */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI2, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4e42, - .subdevice = 0x0212, /* OEM minipci, LR212 */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, /* Animation Technologies (LifeView) */ - .subdevice = 0x0214, /* Standard PCI, LR214 Rev E and earlier (SAA7135) */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, /* Animation Technologies (LifeView) */ - .subdevice = 0x5214, /* Standard PCI, LR214 Rev F onwards (SAA7131) */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1489, /* KYE */ - .subdevice = 0x0214, /* Genius VideoWonder ProTV */ - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */ - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x16be, - .subdevice = 0x0003, - .driver_data = SAA7134_BOARD_MD7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x16be, /* CTX946 analog TV, HW mpeg, DVB-T */ - .subdevice = 0x5000, /* only analog TV and DVB-T for now */ - .driver_data = SAA7134_BOARD_MD7134, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0x2001), + .driver_data = SAA7134_BOARD_PROTEUS_PRO, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1048, - .subdevice = 0x226b, - .driver_data = SAA7134_BOARD_ELSA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1048, - .subdevice = 0x226a, - .driver_data = SAA7134_BOARD_ELSA_500TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1048, - .subdevice = 0x226c, - .driver_data = SAA7134_BOARD_ELSA_700TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4842, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4845, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7135, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4830, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4843, - .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_ASUSTEK, - .subdevice = 0x4840, - .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0xfe01, - .driver_data = SAA7134_BOARD_TVSTATION_RDS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1894, - .subdevice = 0xfe01, - .driver_data = SAA7134_BOARD_TVSTATION_RDS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1894, - .subdevice = 0xa006, - .driver_data = SAA7134_BOARD_TVSTATION_DVR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1131, - .subdevice = 0x7133, - .driver_data = SAA7134_BOARD_VA1000POWER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2001, - .driver_data = SAA7134_BOARD_10MOONSTVMASTER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, - .driver_data = SAA7134_BOARD_VIDEOMATE_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc100, - .driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_MATROX, - .subdevice = 0x48d0, - .driver_data = SAA7134_BOARD_CRONOS_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa70b, - .driver_data = SAA7134_BOARD_MD2819, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa7a1, - .driver_data = SAA7134_BOARD_AVERMEDIA_A700_PRO, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_PHILIPS, 0x2001), + .driver_data = SAA7134_BOARD_PROTEUS_PRO, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa7a2, - .driver_data = SAA7134_BOARD_AVERMEDIA_A700_HYBRID, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0x6752), + .driver_data = SAA7134_BOARD_EMPRESS, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2115, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa115, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_505, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1131, 0x4e85), + .driver_data = SAA7134_BOARD_MONSTERTV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x153b, 0x1142), + .driver_data = SAA7134_BOARD_CINERGY400, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x153b, 0x1143), + .driver_data = SAA7134_BOARD_CINERGY600, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x153b, 0x1158), + .driver_data = SAA7134_BOARD_CINERGY600_MK3, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x153b, 0x1162), + .driver_data = SAA7134_BOARD_CINERGY400_CARDBUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5169, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO3000_NTSC, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5168, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO3000, + }, { + /* "Typhoon PCI Capture TV Card" Art.No. 50673 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x4e42, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO3000, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x5168, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO2000, + }, { + /* Typhoon LifeView FlyTV Prime30 OEM */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x4e42, 0x0138), + .driver_data = SAA7134_BOARD_FLYVIDEO2000, + }, { + /* minipci, LR212 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0212), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + }, { + /* minipci, LR1212 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x14c0, 0x1212), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI2, + }, { + /* OEM minipci, LR212 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x4e42, 0x0212), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + }, { + /* + * Animation Technologies (LifeView) + * Standard PCI, LR214 Rev E and earlier (SAA7135) + */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0214), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, + }, { + /* + * Animation Technologies (LifeView) + * Standard PCI, LR214 Rev F onwards (SAA7131) + */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x5214), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, + }, { + /* KYE Genius VideoWonder ProTV */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1489, 0x0214), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */ + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x16be, 0x0003), + .driver_data = SAA7134_BOARD_MD7134, + }, { + /* CTX946 analog TV, HW mpeg, DVB-T; only analog TV and DVB-T for now */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x16be, 0x5000), + .driver_data = SAA7134_BOARD_MD7134, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1048, 0x226b), + .driver_data = SAA7134_BOARD_ELSA, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1048, 0x226a), + .driver_data = SAA7134_BOARD_ELSA_500TV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1048, 0x226c), + .driver_data = SAA7134_BOARD_ELSA_700TV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_ASUSTEK, 0x4842), + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_ASUSTEK, 0x4845), + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7135, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_ASUSTEK, 0x4830), + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_ASUSTEK, 0x4843), + .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_ASUSTEK, 0x4840), + .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0xfe01), + .driver_data = SAA7134_BOARD_TVSTATION_RDS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1894, 0xfe01), + .driver_data = SAA7134_BOARD_TVSTATION_RDS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1894, 0xa006), + .driver_data = SAA7134_BOARD_TVSTATION_DVR, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1131, 0x7133), + .driver_data = SAA7134_BOARD_VA1000POWER, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0x2001), + .driver_data = SAA7134_BOARD_10MOONSTVMASTER, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x185b, 0xc100), + .driver_data = SAA7134_BOARD_VIDEOMATE_TV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x185b, 0xc100), + .driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_MATROX, 0x48d0), + .driver_data = SAA7134_BOARD_CRONOS_PLUS, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xa70b), + .driver_data = SAA7134_BOARD_MD2819, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xa7a1), + .driver_data = SAA7134_BOARD_AVERMEDIA_A700_PRO, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xa7a2), + .driver_data = SAA7134_BOARD_AVERMEDIA_A700_HYBRID, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0x2115), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0xa115), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_505, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0x2108), + .driver_data = SAA7134_BOARD_AVERMEDIA_305, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0x10ff), + .driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2108, - .driver_data = SAA7134_BOARD_AVERMEDIA_305, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x10ff, - .driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER, - },{ /* AVerMedia CardBus */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xd6ee, - .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS, - },{ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xd6ee), + .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS, + }, { /* AVerMedia CardBus */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xb7e9, - .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_501, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xb7e9), + .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_501, }, { - /* TransGear 3000TV */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x050c, - .driver_data = SAA7134_BOARD_TG3000TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002b, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x11bd, - .subdevice = 0x002d, - .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1019, - .subdevice = 0x4cb4, - .driver_data = SAA7134_BOARD_ECS_TVP3XP, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1019, - .subdevice = 0x4cb5, - .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1019, - .subdevice = 0x4cb6, - .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB6, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x12ab, - .subdevice = 0x0800, - .driver_data = SAA7134_BOARD_UPMOST_PURPLE_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x153b, - .subdevice = 0x1152, - .driver_data = SAA7134_BOARD_CINERGY200, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc100, - .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x9715, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_307, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa70a, - .driver_data = SAA7134_BOARD_AVERMEDIA_307, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x185b, - .subdevice = 0xc200, - .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1540, - .subdevice = 0x9524, - .driver_data = SAA7134_BOARD_PROVIDEO_PV952, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x0502, /* Cardbus version */ - .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x0306, /* PCI version */ - .driver_data = SAA7134_BOARD_FLYDVBTDUO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31f, - .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf11d, - .driver_data = SAA7134_BOARD_AVERMEDIA_M135A, + /* AVerMedia TransGear 3000TV */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0x050c), + .driver_data = SAA7134_BOARD_TG3000TV, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x4155, - .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x11bd, 0x002b), + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x4255, - .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x11bd, 0x002d), + .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_PHILIPS_TOUGH, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x0350, /* PCI version */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x0351, /* PCI version, new revision */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x0370, /* cardbus version */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1421, - .subdevice = 0x1370, /* cardbus version */ - .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4e42, /* Typhoon */ - .subdevice = 0x0502, /* LifeView LR502 OEM */ - .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x0210, /* mini pci NTSC version */ - .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1043, - .subdevice = 0x0210, /* mini pci PAL/SECAM version */ - .driver_data = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV, - - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, /* It shouldn't break anything, since subdevice id seems unique */ - .subdevice = 0x4091, - .driver_data = SAA7134_BOARD_BEHOLD_409FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5456, /* GoTView */ - .subdevice = 0x7135, - .driver_data = SAA7134_BOARD_GOTVIEW_7135, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_PHILIPS_EUROPA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_300, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc901, - .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_200, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1435, - .subdevice = 0x7350, - .driver_data = SAA7134_BOARD_RTD_VFG7350, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1435, - .subdevice = 0x7330, - .driver_data = SAA7134_BOARD_RTD_VFG7330, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, - .subdevice = 0x1044, - .driver_data = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1131, - .subdevice = 0x4ee9, - .driver_data = SAA7134_BOARD_MONSTERTV_MOBILE, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x11bd, - .subdevice = 0x002e, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_110i, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4862, - .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2018, - .driver_data = SAA7134_BOARD_PHILIPS_TIGER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, - .subdevice = 0x6231, /* tda8275a, ks003 IR */ - .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, - .subdevice = 0x8624, /* tda8275, ks003 IR */ - .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1160, - .driver_data = SAA7134_BOARD_CINERGY250PCI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA 7131E */ - .subvendor = 0x5168, - .subdevice = 0x0319, - .driver_data = SAA7134_BOARD_FLYDVB_TRIO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x2c05, - .driver_data = SAA7134_BOARD_AVERMEDIA_777, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5168, - .subdevice = 0x0301, - .driver_data = SAA7134_BOARD_FLYDVBT_LR301, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0331, - .subdevice = 0x1421, - .driver_data = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x17de, - .subdevice = 0x7201, - .driver_data = SAA7134_BOARD_TEVION_DVBT_220RF, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x17de, - .subdevice = 0x7250, - .driver_data = SAA7134_BOARD_KWORLD_DVBT_210, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x17de, - .subdevice = 0x7350, - .driver_data = SAA7134_BOARD_KWORLD_ATSC110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x17de, - .subdevice = 0x7352, - .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x17de, - .subdevice = 0xa134, - .driver_data = SAA7134_BOARD_KWORLD_PC150U, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1019, 0x4cb4), + .driver_data = SAA7134_BOARD_ECS_TVP3XP, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1019, 0x4cb5), + .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1019, 0x4cb6), + .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB6, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x12ab, 0x0800), + .driver_data = SAA7134_BOARD_UPMOST_PURPLE_TV, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x153b, 0x1152), + .driver_data = SAA7134_BOARD_CINERGY200, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x185b, 0xc100), + .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x9715), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_307, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xa70a), + .driver_data = SAA7134_BOARD_AVERMEDIA_307, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x185b, 0xc200), + .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1540, 0x9524), + .driver_data = SAA7134_BOARD_PROVIDEO_PV952, + }, { + /* Cardbus version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0502), + .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, + }, { + /* PCI version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0306), + .driver_data = SAA7134_BOARD_FLYDVBTDUO, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf31f), + .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf11d), + .driver_data = SAA7134_BOARD_AVERMEDIA_M135A, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x4155), + .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x4255), + .driver_data = SAA7134_BOARD_AVERMEDIA_M733A, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0x2004), + .driver_data = SAA7134_BOARD_PHILIPS_TOUGH, + }, { + /* PCI version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x0350), + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + }, { + /* PCI version, new revision */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x0351), + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + }, { + /* cardbus version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x0370), + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + }, { + /* cardbus version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x1370), + .driver_data = SAA7134_BOARD_ADS_INSTANT_TV, + }, { + /* Typhoon LifeView LR502 OEM */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x4e42, 0x0502), + .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, + }, { + /* mini pci NTSC version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x0210), + .driver_data = SAA7134_BOARD_FLYTV_DIGIMATRIX, + }, { + /* mini pci PAL/SECAM version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1043, 0x0210), + .driver_data = SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV, + }, { + /* subvendor == 0 shouldn't break anything, since subdevice id seems unique */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x4091), + .driver_data = SAA7134_BOARD_BEHOLD_409FM, + }, { + /* GoTView */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5456, 0x7135), + .driver_data = SAA7134_BOARD_GOTVIEW_7135, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0x2004), + .driver_data = SAA7134_BOARD_PHILIPS_EUROPA, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x185b, 0xc900), + .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_300, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x185b, 0xc901), + .driver_data = SAA7134_BOARD_VIDEOMATE_DVBT_200, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1435, 0x7350), + .driver_data = SAA7134_BOARD_RTD_VFG7350, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1435, 0x7330), + .driver_data = SAA7134_BOARD_RTD_VFG7330, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x1044), + .driver_data = SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1131, 0x4ee9), + .driver_data = SAA7134_BOARD_MONSTERTV_MOBILE, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x11bd, 0x002e), + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_110i, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4862), + .driver_data = SAA7134_BOARD_ASUSTeK_P7131_DUAL, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_PHILIPS, 0x2018), + .driver_data = SAA7134_BOARD_PHILIPS_TIGER, + }, { + /* tda8275a, ks003 IR */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1462, 0x6231), + .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x7360, - .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x6360, - .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B1, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x16be, - .subdevice = 0x0005, - .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5168, - .subdevice = 0x0300, - .driver_data = SAA7134_BOARD_FLYDVBS_LR300, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x4e42, - .subdevice = 0x0300,/* LR300 */ - .driver_data = SAA7134_BOARD_FLYDVBS_LR300, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1489, - .subdevice = 0x0301, + /* tda8275, ks003 IR */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1462, 0x8624), + .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x153b, 0x1160), + .driver_data = SAA7134_BOARD_CINERGY250PCI, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0319), + .driver_data = SAA7134_BOARD_FLYDVB_TRIO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x2c05), + .driver_data = SAA7134_BOARD_AVERMEDIA_777, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5168, 0x0301), + .driver_data = SAA7134_BOARD_FLYDVBT_LR301, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0331, 0x1421), + .driver_data = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0x7201), + .driver_data = SAA7134_BOARD_TEVION_DVBT_220RF, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0x7250), + .driver_data = SAA7134_BOARD_KWORLD_DVBT_210, + }, { + /* SAA7135HL */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0x7350), + .driver_data = SAA7134_BOARD_KWORLD_ATSC110, + }, { + /* SAA7135HL */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0x7352), + .driver_data = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */ + }, { + /* SAA7135HL */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0xa134), + .driver_data = SAA7134_BOARD_KWORLD_PC150U, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x7360), + .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x6360), + .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B1, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x16be, 0x0005), + .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5168, 0x0300), + .driver_data = SAA7134_BOARD_FLYDVBS_LR300, + }, { + /* LR300 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x4e42, 0x0300), + .driver_data = SAA7134_BOARD_FLYDVBS_LR300, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1489, 0x0301), .driver_data = SAA7134_BOARD_FLYDVBT_LR301, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, /* Animation Technologies (LifeView) */ - .subdevice = 0x0304, + }, { + /* Animation Technologies (LifeView) */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x0304), .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x3306, - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x3502, /* what's the difference to 0x3306 ?*/ - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5168, - .subdevice = 0x3307, /* FlyDVB-T Hybrid Mini PCI */ - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x0007, - .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x0008, - .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x000d, /* triple CTX948_V1.1.1 */ - .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x3306), + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + }, { + /* what's the difference to .subdevice = 0x3306 above? */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x3502), + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + }, { + /* FlyDVB-T Hybrid Mini PCI */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5168, 0x3307), + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x16be, 0x0007), + .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x16be, 0x0008), + .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, + }, { + /* triple CTX948_V1.1.1 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x16be, 0x000d), + .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x2c05), + .driver_data = SAA7134_BOARD_AVERMEDIA_777, + }, { + /* Cardbus version */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1489, 0x0502), + .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, + }, { + /* Philips Proteus PRO 2309 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0919, 0x2003), + .driver_data = SAA7134_BOARD_PROTEUS_2309, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0x2c00), + .driver_data = SAA7134_BOARD_AVERMEDIA_A16AR, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1043, 0x4860), + .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x11bd, 0x002f), + .driver_data = SAA7134_BOARD_PINNACLE_PCTV_310i, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x9715), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1461, 0xa11b), + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4876), + .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6700), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6701), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6702), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6703), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6704), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6705), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6706), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6707), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6708), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x6709), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0070, 0x670a), + .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x153b, 0x1172), + .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, - .subdevice = 0x2c05, - .driver_data = SAA7134_BOARD_AVERMEDIA_777, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1489, - .subdevice = 0x0502, /* Cardbus version */ - .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0919, /* Philips Proteus PRO 2309 */ - .subdevice = 0x2003, - .driver_data = SAA7134_BOARD_PROTEUS_2309, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, - .subdevice = 0x2c00, - .driver_data = SAA7134_BOARD_AVERMEDIA_A16AR, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1043, - .subdevice = 0x4860, - .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x11bd, - .subdevice = 0x002f, - .driver_data = SAA7134_BOARD_PINNACLE_PCTV_310i, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x9715, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa11b, - .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_507UA, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0x2342), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4876, - .driver_data = SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6700, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6701, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6702, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6703, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6704, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6705, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1110, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6706, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6707, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6708, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1150, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x6709, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0070, - .subdevice = 0x670a, - .driver_data = SAA7134_BOARD_HAUPPAUGE_HVR1120, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1172, - .driver_data = SAA7134_BOARD_CINERGY_HT_PCMCIA, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2342, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0x2341, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x3016, - .subdevice = 0x2344, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1131, - .subdevice = 0x230f, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1a7f, - .subdevice = 0x2008, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM53, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1131, 0x2341), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1a7f, - .subdevice = 0x2108, - .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM3, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x3016, 0x2344), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x153b, - .subdevice = 0x1175, - .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31e, - .driver_data = SAA7134_BOARD_AVERMEDIA_M102, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4E42, /* MSI */ - .subdevice = 0x0306, /* TV@nywhere DUO */ - .driver_data = SAA7134_BOARD_FLYDVBTDUO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4871, - .driver_data = SAA7134_BOARD_ASUS_P7131_4871, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4857, /* REV:1.00 */ - .driver_data = SAA7134_BOARD_ASUSTeK_TIGER, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0919, /* SinoVideo PCI 2309 Proteus (7134) */ - .subdevice = 0x2003, /* OEM cardbus */ - .driver_data = SAA7134_BOARD_SABRENT_TV_PCB05, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2304, - .driver_data = SAA7134_BOARD_10MOONSTVMASTER3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf01d, /* AVerTV DVB-T Super 007 */ - .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4016, - .driver_data = SAA7134_BOARD_BEHOLD_401, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4036, - .driver_data = SAA7134_BOARD_BEHOLD_403, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4037, - .driver_data = SAA7134_BOARD_BEHOLD_403FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4050, - .driver_data = SAA7134_BOARD_BEHOLD_405, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x4051, - .driver_data = SAA7134_BOARD_BEHOLD_405FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4070, - .driver_data = SAA7134_BOARD_BEHOLD_407, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x0000, - .subdevice = 0x4071, - .driver_data = SAA7134_BOARD_BEHOLD_407FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x4090, - .driver_data = SAA7134_BOARD_BEHOLD_409, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x505B, - .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK5, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1131, 0x230f), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x0000, - .subdevice = 0x5051, - .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x5ace, - .subdevice = 0x5050, - .driver_data = SAA7134_BOARD_BEHOLD_505FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x5071, - .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x507B, - .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x5070, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x5090, - .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x0000, - .subdevice = 0x5201, - .driver_data = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6070, - .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6071, - .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6072, - .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x5ace, - .subdevice = 0x6073, - .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6090, - .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6091, - .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6092, - .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK3, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6093, - .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK5, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6190, - .driver_data = SAA7134_BOARD_BEHOLD_M6, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6193, - .driver_data = SAA7134_BOARD_BEHOLD_M6_EXTRA, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1a7f, 0x2008), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM53, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6191, - .driver_data = SAA7134_BOARD_BEHOLD_M63, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x4e42, - .subdevice = 0x3502, - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1a7f, 0x2108), + .driver_data = SAA7134_BOARD_ENCORE_ENLTV_FM3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1822, /*Twinhan Technology Co. Ltd*/ - .subdevice = 0x0022, - .driver_data = SAA7134_BOARD_TWINHAN_DTV_DVB_3056, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x153b, 0x1175), + .driver_data = SAA7134_BOARD_CINERGY_HT_PCI, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x16be, - .subdevice = 0x0010, /* Medion version CTX953_V.1.4.3 */ - .driver_data = SAA7134_BOARD_CREATIX_CTX953, + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf31e), + .driver_data = SAA7134_BOARD_AVERMEDIA_M102, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1462, /* MSI */ - .subdevice = 0x8625, /* TV@nywhere A/D v1.1 */ - .driver_data = SAA7134_BOARD_MSI_TVANYWHERE_AD11, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf436, - .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_506, + /* MSI TV@nywhere DUO */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x4E42, 0x0306), + .driver_data = SAA7134_BOARD_FLYDVBTDUO, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf936, - .driver_data = SAA7134_BOARD_AVERMEDIA_A16D, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4871), + .driver_data = SAA7134_BOARD_ASUS_P7131_4871, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa836, - .driver_data = SAA7134_BOARD_AVERMEDIA_M115, + /* REV:1.00 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4857), + .driver_data = SAA7134_BOARD_ASUSTeK_TIGER, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_T750, + /* SinoVideo PCI 2309 Proteus (7134) OEM cardbus */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0919, 0x2003), + .driver_data = SAA7134_BOARD_SABRENT_TV_PCB05, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ - .subvendor = 0x1421, - .subdevice = 0x0380, - .driver_data = SAA7134_BOARD_ADS_INSTANT_HDTV_PCI, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0x2304), + .driver_data = SAA7134_BOARD_10MOONSTVMASTER3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5169, - .subdevice = 0x1502, - .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + /* Avermedia Technologies Inc AVerTV DVB-T Super 007 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf01d), + .driver_data = SAA7134_BOARD_AVERMEDIA_SUPER_007, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x6290, - .driver_data = SAA7134_BOARD_BEHOLD_H6, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x4016), + .driver_data = SAA7134_BOARD_BEHOLD_401, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf636, - .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0000, 0x4036), + .driver_data = SAA7134_BOARD_BEHOLD_403, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf736, - .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0000, 0x4037), + .driver_data = SAA7134_BOARD_BEHOLD_403FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x4878, /* REV:1.02G */ - .driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x4050), + .driver_data = SAA7134_BOARD_BEHOLD_405, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1043, - .subdevice = 0x48cd, - .driver_data = SAA7134_BOARD_ASUSTeK_PS3_100, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x4051), + .driver_data = SAA7134_BOARD_BEHOLD_405FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x17de, - .subdevice = 0x7128, - .driver_data = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0000, 0x4070), + .driver_data = SAA7134_BOARD_BEHOLD_407, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x17de, - .subdevice = 0xb136, - .driver_data = SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x0000, 0x4071), + .driver_data = SAA7134_BOARD_BEHOLD_407FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xf31d, - .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x4090), + .driver_data = SAA7134_BOARD_BEHOLD_409, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_S350, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x505B), + .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ - .subdevice = 0x7595, - .driver_data = SAA7134_BOARD_BEHOLD_X7, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x0000, 0x5051), + .driver_data = SAA7134_BOARD_BEHOLD_505RDS_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x19d1, /* RoverMedia */ - .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */ - .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x5ace, 0x5050), + .driver_data = SAA7134_BOARD_BEHOLD_505FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0x2004, - .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x5071), + .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x1043, - .subdevice = 0x4847, - .driver_data = SAA7134_BOARD_ASUS_EUROPA_HYBRID, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x507B), + .driver_data = SAA7134_BOARD_BEHOLD_507RDS_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x107d, - .subdevice = 0x6655, - .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x5070), + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x13c2, - .subdevice = 0x2804, - .driver_data = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x5090), + .driver_data = SAA7134_BOARD_BEHOLD_507_9FM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ - .subdevice = 0x7190, - .driver_data = SAA7134_BOARD_BEHOLD_H7, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x0000, 0x5201), + .driver_data = SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ - .subdevice = 0x7090, - .driver_data = SAA7134_BOARD_BEHOLD_A7, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x6070), + .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = 0x185b, - .subdevice = 0xc900, - .driver_data = SAA7134_BOARD_VIDEOMATE_M1F, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x6071), + .driver_data = SAA7134_BOARD_BEHOLD_607FM_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x5ace, - .subdevice = 0x5030, - .driver_data = SAA7134_BOARD_BEHOLD_503FM, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x6072), + .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x5ace, - .subdevice = 0x5010, - .driver_data = SAA7134_BOARD_BEHOLD_501, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x5ace, 0x6073), + .driver_data = SAA7134_BOARD_BEHOLD_607RDS_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = 0x17de, - .subdevice = 0xd136, - .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6090), + .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x6000, - .subdevice = 0x0811, - .driver_data = SAA7134_BOARD_SENSORAY811_911, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6091), + .driver_data = SAA7134_BOARD_BEHOLD_609FM_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x6000, - .subdevice = 0x0911, - .driver_data = SAA7134_BOARD_SENSORAY811_911, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6092), + .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK3, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0x2055, /* AverTV Satellite Hybrid+FM A706 */ - .driver_data = SAA7134_BOARD_AVERMEDIA_A706, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6093), + .driver_data = SAA7134_BOARD_BEHOLD_609RDS_MK5, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1905, /* WIS */ - .subdevice = 0x7007, - .driver_data = SAA7134_BOARD_WIS_VOYAGER, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6190), + .driver_data = SAA7134_BOARD_BEHOLD_M6, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x1461, /* Avermedia Technologies Inc */ - .subdevice = 0xa10a, - .driver_data = SAA7134_BOARD_AVERMEDIA_505, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6193), + .driver_data = SAA7134_BOARD_BEHOLD_M6_EXTRA, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = 0x107d, - .subdevice = 0x6f3a, - .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6191), + .driver_data = SAA7134_BOARD_BEHOLD_M63, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x1779, /* V One Multimedia PTE Ltd */ - .subdevice = 0x13cf, - .driver_data = SAA7134_BOARD_SNAZIO_TVPVR_PRO, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x4e42, 0x3502), + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = 0x107d, - .subdevice = 0x6f2e, - .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H, + /*Twinhan Technology Co. Ltd*/ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1822, 0x0022), + .driver_data = SAA7134_BOARD_TWINHAN_DTV_DVB_3056, + }, { + /* Medion version CTX953_V.1.4.3 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x16be, 0x0010), + .driver_data = SAA7134_BOARD_CREATIX_CTX953, + }, { + /* MSI TV@nywhere A/D v1.1 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1462, 0x8625), + .driver_data = SAA7134_BOARD_MSI_TVANYWHERE_AD11, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf436), + .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_506, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf936), + .driver_data = SAA7134_BOARD_AVERMEDIA_A16D, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xa836), + .driver_data = SAA7134_BOARD_AVERMEDIA_M115, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x185b, 0xc900), + .driver_data = SAA7134_BOARD_VIDEOMATE_T750, + }, { + /* SAA7135HL */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1421, 0x0380), + .driver_data = SAA7134_BOARD_ADS_INSTANT_HDTV_PCI, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5169, 0x1502), + .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x6290), + .driver_data = SAA7134_BOARD_BEHOLD_H6, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf636), + .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf736), + .driver_data = SAA7134_BOARD_AVERMEDIA_M103, + }, { + /* REV:1.02G */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x4878), + .driver_data = SAA7134_BOARD_ASUSTeK_TIGER_3IN1, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1043, 0x48cd), + .driver_data = SAA7134_BOARD_ASUSTeK_PS3_100, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x17de, 0x7128), + .driver_data = SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x17de, 0xb136), + .driver_data = SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0xf31d), + .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x185b, 0xc900), + .driver_data = SAA7134_BOARD_VIDEOMATE_S350, + }, { + /* Beholder Intl. Ltd. */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x7595), + .driver_data = SAA7134_BOARD_BEHOLD_X7, + }, { + /* RoverMedia LifeView FlyTV Prime30 OEM */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x19d1, 0x0138), + .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, + PCI_VENDOR_ID_PHILIPS, 0x2004), + .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x1043, 0x4847), + .driver_data = SAA7134_BOARD_ASUS_EUROPA_HYBRID, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x107d, 0x6655), + .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x13c2, 0x2804), + .driver_data = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000, + }, { + /* Beholder Intl. Ltd. */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x7190), + .driver_data = SAA7134_BOARD_BEHOLD_H7, + }, { + /* Beholder Intl. Ltd. */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x7090), + .driver_data = SAA7134_BOARD_BEHOLD_A7, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7135, 0x185b, 0xc900), + .driver_data = SAA7134_BOARD_VIDEOMATE_M1F, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x5ace, 0x5030), + .driver_data = SAA7134_BOARD_BEHOLD_503FM, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x5ace, 0x5010), + .driver_data = SAA7134_BOARD_BEHOLD_501, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, 0x17de, 0xd136), + .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x6000, 0x0811), + .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x6000, 0x0911), + .driver_data = SAA7134_BOARD_SENSORAY811_911, + }, { + /* Avermedia Technologies Inc AverTV Satellite Hybrid+FM A706 */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1461, 0x2055), + .driver_data = SAA7134_BOARD_AVERMEDIA_A706, + }, { + /* WIS */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1905, 0x7007), + .driver_data = SAA7134_BOARD_WIS_VOYAGER, + }, { + /* Avermedia Technologies Inc */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x1461, 0xa10a), + .driver_data = SAA7134_BOARD_AVERMEDIA_505, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, 0x107d, 0x6f3a), + .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_TV2100_FM, + }, { + /* V One Multimedia PTE Ltd */ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x1779, 0x13cf), + .driver_data = SAA7134_BOARD_SNAZIO_TVPVR_PRO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133, 0x107d, 0x6f2e), + .driver_data = SAA7134_BOARD_LEADTEK_WINFAST_HDTV200_H, }, { /* --- boards without eeprom + subsystem ID --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0, - .driver_data = SAA7134_BOARD_NOAUTO, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_VENDOR_ID_PHILIPS, - .subdevice = 0, - .driver_data = SAA7134_BOARD_NOAUTO, - },{ + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134, + PCI_VENDOR_ID_PHILIPS, 0), + .driver_data = SAA7134_BOARD_NOAUTO, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130, + PCI_VENDOR_ID_PHILIPS, 0), + .driver_data = SAA7134_BOARD_NOAUTO, + }, { /* --- default catch --- */ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7130, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7133, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7134, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7135, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = SAA7134_BOARD_UNKNOWN, - },{ + PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7130), + .driver_data = SAA7134_BOARD_UNKNOWN, + }, { + PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7133), + .driver_data = SAA7134_BOARD_UNKNOWN, + }, { + PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7134), + .driver_data = SAA7134_BOARD_UNKNOWN, + }, { + PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7135), + .driver_data = SAA7134_BOARD_UNKNOWN, + }, { /* --- end of list --- */ } }; diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 1eef4e102972..f2298e8bb96d 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -361,22 +361,14 @@ static struct saa7146_pci_extension_data hexium_gemini_dual_4bnc = { static const struct pci_device_id pci_tbl[] = { { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2401, - .driver_data = (unsigned long) &hexium_gemini_4bnc, - }, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x2401), + .driver_data = (unsigned long)&hexium_gemini_4bnc, + }, { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2402, - .driver_data = (unsigned long) &hexium_gemini_dual_4bnc, - }, - { - .vendor = 0, - } + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x2402), + .driver_data = (unsigned long)&hexium_gemini_dual_4bnc, + }, + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 6f1b4bff7596..8ef2a4e8235d 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -425,29 +425,16 @@ static struct saa7146_pci_extension_data hexium_orion_4bnc = { static const struct pci_device_id pci_tbl[] = { { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x0000, - .subdevice = 0x0000, - .driver_data = (unsigned long) &hexium_hv_pci6, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x0101, - .driver_data = (unsigned long) &hexium_orion_1svhs_3bnc, - }, - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x17c8, - .subdevice = 0x2101, - .driver_data = (unsigned long) &hexium_orion_4bnc, - }, - { - .vendor = 0, - } + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x0000, 0x0000), + .driver_data = (unsigned long)&hexium_hv_pci6, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x0101), + .driver_data = (unsigned long)&hexium_orion_1svhs_3bnc, + }, { + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x17c8, 0x2101), + .driver_data = (unsigned long)&hexium_orion_4bnc, + }, + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c index d931b4e3052f..d759e8a87e24 100644 --- a/drivers/media/pci/saa7146/mxb.c +++ b/drivers/media/pci/saa7146/mxb.c @@ -821,14 +821,10 @@ static struct saa7146_pci_extension_data mxb = { static const struct pci_device_id pci_tbl[] = { { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x0000, - .subdevice = 0x0000, + PCI_VDEVICE_SUB(PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, 0x0000, 0x0000), .driver_data = (unsigned long)&mxb, - }, { - .vendor = 0, - } + }, + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 6bcde506adf5..ac5eb6b923e2 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -878,6 +878,9 @@ static int get_resources(struct saa7164_dev *dev) if (request_mem_region(pci_resource_start(dev->pci, 2), pci_resource_len(dev->pci, 2), dev->name)) return 0; + + release_mem_region(pci_resource_start(dev->pci, 0), + pci_resource_len(dev->pci, 0)); } printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx or 0x%llx\n", @@ -1000,8 +1003,7 @@ static int saa7164_dev_setup(struct saa7164_dev *dev) dev->name, dev->pci->subsystem_vendor, dev->pci->subsystem_device); - saa7164_devcount--; - return -ENODEV; + goto err_devlist; } /* PCI/e allocations */ @@ -1039,7 +1041,7 @@ err_ioremap_bar2: iounmap(dev->lmmio); err_ioremap_bar0: release_resources(dev); - +err_devlist: scoped_guard(mutex, &devlist) { list_del(&dev->devlist); } @@ -1535,10 +1537,7 @@ static void saa7164_finidev(struct pci_dev *pci_dev) static const struct pci_device_id saa7164_pci_tbl[] = { { /* SAA7164 */ - .vendor = 0x1131, - .device = 0x7164, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + PCI_DEVICE(0x1131, 0x7164), }, { /* --- end of list --- */ } diff --git a/drivers/media/pci/smipcie/smipcie-main.c b/drivers/media/pci/smipcie/smipcie-main.c index 387c29958c98..5f18abb48b17 100644 --- a/drivers/media/pci/smipcie/smipcie-main.c +++ b/drivers/media/pci/smipcie/smipcie-main.c @@ -1097,8 +1097,7 @@ static const struct smi_cfg_info technotrend_s2_4200_cfg = { /* PCI IDs */ #define SMI_ID(_subvend, _subdev, _driverdata) { \ - .vendor = SMI_VID, .device = SMI_PID, \ - .subvendor = _subvend, .subdevice = _subdev, \ + PCI_DEVICE_SUB(SMI_VID, SMI_PID, (_subvend), (_subdev)), \ .driver_data = (unsigned long)&_driverdata } static const struct pci_device_id smi_id_table[] = { @@ -1106,7 +1105,7 @@ static const struct pci_device_id smi_id_table[] = { SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg), SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg), SMI_ID(0x13c2, 0x3016, technotrend_s2_4200_cfg), - {0} + { } }; MODULE_DEVICE_TABLE(pci, smi_id_table); diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 11cddf4b4312..282c2c87151f 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -656,7 +656,7 @@ static const struct pci_device_id solo_id_table[] = { .driver_data = SOLO_DEV_6110 }, { PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_BC_6110_16), .driver_data = SOLO_DEV_6110 }, - {0,} + { } }; MODULE_DEVICE_TABLE(pci, solo_id_table); diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c index 8b496b959d7e..eb82a670c5bf 100644 --- a/drivers/media/pci/ttpci/budget-ci.c +++ b/drivers/media/pci/ttpci/budget-ci.c @@ -1537,9 +1537,7 @@ static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b), - { - .vendor = 0, - } + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index 95370156aff5..c9f419fc07ad 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c @@ -858,9 +858,7 @@ static const struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020), MAKE_EXTENSION_PCI(sylt, 0x1131, 0x4f52), - { - .vendor = 0, - } + { } }; MODULE_DEVICE_TABLE(pci, pci_tbl); diff --git a/drivers/media/pci/tw5864/tw5864-core.c b/drivers/media/pci/tw5864/tw5864-core.c index 832788603f88..6ec8bce4ac4f 100644 --- a/drivers/media/pci/tw5864/tw5864-core.c +++ b/drivers/media/pci/tw5864/tw5864-core.c @@ -72,8 +72,8 @@ MODULE_PARM_DESC(video_nr, "video devices numbers array"); * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. */ static const struct pci_device_id tw5864_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_5864)}, - {0,} + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_5864) }, + { } }; void tw5864_irqmask_apply(struct tw5864_dev *dev) diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 08b7ce1043aa..509d7ddec150 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -62,14 +62,14 @@ static atomic_t tw68_instance = ATOMIC_INIT(0); * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. */ static const struct pci_device_id tw68_pci_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6800)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6801)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6804)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_1)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_2)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_3)}, - {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_4)}, - {0,} + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6800) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6801) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6804) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_1) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_2) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_3) }, + { PCI_VDEVICE(TECHWELL, PCI_DEVICE_ID_TECHWELL_6816_4) }, + { } }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c index a10e38221817..5a4ab329c06e 100644 --- a/drivers/media/pci/tw686x/tw686x-core.c +++ b/drivers/media/pci/tw686x/tw686x-core.c @@ -416,25 +416,24 @@ static void tw686x_remove(struct pci_dev *pci_dev) /* driver_data is number of A/V channels */ static const struct pci_device_id tw686x_pci_tbl[] = { { - PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6864), - .driver_data = 4 - }, - { - PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6865), /* not tested */ - .driver_data = 4 | TYPE_SECOND_GEN + PCI_VDEVICE(TECHWELL, 0x6864), + .driver_data = 4, + }, { + PCI_VDEVICE(TECHWELL, 0x6865), /* not tested */ + .driver_data = 4 | TYPE_SECOND_GEN, }, /* * TW6868 supports 8 A/V channels with an external TW2865 chip; * not supported by the driver. */ { - PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6868), /* not tested */ - .driver_data = 4 + PCI_VDEVICE(TECHWELL, 0x6868), /* not tested */ + .driver_data = 4, + }, { + PCI_VDEVICE(TECHWELL, 0x6869), + .driver_data = 8 | TYPE_SECOND_GEN }, - { - PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6869), - .driver_data = 8 | TYPE_SECOND_GEN}, - {} + { } }; MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl); diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c index f707bdc1fb0f..e5ff407318df 100644 --- a/drivers/media/pci/zoran/zoran_card.c +++ b/drivers/media/pci/zoran/zoran_card.c @@ -75,8 +75,9 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(ZORAN_VERSION); #define ZR_DEVICE(subven, subdev, data) { \ - .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \ - .subvendor = (subven), .subdevice = (subdev), .driver_data = (data) } + PCI_DEVICE_SUB(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, \ + (subven), (subdev)), \ + .driver_data = (data) } static const struct pci_device_id zr36067_pci_tbl[] = { ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC10PLUS, DC10_PLUS), @@ -84,7 +85,7 @@ static const struct pci_device_id zr36067_pci_tbl[] = { ZR_DEVICE(PCI_VENDOR_ID_ELECTRONICDESIGNGMBH, PCI_DEVICE_ID_LML_33R10, LML33R10), ZR_DEVICE(PCI_VENDOR_ID_IOMEGA, PCI_DEVICE_ID_IOMEGA_BUZ, BUZ), ZR_DEVICE(PCI_ANY_ID, PCI_ANY_ID, NUM_CARDS), - {0} + { } }; MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); @@ -885,7 +886,7 @@ static int zoran_init_video_device(struct zoran *zr, struct video_device *video_ static void zoran_exit_video_devices(struct zoran *zr) { video_unregister_device(zr->video_dev); - kfree(zr->video_dev); + zr->video_dev = NULL; } static int zoran_init_video_devices(struct zoran *zr) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 0b33e927bd59..2c7699b6610b 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -72,6 +72,7 @@ source "drivers/media/platform/atmel/Kconfig" source "drivers/media/platform/broadcom/Kconfig" source "drivers/media/platform/cadence/Kconfig" source "drivers/media/platform/chips-media/Kconfig" +source "drivers/media/platform/dreamchip/Kconfig" source "drivers/media/platform/imagination/Kconfig" source "drivers/media/platform/intel/Kconfig" source "drivers/media/platform/marvell/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 16c185752474..d47c47d817da 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -15,6 +15,7 @@ obj-y += atmel/ obj-y += broadcom/ obj-y += cadence/ obj-y += chips-media/ +obj-y += dreamchip/ obj-y += imagination/ obj-y += intel/ obj-y += marvell/ diff --git a/drivers/media/platform/amd/isp4/Kconfig b/drivers/media/platform/amd/isp4/Kconfig index 9d1927af1cb8..77b61fae82ba 100644 --- a/drivers/media/platform/amd/isp4/Kconfig +++ b/drivers/media/platform/amd/isp4/Kconfig @@ -5,6 +5,7 @@ config VIDEO_AMD_ISP4_CAPTURE depends on DRM_AMDGPU && DRM_AMD_ISP depends on HAS_DMA depends on VIDEO_DEV + select MEDIA_CONTROLLER select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS select VIDEOBUF2_V4L2 diff --git a/drivers/media/platform/amd/isp4/isp4_interface.c b/drivers/media/platform/amd/isp4/isp4_interface.c index 8d73f66bb42c..4801617f9559 100644 --- a/drivers/media/platform/amd/isp4/isp4_interface.c +++ b/drivers/media/platform/amd/isp4/isp4_interface.c @@ -148,12 +148,9 @@ static void isp4if_gpu_mem_free(struct isp4_interface *ispif, struct isp4if_gpu_mem_info **mem_info_ptr) { struct isp4if_gpu_mem_info *mem_info = *mem_info_ptr; - struct device *dev = ispif->dev; - if (!mem_info) { - dev_err(dev, "invalid mem_info\n"); + if (!mem_info) return; - } *mem_info_ptr = NULL; isp_kernel_buffer_free(&mem_info->mem_handle, &mem_info->gpu_mc_addr, @@ -201,6 +198,7 @@ static int isp4if_alloc_fw_gpumem(struct isp4_interface *ispif) error_no_memory: dev_err(dev, "failed to allocate gpu memory\n"); + isp4if_dealloc_fw_gpumem(ispif); return -ENOMEM; } @@ -375,7 +373,7 @@ static int isp4if_send_fw_cmd(struct isp4_interface *ispif, u32 cmd_id, return -ENOMEM; /* Get two references: one for the resp thread, one for us */ - atomic_set(&ele->refcnt, 2); + refcount_set(&ele->refcnt, 2); init_completion(&ele->cmd_done); } @@ -455,7 +453,7 @@ err_dequeue_ele: put_ele_ref: /* Don't free the command if we didn't put the last reference */ - if (ele && atomic_dec_return(&ele->refcnt)) + if (ele && !refcount_dec_and_test(&ele->refcnt)) ele = NULL; free_ele: diff --git a/drivers/media/platform/amd/isp4/isp4_interface.h b/drivers/media/platform/amd/isp4/isp4_interface.h index ce3ac9b9e5cd..04db71cd54e6 100644 --- a/drivers/media/platform/amd/isp4/isp4_interface.h +++ b/drivers/media/platform/amd/isp4/isp4_interface.h @@ -68,7 +68,7 @@ struct isp4if_cmd_element { u32 seq_num; u32 cmd_id; struct completion cmd_done; - atomic_t refcnt; + refcount_t refcnt; }; struct isp4_interface { diff --git a/drivers/media/platform/amd/isp4/isp4_subdev.c b/drivers/media/platform/amd/isp4/isp4_subdev.c index 48deea79ce6c..6716ab9c128a 100644 --- a/drivers/media/platform/amd/isp4/isp4_subdev.c +++ b/drivers/media/platform/amd/isp4/isp4_subdev.c @@ -391,7 +391,7 @@ static void isp4sd_fw_resp_cmd_done(struct isp4_subdev *isp_subdev, if (ele) { complete(&ele->cmd_done); - if (atomic_dec_and_test(&ele->refcnt)) + if (refcount_dec_and_test(&ele->refcnt)) kfree(ele); } } @@ -687,7 +687,7 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd) if (ret) { dev_err(dev, "fail to power on isp_subdev ret %d\n", ret); - goto err_deinit; + goto err_module_disable; } /* ISPPG ISP Power Status */ @@ -697,7 +697,7 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd) dev_err(dev, "fail to set performance state %u, ret %d\n", perf_state, ret); - goto err_deinit; + goto err_power_off; } ispif->status = ISP4IF_STATUS_PWR_ON; @@ -709,12 +709,12 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd) ret = isp4if_start(ispif); if (ret) { dev_err(dev, "fail to start isp_subdev interface\n"); - goto err_deinit; + goto err_perf_restore; } if (isp4sd_start_resp_proc_threads(isp_subdev)) { dev_err(dev, "isp_start_resp_proc_threads fail\n"); - goto err_deinit; + goto err_stop_interface; } dev_dbg(dev, "create resp threads ok\n"); @@ -724,8 +724,24 @@ int isp4sd_pwron_and_init(struct v4l2_subdev *sd) isp_subdev->irq_enabled = true; return 0; -err_deinit: - isp4sd_pwroff_and_deinit(sd); + +err_stop_interface: + isp4if_stop(ispif); +err_perf_restore: + ret = dev_pm_genpd_set_performance_state(dev, ISP4SD_PERFORMANCE_STATE_LOW); + if (ret) + dev_err(dev, "fail to set performance state %u, ret %d\n", + ISP4SD_PERFORMANCE_STATE_LOW, ret); +err_power_off: + isp4hw_wreg(isp_subdev->mmio, ISP_SOFT_RESET, 0); + isp4hw_wreg(isp_subdev->mmio, ISP_POWER_STATUS, 0); + ret = pm_runtime_put_sync(dev); + if (ret) + dev_err(dev, "power off isp_subdev fail %d\n", ret); + ispif->status = ISP4IF_STATUS_PWR_OFF; +err_module_disable: + isp4sd_module_enable(isp_subdev, false); + msleep(20); return -EINVAL; } diff --git a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c index aec3eed0e443..ae0777a20bda 100644 --- a/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c +++ b/drivers/media/platform/amlogic/c3/isp/c3-isp-params.c @@ -535,16 +535,52 @@ static const c3_isp_block_handler c3_isp_params_handlers[] = { [C3_ISP_PARAMS_BLOCK_BLC] = c3_isp_params_cfg_blc, }; -#define C3_ISP_PARAMS_BLOCK_INFO(block, data) \ +static int +c3_isp_params_awb_config_validate(struct device *dev, + const struct v4l2_isp_block_header *block) +{ + const struct c3_isp_params_awb_config *cfg = + (const struct c3_isp_params_awb_config *)block; + + if (cfg->horiz_zones_num * cfg->vert_zones_num > C3_ISP_AWB_MAX_ZONES) { + dev_dbg(dev, "Invalid number of AWB measurement zones\n"); + return -EINVAL; + } + + return 0; +} + +static int +c3_isp_params_ae_config_validate(struct device *dev, + const struct v4l2_isp_block_header *block) +{ + const struct c3_isp_params_ae_config *cfg = + (const struct c3_isp_params_ae_config *)block; + + if (cfg->horiz_zones_num * cfg->vert_zones_num > C3_ISP_AE_MAX_ZONES) { + dev_dbg(dev, "Invalid number of AE measurement zones\n"); + return -EINVAL; + } + + return 0; +} + +#define C3_ISP_PARAMS_BLOCK_INFO_CBK(block, data, cbk) \ [C3_ISP_PARAMS_BLOCK_ ## block] = { \ .size = sizeof(struct c3_isp_params_ ## data), \ + .block_validate = (cbk)\ } +#define C3_ISP_PARAMS_BLOCK_INFO(block, data) \ + C3_ISP_PARAMS_BLOCK_INFO_CBK(block, data, NULL) + static const struct v4l2_isp_params_block_type_info c3_isp_params_block_types_info[] = { C3_ISP_PARAMS_BLOCK_INFO(AWB_GAINS, awb_gains), - C3_ISP_PARAMS_BLOCK_INFO(AWB_CONFIG, awb_config), - C3_ISP_PARAMS_BLOCK_INFO(AE_CONFIG, ae_config), + C3_ISP_PARAMS_BLOCK_INFO_CBK(AWB_CONFIG, awb_config, + &c3_isp_params_awb_config_validate), + C3_ISP_PARAMS_BLOCK_INFO_CBK(AE_CONFIG, ae_config, + &c3_isp_params_ae_config_validate), C3_ISP_PARAMS_BLOCK_INFO(AF_CONFIG, af_config), C3_ISP_PARAMS_BLOCK_INFO(PST_GAMMA, pst_gamma), C3_ISP_PARAMS_BLOCK_INFO(CCM, ccm), diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index 0b3d58b9f2f7..2ba4ae20f829 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -973,8 +973,6 @@ static int venc_start_session(struct vpu_inst *inst, u32 type) venc->ready_count = 0; venc->stopped = false; vpu_process_output_buffer(inst); - if (venc->frame_count == 0) - dev_err(inst->dev, "[%d] there is no input when starting\n", inst->id); return 0; error: diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-capture.c b/drivers/media/platform/arm/mali-c55/mali-c55-capture.c index 7aaa5c3f7354..ff01553026fb 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-capture.c +++ b/drivers/media/platform/arm/mali-c55/mali-c55-capture.c @@ -857,10 +857,8 @@ static int mali_c55_register_cap_dev(struct mali_c55 *mali_c55, cap_dev->pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&cap_dev->vdev.entity, 1, &cap_dev->pad); - if (ret) { - mutex_destroy(&cap_dev->lock); + if (ret) goto err_destroy_mutex; - } vb2q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; vb2q->io_modes = VB2_MMAP | VB2_DMABUF; diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-core.c b/drivers/media/platform/arm/mali-c55/mali-c55-core.c index 94a389b3f833..f28e9f4354ac 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-core.c +++ b/drivers/media/platform/arm/mali-c55/mali-c55-core.c @@ -698,6 +698,8 @@ static int __mali_c55_power_on(struct mali_c55 *mali_c55) mali_c55->resets); if (ret) { dev_err(mali_c55->dev, "failed to deassert resets\n"); + clk_bulk_disable_unprepare(ARRAY_SIZE(mali_c55->clks), + mali_c55->clks); return ret; } diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-params.c b/drivers/media/platform/arm/mali-c55/mali-c55-params.c index de0e9d898db7..70106276b7e4 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-params.c +++ b/drivers/media/platform/arm/mali-c55/mali-c55-params.c @@ -46,6 +46,9 @@ * @awb_config: For header->type == MALI_C55_PARAM_BLOCK_AWB_CONFIG * @shading_config: For header->type == MALI_C55_PARAM_MESH_SHADING_CONFIG * @shading_selection: For header->type == MALI_C55_PARAM_MESH_SHADING_SELECTION + * @ccm: For header->type == MALI_C55_PARAM_BLOCK_CCM + * @gamma: For header->type == MALI_C55_PARAM_BLOCK_GAMMA_FR and + * header->type = MALI_C55_PARAM_BLOCK_GAMMA_DS * @data: Allows easy initialisation of a union variable with a * pointer into a __u8 array. */ @@ -59,6 +62,8 @@ union mali_c55_params_block { const struct mali_c55_params_awb_config *awb_config; const struct mali_c55_params_mesh_shading_config *shading_config; const struct mali_c55_params_mesh_shading_selection *shading_selection; + const struct mali_c55_params_ccm *ccm; + const struct mali_c55_params_gamma *gamma; const __u8 *data; }; @@ -212,6 +217,7 @@ mali_c55_params_aexp_hist_weights(struct mali_c55 *mali_c55, val = params->zone_weights[MALI_C55_MAX_ZONES - 1]; addr = base + MALI_C55_AEXP_HIST_ZONE_WEIGHTS_OFFSET + (4 * 56); + mali_c55_ctx_write(mali_c55, addr, val & MALI_C55_AEXP_HIST_ZONE_WEIGHT_MASK); } static void mali_c55_params_digital_gain(struct mali_c55 *mali_c55, @@ -414,6 +420,116 @@ static void mali_c55_params_lsc_selection(struct mali_c55 *mali_c55, params->mesh_strength); } +static void mali_c55_params_ccm(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + const struct mali_c55_params_ccm *params = block.ccm; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + mali_c55_ctx_write(mali_c55, MALI_C55_REG_CCM_ENABLE, 0); + return; + } + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_R_R, + MALI_C55_CCM_COEF_MASK, params->coeffs[0][0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_R_G, + MALI_C55_CCM_COEF_MASK, params->coeffs[0][1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_R_B, + MALI_C55_CCM_COEF_MASK, params->coeffs[0][2]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_G_R, + MALI_C55_CCM_COEF_MASK, params->coeffs[1][0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_G_G, + MALI_C55_CCM_COEF_MASK, params->coeffs[1][1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_G_B, + MALI_C55_CCM_COEF_MASK, params->coeffs[1][2]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_B_R, + MALI_C55_CCM_COEF_MASK, params->coeffs[2][0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_B_G, + MALI_C55_CCM_COEF_MASK, params->coeffs[2][1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_COEF_B_B, + MALI_C55_CCM_COEF_MASK, params->coeffs[2][2]); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_GAIN_R, + MALI_C55_CCM_ANTIFOG_GAIN_MASK, params->gains[0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_GAIN_G, + MALI_C55_CCM_ANTIFOG_GAIN_MASK, params->gains[1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_GAIN_B, + MALI_C55_CCM_ANTIFOG_GAIN_MASK, params->gains[2]); + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_OFFSET_R, + MALI_C55_CCM_ANTIFOG_OFFSET_MASK, params->offs[0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_OFFSET_G, + MALI_C55_CCM_ANTIFOG_OFFSET_MASK, params->offs[1]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_CCM_ANTIFOG_OFFSET_B, + MALI_C55_CCM_ANTIFOG_OFFSET_MASK, params->offs[2]); + + mali_c55_ctx_write(mali_c55, MALI_C55_REG_CCM_ENABLE, 1); +} + +static void mali_c55_params_gamma(struct mali_c55 *mali_c55, + union mali_c55_params_block block, + __u32 offset, __u32 lut_base) +{ + const struct mali_c55_params_gamma *params = block.gamma; + + if (block.header->flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_RGB_ENABLE + offset, + MALI_C55_GAMMA_ENABLE_MASK, 0x00); + return; + } + + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_GAMMA_GAINS_RG + offset, + MALI_C55_GAMMA_GAIN_R_MASK, params->gains[0]); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_GAMMA_GAINS_RG + offset, + MALI_C55_GAMMA_GAIN_G_MASK, + MALI_C55_GAMMA_GAIN_G(params->gains[1])); + mali_c55_ctx_update_bits(mali_c55, MALI_C55_REG_GAMMA_GAINS_B + offset, + MALI_C55_GAMMA_GAIN_B_MASK, params->gains[2]); + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_OFFSETS_RG + offset, + MALI_C55_GAMMA_OFFSET_R_MASK, + params->offs[0]); + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_OFFSETS_RG + offset, + MALI_C55_GAMMA_OFFSET_G_MASK, + MALI_C55_GAMMA_OFFSET_G(params->offs[1])); + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_OFFSETS_B + offset, + MALI_C55_GAMMA_OFFSET_B_MASK, + params->offs[2]); + + for (unsigned int i = 0; i < MALI_C55_NUM_GAMMA_LUT_ELEMENTS; i++) { + __u32 addr = lut_base + (i * 4); + + mali_c55_ctx_write(mali_c55, addr, params->lut[i]); + } + + mali_c55_ctx_update_bits(mali_c55, + MALI_C55_REG_GAMMA_RGB_ENABLE + offset, + MALI_C55_GAMMA_ENABLE_MASK, 0x1); +} + +static void mali_c55_params_gamma_fr(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + return mali_c55_params_gamma(mali_c55, block, + MALI_C55_CAP_DEV_FR_REG_OFFSET, + MALI_C55_REG_FR_GAMMA_RGB_MEM); +} + +static void mali_c55_params_gamma_ds(struct mali_c55 *mali_c55, + union mali_c55_params_block block) +{ + /* We cannot apply parameters to DS if it is not fitted. */ + if (!(mali_c55->capabilities & MALI_C55_GPS_DS_PIPE_FITTED)) + return; + + return mali_c55_params_gamma(mali_c55, block, + MALI_C55_CAP_DEV_DS_REG_OFFSET, + MALI_C55_REG_DS_GAMMA_RGB_MEM); +} + static const mali_c55_params_handler mali_c55_params_handlers[] = { [MALI_C55_PARAM_BLOCK_SENSOR_OFFS] = &mali_c55_params_sensor_offs, [MALI_C55_PARAM_BLOCK_AEXP_HIST] = &mali_c55_params_aexp_hist, @@ -426,6 +542,9 @@ static const mali_c55_params_handler mali_c55_params_handlers[] = { [MALI_C55_PARAM_BLOCK_AWB_GAINS_AEXP] = &mali_c55_params_awb_gains, [MALI_C55_PARAM_MESH_SHADING_CONFIG] = &mali_c55_params_lsc_config, [MALI_C55_PARAM_MESH_SHADING_SELECTION] = &mali_c55_params_lsc_selection, + [MALI_C55_PARAM_BLOCK_CCM] = &mali_c55_params_ccm, + [MALI_C55_PARAM_BLOCK_GAMMA_FR] = &mali_c55_params_gamma_fr, + [MALI_C55_PARAM_BLOCK_GAMMA_DS] = &mali_c55_params_gamma_ds, }; static const struct v4l2_isp_params_block_type_info @@ -463,6 +582,15 @@ mali_c55_params_block_types_info[] = { [MALI_C55_PARAM_MESH_SHADING_SELECTION] = { .size = sizeof(struct mali_c55_params_mesh_shading_selection), }, + [MALI_C55_PARAM_BLOCK_CCM] = { + .size = sizeof(struct mali_c55_params_ccm), + }, + [MALI_C55_PARAM_BLOCK_GAMMA_FR] = { + .size = sizeof(struct mali_c55_params_gamma), + }, + [MALI_C55_PARAM_BLOCK_GAMMA_DS] = { + .size = sizeof(struct mali_c55_params_gamma), + }, }; static_assert(ARRAY_SIZE(mali_c55_params_handlers) == @@ -487,7 +615,7 @@ static int mali_c55_params_g_fmt_meta_out(struct file *file, void *fh, { static const struct v4l2_meta_format mfmt = { .dataformat = V4L2_META_FMT_MALI_C55_PARAMS, - .buffersize = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE), + .buffersize = v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE), }; f->fmt.meta = mfmt; @@ -540,13 +668,13 @@ mali_c55_params_queue_setup(struct vb2_queue *q, unsigned int *num_buffers, if (*num_planes && *num_planes > 1) return -EINVAL; - if (sizes[0] && sizes[0] < v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)) + if (sizes[0] && sizes[0] < v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE)) return -EINVAL; *num_planes = 1; if (!sizes[0]) - sizes[0] = v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE); + sizes[0] = v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE); return 0; } @@ -556,7 +684,7 @@ static int mali_c55_params_buf_init(struct vb2_buffer *vb) struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct mali_c55_params_buf *buf = to_mali_c55_params_buf(vbuf); - buf->config = kvmalloc(v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE), + buf->config = kvmalloc(v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE), GFP_KERNEL); if (!buf->config) return -ENOMEM; @@ -583,7 +711,7 @@ static int mali_c55_params_buf_prepare(struct vb2_buffer *vb) int ret; ret = v4l2_isp_params_validate_buffer_size(mali_c55->dev, vb, - v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); + v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); if (ret) return ret; @@ -593,7 +721,7 @@ static int mali_c55_params_buf_prepare(struct vb2_buffer *vb) * changed to the buffer content whilst the driver processes it. */ - memcpy(buf->config, config, v4l2_isp_params_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); + memcpy(buf->config, config, v4l2_isp_buffer_size(MALI_C55_PARAMS_MAX_SIZE)); return v4l2_isp_params_validate_buffer(mali_c55->dev, vb, buf->config, mali_c55_params_block_types_info, diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-registers.h b/drivers/media/platform/arm/mali-c55/mali-c55-registers.h index f098effde7b4..8a7c3bfe7051 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-registers.h +++ b/drivers/media/platform/arm/mali-c55/mali-c55-registers.h @@ -173,7 +173,7 @@ enum mali_c55_interrupts { #define MALI_C55_AEXP_HIST_SWITCH_MASK GENMASK(14, 13) #define MALI_C55_AEXP_HIST_SWITCH(x) ((x) << 13) #define MALI_C55_AEXP_IHIST_DISABLE_MASK BIT(16) -#define MALI_C55_AEXP_IHIST_DISABLE (0x01 << 12) +#define MALI_C55_AEXP_IHIST_DISABLE (0x01 << 16) #define MALI_C55_AEXP_SRC_MASK BIT(24) #define MALI_C55_REG_TPG_CH0 0x18ed8 @@ -422,15 +422,17 @@ enum mali_c55_interrupts { #define MALI_C55_REG_GAMMA_RGB_ENABLE 0x1c064 #define MALI_C55_GAMMA_ENABLE_MASK BIT(0) -#define MALI_C55_REG_GAMMA_GAINS_1 0x1c068 +#define MALI_C55_REG_GAMMA_GAINS_RG 0x1c068 #define MALI_C55_GAMMA_GAIN_R_MASK GENMASK(11, 0) #define MALI_C55_GAMMA_GAIN_G_MASK GENMASK(27, 16) -#define MALI_C55_REG_GAMMA_GAINS_2 0x1c06c +#define MALI_C55_GAMMA_GAIN_G(x) ((x) << 16) +#define MALI_C55_REG_GAMMA_GAINS_B 0x1c06c #define MALI_C55_GAMMA_GAIN_B_MASK GENMASK(11, 0) -#define MALI_C55_REG_GAMMA_OFFSETS_1 0x1c070 +#define MALI_C55_REG_GAMMA_OFFSETS_RG 0x1c070 #define MALI_C55_GAMMA_OFFSET_R_MASK GENMASK(11, 0) #define MALI_C55_GAMMA_OFFSET_G_MASK GENMASK(27, 16) -#define MALI_C55_REG_GAMMA_OFFSETS_2 0x1c074 +#define MALI_C55_GAMMA_OFFSET_G(x) ((x) << 16) +#define MALI_C55_REG_GAMMA_OFFSETS_B 0x1c074 #define MALI_C55_GAMMA_OFFSET_B_MASK GENMASK(11, 0) /* @@ -441,6 +443,9 @@ enum mali_c55_interrupts { #define MALI_C55_REG_FR_GAMMA_RGB_ENABLE 0x1c064 #define MALI_C55_REG_DS_GAMMA_RGB_ENABLE 0x1c1d8 +#define MALI_C55_REG_FR_GAMMA_RGB_MEM 0x18280 +#define MALI_C55_REG_DS_GAMMA_RGB_MEM 0x18484 + #define MALI_C55_REG_FR_SCALER_HFILT 0x34a8 #define MALI_C55_REG_FR_SCALER_VFILT 0x44a8 #define MALI_C55_REG_DS_SCALER_HFILT 0x14a8 diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c b/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c index c4f46651dcee..6706939b4a90 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c +++ b/drivers/media/platform/arm/mali-c55/mali-c55-resizer.c @@ -15,7 +15,7 @@ #include "mali-c55-registers.h" /* Scaling factor in Q4.20 format. */ -#define MALI_C55_RSZ_SCALER_FACTOR (1U << 20) +#define MALI_C55_RSZ_SCALER_FACTOR BIT_ULL(20) #define MALI_C55_RSZ_COEFS_BANKS 8 #define MALI_C55_RSZ_COEFS_ENTRIES 64 diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c index 8d28ba0b59a3..14bb916dd7b1 100644 --- a/drivers/media/platform/broadcom/bcm2835-unicam.c +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c @@ -2158,7 +2158,8 @@ static int unicam_video_link_validate(struct media_link *link) * In order to allow the applications using the old behaviour to * run, let's accept the old combination, but warn about it. */ - if (fmtinfo->fourcc != fmt->pixelformat) { + if (fmt->pixelformat != fmtinfo->fourcc && + fmt->pixelformat != fmtinfo->unpacked_fourcc) { if ((fmt->pixelformat == V4L2_PIX_FMT_BGR24 && format->code == MEDIA_BUS_FMT_BGR888_1X24) || (fmt->pixelformat == V4L2_PIX_FMT_RGB24 && @@ -2613,6 +2614,7 @@ static int unicam_async_nf_init(struct unicam_device *unicam) return 0; error: + v4l2_async_nf_cleanup(&unicam->notifier); fwnode_handle_put(ep_handle); return ret; } @@ -2745,6 +2747,7 @@ static void unicam_remove(struct platform_device *pdev) v4l2_device_unregister(&unicam->v4l2_dev); media_device_unregister(&unicam->mdev); v4l2_async_nf_unregister(&unicam->notifier); + v4l2_async_nf_cleanup(&unicam->notifier); unicam_subdev_cleanup(unicam); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c index bb2ba9204a83..6564cf3ec739 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c @@ -5,6 +5,7 @@ * Copyright (C) 2021-2023 CHIPS&MEDIA INC */ +#include <linux/delay.h> #include <linux/pm_runtime.h> #include "wave5-helper.h" @@ -474,7 +475,10 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst) v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } - inst->queuing_fail = false; + if (inst->queuing_fail) { + inst->queuing_fail = false; + v4l2_m2m_try_schedule(m2m_ctx); + } } static int wave5_vpu_dec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) @@ -819,7 +823,15 @@ static int wave5_vpu_dec_stop(struct vpu_instance *inst) * calls do not block on a mutex while inside this spinlock. */ spin_unlock_irqrestore(&inst->state_spinlock, flags); + /* + * V4L2_DEC_CMD_STOP can arrive while the device is runtime + * suspended (e.g. on pipeline teardown). Setting the EOS flag + * accesses VPU registers via send_firmware_command(), so the + * device must be resumed first to avoid an asynchronous SError. + */ + pm_runtime_resume_and_get(inst->dev->dev); ret = wave5_vpu_dec_set_eos_on_firmware(inst); + pm_runtime_put_autosuspend(inst->dev->dev); if (ret) return ret; @@ -1403,6 +1415,7 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { struct dec_initial_info *initial_info = &inst->codec_info->dec_info.initial_info; + struct dec_info *p_dec_info = &inst->codec_info->dec_info; if (inst->state == VPU_INST_STATE_STOP) ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); @@ -1410,6 +1423,7 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count goto return_buffers; if (inst->state == VPU_INST_STATE_INIT_SEQ && + p_dec_info->initial_info_obtained && inst->dev->product_code == WAVE521C_CODE) { if (initial_info->luma_bitdepth != 8) { dev_info(inst->dev->dev, "%s: no support for %d bit depth", @@ -1418,7 +1432,6 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count goto return_buffers; } } - } pm_runtime_put_autosuspend(inst->dev->dev); return ret; @@ -1536,15 +1549,15 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) { struct vpu_instance *inst = vb2_get_drv_priv(q); struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; - - bool check_cmd = TRUE; + unsigned long timeout; dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type); pm_runtime_resume_and_get(inst->dev->dev); inst->empty_queue = true; - while (check_cmd) { + + timeout = jiffies + msecs_to_jiffies(VPU_DEC_STOP_TIMEOUT); + while (true) { struct queue_status_info q_status; - struct dec_output_info dec_output_info; wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); if ((inst->state == VPU_INST_STATE_STOP || @@ -1553,8 +1566,10 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q) q_status.report_queue_count == 0) break; - if (wave5_vpu_dec_get_output_info(inst, &dec_output_info)) - dev_dbg(inst->dev->dev, "there is no output info\n"); + if (time_after(jiffies, timeout)) + break; + + usleep_range(1000, 2000); } v4l2_m2m_update_stop_streaming_state(m2m_ctx, q); @@ -1651,6 +1666,7 @@ static void wave5_vpu_dec_device_run(void *priv) struct queue_status_info q_status; u32 fail_res = 0; int ret = 0; + bool cmd_issued = false; dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__); pm_runtime_resume_and_get(inst->dev->dev); @@ -1662,9 +1678,13 @@ static void wave5_vpu_dec_device_run(void *priv) } else if (!inst->eos && inst->queuing_num == 0 && inst->state == VPU_INST_STATE_PIC_RUN) { - dev_dbg(inst->dev->dev, "%s: no bitstream for feeding, so skip ", __func__); - inst->empty_queue = true; - goto finish_job_and_return; + wave5_vpu_dec_give_command(inst, DEC_GET_QUEUE_STATUS, &q_status); + if (q_status.instance_queue_count == v4l2_m2m_num_src_bufs_ready(m2m_ctx)) { + dev_dbg(inst->dev->dev, "%s: no bitstream, skip\n", + __func__); + inst->empty_queue = true; + goto finish_job_and_return; + } } } @@ -1744,6 +1764,7 @@ static void wave5_vpu_dec_device_run(void *priv) inst->retry = false; if (!inst->eos) inst->queuing_num--; + cmd_issued = true; } break; default: @@ -1761,8 +1782,16 @@ finish_job_and_return: * in power and CPU time. * If EOS is passed, device_run will not call job_finish no more, it is called * only if HW is idle status in order to reduce overhead. + * + * Deferring job_finish() is only safe when this run actually queued a + * DEC_PIC command (cmd_issued): that guarantees a completion IRQ, and + * thus a later finish_decode(), will release the shared job slot. When + * device_run() is entered with no command to issue (e.g. a job that was + * queued while draining but reached the STOP state by the time it ran), + * no IRQ follows, so finish the job here to avoid leaking the slot and + * stalling every instance sharing the VPU. */ - if (!inst->sent_eos) + if (!inst->sent_eos || !cmd_issued) v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } @@ -1776,11 +1805,22 @@ static void wave5_vpu_dec_job_abort(void *priv) if (ret) return; + /* + * job_abort() runs from the STREAMOFF path and may be called while the + * device is runtime suspended. Setting the EOS flag talks to the + * firmware (send_firmware_command() accesses VPU registers), so the + * device must be resumed first; otherwise the register access faults + * with an asynchronous SError. + */ + pm_runtime_resume_and_get(inst->dev->dev); + ret = wave5_vpu_dec_set_eos_on_firmware(inst); if (ret) dev_warn(inst->dev->dev, "Setting EOS for the bitstream, fail: %d\n", ret); + pm_runtime_put_autosuspend(inst->dev->dev); + v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx); } diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index e6c94b6f2671..f9fcdf4c224b 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -1494,7 +1494,8 @@ static const struct vb2_ops wave5_vpu_enc_vb2_ops = { .stop_streaming = wave5_vpu_enc_stop_streaming, }; -static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, +static void wave5_set_default_format(struct vpu_instance *inst, + struct v4l2_pix_format_mplane *src_fmt, struct v4l2_pix_format_mplane *dst_fmt) { src_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt; @@ -1506,6 +1507,7 @@ static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt, wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_CODEC, W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT, &enc_frmsize[VPU_FMT_TYPE_CODEC]); + inst->std = wave5_to_vpu_std(dst_fmt->pixelformat, inst->type); } static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) @@ -1770,7 +1772,7 @@ static int wave5_vpu_open_enc(struct file *filp) inst->v4l2_fh.ctrl_handler = v4l2_ctrl_hdl; v4l2_ctrl_handler_setup(v4l2_ctrl_hdl); - wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt); + wave5_set_default_format(inst, &inst->src_fmt, &inst->dst_fmt); inst->conf_win.width = inst->dst_fmt.width; inst->conf_win.height = inst->dst_fmt.height; inst->colorspace = V4L2_COLORSPACE_REC709; diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h index 4ebd48d5550e..e04f2dbf3b65 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h +++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h @@ -59,7 +59,7 @@ // application specific configuration #define VPU_ENC_TIMEOUT 60000 #define VPU_DEC_TIMEOUT 60000 -#define VPU_DEC_STOP_TIMEOUT 10 +#define VPU_DEC_STOP_TIMEOUT 300 // for WAVE encoder #define USE_SRC_PRP_AXI 0 diff --git a/drivers/media/platform/dreamchip/Kconfig b/drivers/media/platform/dreamchip/Kconfig new file mode 100644 index 000000000000..d177d4ee79ae --- /dev/null +++ b/drivers/media/platform/dreamchip/Kconfig @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +source "drivers/media/platform/dreamchip/rppx1/Kconfig" diff --git a/drivers/media/platform/dreamchip/Makefile b/drivers/media/platform/dreamchip/Makefile new file mode 100644 index 000000000000..ba47ba2d136e --- /dev/null +++ b/drivers/media/platform/dreamchip/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the Dreamchip device drivers. +# + +obj-y += rppx1/ diff --git a/drivers/media/platform/dreamchip/rppx1/Kconfig b/drivers/media/platform/dreamchip/rppx1/Kconfig new file mode 100644 index 000000000000..0998a7d10bf2 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +config VIDEO_DCT_RPPX1 + tristate + depends on V4L_PLATFORM_DRIVERS + select V4L2_ISP + help + Support library for Dreamchip HDR RPP X1 High Dynamic Range Real-time + Pixel Processor (RPP). The library can be used by other drivers who + utilises the RPP as part of an ISP implementation. + + To compile this driver as a module, choose M here: the + module will be called rppx1. diff --git a/drivers/media/platform/dreamchip/rppx1/Makefile b/drivers/media/platform/dreamchip/rppx1/Makefile new file mode 100644 index 000000000000..b2bd6b5d68bc --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/Makefile @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0 +dct-rpp-x1-objs = \ + rpp_module.o \ + rpp_params.o \ + rpp_stats.o \ + rppx1.o \ + rppx1_acq.o \ + rppx1_awbg.o \ + rppx1_bd.o \ + rppx1_bdrgb.o \ + rppx1_bls.o \ + rppx1_cac.o \ + rppx1_ccor.o \ + rppx1_db.o \ + rppx1_dpcc.o \ + rppx1_exm.o \ + rppx1_ga.o \ + rppx1_hist.o \ + rppx1_hist256.o \ + rppx1_is.o \ + rppx1_lin.o \ + rppx1_lsc.o \ + rppx1_ltm.o \ + rppx1_ltmmeas.o \ + rppx1_outif.o \ + rppx1_outregs.o \ + rppx1_rmap.o \ + rppx1_rmapmeas.o \ + rppx1_shrp.o \ + rppx1_wbmeas.o \ + rppx1_xyz2luv.o + +obj-$(CONFIG_VIDEO_DCT_RPPX1) += dct-rpp-x1.o diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_module.c b/drivers/media/platform/dreamchip/rppx1/rpp_module.c new file mode 100644 index 000000000000..cb3e5a33d68c --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_module.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rppx1.h" +#include "rpp_module.h" + +int rpp_module_probe(struct rpp_module *mod, struct rppx1 *rpp, + const struct rpp_module_ops *ops, u32 base) +{ + mod->rpp = rpp; + mod->base = base; + mod->ops = ops; + + if (ops->probe) + return ops->probe(mod); + + return 0; +} + +void rpp_module_write(struct rpp_module *mod, u32 offset, u32 value) +{ + rppx1_write(mod->rpp, mod->base + offset, value); +} + +u32 rpp_module_read(struct rpp_module *mod, u32 offset) +{ + return rppx1_read(mod->rpp, mod->base + offset); +} + +void rpp_module_clrset(struct rpp_module *mod, u32 offset, u32 mask, u32 value) +{ + u32 reg = rpp_module_read(mod, offset) & ~mask; + + rpp_module_write(mod, offset, reg | value); +} diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_module.h b/drivers/media/platform/dreamchip/rppx1/rpp_module.h new file mode 100644 index 000000000000..072309d8662d --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_module.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#ifndef __RPPX1_MODULE_H__ +#define __RPPX1_MODULE_H__ + +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/v4l2-mediabus.h> + +#include <linux/media/dreamchip/rppx1-config.h> + +#include <media/rppx1.h> + +struct rpp_module_ops; + +enum rpp_raw_pattern { + RPP_RGGB = 0, + RPP_GRBG, + RPP_GBRG, + RPP_BGGR, +}; + +struct rpp_module { + struct rppx1 *rpp; + u32 base; + + const struct rpp_module_ops *ops; + + union { + struct { + enum rpp_raw_pattern raw_pattern; + } acq; + } info; +}; + +int rpp_module_probe(struct rpp_module *mod, struct rppx1 *rpp, + const struct rpp_module_ops *ops, u32 base); + +void rpp_module_write(struct rpp_module *mod, u32 offset, u32 value); +u32 rpp_module_read(struct rpp_module *mod, u32 offset); +void rpp_module_clrset(struct rpp_module *mod, u32 offset, u32 mask, u32 value); + +union rppx1_params_block { + struct v4l2_isp_block_header header; + struct rppx1_bls_params bls; + struct rppx1_lin_params lin; + struct rppx1_lsc_params lsc; + struct rppx1_awbg_params awbg; + struct rppx1_ccor_params ccor; + struct rppx1_hist_params hist; + struct rppx1_exm_params exm; + struct rppx1_wbmeas_params wbmeas; + struct rppx1_ga_params ga; +}; + +union rppx1_stats_block { + struct v4l2_isp_block_header header; + struct rppx1_hist_stats hist; + struct rppx1_exm_stats exm; + struct rppx1_wbmeas_stats wbmeas; +}; + +struct rpp_module_ops { + int (*probe)(struct rpp_module *mod); + int (*start)(struct rpp_module *mod, const struct v4l2_mbus_framefmt *fmt); + + int (*fill_params)(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv); + int (*fill_stats)(struct rpp_module *mod, + union rppx1_stats_block *block); +}; + +extern const struct rpp_module_ops rppx1_acq_ops; +extern const struct rpp_module_ops rppx1_awbg_ops; +extern const struct rpp_module_ops rppx1_bd_ops; +extern const struct rpp_module_ops rppx1_bdrgb_ops; +extern const struct rpp_module_ops rppx1_bls_ops; +extern const struct rpp_module_ops rppx1_cac_ops; +extern const struct rpp_module_ops rppx1_ccor_ops; +extern const struct rpp_module_ops rppx1_ccor_csm_ops; +extern const struct rpp_module_ops rppx1_db_ops; +extern const struct rpp_module_ops rppx1_dpcc_ops; +extern const struct rpp_module_ops rppx1_exm_ops; +extern const struct rpp_module_ops rppx1_ga_ops; +extern const struct rpp_module_ops rppx1_hist256_ops; +extern const struct rpp_module_ops rppx1_hist_ops; +extern const struct rpp_module_ops rppx1_is_ops; +extern const struct rpp_module_ops rppx1_lin_ops; +extern const struct rpp_module_ops rppx1_lsc_ops; +extern const struct rpp_module_ops rppx1_ltm_ops; +extern const struct rpp_module_ops rppx1_ltmmeas_ops; +extern const struct rpp_module_ops rppx1_outif_ops; +extern const struct rpp_module_ops rppx1_outregs_ops; +extern const struct rpp_module_ops rppx1_rmapmeas_ops; +extern const struct rpp_module_ops rppx1_rmap_ops; +extern const struct rpp_module_ops rppx1_shrp_ops; +extern const struct rpp_module_ops rppx1_wbmeas_ops; +extern const struct rpp_module_ops rppx1_xyz2luv_ops; + +#define rpp_module_call(mod, op, args...) \ + ({ \ + struct rpp_module *__mod = (mod); \ + int __result; \ + if (!__mod) \ + __result = -ENODEV; \ + else if (!__mod->ops->op) \ + __result = 0; \ + else \ + __result = __mod->ops->op(__mod, ##args); \ + __result; \ + }) + +#endif /* __RPPX1_MODULE_H__ */ diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/media/platform/dreamchip/rppx1/rpp_params.c new file mode 100644 index 000000000000..a75a27a8afd0 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include <media/v4l2-isp.h> +#include <media/videobuf2-v4l2.h> + +#include "rppx1.h" + +#define RPPX1_PARAMS_BLOCK_INFO(block, data) \ + [RPPX1_PARAMS_BLOCK_TYPE_ ## block] = { \ + .size = sizeof(struct rppx1_ ## data ## _params), \ + } + +static const struct v4l2_isp_params_block_type_info +rppx1_ext_params_blocks_info[] = { + RPPX1_PARAMS_BLOCK_INFO(BLS_PRE1, bls), + RPPX1_PARAMS_BLOCK_INFO(BLS_PRE2, bls), + RPPX1_PARAMS_BLOCK_INFO(LIN_PRE1, lin), + RPPX1_PARAMS_BLOCK_INFO(LIN_PRE2, lin), + RPPX1_PARAMS_BLOCK_INFO(LSC_PRE1, lsc), + RPPX1_PARAMS_BLOCK_INFO(LSC_PRE2, lsc), + RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE1, awbg), + RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE2, awbg), + RPPX1_PARAMS_BLOCK_INFO(CCOR_POST, ccor), + RPPX1_PARAMS_BLOCK_INFO(HIST_PRE1, hist), + RPPX1_PARAMS_BLOCK_INFO(HIST_PRE2, hist), + RPPX1_PARAMS_BLOCK_INFO(HIST_POST, hist), + RPPX1_PARAMS_BLOCK_INFO(EXM_PRE1, exm), + RPPX1_PARAMS_BLOCK_INFO(EXM_PRE2, exm), + RPPX1_PARAMS_BLOCK_INFO(WBMEAS_POST, wbmeas), + RPPX1_PARAMS_BLOCK_INFO(GA_HV, ga), + RPPX1_PARAMS_BLOCK_INFO(GA_MV, ga), +}; + +int rppx1_params(struct rppx1 *rpp, struct vb2_buffer *vb, size_t max_size, + rppx1_reg_write write, void *priv) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct v4l2_isp_buffer *cfg; + size_t block_offset; + int ret; + + ret = v4l2_isp_params_validate_buffer_size(rpp->dev, vb, max_size); + if (ret) + return ret; + + cfg = vb2_plane_vaddr(&vbuf->vb2_buf, 0); + + ret = v4l2_isp_params_validate_buffer(rpp->dev, vb, cfg, + rppx1_ext_params_blocks_info, + ARRAY_SIZE(rppx1_ext_params_blocks_info)); + if (ret) + return ret; + + /* Walk the list of parameter blocks and process them. */ + block_offset = 0; + while (block_offset < cfg->data_size) { + const union rppx1_params_block *block = + (const union rppx1_params_block *)&cfg->data[block_offset]; + struct rpp_module *module; + int ret; + + block_offset += block->header.size; + + switch (block->header.type) { + case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1: + module = &rpp->pre1.bls; + break; + case RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE1: + module = &rpp->pre1.lin; + break; + case RPPX1_PARAMS_BLOCK_TYPE_LSC_PRE1: + module = &rpp->pre1.lsc; + break; + case RPPX1_PARAMS_BLOCK_TYPE_AWBG_PRE1: + module = &rpp->pre1.awbg; + break; + case RPPX1_PARAMS_BLOCK_TYPE_CCOR_POST: + module = &rpp->post.ccor; + break; + case RPPX1_PARAMS_BLOCK_TYPE_HIST_POST: + module = &rpp->post.hist; + break; + case RPPX1_PARAMS_BLOCK_TYPE_EXM_PRE1: + module = &rpp->pre1.exm; + break; + case RPPX1_PARAMS_BLOCK_TYPE_WBMEAS_POST: + module = &rpp->post.wbmeas; + break; + case RPPX1_PARAMS_BLOCK_TYPE_GA_HV: + module = &rpp->hv.ga; + break; + default: + dev_warn(rpp->dev, + "Not handled RPPX1 block type: 0x%04x\n", + block->header.type); + continue; + } + + ret = rpp_module_call(module, fill_params, block, write, priv); + if (ret) { + dev_err(rpp->dev, + "Error processing RPPX1 block type: 0x%04x\n", + block->header.type); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(rppx1_params); diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_stats.c b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c new file mode 100644 index 000000000000..4c7fe611d004 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rpp_stats.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rppx1.h" +#include "rpp_module.h" + +#include <media/v4l2-isp.h> + +#define RPPX1_STATS_BLOCK_INFO(type, block) \ + [RPPX1_STATS_BLOCK_TYPE_ ## type] = { \ + .size = sizeof(struct rppx1_ ## block ## _stats), \ + } + +static const struct v4l2_isp_stats_block_type_info +rppx1_stats_blocks_info[] = { + RPPX1_STATS_BLOCK_INFO(HIST_POST, hist), + RPPX1_STATS_BLOCK_INFO(EXM_PRE1, exm), + RPPX1_STATS_BLOCK_INFO(WBMEAS_POST, wbmeas), +}; + +#define rppx1_init_stats_block(rpp, buf, type) \ + ((union rppx1_stats_block *) \ + v4l2_isp_stats_init_block((rpp)->dev, (buf), \ + rppx1_stats_blocks_info, \ + ARRAY_SIZE(rppx1_stats_blocks_info), \ + (type), RPPX1_STATS_MAX_SIZE)) \ + +void rppx1_stats_fill_isr(struct rppx1 *rpp, u32 isc, void *buf) +{ + struct v4l2_isp_buffer *stats = buf; + union rppx1_stats_block *block; + + v4l2_isp_stats_init_buffer(stats, V4L2_ISP_VERSION_V1); + + if (isc & RPPX1_IRQ_ID_POST_HIST_MEAS) { + block = rppx1_init_stats_block(rpp, stats, + RPPX1_STATS_BLOCK_TYPE_HIST_POST); + if (IS_ERR(block)) + return; + + rpp_module_call(&rpp->post.hist, fill_stats, block); + } + + if (isc & RPPX1_IRQ_ID_PRE1_EXM) { + block = rppx1_init_stats_block(rpp, stats, + RPPX1_STATS_BLOCK_TYPE_EXM_PRE1); + if (IS_ERR(block)) + return; + + rpp_module_call(&rpp->pre1.exm, fill_stats, block); + } + + if (isc & RPPX1_IRQ_ID_POST_AWB_MEAS) { + block = rppx1_init_stats_block(rpp, stats, + RPPX1_STATS_BLOCK_TYPE_WBMEAS_POST); + if (IS_ERR(block)) + return; + + rpp_module_call(&rpp->post.wbmeas, fill_stats, block); + } +} +EXPORT_SYMBOL_GPL(rppx1_stats_fill_isr); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1.c b/drivers/media/platform/dreamchip/rppx1/rppx1.c new file mode 100644 index 000000000000..c502be797914 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + * + * Support library for Dreamchip HDR RPPX1 High Dynamic Range Real-time Pixel + * Processor. + */ + +#include <linux/io.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "rppx1.h" + +/* RPP_HDR Base Addresses */ +#define RPPX1_HDRREGS_BASE 0x0000 +#define RPPX1_HDR_IRQ_BASE 0x0200 +#define RPPX1_RPP_OUT_BASE 0x0800 +#define RPPX1_RPP_RMAP_BASE 0x0c00 +#define RPPX1_RPP_RMAP_MEAS_BASE 0x1000 +#define RPPX1_RPP_MAIN_PRE1_BASE 0x2000 +#define RPPX1_RPP_MAIN_PRE2_BASE 0x4000 +#define RPPX1_RPP_MAIN_POST_BASE 0xa000 +#define RPPX1_RPP_MVOUT_BASE 0xc000 +#define RPPX1_RPP_FUSA_BASE 0xf000 + +#define RPPX1_RPP_HDRREGS_VERSION_REG (RPPX1_HDRREGS_BASE + 0x0000) + +#define RPPX1_RPP_HDR_UPD_REG (RPPX1_HDRREGS_BASE + 0x0004) +#define RPPX1_RPP_HDR_UPD_REGS_GEN_CFG_UPD BIT(1) +#define RPPX1_RPP_HDR_UPD_REGS_CFG_UPD BIT(0) + +#define RPPX1_RESERVED_3_REG (RPPX1_HDRREGS_BASE + 0x0008) + +#define RPPX1_RPP_HDR_INFORM_ENABLE_REG (RPPX1_HDRREGS_BASE + 0x000c) +#define RPPX1_RPP_HDR_INFORM_ENABLE_ENABLE 1 +#define RPPX1_RPP_HDR_INFORM_ENABLE_DISABLE 0 + +#define RPPX1_RPP_HDR_OUT_IF_ON_REG (RPPX1_HDRREGS_BASE + 0x0010) +#define RPPX1_RPP_HDR_OUT_IF_OFF_REG (RPPX1_HDRREGS_BASE + 0x0014) + +#define RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_REG (RPPX1_HDRREGS_BASE + 0x0018) +#define RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_ENABLE 1 +#define RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_DISABLE 0 + +#define RPPX1_RPP_ISM (RPPX1_HDR_IRQ_BASE + 0x00) +#define RPPX1_RPP_RIS (RPPX1_HDR_IRQ_BASE + 0x04) +#define RPPX1_RPP_MIS (RPPX1_HDR_IRQ_BASE + 0x08) +#define RPPX1_RPP_ISC (RPPX1_HDR_IRQ_BASE + 0x0c) + +/* RPP_OUT/MV_OUT Pipelines - Base Addresses */ +#define RPPX1_GAMMA_OUT_BASE 0x0000 /* HV, MV */ +#define RPPX1_IS_BASE 0x00c0 /* HV, MV */ +#define RPPX1_CSM_BASE 0x0100 /* HV, MV */ +#define RPPX1_OUT_IF_BASE 0x0200 /* HV, MV */ +#define RPPX1_RPP_OUTREGS_BASE 0x02c0 /* HV, MV */ +#define RPPX1_LUV_BASE 0x0300 /* MV */ + +/* PRE1/PRE2/POST Pipelines - Base Addresses */ +#define RPPX1_ACQ_BASE 0x0080 /* PRE1, PRE2 */ +#define RPPX1_BLS_BASE 0x0100 /* PRE1, PRE2 */ +#define RPPX1_GAMMA_IN_BASE 0x0200 /* PRE1, PRE2 */ +#define RPPX1_LSC_BASE 0x0400 /* PRE1, PRE2 */ +#define RPPX1_AWB_GAIN_BASE 0x0500 /* PRE1, PRE2, POST */ +#define RPPX1_DPCC_BASE 0x0600 /* PRE1, PRE2 */ +#define RPPX1_DPF_BASE 0x0700 /* PRE1, PRE2 */ +#define RPPX1_FILT_BASE 0x0800 /* POST */ +#define RPPX1_CAC_BASE 0x0880 /* POST */ +#define RPPX1_CCOR_BASE 0x0900 /* POST */ +#define RPPX1_HIST_BASE 0x0a00 /* PRE1, PRE2, POST */ +#define RPPX1_HIST256_BASE 0x0b00 /* PRE1 */ +#define RPPX1_EXM_BASE 0x0c00 /* PRE1, PRE2 */ +#define RPPX1_LTM_BASE 0x1000 /* POST */ +#define RPPX1_LTM_MEAS_BASE 0x1200 /* POST */ +#define RPPX1_WBMEAS_BASE 0x1700 /* POST */ +#define RPPX1_BDRGB_BASE 0x1800 /* POST */ +#define RPPX1_SHRP_BASE 0x1a00 /* POST */ + +/* Functional Safety Module Base Addresses */ +#define RPPX1_FMU_BASE 0x0100 + +#define RPPX1_RPP_HDR_FMU_FSM_REG (RPPX1_RPP_FUSA_BASE + RPPX1_FMU_BASE + 0x00) +#define RPPX1_RPP_HDR_FMU_FSM_FSM_IRQM_FAULT BIT(23) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_SIZE_FAULT BIT(20) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_TIME_FAULT BIT(19) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_SIZE_FAULT BIT(18) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_TIME_FAULT BIT(17) +#define RPPX1_RPP_HDR_FMU_FSM_SIZE_FAULT BIT(16) +#define RPPX1_RPP_HDR_FMU_FSM_TIME_FAULT BIT(15) +#define RPPX1_RPP_HDR_FMU_FSM_MV_OUT_SIZE_FAULT BIT(14) +#define RPPX1_RPP_HDR_FMU_FSM_MV_OUT_TIME_FAULT BIT(13) +#define RPPX1_RPP_HDR_FMU_FSM_HV_OUT_SIZE_FAULT BIT(12) +#define RPPX1_RPP_HDR_FMU_FSM_HV_OUT_TIME_FAULT BIT(11) +#define RPPX1_RPP_HDR_FMU_FSM_MV_OUT_SIZE_ERR BIT(10) +#define RPPX1_RPP_HDR_FMU_FSM_IS_OUT_SIZE_ERR BIT(9) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_FIFO_OVFLW BIT(7) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_FIFO_OVFLW BIT(6) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_INFORM_SIZE BIT(5) +#define RPPX1_RPP_HDR_FMU_FSM_PRE1_OUTFORM_SIZE BIT(4) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_INFORM_SIZE BIT(3) +#define RPPX1_RPP_HDR_FMU_FSM_PRE2_OUTFORM_SIZE BIT(2) + +#define RPPX1_RPP_HDR_FMU_RFS_REG (RPPX1_RPP_FUSA_BASE + RPPX1_FMU_BASE + 0x04) +#define RPPX1_RPP_HDR_FMU_MFS_REG (RPPX1_RPP_FUSA_BASE + RPPX1_FMU_BASE + 0x08) +#define RPPX1_RPP_HDR_FMU_FSC_REG (RPPX1_RPP_FUSA_BASE + RPPX1_FMU_BASE + 0x0c) + +void rppx1_write(struct rppx1 *rpp, u32 offset, u32 value) +{ + iowrite32(value, rpp->base + offset); +} + +u32 rppx1_read(struct rppx1 *rpp, u32 offset) +{ + return ioread32(rpp->base + offset); +} + +bool rppx1_interrupt(struct rppx1 *rpp, u32 *isc) +{ + u32 status, raw, fault; + + fault = rppx1_read(rpp, RPPX1_RPP_HDR_FMU_MFS_REG); + if (fault) { + dev_err(rpp->dev, "%s: fault 0x%08x\n", __func__, fault); + rppx1_write(rpp, RPPX1_RPP_HDR_FMU_FSC_REG, fault); + } + + /* Read raw interrupt status. */ + raw = rppx1_read(rpp, RPPX1_RPP_RIS); + status = rppx1_read(rpp, RPPX1_RPP_MIS); + + /* Propagate the isc status. */ + if (isc) + *isc = status | raw; + + /* Clear enabled interrupts */ + rppx1_write(rpp, RPPX1_RPP_ISC, status); + + return !!(status & RPPX1_IRQ_ID_OUT_FRAME); +} +EXPORT_SYMBOL_GPL(rppx1_interrupt); + +void rppx1_destroy(struct rppx1 *rpp) +{ + kfree(rpp); +} +EXPORT_SYMBOL_GPL(rppx1_destroy); + +/* + * Allocate the private data structure and verify the hardware is present. + */ +struct rppx1 *rppx1_create(void __iomem *base, struct device *dev) +{ + struct rppx1 *rpp; + u32 reg; + + /* Allocate library structure */ + rpp = kzalloc_obj(*rpp); + if (!rpp) + return NULL; + + rpp->base = base; + rpp->dev = dev; + + /* Check communication with RPP and verify it truly is a X1. */ + reg = rppx1_read(rpp, RPPX1_RPP_HDRREGS_VERSION_REG); + if (reg != 3) { + dev_err(rpp->dev, "Unsupported HDR version (%u)\n", reg); + rppx1_destroy(rpp); + return NULL; + } + + /* Probe the PRE1 pipeline. */ + if (rpp_module_probe(&rpp->pre1.acq, rpp, &rppx1_acq_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_ACQ_BASE) || + rpp_module_probe(&rpp->pre1.bls, rpp, &rppx1_bls_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_BLS_BASE) || + rpp_module_probe(&rpp->pre1.lin, rpp, &rppx1_lin_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_GAMMA_IN_BASE) || + rpp_module_probe(&rpp->pre1.lsc, rpp, &rppx1_lsc_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_LSC_BASE) || + rpp_module_probe(&rpp->pre1.awbg, rpp, &rppx1_awbg_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_AWB_GAIN_BASE) || + rpp_module_probe(&rpp->pre1.dpcc, rpp, &rppx1_dpcc_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_DPCC_BASE) || + rpp_module_probe(&rpp->pre1.bd, rpp, &rppx1_bd_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_DPF_BASE) || + rpp_module_probe(&rpp->pre1.hist, rpp, &rppx1_hist_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_HIST_BASE) || + rpp_module_probe(&rpp->pre1.hist256, rpp, &rppx1_hist256_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_HIST256_BASE) || + rpp_module_probe(&rpp->pre1.exm, rpp, &rppx1_exm_ops, + RPPX1_RPP_MAIN_PRE1_BASE + RPPX1_EXM_BASE)) + goto err; + + /* Probe the PRE2 pipeline. */ + if (rpp_module_probe(&rpp->pre2.acq, rpp, &rppx1_acq_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_ACQ_BASE) || + rpp_module_probe(&rpp->pre2.bls, rpp, &rppx1_bls_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_BLS_BASE) || + rpp_module_probe(&rpp->pre2.lin, rpp, &rppx1_lin_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_GAMMA_IN_BASE) || + rpp_module_probe(&rpp->pre2.lsc, rpp, &rppx1_lsc_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_LSC_BASE) || + rpp_module_probe(&rpp->pre2.awbg, rpp, &rppx1_awbg_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_AWB_GAIN_BASE) || + rpp_module_probe(&rpp->pre2.dpcc, rpp, &rppx1_dpcc_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_DPCC_BASE) || + rpp_module_probe(&rpp->pre2.bd, rpp, &rppx1_bd_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_DPF_BASE) || + rpp_module_probe(&rpp->pre2.hist, rpp, &rppx1_hist_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_HIST_BASE) || + rpp_module_probe(&rpp->pre2.exm, rpp, &rppx1_exm_ops, + RPPX1_RPP_MAIN_PRE2_BASE + RPPX1_EXM_BASE)) + goto err; + + /* Probe the POST pipeline. */ + if (rpp_module_probe(&rpp->post.awbg, rpp, &rppx1_awbg_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_AWB_GAIN_BASE) || + rpp_module_probe(&rpp->post.ccor, rpp, &rppx1_ccor_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_CCOR_BASE) || + rpp_module_probe(&rpp->post.hist, rpp, &rppx1_hist_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_HIST_BASE) || + rpp_module_probe(&rpp->post.db, rpp, &rppx1_db_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_FILT_BASE) || + rpp_module_probe(&rpp->post.cac, rpp, &rppx1_cac_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_CAC_BASE) || + rpp_module_probe(&rpp->post.ltm, rpp, &rppx1_ltm_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_LTM_BASE) || + rpp_module_probe(&rpp->post.ltmmeas, rpp, &rppx1_ltmmeas_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_LTM_MEAS_BASE) || + rpp_module_probe(&rpp->post.wbmeas, rpp, &rppx1_wbmeas_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_WBMEAS_BASE) || + rpp_module_probe(&rpp->post.bdrgb, rpp, &rppx1_bdrgb_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_BDRGB_BASE) || + rpp_module_probe(&rpp->post.shrp, rpp, &rppx1_shrp_ops, + RPPX1_RPP_MAIN_POST_BASE + RPPX1_SHRP_BASE)) + goto err; + + /* Probe the Human Vision pipeline. */ + if (rpp_module_probe(&rpp->hv.ga, rpp, &rppx1_ga_ops, + RPPX1_RPP_OUT_BASE + RPPX1_GAMMA_OUT_BASE) || + rpp_module_probe(&rpp->hv.is, rpp, &rppx1_is_ops, + RPPX1_RPP_OUT_BASE + RPPX1_IS_BASE) || + rpp_module_probe(&rpp->hv.ccor, rpp, &rppx1_ccor_csm_ops, + RPPX1_RPP_OUT_BASE + RPPX1_CSM_BASE) || + rpp_module_probe(&rpp->hv.outif, rpp, &rppx1_outif_ops, + RPPX1_RPP_OUT_BASE + RPPX1_OUT_IF_BASE) || + rpp_module_probe(&rpp->hv.outregs, rpp, &rppx1_outregs_ops, + RPPX1_RPP_OUT_BASE + RPPX1_RPP_OUTREGS_BASE)) + goto err; + + /* Probe the Machine Vision pipeline. */ + if (rpp_module_probe(&rpp->mv.ga, rpp, &rppx1_ga_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_GAMMA_OUT_BASE) || + rpp_module_probe(&rpp->mv.is, rpp, &rppx1_is_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_IS_BASE) || + rpp_module_probe(&rpp->mv.ccor, rpp, &rppx1_ccor_csm_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_CSM_BASE) || + rpp_module_probe(&rpp->mv.outif, rpp, &rppx1_outif_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_OUT_IF_BASE) || + rpp_module_probe(&rpp->mv.outregs, rpp, &rppx1_outregs_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_RPP_OUTREGS_BASE) || + rpp_module_probe(&rpp->mv.xyz2luv, rpp, &rppx1_xyz2luv_ops, + RPPX1_RPP_MVOUT_BASE + RPPX1_LUV_BASE)) + goto err; + + /* Probe the standalone Radiance Mapping modules. */ + if (rpp_module_probe(&rpp->rmap, rpp, &rppx1_rmap_ops, + RPPX1_RPP_RMAP_BASE) || + rpp_module_probe(&rpp->rmapmeas, rpp, &rppx1_rmapmeas_ops, + RPPX1_RPP_RMAP_MEAS_BASE)) + goto err; + + return rpp; +err: + rppx1_destroy(rpp); + + return NULL; +} +EXPORT_SYMBOL_GPL(rppx1_create); + +int rppx1_start(struct rppx1 *rpp, + const struct v4l2_mbus_framefmt *input, + const struct v4l2_mbus_framefmt *hv, + const struct v4l2_mbus_framefmt *mv) +{ + if (rpp_module_call(&rpp->pre1.acq, start, input) || + rpp_module_call(&rpp->pre1.bls, start, input) || + rpp_module_call(&rpp->pre1.lin, start, input) || + rpp_module_call(&rpp->pre1.lsc, start, input) || + rpp_module_call(&rpp->pre1.awbg, start, input) || + rpp_module_call(&rpp->pre1.dpcc, start, input) || + rpp_module_call(&rpp->pre1.bd, start, input) || + rpp_module_call(&rpp->pre1.hist, start, input) || + rpp_module_call(&rpp->pre1.exm, start, input) || + rpp_module_call(&rpp->pre1.hist256, start, input)) + return -EINVAL; + + if (rpp_module_call(&rpp->rmap, start, NULL) || + rpp_module_call(&rpp->rmapmeas, start, NULL)) + return -EINVAL; + + if (rpp_module_call(&rpp->post.awbg, start, input) || + rpp_module_call(&rpp->post.db, start, input) || + rpp_module_call(&rpp->post.cac, start, input) || + rpp_module_call(&rpp->post.ccor, start, input) || + rpp_module_call(&rpp->post.ltm, start, input) || + rpp_module_call(&rpp->post.bdrgb, start, input) || + rpp_module_call(&rpp->post.shrp, start, input) || + rpp_module_call(&rpp->post.ltmmeas, start, input) || + rpp_module_call(&rpp->post.wbmeas, start, input) || + rpp_module_call(&rpp->post.hist, start, input)) + return -EINVAL; + + if (hv && (rpp_module_call(&rpp->hv.ga, start, hv) || + rpp_module_call(&rpp->hv.ccor, start, hv) || + rpp_module_call(&rpp->hv.outregs, start, hv) || + rpp_module_call(&rpp->hv.is, start, hv) || + rpp_module_call(&rpp->hv.outif, start, hv))) + return -EINVAL; + + if (mv && (rpp_module_call(&rpp->mv.ga, start, mv) || + rpp_module_call(&rpp->mv.ccor, start, mv) || + rpp_module_call(&rpp->mv.xyz2luv, start, mv) || + rpp_module_call(&rpp->mv.outregs, start, mv) || + rpp_module_call(&rpp->mv.is, start, mv) || + rpp_module_call(&rpp->mv.outif, start, mv))) + return -EINVAL; + + /* Immediate update for shadows. */ + rppx1_write(rpp, RPPX1_RPP_HDR_UPD_REG, RPPX1_RPP_HDR_UPD_REGS_CFG_UPD); + + /* Clear fault interrupts. */ + rppx1_write(rpp, RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_REG, + RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_ENABLE); + rppx1_write(rpp, RPPX1_RPP_HDR_FMU_FSM_REG, + RPPX1_RPP_HDR_FMU_FSM_PRE2_FIFO_OVFLW | + RPPX1_RPP_HDR_FMU_FSM_PRE1_FIFO_OVFLW); + rppx1_write(rpp, RPPX1_RPP_HDR_FMU_FSC_REG, + rppx1_read(rpp, RPPX1_RPP_HDR_FMU_MFS_REG)); + rppx1_write(rpp, RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_REG, + RPPX1_RPP_HDR_SAFETY_ACCESS_PROTECTION_DISABLE); + + /* Set interrupt mask. */ + rppx1_write(rpp, RPPX1_RPP_ISM, RPPX1_IRQ_ID_OUT_FRAME); + + /* Immediate commit update for shadows. */ + rppx1_write(rpp, RPPX1_RPP_HDR_UPD_REG, RPPX1_RPP_HDR_UPD_REGS_CFG_UPD); + + /* Then for operation update shadows with picture synchronization. */ + rppx1_write(rpp, RPPX1_RPP_HDR_UPD_REG, RPPX1_RPP_HDR_UPD_REGS_GEN_CFG_UPD); + + /* Clear any pending interrupts. */ + rppx1_interrupt(rpp, NULL); + + /* Enable input formatters. */ + rppx1_write(rpp, RPPX1_RPP_HDR_INFORM_ENABLE_REG, + RPPX1_RPP_HDR_INFORM_ENABLE_ENABLE); + + return 0; +} +EXPORT_SYMBOL_GPL(rppx1_start); + +int rppx1_stop(struct rppx1 *rpp) +{ + /* Disable input formatters. */ + rppx1_write(rpp, RPPX1_RPP_HDR_INFORM_ENABLE_REG, + RPPX1_RPP_HDR_INFORM_ENABLE_DISABLE); + + /* Clear any pending interrupts. */ + rppx1_interrupt(rpp, NULL); + + return 0; +} +EXPORT_SYMBOL_GPL(rppx1_stop); + +MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>"); +MODULE_DESCRIPTION("Dreamchip HDR RPPX1 support library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1.h b/drivers/media/platform/dreamchip/rppx1/rppx1.h new file mode 100644 index 000000000000..3bf3955afbae --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#ifndef __MEDIA_RPPX1_H__ +#define __MEDIA_RPPX1_H__ + +#include <linux/device.h> +#include <linux/types.h> + +#include "rpp_module.h" + +#define RPPX1_IRQ_ID_256HIST BIT(27) +#define RPPX1_IRQ_ID_PRE2_DPCC BIT(25) +#define RPPX1_IRQ_ID_PRE1_DPCC BIT(24) +#define RPPX1_IRQ_ID_MV_OUT_FRAME_OUT BIT(23) +#define RPPX1_IRQ_ID_MV_OUT_OFF BIT(22) +#define RPPX1_IRQ_ID_POST_AWB_MEAS BIT(21) +#define RPPX1_IRQ_ID_POST_HIST_MEAS BIT(20) +#define RPPX1_IRQ_ID_POST_TM BIT(19) +#define RPPX1_IRQ_ID_PRE1_EXM BIT(18) +#define RPPX1_IRQ_ID_PRE1_HIST BIT(17) +#define RPPX1_IRQ_ID_PRE1_FRAME_IN BIT(16) +#define RPPX1_IRQ_ID_PRE1_HSTART BIT(15) +#define RPPX1_IRQ_ID_PRE1_VSTART BIT(14) +#define RPPX1_IRQ_ID_PRE2_EXM BIT(13) +#define RPPX1_IRQ_ID_PRE2_HIST BIT(12) +#define RPPX1_IRQ_ID_PRE2_FRAME_IN BIT(11) +#define RPPX1_IRQ_ID_PRE2_HSTART BIT(10) +#define RPPX1_IRQ_ID_PRE2_VSTART BIT(9) +#define RPPX1_IRQ_ID_OUT_FRAME BIT(3) +#define RPPX1_IRQ_ID_OUT_OFF BIT(2) +#define RPPX1_IRQ_ID_RMAP_MEAS BIT(1) +#define RPPX1_IRQ_ID_RMAP_DONE BIT(0) + +struct rppx1 { + struct device *dev; + void __iomem *base; + + struct { + struct rpp_module acq; + struct rpp_module bls; + struct rpp_module lin; + struct rpp_module lsc; + struct rpp_module awbg; + struct rpp_module dpcc; + struct rpp_module bd; + struct rpp_module hist; + struct rpp_module hist256; + struct rpp_module exm; + } pre1; + + struct { + struct rpp_module acq; + struct rpp_module bls; + struct rpp_module lin; + struct rpp_module lsc; + struct rpp_module awbg; + struct rpp_module dpcc; + struct rpp_module bd; + struct rpp_module hist; + struct rpp_module exm; + } pre2; + + struct { + struct rpp_module awbg; + struct rpp_module ccor; + struct rpp_module hist; + struct rpp_module db; + struct rpp_module cac; + struct rpp_module ltm; + struct rpp_module ltmmeas; + struct rpp_module wbmeas; + struct rpp_module bdrgb; + struct rpp_module shrp; + } post; + + struct { + struct rpp_module ga; + struct rpp_module is; + struct rpp_module ccor; + struct rpp_module outif; + struct rpp_module outregs; + } hv; + + struct { + struct rpp_module ga; + struct rpp_module is; + struct rpp_module ccor; + struct rpp_module outif; + struct rpp_module outregs; + struct rpp_module xyz2luv; + } mv; + + struct rpp_module rmap; + struct rpp_module rmapmeas; +}; + +void rppx1_write(struct rppx1 *rpp, u32 offset, u32 value); +u32 rppx1_read(struct rppx1 *rpp, u32 offset); + +#endif /* __MEDIA_RPPX1_H__ */ diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_acq.c b/drivers/media/platform/dreamchip/rppx1/rppx1_acq.c new file mode 100644 index 000000000000..d5624e3c76a9 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_acq.c @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define ACQ_VERSION_REG 0x0000 + +#define ACQ_CTRL_REG 0x0004 +#define ACQ_CTRL_ALTERNATIVE_CFG_MODE_ENABLE BIT(8) +#define ACQ_CTRL_RPP_MODE_MASK GENMASK(3, 1) +#define ACQ_CTRL_RPP_MODE_RAWBT601 (0 << 1) +#define ACQ_CTRL_RPP_MODE_BT656 (1 << 1) +#define ACQ_CTRL_RPP_MODE_BT601 (2 << 1) +#define ACQ_CTRL_RPP_MODE_BAYER (3 << 1) +#define ACQ_CTRL_RPP_MODE_DATA (4 << 1) +#define ACQ_CTRL_RPP_MODE_BAYERRGB (5 << 1) +#define ACQ_CTRL_RPP_MODE_RAWBT656 (6 << 1) +#define ACQ_CTRL_INFORM_EN_ENABLE BIT(0) + +#define ACQ_PROP_REG 0x0008 + +#define ACQ_PROP_SENSOR_IN_LSB_ALIGNED_IN_LSB BIT(30) +#define ACQ_PROP_YUV_OUT_SEL BIT(25) +#define ACQ_PROP_MUX_DMA_SEL BIT(24) +#define ACQ_PROP_SECOND_INPUT_TYPE BIT(18) +#define ACQ_PROP_LATENCY_FIFO_INPUT_SELECTION BIT(15) +#define ACQ_PROP_INPUT_SELECTION_MASK GENMASK(14, 12) +#define ACQ_PROP_INPUT_SELECTION_8BIT (0 << 12) +#define ACQ_PROP_INPUT_SELECTION_10BIT (1 << 12) +#define ACQ_PROP_INPUT_SELECTION_12BIT (2 << 12) +#define ACQ_PROP_BAYER_PAT_MASK GENMASK(4, 3) +#define ACQ_PROP_BAYER_PAT_RGRG (0 << 3) +#define ACQ_PROP_BAYER_PAT_GRGR (1 << 3) +#define ACQ_PROP_BAYER_PAT_GBGB (2 << 3) +#define ACQ_PROP_BAYER_PAT_BGBG (3 << 3) +#define ACQ_PROP_VSYNC_POL BIT(2) +#define ACQ_PROP_HSYNC_POL BIT(1) +#define ACQ_PROP_SAMPLE_EDGE BIT(0) + +#define ACQ_H_OFFS_REG 0x000c +#define ACQ_V_OFFS_REG 0x0010 +#define ACQ_H_SIZE_REG 0x0014 +#define ACQ_V_SIZE_REG 0x0018 +#define ACQ_OUT_H_OFFS_REG 0x001c +#define ACQ_OUT_V_OFFS_REG 0x0020 +#define ACQ_OUT_H_SIZE_REG 0x0024 +#define ACQ_OUT_V_SIZE_REG 0x0028 +#define FLAGS_SHD_REG 0x002c +#define ACQ_OUT_H_OFFS_SHD_REG 0x0030 +#define ACQ_OUT_V_OFFS_SHD_REG 0x0034 +#define ACQ_OUT_H_SIZE_SHD_REG 0x0038 +#define ACQ_OUT_V_SIZE_SHD_REG 0x003c + +static int rppx1_acq_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, ACQ_VERSION_REG) != 0x0b) + return -EINVAL; + + return 0; +} + +static int rppx1_acq_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + u32 bayerpat, selection; + + rpp_module_clrset(mod, ACQ_CTRL_REG, ACQ_CTRL_RPP_MODE_MASK, + ACQ_CTRL_RPP_MODE_BAYER); + + rpp_module_write(mod, ACQ_H_OFFS_REG, 0); + rpp_module_write(mod, ACQ_V_OFFS_REG, 0); + rpp_module_write(mod, ACQ_H_SIZE_REG, fmt->width); + rpp_module_write(mod, ACQ_V_SIZE_REG, fmt->height); + rpp_module_write(mod, ACQ_OUT_H_OFFS_REG, 0); + rpp_module_write(mod, ACQ_OUT_V_OFFS_REG, 0); + rpp_module_write(mod, ACQ_OUT_H_SIZE_REG, fmt->width); + rpp_module_write(mod, ACQ_OUT_V_SIZE_REG, fmt->height); + + switch (fmt->code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SBGGR12_1X12: + mod->info.acq.raw_pattern = RPP_BGGR; + bayerpat = ACQ_PROP_BAYER_PAT_BGBG; + break; + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGBRG12_1X12: + mod->info.acq.raw_pattern = RPP_GBRG; + bayerpat = ACQ_PROP_BAYER_PAT_GBGB; + break; + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGRBG12_1X12: + mod->info.acq.raw_pattern = RPP_GRBG; + bayerpat = ACQ_PROP_BAYER_PAT_GRGR; + break; + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SRGGB12_1X12: + mod->info.acq.raw_pattern = RPP_RGGB; + bayerpat = ACQ_PROP_BAYER_PAT_RGRG; + break; + default: + return -EINVAL; + } + + switch (fmt->code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + selection = ACQ_PROP_INPUT_SELECTION_8BIT; + break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + selection = ACQ_PROP_INPUT_SELECTION_10BIT; + break; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + selection = ACQ_PROP_INPUT_SELECTION_12BIT; + break; + default: + return -EINVAL; + } + + rpp_module_write(mod, ACQ_PROP_REG, bayerpat | selection | + ACQ_PROP_SENSOR_IN_LSB_ALIGNED_IN_LSB); + + rpp_module_clrset(mod, ACQ_CTRL_REG, ACQ_CTRL_INFORM_EN_ENABLE, + ACQ_CTRL_INFORM_EN_ENABLE); + + return 0; +} + +const struct rpp_module_ops rppx1_acq_ops = { + .probe = rppx1_acq_probe, + .start = rppx1_acq_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c b/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c new file mode 100644 index 000000000000..f30e12d6f880 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_awbg.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define AWB_GAIN_VERSION_REG 0x0000 + +#define AWB_ENABLE_REG 0x0004 +#define AWB_ENABLE_AWB_GAIN_EN BIT(0) + +#define AWB_GAIN_GR_REG 0x0008 +#define AWB_GAIN_GB_REG 0x000c +#define AWB_GAIN_R_REG 0x0010 +#define AWB_GAIN_B_REG 0x0014 + +static int rppx1_awbg_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, AWB_GAIN_VERSION_REG) != 3) + return -EINVAL; + + return 0; +} + +static int +rppx1_awbg_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_awbg_params *cfg = &block->awbg; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + AWB_ENABLE_REG, 0); + return 0; + } + + /* + * RPP gains are 18-bit with 12 bit fractional part and 0x1000 = 1.0, + * giving a possible range of 0.0 to 64.0. NOTE: RPP documentation is + * contradictory this is the register definition, the function + * description states 0x400 = 1.0 AND 18-bit with 12 fractional bits, + * which is not possible... + */ + + write(priv, mod->base + AWB_GAIN_GR_REG, cfg->gain_green_r); + write(priv, mod->base + AWB_GAIN_GB_REG, cfg->gain_green_b); + write(priv, mod->base + AWB_GAIN_R_REG, cfg->gain_red); + write(priv, mod->base + AWB_GAIN_B_REG, cfg->gain_blue); + + write(priv, mod->base + AWB_ENABLE_REG, AWB_ENABLE_AWB_GAIN_EN); + + return 0; +} + +const struct rpp_module_ops rppx1_awbg_ops = { + .probe = rppx1_awbg_probe, + .fill_params = rppx1_awbg_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c b/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c new file mode 100644 index 000000000000..fcbaa0ee9281 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bd.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define DPF_VERSION_REG 0x0000 + +#define DPF_MODE_REG 0x0004 +#define DPF_MODE_USE_NF_GAIN BIT(9) +#define DPF_MODE_LSC_GAIN_COMP BIT(8) +#define DPF_MODE_NLL_SEGMENTATION BIT(6) +#define DPF_MODE_RB_FILTER_SIZE BIT(5) +#define DPF_MODE_R_FILTER_OFF BIT(4) +#define DPF_MODE_GR_FILTER_OFF BIT(3) +#define DPF_MODE_GB_FILTER_OFF BIT(2) +#define DPF_MODE_B_FILTER_OFF BIT(1) +#define DPF_MODE_DPF_ENABLE BIT(0) + +#define DPF_STRENGTH_R_REG 0x0008 +#define DPF_STRENGTH_G_REG 0x000c +#define DPF_STRENGTH_B_REG 0x0010 +#define DPF_S_WEIGHT_G_1_4_REG 0x0014 +#define DPF_S_WEIGHT_G_5_6_REG 0x0018 +#define DPF_S_WEIGHT_RB_1_4_REG 0x001c +#define DPF_S_WEIGHT_RB_5_6_REG 0x0020 + +#define DPF_NLL_G_COEFF_REG_NUM 17 +#define DPF_NLL_G_COEFF_REG(n) (0x0024 + (4 * (n))) + +#define DPF_NLL_RB_COEFF_REG_NUM 17 +#define DPF_NLL_RB_COEFF_REG(n) (0x0068 + (4 * (n))) + +#define DPF_NF_GAIN_R_REG 0x00ac +#define DPF_NF_GAIN_GR_REG 0x00b0 +#define DPF_NF_GAIN_GB_REG 0x00b4 +#define DPF_NF_GAIN_B_REG 0x00b8 + +static int rppx1_bd_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, DPF_VERSION_REG) != 5) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_bd_ops = { + .probe = rppx1_bd_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bdrgb.c b/drivers/media/platform/dreamchip/rppx1/rppx1_bdrgb.c new file mode 100644 index 000000000000..1accc106d65b --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bdrgb.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define RGBDENOISE_VERSION_REG 0x0000 + +#define RGBDENOISE_HW_BYPASS_REG 0x0004 +#define RGBDENOISE_HW_BYPASS_BYPASS_EN BIT(0) + +#define RGBDENOISE_SPNR_CTRL_REG 0x0008 +#define RGBDENOISE_SPNR_CTRL_C2NR_INTENSITY_SHIFT_C_MASK GENMASK(11, 8) +#define RGBDENOISE_SPNR_CTRL_C2NR_INTENSITY_SHIFT_Y_MASK GENMASK(7, 4) +#define RGBDENOISE_SPNR_CTRL_C2NR_EN BIT(0) + +#define RGBDENOISE_SPNR_LUMA_IF_COEF_00_07_REG 0x000c +#define RGBDENOISE_SPNR_LUMA_IF_COEF_08_15_REG 0x0010 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_16_23_REG 0x0014 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_24_31_REG 0x0018 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_00_07_REG 0x001c +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_08_15_REG 0x0020 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_16_23_REG 0x0024 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_24_31_REG 0x0028 +#define RGBDENOISE_SPNR_SPATIAL_COEF_0_3_REG 0x002c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_0_REG 0x0030 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_1_REG 0x0034 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_2_REG 0x0038 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_3_REG 0x003c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_4_REG 0x0040 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_5_REG 0x0044 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_6_REG 0x0048 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_7_REG 0x004c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_8_REG 0x0050 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_R_REG 0x0054 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_G_REG 0x0058 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_B_REG 0x005c +#define RGBDENOISE_HW_BYPASS_SDW_REG 0x0060 +#define RGBDENOISE_SPNR_CTRL_SDW_REG 0x0064 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_00_07_SDW_REG 0x0068 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_08_15_SDW_REG 0x006c +#define RGBDENOISE_SPNR_LUMA_IF_COEF_16_23_SDW_REG 0x0070 +#define RGBDENOISE_SPNR_LUMA_IF_COEF_24_31_SDW_REG 0x0074 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_00_07_SDW_REG 0x0078 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_08_15_SDW_REG 0x007c +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_16_23_SDW_REG 0x0080 +#define RGBDENOISE_SPNR_CHROMA_IF_COEF_24_31_SDW_REG 0x0084 +#define RGBDENOISE_SPNR_SPATIAL_COEFF_0_3_SDW_REG 0x0088 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_0_SDW_REG 0x008c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_1_SDW_REG 0x0090 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_2_SDW_REG 0x0094 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_3_SDW_REG 0x0098 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_4_SDW_REG 0x009c +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_5_SDW_REG 0x00a0 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_6_SDW_REG 0x00a4 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_7_SDW_REG 0x00a8 +#define RGBDENOISE_RGB2YUV_CCOR_COEFF_8_SDW_REG 0x00ac +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_R_SDW_REG 0x00b0 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_G_SDW_REG 0x00b4 +#define RGBDENOISE_RGB2YUV_CCOR_OFFSET_B_SDW_REG 0x00b8 + +static int rppx1_bdrgb_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, RGBDENOISE_VERSION_REG)) { + case 6: + /* 12-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_bdrgb_ops = { + .probe = rppx1_bdrgb_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c new file mode 100644 index 000000000000..01a61db279bf --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" +#include "rppx1.h" + +#define BLS_VERSION_REG 0x0000 + +#define BLS_CTRL_REG 0x0004 +#define BLS_CTRL_BLS_WIN2 BIT(3) +#define BLS_CTRL_BLS_WIN1 BIT(2) +#define BLS_CTRL_BLS_MODE_MEASURED BIT(1) +#define BLS_CTRL_BLS_EN BIT(0) + +#define BLS_SAMPLES_REG 0x0008 +#define BLS_H1_START_REG 0x000c +#define BLS_H1_STOP_REG 0x0010 +#define BLS_V1_START_REG 0x0014 +#define BLS_V1_STOP_REG 0x0018 +#define BLS_H2_START_REG 0x001c +#define BLS_H2_STOP_REG 0x0020 +#define BLS_V2_START_REG 0x0024 +#define BLS_V2_STOP_REG 0x0028 +#define BLS_A_FIXED_REG 0x002c +#define BLS_B_FIXED_REG 0x0030 +#define BLS_C_FIXED_REG 0x0034 +#define BLS_D_FIXED_REG 0x0038 +#define BLS_A_MEASURED_REG 0x003c +#define BLS_B_MEASURED_REG 0x0040 +#define BLS_C_MEASURED_REG 0x0044 +#define BLS_D_MEASURED_REG 0x0048 +#define BLS_PRE1_FIXED_MASK GENMASK(24, 0) +#define BLS_PRE2_FIXED_MASK GENMASK(12, 0) + +static int rppx1_bls_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, BLS_VERSION_REG)) { + case 3: + case 5: + /* 12-bit. */ + break; + case 2: + case 4: + /* 20-bit. */ + break; + case 6: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static void +rppx1_bls_swap_regs(struct rpp_module *mod, const u32 input[4], u32 output[4]) +{ + static const unsigned int swap[4][4] = { + [RPP_RGGB] = { 0, 1, 2, 3 }, + [RPP_GRBG] = { 1, 0, 3, 2 }, + [RPP_GBRG] = { 2, 3, 0, 1 }, + [RPP_BGGR] = { 3, 2, 1, 0 }, + }; + + /* Swap to pattern used in our path, PRE1 or PRE2. */ + struct rpp_module *acq = mod == &mod->rpp->pre1.bls ? + &mod->rpp->pre1.acq : &mod->rpp->pre2.bls; + enum rpp_raw_pattern pattern = acq->info.acq.raw_pattern; + + for (unsigned int i = 0; i < 4; ++i) + output[i] = input[swap[pattern][i]]; +} + +static int +rppx1_bls_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_bls_params *cfg = &block->bls; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + BLS_CTRL_REG, 0); + return 0; + } + + u32 ctrl = BLS_CTRL_BLS_EN; + + if (cfg->mode == RPPX1_BLS_MODE_FIXED) { + static const u32 regs[] = { + BLS_A_FIXED_REG, + BLS_B_FIXED_REG, + BLS_C_FIXED_REG, + BLS_D_FIXED_REG, + }; + u32 swapped[4]; + + rppx1_bls_swap_regs(mod, regs, swapped); + + /* + * The PRE1 pipe fixed values are 24-bits + 1 sign bit, while + * the PRE2 pipe values are 12-bits + 1 sign bit. + */ + u32 mask; + + switch (cfg->header.type) { + case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE1: + mask = BLS_PRE1_FIXED_MASK; + break; + case RPPX1_PARAMS_BLOCK_TYPE_BLS_PRE2: + mask = BLS_PRE2_FIXED_MASK; + break; + default: + return -EINVAL; + } + + write(priv, mod->base + swapped[0], cfg->fixed.a & mask); + write(priv, mod->base + swapped[1], cfg->fixed.b & mask); + write(priv, mod->base + swapped[2], cfg->fixed.c & mask); + write(priv, mod->base + swapped[3], cfg->fixed.d & mask); + } else { + write(priv, mod->base + BLS_SAMPLES_REG, cfg->samples); + + if (cfg->en_windows & RPPX1_BLS_WIN_EN_WIN1) { + write(priv, mod->base + BLS_H1_START_REG, cfg->window1.h_offs); + write(priv, mod->base + BLS_H1_STOP_REG, cfg->window1.h_size); + write(priv, mod->base + BLS_V1_START_REG, cfg->window1.v_offs); + write(priv, mod->base + BLS_V1_STOP_REG, cfg->window1.v_size); + ctrl |= BLS_CTRL_BLS_WIN1; + } + + if (cfg->en_windows & RPPX1_BLS_WIN_EN_WIN2) { + write(priv, mod->base + BLS_H2_START_REG, cfg->window2.h_offs); + write(priv, mod->base + BLS_H2_STOP_REG, cfg->window2.h_size); + write(priv, mod->base + BLS_V2_START_REG, cfg->window2.v_offs); + write(priv, mod->base + BLS_V2_STOP_REG, cfg->window2.v_size); + ctrl |= BLS_CTRL_BLS_WIN2; + } + + ctrl |= BLS_CTRL_BLS_MODE_MEASURED; + } + + write(priv, mod->base + BLS_CTRL_REG, ctrl); + + return 0; +} + +const struct rpp_module_ops rppx1_bls_ops = { + .probe = rppx1_bls_probe, + .fill_params = rppx1_bls_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_cac.c b/drivers/media/platform/dreamchip/rppx1/rppx1_cac.c new file mode 100644 index 000000000000..fb3bfa668425 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_cac.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define CAC_VERSION_REG 0x0000 +#define CAC_CTRL_REG 0x0004 +#define CAC_COUNT_START_REG 0x0008 +#define CAC_A_REG 0x000c +#define CAC_B_REG 0x0010 +#define CAC_C_REG 0x0014 +#define CAC_X_NORM_REG 0x0018 +#define CAC_Y_NORM_REG 0x001c + +static int rppx1_cac_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, CAC_VERSION_REG) != 3) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_cac_ops = { + .probe = rppx1_cac_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c b/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c new file mode 100644 index 000000000000..5ddc7edf6930 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ccor.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define CCOR_VERSION_REG 0x0000 + +#define CCOR_COEFF_REG_NUM 9 +#define CCOR_COEFF_REG(n) (0x0004 + (4 * (n))) + +#define CCOR_OFFSET_R_REG 0x0028 +#define CCOR_OFFSET_G_REG 0x002c +#define CCOR_OFFSET_B_REG 0x0030 + +#define CCOR_CONFIG_TYPE_REG 0x0034 +#define CCOR_CONFIG_TYPE_USE_OFFSETS_AS_PRE_OFFSETS BIT(1) +#define CCOR_CONFIG_TYPE_CCOR_RANGE_AVAILABLE BIT(0) + +#define CCOR_RANGE_REG 0x0038 +#define CCOR_RANGE_CCOR_C_RANGE BIT(1) +#define CCOR_RANGE_CCOR_Y_RANGE BIT(0) + +static int rppx1_ccor_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, CCOR_VERSION_REG)) { + case 3: + /* 12-bit. */ + break; + case 4: + /* 20-bit. */ + break; + case 5: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_ccor_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Configure matrix in bypass mode. */ + rpp_module_write(mod, CCOR_COEFF_REG(0), 0x1000); + rpp_module_write(mod, CCOR_COEFF_REG(1), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(2), 0x0000); + + rpp_module_write(mod, CCOR_COEFF_REG(3), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(4), 0x1000); + rpp_module_write(mod, CCOR_COEFF_REG(5), 0x0000); + + rpp_module_write(mod, CCOR_COEFF_REG(6), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(7), 0x0000); + rpp_module_write(mod, CCOR_COEFF_REG(8), 0x1000); + + rpp_module_write(mod, CCOR_OFFSET_R_REG, 0x00000000); + rpp_module_write(mod, CCOR_OFFSET_G_REG, 0x00000000); + rpp_module_write(mod, CCOR_OFFSET_B_REG, 0x00000000); + + return 0; +} + +static int +rppx1_ccor_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_ccor_params *cfg = &block->ccor; + + /* If the modules is disabled, configure in bypass mode. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + CCOR_COEFF_REG(0), 0x1000); + write(priv, mod->base + CCOR_COEFF_REG(1), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(2), 0x0000); + + write(priv, mod->base + CCOR_COEFF_REG(3), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(4), 0x1000); + write(priv, mod->base + CCOR_COEFF_REG(5), 0x0000); + + write(priv, mod->base + CCOR_COEFF_REG(6), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(7), 0x0000); + write(priv, mod->base + CCOR_COEFF_REG(8), 0x1000); + + write(priv, mod->base + CCOR_OFFSET_R_REG, 0x00000000); + write(priv, mod->base + CCOR_OFFSET_G_REG, 0x00000000); + write(priv, mod->base + CCOR_OFFSET_B_REG, 0x00000000); + + return 0; + } + + /* + * Coefficient n for color correction matrix. + * + * RPP coefficients are 16-bit signed fixed-point numbers with 4 bit + * integer and 12 bit fractional part ranging from -8 (0x8000) to + * +7.9996 (0x7FFF). 0 is represented by 0x0000 and a coefficient + * value of 1 as 0x1000. + */ + write(priv, mod->base + CCOR_COEFF_REG(0), cfg->coeff[0][0]); + write(priv, mod->base + CCOR_COEFF_REG(1), cfg->coeff[0][1]); + write(priv, mod->base + CCOR_COEFF_REG(2), cfg->coeff[0][2]); + + write(priv, mod->base + CCOR_COEFF_REG(3), cfg->coeff[1][0]); + write(priv, mod->base + CCOR_COEFF_REG(4), cfg->coeff[1][1]); + write(priv, mod->base + CCOR_COEFF_REG(5), cfg->coeff[1][2]); + + write(priv, mod->base + CCOR_COEFF_REG(6), cfg->coeff[2][0]); + write(priv, mod->base + CCOR_COEFF_REG(7), cfg->coeff[2][1]); + write(priv, mod->base + CCOR_COEFF_REG(8), cfg->coeff[2][2]); + + /* + * Offset for color components correction matrix. + * + * Values are a two's complement integer with one sign bit. + */ + write(priv, mod->base + CCOR_OFFSET_R_REG, cfg->offset[0]); + write(priv, mod->base + CCOR_OFFSET_G_REG, cfg->offset[1]); + write(priv, mod->base + CCOR_OFFSET_B_REG, cfg->offset[2]); + + return 0; +} + +const struct rpp_module_ops rppx1_ccor_ops = { + .probe = rppx1_ccor_probe, + .start = rppx1_ccor_start, + .fill_params = rppx1_ccor_fill_params, +}; + +static int rppx1_ccor_csm_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Reuse bypass matrix setup. */ + if (fmt->code == MEDIA_BUS_FMT_RGB888_1X24) + return rppx1_ccor_start(mod, fmt); + + /* Color Transformation RGB to YUV according to ITU-R BT.709. */ + rpp_module_write(mod, CCOR_COEFF_REG(0), 0x0367); + rpp_module_write(mod, CCOR_COEFF_REG(1), 0x0b71); + rpp_module_write(mod, CCOR_COEFF_REG(2), 0x0128); + + rpp_module_write(mod, CCOR_COEFF_REG(3), 0xfe2b); + rpp_module_write(mod, CCOR_COEFF_REG(4), 0xf9d5); + rpp_module_write(mod, CCOR_COEFF_REG(5), 0x0800); + + rpp_module_write(mod, CCOR_COEFF_REG(6), 0x0800); + rpp_module_write(mod, CCOR_COEFF_REG(7), 0xf8bc); + rpp_module_write(mod, CCOR_COEFF_REG(8), 0xff44); + + rpp_module_write(mod, CCOR_OFFSET_R_REG, 0x00000000); + rpp_module_write(mod, CCOR_OFFSET_G_REG, 0x00000800); + rpp_module_write(mod, CCOR_OFFSET_B_REG, 0x00000800); + + return 0; +} + +const struct rpp_module_ops rppx1_ccor_csm_ops = { + .probe = rppx1_ccor_probe, + .start = rppx1_ccor_csm_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_db.c b/drivers/media/platform/dreamchip/rppx1/rppx1_db.c new file mode 100644 index 000000000000..78a330066b7e --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_db.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define FILT_VERSION_REG 0x0000 + +#define DEMOSAIC_REG 0x0004 +#define DEMOSAIC_DEMOSAIC_BYPASS BIT(16) +#define DEMOSAIC_DEMOSAIC_TH_MASK GENMASK(15, 0) + +#define FILT_MODE_REG 0x0008 +#define FILT_MODE_FILT_LP_SELECT_MASK GENMASK(11, 8) +#define FILT_MODE_FILT_CHR_H_MODE_MASK GENMASK(7, 6) +#define FILT_MODE_FILT_CHR_V_MODE_MASK GENMASK(5, 4) +#define FILT_MODE_FILT_MODE BIT(1) +#define FILT_MODE_FILT_ENABLE BIT(0) + +#define FILT_THRESH_BL0_REG 0x000c +#define FILT_THRESH_BL1_REG 0x0010 +#define FILT_THRESH_SH0_REG 0x0014 +#define FILT_THRESH_SH1_REG 0x0018 +#define FILT_LUM_WEIGHT_REG 0x001c +#define FILT_FAC_SH1_REG 0x0020 +#define FILT_FAC_SH0_REG 0x0024 +#define FILT_FAC_MID_REG 0x0028 +#define FILT_FAC_BL0_REG 0x002c +#define FILT_FAC_BL1_REG 0x0030 + +static int rppx1_db_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, FILT_VERSION_REG) != 5) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_db_ops = { + .probe = rppx1_db_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_dpcc.c b/drivers/media/platform/dreamchip/rppx1/rppx1_dpcc.c new file mode 100644 index 000000000000..3d5d9c0a7e72 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_dpcc.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define DPCC_VERSION_REG 0x0000 + +#define DPCC_MODE_REG 0x0004 +#define DPCC_MODE_STAGE1_ENABLE BIT(2) +#define DPCC_MODE_GRAYSCALE_MODE BIT(1) +#define DPCC_MODE_DPCC_ENABLE BIT(0) + +#define DPCC_OUTPUT_MODE_REG 0x0008 +#define DPCC_SET_USE_REG 0x000c +#define DPCC_METHODS_SET_1_REG 0x0010 +#define DPCC_METHODS_SET_2_REG 0x0014 +#define DPCC_METHODS_SET_3_REG 0x0018 +#define DPCC_LINE_THRESH_1_REG 0x001c +#define DPCC_LINE_MAD_FAC_1_REG 0x0020 +#define DPCC_PG_FAC_1_REG 0x0024 +#define DPCC_RND_THRESH_1_REG 0x0028 +#define DPCC_RG_FAC_1_REG 0x002c +#define DPCC_LINE_THRESH_2_REG 0x0030 +#define DPCC_LINE_MAD_FAC_2_REG 0x0034 +#define DPCC_PG_FAC_2_REG 0x0038 +#define DPCC_RND_THRESH_2_REG 0x003c +#define DPCC_RG_FAC_2_REG 0x0040 +#define DPCC_LINE_THRESH_3_REG 0x0044 +#define DPCC_LINE_MAD_FAC_3_REG 0x0048 +#define DPCC_PG_FAC_3_REG 0x004c +#define DPCC_RND_THRESH_3_REG 0x0050 +#define DPCC_RG_FAC_3_REG 0x0054 +#define DPCC_RO_LIMITS_REG 0x0058 +#define DPCC_RND_OFFS_REG 0x005c +#define DPCC_BPT_CTRL_REG 0x0060 +#define DPCC_BP_NUMBER_REG 0x0064 +#define DPCC_BP_TADDR_REG 0x0068 +#define DPCC_BP_POSITION_REG 0x006c + +static int rppx1_dpcc_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, DPCC_VERSION_REG)) { + case 2: + case 4: + case 6: + /* 12-bit. */ + break; + case 3: + case 5: + case 7: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_dpcc_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Bypass stage1 and DPCC. */ + rpp_module_write(mod, DPCC_MODE_REG, 0); + + return 0; +} + +const struct rpp_module_ops rppx1_dpcc_ops = { + .probe = rppx1_dpcc_probe, + .start = rppx1_dpcc_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c b/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c new file mode 100644 index 000000000000..c7b24c356222 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_exm.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define EXM_VERSION_REG 0x0000 +#define EXM_START_REG 0x0004 + +#define EXM_CTRL_REG 0x0008 +#define EXM_CTRL_EXM_AUTOSTOP BIT(1) /* HW doc says not supported. */ +#define EXM_CTRL_EXM_UPDATE_ENABLE BIT(0) + +#define EXM_MODE_REG 0x000c + +#define EXM_CHANNEL_SEL_REG 0x0010 +#define EXM_CHANNEL_SEL_CHANNEL_SELECT_MASK GENMASK(2, 0) + +#define EXM_LAST_MEAS_LINE_REG 0x0014 +#define EXM_COEFF_R_REG 0x0018 +#define EXM_COEFF_G_GR_REG 0x001c +#define EXM_COEFF_B_REG 0x0020 +#define EXM_COEFF_GB_REG 0x0024 +#define EXM_H_OFFS_REG 0x0028 +#define EXM_V_OFFS_REG 0x002c +#define EXM_H_SIZE_REG 0x0030 +#define EXM_V_SIZE_REG 0x0034 +#define EXM_FORCED_UPD_START_LINE_REG 0x0038 +#define EXM_VSTART_STATUS_REG 0x003c + +#define EXM_MEAN_REG(n) (0x0040 + (4 * (n))) + +static int rppx1_exm_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, EXM_VERSION_REG)) { + case 1: + /* 8-bit. */ + break; + case 3: + /* 20-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int +rppx1_exm_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_exm_params *cfg = &block->exm; + u32 h_offs, v_offs, h_size, v_size; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + EXM_MODE_REG, 0); + return 0; + } + + switch (cfg->mode) { + case RPPX1_EXP_MEASURING_MODE_RGB: + case RPPX1_EXP_MEASURING_MODE_BAYER: + write(priv, mod->base + EXM_MODE_REG, cfg->mode); + break; + default: + write(priv, mod->base + EXM_MODE_REG, 0); + return 0; + } + + write(priv, mod->base + EXM_COEFF_R_REG, cfg->coeff_r); + write(priv, mod->base + EXM_COEFF_G_GR_REG, cfg->coeff_g_gr); + write(priv, mod->base + EXM_COEFF_GB_REG, cfg->coeff_gb); + write(priv, mod->base + EXM_COEFF_B_REG, cfg->coeff_b); + + /* Select sample point */ + write(priv, mod->base + EXM_CHANNEL_SEL_REG, + cfg->channel_sel & EXM_CHANNEL_SEL_CHANNEL_SELECT_MASK); + + /* + * Adjust and set measurement window, + * - Offsets must be even. + * - Width and height must be even and divisible in 5 windows. + */ + h_offs = cfg->wnd.h_offs & 0x1ffe; + v_offs = cfg->wnd.v_offs & 0x1ffe; + h_size = (cfg->wnd.h_size - 1) - ((cfg->wnd.h_size - 1) % 10); + v_size = (cfg->wnd.v_size - 1) - ((cfg->wnd.v_size - 1) % 10); + + write(priv, mod->base + EXM_H_OFFS_REG, h_offs); + write(priv, mod->base + EXM_V_OFFS_REG, v_offs); + write(priv, mod->base + EXM_H_SIZE_REG, h_size / 5); + write(priv, mod->base + EXM_V_SIZE_REG, v_size / 5); + + /* + * Set last measurement line for ready interrupt. Ignore the value + * from the parameters as it is only useful for fast-channel switching. + */ + write(priv, mod->base + EXM_LAST_MEAS_LINE_REG, v_offs + v_size + 1); + + write(priv, mod->base + EXM_START_REG, 1); + + return 0; +} + +static int rppx1_exm_fill_stats(struct rpp_module *mod, + union rppx1_stats_block *block) +{ + struct rppx1_exm_stats *stats = &block->exm; + + for (unsigned int i = 0; i < RPPX1_EXM_NUM_WIN; i++) + stats->exp_mean[i] = rpp_module_read(mod, EXM_MEAN_REG(i)); + + return 0; +} + +const struct rpp_module_ops rppx1_exm_ops = { + .probe = rppx1_exm_probe, + .fill_params = rppx1_exm_fill_params, + .fill_stats = rppx1_exm_fill_stats, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c b/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c new file mode 100644 index 000000000000..1d9c24c43f77 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ga.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define GAMMA_OUT_VERSION_REG 0x0000 + +#define GAMMA_OUT_ENABLE_REG 0x0004 +#define GAMMA_OUT_ENABLE_GAMMA_OUT_EN BIT(0) + +#define GAMMA_OUT_MODE_REG 0x0008 +#define GAMMA_OUT_MODE_GAMMA_OUT_EQU_SEGM BIT(0) + +#define GAMMA_OUT_Y_REG(n) (0x000c + (4 * (n))) + +#define GAMMA_OUT_HV_GAMMA_CURVE_MASK GENMASK(11, 0) +#define GAMMA_OUT_MV_GAMMA_CURVE_MASK GENMASK(23, 0) + +static int rppx1_ga_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, GAMMA_OUT_VERSION_REG)) { + case 1: + /* 12-bit. */ + break; + case 2: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_ga_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Disable stage. */ + rpp_module_write(mod, GAMMA_OUT_ENABLE_REG, 0); + + return 0; +} + +static int +rppx1_ga_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_ga_params *cfg = &block->ga; + u32 mask; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + GAMMA_OUT_ENABLE_REG, 0); + return 0; + } + + switch (cfg->header.type) { + case RPPX1_PARAMS_BLOCK_TYPE_GA_HV: + mask = GAMMA_OUT_HV_GAMMA_CURVE_MASK; + break; + case RPPX1_PARAMS_BLOCK_TYPE_GA_MV: + mask = GAMMA_OUT_MV_GAMMA_CURVE_MASK; + break; + default: + return -EINVAL; + } + + write(priv, mod->base + GAMMA_OUT_MODE_REG, cfg->mode); + + for (unsigned int i = 0; i < RPPX1_GA_MAX_SAMPLES; i++) + write(priv, mod->base + GAMMA_OUT_Y_REG(i), + cfg->gamma_y[i] & mask); + + /* Enable module. */ + write(priv, mod->base + GAMMA_OUT_ENABLE_REG, + GAMMA_OUT_ENABLE_GAMMA_OUT_EN); + + return 0; +} + +const struct rpp_module_ops rppx1_ga_ops = { + .probe = rppx1_ga_probe, + .start = rppx1_ga_start, + .fill_params = rppx1_ga_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c b/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c new file mode 100644 index 000000000000..8fe8cbbc85df --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_hist.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#include <linux/bitfield.h> + +#define HIST_VERSION_REG 0x0000 + +#define HIST_CTRL_REG 0x0004 +#define HIST_CTRL_HIST_UPDATE_ENABLE BIT(0) + +#define HIST_MODE_REG 0x0008 +#define HIST_MODE_HIST_MODE_MASK GENMASK(2, 0) +#define HIST_MODE_HIST_MODE_DISABLE 0 +#define HIST_MODE_HIST_MODE_YRGB 1 +#define HIST_MODE_HIST_MODE_R 2 +#define HIST_MODE_HIST_MODE_GR 3 +#define HIST_MODE_HIST_MODE_B 4 +#define HIST_MODE_HIST_MODE_GB 5 + +#define HIST_CHANNEL_SEL_REG 0x000c +#define HIST_CHANNEL_SEL_CHANNEL_SELECT_MASK GENMASK(2, 0) + +#define HIST_LAST_MEAS_LINE_REG 0x0010 +#define HIST_SUBSAMPLING_REG 0x0014 +#define HIST_SUBSAMPLING_V_STEPSIZE(x) (((x) & 0x7f) << 24) +#define HIST_SUBSAMPLING_H_STEP_INC(x) (((x) & 0x1ffff)) + +#define HIST_COEFF_R_REG 0x0018 +#define HIST_COEFF_G_REG 0x001c +#define HIST_COEFF_B_REG 0x0020 +#define HIST_H_OFFS_REG 0x0024 +#define HIST_V_OFFS_REG 0x0028 +#define HIST_H_SIZE_REG 0x002c +#define HIST_V_SIZE_REG 0x0030 + +#define HIST_SAMPLE_RANGE_REG 0x0034 +#define HIST_SAMPLE_RANGE_SAMPLE_SHIFT_MASK GENMASK(28, 24) +#define HIST_SAMPLE_RANGE_SAMPLE_OFFSET_MASK GENMASK(23, 0) + +#define HIST_WEIGHT_00TO30_REG 0x0038 +#define HIST_WEIGHT_40TO21_REG 0x003c +#define HIST_WEIGHT_31TO12_REG 0x0040 +#define HIST_WEIGHT_22TO03_REG 0x0044 +#define HIST_WEIGHT_13TO43_REG 0x0048 +#define HIST_WEIGHT_04TO34_REG 0x004c +#define HIST_WEIGHT_44_REG 0x0050 +#define HIST_FORCED_UPD_START_LINE_REG 0x0054 +#define HIST_FORCED_UPDATE_REG 0x0058 +#define HIST_VSTART_STATUS_REG 0x005c + +#define HIST_BIN_REG(n) (0x0060 + (4 * (n))) + +static int rppx1_hist_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, HIST_VERSION_REG)) { + case 3: + /* 12-bit. */ + break; + case 4: + /* 20-bit. */ + break; + case 5: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +#define RPPX1_HIST_WEIGHT(v0, v1, v2, v3) \ + (((v0) & 0x1f) | (((v1) & 0x1f) << 8) | \ + (((v2) & 0x1f) << 16) | \ + (((v3) & 0x1f) << 24)) + +static int rppx1_hist_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_hist_params *cfg = &block->hist; + u32 h_offs, v_offs, h_size, v_size; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + HIST_MODE_REG, + HIST_MODE_HIST_MODE_DISABLE); + return 0; + } + + /* Select sample point */ + write(priv, mod->base + HIST_CHANNEL_SEL_REG, + cfg->channel_sel & HIST_CHANNEL_SEL_CHANNEL_SELECT_MASK); + + /* + * Configure the input subsampling. + * + * In Bayer mode the vertical and horizontal subsampling counters are + * only incremented for color channels selected by hist_mode. + */ + write(priv, mod->base + HIST_SUBSAMPLING_REG, + HIST_SUBSAMPLING_V_STEPSIZE(cfg->v_stepsize) | + HIST_SUBSAMPLING_H_STEP_INC(cfg->h_step_inc)); + + /* + * Adjust and set measurement window to hardware limitations, + * - Offsets must be even. + * - Width and height must be even and divisible in 5 windows. + */ + h_offs = cfg->wnd.h_offs & 0x1ffe; + v_offs = cfg->wnd.v_offs & 0x1ffe; + h_size = cfg->wnd.h_size - cfg->wnd.h_size % 10; + v_size = cfg->wnd.v_size - cfg->wnd.v_size % 10; + + write(priv, mod->base + HIST_H_OFFS_REG, h_offs); + write(priv, mod->base + HIST_V_OFFS_REG, v_offs); + write(priv, mod->base + HIST_H_SIZE_REG, h_size / 5); + write(priv, mod->base + HIST_V_SIZE_REG, v_size / 5); + + /* + * Set last measurement line for ready interrupt. Ignore the value + * from the parameters as it is only useful for fast-channel switching. + */ + write(priv, mod->base + HIST_LAST_MEAS_LINE_REG, v_offs + v_size + 1); + + /* Set measurement window weights. */ + write(priv, mod->base + HIST_WEIGHT_00TO30_REG, + RPPX1_HIST_WEIGHT(cfg->weights[0], cfg->weights[1], + cfg->weights[2], cfg->weights[3])); + write(priv, mod->base + HIST_WEIGHT_40TO21_REG, + RPPX1_HIST_WEIGHT(cfg->weights[4], cfg->weights[5], + cfg->weights[6], cfg->weights[7])); + write(priv, mod->base + HIST_WEIGHT_31TO12_REG, + RPPX1_HIST_WEIGHT(cfg->weights[8], cfg->weights[9], + cfg->weights[10], cfg->weights[11])); + write(priv, mod->base + HIST_WEIGHT_22TO03_REG, + RPPX1_HIST_WEIGHT(cfg->weights[12], cfg->weights[13], + cfg->weights[14], cfg->weights[15])); + write(priv, mod->base + HIST_WEIGHT_13TO43_REG, + RPPX1_HIST_WEIGHT(cfg->weights[16], cfg->weights[17], + cfg->weights[18], cfg->weights[19])); + write(priv, mod->base + HIST_WEIGHT_04TO34_REG, + RPPX1_HIST_WEIGHT(cfg->weights[20], cfg->weights[21], + cfg->weights[22], cfg->weights[23])); + write(priv, mod->base + HIST_WEIGHT_44_REG, + RPPX1_HIST_WEIGHT(cfg->weights[24], 0, 0, 0)); + + write(priv, mod->base + HIST_MODE_REG, cfg->mode); + write(priv, mod->base + HIST_COEFF_R_REG, cfg->coeff[0]); + write(priv, mod->base + HIST_COEFF_G_REG, cfg->coeff[1]); + write(priv, mod->base + HIST_COEFF_B_REG, cfg->coeff[2]); + + u32 sample_reg = FIELD_PREP(HIST_SAMPLE_RANGE_SAMPLE_SHIFT_MASK, + cfg->sample_shift) | + FIELD_PREP(HIST_SAMPLE_RANGE_SAMPLE_OFFSET_MASK, + cfg->sample_offs); + write(priv, mod->base + HIST_SAMPLE_RANGE_REG, sample_reg); + + write(priv, mod->base + HIST_FORCED_UPDATE_REG, 1); + + return 0; +} + +static int rppx1_hist_fill_stats(struct rpp_module *mod, + union rppx1_stats_block *block) +{ + struct rppx1_hist_stats *stats = &block->hist; + + for (unsigned int i = 0; i < RPPX1_HIST_NUM_BINS; i++) + stats->hist_bins[i] = rpp_module_read(mod, HIST_BIN_REG(i)); + + return 0; +} + +const struct rpp_module_ops rppx1_hist_ops = { + .probe = rppx1_hist_probe, + .fill_params = rppx1_hist_fill_params, + .fill_stats = rppx1_hist_fill_stats, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_hist256.c b/drivers/media/platform/dreamchip/rppx1/rppx1_hist256.c new file mode 100644 index 000000000000..80b3244c77aa --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_hist256.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define HIST256_VERSION_REG 0x0000 +#define HIST256_MODE_REG 0x0004 +#define HIST256_MODE_HIST256_MODE BIT(0) + +#define HIST256_CHANNEL_SEL_REG 0x0008 +#define HIST256_CHANNEL_SEL_CHANNEL_SELECT GENMASK(2, 0) + +#define HIST256_H_OFFS_REG 0x000c +#define HIST256_V_OFFS_REG 0x0010 +#define HIST256_H_SIZE_REG 0x0014 +#define HIST256_V_SIZE_REG 0x0018 +#define HIST256_SAMPLE_OFFSET_REG 0x001c +#define HIST256_SAMPLE_SCALE_REG 0x0020 +#define HIST256_MEAS_RESULT_ADDR_AUTOINCR_REG 0x0024 +#define HIST256_MEAS_RESULT_ADDR_REG 0x0028 +#define HIST256_MEAS_RESULT_DATA_REG 0x002c + +#define HIST256_LOG_ENABLE_REG 0x0030 +#define HIST256_LOG_ENABLE_HIST256_LOG_EN BIT(0) + +#define HIST256_LOG_DX_LO_REG 0x0034 +#define HIST256_LOG_DX_HI_REG 0x0038 + +#define HIST256_Y_REG_NUM 17 +#define HIST256_Y_REG(n) (0x0040 + (4 * (n))) + +static int rppx1_hist256_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, HIST256_VERSION_REG) != 2) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_hist256_ops = { + .probe = rppx1_hist256_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_is.c b/drivers/media/platform/dreamchip/rppx1/rppx1_is.c new file mode 100644 index 000000000000..7b1b6f6538cf --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_is.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define IS_VERSION 0x0000 +#define IS_H_OFFS 0x0008 +#define IS_V_OFFS 0x000c +#define IS_H_SIZE 0x0010 +#define IS_V_SIZE 0x0014 +#define IS_H_OFFS_SHD 0x0024 +#define IS_V_OFFS_SHD 0x0028 +#define IS_H_SIZE_SHD 0x002c +#define IS_V_SIZE_SHD 0x0030 + +static int rppx1_is_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, IS_VERSION) != 1) + return -EINVAL; + + return 0; +} + +static int rppx1_is_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + rpp_module_write(mod, IS_H_OFFS, 0); + rpp_module_write(mod, IS_V_OFFS, 0); + rpp_module_write(mod, IS_H_SIZE, fmt->width); + rpp_module_write(mod, IS_V_SIZE, fmt->height); + + return 0; +} + +const struct rpp_module_ops rppx1_is_ops = { + .probe = rppx1_is_probe, + .start = rppx1_is_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_lin.c b/drivers/media/platform/dreamchip/rppx1/rppx1_lin.c new file mode 100644 index 000000000000..b389778f9383 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_lin.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +/* NOTE: The module is called LIN the registers GAMMA_IN. */ +#define LIN_VERSION_REG 0x0000 + +#define LIN_ENABLE_REG 0x0004 +#define LIN_ENABLE_GAMMA_IN_EN BIT(0) + +#define LIN_DX_LO_REG 0x0008 +#define LIN_DX_HI_REG 0x000c + +#define LIN_R_Y_REG_NUM 17 +#define LIN_R_Y_REG(n) (0x0010 + (4 * (n))) + +#define LIN_G_Y_REG_NUM 17 +#define LIN_G_Y_REG(n) (0x0054 + (4 * (n))) + +#define LIN_B_Y_REG_NUM 17 +#define LIN_B_Y_REG(n) (0x0098 + (4 * (n))) + +#define LIN_PRE1_DEGAMMA_CURVE_MASK GENMASK(23, 0) +#define LIN_PRE1_SAMPLE_POINTS_MASK GENMASK(3, 0) +#define LIN_PRE2_DEGAMMA_CURVE_MASK GENMASK(11, 0) +#define LIN_PRE2_SAMPLE_POINTS_MASK GENMASK(2, 0) + +static int rppx1_lin_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, LIN_VERSION_REG)) { + case 7: + /* 12-bit. */ + break; + case 8: + /* 20-bit. */ + break; + case 9: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_lin_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + rpp_module_clrset(mod, LIN_ENABLE_REG, LIN_ENABLE_GAMMA_IN_EN, 0); + + return 0; +} + +static int rppx1_lin_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_lin_params *cfg = &block->lin; + u8 sample_mask; + u32 dx_lo = 0; + u32 dx_hi = 0; + u32 mask; + + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + LIN_ENABLE_REG, 0); + return 0; + } + + switch (cfg->header.type) { + case RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE1: + mask = LIN_PRE1_DEGAMMA_CURVE_MASK; + sample_mask = LIN_PRE1_SAMPLE_POINTS_MASK; + break; + case RPPX1_PARAMS_BLOCK_TYPE_LIN_PRE2: + mask = LIN_PRE2_DEGAMMA_CURVE_MASK; + sample_mask = LIN_PRE2_SAMPLE_POINTS_MASK; + break; + default: + return -EINVAL; + } + + for (unsigned int i = 0; i < 8; ++i) { + dx_lo |= (cfg->dx[i] & sample_mask) << 4 * i; + dx_hi |= (cfg->dx[i + 8] & sample_mask) << 4 * i; + } + + write(priv, mod->base + LIN_DX_LO_REG, dx_lo); + write(priv, mod->base + LIN_DX_HI_REG, dx_hi); + + for (unsigned int i = 0; i < RPPX1_LIN_DEGAMMA_CURVE_NUM; i++) { + write(priv, mod->base + LIN_R_Y_REG(i), cfg->curve_r[i] & mask); + write(priv, mod->base + LIN_G_Y_REG(i), cfg->curve_g[i] & mask); + write(priv, mod->base + LIN_B_Y_REG(i), cfg->curve_b[i] & mask); + } + + write(priv, mod->base + LIN_ENABLE_REG, LIN_ENABLE_GAMMA_IN_EN); + + return 0; +} + +const struct rpp_module_ops rppx1_lin_ops = { + .probe = rppx1_lin_probe, + .start = rppx1_lin_start, + .fill_params = rppx1_lin_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c b/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c new file mode 100644 index 000000000000..8badeca23e24 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_lsc.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define LSC_VERSION_REG 0x0000 + +#define LSC_CTRL_REG 0x0004 +#define LSC_CTRL_LSC_EN BIT(0) + +#define LSC_R_TABLE_ADDR_REG 0x0008 +#define LSC_GR_TABLE_ADDR_REG 0x000c +#define LSC_B_TABLE_ADDR_REG 0x0010 +#define LSC_GB_TABLE_ADDR_REG 0x0014 +#define LSC_R_TABLE_DATA_REG 0x0018 +#define LSC_GR_TABLE_DATA_REG 0x001c +#define LSC_B_TABLE_DATA_REG 0x0020 +#define LSC_GB_TABLE_DATA_REG 0x0024 +#define LSC_XGRAD_01_REG 0x0028 +#define LSC_XGRAD_23_REG 0x002c +#define LSC_XGRAD_45_REG 0x0030 +#define LSC_XGRAD_67_REG 0x0034 +#define LSC_XGRAD_89_REG 0x0038 +#define LSC_XGRAD_1011_REG 0x003c +#define LSC_XGRAD_1213_REG 0x0040 +#define LSC_XGRAD_1415_REG 0x0044 +#define LSC_YGRAD_01_REG 0x0048 +#define LSC_YGRAD_23_REG 0x004c +#define LSC_YGRAD_45_REG 0x0050 +#define LSC_YGRAD_67_REG 0x0054 +#define LSC_YGRAD_89_REG 0x0058 +#define LSC_YGRAD_1011_REG 0x005c +#define LSC_YGRAD_1213_REG 0x0060 +#define LSC_YGRAD_1415_REG 0x0064 +#define LSC_XSIZE_01_REG 0x0068 +#define LSC_XSIZE_23_REG 0x006c +#define LSC_XSIZE_45_REG 0x0070 +#define LSC_XSIZE_67_REG 0x0074 +#define LSC_XSIZE_89_REG 0x0078 +#define LSC_XSIZE_1011_REG 0x007c +#define LSC_XSIZE_1213_REG 0x0080 +#define LSC_XSIZE_1415_REG 0x0084 +#define LSC_YSIZE_01_REG 0x0088 +#define LSC_YSIZE_23_REG 0x008c +#define LSC_YSIZE_45_REG 0x0090 +#define LSC_YSIZE_67_REG 0x0094 +#define LSC_YSIZE_89_REG 0x0098 +#define LSC_YSIZE_1011_REG 0x009c +#define LSC_YSIZE_1213_REG 0x00a0 +#define LSC_YSIZE_1415_REG 0x00a4 +#define LSC_TABLE_SEL_REG 0x00a8 +#define LSC_STATUS_REG 0x00ac + +#define LSC_R_TABLE_DATA_VALUE(v1, v2) (((v1) & 0xfff) | (((v2) & 0xfff) << 12)) +#define LSC_GRAD_VALUE(v1, v2) (((v1) & 0xfff) | (((v2) & 0xfff) << 16)) +#define LSC_SIZE_VALUE(v1, v2) (((v1) & 0x1ff) | (((v2) & 0x1ff) << 16)) + +static int rppx1_lsc_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, LSC_VERSION_REG) != 0x04) + return -EINVAL; + + return 0; +} + +static int +rppx1_lsc_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_lsc_params *cfg = &block->lsc; + const __u16 *v; + + /* Always disable module as it needs be disabled before configuring. */ + write(priv, mod->base + LSC_CTRL_REG, 0); + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) + return 0; + + /* + * Program the color correction sectors. + * + * There are two tables to one can program and switch between. As the + * RPPX1 supports preparing a buffer of commands to be applied later + * only use table 0. This works as long as the ISP is not used in + * inline-mode. + * + * For inline-mode support using DMA for configuration is not possible + * so this is not an issue, but needs to be address if inline-mode + * support is added to the driver. + */ + + /* Start writing at beginning of table 0. */ + write(priv, mod->base + LSC_R_TABLE_ADDR_REG, 0); + write(priv, mod->base + LSC_GR_TABLE_ADDR_REG, 0); + write(priv, mod->base + LSC_B_TABLE_ADDR_REG, 0); + write(priv, mod->base + LSC_GB_TABLE_ADDR_REG, 0); + + /* Program data tables. */ + for (unsigned int i = 0; i < RPPX1_LSC_SAMPLES_MAX; i++) { + const __u16 *r = cfg->r_data[i]; + const __u16 *gr = cfg->gr_data[i]; + const __u16 *b = cfg->b_data[i]; + const __u16 *gb = cfg->gb_data[i]; + unsigned int j; + + for (j = 0; j < RPPX1_LSC_SAMPLES_MAX - 1; j += 2) { + write(priv, mod->base + LSC_R_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(r[j], r[j + 1])); + write(priv, mod->base + LSC_GR_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gr[j], gr[j + 1])); + write(priv, mod->base + LSC_B_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(b[j], b[j + 1])); + write(priv, mod->base + LSC_GB_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gb[j], gb[j + 1])); + } + + write(priv, mod->base + LSC_R_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(r[j], 0)); + write(priv, mod->base + LSC_GR_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gr[j], 0)); + write(priv, mod->base + LSC_B_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(b[j], 0)); + write(priv, mod->base + LSC_GB_TABLE_DATA_REG, + LSC_R_TABLE_DATA_VALUE(gb[j], 0)); + } + + /* Activate table 0. */ + write(priv, mod->base + LSC_TABLE_SEL_REG, 0); + + /* + * Program X- and Y- sizes, and gradients. + */ + + v = cfg->x_grad; + write(priv, mod->base + LSC_XGRAD_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_XGRAD_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_XGRAD_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_XGRAD_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_XGRAD_89_REG, LSC_GRAD_VALUE(v[8], v[9])); + write(priv, mod->base + LSC_XGRAD_1011_REG, LSC_GRAD_VALUE(v[10], v[11])); + write(priv, mod->base + LSC_XGRAD_1213_REG, LSC_GRAD_VALUE(v[12], v[13])); + write(priv, mod->base + LSC_XGRAD_1415_REG, LSC_GRAD_VALUE(v[14], v[15])); + + v = cfg->y_grad; + write(priv, mod->base + LSC_YGRAD_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_YGRAD_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_YGRAD_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_YGRAD_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_YGRAD_89_REG, LSC_GRAD_VALUE(v[8], v[9])); + write(priv, mod->base + LSC_YGRAD_1011_REG, LSC_GRAD_VALUE(v[10], v[11])); + write(priv, mod->base + LSC_YGRAD_1213_REG, LSC_GRAD_VALUE(v[12], v[13])); + write(priv, mod->base + LSC_YGRAD_1415_REG, LSC_GRAD_VALUE(v[14], v[15])); + + v = cfg->x_sect_size; + write(priv, mod->base + LSC_XSIZE_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_XSIZE_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_XSIZE_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_XSIZE_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_XSIZE_89_REG, LSC_GRAD_VALUE(v[8], v[9])); + write(priv, mod->base + LSC_XSIZE_1011_REG, LSC_GRAD_VALUE(v[10], v[11])); + write(priv, mod->base + LSC_XSIZE_1213_REG, LSC_GRAD_VALUE(v[12], v[13])); + write(priv, mod->base + LSC_XSIZE_1415_REG, LSC_GRAD_VALUE(v[14], v[15])); + + v = cfg->y_sect_size; + write(priv, mod->base + LSC_YSIZE_01_REG, LSC_GRAD_VALUE(v[0], v[1])); + write(priv, mod->base + LSC_YSIZE_23_REG, LSC_GRAD_VALUE(v[2], v[3])); + write(priv, mod->base + LSC_YSIZE_45_REG, LSC_GRAD_VALUE(v[4], v[5])); + write(priv, mod->base + LSC_YSIZE_67_REG, LSC_GRAD_VALUE(v[6], v[7])); + write(priv, mod->base + LSC_YSIZE_89_REG, LSC_GRAD_VALUE(v[8], v[9])); + write(priv, mod->base + LSC_YSIZE_1011_REG, LSC_GRAD_VALUE(v[10], v[11])); + write(priv, mod->base + LSC_YSIZE_1213_REG, LSC_GRAD_VALUE(v[12], v[13])); + write(priv, mod->base + LSC_YSIZE_1415_REG, LSC_GRAD_VALUE(v[14], v[15])); + + /* Enable module. */ + write(priv, mod->base + LSC_CTRL_REG, LSC_CTRL_LSC_EN); + + return 0; +} + +const struct rpp_module_ops rppx1_lsc_ops = { + .probe = rppx1_lsc_probe, + .fill_params = rppx1_lsc_fill_params, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ltm.c b/drivers/media/platform/dreamchip/rppx1/rppx1_ltm.c new file mode 100644 index 000000000000..9a71155e7e13 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ltm.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define LTM_VERSION_REG 0x0000 + +#define LTM_CTRL_REG 0x0004 +#define LTM_CTRL_LTM_ENABLE BIT(0) + +#define LTM_RGB_WEIGHTS_REG 0x0008 +#define LTM_CLB_LINESIZE_REG 0x000c +#define LTM_TONECURVE_1_REG 0x0010 +#define LTM_TONECURVE_2_REG 0x0014 +#define LTM_TONECURVE_3_REG 0x0018 +#define LTM_TONECURVE_4_REG 0x001c +#define LTM_TONECURVE_5_REG 0x0020 +#define LTM_TONECURVE_6_REG 0x0024 +#define LTM_TONECURVE_YM_REG(n) (0x0028 + (4 * (n))) +#define LTM_L0W_REG 0x00ec +#define LTM_L0W_R_REG 0x00f0 +#define LTM_L0D_REG 0x00f4 +#define LTM_L0D_R_REG 0x00f8 +#define LTM_KMIND_REG 0x00fc +#define LTM_KMAXD_REG 0x0100 +#define LTM_KDIFFD_REG 0x0104 +#define LTM_KDIFFD_R_REG 0x0108 +#define LTM_KW_REG 0x010c +#define LTM_KW_R_REG 0x0110 +#define LTM_CGAIN_REG 0x0114 +#define LTM_LPRCH_R_HIGH_REG 0x0118 +#define LTM_LPRCH_R_LOW_REG 0x011c + +static int rppx1_ltm_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, LTM_VERSION_REG) != 8) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_ltm_ops = { + .probe = rppx1_ltm_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c b/drivers/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c new file mode 100644 index 000000000000..c874b8fa8999 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_ltmmeas.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define LTM_MEAS_VERSION_REG 0x0000 + +#define LTM_MEAS_CTRL_REG 0x0004 +#define LTM_MEAS_CTRL_LTM_MEAS_ENABLE BIT(0) + +#define LTM_MEAS_RGB_WEIGHTS_REG 0x0008 +#define LTM_MEAS_H_OFFS_REG 0x000c +#define LTM_MEAS_V_OFFS_REG 0x0010 +#define LTM_MEAS_H_SIZE_REG 0x0014 +#define LTM_MEAS_V_SIZE_REG 0x0018 + +#define LTM_MEAS_PRC_THRESH_NUM 8 +#define LTM_MEAS_PRC_THRESH_REG(n) (0x001c + (4 * (n))) + +#define LTM_MEAS_PRC_REG_NUM 8 +#define LTM_MEAS_PRC_REG(n) (0x003c + (4 * (n))) + +#define LTM_MEAS_L_MIN_REG 0x005c +#define LTM_MEAS_L_MAX_REG 0x0060 +#define LTM_MEAS_L_GMEAN_REG 0x0064 + +static int rppx1_ltmmeas_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, LTM_MEAS_VERSION_REG) != 1) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_ltmmeas_ops = { + .probe = rppx1_ltmmeas_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_outif.c b/drivers/media/platform/dreamchip/rppx1/rppx1_outif.c new file mode 100644 index 000000000000..973b82a40d7c --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_outif.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define OUT_IF_VERSION_REG 0x0000 + +#define OUT_IF_ON_REG 0x0004 +#define OUT_IF_ON_RPP_ON BIT(0) + +#define OUT_IF_OFF_REG 0x0008 + +#define OUT_IF_NR_FRAMES_REG 0x000c +#define OUT_IF_NR_FRAMES_NR_FRAMES GENMASK(9, 0) + +#define OUT_IF_NR_FRAMES_CNT_REG 0x0010 +#define FLAGS_SHD_REG 0x0018 + +static int rppx1_outif_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, OUT_IF_VERSION_REG) != 1) + return -EINVAL; + + return 0; +} + +static int rppx1_outif_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + rpp_module_clrset(mod, OUT_IF_NR_FRAMES_REG, + OUT_IF_NR_FRAMES_NR_FRAMES, 0); + + rpp_module_write(mod, OUT_IF_ON_REG, OUT_IF_ON_RPP_ON); + + return 0; +} + +const struct rpp_module_ops rppx1_outif_ops = { + .probe = rppx1_outif_probe, + .start = rppx1_outif_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_outregs.c b/drivers/media/platform/dreamchip/rppx1/rppx1_outregs.c new file mode 100644 index 000000000000..ac8b71867137 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_outregs.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define OUTREGS_VERSION_REG 0x0000 + +#define OUT_MODE_REG 0x0004 +#define OUT_MODE_UNSELECTED_MODE_MASK GENMASK(11, 8) +#define OUT_MODE_UNSELECTED_MODE_MAIN (0x1 << 8) +#define OUT_MODE_UNSELECTED_MODE_PRE1 (0x2 << 8) +#define OUT_MODE_UNSELECTED_MODE_PRE2 (0x4 << 8) +#define OUT_MODE_IN_SEL_MASK GENMASK(3, 0) +#define OUT_MODE_IN_SEL_MAIN 1 +#define OUT_MODE_IN_SEL_PRE1 2 +#define OUT_MODE_IN_SEL_PRE2 4 + +#define OUT_CONV_422_METHOD_REG 0x0008 +#define OUT_CONV_422_METHOD_CONV_422_METHOD_MASK GENMASK(1, 0) +#define OUT_CONV_422_METHOD_CONV_422_METHOD_CO_SITED1 0 +#define OUT_CONV_422_METHOD_CONV_422_METHOD_CO_SITED2 1 +#define OUT_CONV_422_METHOD_CONV_422_METHOD_NON_CO_SITED 2 + +#define OUTREGS_FORMAT_REG 0x000c +#define OUTREGS_FORMAT_OUTPUT_FORMAT_MASK GENMASK(1, 0) +#define OUTREGS_FORMAT_OUTPUT_FORMAT_RGB 0 +#define OUTREGS_FORMAT_OUTPUT_FORMAT_YUV422 1 +#define OUTREGS_FORMAT_OUTPUT_FORMAT_YUV420 2 + +static int rppx1_outregs_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, OUTREGS_VERSION_REG) != 2) + return -EINVAL; + + return 0; +} + +static int rppx1_outregs_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + u32 format; + + switch (fmt->code) { + case MEDIA_BUS_FMT_YUYV12_1X24: + format = OUTREGS_FORMAT_OUTPUT_FORMAT_YUV422; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + format = OUTREGS_FORMAT_OUTPUT_FORMAT_RGB; + break; + default: + return -EINVAL; + } + + rpp_module_clrset(mod, OUT_MODE_REG, + OUT_MODE_UNSELECTED_MODE_MASK | OUT_MODE_IN_SEL_MASK, + OUT_MODE_UNSELECTED_MODE_MASK | OUT_MODE_IN_SEL_MAIN); + + rpp_module_clrset(mod, OUT_CONV_422_METHOD_REG, + OUT_CONV_422_METHOD_CONV_422_METHOD_MASK, + OUT_CONV_422_METHOD_CONV_422_METHOD_CO_SITED1); + + rpp_module_clrset(mod, OUTREGS_FORMAT_REG, + OUTREGS_FORMAT_OUTPUT_FORMAT_MASK, format); + + return 0; +} + +const struct rpp_module_ops rppx1_outregs_ops = { + .probe = rppx1_outregs_probe, + .start = rppx1_outregs_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_rmap.c b/drivers/media/platform/dreamchip/rppx1/rppx1_rmap.c new file mode 100644 index 000000000000..0a891caf3c52 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_rmap.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define RMAP_DATA_VERSION_REG 0x0000 + +#define RMAP_CTRL_REG 0x0004 +#define RMAP_CTRL_BYPASS_LONG BIT(2) + +#define RMAP_WBTHRESHOLD_LONG_REG 0x0008 +#define RMAP_WBTHRESHOLD_SHORT_REG 0x000c +#define RMAP_RESERVED_1_REG 0x0010 +#define RMAP_WBGAIN_LONG_RED_REG 0x0014 +#define RMAP_WBGAIN_LONG_BLUE_REG 0x0018 +#define RMAP_WBGAIN_SHORT_RED_REG 0x001c +#define RMAP_WBGAIN_SHORT_BLUE_REG 0x0020 +#define RMAP_RESERVED_2_REG 0x0024 +#define RMAP_RESERVED_3_REG 0x0028 +#define RMAP_MAP_FAC_SHORT_REG 0x002c +#define RMAP_RESERVED_4_REG 0x0030 +#define RMAP_MIN_THRES_SHORT_REG 0x0034 +#define RMAP_MAX_THRES_SHORT_REG 0x0038 +#define RMAP_STEPSIZE_SHORT_REG 0x003c +#define RMAP_MIN_THRES_LONG_REG 0x0040 +#define RMAP_MAX_THRES_LONG_REG 0x0044 +#define RMAP_STEPSIZE_LONG_REG 0x0048 +#define RMAP_CLB_LINESIZE_REG 0x004c + +static int rppx1_rmap_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, RMAP_DATA_VERSION_REG)) { + case 8: + /* low: 12-bit, high: 20-bit. */ + break; + case 9: + /* low: 12-bit, high: 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rppx1_rmap_start(struct rpp_module *mod, + const struct v4l2_mbus_framefmt *fmt) +{ + /* Bypass radiance mapping and use the long exposure channel (PRE1). */ + rpp_module_write(mod, RMAP_CTRL_REG, RMAP_CTRL_BYPASS_LONG); + + return 0; +} + +const struct rpp_module_ops rppx1_rmap_ops = { + .probe = rppx1_rmap_probe, + .start = rppx1_rmap_start, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c b/drivers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c new file mode 100644 index 000000000000..ef709d2a6ee9 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_rmapmeas.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define RMAP_MEAS_VERSION_REG 0x0000 +#define RMAP_MEAS_MODE_REG 0x0004 +#define RMAP_MEAS_SUBSAMPLING_REG 0x0008 +#define RMAP_MEAS_RESERVED_1_REG 0x000c +#define RMAP_MEAS_MIN_THRES_SHORT_REG 0x0010 +#define RMAP_MEAS_MAX_THRES_SHORT_REG 0x0014 +#define RMAP_MEAS_MAX_THRES_LONG_REG 0x0018 +#define RMAP_MEAS_H_OFFS_REG 0x001c +#define RMAP_MEAS_V_OFFS_REG 0x0020 +#define RMAP_MEAS_H_SIZE_REG 0x0024 +#define RMAP_MEAS_V_SIZE_REG 0x0028 +#define RMAP_MEAS_LAST_MEAS_LINE_REG 0x002c +#define RMAP_MEAS_LS_RESULTSHORT0_REG 0x0030 +#define RMAP_MEAS_LS_RESULTLONG0_REG 0x0034 +#define RMAP_MEAS_RESERVED_2_REG 0x0038 +#define RMAP_MEAS_RESERVED_3_REG 0x003c +#define RMAP_MEAS_LS_RESULTSHORT1_REG 0x0040 +#define RMAP_MEAS_LS_RESULTLONG1_REG 0x0044 +#define RMAP_MEAS_RESERVED_4_REG 0x0048 +#define RMAP_MEAS_RESERVED_5_REG 0x004c + +static int rppx1_rmapmeas_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, RMAP_MEAS_VERSION_REG)) { + case 3: + /* low: 12-bit, high: 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_rmapmeas_ops = { + .probe = rppx1_rmapmeas_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_shrp.c b/drivers/media/platform/dreamchip/rppx1/rppx1_shrp.c new file mode 100644 index 000000000000..c155418129e5 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_shrp.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define SHRPCNR_VERSION_REG 0x0000 + +#define SHRPCNR_CTRL_REG 0x0004 +#define SHRPCNR_CTRL_CAD_EN BIT(3) +#define SHRPCNR_CTRL_DESAT_EN BIT(2) +#define SHRPCNR_CTRL_CNR_EN BIT(1) +#define SHRPCNR_CTRL_SHARPEN_EN BIT(0) + +#define SHRPCNR_PARAM_REG 0x0008 +#define SHRPCNR_PARAM_SHARP_FACTOR_MASK GENMASK(19, 12) +#define SHRPCNR_PARAM_CORING_THR_MASK GENMASK(11, 0) + +#define SHRPCNR_MAT_1_REG 0x000c +#define SHRPCNR_MAT_2_REG 0x0010 +#define SHRPCNR_CLB_LINESIZE_REG 0x0014 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_0_REG 0x0018 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_1_REG 0x001c +#define SHRPCNR_YUV2RGB_CCOR_COEFF_2_REG 0x0020 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_3_REG 0x0024 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_4_REG 0x0028 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_5_REG 0x002c +#define SHRPCNR_YUV2RGB_CCOR_COEFF_6_REG 0x0030 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_7_REG 0x0034 +#define SHRPCNR_YUV2RGB_CCOR_COEFF_8_REG 0x0038 +#define SHRPCNR_YUV2RGB_CCOR_OFFSET_R_REG 0x003c +#define SHRPCNR_YUV2RGB_CCOR_OFFSET_G_REG 0x0040 +#define SHRPCNR_YUV2RGB_CCOR_OFFSET_B_REG 0x0044 + +#define SHRPCNR_CNR_THRES_REG 0x0048 +#define SHRPCNR_CNR_THRES_CNR_THRES_CR_MASK GENMASK(27, 16) +#define SHRPCNR_CNR_THRES_CNR_THRES_CB_MASK GENMASK(11, 0) + +#define SHRPCNR_CRED_THRES_REG 0x004c +#define SHRPCNR_CRED_SLOPE_REG 0x0050 +#define SHRPCNR_CAD_RESTORE_LVL_REG 0x0054 +#define SHRPCNR_CAD_THRESH_V_UNEG_REG 0x0058 +#define SHRPCNR_CAD_THRESH_V_UPOS_REG 0x005c +#define SHRPCNR_CAD_THRESH_U_REG 0x0060 + +static int rppx1_shrp_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, SHRPCNR_VERSION_REG)) { + case 2: + /* 12-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +const struct rpp_module_ops rppx1_shrp_ops = { + .probe = rppx1_shrp_probe, +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c b/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c new file mode 100644 index 000000000000..f0a943556238 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_wbmeas.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define AWB_MEAS_VERSION_REG 0x0000 + +#define AWB_MEAS_PROP_REG 0x0004 +#define AWB_MEAS_PROP_MEAS_MODE_RGB BIT(16) /* 0: YCbCr 1: RGB */ +#define AWB_MEAS_PROP_YMAX BIT(2) +#define AWB_MEAS_PROP_AWB_MODE_ON BIT(1) + +#define AWB_MEAS_H_OFFS_REG 0x0008 +#define AWB_MEAS_V_OFFS_REG 0x000c +#define AWB_MEAS_H_SIZE_REG 0x0010 +#define AWB_MEAS_V_SIZE_REG 0x0014 +#define AWB_MEAS_FRAMES_REG 0x0018 +#define AWB_MEAS_REF_CB_MAX_B_REG 0x001c +#define AWB_MEAS_REF_CR_MAX_R_REG 0x0020 +#define AWB_MEAS_MAX_Y_REG 0x0024 +#define AWB_MEAS_MIN_Y_MAX_G_REG 0x0028 +#define AWB_MEAS_MAX_CSUM_REG 0x002c +#define AWB_MEAS_MIN_C_REG 0x0030 +#define AWB_MEAS_WHITE_CNT_REG 0x0034 +#define AWB_MEAS_MEAN_Y_G_REG 0x0038 +#define AWB_MEAS_MEAN_CB_B_REG 0x003c +#define AWB_MEAS_MEAN_CR_R_REG 0x0040 + +#define AWB_MEAS_CCOR_COEFF_NUM 9 +#define AWB_MEAS_CCOR_COEFF_REG(n) (0x0044 + (4 * (n))) + +#define AWB_MEAS_CCOR_OFFSET_R_REG 0x0068 +#define AWB_MEAS_CCOR_OFFSET_G_REG 0x006c +#define AWB_MEAS_CCOR_OFFSET_B_REG 0x0070 + +static int rppx1_wbmeas_probe(struct rpp_module *mod) +{ + /* Version check. */ + switch (rpp_module_read(mod, AWB_MEAS_VERSION_REG)) { + case 1: + /* 8-bit. */ + break; + case 2: + /* 20-bit. */ + break; + case 3: + /* 24-bit. */ + break; + default: + return -EINVAL; + } + + return 0; +} + +static int +rppx1_wbmeas_fill_params(struct rpp_module *mod, + const union rppx1_params_block *block, + rppx1_reg_write write, void *priv) +{ + const struct rppx1_wbmeas_params *cfg = &block->wbmeas; + u32 awb_meas_props; + + /* If the modules is disabled, simply bypass it. */ + if (cfg->header.flags & V4L2_ISP_PARAMS_FL_BLOCK_DISABLE) { + write(priv, mod->base + AWB_MEAS_PROP_REG, 0); + return 0; + } + + /* Program measurement window. */ + write(priv, mod->base + AWB_MEAS_H_OFFS_REG, cfg->wnd.h_offs); + write(priv, mod->base + AWB_MEAS_V_OFFS_REG, cfg->wnd.v_offs); + write(priv, mod->base + AWB_MEAS_H_SIZE_REG, cfg->wnd.h_size); + write(priv, mod->base + AWB_MEAS_V_SIZE_REG, cfg->wnd.v_size); + + /* Set number of frames to sample. */ + write(priv, mod->base + AWB_MEAS_FRAMES_REG, cfg->frames); + + if (cfg->mode == RPPX1_WBMEAS_MODE_YCBCR) { + write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG, + cfg->ref_cb_max_b); + write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG, + cfg->ref_cr_max_r); + write(priv, mod->base + AWB_MEAS_MAX_Y_REG, cfg->max_y); + write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG, + cfg->min_y_max_g); + write(priv, mod->base + AWB_MEAS_MAX_CSUM_REG, cfg->max_csum); + write(priv, mod->base + AWB_MEAS_MIN_C_REG, cfg->min_c); + + /* + * Program the color conversion matrix coefficients and the + * per-color channel offsets. + */ + for (unsigned int i = 0; i < 3; i++) { + for (unsigned int j = 0; j < 3; j++) { + unsigned int index = i * 3 + j; + + write(priv, + mod->base + AWB_MEAS_CCOR_COEFF_REG(index), + cfg->ccor_coeff[i][j]); + } + } + + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG, + cfg->ccor_offs[0]); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG, + cfg->ccor_offs[1]); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG, + cfg->ccor_offs[2]); + + awb_meas_props = cfg->ymax_cmp ? AWB_MEAS_PROP_YMAX : 0; + } else { + write(priv, mod->base + AWB_MEAS_REF_CB_MAX_B_REG, + cfg->ref_cb_max_b); + write(priv, mod->base + AWB_MEAS_REF_CR_MAX_R_REG, + cfg->ref_cr_max_r); + write(priv, mod->base + AWB_MEAS_MIN_Y_MAX_G_REG, + cfg->min_y_max_g); + + /* Bypass color conversion matrix and color offsets. */ + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(0), 0x1000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(1), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(2), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(3), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(4), 0x1000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(5), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(6), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(7), 0x0000); + write(priv, mod->base + AWB_MEAS_CCOR_COEFF_REG(8), 0x1000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_R_REG, 0x00000000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_G_REG, 0x00000000); + write(priv, mod->base + AWB_MEAS_CCOR_OFFSET_B_REG, 0x00000000); + + awb_meas_props = AWB_MEAS_PROP_MEAS_MODE_RGB; + } + + write(priv, mod->base + AWB_MEAS_PROP_REG, + awb_meas_props | AWB_MEAS_PROP_AWB_MODE_ON); + + return 0; +} + +static int rppx1_wbmeas_fill_stats(struct rpp_module *mod, + union rppx1_stats_block *block) +{ + struct rppx1_wbmeas_stats *stats = &block->wbmeas; + + /* Return measurements at native hardware precision. */ + stats->cnt = rpp_module_read(mod, AWB_MEAS_WHITE_CNT_REG); + stats->mean_y_or_g = rpp_module_read(mod, AWB_MEAS_MEAN_Y_G_REG); + stats->mean_cb_or_b = rpp_module_read(mod, AWB_MEAS_MEAN_CB_B_REG); + stats->mean_cr_or_r = rpp_module_read(mod, AWB_MEAS_MEAN_CR_R_REG); + + return 0; +} + +const struct rpp_module_ops rppx1_wbmeas_ops = { + .probe = rppx1_wbmeas_probe, + .fill_params = rppx1_wbmeas_fill_params, + .fill_stats = rppx1_wbmeas_fill_stats +}; diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c b/drivers/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c new file mode 100644 index 000000000000..cc6f977c8a03 --- /dev/null +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_xyz2luv.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include "rpp_module.h" + +#define XYZ2LUV_VERSION_REG 0x0000 +#define XYZ2LUV_U_REF_REG 0x0004 +#define XYZ2LUV_V_REF_REG 0x0008 +#define XYZ2LUV_LUMA_OUT_FAC_REG 0x000c +#define XYZ2LUV_CHROMA_OUT_FAC_REG 0x0010 + +static int rppx1_xyz2luv_probe(struct rpp_module *mod) +{ + /* Version check. */ + if (rpp_module_read(mod, XYZ2LUV_VERSION_REG) != 4) + return -EINVAL; + + return 0; +} + +const struct rpp_module_ops rppx1_xyz2luv_ops = { + .probe = rppx1_xyz2luv_probe, +}; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c index d30a05782ab9..96a66aadf0cd 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c @@ -321,7 +321,7 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, /* Enable mux settings */ for (index = 0; index < ctrl->num_sets; index++) { set = &ctrl->sets[index]; - cmdq_pkt_write(&cmd->pkt, set->subsys_id, set->reg, set->value); + cmdq_pkt_write_subsys(&cmd->pkt, set->subsys_id, set->reg, set->reg, set->value); } /* Config sub-frame information */ for (index = (num_comp - 1); index >= 0; index--) { @@ -376,7 +376,7 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, /* Disable mux settings */ for (index = 0; index < ctrl->num_sets; index++) { set = &ctrl->sets[index]; - cmdq_pkt_write(&cmd->pkt, set->subsys_id, set->reg, 0); + cmdq_pkt_write_subsys(&cmd->pkt, set->subsys_id, set->reg, set->reg, 0); } return 0; @@ -628,7 +628,7 @@ static struct mdp_cmdq_cmd *mdp_cmdq_prepare(struct mdp_dev *mdp, goto err_free_path; } cmdq_pkt_eoc(&cmd->pkt); - cmdq_pkt_jump_rel(&cmd->pkt, CMDQ_INST_SIZE, mdp->cmdq_shift_pa[pp_idx]); + cmdq_pkt_jump_rel_temp(&cmd->pkt, CMDQ_INST_SIZE, mdp->cmdq_shift_pa[pp_idx]); for (i = 0; i < num_comp; i++) { s32 inner_id = MDP_COMP_NONE; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h index 681906c16419..c6fc180950f2 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h @@ -12,14 +12,14 @@ #define MM_REG_WRITE_MASK(cmd, id, base, ofst, val, mask) \ do { \ typeof(mask) (m) = (mask); \ - cmdq_pkt_write_mask(&((cmd)->pkt), id, (base) + (ofst), \ - (val), \ + cmdq_pkt_write_mask_subsys(&((cmd)->pkt), (id), (base), \ + (base) + (ofst), (val), \ (((m) & (ofst##_MASK)) == (ofst##_MASK)) ? \ (0xffffffff) : (m)); \ } while (0) #define MM_REG_WRITE(cmd, id, base, ofst, val) \ - cmdq_pkt_write(&((cmd)->pkt), id, (base) + (ofst), (val)) + cmdq_pkt_write_subsys(&((cmd)->pkt), (id), (base), (base) + (ofst), (val)) #define MM_REG_WAIT(cmd, evt) \ do { \ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index 8f4da4cf55d2..f412aadb5996 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -294,7 +294,11 @@ static int mdp_probe(struct platform_device *pdev) goto err_destroy_clock_wq; } mdp->scp = platform_get_drvdata(mm_pdev); - put_device(&mm_pdev->dev); + } + + if (!mdp->scp) { + ret = -EPROBE_DEFER; + goto err_destroy_clock_wq; } mdp->rproc_handle = scp_get_rproc(mdp->scp); diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c index adbacabdbebc..ba7a1cd998b9 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c @@ -974,10 +974,10 @@ static int vdec_vp9_slice_setup_pfc(struct vdec_vp9_slice_instance *instance, return 0; } -static int vdec_vp9_slice_setup_lat_buffer(struct vdec_vp9_slice_instance *instance, - struct vdec_vp9_slice_vsi *vsi, - struct mtk_vcodec_mem *bs, - struct vdec_lat_buf *lat_buf) +static void vdec_vp9_slice_setup_lat_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *bs, + struct vdec_lat_buf *lat_buf) { int i; @@ -1011,12 +1011,10 @@ static int vdec_vp9_slice_setup_lat_buffer(struct vdec_vp9_slice_instance *insta vsi->row_info.buf = 0; vsi->row_info.size = 0; - - return 0; } -static int vdec_vp9_slice_setup_prob_buffer(struct vdec_vp9_slice_instance *instance, - struct vdec_vp9_slice_vsi *vsi) +static void vdec_vp9_slice_setup_prob_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) { struct vdec_vp9_slice_frame_ctx *frame_ctx; struct vdec_vp9_slice_uncompressed_header *uh; @@ -1032,8 +1030,6 @@ static int vdec_vp9_slice_setup_prob_buffer(struct vdec_vp9_slice_instance *inst else frame_ctx = vdec_vp9_slice_default_frame_ctx; memcpy(instance->prob.va, frame_ctx, sizeof(*frame_ctx)); - - return 0; } static void vdec_vp9_slice_setup_seg_buffer(struct vdec_vp9_slice_instance *instance, @@ -1166,17 +1162,13 @@ static int vdec_vp9_slice_setup_lat(struct vdec_vp9_slice_instance *instance, if (ret) goto err; - ret = vdec_vp9_slice_setup_lat_buffer(instance, vsi, bs, lat_buf); - if (ret) - goto err; + vdec_vp9_slice_setup_lat_buffer(instance, vsi, bs, lat_buf); vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); /* setup prob/tile buffers for LAT */ - ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); - if (ret) - goto err; + vdec_vp9_slice_setup_prob_buffer(instance, vsi); ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); if (ret) @@ -1808,10 +1800,7 @@ static int vdec_vp9_slice_setup_single(struct vdec_vp9_slice_instance *instance, vdec_vp9_slice_setup_single_buffer(instance, pfc, vsi, bs, fb); vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]); - - ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi); - if (ret) - goto err; + vdec_vp9_slice_setup_prob_buffer(instance, vsi); ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); if (ret) diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c index b0302dfc3278..7383341ec51d 100644 --- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c +++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c @@ -598,13 +598,8 @@ static int __maybe_unused xisc_runtime_suspend(struct device *dev) static int __maybe_unused xisc_runtime_resume(struct device *dev) { struct isc_device *isc = dev_get_drvdata(dev); - int ret; - - ret = clk_prepare_enable(isc->hclock); - if (ret) - return ret; - return ret; + return clk_prepare_enable(isc->hclock); } static const struct dev_pm_ops microchip_xisc_dev_pm_ops = { diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c index e8545761b5ff..0ae5f35e017c 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -318,6 +318,7 @@ static const struct mxc_isi_plat_data mxc_imx95_data = { .model = MXC_ISI_IMX95, .num_ports = 4, .num_channels = 8, + .num_vc = 8, .reg_offset = 0x10000, .ier_reg = &mxc_imx8_isi_ier_v2, .set_thd = &mxc_imx8_isi_thd_v1, @@ -329,6 +330,7 @@ static const struct mxc_isi_plat_data mxc_imx8qm_data = { .model = MXC_ISI_IMX8QM, .num_ports = 5, .num_channels = 8, + .num_vc = 4, .reg_offset = 0x10000, .ier_reg = &mxc_imx8_isi_ier_qm, .set_thd = &mxc_imx8_isi_thd_v1, @@ -340,6 +342,7 @@ static const struct mxc_isi_plat_data mxc_imx8qxp_data = { .model = MXC_ISI_IMX8QXP, .num_ports = 5, .num_channels = 6, + .num_vc = 4, .reg_offset = 0x10000, .ier_reg = &mxc_imx8_isi_ier_v2, .set_thd = &mxc_imx8_isi_thd_v1, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h index 7547a6559d4c..58b47335afc7 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h @@ -170,6 +170,7 @@ struct mxc_isi_plat_data { enum model model; unsigned int num_ports; unsigned int num_channels; + unsigned int num_vc; /* Number of VCs, 0 = no VC support */ unsigned int reg_offset; const struct mxc_isi_ier_reg *ier_reg; const struct mxc_isi_set_thd *set_thd; @@ -185,7 +186,7 @@ struct mxc_isi_dma_buffer { }; struct mxc_isi_input { - unsigned int enable_count; + u64 enabled_streams; }; struct mxc_isi_crossbar { @@ -258,6 +259,14 @@ struct mxc_isi_pipe { u8 acquired_res; u8 chained_res; bool chained; + + unsigned int input; + /* + * Stream on the connected crossbar input, expressed as a bitmask. Zero + * when the pipeline is disabled, a single bit set when the pipeline is + * enabled (as each pipeline processes a single stream). + */ + u64 input_stream; }; struct mxc_isi_m2m { @@ -378,6 +387,7 @@ void mxc_isi_channel_unchain(struct mxc_isi_pipe *pipe); void mxc_isi_channel_config(struct mxc_isi_pipe *pipe, enum mxc_isi_input_id input, + unsigned int vc, const struct v4l2_area *in_size, const struct v4l2_area *scale, const struct v4l2_rect *crop, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c index c580c831972e..7bb1335f2110 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c @@ -106,8 +106,20 @@ static int __mxc_isi_crossbar_set_routing(struct v4l2_subdev *sd, if (ret) return ret; - /* The memory input can be routed to the first pipeline only. */ - for_each_active_route(&state->routing, route) { + /* + * Validate routes against hardware constraints: + * - SOURCE stream must be 0 (pipes are hardcoded to stream 0) + * - Memory input can only route to the first pipeline + */ + for_each_active_route(routing, route) { + if (route->source_stream != 0) { + dev_dbg(xbar->isi->dev, + "route to pipe %u must use source_stream=0, got %u\n", + route->source_pad - xbar->num_sinks, + route->source_stream); + return -ENXIO; + } + if (route->sink_pad == xbar->num_sinks - 1 && route->source_pad != xbar->num_sinks) { dev_dbg(xbar->isi->dev, @@ -145,10 +157,10 @@ mxc_isi_crossbar_xlate_streams(struct mxc_isi_crossbar *xbar, */ for_each_active_route(&state->routing, route) { if (route->source_pad != source_pad || - !(source_streams & BIT(route->source_stream))) + !(source_streams & BIT_ULL(route->source_stream))) continue; - sink_streams |= BIT(route->sink_stream); + sink_streams |= BIT_ULL(route->sink_stream); sink_pad = route->sink_pad; } @@ -318,11 +330,32 @@ static int mxc_isi_crossbar_set_routing(struct v4l2_subdev *sd, return __mxc_isi_crossbar_set_routing(sd, state, routing); } +/* + * Check if a stream on a sink pad is in used by any of the ISI pipelines. The + * sink_streams argument is a bitmask that must have a single bit set (enforced + * by mxc_isi_crossbar_xlate_streams() translating the single stream mask of the + * pipeline to a single stream on the crossbar input side). + */ +static bool mxc_isi_crossbar_stream_in_use(const struct mxc_isi_crossbar *xbar, + unsigned int sink_pad, u64 sink_streams) +{ + for (unsigned int i = 0; i < xbar->isi->pdata->num_channels; ++i) { + const struct mxc_isi_pipe *pipe = &xbar->isi->pipes[i]; + + if (pipe->input == sink_pad && + pipe->input_stream == sink_streams) + return true; + } + + return false; +} + static int mxc_isi_crossbar_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd); + struct mxc_isi_pipe *pipe = &xbar->isi->pipes[pad - xbar->num_sinks]; struct v4l2_subdev *remote_sd; struct mxc_isi_input *input; u64 sink_streams; @@ -339,29 +372,44 @@ static int mxc_isi_crossbar_enable_streams(struct v4l2_subdev *sd, input = &xbar->inputs[sink_pad]; /* - * TODO: Track per-stream enable counts to support multiplexed - * streams. + * Check if any other pipe already receives the same input stream. + * If so, just record this pipe's usage and return. */ - if (!input->enable_count) { + if (mxc_isi_crossbar_stream_in_use(xbar, sink_pad, sink_streams)) { + pipe->input = sink_pad; + pipe->input_stream = sink_streams; + return 0; + } + + /* Enable the gasket when the first stream is enabled for this input. */ + if (!input->enabled_streams) { ret = mxc_isi_crossbar_gasket_enable(xbar, state, remote_sd, remote_pad, sink_pad); if (ret) return ret; + } - ret = v4l2_subdev_enable_streams(remote_sd, remote_pad, - sink_streams); - if (ret) { - dev_err(xbar->isi->dev, - "failed to enable streams 0x%llx on '%s':%u: %d\n", - sink_streams, remote_sd->name, remote_pad, ret); - mxc_isi_crossbar_gasket_disable(xbar, sink_pad); - return ret; - } + ret = v4l2_subdev_enable_streams(remote_sd, remote_pad, sink_streams); + if (ret) { + dev_err(xbar->isi->dev, + "failed to enable streams 0x%llx on '%s':%u: %d\n", + sink_streams, remote_sd->name, remote_pad, ret); + goto err_gasket_disable; } - input->enable_count++; + input->enabled_streams |= sink_streams; + + /* Record the input and stream for this pipe. */ + pipe->input = sink_pad; + pipe->input_stream = sink_streams; return 0; + +err_gasket_disable: + if (!input->enabled_streams) + mxc_isi_crossbar_gasket_disable(xbar, sink_pad); + + return ret; } static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, @@ -369,6 +417,7 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, u32 pad, u64 streams_mask) { struct mxc_isi_crossbar *xbar = to_isi_crossbar(sd); + struct mxc_isi_pipe *pipe = &xbar->isi->pipes[pad - xbar->num_sinks]; struct v4l2_subdev *remote_sd; struct mxc_isi_input *input; u64 sink_streams; @@ -384,18 +433,27 @@ static int mxc_isi_crossbar_disable_streams(struct v4l2_subdev *sd, input = &xbar->inputs[sink_pad]; - input->enable_count--; + /* Clear the input and stream for this pipe. */ + pipe->input = UINT_MAX; + pipe->input_stream = 0; - if (!input->enable_count) { - ret = v4l2_subdev_disable_streams(remote_sd, remote_pad, - sink_streams); - if (ret) - dev_err(xbar->isi->dev, - "failed to disable streams 0x%llx on '%s':%u: %d\n", - sink_streams, remote_sd->name, remote_pad, ret); + /* + * Check if any other pipe receives the same input stream. If so we + * can't disable it yet, so return immediately. + */ + if (mxc_isi_crossbar_stream_in_use(xbar, sink_pad, sink_streams)) + return 0; + ret = v4l2_subdev_disable_streams(remote_sd, remote_pad, sink_streams); + if (ret) + dev_err(xbar->isi->dev, + "failed to disable streams 0x%llx on '%s':%u: %d\n", + sink_streams, remote_sd->name, remote_pad, ret); + + input->enabled_streams &= ~sink_streams; + + if (!input->enabled_streams) mxc_isi_crossbar_gasket_disable(xbar, sink_pad); - } return ret; } @@ -404,6 +462,7 @@ static const struct v4l2_subdev_pad_ops mxc_isi_crossbar_subdev_pad_ops = { .enum_mbus_code = mxc_isi_crossbar_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = mxc_isi_crossbar_set_fmt, + .get_frame_desc = v4l2_subdev_get_frame_desc_passthrough, .set_routing = mxc_isi_crossbar_set_routing, .enable_streams = mxc_isi_crossbar_enable_streams, .disable_streams = mxc_isi_crossbar_disable_streams, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c index 16b20ea2d1db..6aa760ce3605 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c @@ -11,8 +11,6 @@ #include "imx8-isi-core.h" #include "imx8-isi-regs.h" -#define ISI_DOWNSCALE_THRESHOLD 0x4000 - static inline u32 mxc_isi_read(struct mxc_isi_pipe *pipe, u32 reg) { return readl(pipe->regs + reg); @@ -118,8 +116,7 @@ static u32 mxc_isi_channel_scaling_ratio(unsigned int from, unsigned int to, * output (input / scale_factor) rounds up to exactly the desired * output. */ - return min_t(u32, DIV_ROUND_UP(from * 0x1000, to * *dec), - ISI_DOWNSCALE_THRESHOLD); + return DIV_ROUND_UP(from * 0x1000, to * *dec); } static void mxc_isi_channel_set_scaling(struct mxc_isi_pipe *pipe, @@ -308,6 +305,7 @@ static void mxc_isi_channel_set_panic_threshold(struct mxc_isi_pipe *pipe) static void mxc_isi_channel_set_control(struct mxc_isi_pipe *pipe, enum mxc_isi_input_id input, + unsigned int vc, bool bypass) { u32 val; @@ -319,6 +317,10 @@ static void mxc_isi_channel_set_control(struct mxc_isi_pipe *pipe, CHNL_CTRL_SRC_TYPE_MASK | CHNL_CTRL_MIPI_VC_ID_MASK | CHNL_CTRL_SRC_INPUT_MASK); + /* Clear the VC_ID_1 bit on platforms supporting more than 4 VCs. */ + if (pipe->isi->pdata->num_vc > 4) + val &= ~CHNL_CTRL_VC_ID_1_MASK; + /* * If no scaling or color space conversion is needed, bypass the * channel. @@ -345,7 +347,14 @@ static void mxc_isi_channel_set_control(struct mxc_isi_pipe *pipe, } else { val |= CHNL_CTRL_SRC_TYPE(CHNL_CTRL_SRC_TYPE_DEVICE); val |= CHNL_CTRL_SRC_INPUT(input); - val |= CHNL_CTRL_MIPI_VC_ID(0); /* FIXME: For CSI-2 only */ + val |= CHNL_CTRL_MIPI_VC_ID(vc); /* FIXME: For CSI-2 only */ + + /* + * On platforms with more than 4 VCs (i.MX95), the VC ID is + * split across VC_ID_0 (bits 7:6) and VC_ID_1 (bit 16). + */ + if (pipe->isi->pdata->num_vc > 4) + val |= CHNL_CTRL_VC_ID_1(vc >> 2); } mxc_isi_write(pipe, CHNL_CTRL, val); @@ -355,6 +364,7 @@ static void mxc_isi_channel_set_control(struct mxc_isi_pipe *pipe, void mxc_isi_channel_config(struct mxc_isi_pipe *pipe, enum mxc_isi_input_id input, + unsigned int vc, const struct v4l2_area *in_size, const struct v4l2_area *scale, const struct v4l2_rect *crop, @@ -381,7 +391,7 @@ void mxc_isi_channel_config(struct mxc_isi_pipe *pipe, mxc_isi_channel_set_panic_threshold(pipe); /* Channel control */ - mxc_isi_channel_set_control(pipe, input, csc_bypass && scaler_bypass); + mxc_isi_channel_set_control(pipe, input, vc, csc_bypass && scaler_bypass); } void mxc_isi_channel_set_input_format(struct mxc_isi_pipe *pipe, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c index de398b232d74..b729eecad0fe 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c @@ -144,7 +144,7 @@ static void mxc_isi_m2m_device_run(void *priv) .height = ctx->queues.cap.format.height, }; - mxc_isi_channel_config(m2m->pipe, MXC_ISI_INPUT_MEM, + mxc_isi_channel_config(m2m->pipe, MXC_ISI_INPUT_MEM, 0, &in_size, &scale, &crop, ctx->queues.out.info->encoding, ctx->queues.cap.info->encoding); diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c index 2d0843c86534..934f7b356258 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c @@ -84,6 +84,12 @@ static const struct mxc_isi_bus_format_info mxc_isi_bus_formats[] = { | BIT(MXC_ISI_PIPE_PAD_SOURCE), .encoding = MXC_ISI_ENC_RAW, }, { + .mbus_code = MEDIA_BUS_FMT_Y16_1X16, + .output = MEDIA_BUS_FMT_Y16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, + }, { .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .output = MEDIA_BUS_FMT_SBGGR8_1X8, .pads = BIT(MXC_ISI_PIPE_PAD_SINK) @@ -179,6 +185,30 @@ static const struct mxc_isi_bus_format_info mxc_isi_bus_formats[] = { .pads = BIT(MXC_ISI_PIPE_PAD_SINK) | BIT(MXC_ISI_PIPE_PAD_SOURCE), .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, + .output = MEDIA_BUS_FMT_SBGGR16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, + .output = MEDIA_BUS_FMT_SGBRG16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, + .output = MEDIA_BUS_FMT_SGRBG16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, + .output = MEDIA_BUS_FMT_SRGGB16_1X16, + .pads = BIT(MXC_ISI_PIPE_PAD_SINK) + | BIT(MXC_ISI_PIPE_PAD_SOURCE), + .encoding = MXC_ISI_ENC_RAW, }, /* JPEG */ { @@ -232,6 +262,47 @@ static inline struct mxc_isi_pipe *to_isi_pipe(struct v4l2_subdev *sd) return container_of(sd, struct mxc_isi_pipe, sd); } +static int mxc_isi_get_vc(struct mxc_isi_pipe *pipe) +{ + struct mxc_isi_crossbar *xbar = &pipe->isi->crossbar; + struct device *dev = pipe->isi->dev; + struct v4l2_mbus_frame_desc fd = { }; + unsigned int source_pad = xbar->num_sinks + pipe->id; + unsigned int num_vcs; + unsigned int i; + int ret; + + ret = v4l2_subdev_call(&xbar->sd, pad, get_frame_desc, + source_pad, &fd); + if (ret < 0) { + dev_err(dev, "Failed to get source frame desc from pad %u\n", + source_pad); + return ret; + } + + /* Find stream 0 in the frame descriptor. */ + for (i = 0; i < fd.num_entries; i++) { + if (fd.entry[i].stream == 0) + break; + } + + if (i == fd.num_entries) { + dev_err(dev, "Failed to find stream from source frame desc\n"); + return -EPIPE; + } + + num_vcs = pipe->isi->pdata->num_vc ? : 1; + + /* Check virtual channel range. */ + if (fd.entry[i].bus.csi2.vc >= num_vcs) { + dev_err(dev, "Virtual channel %u exceeds maximum %u\n", + fd.entry[i].bus.csi2.vc, num_vcs - 1); + return -EPIPE; + } + + return fd.entry[i].bus.csi2.vc; +} + int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe) { struct mxc_isi_crossbar *xbar = &pipe->isi->crossbar; @@ -246,6 +317,7 @@ int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe) struct v4l2_rect crop; u32 input; int ret; + int vc; /* * Find the connected input by inspecting the crossbar switch routing @@ -280,8 +352,12 @@ int mxc_isi_pipe_enable(struct mxc_isi_pipe *pipe) v4l2_subdev_unlock_state(state); + vc = mxc_isi_get_vc(pipe); + if (vc < 0) + return vc; + /* Configure the ISI channel. */ - mxc_isi_channel_config(pipe, input, &in_size, &scale, &crop, + mxc_isi_channel_config(pipe, input, vc, &in_size, &scale, &crop, sink_info->encoding, src_info->encoding); mxc_isi_channel_enable(pipe); @@ -770,6 +846,7 @@ int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id) pipe->acquired_res = 0; pipe->chained_res = 0; pipe->chained = false; + pipe->input = UINT_MAX; sd = &pipe->sd; v4l2_subdev_init(sd, &mxc_isi_pipe_subdev_ops); diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h index 1b65eccdf0da..e795f4daf3ff 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-regs.h @@ -6,6 +6,7 @@ #ifndef __IMX8_ISI_REGS_H__ #define __IMX8_ISI_REGS_H__ +#include <linux/bitfield.h> #include <linux/bits.h> /* ISI Registers Define */ @@ -19,9 +20,14 @@ #define CHNL_CTRL_CHAIN_BUF_NO_CHAIN 0 #define CHNL_CTRL_CHAIN_BUF_2_CHAIN 1 #define CHNL_CTRL_SW_RST BIT(24) -#define CHNL_CTRL_BLANK_PXL(n) ((n) << 16) -#define CHNL_CTRL_BLANK_PXL_MASK GENMASK(23, 16) -#define CHNL_CTRL_MIPI_VC_ID(n) ((n) << 6) +/* + * CHNL_CTRL_BLANK_PXL: i.MX8{QM,QXP} only + * CHNL_CTRL_VC_ID_1, CHNL_CTRL_VC_ID_1_MASK: i.MX95 only + */ +#define CHNL_CTRL_BLANK_PXL(n) FIELD_PREP(GENMASK(23, 16), (n)) +#define CHNL_CTRL_VC_ID_1(n) FIELD_PREP(BIT(16), (n)) +#define CHNL_CTRL_VC_ID_1_MASK BIT(16) +#define CHNL_CTRL_MIPI_VC_ID(n) FIELD_PREP(GENMASK(7, 6), (n)) #define CHNL_CTRL_MIPI_VC_ID_MASK GENMASK(7, 6) #define CHNL_CTRL_SRC_TYPE(n) ((n) << 4) #define CHNL_CTRL_SRC_TYPE_MASK BIT(4) diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c index fe4adfa3a1f0..f45c2aae59ce 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c @@ -151,7 +151,7 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = { .fourcc = V4L2_PIX_FMT_XBGR32, .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT | MXC_ISI_VIDEO_M2M_CAP, - .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XBGR8, + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XRGB8, .isi_out_format = CHNL_IMG_CTRL_FORMAT_XRGB888, .mem_planes = 1, .color_planes = 1, @@ -166,6 +166,57 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = { .color_planes = 1, .depth = { 32 }, .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_BGRA32, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RGBA8888, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_RGBA32, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_ABGR8888, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_BGRX32, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT + | MXC_ISI_VIDEO_M2M_CAP, + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_RGBX8, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RGBX888, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_RGBX32, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT + | MXC_ISI_VIDEO_M2M_CAP, + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_XBGR8, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_XBGR888, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, + }, { + .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, + .fourcc = V4L2_PIX_FMT_ARGB2101010, + .type = MXC_ISI_VIDEO_CAP | MXC_ISI_VIDEO_M2M_OUT + | MXC_ISI_VIDEO_M2M_CAP, + .isi_in_format = CHNL_MEM_RD_CTRL_IMG_TYPE_A2RGB10, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_A2RGB10, + .mem_planes = 1, + .color_planes = 1, + .depth = { 32 }, + .encoding = MXC_ISI_ENC_RGB, }, /* * RAW formats @@ -213,6 +264,15 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = { .depth = { 16 }, .encoding = MXC_ISI_ENC_RAW, }, { + .mbus_code = MEDIA_BUS_FMT_Y16_1X16, + .fourcc = V4L2_PIX_FMT_Y16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, + }, { .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .fourcc = V4L2_PIX_FMT_SBGGR8, .type = MXC_ISI_VIDEO_CAP, @@ -356,6 +416,42 @@ static const struct mxc_isi_format_info mxc_isi_formats[] = { .color_planes = 1, .depth = { 16 }, .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, + .fourcc = V4L2_PIX_FMT_SBGGR16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, + .fourcc = V4L2_PIX_FMT_SGBRG16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, + .fourcc = V4L2_PIX_FMT_SGRBG16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, + }, { + .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, + .fourcc = V4L2_PIX_FMT_SRGGB16, + .type = MXC_ISI_VIDEO_CAP, + .isi_out_format = CHNL_IMG_CTRL_FORMAT_RAW16, + .mem_planes = 1, + .color_planes = 1, + .depth = { 16 }, + .encoding = MXC_ISI_ENC_RAW, }, /* JPEG */ { diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c index aaf3caa42d33..20ccd7b1f11f 100644 --- a/drivers/media/platform/qcom/camss/camss-ispif.c +++ b/drivers/media/platform/qcom/camss/camss-ispif.c @@ -83,8 +83,8 @@ (0x270 + 0x200 * (m) + 0x4 * (n)) #define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_1(m, n) \ (0x27c + 0x200 * (m) + 0x4 * (n)) -#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0_CID_c_PLAIN(c) \ - (1 << ((cid % 8) * 4)) +#define ISPIF_VFE_m_RDI_INTF_n_PACK_CFG_0_CID_c_PLAIN(cid) \ + (1 << (((cid) % 8) * 4)) #define ISPIF_VFE_m_PIX_INTF_n_STATUS(m, n) \ (0x2c0 + 0x200 * (m) + 0x4 * (n)) #define ISPIF_VFE_m_RDI_INTF_n_STATUS(m, n) \ diff --git a/drivers/media/platform/qcom/iris/iris_buffer.c b/drivers/media/platform/qcom/iris/iris_buffer.c index 246ad0abbac3..eb8de60c1177 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_buffer.c @@ -492,39 +492,41 @@ static void iris_fill_internal_buf_info(struct iris_inst *inst, buffers->min_count = iris_vpu_buf_count(inst, buffer_type); } -void iris_get_internal_buffers(struct iris_inst *inst, u32 plane) +static void iris_get_int_buf_tbl(struct iris_inst *inst, u32 plane, + const u32 **internal_buf_type, u32 *internal_buffer_count) { const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; - const u32 *internal_buf_type; - u32 internal_buffer_count, i; if (inst->domain == DECODER) { if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + *internal_buf_type = firmware_data->dec_ip_int_buf_tbl; + *internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + *internal_buf_type = firmware_data->dec_op_int_buf_tbl; + *internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; } } else { if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + *internal_buf_type = firmware_data->enc_ip_int_buf_tbl; + *internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; - for (i = 0; i < internal_buffer_count; i++) - iris_fill_internal_buf_info(inst, internal_buf_type[i]); + *internal_buf_type = firmware_data->enc_op_int_buf_tbl; + *internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; } } } +void iris_get_internal_buffers(struct iris_inst *inst, u32 plane) +{ + const u32 *internal_buf_type; + u32 internal_buffer_count, i; + + iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &internal_buffer_count); + + for (i = 0; i < internal_buffer_count; i++) + iris_fill_internal_buf_info(inst, internal_buf_type[i]); +} + static int iris_create_internal_buffer(struct iris_inst *inst, enum iris_buffer_type buffer_type, u32 index) { @@ -559,29 +561,12 @@ static int iris_create_internal_buffer(struct iris_inst *inst, int iris_create_internal_buffers(struct iris_inst *inst, u32 plane) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; u32 internal_buffer_count, i, j; struct iris_buffers *buffers; const u32 *internal_buf_type; int ret; - if (inst->domain == DECODER) { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; - } - } else { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; - } - } + iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &internal_buffer_count); for (i = 0; i < internal_buffer_count; i++) { buffers = &inst->buffers[internal_buf_type[i]]; @@ -635,30 +620,13 @@ int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffe int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; struct iris_buffer *buffer, *next; struct iris_buffers *buffers; const u32 *internal_buf_type; u32 internal_buffer_count, i; int ret; - if (inst->domain == DECODER) { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - internal_buffer_count = firmware_data->dec_op_int_buf_tbl_size; - } - } else { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - internal_buffer_count = firmware_data->enc_op_int_buf_tbl_size; - } - } + iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &internal_buffer_count); for (i = 0; i < internal_buffer_count; i++) { buffers = &inst->buffers[internal_buf_type[i]]; @@ -680,7 +648,7 @@ int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane) return 0; } -int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer) +void iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer) { struct iris_core *core = inst->core; @@ -688,36 +656,16 @@ int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buf dma_free_attrs(core->dev, buffer->buffer_size, buffer->kvaddr, buffer->device_addr, buffer->dma_attrs); kfree(buffer); - - return 0; } static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool force) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; struct iris_buffer *buf, *next; struct iris_buffers *buffers; const u32 *internal_buf_type; u32 i, len; - int ret; - if (inst->domain == DECODER) { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - len = firmware_data->dec_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->dec_op_int_buf_tbl; - len = firmware_data->dec_op_int_buf_tbl_size; - } - } else { - if (V4L2_TYPE_IS_OUTPUT(plane)) { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - len = firmware_data->enc_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->enc_op_int_buf_tbl; - len = firmware_data->enc_op_int_buf_tbl_size; - } - } + iris_get_int_buf_tbl(inst, plane, &internal_buf_type, &len); for (i = 0; i < len; i++) { buffers = &inst->buffers[internal_buf_type[i]]; @@ -730,9 +678,7 @@ static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool if (!force && buf->attr & BUF_ATTR_QUEUED) continue; - ret = iris_destroy_internal_buffer(inst, buf); - if (ret) - return ret; + iris_destroy_internal_buffer(inst, buf); } } @@ -742,11 +688,8 @@ static int iris_destroy_internal_buffers(struct iris_inst *inst, u32 plane, bool else buffers = &inst->buffers[BUF_ARP]; - list_for_each_entry_safe(buf, next, &buffers->list, list) { - ret = iris_destroy_internal_buffer(inst, buf); - if (ret) - return ret; - } + list_for_each_entry_safe(buf, next, &buffers->list, list) + iris_destroy_internal_buffer(inst, buf); } return 0; @@ -788,18 +731,12 @@ static int iris_release_internal_buffers(struct iris_inst *inst, static int iris_release_input_internal_buffers(struct iris_inst *inst) { - const struct iris_firmware_data *firmware_data = inst->core->iris_firmware_data; const u32 *internal_buf_type; u32 internal_buffer_count, i; int ret; - if (inst->domain == DECODER) { - internal_buf_type = firmware_data->dec_ip_int_buf_tbl; - internal_buffer_count = firmware_data->dec_ip_int_buf_tbl_size; - } else { - internal_buf_type = firmware_data->enc_ip_int_buf_tbl; - internal_buffer_count = firmware_data->enc_ip_int_buf_tbl_size; - } + iris_get_int_buf_tbl(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + &internal_buf_type, &internal_buffer_count); for (i = 0; i < internal_buffer_count; i++) { ret = iris_release_internal_buffers(inst, internal_buf_type[i]); diff --git a/drivers/media/platform/qcom/iris/iris_buffer.h b/drivers/media/platform/qcom/iris/iris_buffer.h index 75bb76776182..ab8e5d953101 100644 --- a/drivers/media/platform/qcom/iris/iris_buffer.h +++ b/drivers/media/platform/qcom/iris/iris_buffer.h @@ -112,7 +112,7 @@ void iris_get_internal_buffers(struct iris_inst *inst, u32 plane); int iris_create_internal_buffers(struct iris_inst *inst, u32 plane); int iris_queue_internal_buffers(struct iris_inst *inst, u32 plane); int iris_queue_internal_deferred_buffers(struct iris_inst *inst, enum iris_buffer_type buffer_type); -int iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer); +void iris_destroy_internal_buffer(struct iris_inst *inst, struct iris_buffer *buffer); int iris_destroy_all_internal_buffers(struct iris_inst *inst, u32 plane); int iris_destroy_dequeued_internal_buffers(struct iris_inst *inst, u32 plane); int iris_alloc_and_queue_persist_bufs(struct iris_inst *inst, enum iris_buffer_type buf_type); diff --git a/drivers/media/platform/qcom/iris/iris_core.c b/drivers/media/platform/qcom/iris/iris_core.c index 52bf56e517f9..8c335dbfce16 100644 --- a/drivers/media/platform/qcom/iris/iris_core.c +++ b/drivers/media/platform/qcom/iris/iris_core.c @@ -12,18 +12,24 @@ void iris_core_deinit(struct iris_core *core) { - pm_runtime_resume_and_get(core->dev); + int ret; + + ret = pm_runtime_resume_and_get(core->dev); mutex_lock(&core->lock); if (core->state != IRIS_CORE_DEINIT) { iris_fw_unload(core); - iris_vpu_power_off(core); + + if (!ret) + iris_vpu_power_off(core); + iris_hfi_queues_deinit(core); core->state = IRIS_CORE_DEINIT; } mutex_unlock(&core->lock); - pm_runtime_put_sync(core->dev); + if (!ret) + pm_runtime_put_sync(core->dev); } static int iris_wait_for_system_response(struct iris_core *core) diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.c b/drivers/media/platform/qcom/iris/iris_ctrls.c index 10e33b8a73f6..bf17d310eac0 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.c +++ b/drivers/media/platform/qcom/iris/iris_ctrls.c @@ -154,6 +154,8 @@ static enum platform_inst_fw_cap_type iris_get_cap_id(u32 id) return LAYER4_BITRATE_HEVC; case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: return LAYER5_BITRATE_HEVC; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + return REQUEST_SYNC_FRAME; default: return INST_FW_CAP_MAX; } @@ -297,6 +299,8 @@ static u32 iris_get_v4l2_id(enum platform_inst_fw_cap_type cap_id) return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR; case LAYER5_BITRATE_HEVC: return V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR; + case REQUEST_SYNC_FRAME: + return V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME; default: return 0; } @@ -1293,7 +1297,7 @@ int iris_set_use_and_mark_ltr(struct iris_inst *inst, enum platform_inst_fw_cap_ int iris_set_intra_period(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) { const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; - u32 gop_size = inst->fw_caps[GOP_SIZE].value; + u32 gop_size = inst->fw_caps[cap_id].value; u32 b_frame = inst->fw_caps[B_FRAME].value; u32 hfi_id = inst->fw_caps[cap_id].hfi_id; struct hfi_intra_period intra_period; @@ -1477,6 +1481,43 @@ int iris_set_layer_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_typ &bitrate, sizeof(u32)); } +int iris_set_req_sync_frame(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 hfi_val = 0; + + if (inst->fw_caps[PREPEND_SPSPPS_TO_IDR].value) + hfi_val = HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR; + else + hfi_val = HFI_SYNC_FRAME_REQUEST_WITHOUT_SEQ_HDR; + + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32_ENUM, + &hfi_val, sizeof(u32)); +} + +int iris_set_time_delta_based_rc(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id) +{ + const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; + u32 hfi_id = inst->fw_caps[cap_id].hfi_id; + u32 value = inst->fw_caps[cap_id].value; + + /* + * Disable time-delta-based rate control (value = 0). + * This overrides the firmware's default (enabled), ensuring the + * firmware uses the configured bitrate target rather than calculating + * bitrate from frame timing. + */ + return hfi_ops->session_set_property(inst, hfi_id, + HFI_HOST_FLAGS_NONE, + iris_get_port_info(inst, cap_id), + HFI_PAYLOAD_U32, + &value, sizeof(u32)); +} + int iris_set_properties(struct iris_inst *inst, u32 plane) { const struct iris_hfi_session_ops *hfi_ops = inst->hfi_session_ops; diff --git a/drivers/media/platform/qcom/iris/iris_ctrls.h b/drivers/media/platform/qcom/iris/iris_ctrls.h index 3c462ec9190b..5180d53d3c90 100644 --- a/drivers/media/platform/qcom/iris/iris_ctrls.h +++ b/drivers/media/platform/qcom/iris/iris_ctrls.h @@ -47,6 +47,8 @@ int iris_set_layer_type(struct iris_inst *inst, enum platform_inst_fw_cap_type c int iris_set_layer_count_gen1(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_layer_count_gen2(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_layer_bitrate(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_req_sync_frame(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); +int iris_set_time_delta_based_rc(struct iris_inst *inst, enum platform_inst_fw_cap_type cap_id); int iris_set_properties(struct iris_inst *inst, u32 plane); #endif diff --git a/drivers/media/platform/qcom/iris/iris_firmware.c b/drivers/media/platform/qcom/iris/iris_firmware.c index ea9654dd679e..21cdf1c39835 100644 --- a/drivers/media/platform/qcom/iris/iris_firmware.c +++ b/drivers/media/platform/qcom/iris/iris_firmware.c @@ -17,20 +17,109 @@ #define MAX_FIRMWARE_NAME_SIZE 128 -static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) +/* Detect Gen2 firmware by scanning the blob for: + * QC_IMAGE_VERSION_STRING=<version> + * and then checking: + * - version starts with "vfw", OR + * - version matches "video-firmware.N.M" with N >= 2 + */ + +static bool iris_detect_gen2_from_fwdata(const u8 *data, size_t size) +{ + static const char *marker = "QC_IMAGE_VERSION_STRING="; + const size_t mlen = strlen(marker); + static const char *vfw = "vfw"; + const size_t vfwlen = strlen(vfw); + static const char *vf = "video-firmware."; + const size_t vflen = strlen(vf); + + for (size_t i = 0; i + mlen < size; i++) { + const char *found; + + if (memcmp(data + i, marker, mlen)) + continue; + + found = data + i + mlen; + size -= i + mlen; + + /* vfw => Gen2 */ + if (size > vfwlen && !memcmp(found, vfw, vfwlen)) + return true; + + if (size < vflen || + memcmp(found, vf, vflen)) + return false; + + found += vflen; + size -= vflen; + + /* + * video-firmware.1.x is Gen1. + * video-firmware.2.x and video-firmware.10.x are Gen2. + */ + return size >= 2 && + (*found >= '2' || (*found == '1' && found[1] != '.')); + } + + return false; +} + +static const struct firmware *iris_detect_firmware(struct iris_core *core, + const char **fw_name) +{ + const struct firmware *firmware; + bool has_both_gens; + int ret; + + *fw_name = NULL; + if (core->iris_platform_data->firmware_desc_gen2) + core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen2; + else if (core->iris_platform_data->firmware_desc_gen1) + core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1; + else + return ERR_PTR(-EINVAL); + + has_both_gens = core->iris_platform_data->firmware_desc_gen2 && + core->iris_platform_data->firmware_desc_gen1; + + ret = of_property_read_string_index(dev_of_node(core->dev), "firmware-name", 0, fw_name); + if (ret) { + *fw_name = core->iris_firmware_desc->fwname; + ret = request_firmware(&firmware, *fw_name, core->dev); + if (ret && has_both_gens) { + core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1; + *fw_name = core->iris_firmware_desc->fwname; + ret = request_firmware(&firmware, *fw_name, core->dev); + } + + return ret ? ERR_PTR(ret) : firmware; + } + + ret = request_firmware(&firmware, *fw_name, core->dev); + if (ret) + return ERR_PTR(ret); + + if (has_both_gens && + !iris_detect_gen2_from_fwdata((const u8 *)firmware->data, firmware->size)) { + dev_info(core->dev, "Gen1 FW detected in %s\n", *fw_name); + core->iris_firmware_desc = core->iris_platform_data->firmware_desc_gen1; + } + + return firmware; +} + +static int iris_load_fw_to_memory(struct iris_core *core) { const struct firmware *firmware = NULL; struct device *dev = core->dev; struct resource res; phys_addr_t mem_phys; + const char *fw_name; size_t res_size; ssize_t fw_size; void *mem_virt; int ret; - if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4) - return -EINVAL; - ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); if (ret) return ret; @@ -38,9 +127,11 @@ static int iris_load_fw_to_memory(struct iris_core *core, const char *fw_name) mem_phys = res.start; res_size = resource_size(&res); - ret = request_firmware(&firmware, fw_name, dev); - if (ret) - return ret; + firmware = iris_detect_firmware(core, &fw_name); + if (IS_ERR(firmware)) + return PTR_ERR(firmware); + + core->iris_firmware_data = core->iris_firmware_desc->firmware_data; fw_size = qcom_mdt_get_size(firmware); if (fw_size < 0 || res_size < (size_t)fw_size) { @@ -67,18 +158,12 @@ err_release_fw: int iris_fw_load(struct iris_core *core) { const struct tz_cp_config *cp_config; - const char *fwpath = NULL; int i, ret; - ret = of_property_read_string_index(core->dev->of_node, "firmware-name", 0, - &fwpath); - if (ret) - fwpath = core->iris_firmware_desc->fwname; - - ret = iris_load_fw_to_memory(core, fwpath); + ret = iris_load_fw_to_memory(core); if (ret) { - dev_err(core->dev, "firmware download failed\n"); - return -ENOMEM; + dev_err(core->dev, "firmware download failed %d\n", ret); + return ret; } ret = qcom_pas_auth_and_reset(IRIS_PAS_ID); @@ -100,7 +185,7 @@ int iris_fw_load(struct iris_core *core) } } - return ret; + return 0; } int iris_fw_unload(struct iris_core *core) diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c index ca1545d28b53..0f7e7d6b25f4 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1.c @@ -171,7 +171,9 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { .max = (1 << 16) - 1, .step_or_mask = 1, .value = 30, - .set = iris_set_u32 + .hfi_id = HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_intra_period, }, { .cap_id = ENTROPY_MODE, @@ -240,7 +242,7 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { .step_or_mask = 1, .value = 0, .hfi_id = HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH, - .flags = CAP_FLAG_OUTPUT_PORT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, .set = iris_set_ir_period_gen1, }, { @@ -282,16 +284,6 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { .flags = CAP_FLAG_OUTPUT_PORT, }, { - .cap_id = INTRA_PERIOD, - .min = 0, - .max = 1, - .step_or_mask = 1, - .value = 0, - .hfi_id = HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD, - .flags = CAP_FLAG_OUTPUT_PORT, - .set = iris_set_intra_period, - }, - { .cap_id = LAYER_ENABLE, .min = 0, .max = 1, @@ -383,6 +375,16 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8250_enc[] = { CAP_FLAG_DYNAMIC_ALLOWED, .set = iris_set_bitrate_gen1, }, + { + .cap_id = REQUEST_SYNC_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME, + .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_req_sync_frame, + }, }; static const u32 sm8250_vdec_input_config_param_default[] = { diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c index 7674b47ad6c4..f6e9cbfccd09 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_command.c @@ -442,7 +442,7 @@ static int iris_hfi_gen1_session_unset_buffers(struct iris_inst *inst, struct ir ret = iris_wait_for_session_response(inst, false); if (!ret) - ret = iris_destroy_internal_buffer(inst, buf); + iris_destroy_internal_buffer(inst, buf); exit: kfree(pkt); @@ -741,6 +741,9 @@ iris_hfi_gen1_packet_session_set_property(struct hfi_session_set_property_pkt *p packet->shdr.hdr.size += sizeof(u32); break; } + case HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME: { + break; + } default: return -EINVAL; } diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h index 0e4dee192384..275f3fea3d2a 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen1_defines.h @@ -157,6 +157,7 @@ #define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER 0x2005026 #define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE 0x2006001 #define HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD 0x2006003 +#define HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME 0x2006004 #define HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME 0x2006009 #define HFI_PROPERTY_CONFIG_VENC_USELTRFRAME 0x200600a #define HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER 0x2006008 diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2.c index acc0ed8adda1..3b8fbefb8b93 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2.c @@ -11,8 +11,832 @@ #include "iris_vpu_buffer.h" #define VIDEO_ARCH_LX 1 +#define MILOS_BITRATE_MAX 100000000 #define BITRATE_MAX 245000000 +static const struct platform_inst_fw_cap inst_fw_cap_milos_dec[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = PROFILE_VP9, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_2, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + .value = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = LEVEL_VP9, + .min = V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_VP9_LEVEL_5_0, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0), + .value = V4L2_MPEG_VIDEO_VP9_LEVEL_5_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = TIER, + .min = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + .value = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .hfi_id = HFI_PROP_TIER, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_u32_enum, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = PIPE, + /* .max, .min and .value are set via platform data */ + .step_or_mask = 1, + .hfi_id = HFI_PROP_PIPE, + .set = iris_set_pipe, + }, + { + .cap_id = POC, + .min = 0, + .max = 2, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_PIC_ORDER_CNT_TYPE, + }, + { + .cap_id = CODED_FRAMES, + .min = CODED_FRAMES_PROGRESSIVE, + .max = CODED_FRAMES_PROGRESSIVE, + .step_or_mask = 0, + .value = CODED_FRAMES_PROGRESSIVE, + .hfi_id = HFI_PROP_CODED_FRAMES, + }, + { + .cap_id = BIT_DEPTH, + .min = BIT_DEPTH_8, + .max = BIT_DEPTH_10, + .step_or_mask = 1, + .value = BIT_DEPTH_8, + .hfi_id = HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + }, + { + .cap_id = RAP_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + .hfi_id = HFI_PROP_DEC_START_FROM_RAP_FRAME, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, +}; + +static const struct platform_inst_fw_cap inst_fw_cap_milos_enc[] = { + { + .cap_id = PROFILE_H264, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + .value = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = PROFILE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10), + .value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .hfi_id = HFI_PROP_PROFILE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_profile, + }, + { + .cap_id = LEVEL_H264, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + .value = V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = LEVEL_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .max = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5), + .value = V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + .hfi_id = HFI_PROP_LEVEL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_level, + }, + { + .cap_id = STAGE, + .min = STAGE_1, + .max = STAGE_2, + .step_or_mask = 1, + .value = STAGE_2, + .hfi_id = HFI_PROP_STAGE, + .set = iris_set_stage, + }, + { + .cap_id = HEADER_MODE, + .min = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .max = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + .value = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .hfi_id = HFI_PROP_SEQ_HEADER_MODE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_header_mode_gen2, + }, + { + .cap_id = PREPEND_SPSPPS_TO_IDR, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + }, + { + .cap_id = BITRATE, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_bitrate_gen2, + }, + { + .cap_id = BITRATE_PEAK, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_TOTAL_PEAK_BITRATE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_peak_bitrate, + }, + { + .cap_id = BITRATE_MODE, + .min = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + .value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .hfi_id = HFI_PROP_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_bitrate_mode_gen2, + }, + { + .cap_id = FRAME_SKIP_MODE, + .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + .value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = FRAME_RC_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 1, + }, + { + .cap_id = GOP_SIZE, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 2 * DEFAULT_FPS - 1, + .hfi_id = HFI_PROP_MAX_GOP_FRAMES, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_u32, + }, + { + .cap_id = ENTROPY_MODE, + .min = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .max = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + .value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .hfi_id = HFI_PROP_CABAC_SESSION, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_entropy_mode_gen2, + }, + { + .cap_id = MIN_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MIN_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + .hfi_id = HFI_PROP_MIN_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_min_qp, + }, + { + .cap_id = MAX_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = MAX_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + .hfi_id = HFI_PROP_MAX_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_max_qp, + }, + { + .cap_id = I_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = P_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = B_FRAME_MIN_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MIN_QP_8BIT, + }, + { + .cap_id = I_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = P_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = B_FRAME_MAX_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = MAX_QP, + }, + { + .cap_id = I_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = I_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = P_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_H264, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = B_FRAME_QP_HEVC, + .min = MIN_QP_8BIT, + .max = MAX_QP, + .step_or_mask = 1, + .value = DEFAULT_QP, + .hfi_id = HFI_PROP_QP_PACKED, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_frame_qp, + }, + { + .cap_id = INPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_INPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = OUTPUT_BUF_HOST_MAX_COUNT, + .min = DEFAULT_MAX_HOST_BUF_COUNT, + .max = DEFAULT_MAX_HOST_BURST_BUF_COUNT, + .step_or_mask = 1, + .value = DEFAULT_MAX_HOST_BUF_COUNT, + .hfi_id = HFI_PROP_BUFFER_HOST_MAX_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = ROTATION, + .min = 0, + .max = 270, + .step_or_mask = 90, + .value = 0, + .hfi_id = HFI_PROP_ROTATION, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_rotation, + }, + { + .cap_id = HFLIP, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_FLIP, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_flip, + }, + { + .cap_id = VFLIP, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_FLIP, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_flip, + }, + { + .cap_id = IR_TYPE, + .min = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + .max = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + .step_or_mask = BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM), + .value = V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + }, + { + .cap_id = IR_PERIOD, + .min = 0, + .max = INT_MAX, + .step_or_mask = 1, + .value = 0, + .flags = CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_ir_period_gen2, + }, + { + .cap_id = LTR_COUNT, + .min = 0, + .max = MAX_LTR_FRAME_COUNT_GEN2, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_LTR_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_ltr_count_gen2, + }, + { + .cap_id = USE_LTR, + .min = 0, + .max = ((1 << MAX_LTR_FRAME_COUNT_GEN2) - 1), + .step_or_mask = 0, + .value = 0, + .hfi_id = HFI_PROP_LTR_USE, + .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_use_and_mark_ltr, + }, + { + .cap_id = MARK_LTR, + .min = INVALID_DEFAULT_MARK_OR_USE_LTR, + .max = (MAX_LTR_FRAME_COUNT_GEN2 - 1), + .step_or_mask = 1, + .value = INVALID_DEFAULT_MARK_OR_USE_LTR, + .hfi_id = HFI_PROP_LTR_MARK, + .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_use_and_mark_ltr, + }, + { + .cap_id = B_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_MAX_B_FRAMES, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_u32, + }, + { + .cap_id = LAYER_ENABLE, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .flags = CAP_FLAG_OUTPUT_PORT, + }, + { + .cap_id = LAYER_TYPE_H264, + .min = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + .max = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + .value = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + .hfi_id = HFI_PROP_LAYER_ENCODING_TYPE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_layer_type, + }, + { + .cap_id = LAYER_TYPE_HEVC, + .min = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + .max = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .step_or_mask = BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + .value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .hfi_id = HFI_PROP_LAYER_ENCODING_TYPE, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU, + .set = iris_set_layer_type, + }, + { + .cap_id = LAYER_COUNT_H264, + .min = 0, + .max = 5, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_LAYER_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_count_gen2, + }, + { + .cap_id = LAYER_COUNT_HEVC, + .min = 0, + .max = 5, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_LAYER_COUNT, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_count_gen2, + }, + { + .cap_id = LAYER0_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER1, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER1_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER2, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER2_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER3, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER3_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER4, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER4_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER5, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER5_BITRATE_H264, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER6, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER0_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER1, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER1_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER2, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER2_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER3, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER3_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER4, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER4_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER5, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + }, + { + .cap_id = LAYER5_BITRATE_HEVC, + .min = 1, + .max = MILOS_BITRATE_MAX, + .step_or_mask = 1, + .value = BITRATE_DEFAULT, + .hfi_id = HFI_PROP_BITRATE_LAYER6, + .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_layer_bitrate, + } +}; + static const struct platform_inst_fw_cap inst_fw_cap_sm8550_dec[] = { { .cap_id = PROFILE_H264, @@ -417,6 +1241,16 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { .set = iris_set_bitrate_mode_gen2, }, { + .cap_id = TIME_DELTA_BASED_RC, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + .flags = CAP_FLAG_OUTPUT_PORT, + .set = iris_set_time_delta_based_rc, + }, + { .cap_id = FRAME_SKIP_MODE, .min = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, .max = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, @@ -937,7 +1771,17 @@ static const struct platform_inst_fw_cap inst_fw_cap_sm8550_enc[] = { .flags = CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, .set = iris_set_layer_bitrate, - } + }, + { + .cap_id = REQUEST_SYNC_FRAME, + .min = 0, + .max = 1, + .step_or_mask = 1, + .value = 0, + .hfi_id = HFI_PROP_REQUEST_SYNC_FRAME, + .flags = CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED, + .set = iris_set_req_sync_frame, + }, }; static const u32 sm8550_vdec_input_config_params_default[] = { @@ -1118,3 +1962,62 @@ const struct iris_firmware_data iris_hfi_gen2_data = { .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), }; + +const struct iris_firmware_data iris_hfi_milos_data = { + .init_hfi_ops = iris_hfi_gen2_sys_ops_init, + + .core_arch = VIDEO_ARCH_LX, + + .inst_fw_caps_dec = inst_fw_cap_milos_dec, + .inst_fw_caps_dec_size = ARRAY_SIZE(inst_fw_cap_milos_dec), + .inst_fw_caps_enc = inst_fw_cap_milos_enc, + .inst_fw_caps_enc_size = ARRAY_SIZE(inst_fw_cap_milos_enc), + + .dec_input_config_params_default = + sm8550_vdec_input_config_params_default, + .dec_input_config_params_default_size = + ARRAY_SIZE(sm8550_vdec_input_config_params_default), + .dec_input_config_params_hevc = + sm8550_vdec_input_config_param_hevc, + .dec_input_config_params_hevc_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_hevc), + .dec_input_config_params_vp9 = + sm8550_vdec_input_config_param_vp9, + .dec_input_config_params_vp9_size = + ARRAY_SIZE(sm8550_vdec_input_config_param_vp9), + .dec_output_config_params = + sm8550_vdec_output_config_params, + .dec_output_config_params_size = + ARRAY_SIZE(sm8550_vdec_output_config_params), + + .enc_input_config_params = + sm8550_venc_input_config_params, + .enc_input_config_params_size = + ARRAY_SIZE(sm8550_venc_input_config_params), + .enc_output_config_params = + sm8550_venc_output_config_params, + .enc_output_config_params_size = + ARRAY_SIZE(sm8550_venc_output_config_params), + + .dec_input_prop = sm8550_vdec_subscribe_input_properties, + .dec_input_prop_size = ARRAY_SIZE(sm8550_vdec_subscribe_input_properties), + .dec_output_prop_avc = sm8550_vdec_subscribe_output_properties_avc, + .dec_output_prop_avc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_avc), + .dec_output_prop_hevc = sm8550_vdec_subscribe_output_properties_hevc, + .dec_output_prop_hevc_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_hevc), + .dec_output_prop_vp9 = sm8550_vdec_subscribe_output_properties_vp9, + .dec_output_prop_vp9_size = + ARRAY_SIZE(sm8550_vdec_subscribe_output_properties_vp9), + + .dec_ip_int_buf_tbl = sm8550_dec_ip_int_buf_tbl, + .dec_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_ip_int_buf_tbl), + .dec_op_int_buf_tbl = sm8550_dec_op_int_buf_tbl, + .dec_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_dec_op_int_buf_tbl), + + .enc_ip_int_buf_tbl = sm8550_enc_ip_int_buf_tbl, + .enc_ip_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_ip_int_buf_tbl), + .enc_op_int_buf_tbl = sm8550_enc_op_int_buf_tbl, + .enc_op_int_buf_tbl_size = ARRAY_SIZE(sm8550_enc_op_int_buf_tbl), +}; diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c index ca2954f8bd3a..388a36ff2b07 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_command.c @@ -603,10 +603,9 @@ static int iris_hfi_gen2_set_tier(struct iris_inst *inst, u32 plane) { u32 port = iris_hfi_gen2_get_port(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); struct iris_inst_hfi_gen2 *inst_hfi_gen2 = to_iris_inst_hfi_gen2(inst); - u32 tier = inst->fw_caps[TIER].value; + u32 tier_cap = (inst->codec == V4L2_PIX_FMT_AV1) ? TIER_AV1 : TIER; + u32 tier = inst->fw_caps[tier_cap].value; - tier = (inst->codec == V4L2_PIX_FMT_AV1) ? inst->fw_caps[TIER_AV1].value : - inst->fw_caps[TIER].value; inst_hfi_gen2->src_subcr_params.tier = tier; return iris_hfi_gen2_session_set_property(inst, @@ -692,7 +691,6 @@ static int iris_hfi_gen2_session_set_config_params(struct iris_inst *inst, u32 p {HFI_PROP_FRAME_RATE, iris_hfi_gen2_set_frame_rate }, {HFI_PROP_AV1_FILM_GRAIN_PRESENT, iris_hfi_gen2_set_film_grain }, {HFI_PROP_AV1_SUPER_BLOCK_ENABLED, iris_hfi_gen2_set_super_block }, - {HFI_PROP_OPB_ENABLE, iris_hfi_gen2_set_opb_enable }, }; if (inst->domain == DECODER) { @@ -766,6 +764,7 @@ static int iris_hfi_gen2_session_set_codec(struct iris_inst *inst) break; case V4L2_PIX_FMT_AV1: codec = HFI_CODEC_DECODE_AV1; + break; } iris_hfi_gen2_packet_session_property(inst, diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h index 776b21cd11b2..f43aea10090d 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_defines.h @@ -67,6 +67,7 @@ enum hfi_rate_control { }; #define HFI_PROP_RATE_CONTROL 0x0300012a +#define HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL 0x0300012b #define HFI_PROP_QP_PACKED 0x0300012e #define HFI_PROP_MIN_QP_PACKED 0x0300012f #define HFI_PROP_MAX_QP_PACKED 0x03000130 @@ -90,6 +91,13 @@ enum hfi_layer_encoding_type { #define HFI_PROP_BITRATE_LAYER4 0x0300013f #define HFI_PROP_BITRATE_LAYER5 0x03000140 #define HFI_PROP_BITRATE_LAYER6 0x03000141 + +enum hfi_syncframe_request_mode { + HFI_SYNC_FRAME_REQUEST_WITHOUT_SEQ_HDR = 0x00000001, + HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR = 0x00000002, +}; + +#define HFI_PROP_REQUEST_SYNC_FRAME 0x03000145 #define HFI_PROP_MAX_GOP_FRAMES 0x03000146 #define HFI_PROP_MAX_B_FRAMES 0x03000147 #define HFI_PROP_QUALITY_MODE 0x03000148 diff --git a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c index 25162ae71357..8c2644c7f6e8 100644 --- a/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c +++ b/drivers/media/platform/qcom/iris/iris_hfi_gen2_response.c @@ -447,7 +447,9 @@ static int iris_hfi_gen2_handle_release_internal_buffer(struct iris_inst *inst, buf->attr &= ~BUF_ATTR_QUEUED; - return iris_destroy_internal_buffer(inst, buf); + iris_destroy_internal_buffer(inst, buf); + + return 0; } static int iris_hfi_gen2_handle_session_stop(struct iris_inst *inst, diff --git a/drivers/media/platform/qcom/iris/iris_platform_common.h b/drivers/media/platform/qcom/iris/iris_platform_common.h index c9256f2323dc..974809509146 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_common.h +++ b/drivers/media/platform/qcom/iris/iris_platform_common.h @@ -52,7 +52,9 @@ enum pipe_type { extern const struct iris_firmware_data iris_hfi_gen1_data; extern const struct iris_firmware_data iris_hfi_gen2_data; +extern const struct iris_firmware_data iris_hfi_milos_data; +extern const struct iris_platform_data milos_data; extern const struct iris_platform_data qcs8300_data; extern const struct iris_platform_data sc7280_data; extern const struct iris_platform_data sm8250_data; @@ -165,7 +167,6 @@ enum platform_inst_fw_cap_type { USE_LTR, MARK_LTR, B_FRAME, - INTRA_PERIOD, LAYER_ENABLE, LAYER_TYPE_H264, LAYER_TYPE_HEVC, @@ -183,6 +184,8 @@ enum platform_inst_fw_cap_type { LAYER3_BITRATE_HEVC, LAYER4_BITRATE_HEVC, LAYER5_BITRATE_HEVC, + REQUEST_SYNC_FRAME, + TIME_DELTA_BASED_RC, INST_FW_CAP_MAX, }; @@ -289,11 +292,7 @@ struct iris_firmware_desc { }; struct iris_platform_data { - /* - * XXX: replace with gen1 / gen2 pointers once we have platforms - * supporting both firmware kinds. - */ - const struct iris_firmware_desc *firmware_desc; + const struct iris_firmware_desc *firmware_desc_gen1, *firmware_desc_gen2; const struct vpu_ops *vpu_ops; const struct icc_info *icc_tbl; diff --git a/drivers/media/platform/qcom/iris/iris_platform_milos.h b/drivers/media/platform/qcom/iris/iris_platform_milos.h new file mode 100644 index 000000000000..8a45a4aa9e86 --- /dev/null +++ b/drivers/media/platform/qcom/iris/iris_platform_milos.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __IRIS_PLATFORM_MILOS_H__ +#define __IRIS_PLATFORM_MILOS_H__ + +#define MILOS_MAXIMUM_FPS 240 + +static const struct icc_info iris_icc_info_milos[] = { + { "cpu-cfg", 1000, 1000 }, + { "video-mem", 1000, 10000000 }, +}; + +static const char * const milos_opp_pd_table[] = { "cx", "mx" }; + +static struct platform_inst_caps platform_inst_cap_milos = { + .min_frame_width = 96, + .max_frame_width = 4096, + .min_frame_height = 96, + .max_frame_height = 4096, + .max_mbpf = (4096 * 2176) / 256, + .mb_cycles_vsp = 25, + .mb_cycles_vpp = 200, + .max_frame_rate = MILOS_MAXIMUM_FPS, + .max_operating_rate = MILOS_MAXIMUM_FPS, +}; + +#endif diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c index 6e06a32822bb..bbdbf21961d7 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_vpu2.c +++ b/drivers/media/platform/qcom/iris/iris_platform_vpu2.c @@ -13,15 +13,28 @@ #include "iris_vpu_common.h" #include "iris_instance.h" +#include "iris_platform_milos.h" #include "iris_platform_sc7280.h" #include "iris_platform_sm8250.h" +static const struct iris_firmware_desc iris_milos_desc = { + .firmware_data = &iris_hfi_milos_data, + .get_vpu_buffer_size = iris_vpu_buf_size, + .fwname = "qcom/vpu/vpu20_p2_gen2_s7.mbn", +}; + static const struct iris_firmware_desc iris_vpu20_p1_gen1_desc = { .firmware_data = &iris_hfi_gen1_data, .get_vpu_buffer_size = iris_vpu_buf_size, .fwname = "qcom/vpu/vpu20_p1.mbn", }; +static const struct iris_firmware_desc iris_vpu20_p1_gen2_s6_desc = { + .firmware_data = &iris_hfi_gen2_data, + .get_vpu_buffer_size = iris_vpu33_buf_size, + .fwname = "qcom/vpu/vpu20_p1_gen2_s6.mbn", +}; + static const struct iris_firmware_desc iris_vpu20_p4_gen1_desc = { .firmware_data = &iris_hfi_gen1_data, .get_vpu_buffer_size = iris_vpu_buf_size, @@ -64,8 +77,37 @@ static const struct tz_cp_config tz_cp_config_vpu2[] = { }, }; +const struct iris_platform_data milos_data = { + .firmware_desc_gen1 = &iris_milos_desc, + .vpu_ops = &iris_vpu2_ops, + .icc_tbl = iris_icc_info_milos, + .icc_tbl_size = ARRAY_SIZE(iris_icc_info_milos), + .bw_tbl_dec = sm8250_bw_table_dec, + .bw_tbl_dec_size = ARRAY_SIZE(sm8250_bw_table_dec), + .pmdomain_tbl = iris_pmdomain_table_vpu2, + .pmdomain_tbl_size = ARRAY_SIZE(iris_pmdomain_table_vpu2), + .opp_pd_tbl = milos_opp_pd_table, + .opp_pd_tbl_size = ARRAY_SIZE(milos_opp_pd_table), + .clk_tbl = sm8250_clk_table, + .clk_tbl_size = ARRAY_SIZE(sm8250_clk_table), + .opp_clk_tbl = sm8250_opp_clk_table, + .clk_rst_tbl = iris_clk_reset_table_vpu2, + .clk_rst_tbl_size = ARRAY_SIZE(iris_clk_reset_table_vpu2), + .dma_mask = 0xe0000000 - 1, + .inst_iris_fmts = iris_fmts_vpu2_dec, + .inst_iris_fmts_size = ARRAY_SIZE(iris_fmts_vpu2_dec), + .inst_caps = &platform_inst_cap_milos, + .tz_cp_config_data = tz_cp_config_vpu2, + .tz_cp_config_data_size = ARRAY_SIZE(tz_cp_config_vpu2), + .num_vpp_pipe = 2, + .max_session_count = 16, + .max_core_mbpf = ((4096 * 2176) / 256) * 2, + .max_core_mbps = ((3840 * 2176) / 256) * 30 + ((1920 * 1088) / 256) * 30, +}; + const struct iris_platform_data sc7280_data = { - .firmware_desc = &iris_vpu20_p1_gen1_desc, + .firmware_desc_gen1 = &iris_vpu20_p1_gen1_desc, + .firmware_desc_gen2 = &iris_vpu20_p1_gen2_s6_desc, .vpu_ops = &iris_vpu2_ops, .icc_tbl = iris_icc_info_vpu2, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu2), @@ -94,7 +136,7 @@ const struct iris_platform_data sc7280_data = { }; const struct iris_platform_data sm8250_data = { - .firmware_desc = &iris_vpu20_p4_gen1_desc, + .firmware_desc_gen1 = &iris_vpu20_p4_gen1_desc, .vpu_ops = &iris_vpu2_ops, .icc_tbl = iris_icc_info_vpu2, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu2), diff --git a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c index 2c63adbc5579..74626b35d9cb 100644 --- a/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c +++ b/drivers/media/platform/qcom/iris/iris_platform_vpu3x.c @@ -90,7 +90,7 @@ static const struct tz_cp_config tz_cp_config_vpu3[] = { * - inst_caps to platform_inst_cap_qcs8300 */ const struct iris_platform_data qcs8300_data = { - .firmware_desc = &iris_vpu30_p4_s6_gen2_desc, + .firmware_desc_gen2 = &iris_vpu30_p4_s6_gen2_desc, .vpu_ops = &iris_vpu3_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), @@ -119,7 +119,7 @@ const struct iris_platform_data qcs8300_data = { }; const struct iris_platform_data sm8550_data = { - .firmware_desc = &iris_vpu30_p4_gen2_desc, + .firmware_desc_gen2 = &iris_vpu30_p4_gen2_desc, .vpu_ops = &iris_vpu3_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), @@ -154,7 +154,7 @@ const struct iris_platform_data sm8550_data = { * - controller_rst_tbl to sm8650_controller_reset_table */ const struct iris_platform_data sm8650_data = { - .firmware_desc = &iris_vpu33_p4_gen2_desc, + .firmware_desc_gen2 = &iris_vpu33_p4_gen2_desc, .vpu_ops = &iris_vpu33_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), @@ -185,7 +185,7 @@ const struct iris_platform_data sm8650_data = { }; const struct iris_platform_data sm8750_data = { - .firmware_desc = &iris_vpu35_p4_gen2_desc, + .firmware_desc_gen2 = &iris_vpu35_p4_gen2_desc, .vpu_ops = &iris_vpu35_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), @@ -220,7 +220,7 @@ const struct iris_platform_data sm8750_data = { * - different num_vpp_pipe */ const struct iris_platform_data x1p42100_data = { - .firmware_desc = &iris_vpu30_p1_gen2_desc, + .firmware_desc_gen2 = &iris_vpu30_p1_gen2_desc, .vpu_ops = &iris_vpu3_ops, .icc_tbl = iris_icc_info_vpu3x, .icc_tbl_size = ARRAY_SIZE(iris_icc_info_vpu3x), diff --git a/drivers/media/platform/qcom/iris/iris_probe.c b/drivers/media/platform/qcom/iris/iris_probe.c index c2dcb50a2782..e4acf4a74f94 100644 --- a/drivers/media/platform/qcom/iris/iris_probe.c +++ b/drivers/media/platform/qcom/iris/iris_probe.c @@ -251,8 +251,6 @@ static int iris_probe(struct platform_device *pdev) return core->irq; core->iris_platform_data = of_device_get_match_data(core->dev); - core->iris_firmware_desc = core->iris_platform_data->firmware_desc; - core->iris_firmware_data = core->iris_firmware_desc->firmware_data; core->ubwc_cfg = qcom_ubwc_config_get_data(); if (IS_ERR(core->ubwc_cfg)) @@ -271,8 +269,6 @@ static int iris_probe(struct platform_device *pdev) if (ret) return ret; - iris_session_init_caps(core); - ret = v4l2_device_register(dev, &core->v4l2_dev); if (ret) return ret; @@ -361,6 +357,10 @@ static const struct dev_pm_ops iris_pm_ops = { static const struct of_device_id iris_dt_match[] = { { + .compatible = "qcom,milos-iris", + .data = &milos_data, + }, + { .compatible = "qcom,qcs8300-iris", .data = &qcs8300_data, }, diff --git a/drivers/media/platform/qcom/iris/iris_resources.c b/drivers/media/platform/qcom/iris/iris_resources.c index 773f6548370a..2c4d34c7bd77 100644 --- a/drivers/media/platform/qcom/iris/iris_resources.c +++ b/drivers/media/platform/qcom/iris/iris_resources.c @@ -61,9 +61,9 @@ int iris_unset_icc_bw(struct iris_core *core) int iris_opp_set_rate(struct device *dev, unsigned long freq) { - struct dev_pm_opp *opp __free(put_opp); + struct dev_pm_opp *opp __free(put_opp) = + devfreq_recommended_opp(dev, &freq, 0); - opp = devfreq_recommended_opp(dev, &freq, 0); if (IS_ERR(opp)) return PTR_ERR(opp); @@ -78,24 +78,21 @@ int iris_enable_power_domains(struct iris_core *core, struct device *pd_dev) if (ret) return ret; - ret = pm_runtime_get_sync(pd_dev); - if (ret < 0) - return ret; - - return ret; + return pm_runtime_resume_and_get(pd_dev); } int iris_disable_power_domains(struct iris_core *core, struct device *pd_dev) { int ret; + int pm_ret; ret = iris_opp_set_rate(core->dev, 0); - if (ret) - return ret; - pm_runtime_put_sync(pd_dev); + pm_ret = pm_runtime_put_sync(pd_dev); + if (!ret) + ret = pm_ret; - return 0; + return ret; } static struct clk *iris_get_clk_by_type(struct iris_core *core, enum platform_clk_type clk_type) diff --git a/drivers/media/platform/qcom/iris/iris_state.c b/drivers/media/platform/qcom/iris/iris_state.c index d14472414750..5552725c614e 100644 --- a/drivers/media/platform/qcom/iris/iris_state.c +++ b/drivers/media/platform/qcom/iris/iris_state.c @@ -60,9 +60,9 @@ int iris_inst_change_state(struct iris_inst *inst, return -EINVAL; change_state: - inst->state = request_state; dev_dbg(inst->core->dev, "state changed from %x to %x\n", inst->state, request_state); + inst->state = request_state; return 0; } @@ -269,7 +269,7 @@ bool iris_allow_cmd(struct iris_inst *inst, u32 cmd) return true; } else if (cmd == V4L2_DEC_CMD_STOP || cmd == V4L2_ENC_CMD_STOP) { if (vb2_is_streaming(src_q)) - if (inst->sub_state != IRIS_INST_SUB_DRAIN) + if (!(inst->sub_state & IRIS_INST_SUB_DRAIN)) return true; } diff --git a/drivers/media/platform/qcom/iris/iris_vidc.c b/drivers/media/platform/qcom/iris/iris_vidc.c index 14d63dc76c9b..fcbc60016bee 100644 --- a/drivers/media/platform/qcom/iris/iris_vidc.c +++ b/drivers/media/platform/qcom/iris/iris_vidc.c @@ -9,6 +9,7 @@ #include <media/v4l2-mem2mem.h> #include <media/videobuf2-dma-contig.h> +#include "iris_ctrls.h" #include "iris_vidc.h" #include "iris_instance.h" #include "iris_vdec.h" @@ -196,6 +197,8 @@ int iris_open(struct file *filp) goto fail_m2m_release; } + iris_session_init_caps(core); + if (inst->domain == DECODER) ret = iris_vdec_inst_init(inst); else if (inst->domain == ENCODER) @@ -449,14 +452,21 @@ static int iris_enum_frameintervals(struct file *filp, void *fh, static int iris_querycap(struct file *filp, void *fh, struct v4l2_capability *cap) { + struct iris_core *core = video_drvdata(filp); struct iris_inst *inst = iris_get_inst(filp); + char *info; strscpy(cap->driver, IRIS_DRV_NAME, sizeof(cap->driver)); - if (inst->domain == DECODER) + if (inst->domain == DECODER) { strscpy(cap->card, "Iris Decoder", sizeof(cap->card)); - else + info = "dec"; + } else { strscpy(cap->card, "Iris Encoder", sizeof(cap->card)); + info = "enc"; + } + snprintf(cap->bus_info, sizeof(cap->bus_info), + "plat:%s:%s", dev_name(core->dev), info); return 0; } diff --git a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c index fb6f1016415e..faebb5472866 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_buffer.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_buffer.c @@ -580,7 +580,7 @@ static u32 hfi_buffer_line_av1d(u32 frame_width, u32 frame_height, ALIGN(size_av1d_qp(frame_width, frame_height), DMA_ALIGNMENT); opbwr8 = size_av1d_lb_opb_wr1_nv12_ubwc(frame_width, frame_height); opbwr10 = size_av1d_lb_opb_wr1_tp10_ubwc(frame_width, frame_height); - opbwrbufsize = opbwr8 >= opbwr10 ? opbwr8 : opbwr10; + opbwrbufsize = max(opbwr8, opbwr10); size = ALIGN((size + opbwrbufsize), DMA_ALIGNMENT); if (is_opb) { vpss_lb_size = size_vpss_lb(frame_width, frame_height); @@ -700,7 +700,7 @@ static u32 hfi_buffer_ibc_av1d(u32 frame_width, u32 frame_height) ibc8 = size_av1d_ibc_nv12_ubwc(frame_width, frame_height); ibc10 = size_av1d_ibc_tp10_ubwc(frame_width, frame_height); - size = ibc8 >= ibc10 ? ibc8 : ibc10; + size = max(ibc8, ibc10); return ALIGN(size, DMA_ALIGNMENT); } diff --git a/drivers/media/platform/qcom/iris/iris_vpu_common.c b/drivers/media/platform/qcom/iris/iris_vpu_common.c index ab41da1f47c8..e4847c107709 100644 --- a/drivers/media/platform/qcom/iris/iris_vpu_common.c +++ b/drivers/media/platform/qcom/iris/iris_vpu_common.c @@ -237,7 +237,7 @@ void iris_vpu_power_off(struct iris_core *core) iris_unset_icc_bw(core); if (!iris_vpu_watchdog(core, core->intr_status)) - disable_irq_nosync(core->irq); + disable_irq(core->irq); } int iris_vpu_power_on_controller(struct iris_core *core) diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index f44059f19505..e96d458c52fa 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -616,7 +616,7 @@ struct hfi_capability { struct hfi_capabilities { u32 num_capabilities; - struct hfi_capability data[]; + struct hfi_capability data[] __counted_by(num_capabilities); }; #define HFI_DEBUG_MSG_LOW 0x01 @@ -802,7 +802,7 @@ struct hfi_profile_level { struct hfi_profile_level_supported { u32 profile_count; - struct hfi_profile_level profile_level[]; + struct hfi_profile_level profile_level[] __counted_by(profile_count); }; struct hfi_quality_vs_speed { @@ -1085,7 +1085,7 @@ struct hfi_resource_ocmem_requirement { struct hfi_resource_ocmem_requirement_info { u32 num_entries; - struct hfi_resource_ocmem_requirement requirements[]; + struct hfi_resource_ocmem_requirement requirements[] __counted_by(num_entries); }; struct hfi_property_sys_image_version_info_type { diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index 47b99d5b5af7..5c2025c5acc7 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -690,7 +690,7 @@ struct hfi_done_handler { u32 pkt; u32 pkt_sz; u32 pkt_sz2; - void (*done)(struct venus_core *, struct venus_inst *, void *); + void (*done)(struct venus_core *core, struct venus_inst *inst, void *packet); bool is_sys_pkt; }; diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c index b1657443f23f..d07845f37c55 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.c +++ b/drivers/media/platform/qcom/venus/hfi_parser.c @@ -85,7 +85,7 @@ parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data) type++; } - return sizeof(*mode); + return mode->num_entries * sizeof(u32) + sizeof(*mode); } static void fill_profile_level(struct hfi_plat_caps *cap, const void *data, @@ -146,7 +146,7 @@ parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data) for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, fill_caps, caps_arr, num_caps); - return sizeof(*caps); + return num_caps * sizeof(*cap) + sizeof(u32); } static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts, @@ -171,7 +171,7 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) u32 entries = fmt->format_entries; unsigned int i = 0; u32 num_planes = 0; - u32 size; + u32 size = 2 * sizeof(u32); while (entries) { num_planes = pinfo->num_planes; @@ -186,6 +186,7 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) if (pinfo->num_planes > MAX_PLANES) break; + size += sizeof(*constr) * num_planes + 2 * sizeof(u32); pinfo = (void *)pinfo + sizeof(*constr) * num_planes + 2 * sizeof(u32); entries--; @@ -193,8 +194,6 @@ parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data) for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain, fill_raw_fmts, rawfmts, i); - size = fmt->format_entries * (sizeof(*constr) * num_planes + 2 * sizeof(u32)) - + 2 * sizeof(u32); return size; } diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index be1cbd5cfe84..e88e66be4f6d 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -781,7 +781,6 @@ static int decide_core(struct venus_inst *inst) unsigned long max_freq = ULONG_MAX; struct device *dev = core->dev; struct dev_pm_opp *opp; - int ret = 0; if (legacy_binding) { if (inst->session_type == VIDC_SESSION_TYPE_DEC) @@ -829,11 +828,7 @@ static int decide_core(struct venus_inst *inst) } done: - ret = hfi_session_set_property(inst, ptype, &cu); - if (ret) - return ret; - - return ret; + return hfi_session_set_property(inst, ptype, &cu); } static int acquire_core(struct venus_inst *inst) diff --git a/drivers/media/platform/renesas/rcar-csi2.c b/drivers/media/platform/renesas/rcar-csi2.c index 7305cc4a04cb..6635f5782175 100644 --- a/drivers/media/platform/renesas/rcar-csi2.c +++ b/drivers/media/platform/renesas/rcar-csi2.c @@ -2273,11 +2273,7 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, return ret; } - ret = rcsi2_phtw_write_array(priv, step4, ARRAY_SIZE(step4)); - if (ret) - return ret; - - return ret; + return rcsi2_phtw_write_array(priv, step4, ARRAY_SIZE(step4)); } /* ----------------------------------------------------------------------------- diff --git a/drivers/media/platform/renesas/rcar-isp/Kconfig b/drivers/media/platform/renesas/rcar-isp/Kconfig index 242f6a23851f..bacc15c250fe 100644 --- a/drivers/media/platform/renesas/rcar-isp/Kconfig +++ b/drivers/media/platform/renesas/rcar-isp/Kconfig @@ -5,10 +5,12 @@ config VIDEO_RCAR_ISP depends on V4L_PLATFORM_DRIVERS depends on VIDEO_DEV && OF depends on ARCH_RENESAS || COMPILE_TEST + depends on VIDEO_RENESAS_VSP1 select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select RESET_CONTROLLER select V4L2_FWNODE + select VIDEO_DCT_RPPX1 help Support for Renesas R-Car Image Signal Processor (ISP). Enable this to support the Renesas R-Car Image Signal diff --git a/drivers/media/platform/renesas/rcar-isp/Makefile b/drivers/media/platform/renesas/rcar-isp/Makefile index b542118c831e..c0c80303682c 100644 --- a/drivers/media/platform/renesas/rcar-isp/Makefile +++ b/drivers/media/platform/renesas/rcar-isp/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -rcar-isp-objs = csisp.o +rcar-isp-objs = csisp.o core.o core-io.o obj-$(CONFIG_VIDEO_RCAR_ISP) += rcar-isp.o diff --git a/drivers/media/platform/renesas/rcar-isp/core-io.c b/drivers/media/platform/renesas/rcar-isp/core-io.c new file mode 100644 index 000000000000..820af506f896 --- /dev/null +++ b/drivers/media/platform/renesas/rcar-isp/core-io.c @@ -0,0 +1,997 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-isp.h> +#include <media/v4l2-mc.h> + +#include <linux/media/dreamchip/rppx1-config.h> + +#include "risp-core.h" + +#define risp_io_err(d, fmt, arg...) dev_err((d)->core->dev, fmt, ##arg) + +static struct risp_buffer *risp_io_vb2buf(struct vb2_v4l2_buffer *vb) +{ + return container_of(vb, struct risp_buffer, vb); +} + +static int risp_io_open(struct file *file) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + int ret; + + ret = mutex_lock_interruptible(&io->lock); + if (ret) + return ret; + + file->private_data = io; + + ret = v4l2_fh_open(file); + if (ret) + goto err_unlock; + + ret = v4l2_pipeline_pm_get(&io->vdev.entity); + if (ret < 0) + goto err_open; + + mutex_unlock(&io->lock); + + return 0; +err_open: + v4l2_fh_release(file); +err_unlock: + mutex_unlock(&io->lock); + + return ret; +} + +static int risp_io_release(struct file *file) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + int ret; + + mutex_lock(&io->lock); + + ret = _vb2_fop_release(file, NULL); + + v4l2_pipeline_pm_put(&io->vdev.entity); + + mutex_unlock(&io->lock); + + return ret; +} + +static const struct v4l2_file_operations risp_io_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = risp_io_open, + .release = risp_io_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .read = vb2_fop_read, +}; + +/* ----------------------------------------------------------------------------- + * Common queue + */ + +static int risp_io_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) + +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vq); + + if (V4L2_TYPE_IS_MULTIPLANAR(vq->type)) { + const struct v4l2_pix_format_mplane *pix = &io->format.fmt.pix_mp; + + if (*nplanes) { + if (*nplanes > pix->num_planes) + return -EINVAL; + + for (unsigned int i = 0; i < pix->num_planes; i++) + if (sizes[i] < pix->plane_fmt[i].sizeimage) + return -EINVAL; + + return 0; + } + + *nplanes = pix->num_planes; + for (unsigned int i = 0; i < pix->num_planes; i++) + sizes[i] = pix->plane_fmt[i].sizeimage; + } else { + if (*nplanes) { + if (sizes[0] < io->format.fmt.meta.buffersize) + return -EINVAL; + + return 0; + } + + *nplanes = 1; + sizes[0] = io->format.fmt.meta.buffersize; + } + + /* Initialize buffer queue */ + INIT_LIST_HEAD(&io->buffers); + + return 0; +}; + +static int risp_io_buffer_prepare_set(struct rcar_isp_core_io *io, + struct vb2_buffer *vb, unsigned int plane, + unsigned long size) +{ + if (vb2_plane_size(vb, plane) < size) { + risp_io_err(io, "Buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, plane), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, plane, size); + + return 0; +} + +static int risp_io_buffer_prepare(struct vb2_buffer *vb) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + + if (V4L2_TYPE_IS_MULTIPLANAR(vb->vb2_queue->type)) { + const struct v4l2_pix_format_mplane *pix = &io->format.fmt.pix_mp; + int ret = 0; + + for (unsigned int i = 0; i < pix->num_planes; i++) { + ret = risp_io_buffer_prepare_set(io, vb, i, + pix->plane_fmt[i].sizeimage); + if (ret) + break; + } + + return ret; + } + + return risp_io_buffer_prepare_set(io, vb, 0, + io->format.fmt.meta.buffersize); +} + +static void risp_io_buffer_queue(struct vb2_buffer *vb) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf = risp_io_vb2buf(vbuf); + + guard(mutex)(&io->core->io_lock); + + list_add_tail(&buf->list, &io->buffers); + + if (risp_core_job_prepare(io->core)) + risp_io_err(io, "Failed to prepare job\n"); +} + +static void risp_io_return_buffers(struct rcar_isp_core_io *io, + enum vb2_buffer_state state) +{ + struct risp_buffer *buf, *node; + + lockdep_assert_held(&io->core->io_lock); + + list_for_each_entry_safe(buf, node, &io->buffers, list) { + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->list); + } +} + +static int risp_io_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vq); + int ret; + + scoped_guard(mutex, &io->core->io_lock) { + if (io->core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.width != + io->core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.width || + io->core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.height != + io->core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.height) { + risp_io_return_buffers(io, VB2_BUF_STATE_QUEUED); + return -EPIPE; + } + + io->streaming = true; + } + + ret = risp_core_start_streaming(io->core); + if (ret) { + guard(mutex)(&io->core->io_lock); + + risp_io_return_buffers(io, VB2_BUF_STATE_QUEUED); + return ret; + } + + return 0; +} + +static void risp_io_stop_streaming(struct vb2_queue *vq) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vq); + + scoped_guard(mutex, &io->core->io_lock) { + io->streaming = false; + risp_core_stop_streaming(io->core); + risp_io_return_buffers(io, VB2_BUF_STATE_ERROR); + } + + /* + * Wait for buffers part of the jobs not yet processed. Note that this + * might complete buffers out of order. + */ + vb2_wait_for_all_buffers(&io->queue); +} + +/* ----------------------------------------------------------------------------- + * Common V4L2 IOCTLs + */ + +static int risp_io_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + + strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + strscpy(cap->card, vdev->name, sizeof(cap->card)); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Input Exposure + */ + +static int risp_io_input_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) + +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vq); + struct rcar_isp_core *core = io->core; + struct device *bus_master; + int ret; + + ret = risp_io_queue_setup(vq, nbuffers, nplanes, sizes, alloc_devs); + if (ret) + return ret; + + bus_master = vsp1_isp_get_bus_master(core->vspx.dev); + if (IS_ERR_OR_NULL(bus_master)) { + risp_io_err(io, "Missing reference to bus-master device\n"); + return -EINVAL; + } + + /* + * Allocate buffers using the bus_master device associated with the + * VSPX associated to this ISP instance. + */ + alloc_devs[0] = bus_master; + + return 0; +}; + +static const struct vb2_ops risp_io_input_qops = { + .queue_setup = risp_io_input_queue_setup, + .buf_prepare = risp_io_buffer_prepare, + .buf_queue = risp_io_buffer_queue, + .start_streaming = risp_io_start_streaming, + .stop_streaming = risp_io_stop_streaming, +}; + +static const struct v4l2_pix_format_mplane risp_io_input_default_format = { + .width = 1920, + .height = 1080, + .field = V4L2_FIELD_NONE, + .pixelformat = V4L2_PIX_FMT_SGRBG8, + .colorspace = V4L2_COLORSPACE_RAW, + .xfer_func = V4L2_XFER_FUNC_NONE, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .num_planes = 1, + .plane_fmt = { + [0] = { + .sizeimage = 1920 * 1080, + .bytesperline = 1920, + }, + }, +}; + +static const struct risp_io_input_format { + unsigned int fourcc; + unsigned int bpp; +} risp_io_input_formats[] = { + { .fourcc = V4L2_PIX_FMT_SBGGR8, .bpp = 1 }, + { .fourcc = V4L2_PIX_FMT_SGBRG8, .bpp = 1 }, + { .fourcc = V4L2_PIX_FMT_SGRBG8, .bpp = 1 }, + { .fourcc = V4L2_PIX_FMT_SRGGB8, .bpp = 1 }, + { .fourcc = V4L2_PIX_FMT_SBGGR10, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SGBRG10, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SGRBG10, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SRGGB10, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SBGGR12, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SGBRG12, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SGRBG12, .bpp = 2 }, + { .fourcc = V4L2_PIX_FMT_SRGGB12, .bpp = 2 }, +}; + +static void risp_io_input_try_format(struct rcar_isp_core_io *io, + struct v4l2_pix_format_mplane *pix) +{ + unsigned int bpp = 0; + + v4l_bound_align_image(&pix->width, 128, 5120, 2, + &pix->height, 128, 4096, 2, 0); + + for (unsigned int i = 0; i < ARRAY_SIZE(risp_io_input_formats); i++) { + if (risp_io_input_formats[i].fourcc == pix->pixelformat) { + bpp = risp_io_input_formats[i].bpp; + break; + } + } + + if (!bpp) { + pix->pixelformat = risp_io_input_formats[0].fourcc; + bpp = risp_io_input_formats[0].bpp; + } + + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_RAW; + + pix->num_planes = 1; + pix->plane_fmt[0].bytesperline = pix->width * bpp; + pix->plane_fmt[0].sizeimage = pix->plane_fmt[0].bytesperline * pix->height; +} + +static int risp_io_input_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->index >= ARRAY_SIZE(risp_io_input_formats)) + return -EINVAL; + + f->pixelformat = risp_io_input_formats[f->index].fourcc; + + return 0; +} + +static int risp_io_input_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + f->fmt.pix_mp = io->format.fmt.pix_mp; + + return 0; +} + +static int risp_io_input_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + risp_io_input_try_format(io, &f->fmt.pix_mp); + + io->format.fmt.pix_mp = f->fmt.pix_mp; + + return 0; +} + +static int risp_io_input_try_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + risp_io_input_try_format(io, &f->fmt.pix_mp); + + return 0; +} + +static int risp_io_input_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + bool found = false; + + if (fsize->index != 0) + return -EINVAL; + + for (unsigned int i = 0; i < ARRAY_SIZE(risp_io_input_formats); i++) { + if (risp_io_input_formats[i].fourcc == fsize->pixel_format) { + found = true; + break; + } + } + + if (!found) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + + fsize->stepwise.min_width = 128; + fsize->stepwise.max_width = 5120; + fsize->stepwise.step_width = 2; + + fsize->stepwise.min_height = 128; + fsize->stepwise.max_height = 4096; + fsize->stepwise.step_height = 2; + + return 0; +} + +static const struct v4l2_ioctl_ops risp_io_input_ioctl_ops = { + .vidioc_querycap = risp_io_querycap, + + .vidioc_enum_fmt_vid_out = risp_io_input_enum_fmt, + .vidioc_g_fmt_vid_out_mplane = risp_io_input_g_fmt, + .vidioc_s_fmt_vid_out_mplane = risp_io_input_s_fmt, + .vidioc_try_fmt_vid_out_mplane = risp_io_input_try_fmt, + .vidioc_enum_framesizes = risp_io_input_enum_framesizes, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * Parameters + * + */ + +static int risp_io_params_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf = risp_io_vb2buf(vbuf); + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + struct rcar_isp_core *core = io->core; + size_t size; + int ret; + + memset(&buf->vsp_buffer, 0, sizeof(buf->vsp_buffer)); + + size = RISP_IO_PARAMS_BUF_SIZE; + ret = vsp1_isp_alloc_buffer(core->vspx.dev, size, &buf->vsp_buffer); + if (ret) + return -EINVAL; + + memset(buf->vsp_buffer.cpu_addr, 0, RISP_IO_PARAMS_BUF_SIZE); + + return 0; +} + +static void risp_io_params_buf_cleanup(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf = risp_io_vb2buf(vbuf); + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + struct rcar_isp_core *core = io->core; + + vsp1_isp_free_buffer(core->vspx.dev, &buf->vsp_buffer); +} + +struct risp_conf_dma_write_desc { + u32 *buf; + u32 base; + unsigned int count; +}; + +static int risp_conf_dma_prepare(void *priv, u32 offset, u32 value) +{ + struct risp_conf_dma_write_desc *desc = priv; + + /* Bounds check, 8 bytes = address (4)+ value (4). */ + if ((desc->count + 1) * 8 > RISP_IO_PARAMS_BUF_SIZE) + return -ENOMEM; + + (*desc->buf++) = desc->base | offset; + (*desc->buf++) = value; + + desc->count++; + + return 0; +} + +static int risp_io_params_buffer_prepare(struct vb2_buffer *vb) +{ + struct rcar_isp_core_io *io = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct risp_buffer *buf = risp_io_vb2buf(vbuf); + struct risp_conf_dma_write_desc desc; + u32 *cpu_addr; + int ret; + + /* Prepare params. */ + cpu_addr = (u32 *)buf->vsp_buffer.cpu_addr; + + desc.buf = cpu_addr + 2; + desc.base = io->core->rppaddr; + desc.count = 0; + + /* Fill params body. */ + ret = rppx1_params(io->core->rpp, vb, io->format.fmt.meta.buffersize, + risp_conf_dma_prepare, &desc); + if (ret) + return ret; + + /* Fill params header. */ + cpu_addr[0] = desc.count; + cpu_addr[1] = 0x0; + + return 0; +} + +static const struct vb2_ops risp_io_params_qops = { + .queue_setup = risp_io_queue_setup, + .buf_init = risp_io_params_buf_init, + .buf_cleanup = risp_io_params_buf_cleanup, + .buf_prepare = risp_io_params_buffer_prepare, + .buf_queue = risp_io_buffer_queue, + .start_streaming = risp_io_start_streaming, + .stop_streaming = risp_io_stop_streaming, +}; + +static const struct v4l2_meta_format risp_io_params_default_format = { + .dataformat = V4L2_META_FMT_RPPX1_PARAMS, + .buffersize = v4l2_isp_buffer_size(RPPX1_PARAMS_MAX_SIZE), +}; + +static int risp_io_params_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (f->type != V4L2_BUF_TYPE_META_OUTPUT || f->index) + return -EINVAL; + + f->pixelformat = io->format.fmt.meta.dataformat; + + return 0; +} + +static int risp_io_params_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (f->type != V4L2_BUF_TYPE_META_OUTPUT) + return -EINVAL; + + *meta = io->format.fmt.meta; + + return 0; +} + +static int risp_io_params_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + return risp_io_params_g_fmt(file, priv, f); +} + +static const struct v4l2_ioctl_ops risp_io_params_ioctl_ops = { + .vidioc_querycap = risp_io_querycap, + + .vidioc_enum_fmt_meta_out = risp_io_params_enum_fmt, + .vidioc_g_fmt_meta_out = risp_io_params_g_fmt, + .vidioc_s_fmt_meta_out = risp_io_params_s_fmt, + .vidioc_try_fmt_meta_out = risp_io_params_g_fmt, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * Statistics + */ + +static const struct vb2_ops risp_io_stats_qops = { + .queue_setup = risp_io_queue_setup, + .buf_prepare = risp_io_buffer_prepare, + .buf_queue = risp_io_buffer_queue, + .start_streaming = risp_io_start_streaming, + .stop_streaming = risp_io_stop_streaming, +}; + +static const struct v4l2_meta_format risp_io_stats_default_format = { + .dataformat = V4L2_META_FMT_RPPX1_STATS, + .buffersize = v4l2_isp_buffer_size(RPPX1_STATS_MAX_SIZE), +}; + +static int risp_io_stats_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (f->type != V4L2_BUF_TYPE_META_CAPTURE || f->index) + return -EINVAL; + + f->pixelformat = io->format.fmt.meta.dataformat; + + return 0; +} + +static int risp_io_stats_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (f->type != V4L2_BUF_TYPE_META_CAPTURE) + return -EINVAL; + + *meta = io->format.fmt.meta; + + return 0; +} + +static int risp_io_stats_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + return risp_io_stats_g_fmt(file, priv, f); +} + +static const struct v4l2_ioctl_ops risp_io_stats_ioctl_ops = { + .vidioc_querycap = risp_io_querycap, + + .vidioc_enum_fmt_meta_cap = risp_io_stats_enum_fmt, + .vidioc_g_fmt_meta_cap = risp_io_stats_g_fmt, + .vidioc_s_fmt_meta_cap = risp_io_stats_s_fmt, + .vidioc_try_fmt_meta_cap = risp_io_stats_g_fmt, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * Video capture + */ + +static const struct vb2_ops risp_io_capture_qops = { + .queue_setup = risp_io_queue_setup, + .buf_prepare = risp_io_buffer_prepare, + .buf_queue = risp_io_buffer_queue, + .start_streaming = risp_io_start_streaming, + .stop_streaming = risp_io_stop_streaming, +}; + +static const struct v4l2_pix_format_mplane risp_io_capture_default_format = { + .width = 1920, + .height = 1080, + .pixelformat = V4L2_PIX_FMT_XBGR32, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + .num_planes = 1, + .plane_fmt = { + [0] = { + .bytesperline = ALIGN(1920 * 4, 256), + .sizeimage = ALIGN(1920 * 4, 256) * 1080, + }, + }, +}; + +static void risp_io_capture_try_format(struct rcar_isp_core_io *io, + struct v4l2_pix_format_mplane *pix) +{ + v4l_bound_align_image(&pix->width, 128, 5120, 2, + &pix->height, 128, 4096, 2, 0); + + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_SRGB; + pix->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix->xfer_func = V4L2_XFER_FUNC_SRGB; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV16M: + pix->quantization = V4L2_QUANTIZATION_LIM_RANGE; + pix->num_planes = 2; + pix->plane_fmt[0].bytesperline = ALIGN(pix->width, 256); + pix->plane_fmt[0].sizeimage = pix->plane_fmt[0].bytesperline * pix->height; + pix->plane_fmt[1].bytesperline = ALIGN(pix->width, 256); + pix->plane_fmt[1].sizeimage = pix->plane_fmt[1].bytesperline * pix->height; + break; + default: + pix->pixelformat = V4L2_PIX_FMT_XBGR32; + pix->quantization = V4L2_QUANTIZATION_FULL_RANGE; + pix->num_planes = 1; + pix->plane_fmt[0].bytesperline = ALIGN(pix->width * 4, 256); + pix->plane_fmt[0].sizeimage = pix->plane_fmt[0].bytesperline * pix->height; + break; + } +} + +static int risp_io_capture_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + switch (f->index) { + case 0: + f->pixelformat = V4L2_PIX_FMT_NV16M; + break; + case 1: + f->pixelformat = V4L2_PIX_FMT_XBGR32; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int risp_io_capture_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + f->fmt.pix_mp = io->format.fmt.pix_mp; + + return 0; +} + +static int risp_io_capture_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + if (vb2_is_busy(&io->queue)) + return -EBUSY; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + risp_io_capture_try_format(io, &f->fmt.pix_mp); + + io->format.fmt.pix_mp = f->fmt.pix_mp; + + return 0; +} + +static int risp_io_capture_try_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct rcar_isp_core_io *io = video_drvdata(file); + + risp_io_capture_try_format(io, &f->fmt.pix_mp); + + return 0; +} + +static int risp_io_capture_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index != 0) + return -EINVAL; + + switch (fsize->pixel_format) { + case V4L2_PIX_FMT_NV16M: + case V4L2_PIX_FMT_XBGR32: + break; + default: + return -EINVAL; + } + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + + fsize->stepwise.min_width = 128; + fsize->stepwise.max_width = 5120; + fsize->stepwise.step_width = 2; + + fsize->stepwise.min_height = 128; + fsize->stepwise.max_height = 4096; + fsize->stepwise.step_height = 2; + + return 0; +} + +static const struct v4l2_ioctl_ops risp_io_capture_ioctl_ops = { + .vidioc_querycap = risp_io_querycap, + + .vidioc_enum_fmt_vid_cap = risp_io_capture_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane = risp_io_capture_g_fmt, + .vidioc_s_fmt_vid_cap_mplane = risp_io_capture_s_fmt, + .vidioc_try_fmt_vid_cap_mplane = risp_io_capture_try_fmt, + .vidioc_enum_framesizes = risp_io_capture_enum_framesizes, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +/* ----------------------------------------------------------------------------- + * Create and remove IO video devices + */ + +int risp_core_io_create(struct device *dev, struct rcar_isp_core *core, + struct rcar_isp_core_io *io, unsigned int pad) +{ + struct video_device *vdev = &io->vdev; + struct vb2_queue *q = &io->queue; + int ret; + + switch (pad) { + case RISP_CORE_INPUT1: + snprintf(vdev->name, sizeof(vdev->name), "%s %s input1", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir = VFL_DIR_TX; + vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE; + vdev->ioctl_ops = &risp_io_input_ioctl_ops; + + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + q->ops = &risp_io_input_qops; + + io->pad.flags = MEDIA_PAD_FL_SOURCE; + io->format.fmt.pix_mp = risp_io_input_default_format; + break; + + case RISP_CORE_PARAMS: + snprintf(vdev->name, sizeof(vdev->name), "%s %s params", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir = VFL_DIR_TX; + vdev->device_caps = V4L2_CAP_META_OUTPUT; + vdev->ioctl_ops = &risp_io_params_ioctl_ops; + + q->type = V4L2_BUF_TYPE_META_OUTPUT; + q->ops = &risp_io_params_qops; + + io->pad.flags = MEDIA_PAD_FL_SOURCE; + io->format.fmt.meta = risp_io_params_default_format; + break; + + case RISP_CORE_STATS: + snprintf(vdev->name, sizeof(vdev->name), "%s %s stats", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir = VFL_DIR_RX; + vdev->device_caps = V4L2_CAP_META_CAPTURE; + vdev->ioctl_ops = &risp_io_stats_ioctl_ops; + + q->type = V4L2_BUF_TYPE_META_CAPTURE; + q->ops = &risp_io_stats_qops; + + io->pad.flags = MEDIA_PAD_FL_SINK; + io->format.fmt.meta = risp_io_stats_default_format; + break; + + case RISP_CORE_OUTPUT1: + snprintf(vdev->name, sizeof(vdev->name), "%s %s output1", + KBUILD_MODNAME, dev_name(dev)); + vdev->vfl_dir = VFL_DIR_RX; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE; + vdev->ioctl_ops = &risp_io_capture_ioctl_ops; + + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->ops = &risp_io_capture_qops; + + io->pad.flags = MEDIA_PAD_FL_SINK; + io->format.fmt.pix_mp = risp_io_capture_default_format; + break; + } + + io->core = core; + + mutex_init(&io->lock); + INIT_LIST_HEAD(&io->buffers); + + /* Create media graph pad. */ + ret = media_entity_pads_init(&io->vdev.entity, 1, &io->pad); + if (ret) + return ret; + + /* Create queue */ + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->lock = &io->lock; + q->drv_priv = io; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct risp_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->dev = dev; + + ret = vb2_queue_init(q); + if (ret < 0) { + risp_io_err(io, "Failed to initialize VB2 queue\n"); + return ret; + } + + /* Create video device */ + vdev->v4l2_dev = &core->v4l2_dev; + vdev->queue = &io->queue; + + vdev->release = video_device_release_empty; + vdev->lock = &io->lock; + vdev->fops = &risp_io_fops; + + vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_IO_MC; + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + risp_io_err(io, "Failed to register video device\n"); + return ret; + } + + video_set_drvdata(&io->vdev, io); + + v4l2_info(&core->v4l2_dev, "Device registered as %s\n", + video_device_node_name(vdev)); + + switch (pad) { + case RISP_CORE_INPUT1: + case RISP_CORE_PARAMS: + ret = media_create_pad_link(&io->vdev.entity, 0, + &core->subdev.entity, pad, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + break; + case RISP_CORE_STATS: + case RISP_CORE_OUTPUT1: + ret = media_create_pad_link(&core->subdev.entity, pad, + &io->vdev.entity, 0, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + break; + } + + return ret; +} + +void risp_core_io_destroy(struct rcar_isp_core_io *io) +{ + if (!video_is_registered(&io->vdev)) + return; + + vb2_video_unregister_device(&io->vdev); +} diff --git a/drivers/media/platform/renesas/rcar-isp/core.c b/drivers/media/platform/renesas/rcar-isp/core.c new file mode 100644 index 000000000000..b5861d0cd0e8 --- /dev/null +++ b/drivers/media/platform/renesas/rcar-isp/core.c @@ -0,0 +1,916 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#include <linux/delay.h> +#include <linux/of_platform.h> +#include <linux/pm_runtime.h> + +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-dma-contig.h> +#include <media/vsp1.h> + +#include "risp-core.h" + +#define ISP_CS_STREAMER_MODE_REG 0x7000 +#define ISP_CS_STREAMER_MODE_STREAMER_EN 0xf + +#define ISP_CS_STREAMER_VBLANK_REG 0x7004 +#define ISP_CS_STREAMER_HBLANK_REG 0x7008 + +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL_REG 0x7100 +#define ISP_CS_STREAMER_CONFIG_DMA_REG_ADDRESS_UPPER_8BIT_MASK GENMASK(31, 24) +#define ISP_CS_STREAMER_CONFIG_DMA_ENABLE0 BIT(0) + +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_REG 0x2100 +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_ENABLE1 BIT(31) +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_CONFIG_DATA_START_REG_ADDRESS_MASK GENMASK(15, 0) + +#define ISP_CS_STREAMER_CONFIG_DMA_CONTROL2_REG 0x2104 + +#define ISP_CORE_ISPCORE_INT_STATUS 0x80000 +#define ISP_CORE_ISPCORE_INT_ENABLE 0x80004 +#define ISPCORE_DMA_IMAGE_FRAME_MODE(i, f) (0x84000 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_PIXEL_POSITION(i, f) (0x84004 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_PIXEL_BITWIDTH_MINUS1(i, f) (0x84008 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_PIXEL_BPP(i, f) (0x8400c + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP0(i, f) (0x84010 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP1(i, f) (0x84014 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP2(i, f) (0x84018 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP3(i, f) (0x8401c + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP0(i, f) (0x84020 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP1(i, f) (0x84024 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP2(i, f) (0x84028 + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP3(i, f) (0x8402c + 0x1000 * (i) + 0x100 * (f)) +#define ISPCORE_DMA_IMAGE_FRAME_AXI_ID(i, f) (0x84030 + 0x1000 * (i) + 0x100 * (f)) + +#define ISPCORE_DMA_IMAGE_FLUSH_OUT_REG(i) (0x84400 + 0x1000 * (i)) +#define ISPCORE_DMA_IMAGE_FLUSH_OUT_PADDING_PIXEL_EOF_MASK GENMASK(31, 16) +#define ISPCORE_DMA_IMAGE_FLUSH_OUT_PADDING_PIXEL_EOF_SHIFT 16 + +#define ISPCORE_DMA_IMAGE_AXI_CONFIG_REG(i) (0x84800 + 0x1000 * (i)) + +static void risp_cs_write(struct rcar_isp_core *core, u32 offset, u32 value) +{ + iowrite32(value, core->csbase + offset); +} + +static u32 risp_cs_read(struct rcar_isp_core *core, u32 offset) +{ + return ioread32(core->csbase + offset); +} + +static void risp_core_write(struct rcar_isp_core *core, u32 offset, u32 value) +{ + iowrite32(value, core->base + offset); +} + +static u32 risp_core_read(struct rcar_isp_core *core, u32 offset) +{ + return ioread32(core->base + offset); +} + +static void risp_core_job_run_params(struct rcar_isp_core *core, + struct vsp1_isp_job_desc *vspx_job, + struct risp_buffer *buf) +{ + u32 *params_buf = (u32 *)buf->vsp_buffer.cpu_addr; + bool have_config = !!params_buf[0]; + u32 ctrl0, ctrl1, ctrl2; + + /* + * If we have a configuration but not asked the VSPX to program it, + * use MMIO to write the configuration. This might be needed to work + * around limitations of the VSPX ConfigDMA, see comment in + * risp_core_job_prepare(). + */ + if (have_config && !vspx_job->config.pairs) { + for (unsigned int i = 0; i < params_buf[0]; i++) + risp_core_write(core, params_buf[2 + i * 2] & 0xffff, + params_buf[3 + i * 2]); + + /* Disable ConfigDMA. */ + have_config = false; + } + + ctrl0 = risp_cs_read(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL_REG) & + ~ISP_CS_STREAMER_CONFIG_DMA_ENABLE0; + ctrl1 = risp_cs_read(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_REG) & + ~(ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_ENABLE1 | 0xffff); + ctrl2 = 0; + + if (have_config) { + ctrl0 |= ISP_CS_STREAMER_CONFIG_DMA_ENABLE0; + ctrl1 |= ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_ENABLE1 | + (params_buf[2] & 0xffff); + ctrl2 = params_buf[3]; + } + + risp_cs_write(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL_REG, ctrl0); + risp_cs_write(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL1_REG, ctrl1); + risp_cs_write(core, ISP_CS_STREAMER_CONFIG_DMA_CONTROL2_REG, ctrl2); +} + +static void risp_core_job_run_output(struct rcar_isp_core *core, + struct risp_buffer *buf) +{ + const struct v4l2_format *fmt = &core->io[RISP_CORE_OUTPUT1].format; + dma_addr_t mem; + u32 reg; + + for (unsigned int frame = 0; frame < 4; frame++) { + reg = ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP0(0, frame); + mem = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + risp_core_write(core, reg, mem); + + /* Only NV16 uses 2 planes. */ + if (fmt->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_NV16M) + continue; + + reg = ISPCORE_DMA_IMAGE_FRAME_BASE_ADDRESS_COMP1(0, frame); + mem = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1); + risp_core_write(core, reg, mem); + } +} + +static void risp_core_job_run(struct rcar_isp_core *core) +{ + struct rcar_isp_job *job; + + lockdep_assert_held(&core->lock); + + /* ISP not yet started, nothing to do. */ + if (!core->streaming) + return; + + /* If we have active buffers in the ISP core, nothing to do. */ + if (core->vspx.job) + return; + + job = list_first_entry_or_null(&core->risp_jobs, + struct rcar_isp_job, + job_queue); + if (!job) + return; + + list_del(&job->job_queue); + + core->vspx.job = job; + + /* Program the ISP register before kicking the VSPX. */ + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf = job->buffers[i]; + + switch (i) { + case RISP_CORE_PARAMS: + risp_core_job_run_params(core, &job->vspx_job, buf); + break; + case RISP_CORE_OUTPUT1: + risp_core_job_run_output(core, buf); + break; + } + } + + if (vsp1_isp_job_run(core->vspx.dev, &job->vspx_job)) { + /* + * Release all buffers in this job if running on the VSPX + * failed. Userspace should recover from this, no new jobs are + * scheduled. + */ + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf = job->buffers[i]; + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + + vsp1_isp_job_release(core->vspx.dev, &job->vspx_job); + core->vspx.job = NULL; + kfree(job); + + dev_err(core->dev, "Failed to run job"); + } +} + +static int risp_core_pixfmt_to_vspx(u32 pixfmt) +{ + switch (pixfmt) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return V4L2_PIX_FMT_GREY; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + return V4L2_PIX_FMT_Y10; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + return V4L2_PIX_FMT_Y12; + default: + return -EINVAL; + } +} + +int risp_core_job_prepare(struct rcar_isp_core *core) +{ + struct vsp1_isp_job_desc *vspx_job; + int vspx_pixfmt = -EINVAL; + struct rcar_isp_job *job; + int ret; + + lockdep_assert_held(&core->io_lock); + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + if (list_empty(&core->io[i].buffers)) + return 0; + } + + /* Memory is released when the job is consumed. */ + job = kzalloc(sizeof(*job), GFP_KERNEL); + if (!job) + return -ENOMEM; + + vspx_job = &job->vspx_job; + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf; + + /* + * Extract buffer from the IO queue and save a reference in + * the job description. Buffers will be completed when the + * corresponding frame will be completed by the ISP. + */ + buf = list_first_entry_or_null(&core->io[i].buffers, + struct risp_buffer, list); + /* + * This should not happen as we have checked there is buffers, + * with the lock held, but check the return value anyhow. + */ + if (WARN_ON(!buf)) { + ret = -EINVAL; + goto error_return_buffers; + } + + switch (i) { + case RISP_CORE_INPUT1: { + u32 isp_pixfmt = core->io[i].format.fmt.pix_mp.pixelformat; + + vspx_pixfmt = risp_core_pixfmt_to_vspx(isp_pixfmt); + + vspx_job->img.fmt = core->io[i].format.fmt.pix_mp; + vspx_job->img.fmt.pixelformat = vspx_pixfmt; + vspx_job->img.mem = + vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, + 0); + break; + } + case RISP_CORE_PARAMS: { + u32 *params_buf = (u32 *)buf->vsp_buffer.cpu_addr; + u32 pairs = params_buf[0]; + + /* + * Check config pairs not larger then buffer. + * + * Remove 8 byte header and each pair is 16 bytes. + */ + if (pairs > (RISP_IO_PARAMS_BUF_SIZE - 8) / 16) { + ret = -EINVAL; + goto error_return_buffers; + } + + /* + * Work around undocumented behavior of the ConfigDMA + * interface by using MMIO if 16 or less pairs are to + * be programmed. + * + * Programming 15 or less pairs corrupts the image data + * following the config buffer, programming exactly 16 + * pairs freeze the whole VSPX. + */ + if (pairs <= 16) { + vspx_job->config.pairs = 0; + } else { + vspx_job->config.pairs = pairs; + vspx_job->config.mem = buf->vsp_buffer.dma_addr; + } + break; + } + } + + list_del(&buf->list); + job->buffers[i] = buf; + } + + if (vspx_pixfmt < 0) { + ret = -EINVAL; + goto error_return_buffers; + } + + ret = vsp1_isp_job_prepare(core->vspx.dev, vspx_job); + if (ret) + goto error_return_buffers; + + scoped_guard(spinlock_irqsave, &core->lock) { + list_add_tail(&job->job_queue, &core->risp_jobs); + risp_core_job_run(core); + } + + return 0; + +error_return_buffers: + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + if (!job->buffers[i]) + continue; + + vb2_buffer_done(&job->buffers[i]->vb.vb2_buf, + VB2_BUF_STATE_ERROR); + } + kfree(job); + return ret; +} + +static int risp_core_config_output(struct rcar_isp_core *core, + unsigned int index, + const struct v4l2_pix_format_mplane *pix) +{ + /* For all frame capture slots. */ + for (unsigned int frame = 0; frame < 4; frame++) { + switch (pix->pixelformat) { + case V4L2_PIX_FMT_NV16M: + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_MODE(index, frame), + 1); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_POSITION(index, frame), + 0 << 24 | 0 << 16 | 4 << 8 | 16 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BITWIDTH_MINUS1(index, frame), + 0 << 24 | 0 << 16 | 7 << 8 | 7 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BPP(index, frame), + 0 << 28 | 0 << 24 | + 0 << 20 | 0 << 16 | + 3 << 12 | 0 << 8 | + 3 << 4 | 0 << 0); + + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP0(index, frame), + pix->plane_fmt[0].bytesperline); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP1(index, frame), + pix->plane_fmt[1].bytesperline); + break; + case V4L2_PIX_FMT_XBGR32: + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_MODE(index, frame), + 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_POSITION(index, frame), + 0 << 24 | 0 << 16 | 0 << 8 | 0 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BITWIDTH_MINUS1(index, frame), + 0 << 24 | 0 << 16 | 0 << 8 | 23 << 0); + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_PIXEL_BPP(index, frame), + 0 << 28 | 0 << 24 | + 0 << 20 | 0 << 16 | + 0 << 12 | 0 << 8 | + 3 << 4 | 2 << 0); + + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_STRIDE_COMP0(index, frame), + pix->plane_fmt[0].bytesperline); + break; + default: + return -EINVAL; + } + + risp_core_write(core, + ISPCORE_DMA_IMAGE_FRAME_AXI_ID(index, frame), + 0); + } + + /* Set image out flush EOF. */ + risp_core_write(core, ISPCORE_DMA_IMAGE_FLUSH_OUT_REG(index), + pix->plane_fmt[0].bytesperline << + ISPCORE_DMA_IMAGE_FLUSH_OUT_PADDING_PIXEL_EOF_SHIFT); + + /* Enable DMA and set burst length. */ + risp_core_write(core, ISPCORE_DMA_IMAGE_AXI_CONFIG_REG(index), + BIT(31) | 7); + + return 0; +} + +static u32 risp_core_pix2bus(const struct rcar_isp_core_io *io) +{ + switch (io->format.fmt.pix_mp.pixelformat) { + case V4L2_PIX_FMT_SBGGR8: + return MEDIA_BUS_FMT_SBGGR8_1X8; + case V4L2_PIX_FMT_SGBRG8: + return MEDIA_BUS_FMT_SGBRG8_1X8; + case V4L2_PIX_FMT_SGRBG8: + return MEDIA_BUS_FMT_SGRBG8_1X8; + case V4L2_PIX_FMT_SRGGB8: + return MEDIA_BUS_FMT_SRGGB8_1X8; + case V4L2_PIX_FMT_SBGGR10: + return MEDIA_BUS_FMT_SBGGR10_1X10; + case V4L2_PIX_FMT_SGBRG10: + return MEDIA_BUS_FMT_SGBRG10_1X10; + case V4L2_PIX_FMT_SGRBG10: + return MEDIA_BUS_FMT_SGRBG10_1X10; + case V4L2_PIX_FMT_SRGGB10: + return MEDIA_BUS_FMT_SRGGB10_1X10; + case V4L2_PIX_FMT_SBGGR12: + return MEDIA_BUS_FMT_SBGGR12_1X12; + case V4L2_PIX_FMT_SGBRG12: + return MEDIA_BUS_FMT_SGBRG12_1X12; + case V4L2_PIX_FMT_SGRBG12: + return MEDIA_BUS_FMT_SGRBG12_1X12; + case V4L2_PIX_FMT_SRGGB12: + return MEDIA_BUS_FMT_SRGGB12_1X12; + case V4L2_PIX_FMT_XBGR32: + return MEDIA_BUS_FMT_RGB888_1X24; + case V4L2_PIX_FMT_NV16M: + return MEDIA_BUS_FMT_YUYV12_1X24; + default: + return 0; + } +} + +static void risp_core_try_next_job(struct rcar_isp_core *core) +{ + lockdep_assert_held(&core->lock); + + struct rcar_isp_job *job = core->vspx.job; + + /* If the ISP or the VSPX is not done with the job, wait. */ + if (!job || !job->done_isp || !job->done_vspx) + return; + + core->vspx.job = NULL; + kfree(job); + + core->sequence++; + + /* Kickoff processing of next frame (if any). */ + risp_core_job_run(core); +} + +static void risp_core_vspx_frame_end(void *data) +{ + struct rcar_isp_core *core = data; + + guard(spinlock_irqsave)(&core->lock); + + /* + * In tear-down the ISP may report a frame end event but we have already + * freed the job. It is safe to ignore the end of frame event. + */ + if (!core->vspx.job) + return; + + core->vspx.job->done_vspx = true; + risp_core_try_next_job(core); +} + +static int risp_core_power_on(struct rcar_isp_core *core) +{ + int ret; + + ret = pm_runtime_resume_and_get(core->dev); + if (ret < 0) + return ret; + + ret = reset_control_deassert(core->csrstc); + if (ret) + goto err_pm; + + ret = clk_prepare_enable(core->clk); + if (ret) + goto err_csrstc; + + return 0; + +err_csrstc: + reset_control_assert(core->csrstc); +err_pm: + pm_runtime_put(core->dev); + + return ret; +} + +static void risp_core_power_off(struct rcar_isp_core *core) +{ + clk_disable_unprepare(core->clk); + + reset_control_assert(core->csrstc); + + pm_runtime_put(core->dev); +} + +int risp_core_start_streaming(struct rcar_isp_core *core) +{ + struct vsp1_vspx_frame_end vspx_fe = { + .vspx_frame_end = risp_core_vspx_frame_end, + .frame_end_data = core, + }; + + struct v4l2_mbus_framefmt inputfmt = { + .width = core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.width, + .height = core->io[RISP_CORE_INPUT1].format.fmt.pix_mp.height, + .code = risp_core_pix2bus(&core->io[RISP_CORE_INPUT1]), + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_RAW, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = V4L2_QUANTIZATION_FULL_RANGE, + .xfer_func = V4L2_XFER_FUNC_NONE, + }; + + struct v4l2_mbus_framefmt hvout = { + .width = core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.width, + .height = core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.height, + .code = risp_core_pix2bus(&core->io[RISP_CORE_OUTPUT1]), + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .ycbcr_enc = V4L2_YCBCR_ENC_601, + .quantization = + core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_XBGR32 ? + V4L2_QUANTIZATION_FULL_RANGE : + V4L2_QUANTIZATION_LIM_RANGE, + .xfer_func = V4L2_XFER_FUNC_SRGB, + }; + int ret; + + scoped_guard(mutex, &core->io_lock) { + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + if (!core->io[i].streaming) + return 0; + } + + /* + * The state core->streaming is protected by core->lock, which + * is not held yet. It is however safe to read it here since + * core->io_lock is held both in risp_core_stop_streaming() and + * here, the only two places the variable is modified. + * + * With this small implied dependency on the two locks for write + * access, the interrupt handler can safely depend sole on the + * spinlock core->lock for read access to core->streaming. + * + * The gain is an interrupt handler which can hold the spinlock + * and a start/stop procedure which can reset the ISP using the + * reset_control_reset() API, The later which can not be called + * from a context that may sleep. + * + * All other locations core->streaming is read and _all_ + * locations where it is written core->lock is held. + */ + if (core->streaming) + return 0; + + ret = risp_core_power_on(core); + if (ret) + return ret; + + /* Reset and wait for ISP core to initialize itself. */ + reset_control_reset(core->rstc); + usleep_range(2000, 4000); + + scoped_guard(spinlock_irqsave, &core->lock) { + risp_core_write(core, ISP_CORE_ISPCORE_INT_ENABLE, 1); + + /* Configure output DMA */ + risp_core_config_output(core, 0, + &core->io[RISP_CORE_OUTPUT1].format.fmt.pix_mp); + + risp_cs_write(core, ISP_CS_STREAMER_VBLANK_REG, inputfmt.width * 25); + risp_cs_write(core, ISP_CS_STREAMER_HBLANK_REG, 64); + + /* Enable ISP Streaming bridge. */ + risp_cs_write(core, ISP_CS_STREAMER_MODE_REG, + ISP_CS_STREAMER_MODE_STREAMER_EN); + + /* Start RPP ISP */ + ret = rppx1_start(core->rpp, &inputfmt, &hvout, NULL); + if (ret) { + risp_core_power_off(core); + return ret; + } + + core->vspx.job = NULL; + core->sequence = 0; + core->streaming = true; + } + + /* Start VSPX */ + vsp1_isp_start_streaming(core->vspx.dev, &vspx_fe); + + scoped_guard(spinlock_irqsave, &core->lock) { + risp_core_job_run(core); + } + } + + return 0; +} + +void risp_core_stop_streaming(struct rcar_isp_core *core) +{ + struct rcar_isp_job *job, *tmp; + + /* + * This function releases buffers and jobs: make sure the queues mutex + * is held. + */ + lockdep_assert_held(&core->io_lock); + + scoped_guard(spinlock_irqsave, &core->lock) { + /* Stop is called by each vdev, only act on the first call. */ + if (!core->streaming) + return; + + /* Stop queueing jobs to VSPX. */ + core->streaming = false; + } + + /* Wait for active VSPX job to finish. */ + for (unsigned int retry = 0; retry <= 10; retry++) { + if (!core->vspx.job) + break; + + usleep_range(2000, 4000); + } + + if (core->vspx.job) + dev_err(core->dev, "Failed to complete running job"); + + /* Free all buffers and switch off the hardware. */ + scoped_guard(spinlock_irqsave, &core->lock) { + /* Free all jobs and buffers. */ + list_for_each_entry_safe(job, tmp, &core->risp_jobs, job_queue) { + vsp1_isp_job_release(core->vspx.dev, &job->vspx_job); + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf = job->buffers[i]; + + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + + list_del(&job->job_queue); + kfree(job); + } + + rppx1_stop(core->rpp); + risp_cs_write(core, ISP_CS_STREAMER_MODE_REG, 0); + risp_core_write(core, ISP_CORE_ISPCORE_INT_ENABLE, 0); + } + + vsp1_isp_stop_streaming(core->vspx.dev); + + risp_core_power_off(core); +} + +static irqreturn_t risp_core_irq(int irq, void *data) +{ + struct rcar_isp_core *core = data; + struct rcar_isp_job *job; + u32 status; + + status = risp_core_read(core, ISP_CORE_ISPCORE_INT_STATUS); + if (!(status & BIT(0))) + return IRQ_NONE; + + if (!rppx1_interrupt(core->rpp, &status)) + return IRQ_HANDLED; + + guard(spinlock_irqsave)(&core->lock); + + job = core->vspx.job; + if (!job) + return IRQ_HANDLED; + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + struct risp_buffer *buf; + + buf = job->buffers[i]; + + switch (i) { + case RISP_CORE_STATS: + rppx1_stats_fill_isr(core->rpp, status, + vb2_plane_vaddr(&buf->vb.vb2_buf, 0)); + fallthrough; + case RISP_CORE_OUTPUT1: + case RISP_CORE_INPUT1: + buf->vb.sequence = core->sequence; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + fallthrough; + case RISP_CORE_PARAMS: + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + break; + } + } + + core->vspx.job->done_isp = true; + risp_core_try_next_job(core); + + return IRQ_HANDLED; +} + +static const struct v4l2_subdev_ops risp_core_subdev_ops = { +}; + +static int risp_core_create_subdev(struct rcar_isp_core *core) +{ + struct v4l2_subdev *subdev = &core->subdev; + int ret; + + subdev->owner = THIS_MODULE; + subdev->dev = core->dev; + v4l2_subdev_init(subdev, &risp_core_subdev_ops); + v4l2_set_subdevdata(subdev, core->dev); + snprintf(subdev->name, sizeof(subdev->name), "%s %s core", + KBUILD_MODNAME, dev_name(core->dev)); + subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + + subdev->entity.function = MEDIA_ENT_F_VID_MUX; + + core->pads[RISP_CORE_INPUT1].flags = MEDIA_PAD_FL_SINK; + core->pads[RISP_CORE_PARAMS].flags = MEDIA_PAD_FL_SINK; + core->pads[RISP_CORE_STATS].flags = MEDIA_PAD_FL_SOURCE; + core->pads[RISP_CORE_OUTPUT1].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&subdev->entity, RISP_CORE_NUM_PADS, + core->pads); + if (ret) + return ret; + + return 0; +} + +int risp_core_registered(struct rcar_isp_core *core, struct v4l2_subdev *sd) +{ + int ret; + + core->v4l2_dev.mdev = sd->v4l2_dev->mdev; + + /* Register ISP Core subdevice. */ + ret = v4l2_device_register_subdev(&core->v4l2_dev, &core->subdev); + if (ret) + return ret; + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) { + ret = risp_core_io_create(core->dev, core, &core->io[i], i); + if (ret) { + /* It is safe to destroy io node that is not created. */ + for (unsigned int n = 0; n < RISP_CORE_NUM_PADS; n++) + risp_core_io_destroy(&core->io[n]); + + v4l2_device_unregister_subdev(&core->subdev); + + return ret; + } + } + + return 0; +} + +static int risp_core_probe_resources(struct rcar_isp_core *core, + struct platform_device *pdev) +{ + struct platform_device *vspx; + struct device_node *of_vspx; + struct resource *res; + int ret; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); + if (!res) + return -ENODEV; + + core->rppaddr = res->start; + core->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(core->base)) + return PTR_ERR(core->base); + + ret = platform_get_irq_byname(pdev, "core"); + if (ret < 0) + return -ENODEV; + + ret = devm_request_irq(&pdev->dev, ret, risp_core_irq, IRQF_SHARED, + KBUILD_MODNAME, core); + if (ret) + return ret; + + core->clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(core->clk)) + return -ENODEV; + + core->rstc = devm_reset_control_get(&pdev->dev, "core"); + if (IS_ERR(core->rstc)) + return -ENODEV; + + of_vspx = of_parse_phandle(pdev->dev.of_node, "renesas,vspx", 0); + if (!of_vspx) + return -ENODEV; + + vspx = of_find_device_by_node(of_vspx); + of_node_put(of_vspx); + if (!vspx) + return -ENODEV; + + /* Attach to VSP-X */ + core->vspx.dev = &vspx->dev; + + ret = vsp1_isp_init(&vspx->dev); + if (ret < 0) + goto err_put_vspx; + + /* Attach to the RPP library + * + * 1. Start and wait for the ISP to startup. + * 2. Attach the RPP library and talk with the RPP ISP. + * 3. Turn off ISP. + * 4. Fail if the RPP is unhappy with the hardware. + */ + ret = clk_prepare_enable(core->clk); + if (ret) + goto err_put_vspx; + + usleep_range(2000, 4000); + + core->rpp = rppx1_create(core->base, &pdev->dev); + + clk_disable_unprepare(core->clk); + + if (!core->rpp) { + ret = -ENODEV; + goto err_put_vspx; + } + + return 0; + +err_put_vspx: + put_device(&vspx->dev); + return ret; +} + +int risp_core_probe(struct rcar_isp_core *core, struct platform_device *pdev, + void __iomem *csbase, struct reset_control *csrstc) +{ + int ret; + + core->dev = &pdev->dev; + core->csrstc = csrstc; + core->csbase = csbase; + + ret = risp_core_probe_resources(core, pdev); + if (ret) { + core->base = NULL; + return ret; + } + + ret = v4l2_device_register(core->dev, &core->v4l2_dev); + if (ret) + goto err_destroy_rpp; + + ret = risp_core_create_subdev(core); + if (ret) + goto err_unregister_v4l2; + + mutex_init(&core->io_lock); + spin_lock_init(&core->lock); + INIT_LIST_HEAD(&core->risp_jobs); + + return 0; + +err_unregister_v4l2: + v4l2_device_unregister(&core->v4l2_dev); +err_destroy_rpp: + rppx1_destroy(core->rpp); + put_device(core->vspx.dev); + return ret; +} + +void risp_core_remove(struct rcar_isp_core *core) +{ + /* If we did not probe the ISP core, nothing to do. */ + if (!core->base) + return; + + dev_info(core->dev, "Remove ISP Core\n"); + + for (unsigned int i = 0; i < RISP_CORE_NUM_PADS; i++) + risp_core_io_destroy(&core->io[i]); + + v4l2_device_unregister(&core->v4l2_dev); + + mutex_destroy(&core->io_lock); + rppx1_destroy(core->rpp); + put_device(core->vspx.dev); +} diff --git a/drivers/media/platform/renesas/rcar-isp/csisp.c b/drivers/media/platform/renesas/rcar-isp/csisp.c index 8fb2cc3b5650..53ce47020d17 100644 --- a/drivers/media/platform/renesas/rcar-isp/csisp.c +++ b/drivers/media/platform/renesas/rcar-isp/csisp.c @@ -11,14 +11,13 @@ */ #include <linux/module.h> -#include <linux/mutex.h> #include <linux/of.h> -#include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/reset.h> #include <media/mipi-csi2.h> -#include <media/v4l2-subdev.h> +#include <media/v4l2-async.h> + +#include "risp-core.h" #define ISPINPUTSEL0_REG 0x0008 #define ISPINPUTSEL0_SEL_CSI0 BIT(31) @@ -158,6 +157,7 @@ struct rcar_isp { struct device *dev; void __iomem *csbase; struct reset_control *rstc; + struct rcar_isp_core core; enum rcar_isp_input csi_input; @@ -452,6 +452,21 @@ static int risp_parse_dt(struct rcar_isp *isp) } /* ----------------------------------------------------------------------------- + * ISP Core connection + */ + +static int risp_cs_registered(struct v4l2_subdev *sd) +{ + struct rcar_isp *isp = sd_to_isp(sd); + + return risp_core_registered(&isp->core, sd); +} + +static const struct v4l2_subdev_internal_ops risp_cs_internal_ops = { + .registered = risp_cs_registered, +}; + +/* ----------------------------------------------------------------------------- * Platform Device Driver */ @@ -477,7 +492,7 @@ static int risp_probe_resources(struct rcar_isp *isp, if (IS_ERR(isp->csbase)) return PTR_ERR(isp->csbase); - isp->rstc = devm_reset_control_get(&pdev->dev, NULL); + isp->rstc = devm_reset_control_get_shared(&pdev->dev, NULL); return PTR_ERR_OR_ZERO(isp->rstc); } @@ -541,14 +556,31 @@ static int risp_probe(struct platform_device *pdev) if (ret) goto error_notifier; + ret = risp_core_probe(&isp->core, pdev, isp->csbase, isp->rstc); + switch (ret) { + case 0: + /* The device have an ISP core. */ + isp->subdev.internal_ops = &risp_cs_internal_ops; + break; + case -ENODEV: + /* The device don't have an ISP core, that is OK. */ + ret = 0; + break; + default: + /* Something went wrong registering the ISP core. */ + goto error_subdev; + } + ret = v4l2_async_register_subdev(&isp->subdev); if (ret < 0) - goto error_subdev; + goto error_core; dev_info(isp->dev, "Using CSI-2 input: %u\n", isp->csi_input); return 0; +error_core: + risp_core_remove(&isp->core); error_subdev: v4l2_subdev_cleanup(&isp->subdev); error_notifier: @@ -564,6 +596,8 @@ static void risp_remove(struct platform_device *pdev) { struct rcar_isp *isp = platform_get_drvdata(pdev); + risp_core_remove(&isp->core); + v4l2_async_nf_unregister(&isp->notifier); v4l2_async_nf_cleanup(&isp->notifier); diff --git a/drivers/media/platform/renesas/rcar-isp/risp-core.h b/drivers/media/platform/renesas/rcar-isp/risp-core.h new file mode 100644 index 000000000000..627a762d6b19 --- /dev/null +++ b/drivers/media/platform/renesas/rcar-isp/risp-core.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2026 Renesas Electronics Corp. + * Copyright (C) 2026 Ideas on Board Oy + * Copyright (C) 2026 Ragnatech AB + */ + +#ifndef __RCAR_ISP__ +#define __RCAR_ISP__ + +#include <linux/clk.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/spinlock.h> +#include <linux/videodev2.h> + +#include <media/v4l2-device.h> +#include <media/v4l2-subdev.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include <media/rppx1.h> +#include <media/vsp1.h> + +/* Max 2048 address + value pairs in one VSPX buffer, increase if needed. */ +#define RISP_IO_PARAMS_BUF_SIZE 16384 + +struct rcar_isp_core; + +enum risp_core_pads { + RISP_CORE_INPUT1, + RISP_CORE_PARAMS, + RISP_CORE_STATS, + RISP_CORE_OUTPUT1, + RISP_CORE_NUM_PADS, +}; + +/** + * struct risp_buffer - Describe an IO buffer + * @vb: The VB2 buffer + * @list: List of buffers queued to the IO queue + * @vsp_buffer: Buffer mapped from VSP-X, only used for params IO + */ +struct risp_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; + struct vsp1_isp_buffer_desc vsp_buffer; +}; + +/** + * struct rcar_isp_core_io - Information for a IO video devices + * @core: Backlink to the common ISP core structure + * + * @lock: Protects @vdev, @pad and @queue + open/close fops + * @vdev: V4L2 video device associated with this IO port + * @pad: Media pad for @vdev + * @queue: VB2 buffers queue for $@vdev + * + * @streaming: Flag to indicate if device is streaming, or not + * @buffers: List of buffers queued to the device + * + * @format: The active V4L2 format + */ +struct rcar_isp_core_io { + struct rcar_isp_core *core; + + struct mutex lock; /* See KDoc block. */ + struct video_device vdev; + struct media_pad pad; + struct vb2_queue queue; + + bool streaming; + struct list_head buffers; + + struct v4l2_format format; +}; + +/** + * struct rcar_isp_job - R-Car ISP job description + * + * Both done_isp and done_vspx shall be set before the job can be considered + * completely done. + * + * @buffers: IO buffers that form a job + * @vspx_job: VSPX job description + * @job_queue: list handle + * @done_isp: Flag to indicate the ISP is done with the job + * @done_vspx: Flag to indicate the VSPX is done with the job + */ +struct rcar_isp_job { + struct risp_buffer *buffers[RISP_CORE_NUM_PADS]; + struct vsp1_isp_job_desc vspx_job; + struct list_head job_queue; + bool done_isp; + bool done_vspx; +}; + +/** + * struct rcar_isp_vspx - R-Car ISP job description + * + * @dev: Device reference to VSPX + * @job: Job currently being processed by VSPX + */ +struct rcar_isp_vspx { + struct device *dev; + struct rcar_isp_job *job; +}; + +/** + * struct rcar_isp_core - ISP Core + * @dev: (OF) device + * @rppaddr: Hardware address of the RPP ISP (from OF) + * @clk: The clock for the ISP CORE + * @rstc: The reset for the ISP Core + * @csrstc: The reset for the ISP Channel Selector + * + * @base: MMIO base of the ISP CORE + * @csbase: MMIO base of the ISP CS + * + * @subdev: V4L2 subdevice to represent the ISP CORE + * @pads: Media pad for @subdev + * + * @v4l2_dev: V4L2 device + * @rpp: Handle to the RPP ISP connected to the ISP CORE + * + * @io_lock: Protect io[*].streaming and io[*].buffers + * @io: Array of IO ports to the ISP CORE + * + * @lock: Protects @vspx, @risp_jobs, @sequence and @streaming + * @vspx: Handle to the resources used by VSPX connected to the ISP CORE + * @risp_jobs: Queue of VSPX transfer jobs + * @sequence: V4L2 buffers sequence number + * @streaming: Tracks if the device is streaming + */ +struct rcar_isp_core { + struct device *dev; + + u32 rppaddr; + struct clk *clk; + + struct reset_control *rstc; + struct reset_control *csrstc; + + void __iomem *base; + void __iomem *csbase; + + struct v4l2_subdev subdev; + struct media_pad pads[RISP_CORE_NUM_PADS]; + + struct v4l2_device v4l2_dev; + struct rppx1 *rpp; + + struct mutex io_lock; /* See KDoc block. */ + struct rcar_isp_core_io io[RISP_CORE_NUM_PADS]; + + spinlock_t lock; /* See KDoc block. */ + struct rcar_isp_vspx vspx; + struct list_head risp_jobs; + unsigned int sequence; + bool streaming; +}; + +int risp_core_probe(struct rcar_isp_core *core, struct platform_device *pdev, + void __iomem *csbase, struct reset_control *csrstc); +void risp_core_remove(struct rcar_isp_core *core); +int risp_core_registered(struct rcar_isp_core *core, struct v4l2_subdev *sd); + +int risp_core_job_prepare(struct rcar_isp_core *core); + +int risp_core_start_streaming(struct rcar_isp_core *core); +void risp_core_stop_streaming(struct rcar_isp_core *core); + +int risp_core_io_create(struct device *dev, struct rcar_isp_core *core, + struct rcar_isp_core_io *io, unsigned int pad); +void risp_core_io_destroy(struct rcar_isp_core_io *io); + +#endif diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h index 5bf334e173d2..b426bc7898bf 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h @@ -116,11 +116,9 @@ struct rzg2l_cru_info { * @scratch_phys: physical address of the scratch buffer * * @qlock: protects @queue_buf, @buf_list, @sequence - * @state * @queue_buf: Keeps track of buffers given to HW slot * @buf_list: list of queued buffers * @sequence: V4L2 buffers sequence number - * @state: keeps track of operation state * * @format: active V4L2 pixel format */ diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c index 5185a547461d..91eda5034248 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c @@ -851,6 +851,11 @@ static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru, v4l2_fill_pixfmt(pix, pix->pixelformat, pix->width, pix->height); + if (info->has_stride) { + pix->bytesperline = ALIGN(pix->bytesperline, RZG2L_CRU_STRIDE_ALIGN); + pix->sizeimage = pix->bytesperline * pix->height; + } + dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n", pix->width, pix->height, pix->bytesperline, pix->sizeimage); } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_brx.c b/drivers/media/platform/renesas/vsp1/vsp1_brx.c index 325be30836d7..360a42502947 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_brx.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_brx.c @@ -155,9 +155,7 @@ static int brx_set_format(struct v4l2_subdev *subdev, /* Propagate the format code to all pads. */ if (fmt->pad == BRX_PAD_SINK(0)) { - unsigned int i; - - for (i = 0; i <= brx->entity.source_pad; ++i) { + for (unsigned int i = 0; i <= brx->entity.source_pad; ++i) { format = v4l2_subdev_state_get_format(state, i); format->code = fmt->format.code; } @@ -271,7 +269,6 @@ static void brx_configure_stream(struct vsp1_entity *entity, struct vsp1_brx *brx = to_brx(&entity->subdev); struct v4l2_mbus_framefmt *format; unsigned int flags; - unsigned int i; format = v4l2_subdev_state_get_format(state, brx->entity.source_pad); @@ -315,7 +312,7 @@ static void brx_configure_stream(struct vsp1_entity *entity, VI6_BRU_ROP_CROP(VI6_ROP_NOP) | VI6_BRU_ROP_AROP(VI6_ROP_NOP)); - for (i = 0; i < brx->entity.source_pad; ++i) { + for (unsigned int i = 0; i < brx->entity.source_pad; ++i) { bool premultiplied = false; u32 ctrl = 0; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_clu.c b/drivers/media/platform/renesas/vsp1/vsp1_clu.c index a6e4bcab5101..4b7d07d730da 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_clu.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_clu.c @@ -43,14 +43,13 @@ static inline void vsp1_clu_write(struct vsp1_clu *clu, static int clu_set_table(struct vsp1_clu *clu, struct v4l2_ctrl *ctrl) { struct vsp1_dl_body *dlb; - unsigned int i; dlb = vsp1_dl_body_get(clu->pool); if (!dlb) return -ENOMEM; vsp1_dl_body_write(dlb, VI6_CLU_ADDR, 0); - for (i = 0; i < CLU_SIZE; ++i) + for (unsigned int i = 0; i < CLU_SIZE; ++i) vsp1_dl_body_write(dlb, VI6_CLU_DATA, ctrl->p_new.p_u32[i]); scoped_guard(spinlock_irq, &clu->lock) { diff --git a/drivers/media/platform/renesas/vsp1/vsp1_dl.c b/drivers/media/platform/renesas/vsp1/vsp1_dl.c index 3dc74fed91dc..6430f2ec8b32 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_dl.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_dl.c @@ -257,7 +257,6 @@ vsp1_dl_body_pool_create(struct vsp1_device *vsp1, unsigned int num_bodies, { struct vsp1_dl_body_pool *pool; size_t dlb_size; - unsigned int i; pool = kzalloc_obj(*pool); if (!pool) @@ -291,7 +290,7 @@ vsp1_dl_body_pool_create(struct vsp1_device *vsp1, unsigned int num_bodies, spin_lock_init(&pool->lock); INIT_LIST_HEAD(&pool->free); - for (i = 0; i < num_bodies; ++i) { + for (unsigned int i = 0; i < num_bodies; ++i) { struct vsp1_dl_body *dlb = &pool->bodies[i]; dlb->pool = pool; @@ -426,7 +425,6 @@ vsp1_dl_cmd_pool_create(struct vsp1_device *vsp1, enum vsp1_extcmd_type type, unsigned int num_cmds) { struct vsp1_dl_cmd_pool *pool; - unsigned int i; size_t cmd_size; pool = kzalloc_obj(*pool); @@ -457,7 +455,7 @@ vsp1_dl_cmd_pool_create(struct vsp1_device *vsp1, enum vsp1_extcmd_type type, return NULL; } - for (i = 0; i < num_cmds; ++i) { + for (unsigned int i = 0; i < num_cmds; ++i) { struct vsp1_dl_ext_cmd *cmd = &pool->cmds[i]; size_t cmd_offset = i * cmd_size; /* data_offset must be 16 byte aligned for DMA. */ @@ -1046,7 +1044,6 @@ unsigned int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm) /* Hardware Setup */ void vsp1_dlm_setup(struct vsp1_device *vsp1) { - unsigned int i; u32 ctrl = (256 << VI6_DL_CTRL_AR_WAIT_SHIFT) | VI6_DL_CTRL_DC2 | VI6_DL_CTRL_DC1 | VI6_DL_CTRL_DC0 | VI6_DL_CTRL_DLE; @@ -1054,7 +1051,7 @@ void vsp1_dlm_setup(struct vsp1_device *vsp1) | VI6_DL_EXT_CTRL_DLPRI | VI6_DL_EXT_CTRL_EXT; if (vsp1_feature(vsp1, VSP1_HAS_EXT_DL)) { - for (i = 0; i < vsp1->info->wpf_count; ++i) + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) vsp1_write(vsp1, VI6_DL_EXT_CTRL(i), ext_dl); } @@ -1092,7 +1089,6 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, { struct vsp1_dl_manager *dlm; size_t header_size; - unsigned int i; dlm = devm_kzalloc(vsp1->dev, sizeof(*dlm), GFP_KERNEL); if (!dlm) @@ -1128,7 +1124,7 @@ struct vsp1_dl_manager *vsp1_dlm_create(struct vsp1_device *vsp1, if (!dlm->pool) return NULL; - for (i = 0; i < prealloc; ++i) { + for (unsigned int i = 0; i < prealloc; ++i) { struct vsp1_dl_list *dl; dl = vsp1_dl_list_alloc(dlm); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.c b/drivers/media/platform/renesas/vsp1/vsp1_drm.c index f6fbd3475329..9cd5c025d2be 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drm.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.c @@ -419,13 +419,12 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1, struct vsp1_entity *uif; bool use_uif = false; struct vsp1_brx *brx; - unsigned int i; int ret; /* Count the number of enabled inputs and sort them by Z-order. */ pipe->num_inputs = 0; - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *rpf = vsp1->rpf[i]; unsigned int j; @@ -457,7 +456,7 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1, brx = to_brx(&pipe->brx->subdev); /* Setup the RPF input pipeline for every enabled input. */ - for (i = 0; i < pipe->brx->source_pad; ++i) { + for (unsigned int i = 0; i < pipe->brx->source_pad; ++i) { struct vsp1_rwpf *rpf = inputs[i]; if (!rpf) { @@ -732,7 +731,6 @@ int vsp1_du_disable(struct device *dev, unsigned int pipe_index) struct vsp1_device *vsp1 = dev_get_drvdata(dev); struct vsp1_drm_pipeline *drm_pipe; struct vsp1_pipeline *pipe; - unsigned int i; int ret; if (pipe_index >= vsp1->info->lif_count) @@ -748,7 +746,7 @@ int vsp1_du_disable(struct device *dev, unsigned int pipe_index) if (ret == -ETIMEDOUT) dev_err(vsp1->dev, "DRM pipeline stop timeout\n"); - for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) { + for (unsigned int i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) { struct vsp1_rwpf *rpf = pipe->inputs[i]; if (!rpf) @@ -964,8 +962,6 @@ EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg); int vsp1_drm_init(struct vsp1_device *vsp1) { - unsigned int i; - vsp1->drm = devm_kzalloc(vsp1->dev, sizeof(*vsp1->drm), GFP_KERNEL); if (!vsp1->drm) return -ENOMEM; @@ -973,7 +969,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1) mutex_init(&vsp1->drm->lock); /* Create one DRM pipeline per LIF. */ - for (i = 0; i < vsp1->info->lif_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->lif_count; ++i) { struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[i]; struct vsp1_pipeline *pipe = &drm_pipe->pipe; @@ -1010,7 +1006,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1) } /* Disable all RPFs initially. */ - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *input = vsp1->rpf[i]; INIT_LIST_HEAD(&input->entity.list_pipe); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c index 627b5046fa80..762a9e776a94 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c @@ -51,10 +51,9 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data) VI6_WPF_IRQ_STA_UND; struct vsp1_device *vsp1 = data; irqreturn_t ret = IRQ_NONE; - unsigned int i; u32 status; - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; if (wpf == NULL) @@ -103,7 +102,6 @@ static int vsp1_create_sink_links(struct vsp1_device *vsp1, { struct media_entity *entity = &sink->subdev.entity; struct vsp1_entity *source; - unsigned int pad; int ret; list_for_each_entry(source, &vsp1->entities, list_dev) { @@ -123,7 +121,7 @@ static int vsp1_create_sink_links(struct vsp1_device *vsp1, source->index == sink->index ? MEDIA_LNK_FL_ENABLED : 0; - for (pad = 0; pad < entity->num_pads; ++pad) { + for (unsigned int pad = 0; pad < entity->num_pads; ++pad) { if (!(entity->pads[pad].flags & MEDIA_PAD_FL_SINK)) continue; @@ -144,7 +142,6 @@ static int vsp1_create_sink_links(struct vsp1_device *vsp1, static int vsp1_uapi_create_links(struct vsp1_device *vsp1) { struct vsp1_entity *entity; - unsigned int i; int ret; list_for_each_entry(entity, &vsp1->entities, list_dev) { @@ -177,7 +174,7 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) return ret; } - for (i = 0; i < vsp1->info->lif_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->lif_count; ++i) { if (!vsp1->lif[i]) continue; @@ -189,7 +186,7 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) return ret; } - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *rpf = vsp1->rpf[i]; ret = media_create_pad_link(&rpf->video->video.entity, 0, @@ -201,7 +198,7 @@ static int vsp1_uapi_create_links(struct vsp1_device *vsp1) return ret; } - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { /* * Connect the video device to the WPF. All connections are * immutable. @@ -253,7 +250,6 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) struct media_device *mdev = &vsp1->media_dev; struct v4l2_device *vdev = &vsp1->v4l2_dev; struct vsp1_entity *entity; - unsigned int i; int ret; mdev->dev = vsp1->dev; @@ -365,7 +361,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) * enabled skip the LIFs, even when present. */ if (!vsp1->info->uapi) { - for (i = 0; i < vsp1->info->lif_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->lif_count; ++i) { struct vsp1_lif *lif; lif = vsp1_lif_create(vsp1, i); @@ -389,7 +385,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *rpf; rpf = vsp1_rpf_create(vsp1, i); @@ -423,7 +419,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->info->uds_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->uds_count; ++i) { struct vsp1_uds *uds; uds = vsp1_uds_create(vsp1, i); @@ -436,7 +432,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&uds->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->info->uif_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->uif_count; ++i) { struct vsp1_uif *uif; uif = vsp1_uif_create(vsp1, i); @@ -449,7 +445,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&uif->entity.list_dev, &vsp1->entities); } - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf; wpf = vsp1_wpf_create(vsp1, i); @@ -543,11 +539,10 @@ int vsp1_reset_wpf(struct vsp1_device *vsp1, unsigned int index) static int vsp1_device_init(struct vsp1_device *vsp1) { - unsigned int i; int ret; /* Reset any channel that might be running. */ - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { ret = vsp1_reset_wpf(vsp1, i); if (ret < 0) return ret; @@ -556,13 +551,13 @@ static int vsp1_device_init(struct vsp1_device *vsp1) vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) | (8 << VI6_CLK_DCSWT_CSTRW_SHIFT)); - for (i = 0; i < vsp1->info->rpf_count; ++i) + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED); - for (i = 0; i < vsp1->info->uds_count; ++i) + for (unsigned int i = 0; i < vsp1->info->uds_count; ++i) vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED); - for (i = 0; i < vsp1->info->uif_count; ++i) + for (unsigned int i = 0; i < vsp1->info->uif_count; ++i) vsp1_write(vsp1, VI6_DPR_UIF_ROUTE(i), VI6_DPR_NODE_UNUSED); vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED); @@ -587,11 +582,9 @@ static int vsp1_device_init(struct vsp1_device *vsp1) static void vsp1_mask_all_interrupts(struct vsp1_device *vsp1) { - unsigned int i; - - for (i = 0; i < vsp1->info->lif_count; ++i) + for (unsigned int i = 0; i < vsp1->info->lif_count; ++i) vsp1_write(vsp1, VI6_DISP_IRQ_ENB(i), 0); - for (i = 0; i < vsp1->info->wpf_count; ++i) + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) vsp1_write(vsp1, VI6_WPF_IRQ_ENB(i), 0); } @@ -891,7 +884,6 @@ static const struct vsp1_device_info rzg2l_vsp2_device_info = { static const struct vsp1_device_info *vsp1_lookup_info(struct vsp1_device *vsp1) { const struct vsp1_device_info *info; - unsigned int i; u32 model; u32 soc; @@ -909,7 +901,7 @@ static const struct vsp1_device_info *vsp1_lookup_info(struct vsp1_device *vsp1) model = vsp1->version & VI6_IP_VERSION_MODEL_MASK; soc = vsp1->version & VI6_IP_VERSION_SOC_MASK; - for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { + for (unsigned int i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) { info = &vsp1_device_infos[i]; if (model == info->version && (!info->soc || soc == info->soc)) @@ -947,7 +939,7 @@ static int vsp1_probe(struct platform_device *pdev) if (irq < 0) return irq; - vsp1->rstc = devm_reset_control_get_shared(&pdev->dev, NULL); + vsp1->rstc = devm_reset_control_get_optional_shared(&pdev->dev, NULL); if (IS_ERR(vsp1->rstc)) return dev_err_probe(&pdev->dev, PTR_ERR(vsp1->rstc), "failed to get reset control\n"); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index 2ae2a573f0de..26b21559878d 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -372,10 +372,8 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev, static int vsp1_entity_init_state(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state) { - unsigned int pad; - /* Initialize all pad formats with default values. */ - for (pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { + for (unsigned int pad = 0; pad < subdev->entity.num_pads - 1; ++pad) { struct v4l2_subdev_format format = { .pad = pad, .which = sd_state ? V4L2_SUBDEV_FORMAT_TRY diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c index 0ef512e3a94b..d3eaa7c2d595 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c @@ -42,7 +42,6 @@ void vsp1_hgo_frame_end(struct vsp1_entity *entity) { struct vsp1_hgo *hgo = to_hgo(&entity->subdev); struct vsp1_histogram_buffer *buf; - unsigned int i; size_t size; u32 *data; @@ -56,7 +55,7 @@ void vsp1_hgo_frame_end(struct vsp1_entity *entity) *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN); *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM); - for (i = 0; i < 256; ++i) { + for (unsigned int i = 0; i < 256; ++i) { vsp1_write(hgo->histo.entity.vsp1, VI6_HGO_EXT_HIST_ADDR, i); *data++ = vsp1_hgo_read(hgo, VI6_HGO_EXT_HIST_DATA); @@ -67,7 +66,7 @@ void vsp1_hgo_frame_end(struct vsp1_entity *entity) *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_MAXMIN); *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM); - for (i = 0; i < 64; ++i) + for (unsigned int i = 0; i < 64; ++i) *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i)); size = (2 + 64) * sizeof(u32); @@ -80,7 +79,7 @@ void vsp1_hgo_frame_end(struct vsp1_entity *entity) *data++ = vsp1_hgo_read(hgo, VI6_HGO_G_SUM); *data++ = vsp1_hgo_read(hgo, VI6_HGO_B_SUM); - for (i = 0; i < 64; ++i) { + for (unsigned int i = 0; i < 64; ++i) { data[i] = vsp1_hgo_read(hgo, VI6_HGO_R_HISTO(i)); data[i+64] = vsp1_hgo_read(hgo, VI6_HGO_G_HISTO(i)); data[i+128] = vsp1_hgo_read(hgo, VI6_HGO_B_HISTO(i)); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c index 78b5a9201c70..8c04bdec8510 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c @@ -42,8 +42,6 @@ void vsp1_hgt_frame_end(struct vsp1_entity *entity) { struct vsp1_hgt *hgt = to_hgt(&entity->subdev); struct vsp1_histogram_buffer *buf; - unsigned int m; - unsigned int n; u32 *data; buf = vsp1_histogram_buffer_get(&hgt->histo); @@ -55,9 +53,10 @@ void vsp1_hgt_frame_end(struct vsp1_entity *entity) *data++ = vsp1_hgt_read(hgt, VI6_HGT_MAXMIN); *data++ = vsp1_hgt_read(hgt, VI6_HGT_SUM); - for (m = 0; m < 6; ++m) - for (n = 0; n < 32; ++n) + for (unsigned int m = 0; m < 6; ++m) { + for (unsigned int n = 0; n < 32; ++n) *data++ = vsp1_hgt_read(hgt, VI6_HGT_HISTO(m, n)); + } vsp1_histogram_buffer_complete(&hgt->histo, buf, HGT_DATA_SIZE); } @@ -71,7 +70,6 @@ void vsp1_hgt_frame_end(struct vsp1_entity *entity) static int hgt_hue_areas_try_ctrl(struct v4l2_ctrl *ctrl) { const u8 *values = ctrl->p_new.p_u8; - unsigned int i; /* * The hardware has constraints on the hue area boundaries beyond the @@ -83,7 +81,7 @@ static int hgt_hue_areas_try_ctrl(struct v4l2_ctrl *ctrl) * * Start by verifying the common part... */ - for (i = 1; i < (HGT_NUM_HUE_AREAS * 2) - 1; ++i) { + for (unsigned int i = 1; i < (HGT_NUM_HUE_AREAS * 2) - 1; ++i) { if (values[i] > values[i+1]) return -EINVAL; } @@ -138,7 +136,6 @@ static void hgt_configure_stream(struct vsp1_entity *entity, unsigned int vratio; u8 lower; u8 upper; - unsigned int i; crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK); compose = v4l2_subdev_state_get_compose(state, HISTO_PAD_SINK); @@ -153,7 +150,7 @@ static void hgt_configure_stream(struct vsp1_entity *entity, (crop->height << VI6_HGT_SIZE_VSIZE_SHIFT)); scoped_guard(mutex, hgt->ctrls.lock) { - for (i = 0; i < HGT_NUM_HUE_AREAS; ++i) { + for (unsigned int i = 0; i < HGT_NUM_HUE_AREAS; ++i) { lower = hgt->hue_areas[i*2 + 0]; upper = hgt->hue_areas[i*2 + 1]; vsp1_hgt_write(hgt, dlb, VI6_HGT_HUE_AREA(i), diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lut.c b/drivers/media/platform/renesas/vsp1/vsp1_lut.c index a22c31e17cb7..6433b5515ef9 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_lut.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_lut.c @@ -40,13 +40,12 @@ static inline void vsp1_lut_write(struct vsp1_lut *lut, static int lut_set_table(struct vsp1_lut *lut, struct v4l2_ctrl *ctrl) { struct vsp1_dl_body *dlb; - unsigned int i; dlb = vsp1_dl_body_get(lut->pool); if (!dlb) return -ENOMEM; - for (i = 0; i < LUT_SIZE; ++i) + for (unsigned int i = 0; i < LUT_SIZE; ++i) vsp1_dl_body_write(dlb, VI6_LUT_TABLE + 4 * i, ctrl->p_new.p_u32[i]); diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c index 32bb02ce0366..c6a624e193b3 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c @@ -391,16 +391,15 @@ void vsp1_adjust_color_space(u32 code, u32 *colorspace, u8 *xfer_func, void vsp1_pipeline_reset(struct vsp1_pipeline *pipe) { struct vsp1_entity *entity; - unsigned int i; if (pipe->brx) { struct vsp1_brx *brx = to_brx(&pipe->brx->subdev); - for (i = 0; i < ARRAY_SIZE(brx->inputs); ++i) + for (unsigned int i = 0; i < ARRAY_SIZE(brx->inputs); ++i) brx->inputs[i].rpf = NULL; } - for (i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) + for (unsigned int i = 0; i < ARRAY_SIZE(pipe->inputs); ++i) pipe->inputs[i] = NULL; pipe->output = NULL; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index 5a1d284213ad..b85351986fae 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -104,14 +104,13 @@ static int __vsp1_video_try_format(struct vsp1_video *video, const struct vsp1_format_info *info; unsigned int width = pix->width; unsigned int height = pix->height; - unsigned int i; /* * Backward compatibility: replace deprecated RGB formats by their XRGB * equivalent. This selects the format older userspace applications want * while still exposing the new format. */ - for (i = 0; i < ARRAY_SIZE(xrgb_formats); ++i) { + for (unsigned int i = 0; i < ARRAY_SIZE(xrgb_formats); ++i) { if (xrgb_formats[i][0] == pix->pixelformat) { pix->pixelformat = xrgb_formats[i][1]; break; @@ -161,7 +160,7 @@ static int __vsp1_video_try_format(struct vsp1_video *video, * the datasheet, strides not aligned to a multiple of 128 bytes result * in image corruption. */ - for (i = 0; i < min(info->planes, 2U); ++i) { + for (unsigned int i = 0; i < min(info->planes, 2U); ++i) { unsigned int hsub = i > 0 ? info->hsub : 1; unsigned int vsub = i > 0 ? info->vsub : 1; unsigned int align = 128; @@ -209,7 +208,6 @@ vsp1_video_complete_buffer(struct vsp1_video *video) struct vsp1_pipeline *pipe = video->rwpf->entity.pipe; struct vsp1_vb2_buffer *next = NULL; struct vsp1_vb2_buffer *done; - unsigned int i; scoped_guard(spinlock_irqsave, &video->irqlock) { if (list_empty(&video->irqqueue)) @@ -227,7 +225,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video) done->buf.sequence = pipe->sequence; done->buf.vb2_buf.timestamp = ktime_get_ns(); - for (i = 0; i < done->buf.vb2_buf.num_planes; ++i) + for (unsigned int i = 0; i < done->buf.vb2_buf.num_planes; ++i) vb2_set_plane_payload(&done->buf.vb2_buf, i, vb2_plane_size(&done->buf.vb2_buf, i)); vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE); @@ -267,7 +265,6 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) struct vsp1_entity *entity; struct vsp1_dl_body *dlb; struct vsp1_dl_list *dl; - unsigned int partition; dl = vsp1_dl_list_get(pipe->output->dlm); @@ -289,7 +286,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe) vsp1_video_pipeline_run_partition(pipe, dl, 0); /* Process consecutive partitions as necessary. */ - for (partition = 1; partition < pipe->partitions; ++partition) { + for (unsigned int partition = 1; partition < pipe->partitions; ++partition) { struct vsp1_dl_list *dl_next; dl_next = vsp1_dl_list_get(pipe->output->dlm); @@ -321,7 +318,6 @@ static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe, struct vsp1_device *vsp1 = pipe->output->entity.vsp1; enum vsp1_pipeline_state state; unsigned long flags; - unsigned int i; /* M2M Pipelines should never call here with an incomplete frame. */ WARN_ON_ONCE(!(completion & VSP1_DL_FRAME_END_COMPLETED)); @@ -329,7 +325,7 @@ static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe, spin_lock_irqsave(&pipe->irqlock, flags); /* Complete buffers on all video nodes. */ - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { if (!pipe->inputs[i]) continue; @@ -449,7 +445,6 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, struct media_graph graph; struct media_entity *entity = &video->video.entity; struct media_device *mdev = entity->graph_obj.mdev; - unsigned int i; int ret; /* Walk the graph to locate the entities and video nodes. */ @@ -517,7 +512,7 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe, * Follow links downstream for each input and make sure the graph * contains no loop and that all branches end at the output WPF. */ - for (i = 0; i < video->vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < video->vsp1->info->rpf_count; ++i) { if (!pipe->inputs[i]) continue; @@ -606,13 +601,12 @@ vsp1_video_queue_setup(struct vb2_queue *vq, { struct vsp1_video *video = vb2_get_drv_priv(vq); const struct v4l2_pix_format_mplane *format = &video->rwpf->format; - unsigned int i; if (*nplanes) { if (*nplanes != format->num_planes) return -EINVAL; - for (i = 0; i < *nplanes; i++) + for (unsigned int i = 0; i < *nplanes; i++) if (sizes[i] < format->plane_fmt[i].sizeimage) return -EINVAL; return 0; @@ -620,7 +614,7 @@ vsp1_video_queue_setup(struct vb2_queue *vq, *nplanes = format->num_planes; - for (i = 0; i < format->num_planes; ++i) + for (unsigned int i = 0; i < format->num_planes; ++i) sizes[i] = format->plane_fmt[i].sizeimage; return 0; @@ -682,7 +676,6 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) const struct v4l2_mbus_framefmt *format; struct vsp1_entity *entity; unsigned int div_size; - unsigned int i; /* * Partitions are computed on the size before rotation, use the format @@ -716,7 +709,7 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe) if (!pipe->part_table) return -ENOMEM; - for (i = 0; i < pipe->partitions; ++i) + for (unsigned int i = 0; i < pipe->partitions; ++i) vsp1_pipeline_calculate_partition(pipe, &pipe->part_table[i], div_size, i); @@ -1116,7 +1109,6 @@ static const struct media_entity_operations vsp1_video_media_ops = { void vsp1_video_suspend(struct vsp1_device *vsp1) { - unsigned int i; int ret; /* @@ -1124,7 +1116,7 @@ void vsp1_video_suspend(struct vsp1_device *vsp1) * pipelines twice, first to set them all to the stopping state, and * then to wait for the stop to complete. */ - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; struct vsp1_pipeline *pipe; @@ -1141,7 +1133,7 @@ void vsp1_video_suspend(struct vsp1_device *vsp1) } } - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; struct vsp1_pipeline *pipe; @@ -1162,10 +1154,8 @@ void vsp1_video_suspend(struct vsp1_device *vsp1) void vsp1_video_resume(struct vsp1_device *vsp1) { - unsigned int i; - /* Resume all running pipelines. */ - for (i = 0; i < vsp1->info->wpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->wpf_count; ++i) { struct vsp1_rwpf *wpf = vsp1->wpf[i]; struct vsp1_pipeline *pipe; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c index 0ec707d2913f..821887815eb2 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c @@ -232,7 +232,6 @@ static void wpf_configure_stream(struct vsp1_entity *entity, const struct v4l2_mbus_framefmt *source_format; const struct v4l2_mbus_framefmt *sink_format; unsigned int index = wpf->entity.index; - unsigned int i; u32 outfmt = 0; u32 srcrpf = 0; int ret; @@ -314,7 +313,7 @@ static void wpf_configure_stream(struct vsp1_entity *entity, * inputs as sub-layers and select the virtual RPF as the master * layer. For VSPX configure the enabled sources as masters. */ - for (i = 0; i < vsp1->info->rpf_count; ++i) { + for (unsigned int i = 0; i < vsp1->info->rpf_count; ++i) { struct vsp1_rwpf *input = pipe->inputs[i]; if (!input) @@ -399,7 +398,6 @@ static void wpf_configure_partition(struct vsp1_entity *entity, unsigned int left; unsigned int offset; unsigned int flip; - unsigned int i; /* * Cropping. The partition algorithm can split the image into multiple @@ -448,7 +446,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity, else offset = left; - for (i = 0; i < format->num_planes; ++i) { + for (unsigned int i = 0; i < format->num_planes; ++i) { unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; unsigned int vsub = i > 0 ? fmtinfo->vsub : 1; @@ -490,7 +488,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity, * Compute the output coordinate. The partition * horizontal (left) offset becomes a vertical offset. */ - for (i = 0; i < format->num_planes; ++i) { + for (unsigned int i = 0; i < format->num_planes; ++i) { unsigned int hsub = i > 0 ? fmtinfo->hsub : 1; mem.addr[i] += hoffset / hsub diff --git a/drivers/media/platform/rockchip/rga/rga3-hw.c b/drivers/media/platform/rockchip/rga/rga3-hw.c index ca1c268303dd..c4a71306278b 100644 --- a/drivers/media/platform/rockchip/rga/rga3-hw.c +++ b/drivers/media/platform/rockchip/rga/rga3-hw.c @@ -450,10 +450,14 @@ static void *rga3_adjust_and_map_format(struct rga_ctx *ctx, other_format = is_output ? &ctx->out.pix : &ctx->in.pix; other_format_info = v4l2_format_info(other_format->pixelformat); - if ((v4l2_is_format_rgb(format_info) && - v4l2_is_format_yuv(other_format_info)) || - (v4l2_is_format_yuv(format_info) && - v4l2_is_format_rgb(other_format_info))) { + /* + * Only apply the quantization restrictions when we need to + * convert between RGB and YUV. Otherwise there is no point + * to limit the quantization for operations like scaling or + * rotations. + */ + if (v4l2_is_format_yuv(format_info) && + v4l2_is_format_rgb(other_format_info)) { /* * The RGA3 only supports BT601, BT709 and BT2020 RGB<->YUV conversions * Additionally BT709 and BT2020 only support limited range YUV. diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c index f89602075121..9c4a6093af32 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c @@ -209,6 +209,9 @@ static void st_ref_pic_set_prediction(struct rkvdec_hevc_run *run, int idx, int i, j; int dPoc; + if ((unsigned int)rps_data->delta_idx_minus1 + 1 > idx) + return; + ref_rps_idx = st_rps_idx - (rps_data->delta_idx_minus1 + 1); /* 7-59 */ delta_rps = (1 - 2 * rps_data->delta_rps_sign) * (rps_data->abs_delta_rps_minus1 + 1); /* 7-60 */ diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c index 87abf93dfd5e..ff3942f91c5d 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c @@ -258,9 +258,9 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, for (i = 0; i <= pps->num_tile_rows_minus1; i++) WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i)); } else { - WRITE_PPS(((sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1, + WRITE_PPS(DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_y) - 1, COLUMN_WIDTH(0)); - WRITE_PPS(((sps->pic_height_in_luma_samples + ctb_size_y - 1) / ctb_size_y) - 1, + WRITE_PPS(DIV_ROUND_UP(sps->pic_height_in_luma_samples, ctb_size_y) - 1, ROW_HEIGHT(0)); } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c index fe6414a17551..d07c74679552 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c @@ -261,8 +261,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, memset(row_height, 0, sizeof(row_height)); max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size); - pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width; - pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width; + pic_in_cts_width = DIV_ROUND_UP(width, max_cu_width); + pic_in_cts_height = DIV_ROUND_UP(height, max_cu_width); if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) { if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) { @@ -275,8 +275,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, column_width, row_height); } } else { - column_width[0] = (width + max_cu_width - 1) / max_cu_width; - row_height[0] = (height + max_cu_width - 1) / max_cu_width; + column_width[0] = DIV_ROUND_UP(width, max_cu_width); + row_height[0] = DIV_ROUND_UP(height, max_cu_width); } for (i = 0; i < 20; i++) { diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c index 3575338a531a..3462d995d4cf 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c @@ -287,8 +287,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, memset(row_height, 0, sizeof(row_height)); max_cu_width = 1 << (sps->log2_diff_max_min_luma_coding_block_size + log2_min_cb_size); - pic_in_cts_width = (width + max_cu_width - 1) / max_cu_width; - pic_in_cts_height = (height + max_cu_width - 1) / max_cu_width; + pic_in_cts_width = DIV_ROUND_UP(width, max_cu_width); + pic_in_cts_height = DIV_ROUND_UP(height, max_cu_width); if (tiles_enabled) { if (pps->flags & V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING) { @@ -301,8 +301,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, column_width, row_height); } } else { - column_width[0] = (width + max_cu_width - 1) / max_cu_width; - row_height[0] = (height + max_cu_width - 1) / max_cu_width; + column_width[0] = DIV_ROUND_UP(width, max_cu_width); + row_height[0] = DIV_ROUND_UP(height, max_cu_width); } for (i = 0; i < 20; i++) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c index 1d1e9bfef8e9..061281f903f3 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -278,12 +278,12 @@ static const struct rkvdec_ctrl_desc vdpu38x_hevc_ctrl_descs[] = { { .cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS, .cfg.ops = &rkvdec_ctrl_ops, - .cfg.dims = { 65 }, + .cfg.dims = { 64 }, }, { .cfg.id = V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS, .cfg.ops = &rkvdec_ctrl_ops, - .cfg.dims = { 65 }, + .cfg.dims = { 32 }, }, }; @@ -1818,8 +1818,8 @@ static int rkvdec_probe(struct platform_device *pdev) vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return -ENXIO; + if (irq < 0) + return irq; ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, rkvdec_irq_handler, IRQF_ONESHOT, diff --git a/drivers/media/platform/samsung/s3c-camif/camif-core.c b/drivers/media/platform/samsung/s3c-camif/camif-core.c index 221e3c447f36..bb06847f3a63 100644 --- a/drivers/media/platform/samsung/s3c-camif/camif-core.c +++ b/drivers/media/platform/samsung/s3c-camif/camif-core.c @@ -12,7 +12,6 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/errno.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -302,7 +301,6 @@ static int camif_media_dev_init(struct camif_dev *camif) struct media_device *md = &camif->media_dev; struct v4l2_device *v4l2_dev = &camif->v4l2_dev; unsigned int ip_rev = camif->variant->ip_revision; - int ret; memset(md, 0, sizeof(*md)); snprintf(md->model, sizeof(md->model), "Samsung S3C%s CAMIF", @@ -317,11 +315,7 @@ static int camif_media_dev_init(struct camif_dev *camif) media_device_init(md); - ret = v4l2_device_register(camif->dev, v4l2_dev); - if (ret < 0) - return ret; - - return ret; + return v4l2_device_register(camif->dev, v4l2_dev); } static void camif_clk_put(struct camif_dev *camif) @@ -412,7 +406,7 @@ static int s3c_camif_probe(struct platform_device *pdev) camif->dev = dev; - if (!pdata || !pdata->gpio_get || !pdata->gpio_put) { + if (!pdata) { dev_err(dev, "wrong platform data\n"); return -EINVAL; } @@ -429,9 +423,7 @@ static int s3c_camif_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = pdata->gpio_get(); - if (ret < 0) - return ret; + /* FIXME: get GPIOs here */ ret = s3c_camif_create_subdev(camif); if (ret < 0) @@ -504,14 +496,12 @@ err_disable: err_clk: s3c_camif_unregister_subdev(camif); err_sd: - pdata->gpio_put(); return ret; } static void s3c_camif_remove(struct platform_device *pdev) { struct camif_dev *camif = platform_get_drvdata(pdev); - struct s3c_camif_plat_data *pdata = &camif->pdata; media_device_unregister(&camif->media_dev); media_device_cleanup(&camif->media_dev); @@ -521,7 +511,6 @@ static void s3c_camif_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); camif_clk_put(camif); s3c_camif_unregister_subdev(camif); - pdata->gpio_put(); } static int s3c_camif_runtime_resume(struct device *dev) diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index eeb0199864dd..aa79fe60ff0c 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -2024,8 +2024,10 @@ static int dcmi_probe(struct platform_device *pdev) mdma_chan = dma_request_chan(&pdev->dev, "mdma_tx"); if (IS_ERR(mdma_chan)) { ret = PTR_ERR(mdma_chan); - if (ret != -ENODEV) - return dev_err_probe(&pdev->dev, ret, "Failed to request MDMA channel\n"); + if (ret != -ENODEV) { + dev_err_probe(&pdev->dev, ret, "Failed to request MDMA channel\n"); + goto err_release_chan; + } mdma_chan = NULL; } @@ -2050,6 +2052,7 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); if (!dcmi->sram_pool) { dev_info(&pdev->dev, "No SRAM pool, can't use MDMA chaining\n"); + ret = -ENOMEM; goto err_dma_slave_config; } @@ -2061,6 +2064,7 @@ static int dcmi_probe(struct platform_device *pdev) &dcmi->sram_dma_buf); if (!dcmi->sram_buf) { dev_err(dcmi->dev, "Failed to allocate from SRAM\n"); + ret = -ENOMEM; goto err_dma_slave_config; } @@ -2206,12 +2210,13 @@ err_device_unregister: err_media_device_cleanup: media_device_cleanup(&dcmi->mdev); err_mdma_slave_config: - if (dcmi->mdma_chan) + if (mdma_chan) gen_pool_free(dcmi->sram_pool, (unsigned long)dcmi->sram_buf, dcmi->sram_buf_size); err_dma_slave_config: - dma_release_channel(dcmi->dma_chan); - if (dcmi->mdma_chan) + if (mdma_chan) dma_release_channel(mdma_chan); +err_release_chan: + dma_release_channel(chan); return ret; } @@ -2273,9 +2278,7 @@ static int dcmi_resume(struct device *dev) pinctrl_pm_select_default_state(dev); /* clock enable */ - pm_runtime_force_resume(dev); - - return 0; + return pm_runtime_force_resume(dev); } static const struct dev_pm_ops dcmi_pm_ops = { diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c index 49398d077764..516334541b2c 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c @@ -649,9 +649,7 @@ static int dcmipp_resume(struct device *dev) pinctrl_pm_select_default_state(dev); /* clock enable */ - pm_runtime_force_resume(dev); - - return 0; + return pm_runtime_force_resume(dev); } static const struct dev_pm_ops dcmipp_pm_ops = { diff --git a/drivers/media/platform/ti/Kconfig b/drivers/media/platform/ti/Kconfig index d0cb05481bd8..1a020b2bbb4f 100644 --- a/drivers/media/platform/ti/Kconfig +++ b/drivers/media/platform/ti/Kconfig @@ -50,6 +50,7 @@ config VIDEO_TI_VIP select VIDEO_TI_VPDMA select VIDEO_TI_SC select VIDEO_TI_CSC + select V4L2_FWNODE help Driver support for VIP module on certain TI SoC's VIP = Video Input Port. diff --git a/drivers/media/platform/ti/vpe/vip.c b/drivers/media/platform/ti/vpe/vip.c index e56a95f53ea9..ccb688f4d7af 100644 --- a/drivers/media/platform/ti/vpe/vip.c +++ b/drivers/media/platform/ti/vpe/vip.c @@ -815,6 +815,22 @@ static void clear_irqs(struct vip_dev *dev, int irq_num, int list_num) vpdma_clear_list_stat(dev->shared->vpdma, irq_num, dev->slice_id); } +/* + * Quiesce recovery work and per-list IRQs before releasing stream resources. + * disable_work_sync() prevents the overflow handler from requeueing recovery + * work. Mask and synchronize IRQs afterwards because a running worker may + * have re-enabled them before exiting. + */ +static void vip_quiesce_stream(struct vip_stream *stream) +{ + struct vip_dev *dev = stream->port->dev; + + disable_work_sync(&stream->recovery_work); + disable_irqs(dev, dev->slice_id, stream->list_num); + clear_irqs(dev, dev->slice_id, stream->list_num); + synchronize_irq(dev->irq); +} + static void populate_desc_list(struct vip_stream *stream) { struct vip_port *port = stream->port; @@ -2429,6 +2445,7 @@ static int vip_start_streaming(struct vb2_queue *vq, unsigned int count) goto err; stream->num_recovery = 0; + enable_work(&stream->recovery_work); clear_irqs(dev, dev->slice_id, stream->list_num); enable_irqs(dev, dev->slice_id, stream->list_num); @@ -2453,13 +2470,17 @@ static void vip_stop_streaming(struct vb2_queue *vq) struct vip_dev *dev = port->dev; int ret; + /* + * A running recovery worker may re-enable the parser, so quiesce it + * and its IRQ handler before stopping the parser or releasing the + * descriptor list. + */ + vip_quiesce_stream(stream); + vip_parser_stop_imm(port, true); vip_enable_parser(port, false); unset_fmt_params(stream); - disable_irqs(dev, dev->slice_id, stream->list_num); - clear_irqs(dev, dev->slice_id, stream->list_num); - if (port->subdev) { ret = v4l2_subdev_call(port->subdev, video, s_stream, 0); if (ret) @@ -3075,6 +3096,8 @@ static int alloc_stream(struct vip_port *port, int stream_id, int vfl_type) goto do_free_hwlist; INIT_WORK(&stream->recovery_work, vip_overflow_recovery_work); + /* Start disabled; vip_start_streaming() enables it before IRQs. */ + disable_work(&stream->recovery_work); INIT_LIST_HEAD(&stream->vidq); @@ -3140,6 +3163,13 @@ static void free_stream(struct vip_stream *stream) return; dev = stream->port->dev; + /* + * Quiesce the IRQ handler and recovery worker, then drop the stream + * from cap_streams[], before releasing stream-owned resources. + */ + vip_quiesce_stream(stream); + stream->port->cap_streams[stream->stream_id] = NULL; + /* Free up the Drop queue */ list_for_each_safe(pos, q, &stream->dropq) { buf = list_entry(pos, @@ -3151,7 +3181,6 @@ static void free_stream(struct vip_stream *stream) video_unregister_device(stream->vfd); vpdma_hwlist_release(dev->shared->vpdma, stream->list_num); - stream->port->cap_streams[stream->stream_id] = NULL; kfree(stream); } diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index 2e81877f640f..ad71c0402ef3 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -771,8 +771,10 @@ static int hantro_register_entity(struct media_device *mdev, return ret; ret = media_device_register_entity(mdev, entity); - if (ret) + if (ret) { + media_entity_cleanup(entity); return ret; + } return 0; } @@ -860,12 +862,13 @@ err_rm_links0: err_rel_entity2: media_device_unregister_entity(&func->sink); - + media_entity_cleanup(&func->sink); err_rel_entity1: media_device_unregister_entity(&func->proc); - + media_entity_cleanup(&func->proc); err_rel_entity0: media_device_unregister_entity(&func->vdev.entity); + media_entity_cleanup(&func->vdev.entity); return ret; } @@ -878,6 +881,9 @@ static void hantro_detach_func(struct hantro_func *func) media_device_unregister_entity(&func->sink); media_device_unregister_entity(&func->proc); media_device_unregister_entity(&func->vdev.entity); + media_entity_cleanup(&func->sink); + media_entity_cleanup(&func->proc); + media_entity_cleanup(&func->vdev.entity); } static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 5110754e1a31..53c1d1061cf4 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -527,8 +527,8 @@ static const struct v4l2_ctrl_ops cadet_ctrl_ops = { static const struct pnp_device_id cadet_pnp_devices[] = { /* ADS Cadet AM/FM Radio Card */ - {.id = "MSM0c24", .driver_data = 0}, - {.id = ""} + { .id = "MSM0c24" }, + { } }; MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices); diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 3d1d0b46195b..7e4257e4b71d 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -284,8 +284,8 @@ static const int gemtek_ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c } #ifdef CONFIG_PNP static const struct pnp_device_id gemtek_pnp_devices[] = { /* AOpen FX-3D/Pro Radio */ - {.id = "ADS7183", .driver_data = 0}, - {.id = ""} + { .id = "ADS7183" }, + { } }; MODULE_DEVICE_TABLE(pnp, gemtek_pnp_devices); diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 5055dfc3f465..c196ee923ecd 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -642,8 +642,8 @@ static void fintek_shutdown(struct pnp_dev *pdev) } static const struct pnp_device_id fintek_ids[] = { - { "FIT0002", 0 }, /* CIR */ - { "", 0 }, + { .id = "FIT0002" }, /* CIR */ + { } }; static struct pnp_driver fintek_driver = { diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index bde2a7051231..1fbafcd8219e 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1203,9 +1203,16 @@ static void ite_close(struct rc_dev *rcdev) spin_unlock_irqrestore(&dev->lock, flags); } +enum ite_model_type { + ITE8704, + ITE8713, + ITE8708, + ITE8709, +}; + /* supported models and their parameters */ static const struct ite_dev_params ite_dev_descs[] = { - { /* 0: ITE8704 */ + [ITE8704] = { .model = "ITE8704 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, .io_rsrc_no = 0, @@ -1224,7 +1231,7 @@ static const struct ite_dev_params ite_dev_descs[] = { .init_hardware = it87_init_hardware, .set_carrier_params = it87_set_carrier_params, }, - { /* 1: ITE8713 */ + [ITE8713] = { .model = "ITE8713 CIR transceiver", .io_region_size = IT87_IOREG_LENGTH, .io_rsrc_no = 0, @@ -1243,7 +1250,7 @@ static const struct ite_dev_params ite_dev_descs[] = { .init_hardware = it87_init_hardware, .set_carrier_params = it87_set_carrier_params, }, - { /* 2: ITE8708 */ + [ITE8708] = { .model = "ITE8708 CIR transceiver", .io_region_size = IT8708_IOREG_LENGTH, .io_rsrc_no = 0, @@ -1263,7 +1270,7 @@ static const struct ite_dev_params ite_dev_descs[] = { .init_hardware = it8708_init_hardware, .set_carrier_params = it8708_set_carrier_params, }, - { /* 3: ITE8709 */ + [ITE8709] = { .model = "ITE8709 CIR transceiver", .io_region_size = IT8709_IOREG_LENGTH, .io_rsrc_no = 2, @@ -1286,11 +1293,11 @@ static const struct ite_dev_params ite_dev_descs[] = { }; static const struct pnp_device_id ite_ids[] = { - {"ITE8704", 0}, /* Default model */ - {"ITE8713", 1}, /* CIR found in EEEBox 1501U */ - {"ITE8708", 2}, /* Bridged IT8512 */ - {"ITE8709", 3}, /* SRAM-Bridged IT8512 */ - {"", 0}, + { .id = "ITE8704", .driver_data = ITE8704 }, /* Default model */ + { .id = "ITE8713", .driver_data = ITE8713 }, /* CIR found in EEEBox 1501U */ + { .id = "ITE8708", .driver_data = ITE8708 }, /* Bridged IT8512 */ + { .id = "ITE8709", .driver_data = ITE8709 }, /* SRAM-Bridged IT8512 */ + { } }; /* allocate memory, probe hardware, and initialize everything */ @@ -1301,7 +1308,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id struct ite_dev *itdev = NULL; struct rc_dev *rdev = NULL; int ret = -ENOMEM; - int model_no; + enum ite_model_type model_no; int io_rsrc_no; itdev = kzalloc_obj(struct ite_dev); @@ -1317,7 +1324,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id ret = -ENODEV; /* get the model number */ - model_no = (int)dev_id->driver_data; + model_no = dev_id->driver_data; dev_dbg(&pdev->dev, "Auto-detected model: %s\n", ite_dev_descs[model_no].model); diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index d04572627cdd..38b84e34b225 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -129,7 +129,7 @@ obj-$(CONFIG_RC_MAP) += \ rc-twinhan1027.o \ rc-twinhan-dtv-cab-ci.o \ rc-vega-s9x.o \ - rc-videomate-m1f.o \ + rc-videomate-k100.o \ rc-videomate-s350.o \ rc-videomate-tv-pvr.o \ rc-videostrong-kii-pro.o \ diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-k100.c index 1f9be84ff27b..6664cfd0b7f3 100644 --- a/drivers/media/rc/keymaps/rc-videomate-m1f.c +++ b/drivers/media/rc/keymaps/rc-videomate-k100.c @@ -87,4 +87,4 @@ module_exit(exit_rc_map_videomate_k100) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>"); -MODULE_DESCRIPTION("videomate-m1f remote controller keytable"); +MODULE_DESCRIPTION("videomate-k100 remote controller keytable"); diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 4e5a0c8dc9a0..918258dadd69 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -1092,9 +1092,9 @@ static void nvt_shutdown(struct pnp_dev *pdev) } static const struct pnp_device_id nvt_ids[] = { - { "WEC0530", 0 }, /* CIR */ - { "NTN0530", 0 }, /* CIR for new chip's pnp id*/ - { "", 0 }, + { .id = "WEC0530" }, /* CIR */ + { .id = "NTN0530" }, /* CIR for new chip's pnp id*/ + { } }; static struct pnp_driver nvt_driver = { diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index cb4c56bf0752..28e840a7e5b8 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -344,22 +344,25 @@ static int sunxi_ir_probe(struct platform_device *pdev) ir->irq = platform_get_irq(pdev, 0); if (ir->irq < 0) { ret = ir->irq; - goto exit_free_dev; + goto exit_unregister_dev; } ret = devm_request_irq(dev, ir->irq, sunxi_ir_irq, 0, SUNXI_IR_DEV, ir); if (ret) { dev_err(dev, "failed request irq\n"); - goto exit_free_dev; + goto exit_unregister_dev; } ret = sunxi_ir_hw_init(dev); if (ret) - goto exit_free_dev; + goto exit_unregister_dev; dev_info(dev, "initialized sunXi IR driver\n"); return 0; +exit_unregister_dev: + rc_unregister_device(ir->rc); + exit_free_dev: rc_free_device(ir->rc); diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 8e804661a621..1ae036f8a296 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -1179,8 +1179,8 @@ wbcir_remove(struct pnp_dev *device) } static const struct pnp_device_id wbcir_ids[] = { - { "WEC1022", 0 }, - { "", 0 } + { .id = "WEC1022" }, + { } }; MODULE_DEVICE_TABLE(pnp, wbcir_ids); diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c index 318e8330f16a..ff9d50fb05fd 100644 --- a/drivers/media/test-drivers/vicodec/vicodec-core.c +++ b/drivers/media/test-drivers/vicodec/vicodec-core.c @@ -63,11 +63,11 @@ struct pixfmt_info { }; static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = { - V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1 + V4L2_PIX_FMT_FWHT, 0, 4, 1, 1, 1, 1, 1, 0, 1 }; static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = { - V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1 + V4L2_PIX_FMT_FWHT_STATELESS, 0, 4, 1, 1, 1, 1, 1, 0, 1 }; static void vicodec_dev_release(struct device *dev) diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c index e0c6bc9f8f20..ac60c9b5418e 100644 --- a/drivers/media/test-drivers/vimc/vimc-capture.c +++ b/drivers/media/test-drivers/vimc/vimc-capture.c @@ -175,8 +175,8 @@ static int vimc_capture_enum_framesizes(struct file *file, void *priv, if (fsize->index) return -EINVAL; - /* Only accept code in the pix map table */ - vpix = vimc_pix_map_by_code(fsize->pixel_format); + /* Only accept pixel_format in the pix map table */ + vpix = vimc_pix_map_by_pixelformat(fsize->pixel_format); if (!vpix) return -EINVAL; diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c index 5deebcc78a33..83dcc9d61ee0 100644 --- a/drivers/media/test-drivers/vimc/vimc-sensor.c +++ b/drivers/media/test-drivers/vimc/vimc-sensor.c @@ -92,8 +92,8 @@ static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor, tpg_s_xfer_func(&vsensor->tpg, format->xfer_func); } -static int vimc_sensor_update_frame_timing(struct v4l2_subdev *sd, - u32 width, u32 height) +static void vimc_sensor_update_frame_timing(struct v4l2_subdev *sd, + u32 width, u32 height) { struct vimc_sensor_device *vsensor = container_of(sd, struct vimc_sensor_device, sd); @@ -103,13 +103,15 @@ static int vimc_sensor_update_frame_timing(struct v4l2_subdev *sd, u64 total_pixels = (u64)hts * vts; u64 frame_interval_ns; + /* Sanity check, pixel rate is fixed and fits in 32 bits. */ + if (WARN_ON(pixel_rate >= 0x100000000)) + return; + frame_interval_ns = total_pixels * NSEC_PER_SEC; - do_div(frame_interval_ns, pixel_rate); + do_div(frame_interval_ns, (u32)pixel_rate); vsensor->hw.fps_jiffies = nsecs_to_jiffies(frame_interval_ns); if (vsensor->hw.fps_jiffies == 0) vsensor->hw.fps_jiffies = 1; - - return 0; } static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt) diff --git a/drivers/media/test-drivers/vivid/vivid-meta-out.c b/drivers/media/test-drivers/vivid/vivid-meta-out.c index 55e5e5dec2f2..ca913b808225 100644 --- a/drivers/media/test-drivers/vivid/vivid-meta-out.c +++ b/drivers/media/test-drivers/vivid/vivid-meta-out.c @@ -17,12 +17,8 @@ static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { - struct vivid_dev *dev = vb2_get_drv_priv(vq); unsigned int size = sizeof(struct vivid_meta_out_buf); - if (!vivid_is_webcam(dev)) - return -EINVAL; - if (*nplanes) { if (sizes[0] < size) return -EINVAL; @@ -127,11 +123,6 @@ const struct vb2_ops vivid_meta_out_qops = { int vidioc_enum_fmt_meta_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_webcam(dev)) - return -EINVAL; - if (f->index > 0) return -EINVAL; @@ -143,12 +134,8 @@ int vidioc_enum_fmt_meta_out(struct file *file, void *priv, int vidioc_g_fmt_meta_out(struct file *file, void *priv, struct v4l2_format *f) { - struct vivid_dev *dev = video_drvdata(file); struct v4l2_meta_format *meta = &f->fmt.meta; - if (!vivid_is_webcam(dev) || !dev->has_meta_out) - return -EINVAL; - meta->dataformat = V4L2_META_FMT_VIVID; meta->buffersize = sizeof(struct vivid_meta_out_buf); return 0; @@ -159,10 +146,12 @@ void vivid_meta_out_process(struct vivid_dev *dev, { struct vivid_meta_out_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - v4l2_ctrl_s_ctrl(dev->brightness, meta->brightness); - v4l2_ctrl_s_ctrl(dev->contrast, meta->contrast); - v4l2_ctrl_s_ctrl(dev->saturation, meta->saturation); - v4l2_ctrl_s_ctrl(dev->hue, meta->hue); + if (dev->brightness) { + v4l2_ctrl_s_ctrl(dev->brightness, meta->brightness); + v4l2_ctrl_s_ctrl(dev->contrast, meta->contrast); + v4l2_ctrl_s_ctrl(dev->saturation, meta->saturation); + v4l2_ctrl_s_ctrl(dev->hue, meta->hue); + } dprintk(dev, 2, " %s brightness %u contrast %u saturation %u hue %d\n", __func__, meta->brightness, meta->contrast, diff --git a/drivers/media/tuners/tda18250.c b/drivers/media/tuners/tda18250.c index 7bb945ba0989..bd7ed50fb6e8 100644 --- a/drivers/media/tuners/tda18250.c +++ b/drivers/media/tuners/tda18250.c @@ -440,8 +440,8 @@ static int tda18250_pll_calc(struct dvb_frontend *fe, u8 *rdiv, goto err; exp = (uval & 0x70) >> 4; - if (exp > 5) - exp = 0; + if (exp == 0 || exp > 5) + exp = 1; lopd = 1 << (exp - 1); scale = uval & 0x0f; fvco = lopd * scale * ((c->frequency / 1000) + dev->if_frequency); diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 57edb42463e8..358a66ab8e48 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -464,14 +464,21 @@ static void airspy_disconnect(struct usb_interface *intf) dev_dbg(s->dev, "\n"); - mutex_lock(&s->vb_queue_lock); + /* + * vb2_video_unregister_device() releases the vb2 queue, which + * triggers airspy_stop_streaming() if streaming is active. + * stop_streaming() dereferences s->udev via airspy_ctrl_msg() and + * airspy_free_stream_bufs(), so it must run before s->udev is + * cleared. vb2_video_unregister_device() locks vb_queue_lock + * internally and stop_streaming() locks v4l2_lock, so neither may + * be held by the caller. + */ + v4l2_device_disconnect(&s->v4l2_dev); + vb2_video_unregister_device(&s->vdev); + mutex_lock(&s->v4l2_lock); - /* No need to keep the urbs around after disconnection */ s->udev = NULL; - v4l2_device_disconnect(&s->v4l2_dev); - video_unregister_device(&s->vdev); mutex_unlock(&s->v4l2_lock); - mutex_unlock(&s->vb_queue_lock); v4l2_device_put(&s->v4l2_dev); } diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 9929ce5dcdcd..8ab100db01ab 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -124,6 +124,17 @@ struct au0828_board au0828_boards[] = { }, }, }, + [AU0828_BOARD_MONOPRICE_106456] = { + /* + * Monoprice 106456 USB ATSC/QAM tuner (board rev TV22AD-A), + * a.k.a. AnyTV AUTV002, USB ID 05e1:0400. Same AU8522 demod + + * NXP TDA18271HDC2 tuner @ 0x60 as the Hauppauge Woodbury. + */ + .name = "Monoprice 106456 USB ATSC/QAM (TV22AD-A)", + .tuner_type = TUNER_NXP_TDA18271, + .tuner_addr = 0x60, + .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, + }, [AU0828_BOARD_HAUPPAUGE_HVR1265] = { .name = "Hauppauge HVR1265", .tuner_type = TUNER_XC5000, @@ -294,6 +305,7 @@ void au0828_gpio_setup(struct au0828_dev *dev) case AU0828_BOARD_HAUPPAUGE_WOODBURY: case AU0828_BOARD_HAUPPAUGE_HVR1265: case AU0828_BOARD_HAUPPAUGE_IMPACTVCBE: + case AU0828_BOARD_MONOPRICE_106456: /* GPIO's * 4 - CS5340 * 5 - AU8522 Demodulator @@ -378,6 +390,8 @@ struct usb_device_id au0828_usb_id_table[] = { .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, { USB_DEVICE(0x05e1, 0x0480), .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, + { USB_DEVICE(0x05e1, 0x0400), + .driver_info = AU0828_BOARD_MONOPRICE_106456 }, { USB_DEVICE(0x2040, 0x8200), .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, { USB_DEVICE(0x2040, 0x7260), diff --git a/drivers/media/usb/au0828/au0828-cards.h b/drivers/media/usb/au0828/au0828-cards.h index a438aeb334a0..a4a283731f7d 100644 --- a/drivers/media/usb/au0828/au0828-cards.h +++ b/drivers/media/usb/au0828/au0828-cards.h @@ -13,3 +13,4 @@ #define AU0828_BOARD_HAUPPAUGE_WOODBURY 5 #define AU0828_BOARD_HAUPPAUGE_IMPACTVCBE 6 #define AU0828_BOARD_HAUPPAUGE_HVR1265 7 +#define AU0828_BOARD_MONOPRICE_106456 8 diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index 31123e6f9fc3..9c95b7ceaecd 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -600,6 +600,7 @@ int au0828_dvb_register(struct au0828_dev *dev) &mxl5007t_hvr950q_config); break; case AU0828_BOARD_HAUPPAUGE_WOODBURY: + case AU0828_BOARD_MONOPRICE_106456: dvb->frontend = dvb_attach(au8522_attach, &hauppauge_woodbury_config, &dev->i2c_adap); diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c index 9c71b32552df..b24ceef497e4 100644 --- a/drivers/media/usb/cx231xx/cx231xx-audio.c +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c @@ -443,6 +443,11 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream) int ret; struct cx231xx *dev = snd_pcm_substream_chip(substream); + if (!dev) { + pr_err("cx231xx: called with null device\n"); + return -ENODEV; + } + dev_dbg(dev->dev, "closing device\n"); /* inform hardware to stop streaming */ diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 2cd4e333bc4b..70aa99fead27 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -898,7 +898,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (rc) return rc; - if (vb2_is_busy(&dev->vidq)) { + if (vb2_is_busy(&dev->vidq) || vb2_is_busy(&dev->vbiq)) { dev_err(dev->dev, "%s: queue busy\n", __func__); return -EBUSY; } @@ -933,7 +933,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) if (dev->norm == norm) return 0; - if (vb2_is_busy(&dev->vidq)) + if (vb2_is_busy(&dev->vidq) || vb2_is_busy(&dev->vbiq)) return -EBUSY; dev->norm = norm; diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index 870ac3c8b085..6404eb74db32 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -987,11 +987,7 @@ static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap) if (ret < 0) return ret; - ret = mxl111sf_lg2160_frontend_attach(adap, 2); - if (ret < 0) - return ret; - - return ret; + return mxl111sf_lg2160_frontend_attach(adap, 2); } static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap) @@ -1007,11 +1003,7 @@ static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap) if (ret < 0) return ret; - ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2); - if (ret < 0) - return ret; - - return ret; + return mxl111sf_lg2161_ep6_frontend_attach(adap, 2); } static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index fbfb74eab475..b7c534fc8a21 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2677,6 +2677,28 @@ const struct em28xx_board em28xx_boards[] = { .gpio = mygica_utv3_tuner_audio_gpio, } }, }, + /* eb1a:8286 StarTech SVID2USB232 + * Empia EM28281 with integrated TVP5150-compatible video decoder. + * Composite and S-Video inputs, stereo line-in audio. + */ + [EM28281_BOARD_STARTECH_SVID2USB232] = { + .name = "StarTech SVID2USB232", + .vchannels = 2, + .tuner_type = TUNER_ABSENT, + .has_dvb = 0, + .decoder = EM28XX_BUILTIN, + .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .input = { { + .type = EM28XX_VMUX_COMPOSITE, + .vmux = EM2828X_COMPOSITE, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = EM2828X_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, [EM2828X_BOARD_HAUPPAUGE_USB_LIVE2] = { .name = "Hauppauge USB Live2", .vchannels = 2, @@ -2946,6 +2968,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2874_BOARD_HAUPPAUGE_USB_QUADHD }, { USB_DEVICE(0x2040, 0xc220), .driver_info = EM2828X_BOARD_HAUPPAUGE_USB_LIVE2 }, + { USB_DEVICE(0xeb1a, 0x8286), + .driver_info = EM28281_BOARD_STARTECH_SVID2USB232 }, { USB_DEVICE(0x2040, 0x0360), .driver_info = EM2828X_BOARD_HAUPPAUGE_935_V2 }, { USB_DEVICE(0x2040, 0x8360), @@ -3651,6 +3675,7 @@ static void request_module_async(struct work_struct *work) * intf. Don't register extensions twice on those devices. */ if (dev->is_audio_only) { + em28xx_init_extension(dev); #if defined(CONFIG_MODULES) && defined(MODULE) request_module("em28xx-alsa"); #endif @@ -3758,7 +3783,7 @@ void em28xx_free_device(struct kref *ref) { struct em28xx *dev = kref_to_dev(ref); - dev_info(&dev->intf->dev, "Freeing device\n"); + pr_info("%s: Freeing device\n", dev->name); if (!dev->disconnected) em28xx_release_resources(dev); @@ -3859,6 +3884,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, dev->wait_after_write = 0; dev->eeprom_addrwidth_16bit = 1; break; + case CHIP_ID_EM28281: + chip_name = "em28281"; + dev->wait_after_write = 0; + dev->eeprom_addrwidth_16bit = 1; + break; case CHIP_ID_EM2883: chip_name = "em2882/3"; dev->wait_after_write = 0; @@ -3884,8 +3914,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, retval = -ENODEV; goto err_deinit_media; } - em28xx_init_extension(dev); - return 0; } @@ -4082,7 +4110,7 @@ static void em28xx_check_usb_descriptor(struct em28xx *dev, dev->analog_ep_bulk = e->bEndpointAddress; } return; - }; + } } /* diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 5bbb082dbed9..0b998e7cafef 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -632,7 +632,7 @@ void em2828X_decoder_vmux(struct em28xx *dev, unsigned int vin) default: dev_dbg(&dev->intf->dev, "EM2828X_SVIDEO\n"); break; - }; + } em28xx_write_reg(dev, 0x24, 0x00); em28xx_write_reg(dev, 0x25, 0x02); @@ -1265,6 +1265,8 @@ void em28xx_close_extension(struct em28xx *dev) ops->fini(dev); } } + if (dev->dev_next) + list_del(&dev->dev_next->devlist); list_del(&dev->devlist); mutex_unlock(&em28xx_devlist_mutex); } diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 938f1980d448..8482fc4045ea 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -29,7 +29,7 @@ #include <media/dmxdev.h> #include <media/tuner.h> #include "tuner-simple.h" -#include <linux/gpio.h> +#include <linux/gpio/legacy.h> #include "lgdt330x.h" #include "lgdt3305.h" diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h index 68a0fcc2fa72..8931733a8e24 100644 --- a/drivers/media/usb/em28xx/em28xx-reg.h +++ b/drivers/media/usb/em28xx/em28xx-reg.h @@ -283,6 +283,7 @@ enum em28xx_chip_id { CHIP_ID_EM2884 = 68, CHIP_ID_EM28174 = 113, CHIP_ID_EM28178 = 114, + CHIP_ID_EM28281 = 145, CHIP_ID_EM2828X = 148, }; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index da0422c65e5f..c418add65bb5 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1213,6 +1213,9 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) { struct em28xx *dev = vb2_get_drv_priv(vq); struct em28xx_v4l2 *v4l2 = dev->v4l2; + struct em28xx_dmaqueue *dmaq = vq->type == V4L2_BUF_TYPE_VBI_CAPTURE ? + &dev->vbiq : &dev->vidq; + unsigned long flags = 0; struct v4l2_frequency f; struct v4l2_fh *owner; int rc = 0; @@ -1227,7 +1230,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) */ rc = res_get(dev, vq->type); if (rc) - return rc; + goto exit; if (v4l2->streaming_users == 0) { /* First active streaming user, so allocate all the URBs */ @@ -1250,7 +1253,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) em28xx_urb_data_copy); if (rc < 0) { res_free(dev, vq->type); - return rc; + goto exit; } /* @@ -1275,7 +1278,18 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count) } v4l2->streaming_users++; + return 0; + +exit: + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct em28xx_buffer *buf; + buf = list_entry(dmaq->active.next, struct em28xx_buffer, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + } + spin_unlock_irqrestore(&dev->slock, flags); return rc; } @@ -2275,18 +2289,27 @@ static int radio_s_tuner(struct file *file, void *priv, } /* - * em28xx_free_v4l2() - Free struct em28xx_v4l2 + * em28xx_free_v4l2() - v4l2_device release callback * - * @ref: struct kref for struct em28xx_v4l2 + * @v4l2_dev: pointer to struct v4l2_device embedded in struct em28xx_v4l2 * - * Called when all users of struct em28xx_v4l2 are gone + * Called by the v4l2 core when the last reference to the v4l2_device is + * released. At this point no userspace file handle nor video_device node + * keeps the v4l2 instance alive anymore, so it is safe to release all + * v4l2-related resources and drop the em28xx device reference taken when + * the v4l2 extension was initialized. */ -static void em28xx_free_v4l2(struct kref *ref) +static void em28xx_free_v4l2(struct v4l2_device *v4l2_dev) { - struct em28xx_v4l2 *v4l2 = container_of(ref, struct em28xx_v4l2, ref); + struct em28xx_v4l2 *v4l2 = + container_of(v4l2_dev, struct em28xx_v4l2, v4l2_dev); + struct em28xx *dev = v4l2->dev; - v4l2->dev->v4l2 = NULL; + v4l2_ctrl_handler_free(&v4l2->ctrl_handler); + v4l2_device_unregister(v4l2_dev); + dev->v4l2 = NULL; kfree(v4l2); + kref_put(&dev->ref, em28xx_free_device); } /* @@ -2323,9 +2346,8 @@ static int em28xx_v4l2_open(struct file *filp) return -ENODEV; } - em28xx_videodbg("open dev=%s type=%s users=%d\n", - video_device_node_name(vdev), v4l2_type_names[fh_type], - v4l2->users); + em28xx_videodbg("open dev=%s type=%s\n", + video_device_node_name(vdev), v4l2_type_names[fh_type]); ret = v4l2_fh_open(filp); if (ret) { @@ -2336,7 +2358,7 @@ static int em28xx_v4l2_open(struct file *filp) return ret; } - if (v4l2->users == 0) { + if (v4l2_fh_is_singular_file(filp)) { em28xx_set_mode(dev, EM28XX_ANALOG_MODE); if (vdev->vfl_type != VFL_TYPE_RADIO) @@ -2354,10 +2376,6 @@ static int em28xx_v4l2_open(struct file *filp) v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_radio); } - kref_get(&dev->ref); - kref_get(&v4l2->ref); - v4l2->users++; - mutex_unlock(&dev->lock); return 0; @@ -2398,27 +2416,27 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (video_is_registered(&v4l2->radio_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->radio_dev)); - video_unregister_device(&v4l2->radio_dev); + vb2_video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vbi_dev)); - video_unregister_device(&v4l2->vbi_dev); + vb2_video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vdev)); - video_unregister_device(&v4l2->vdev); + vb2_video_unregister_device(&v4l2->vdev); } - v4l2_ctrl_handler_free(&v4l2->ctrl_handler); - v4l2_device_unregister(&v4l2->v4l2_dev); - - kref_put(&v4l2->ref, em28xx_free_v4l2); - mutex_unlock(&dev->lock); - kref_put(&dev->ref, em28xx_free_device); + /* + * Drop the initial reference taken at v4l2_device_register() time. + * The em28xx_free_v4l2() release callback will be invoked once all + * userspace file handles to the video device nodes are closed. + */ + v4l2_device_put(&v4l2->v4l2_dev); return 0; } @@ -2460,13 +2478,13 @@ static int em28xx_v4l2_close(struct file *filp) struct em28xx_v4l2 *v4l2 = dev->v4l2; struct usb_device *udev = interface_to_usbdev(dev->intf); int err; + bool last_user; - em28xx_videodbg("users=%d\n", v4l2->users); - - vb2_fop_release(filp); mutex_lock(&dev->lock); + last_user = v4l2_fh_is_singular_file(filp); + _vb2_fop_release(filp, NULL); - if (v4l2->users == 1) { + if (last_user) { /* No sense to try to write to the device */ if (dev->disconnected) goto exit; @@ -2489,10 +2507,7 @@ static int em28xx_v4l2_close(struct file *filp) } exit: - v4l2->users--; - kref_put(&v4l2->ref, em28xx_free_v4l2); mutex_unlock(&dev->lock); - kref_put(&dev->ref, em28xx_free_device); return 0; } @@ -2711,7 +2726,6 @@ static int em28xx_v4l2_init(struct em28xx *dev) mutex_unlock(&dev->lock); return -ENOMEM; } - kref_init(&v4l2->ref); v4l2->dev = dev; dev->v4l2 = v4l2; @@ -2722,9 +2736,21 @@ static int em28xx_v4l2_init(struct em28xx *dev) if (ret < 0) { dev_err(&dev->intf->dev, "Call to v4l2_device_register() failed!\n"); - goto err; + dev->v4l2 = NULL; + kfree(v4l2); + mutex_unlock(&dev->lock); + return ret; } + /* + * From this point on, em28xx_free_v4l2() will be used to release + * v4l2-related resources when the v4l2_device refcount reaches + * zero. Take a reference to the em28xx device so that it cannot + * be freed before the v4l2 instance is released. + */ + v4l2->v4l2_dev.release = em28xx_free_v4l2; + kref_get(&dev->ref); + hdl = &v4l2->ctrl_handler; v4l2_ctrl_handler_init(hdl, 9); v4l2->v4l2_dev.ctrl_handler = hdl; @@ -3048,8 +3074,6 @@ static int em28xx_v4l2_init(struct em28xx *dev) dev_info(&dev->intf->dev, "V4L2 extension successfully initialized\n"); - kref_get(&dev->ref); - mutex_unlock(&dev->lock); return 0; @@ -3058,27 +3082,29 @@ unregister_dev: dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->radio_dev)); - video_unregister_device(&v4l2->radio_dev); + vb2_video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vbi_dev)); - video_unregister_device(&v4l2->vbi_dev); + vb2_video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vdev)); - video_unregister_device(&v4l2->vdev); + vb2_video_unregister_device(&v4l2->vdev); } - v4l2_ctrl_handler_free(&v4l2->ctrl_handler); - v4l2_device_unregister(&v4l2->v4l2_dev); -err: - dev->v4l2 = NULL; - kref_put(&v4l2->ref, em28xx_free_v4l2); mutex_unlock(&dev->lock); + + /* + * Drop the initial reference. em28xx_free_v4l2() will be called + * once the last video_device node release has decremented the + * v4l2_device refcount to zero. + */ + v4l2_device_put(&v4l2->v4l2_dev); return ret; } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 711f281613f5..8eee639b0940 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -150,6 +150,7 @@ #define EM2828X_BOARD_HAUPPAUGE_955_V2 110 #define EM2828X_BOARD_HAUPPAUGE_975_V2 111 #define EM28178_BOARD_PCTV_461E_V3 112 +#define EM28281_BOARD_STARTECH_SVID2USB232 113 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 @@ -558,7 +559,6 @@ struct em28xx_eeprom { #define EM28XX_RESOURCE_VBI 0x02 struct em28xx_v4l2 { - struct kref ref; struct em28xx *dev; struct v4l2_device v4l2_dev; @@ -582,7 +582,6 @@ struct em28xx_v4l2 { int sensor_yres; int sensor_xtal; - int users; /* user count for exclusive use */ int streaming_users; /* number of actively streaming users */ u32 frequency; /* selected tuner frequency */ diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index 25b3ee25aaa4..453ab5c3aa03 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -264,17 +264,17 @@ int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs) ret = go7007_init_encoder(go); mutex_unlock(&go->hw_lock); if (ret < 0) - return ret; + goto err_unregister_v4l2_dev; ret = go7007_v4l2_ctrl_init(go); if (ret < 0) - return ret; + goto err_free_controls; if (!go->i2c_adapter_online && go->board_info->flags & GO7007_BOARD_USE_ONBOARD_I2C) { ret = go7007_i2c_init(go); if (ret < 0) - return ret; + goto err_free_controls; go->i2c_adapter_online = 1; } if (go->i2c_adapter_online) { @@ -304,13 +304,19 @@ int go7007_register_encoder(struct go7007 *go, unsigned num_i2c_devs) ret = go7007_v4l2_init(go); if (ret < 0) - return ret; + goto err_free_controls; if (go->board_info->flags & GO7007_BOARD_HAS_AUDIO) { go->audio_enabled = 1; go7007_snd_init(go); } return 0; + +err_free_controls: + v4l2_ctrl_handler_free(&go->hdl); +err_unregister_v4l2_dev: + v4l2_device_unregister(&go->v4l2_dev); + return ret; } EXPORT_SYMBOL(go7007_register_encoder); diff --git a/drivers/media/usb/go7007/go7007-fw.c b/drivers/media/usb/go7007/go7007-fw.c index 86ce593e0c54..8cf959c20e30 100644 --- a/drivers/media/usb/go7007/go7007-fw.c +++ b/drivers/media/usb/go7007/go7007-fw.c @@ -13,6 +13,7 @@ */ #include <linux/module.h> +#include <linux/bitops.h> #include <linux/time.h> #include <linux/mm.h> #include <linux/device.h> @@ -58,14 +59,16 @@ struct code_gen { #define CODE_GEN(name, dest) struct code_gen name = { dest, 0, 32, 0 } #define CODE_ADD(name, val, length) do { \ - name.b -= (length); \ - name.a |= (val) << name.b; \ - while (name.b <= 24) { \ - *name.p = name.a >> 24; \ - ++name.p; \ - name.a <<= 8; \ - name.b += 8; \ - name.len += 8; \ + if (length) { \ + name.b -= (length); \ + name.a |= (val) << name.b; \ + while (name.b <= 24) { \ + *name.p = name.a >> 24; \ + ++name.p; \ + name.a <<= 8; \ + name.b += 8; \ + name.len += 8; \ + } \ } \ } while (0) @@ -707,11 +710,10 @@ done: static int vti_bitlen(struct go7007 *go) { - unsigned int i, max_time_incr = go->sensor_framerate / go->fps_scale; + unsigned int max_time_incr = go->sensor_framerate / go->fps_scale; + int bitlen = fls(max_time_incr); - for (i = 31; (max_time_incr & ((1 << i) - 1)) == max_time_incr; --i) - ; - return i + 1; + return bitlen ?: 1; } static int mpeg4_frame_header(struct go7007 *go, unsigned char *buf, @@ -1209,7 +1211,7 @@ static int seqhead_to_package(struct go7007 *go, __le16 *code, int space, 0xbf08, fps, 0xbf09, 0, 0xbff2, vop_time_increment_bitlength, - 0xbff3, (1 << vop_time_increment_bitlength) - 1, + 0xbff3, GENMASK(vop_time_increment_bitlength - 1, 0), 0xbfe6, 0, 0xbfe7, (fps / 1000) << 8, 0, 0, diff --git a/drivers/media/usb/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c index 0901d79e827d..d11f8e723624 100644 --- a/drivers/media/usb/go7007/s2250-board.c +++ b/drivers/media/usb/go7007/s2250-board.c @@ -365,36 +365,48 @@ static int s2250_s_ctrl(struct v4l2_ctrl *ctrl) struct s2250 *state = container_of(ctrl->handler, struct s2250, hdl); struct i2c_client *client = v4l2_get_subdevdata(&state->sd); u16 oldvalue; + int ret; switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: - read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue); - write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, - ctrl->val | (oldvalue & ~0xff)); - read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue); - write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, - ctrl->val | (oldvalue & ~0xff)); - write_reg_fp(client, 0x140, 0x60); - break; + ret = read_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, &oldvalue); + if (ret) + return ret; + ret = write_reg_fp(client, VPX322_ADDR_BRIGHTNESS0, + ctrl->val | (oldvalue & ~0xff)); + if (ret) + return ret; + ret = read_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, &oldvalue); + if (ret) + return ret; + ret = write_reg_fp(client, VPX322_ADDR_BRIGHTNESS1, + ctrl->val | (oldvalue & ~0xff)); + if (ret) + return ret; + return write_reg_fp(client, 0x140, 0x60); case V4L2_CID_CONTRAST: - read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue); - write_reg_fp(client, VPX322_ADDR_CONTRAST0, - ctrl->val | (oldvalue & ~0x3f)); - read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue); - write_reg_fp(client, VPX322_ADDR_CONTRAST1, - ctrl->val | (oldvalue & ~0x3f)); - write_reg_fp(client, 0x140, 0x60); - break; + ret = read_reg_fp(client, VPX322_ADDR_CONTRAST0, &oldvalue); + if (ret) + return ret; + ret = write_reg_fp(client, VPX322_ADDR_CONTRAST0, + ctrl->val | (oldvalue & ~0x3f)); + if (ret) + return ret; + ret = read_reg_fp(client, VPX322_ADDR_CONTRAST1, &oldvalue); + if (ret) + return ret; + ret = write_reg_fp(client, VPX322_ADDR_CONTRAST1, + ctrl->val | (oldvalue & ~0x3f)); + if (ret) + return ret; + return write_reg_fp(client, 0x140, 0x60); case V4L2_CID_SATURATION: - write_reg_fp(client, VPX322_ADDR_SAT, ctrl->val); - break; + return write_reg_fp(client, VPX322_ADDR_SAT, ctrl->val); case V4L2_CID_HUE: - write_reg_fp(client, VPX322_ADDR_HUE, ctrl->val); - break; + return write_reg_fp(client, VPX322_ADDR_HUE, ctrl->val); default: return -EINVAL; } - return 0; } static int s2250_set_fmt(struct v4l2_subdev *sd, diff --git a/drivers/media/usb/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c index e4b9f37be77b..01d547ad678d 100644 --- a/drivers/media/usb/go7007/snd-go7007.c +++ b/drivers/media/usb/go7007/snd-go7007.c @@ -195,6 +195,13 @@ static const struct snd_device_ops go7007_snd_device_ops = { .dev_free = go7007_snd_free, }; +static void go7007_snd_card_free(struct snd_card *card) +{ + struct go7007 *go = card->private_data; + + v4l2_device_put(&go->v4l2_dev); +} + int go7007_snd_init(struct go7007 *go) { static int dev; @@ -245,6 +252,8 @@ int go7007_snd_init(struct go7007 *go) gosnd->substream = NULL; go->snd_context = gosnd; v4l2_device_get(&go->v4l2_dev); + gosnd->card->private_data = go; + gosnd->card->private_free = go7007_snd_card_free; ++dev; return 0; @@ -263,7 +272,6 @@ int go7007_snd_remove(struct go7007 *go) snd_card_disconnect(gosnd->card); snd_card_free_when_closed(gosnd->card); - v4l2_device_put(&go->v4l2_dev); return 0; } EXPORT_SYMBOL(go7007_snd_remove); diff --git a/drivers/media/usb/gspca/jl2005bcd.c b/drivers/media/usb/gspca/jl2005bcd.c index a408fcc3a060..4988fbf5005e 100644 --- a/drivers/media/usb/gspca/jl2005bcd.c +++ b/drivers/media/usb/gspca/jl2005bcd.c @@ -148,17 +148,12 @@ static int jl2005c_start_new_frame(struct gspca_dev *gspca_dev) static int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg, unsigned char value) { - int retval; u8 instruction[2]; instruction[0] = reg; instruction[1] = value; - retval = jl2005c_write2(gspca_dev, instruction); - if (retval < 0) - return retval; - - return retval; + return jl2005c_write2(gspca_dev, instruction); } static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev) diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 0b8182edf8e4..15012d73975c 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -69,7 +69,7 @@ #define MAX_CHANNELS 4 #define SYS_FRAMES 4 /* maximum size is PAL full size plus room for the marker header(s) */ -#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096) +#define SYS_FRAMES_MAXSIZE (720 * 288 * 2 * 2 + 4096) #define DEF_USB_BLOCK S2255_USB_XFER_SIZE #define LINE_SZ_4CIFS_NTSC 640 #define LINE_SZ_2CIFS_NTSC 640 @@ -86,7 +86,6 @@ #define LINE_SZ_DEF 640 #define NUM_LINES_DEF 240 - /* predefined settings */ #define FORMAT_NTSC 1 #define FORMAT_PAL 2 @@ -111,9 +110,9 @@ #define FDEC_3 3 /* capture every 3rd frame */ #define FDEC_5 5 /* capture every 5th frame */ -/*------------------------------------------------------- - * Default mode parameters. - *-------------------------------------------------------*/ +/*-------------------------------------------------------*/ +/* Default mode parameters. */ +/*-------------------------------------------------------*/ #define DEF_SCALE SCALE_4CIFS #define DEF_COLOR COLOR_YUVPL #define DEF_FDEC FDEC_1 @@ -144,21 +143,20 @@ struct s2255_mode { u32 restart; /* if DSP requires restart */ }; - #define S2255_READ_IDLE 0 #define S2255_READ_FRAME 1 /* frame structure */ struct s2255_framei { unsigned long size; - unsigned long ulState; /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/ + unsigned long state; /* state:S2255_READ_IDLE, S2255_READ_FRAME*/ void *lpvbits; /* image data */ unsigned long cur_size; /* current data copied to it */ }; /* image buffer structure */ struct s2255_bufferi { - unsigned long dwFrames; /* number of frames in buffer */ + unsigned long num_frames; /* number of frames in buffer */ struct s2255_framei frame[SYS_FRAMES]; /* array of FRAME structures */ }; @@ -212,7 +210,7 @@ struct s2255_vc { struct s2255_mode mode; v4l2_std_id std; /* jpeg compression */ - unsigned jpegqual; + unsigned int jpegqual; /* capture parameters (for high quality mode full size) */ struct v4l2_captureparm cap_parm; int cur_frame; @@ -243,7 +241,6 @@ struct s2255_vc { spinlock_t qlock; }; - struct s2255_dev { struct s2255_vc vc[MAX_CHANNELS]; struct v4l2_device v4l2_dev; @@ -284,7 +281,6 @@ struct s2255_buffer { struct list_head list; }; - /* current cypress EEPROM firmware version */ #define S2255_CUR_USB_FWVER ((3 << 8) | 12) /* current DSP FW version */ @@ -343,8 +339,8 @@ static int s2255_board_shutdown(struct s2255_dev *dev); static void s2255_fwload_start(struct s2255_dev *dev); static void s2255_destroy(struct s2255_dev *dev); static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, - u16 index, u16 value, void *buf, - s32 buf_len, int bOut); + u16 index, u16 value, void *xfer_buf, + s32 xfer_buf_len, int is_out); /* dev_err macro with driver name */ #define S2255_DRIVER_NAME "s2255" @@ -352,7 +348,7 @@ static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, dev_err(dev, S2255_DRIVER_NAME " - " fmt, ##arg) #define dprintk(dev, level, fmt, arg...) \ - v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) + v4l2_dbg(level, debug, &(dev)->v4l2_dev, fmt, ## arg) static struct usb_driver s2255_driver; @@ -430,7 +426,6 @@ static int norm_minh(struct s2255_vc *vc) (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL); } - /* * TODO: fixme: move YUV reordering to hardware * converts 2255 planar format to yuyv or uyvy @@ -440,21 +435,21 @@ static void planar422p_to_yuv_packed(const unsigned char *in, int width, int height, int fmt) { - unsigned char *pY; - unsigned char *pCb; - unsigned char *pCr; + unsigned char *p_y; + unsigned char *p_cb; + unsigned char *p_cr; unsigned long size = height * width; unsigned int i; - pY = (unsigned char *)in; - pCr = (unsigned char *)in + height * width; - pCb = (unsigned char *)in + height * width + (height * width / 2); + + p_y = (unsigned char *)in; + p_cr = (unsigned char *)in + height * width; + p_cb = (unsigned char *)in + height * width + (height * width / 2); for (i = 0; i < size * 2; i += 4) { - out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCr++; - out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCr++ : *pY++; - out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *pY++ : *pCb++; - out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *pCb++ : *pY++; + out[i] = (fmt == V4L2_PIX_FMT_YUYV) ? *p_y++ : *p_cr++; + out[i + 1] = (fmt == V4L2_PIX_FMT_YUYV) ? *p_cr++ : *p_y++; + out[i + 2] = (fmt == V4L2_PIX_FMT_YUYV) ? *p_y++ : *p_cb++; + out[i + 3] = (fmt == V4L2_PIX_FMT_YUYV) ? *p_cb++ : *p_y++; } - return; } static void s2255_reset_dsppower(struct s2255_dev *dev) @@ -464,7 +459,6 @@ static void s2255_reset_dsppower(struct s2255_dev *dev) s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1); msleep(600); s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1); - return; } /* kickstarts the firmware loading. from probe @@ -473,6 +467,7 @@ static void s2255_timer(struct timer_list *t) { struct s2255_dev *dev = timer_container_of(dev, t, timer); struct s2255_fw *data = dev->fw_data; + if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { pr_err("s2255: can't submit urb\n"); atomic_set(&data->fw_state, S2255_FW_FAILED); @@ -482,18 +477,18 @@ static void s2255_timer(struct timer_list *t) } } - /* this loads the firmware asynchronously. - Originally this was done synchronously in probe. - But it is better to load it asynchronously here than block - inside the probe function. Blocking inside probe affects boot time. - FW loading is triggered by the timer in the probe function -*/ + * Originally this was done synchronously in probe. + * But it is better to load it asynchronously here than block + * inside the probe function. Blocking inside probe affects boot time. + * FW loading is triggered by the timer in the probe function + */ static void s2255_fwchunk_complete(struct urb *urb) { struct s2255_fw *data = urb->context; struct usb_device *udev = urb->dev; int len; + if (urb->status) { dev_err(&udev->dev, "URB failed with status %d\n", urb->status); atomic_set(&data->fw_state, S2255_FW_FAILED); @@ -501,7 +496,7 @@ static void s2255_fwchunk_complete(struct urb *urb) wake_up(&data->wait_fw); return; } - if (data->fw_urb == NULL) { + if (!data->fw_urb) { s2255_dev_err(&udev->dev, "disconnected\n"); atomic_set(&data->fw_state, S2255_FW_FAILED); /* wake up anything waiting for the firmware */ @@ -510,8 +505,8 @@ static void s2255_fwchunk_complete(struct urb *urb) } #define CHUNK_SIZE 512 /* all USB transfers must be done with continuous kernel memory. - can't allocate more than 128k in current linux kernel, so - upload the firmware in chunks + * can't allocate more than 128k in current linux kernel, so + * upload the firmware in chunks */ if (data->fw_loaded < data->fw_size) { len = (data->fw_loaded + CHUNK_SIZE) > data->fw_size ? @@ -521,7 +516,7 @@ static void s2255_fwchunk_complete(struct urb *urb) memset(data->pfw_data, 0, CHUNK_SIZE); memcpy(data->pfw_data, - (char *) data->fw->data + data->fw_loaded, len); + (char *)data->fw->data + data->fw_loaded, len); usb_fill_bulk_urb(data->fw_urb, udev, usb_sndbulkpipe(udev, 2), data->pfw_data, CHUNK_SIZE, @@ -534,10 +529,9 @@ static void s2255_fwchunk_complete(struct urb *urb) return; } data->fw_loaded += len; - } else + } else { atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT); - return; - + } } static void s2255_got_frame(struct s2255_vc *vc, int jpgsize) @@ -569,11 +563,12 @@ static void s2255_got_frame(struct s2255_vc *vc, int jpgsize) static const struct s2255_fmt *format_by_fourcc(int fourcc) { unsigned int i; + for (i = 0; i < ARRAY_SIZE(formats); i++) { if (-1 == formats[i].fourcc) continue; - if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) || - (formats[i].fourcc == V4L2_PIX_FMT_MJPEG))) + if (!jpeg_enable && (formats[i].fourcc == V4L2_PIX_FMT_JPEG || + formats[i].fourcc == V4L2_PIX_FMT_MJPEG)) continue; if (formats[i].fourcc == fourcc) return formats + i; @@ -617,6 +612,12 @@ static void s2255_fillbuff(struct s2255_vc *vc, break; case V4L2_PIX_FMT_JPEG: case V4L2_PIX_FMT_MJPEG: + if (jpgsize < 0 || + jpgsize > vb2_plane_size(&buf->vb.vb2_buf, 0)) { + dprintk(dev, 1, "bad JPEG frame size %d\n", + jpgsize); + break; + } vb2_set_plane_payload(&buf->vb.vb2_buf, 0, jpgsize); memcpy(vbuf, tmpbuf, jpgsize); break; @@ -636,16 +637,16 @@ static void s2255_fillbuff(struct s2255_vc *vc, vbuf, pos); } - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ +/* ------------------------------------------------------------------ */ +/* Videobuf operations */ +/* ------------------------------------------------------------------ */ static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) { struct s2255_vc *vc = vb2_get_drv_priv(vq); + if (*nbuffers < S2255_MIN_BUFS) *nbuffers = S2255_MIN_BUFS; *nplanes = 1; @@ -662,14 +663,13 @@ static int buffer_prepare(struct vb2_buffer *vb) int h = vc->height; unsigned long size; - dprintk(vc->dev, 4, "%s\n", __func__); - if (vc->fmt == NULL) + if (!vc->fmt) return -EINVAL; - if ((w < norm_minw(vc)) || - (w > norm_maxw(vc)) || - (h < norm_minh(vc)) || - (h > norm_maxh(vc))) { + if (w < norm_minw(vc) || + w > norm_maxw(vc) || + h < norm_minh(vc) || + h > norm_maxh(vc)) { dprintk(vc->dev, 4, "invalid buffer prepare\n"); return -EINVAL; } @@ -689,7 +689,7 @@ static void buffer_queue(struct vb2_buffer *vb) struct s2255_buffer *buf = container_of(vbuf, struct s2255_buffer, vb); struct s2255_vc *vc = vb2_get_drv_priv(vb->vb2_queue); unsigned long flags = 0; - dprintk(vc->dev, 1, "%s\n", __func__); + spin_lock_irqsave(&vc->qlock, flags); list_add_tail(&buf->list, &vc->buf_list); spin_unlock_irqrestore(&vc->qlock, flags); @@ -719,21 +719,21 @@ static int vidioc_querycap(struct file *file, void *priv, } static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) + struct v4l2_fmtdesc *f) { int index = f->index; if (index >= ARRAY_SIZE(formats)) return -EINVAL; - if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) || - (formats[index].fourcc == V4L2_PIX_FMT_MJPEG))) + if (!jpeg_enable && (formats[index].fourcc == V4L2_PIX_FMT_JPEG || + formats[index].fourcc == V4L2_PIX_FMT_MJPEG)) return -EINVAL; f->pixelformat = formats[index].fourcc; return 0; } static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct s2255_vc *vc = video_drvdata(file); int is_ntsc = vc->std & V4L2_STD_525_60; @@ -753,7 +753,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { const struct s2255_fmt *fmt; enum v4l2_field field; @@ -762,7 +762,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (fmt == NULL) + if (!fmt) return -EINVAL; dprintk(vc->dev, 50, "%s NTSC: %d suggested width: %d, height: %d\n", @@ -804,7 +804,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct s2255_vc *vc = video_drvdata(file); const struct s2255_fmt *fmt; @@ -819,7 +819,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (fmt == NULL) + if (!fmt) return -EINVAL; if (vb2_is_busy(q)) { @@ -839,8 +839,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, mode.scale = SCALE_4CIFSI; else mode.scale = SCALE_4CIFS; - } else + } else { mode.scale = SCALE_2CIFS; + } } else { mode.scale = SCALE_1CIFS; @@ -875,11 +876,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, else if (mode.format != vc->mode.format) mode.restart = 1; vc->mode = mode; - (void) s2255_set_mode(vc, &mode); + (void)s2255_set_mode(vc, &mode); return 0; } - /* write to the configuration pipe, synchronously */ static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, int size) @@ -887,6 +887,7 @@ static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, int pipe; int done; long retval = -1; + if (udev) { pipe = usb_sndbulkpipe(udev, S2255_CONFIG_EP); retval = usb_bulk_msg(udev, pipe, pbuf, size, &done, 500); @@ -896,29 +897,29 @@ static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf, static u32 get_transfer_size(struct s2255_mode *mode) { - int linesPerFrame = LINE_SZ_DEF; - int pixelsPerLine = NUM_LINES_DEF; - u32 outImageSize; - u32 usbInSize; + int lines_per_frame = LINE_SZ_DEF; + int pixels_per_line = NUM_LINES_DEF; + u32 out_image_size; + u32 usb_in_size; unsigned int mask_mult; - if (mode == NULL) + if (!mode) return 0; if (mode->format == FORMAT_NTSC) { switch (mode->scale) { case SCALE_4CIFS: case SCALE_4CIFSI: - linesPerFrame = NUM_LINES_4CIFS_NTSC * 2; - pixelsPerLine = LINE_SZ_4CIFS_NTSC; + lines_per_frame = NUM_LINES_4CIFS_NTSC * 2; + pixels_per_line = LINE_SZ_4CIFS_NTSC; break; case SCALE_2CIFS: - linesPerFrame = NUM_LINES_2CIFS_NTSC; - pixelsPerLine = LINE_SZ_2CIFS_NTSC; + lines_per_frame = NUM_LINES_2CIFS_NTSC; + pixels_per_line = LINE_SZ_2CIFS_NTSC; break; case SCALE_1CIFS: - linesPerFrame = NUM_LINES_1CIFS_NTSC; - pixelsPerLine = LINE_SZ_1CIFS_NTSC; + lines_per_frame = NUM_LINES_1CIFS_NTSC; + pixels_per_line = LINE_SZ_1CIFS_NTSC; break; default: break; @@ -927,40 +928,42 @@ static u32 get_transfer_size(struct s2255_mode *mode) switch (mode->scale) { case SCALE_4CIFS: case SCALE_4CIFSI: - linesPerFrame = NUM_LINES_4CIFS_PAL * 2; - pixelsPerLine = LINE_SZ_4CIFS_PAL; + lines_per_frame = NUM_LINES_4CIFS_PAL * 2; + pixels_per_line = LINE_SZ_4CIFS_PAL; break; case SCALE_2CIFS: - linesPerFrame = NUM_LINES_2CIFS_PAL; - pixelsPerLine = LINE_SZ_2CIFS_PAL; + lines_per_frame = NUM_LINES_2CIFS_PAL; + pixels_per_line = LINE_SZ_2CIFS_PAL; break; case SCALE_1CIFS: - linesPerFrame = NUM_LINES_1CIFS_PAL; - pixelsPerLine = LINE_SZ_1CIFS_PAL; + lines_per_frame = NUM_LINES_1CIFS_PAL; + pixels_per_line = LINE_SZ_1CIFS_PAL; break; default: break; } } - outImageSize = linesPerFrame * pixelsPerLine; + out_image_size = lines_per_frame * pixels_per_line; if ((mode->color & MASK_COLOR) != COLOR_Y8) { /* 2 bytes/pixel if not monochrome */ - outImageSize *= 2; + out_image_size *= 2; } /* total bytes to send including prefix and 4K padding; - must be a multiple of USB_READ_SIZE */ - usbInSize = outImageSize + PREFIX_SIZE; /* always send prefix */ + * must be a multiple of USB_READ_SIZE + */ + usb_in_size = out_image_size + PREFIX_SIZE; /* always send prefix */ mask_mult = 0xffffffffUL - DEF_USB_BLOCK + 1; /* if size not a multiple of USB_READ_SIZE */ - if (usbInSize & ~mask_mult) - usbInSize = (usbInSize & mask_mult) + (DEF_USB_BLOCK); - return usbInSize; + if (usb_in_size & ~mask_mult) + usb_in_size = (usb_in_size & mask_mult) + (DEF_USB_BLOCK); + return usb_in_size; } static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode) { struct device *dev = &sdev->udev->dev; + dev_info(dev, "------------------------------------------------\n"); dev_info(dev, "format: %d\nscale %d\n", mode->format, mode->scale); dev_info(dev, "fdec: %d\ncolor %d\n", mode->fdec, mode->color); @@ -1001,7 +1004,7 @@ static int s2255_set_mode(struct s2255_vc *vc, dprintk(dev, 1, "%s: reqsize %ld\n", __func__, vc->req_image_size); /* set the mode */ buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[1] = (__le32)cpu_to_le32(chn_rev); buffer[2] = CMD_SET_MODE; for (i = 0; i < sizeof(struct s2255_mode) / sizeof(u32); i++) buffer[3 + i] = cpu_to_le32(((u32 *)&vc->mode)[i]); @@ -1038,7 +1041,7 @@ static int s2255_cmd_status(struct s2255_vc *vc, u32 *pstatus) dprintk(dev, 4, "%s chan %d\n", __func__, vc->idx); /* form the get vid status command */ buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[1] = (__le32)cpu_to_le32(chn_rev); buffer[2] = CMD_STATUS; *pstatus = 0; vc->vidstatus_ready = 0; @@ -1066,7 +1069,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) vc->cur_frame = 0; vc->frame_count = 0; for (j = 0; j < SYS_FRAMES; j++) { - vc->buffer.frame[j].ulState = S2255_READ_IDLE; + vc->buffer.frame[j].state = S2255_READ_IDLE; vc->buffer.frame[j].cur_size = 0; } return s2255_start_acquire(vc); @@ -1078,7 +1081,7 @@ static void stop_streaming(struct vb2_queue *vq) struct s2255_vc *vc = vb2_get_drv_priv(vq); struct s2255_buffer *buf, *node; unsigned long flags; - (void) s2255_stop_acquire(vc); + (void)s2255_stop_acquire(vc); spin_lock_irqsave(&vc->qlock, flags); list_for_each_entry_safe(buf, node, &vc->buf_list, list) { list_del(&buf->list); @@ -1122,8 +1125,9 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i) vc->width = LINE_SZ_4CIFS_PAL; vc->height = NUM_LINES_4CIFS_PAL * 2; } - } else + } else { return -EINVAL; + } vc->std = i; if (mode.restart) s2255_set_mode(vc, &mode); @@ -1139,12 +1143,12 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *i) } /* Sensoray 2255 is a multiple channel capture device. - It does not have a "crossbar" of inputs. - We use one V4L device per channel. The user must - be aware that certain combinations are not allowed. - For instance, you cannot do full FPS on more than 2 channels(2 videodevs) - at once in color(you can do full fps on 4 channels with greyscale. -*/ + * It does not have a "crossbar" of inputs. + * We use one V4L device per channel. The user must + * be aware that certain combinations are not allowed. + * For instance, you cannot do full FPS on more than 2 channels(2 videodevs) + * at once in color(you can do full fps on 4 channels with greyscale. + */ static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { @@ -1159,6 +1163,7 @@ static int vidioc_enum_input(struct file *file, void *priv, inp->status = 0; if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) { int rc; + rc = s2255_cmd_status(vc, &status); dprintk(dev, 4, "s2255_cmd_status rc: %d status %x\n", rc, status); @@ -1184,6 +1189,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) *i = 0; return 0; } + static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { if (i > 0) @@ -1196,6 +1202,7 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) struct s2255_vc *vc = container_of(ctrl->handler, struct s2255_vc, hdl); struct s2255_mode mode; + mode = vc->mode; /* update the mode to the corresponding value */ switch (ctrl->id) { @@ -1223,15 +1230,15 @@ static int s2255_s_ctrl(struct v4l2_ctrl *ctrl) } mode.restart = 0; /* set mode here. Note: stream does not need restarted. - some V4L programs restart stream unnecessarily - after a s_crtl. - */ + * some V4L programs restart stream unnecessarily + * after a s_crtl. + */ s2255_set_mode(vc, &mode); return 0; } static int vidioc_g_jpegcomp(struct file *file, void *priv, - struct v4l2_jpegcompression *jc) + struct v4l2_jpegcompression *jc) { struct s2255_vc *vc = video_drvdata(file); @@ -1242,7 +1249,7 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv, } static int vidioc_s_jpegcomp(struct file *file, void *priv, - const struct v4l2_jpegcompression *jc) + const struct v4l2_jpegcompression *jc) { struct s2255_vc *vc = video_drvdata(file); @@ -1297,20 +1304,21 @@ static int vidioc_s_parm(struct file *file, void *priv, struct s2255_mode mode; int fdec = FDEC_1; __u32 def_num, def_dem; + if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; mode = vc->mode; /* high quality capture mode requires a stream restart */ - if ((vc->cap_parm.capturemode != sp->parm.capture.capturemode) - && vb2_is_streaming(&vc->vb_vidq)) + if (vc->cap_parm.capturemode != sp->parm.capture.capturemode && + vb2_is_streaming(&vc->vb_vidq)) return -EBUSY; def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000; def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000; - if (def_dem != sp->parm.capture.timeperframe.denominator) + if (def_dem != sp->parm.capture.timeperframe.denominator) { sp->parm.capture.timeperframe.numerator = def_num; - else if (sp->parm.capture.timeperframe.numerator <= def_num) + } else if (sp->parm.capture.timeperframe.numerator <= def_num) { sp->parm.capture.timeperframe.numerator = def_num; - else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) { + } else if (sp->parm.capture.timeperframe.numerator <= (def_num * 2)) { sp->parm.capture.timeperframe.numerator = def_num * 2; fdec = FDEC_2; } else if (sp->parm.capture.timeperframe.numerator <= (def_num * 3)) { @@ -1338,6 +1346,7 @@ static const struct v4l2_frmsize_discrete ntsc_sizes[] = { { 640, 240 }, { 320, 240 }, }; + static const struct v4l2_frmsize_discrete pal_sizes[] = { { 704, 576 }, { 704, 288 }, @@ -1345,7 +1354,7 @@ static const struct v4l2_frmsize_discrete pal_sizes[] = { }; static int vidioc_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fe) + struct v4l2_frmsizeenum *fe) { struct s2255_vc *vc = video_drvdata(file); int is_ntsc = vc->std & V4L2_STD_525_60; @@ -1355,7 +1364,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, return -EINVAL; fmt = format_by_fourcc(fe->pixel_format); - if (fmt == NULL) + if (!fmt) return -EINVAL; fe->type = V4L2_FRMSIZE_TYPE_DISCRETE; fe->discrete = is_ntsc ? ntsc_sizes[fe->index] : pal_sizes[fe->index]; @@ -1363,7 +1372,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, } static int vidioc_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fe) + struct v4l2_frmivalenum *fe) { struct s2255_vc *vc = video_drvdata(file); const struct s2255_fmt *fmt; @@ -1377,7 +1386,7 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv, return -EINVAL; fmt = format_by_fourcc(fe->pixel_format); - if (fmt == NULL) + if (!fmt) return -EINVAL; sizes = is_ntsc ? ntsc_sizes : pal_sizes; @@ -1415,7 +1424,7 @@ static int s2255_open(struct file *file) return -ENODEV; case S2255_FW_FAILED: s2255_dev_err(&dev->udev->dev, - "firmware load failed. retrying.\n"); + "firmware load failed. retrying.\n"); s2255_fwload_start(dev); wait_event_timeout(dev->fw_data->wait_fw, ((atomic_read(&dev->fw_data->fw_state) @@ -1429,7 +1438,8 @@ static int s2255_open(struct file *file) case S2255_FW_NOTLOADED: case S2255_FW_LOADED_DSPWAIT: /* give S2255_LOAD_TIMEOUT time for firmware to load in case - driver loaded and then device immediately opened */ + * driver loaded and then device immediately opened + */ pr_info("%s waiting for firmware load\n", __func__); wait_event_timeout(dev->fw_data->wait_fw, ((atomic_read(&dev->fw_data->fw_state) @@ -1481,7 +1491,6 @@ static int s2255_open(struct file *file) static void s2255_destroy(struct s2255_dev *dev) { - dprintk(dev, 1, "%s", __func__); /* board shutdown stops the read pipe if it is running */ s2255_board_shutdown(dev); /* make sure firmware still not trying to load */ @@ -1554,7 +1563,6 @@ static void s2255_video_device_release(struct video_device *vdev) if (refcount_dec_and_test(&dev->num_channels)) s2255_destroy(dev); - return; } static const struct video_device template = { @@ -1598,17 +1606,17 @@ static int s2255_probe_v4l(struct s2255_dev *dev) v4l2_ctrl_handler_init(&vc->hdl, 6); v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, - V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); + V4L2_CID_BRIGHTNESS, -127, 127, 1, DEF_BRIGHT); v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST); + V4L2_CID_CONTRAST, 0, 255, 1, DEF_CONTRAST); v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); + V4L2_CID_SATURATION, 0, 255, 1, DEF_SATURATION); v4l2_ctrl_new_std(&vc->hdl, &s2255_ctrl_ops, - V4L2_CID_HUE, 0, 255, 1, DEF_HUE); + V4L2_CID_HUE, 0, 255, 1, DEF_HUE); vc->jpegqual_ctrl = v4l2_ctrl_new_std(&vc->hdl, - &s2255_ctrl_ops, - V4L2_CID_JPEG_COMPRESSION_QUALITY, - 0, 100, 1, S2255_DEF_JPEG_QUAL); + &s2255_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, + 0, 100, 1, S2255_DEF_JPEG_QUAL); if (dev->dsp_fw_ver >= S2255_MIN_DSP_COLORFILTER && (dev->pid != 0x2257 || vc->idx <= 1)) v4l2_ctrl_new_custom(&vc->hdl, &color_filter_ctrl, @@ -1660,7 +1668,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev) refcount_inc(&dev->num_channels); v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n", video_device_node_name(&vc->vdev)); - } pr_info("Sensoray 2255 V4L driver Revision: %s\n", S2255_VERSION); @@ -1697,11 +1704,12 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) struct s2255_framei *frm; unsigned char *pdata; struct s2255_vc *vc; + dprintk(dev, 100, "buffer to user\n"); vc = &dev->vc[dev->cc]; idx = vc->cur_frame; frm = &vc->buffer.frame[idx]; - if (frm->ulState == S2255_READ_IDLE) { + if (frm->state == S2255_READ_IDLE) { int jj; unsigned int cc; __le32 *pdword; /*data from dsp is little endian */ @@ -1790,20 +1798,19 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) /* search done. now find out if should be acquiring on this channel */ if (!vb2_is_streaming(&vc->vb_vidq)) { /* we found a frame, but this channel is turned off */ - frm->ulState = S2255_READ_IDLE; + frm->state = S2255_READ_IDLE; return -EINVAL; } - if (frm->ulState == S2255_READ_IDLE) { - frm->ulState = S2255_READ_FRAME; + if (frm->state == S2255_READ_IDLE) { + frm->state = S2255_READ_FRAME; frm->cur_size = 0; } /* skip the marker 512 bytes (and offset if out of sync) */ psrc = (u8 *)pipe_info->transfer_buffer + offset; - - if (frm->lpvbits == NULL) { + if (!frm->lpvbits) { dprintk(dev, 1, "s2255 frame buffer == NULL.%p %p %d %d", frm, dev, dev->cc, idx); return -ENOMEM; @@ -1828,16 +1835,15 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) vc->last_frame = vc->cur_frame; vc->cur_frame++; /* end of system frame ring buffer, start at zero */ - if ((vc->cur_frame == SYS_FRAMES) || - (vc->cur_frame == vc->buffer.dwFrames)) + if (vc->cur_frame == SYS_FRAMES || + vc->cur_frame == vc->buffer.num_frames) vc->cur_frame = 0; /* frame ready */ if (vb2_is_streaming(&vc->vb_vidq)) s2255_got_frame(vc, vc->jpg_size); vc->frame_count++; - frm->ulState = S2255_READ_IDLE; + frm->state = S2255_READ_IDLE; frm->cur_size = 0; - } /* done successfully */ return 0; @@ -1847,6 +1853,7 @@ static void s2255_read_video_callback(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) { int res; + dprintk(dev, 50, "callback read video\n"); if (dev->cc >= MAX_CHANNELS) { @@ -1860,36 +1867,35 @@ static void s2255_read_video_callback(struct s2255_dev *dev, dprintk(dev, 4, "s2255: read callback failed\n"); dprintk(dev, 50, "callback read video done\n"); - return; } -static long s2255_vendor_req(struct s2255_dev *dev, unsigned char Request, - u16 Index, u16 Value, void *TransferBuffer, - s32 TransferBufferLength, int bOut) +static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, + u16 index, u16 value, void *xfer_buf, + s32 xfer_buf_len, int is_out) { int r; unsigned char *buf; - buf = kmalloc(TransferBufferLength, GFP_KERNEL); + buf = kmalloc(xfer_buf_len, GFP_KERNEL); if (!buf) return -ENOMEM; - if (!bOut) { + if (!is_out) { r = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), - Request, + req, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, - Value, Index, buf, - TransferBufferLength, USB_CTRL_SET_TIMEOUT); + value, index, buf, + xfer_buf_len, USB_CTRL_SET_TIMEOUT); if (r >= 0) - memcpy(TransferBuffer, buf, TransferBufferLength); + memcpy(xfer_buf, buf, xfer_buf_len); } else { - memcpy(buf, TransferBuffer, TransferBufferLength); + memcpy(buf, xfer_buf, xfer_buf_len); r = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - Request, USB_TYPE_VENDOR | USB_RECIP_DEVICE, - Value, Index, buf, - TransferBufferLength, USB_CTRL_SET_TIMEOUT); + req, USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, buf, + xfer_buf_len, USB_CTRL_SET_TIMEOUT); } kfree(buf); return r; @@ -1904,14 +1910,14 @@ static int s2255_get_fx2fw(struct s2255_dev *dev) { int fw; int ret; - u8 transBuffer[2] = {}; + u8 trans_buf[2] = {}; - ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, transBuffer, - sizeof(transBuffer), S2255_VR_IN); + ret = s2255_vendor_req(dev, S2255_VR_FW, 0, 0, trans_buf, + sizeof(trans_buf), S2255_VR_IN); if (ret < 0) dprintk(dev, 2, "get fw error: %x\n", ret); - fw = transBuffer[0] + (transBuffer[1] << 8); - dprintk(dev, 2, "Get FW %x %x\n", transBuffer[0], transBuffer[1]); + fw = trans_buf[0] + (trans_buf[1] << 8); + dprintk(dev, 2, "Get FW %x %x\n", trans_buf[0], trans_buf[1]); return fw; } @@ -1923,7 +1929,8 @@ static int s2255_create_sys_buffers(struct s2255_vc *vc) { unsigned long i; unsigned long reqsize; - vc->buffer.dwFrames = SYS_FRAMES; + + vc->buffer.num_frames = SYS_FRAMES; /* always allocate maximum size(PAL) for system buffers */ reqsize = SYS_FRAMES_MAXSIZE; @@ -1934,16 +1941,15 @@ static int s2255_create_sys_buffers(struct s2255_vc *vc) /* allocate the frames */ vc->buffer.frame[i].lpvbits = vmalloc(reqsize); vc->buffer.frame[i].size = reqsize; - if (vc->buffer.frame[i].lpvbits == NULL) { - pr_info("out of memory. using less frames\n"); - vc->buffer.dwFrames = i; + if (!vc->buffer.frame[i].lpvbits) { + vc->buffer.num_frames = i; break; } } /* make sure internal states are set */ for (i = 0; i < SYS_FRAMES; i++) { - vc->buffer.frame[i].ulState = 0; + vc->buffer.frame[i].state = 0; vc->buffer.frame[i].cur_size = 0; } @@ -1955,6 +1961,7 @@ static int s2255_create_sys_buffers(struct s2255_vc *vc) static int s2255_release_sys_buffers(struct s2255_vc *vc) { unsigned long i; + for (i = 0; i < SYS_FRAMES; i++) { vfree(vc->buffer.frame[i].lpvbits); vc->buffer.frame[i].lpvbits = NULL; @@ -1968,6 +1975,7 @@ static int s2255_board_init(struct s2255_dev *dev) int fw_ver; int j; struct s2255_pipeinfo *pipe = &dev->pipe; + dprintk(dev, 4, "board init: %p", dev); memset(pipe, 0, sizeof(*pipe)); pipe->dev = dev; @@ -1976,10 +1984,8 @@ static int s2255_board_init(struct s2255_dev *dev) pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, GFP_KERNEL); - if (pipe->transfer_buffer == NULL) { - dprintk(dev, 1, "out of memory!\n"); + if (!pipe->transfer_buffer) return -ENOMEM; - } /* query the firmware */ fw_ver = s2255_get_fx2fw(dev); @@ -1992,6 +1998,7 @@ static int s2255_board_init(struct s2255_dev *dev) for (j = 0; j < MAX_CHANNELS; j++) { struct s2255_vc *vc = &dev->vc[j]; + vc->mode = mode_def; if (dev->pid == 0x2257 && j > 1) vc->mode.color |= (1 << 16); @@ -2015,6 +2022,7 @@ static int s2255_board_init(struct s2255_dev *dev) static int s2255_board_shutdown(struct s2255_dev *dev) { u32 i; + dprintk(dev, 1, "%s: dev: %p", __func__, dev); for (i = 0; i < MAX_CHANNELS; i++) { @@ -2035,13 +2043,14 @@ static void read_pipe_completion(struct urb *purb) struct s2255_dev *dev; int status; int pipe; + pipe_info = purb->context; - if (pipe_info == NULL) { + if (!pipe_info) { dev_err(&purb->dev->dev, "no context!\n"); return; } dev = pipe_info->dev; - if (dev == NULL) { + if (!dev) { dev_err(&purb->dev->dev, "no context!\n"); return; } @@ -2058,9 +2067,9 @@ static void read_pipe_completion(struct urb *purb) return; } - if (status == 0) + if (status == 0) { s2255_read_video_callback(dev, pipe_info); - else { + } else { pipe_info->err_count++; dprintk(dev, 1, "%s: failed URB %d\n", __func__, status); } @@ -2079,7 +2088,6 @@ static void read_pipe_completion(struct urb *purb) } else { dprintk(dev, 2, "%s :complete state 0\n", __func__); } - return; } static int s2255_start_readpipe(struct s2255_dev *dev) @@ -2087,6 +2095,7 @@ static int s2255_start_readpipe(struct s2255_dev *dev) int pipe; int retval; struct s2255_pipeinfo *pipe_info = &dev->pipe; + pipe = usb_rcvbulkpipe(dev->udev, dev->read_endpoint); dprintk(dev, 2, "%s: IN %d\n", __func__, dev->read_endpoint); pipe_info->state = 1; @@ -2123,13 +2132,13 @@ static int s2255_start_acquire(struct s2255_vc *vc) vc->bad_payload = 0; vc->cur_frame = 0; for (j = 0; j < SYS_FRAMES; j++) { - vc->buffer.frame[j].ulState = 0; + vc->buffer.frame[j].state = 0; vc->buffer.frame[j].cur_size = 0; } /* send the start command */ buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[1] = (__le32)cpu_to_le32(chn_rev); buffer[2] = CMD_START; res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); if (res != 0) @@ -2151,7 +2160,7 @@ static int s2255_stop_acquire(struct s2255_vc *vc) chn_rev = G_chnmap[vc->idx]; /* send the stop command */ buffer[0] = IN_DATA_TOKEN; - buffer[1] = (__le32) cpu_to_le32(chn_rev); + buffer[1] = (__le32)cpu_to_le32(chn_rev); buffer[2] = CMD_STOP; res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512); @@ -2174,8 +2183,6 @@ static void s2255_stop_readpipe(struct s2255_dev *dev) usb_free_urb(pipe->stream_urb); pipe->stream_urb = NULL; } - dprintk(dev, 4, "%s", __func__); - return; } static void s2255_fwload_start(struct s2255_dev *dev) @@ -2208,30 +2215,26 @@ static int s2255_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it to zero */ dev = kzalloc_obj(struct s2255_dev); - if (dev == NULL) { - s2255_dev_err(&interface->dev, "out of memory\n"); + if (!dev) return -ENOMEM; - } dev->cmdbuf = kzalloc(S2255_CMDBUF_SIZE, GFP_KERNEL); - if (dev->cmdbuf == NULL) { - s2255_dev_err(&interface->dev, "out of memory\n"); - goto errorFWDATA1; - } + if (!dev->cmdbuf) + goto err_fwdata1; refcount_set(&dev->num_channels, 0); dev->pid = id->idProduct; dev->fw_data = kzalloc_obj(struct s2255_fw); if (!dev->fw_data) - goto errorFWDATA1; + goto err_fwdata1; mutex_init(&dev->lock); mutex_init(&dev->cmdlock); /* grab usb_device and save it */ dev->udev = usb_get_dev(interface_to_usbdev(interface)); - if (dev->udev == NULL) { + if (!dev->udev) { dev_err(&interface->dev, "null usb device\n"); retval = -ENODEV; - goto errorUDEV; + goto err_udev; } dev_dbg(&interface->dev, "dev: %p, udev %p interface %p\n", dev, dev->udev, interface); @@ -2243,7 +2246,7 @@ static int s2255_probe(struct usb_interface *interface, if (usb_find_bulk_in_endpoint(iface_desc, &endpoint)) { dev_err(&interface->dev, "Could not find bulk-in endpoint\n"); - goto errorEP; + goto err_ep; } dev->read_endpoint = endpoint->bEndpointAddress; @@ -2252,6 +2255,7 @@ static int s2255_probe(struct usb_interface *interface, init_waitqueue_head(&dev->fw_data->wait_fw); for (i = 0; i < MAX_CHANNELS; i++) { struct s2255_vc *vc = &dev->vc[i]; + vc->idx = i; vc->dev = dev; init_waitqueue_head(&vc->wait_setmode); @@ -2262,37 +2266,41 @@ static int s2255_probe(struct usb_interface *interface, dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->fw_data->fw_urb) - goto errorFWURB; + goto err_fwurb; dev->fw_data->pfw_data = kzalloc(CHUNK_SIZE, GFP_KERNEL); - if (!dev->fw_data->pfw_data) { - dev_err(&interface->dev, "out of memory!\n"); - goto errorFWDATA2; - } + if (!dev->fw_data->pfw_data) + goto err_fwdata2; /* load the first chunk */ if (request_firmware(&dev->fw_data->fw, FIRMWARE_FILE_NAME, &dev->udev->dev)) { dev_err(&interface->dev, "sensoray 2255 failed to get firmware\n"); - goto errorREQFW; + goto err_reqfw; } /* check the firmware is valid */ fw_size = dev->fw_data->fw->size; - pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8]; + if (fw_size < 8) { + dev_err(&interface->dev, "Firmware invalid: too small.\n"); + retval = -ENODEV; + goto err_fwmarker; + } + pdata = (__le32 *)&dev->fw_data->fw->data[fw_size - 8]; if (*pdata != S2255_FW_MARKER) { dev_err(&interface->dev, "Firmware invalid.\n"); retval = -ENODEV; - goto errorFWMARKER; + goto err_fwmarker; } else { /* make sure firmware is the latest */ - __le32 *pRel; - pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; - pr_info("s2255 dsp fw version %x\n", le32_to_cpu(*pRel)); - dev->dsp_fw_ver = le32_to_cpu(*pRel); + __le32 *p_rel; + + p_rel = (__le32 *)&dev->fw_data->fw->data[fw_size - 4]; + pr_info("s2255 dsp fw version %x\n", le32_to_cpu(*p_rel)); + dev->dsp_fw_ver = le32_to_cpu(*p_rel); if (dev->dsp_fw_ver < S2255_CUR_DSP_FWVER) pr_info("s2255: f2255usb.bin out of date.\n"); if (dev->pid == 0x2257 && - dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) + dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER) pr_warn("2257 needs firmware %d or above.\n", S2255_MIN_DSP_COLORFILTER); } @@ -2300,30 +2308,30 @@ static int s2255_probe(struct usb_interface *interface, /* load 2255 board specific */ retval = s2255_board_init(dev); if (retval) - goto errorBOARDINIT; + goto err_boardinit; s2255_fwload_start(dev); /* loads v4l specific */ retval = s2255_probe_v4l(dev); if (retval) - goto errorBOARDINIT; + goto err_boardinit; dev_info(&interface->dev, "Sensoray 2255 detected\n"); return 0; -errorBOARDINIT: +err_boardinit: s2255_board_shutdown(dev); -errorFWMARKER: +err_fwmarker: release_firmware(dev->fw_data->fw); -errorREQFW: +err_reqfw: kfree(dev->fw_data->pfw_data); -errorFWDATA2: +err_fwdata2: usb_free_urb(dev->fw_data->fw_urb); -errorFWURB: +err_fwurb: timer_shutdown_sync(&dev->timer); -errorEP: +err_ep: usb_put_dev(dev->udev); -errorUDEV: +err_udev: kfree(dev->fw_data); mutex_destroy(&dev->lock); -errorFWDATA1: +err_fwdata1: kfree(dev->cmdbuf); kfree(dev); pr_warn("Sensoray 2255 driver load failed: 0x%x\n", retval); @@ -2336,6 +2344,7 @@ static void s2255_disconnect(struct usb_interface *interface) struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface)); int i; int channels = refcount_read(&dev->num_channels); + mutex_lock(&dev->lock); v4l2_device_disconnect(&dev->v4l2_dev); mutex_unlock(&dev->lock); @@ -2355,7 +2364,6 @@ static void s2255_disconnect(struct usb_interface *interface) } if (refcount_dec_and_test(&dev->num_channels)) s2255_destroy(dev); - dev_info(&interface->dev, "%s\n", __func__); } static struct usb_driver s2255_driver = { diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index f9462a9ca761..5058cada0d0a 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -263,7 +263,7 @@ static int stk1160_scan_usb(struct usb_interface *intf, struct usb_device *udev, static int stk1160_probe(struct usb_interface *interface, const struct usb_device_id *id) { - int rc = 0; + int rc; unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ struct usb_device *udev; @@ -290,15 +290,13 @@ static int stk1160_probe(struct usb_interface *interface, * Also, check if device speed is fast enough. */ rc = stk1160_scan_usb(interface, udev, alt_max_pkt_size); - if (rc < 0) { - kfree(alt_max_pkt_size); - return rc; - } + if (rc < 0) + goto free_array; dev = kzalloc_obj(struct stk1160); if (dev == NULL) { - kfree(alt_max_pkt_size); - return -ENOMEM; + rc = -ENOMEM; + goto free_array; } dev->alt_max_pkt_size = alt_max_pkt_size; @@ -379,8 +377,9 @@ unreg_v4l2: free_ctrl: v4l2_ctrl_handler_free(&dev->ctrl_handler); free_err: - kfree(alt_max_pkt_size); kfree(dev); +free_array: + kfree(alt_max_pkt_size); return rc; } diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index f4baf9263286..020b75fc5b2d 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -48,6 +48,9 @@ static inline void print_err_status(struct stk1160 *dev, case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; + case -ESHUTDOWN: + errmsg = "host controller removed"; + break; case -ETIME: errmsg = "Device does not respond"; break; diff --git a/drivers/media/usb/usbtv/usbtv-audio.c b/drivers/media/usb/usbtv/usbtv-audio.c index 333bd305a4f9..ae0a14e5ed2a 100644 --- a/drivers/media/usb/usbtv/usbtv-audio.c +++ b/drivers/media/usb/usbtv/usbtv-audio.c @@ -317,6 +317,13 @@ static const struct snd_pcm_ops snd_usbtv_pcm_ops = { .pointer = snd_usbtv_pointer, }; +static void usbtv_audio_card_free(struct snd_card *card) +{ + struct usbtv *usbtv = card->private_data; + + v4l2_device_put(&usbtv->v4l2_dev); +} + int usbtv_audio_init(struct usbtv *usbtv) { int rv; @@ -331,6 +338,10 @@ int usbtv_audio_init(struct usbtv *usbtv) if (rv < 0) return rv; + v4l2_device_get(&usbtv->v4l2_dev); + card->private_data = usbtv; + card->private_free = usbtv_audio_card_free; + strscpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver)); strscpy(card->shortname, "usbtv", sizeof(card->shortname)); snprintf(card->longname, sizeof(card->longname), diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 6c4facf4f41a..4f10f6613bc4 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -119,7 +119,10 @@ usbtv_audio_fail: usbtv_video_fail: usb_set_intfdata(intf, NULL); - kfree(usbtv); + if (usbtv->v4l2_dev.dev) + v4l2_device_put(&usbtv->v4l2_dev); + else + kfree(usbtv); return ret; } diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index de0328100a60..92bc7a2509c3 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -949,13 +949,11 @@ int usbtv_video_init(struct usbtv *usbtv) ret = video_register_device(&usbtv->vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { dev_warn(usbtv->dev, "Could not register video device\n"); - goto vdev_fail; + return ret; } return 0; -vdev_fail: - v4l2_device_unregister(&usbtv->v4l2_dev); v4l2_fail: ctrl_fail: v4l2_ctrl_handler_free(&usbtv->ctrl); diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 888a2e213b08..460bf3dbbb88 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -392,7 +392,6 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, err_call_unbind: v4l2_async_nf_call_unbind(notifier, sd, asc); - list_del(&asc->asc_subdev_entry); err_unregister_subdev: if (registered) @@ -898,9 +897,18 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) sd->subdev_notifier = NULL; if (sd->asc_list.next) { - list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list, - asc_subdev_entry) { - v4l2_async_unbind_subdev_one(asc->notifier, asc); + if (list_empty(&sd->asc_list)) { + /* + * If the sub-device was registered through other means + * than v4l2-async, there are no async connections but + * the sub-device may still well be registered. + * Unregister it now. + */ + v4l2_device_unregister_subdev(sd); + } else { + list_for_each_entry_safe(asc, asc_tmp, &sd->asc_list, + asc_subdev_entry) + v4l2_async_unbind_subdev_one(asc->notifier, asc); } } diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index ba047d7d8601..5b8a594fb9e2 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -16,6 +16,9 @@ static const union v4l2_ctrl_ptr ptr_null; +#define V4L2_HEVC_MAX_SHORT_TERM_REF_PIC_SETS 64 +#define V4L2_HEVC_MAX_LONG_TERM_REF_PICS_SPS 32 + static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes) { @@ -1214,6 +1217,10 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_HEVC_SPS: p_hevc_sps = p; + if (p_hevc_sps->num_short_term_ref_pic_sets > + V4L2_HEVC_MAX_SHORT_TERM_REF_PIC_SETS) + return -EINVAL; + if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_PCM_ENABLED)) { p_hevc_sps->pcm_sample_bit_depth_luma_minus1 = 0; p_hevc_sps->pcm_sample_bit_depth_chroma_minus1 = 0; @@ -1224,6 +1231,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, if (!(p_hevc_sps->flags & V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT)) p_hevc_sps->num_long_term_ref_pics_sps = 0; + else if (p_hevc_sps->num_long_term_ref_pics_sps > + V4L2_HEVC_MAX_LONG_TERM_REF_PICS_SPS) + return -EINVAL; break; case V4L2_CTRL_TYPE_HEVC_PPS: @@ -1280,6 +1290,11 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, if (p_hevc_st_rps->flags & ~V4L2_HEVC_EXT_SPS_ST_RPS_FLAG_INTER_REF_PIC_SET_PRED) return -EINVAL; + if (p_hevc_st_rps->num_negative_pics > 16 || + p_hevc_st_rps->num_positive_pics > 16 || + p_hevc_st_rps->num_negative_pics + + p_hevc_st_rps->num_positive_pics > 16) + return -EINVAL; break; case V4L2_CTRL_TYPE_HEVC_EXT_SPS_LT_RPS: @@ -1307,24 +1322,41 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, 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) + /* + * SMPTE ST 2086 Annex A documents that CTA 861-G uses + * (0, 0) to indicate that the white point chromaticity + * is unknown. + */ + if (p_hdr10_mastering->white_point_x || + p_hdr10_mastering->white_point_y) { + 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; + } + + /* + * SMPTE ST 2086 Annex A documents that CTA 861-G uses zero + * maximum and minimum luminance values to indicate that + * the corresponding values are unknown. + */ + if (p_hdr10_mastering->max_display_mastering_luminance && + (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)) 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) + if (p_hdr10_mastering->min_display_mastering_luminance && + (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 */ diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 5516b2bbb08f..fd267fb74905 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -1071,25 +1071,39 @@ int __video_register_device(struct video_device *vdev, vdev->dev.class = &video_class; vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); vdev->dev.parent = vdev->dev_parent; - vdev->dev.release = v4l2_device_release; dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); - - /* Increase v4l2_device refcount */ - v4l2_device_get(vdev->v4l2_dev); - mutex_lock(&videodev_lock); ret = device_register(&vdev->dev); if (ret < 0) { + /* + * We should do a put_device() here, but the problem is that + * the V4L2 API expects drivers to call video_device_release() + * on error, and so both put_device() and video_device_release + * would kfree vdev. + * + * The proper solution would be to split this function into + * two parts: initialization and registration, and then rework + * all drivers. + * + * Until then just skip the put_device and free everything. + * This will result in a small memory leak, which is better + * than a double-free. + */ mutex_unlock(&videodev_lock); pr_err("%s: device_register failed\n", __func__); - put_device(&vdev->dev); - return ret; + goto cleanup; } + /* Register the release callback that will be called when the last + reference to the device goes away. */ + vdev->dev.release = v4l2_device_release; if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) pr_warn("%s: requested %s%d, got %s\n", __func__, name_base, nr, video_device_node_name(vdev)); + /* Increase v4l2_device refcount */ + v4l2_device_get(vdev->v4l2_dev); + /* Part 5: Register the entity. */ ret = video_register_media_controller(vdev); diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 62a3a452f788..570df3c415b0 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -633,6 +633,8 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, if (!link->remote_node) goto err_put_remote_endpoint; + fwnode_handle_put(fwnode); + return 0; err_put_remote_endpoint: diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index a2b650f4ec3c..17ba1ae70735 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1471,6 +1471,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_META_FMT_C3ISP_STATS: descr = "Amlogic C3 ISP Statistics"; break; case V4L2_META_FMT_MALI_C55_PARAMS: descr = "ARM Mali-C55 ISP Parameters"; break; case V4L2_META_FMT_MALI_C55_STATS: descr = "ARM Mali-C55 ISP 3A Statistics"; break; + case V4L2_META_FMT_RPPX1_PARAMS: descr = "Dreamchip RPP-X1 ISP Parameters"; break; + case V4L2_META_FMT_RPPX1_STATS: descr = "Dreamchip RPP-X1 ISP Statistics"; break; case V4L2_PIX_FMT_NV12_8L128: descr = "NV12 (8x128 Linear)"; break; case V4L2_PIX_FMT_NV12M_8L128: descr = "NV12M (8x128 Linear)"; break; case V4L2_PIX_FMT_NV12_10BE_8L128: descr = "10-bit NV12 (8x128 Linear, BE)"; break; diff --git a/drivers/media/v4l2-core/v4l2-isp.c b/drivers/media/v4l2-core/v4l2-isp.c index 29831f7032e9..1eb46e080afa 100644 --- a/drivers/media/v4l2-core/v4l2-isp.c +++ b/drivers/media/v4l2-core/v4l2-isp.c @@ -114,6 +114,9 @@ int v4l2_isp_params_validate_buffer(struct device *dev, struct vb2_buffer *vb, return -EINVAL; } + if (info->block_validate && info->block_validate(dev, block)) + return -EINVAL; + block_offset += block->size; buffer_size -= block->size; } @@ -127,6 +130,58 @@ int v4l2_isp_params_validate_buffer(struct device *dev, struct vb2_buffer *vb, } EXPORT_SYMBOL_GPL(v4l2_isp_params_validate_buffer); +void v4l2_isp_stats_init_buffer(struct v4l2_isp_buffer *buf, + enum v4l2_isp_version version) +{ + if (WARN_ON(!buf)) + return; + + if (WARN_ON(version > V4L2_ISP_VERSION_V1)) + return; + + buf->version = version; + buf->data_size = 0; +} +EXPORT_SYMBOL_GPL(v4l2_isp_stats_init_buffer); + +struct v4l2_isp_block_header * +v4l2_isp_stats_init_block(struct device *dev, struct v4l2_isp_buffer *buf, + const struct v4l2_isp_stats_block_type_info *type_info, + size_t num_block_types, unsigned int block_type, + size_t max_size) +{ + const struct v4l2_isp_stats_block_type_info *block_info; + struct v4l2_isp_block_header *header; + size_t used; + + if (WARN_ON(!dev || !buf || !type_info)) + return ERR_PTR(-EINVAL); + + if (block_type >= num_block_types) { + dev_err(dev, "Invalid block type %u\n", block_type); + return ERR_PTR(-EINVAL); + } + + block_info = &type_info[block_type]; + used = buf->data_size; + + if (used + block_info->size > max_size) { + dev_err(dev, "No space for stats block type %u of size %zu\n", + block_type, block_info->size); + return ERR_PTR(-ENOMEM); + } + + buf->data_size += block_info->size; + + header = (struct v4l2_isp_block_header *)&buf->data[used]; + header->type = block_type; + header->size = block_info->size; + header->flags = 0; + + return header; +} +EXPORT_SYMBOL_GPL(v4l2_isp_stats_init_block); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jacopo Mondi <jacopo.mondi@ideasonboard.com"); MODULE_DESCRIPTION("V4L2 generic ISP parameters and statistics helpers"); diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c index 115bb37577a1..6c729fcfce5d 100644 --- a/drivers/platform/x86/intel/int3472/discrete.c +++ b/drivers/platform/x86/intel/int3472/discrete.c @@ -123,10 +123,31 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472, return desc; } +/* + * Other vana-supply users (e.g. ST, Toshiba, Sony sensors) can be added to + * this array instead of adding new quirk table entries. + */ +static const char * const power_enable_hids_vana[] = { + "SONY471A", /* imx471 on Lenovo X9-14 and X9-15 */ + "TBE20A0", /* imx471 on Lenovo X1 Carbon G14 */ + NULL +}; + +static const char * const power_enable_hids_vdd[] = { + "INT33F0", /* mt9m114 */ + NULL +}; + +static const char * const power_enable_hids_enable[] = { + "INT347E", /* ov7251 */ + NULL +}; + /** * struct int3472_gpio_map - Map GPIOs to whatever is expected by the * sensor driver (as in DT bindings) - * @hid: The ACPI HID of the device without the instance number e.g. INT347E + * @hids: NULL-terminated array of ACPI HIDs of the devices without the + * instance number e.g. INT347E * @type_from: The GPIO type from ACPI ?SDT * @type_to: The assigned GPIO type, typically same as @type_from * @enable_time_us: Enable time in usec for GPIOs mapped to regulators @@ -135,7 +156,7 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472, * GPIO_ACTIVE_HIGH otherwise */ struct int3472_gpio_map { - const char *hid; + const char * const *hids; u8 type_from; u8 type_to; bool polarity_low; @@ -145,27 +166,45 @@ struct int3472_gpio_map { static const struct int3472_gpio_map int3472_gpio_map[] = { { /* mt9m114 designs declare a powerdown pin which controls the regulators */ - .hid = "INT33F0", + .hids = power_enable_hids_vdd, .type_from = INT3472_GPIO_TYPE_POWERDOWN, .type_to = INT3472_GPIO_TYPE_POWER_ENABLE, .con_id = "vdd", .enable_time_us = GPIO_REGULATOR_ENABLE_TIME, }, { /* ov7251 driver / DT-bindings expect "enable" as con_id for reset */ - .hid = "INT347E", + .hids = power_enable_hids_enable, .type_from = INT3472_GPIO_TYPE_RESET, .type_to = INT3472_GPIO_TYPE_RESET, .con_id = "enable", }, { /* ov08x40's handshake pin needs a 45 ms delay on some HP laptops */ - .hid = "OVTI08F4", + .hids = (const char * const[]) { "OVTI08F4", NULL }, .type_from = INT3472_GPIO_TYPE_HANDSHAKE, .type_to = INT3472_GPIO_TYPE_HANDSHAKE, .con_id = "dvdd", .enable_time_us = 45 * USEC_PER_MSEC, }, + { /* Sensors which expect "vana" as con_id for power enable */ + .hids = power_enable_hids_vana, + .type_from = INT3472_GPIO_TYPE_POWER_ENABLE, + .type_to = INT3472_GPIO_TYPE_POWER_ENABLE, + .con_id = "vana", + .enable_time_us = GPIO_REGULATOR_ENABLE_TIME, + }, }; +static bool int3472_gpio_map_hids_match(struct acpi_device *adev, + const char * const *hids) +{ + for (unsigned int i = 0; hids[i]; i++) { + if (acpi_dev_hid_uid_match(adev, hids[i], NULL)) + return true; + } + + return false; +} + static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3472, u8 *type, const char **con_id, unsigned long *gpio_flags, unsigned int *enable_time_us) @@ -182,7 +221,7 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3 if (*type != int3472_gpio_map[i].type_from) continue; - if (!acpi_dev_hid_uid_match(adev, int3472_gpio_map[i].hid, NULL)) + if (!int3472_gpio_map_hids_match(adev, int3472_gpio_map[i].hids)) continue; dev_dbg(int3472->dev, "mapping type 0x%02x pin to 0x%02x %s\n", diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h index 4732b45b25ee..fbcd73b711ba 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf.h @@ -20,7 +20,7 @@ * Data structures. * ****************************************************************/ -/** +/* * @brief Data structure for the circular buffer. */ typedef struct ia_css_circbuf_s ia_css_circbuf_t; @@ -29,7 +29,7 @@ struct ia_css_circbuf_s { ia_css_circbuf_elem_t *elems; /* an array of elements */ }; -/** +/* * @brief Create the circular buffer. * * @param cb The pointer to the circular buffer. @@ -41,7 +41,7 @@ void ia_css_circbuf_create( ia_css_circbuf_elem_t *elems, ia_css_circbuf_desc_t *desc); -/** +/* * @brief Destroy the circular buffer. * * @param cb The pointer to the circular buffer. @@ -49,7 +49,7 @@ void ia_css_circbuf_create( void ia_css_circbuf_destroy( ia_css_circbuf_t *cb); -/** +/* * @brief Pop a value out of the circular buffer. * Get a value at the head of the circular buffer. * The user should call "ia_css_circbuf_is_empty()" @@ -62,7 +62,7 @@ void ia_css_circbuf_destroy( uint32_t ia_css_circbuf_pop( ia_css_circbuf_t *cb); -/** +/* * @brief Extract a value out of the circular buffer. * Get a value at an arbitrary position in the circular * buffer. The user should call "ia_css_circbuf_is_empty()" @@ -82,7 +82,7 @@ uint32_t ia_css_circbuf_extract( * Inline functions. * ****************************************************************/ -/** +/* * @brief Set the "val" field in the element. * * @param elem The pointer to the element. @@ -97,7 +97,7 @@ static inline void ia_css_circbuf_elem_set_val( elem->val = val; } -/** +/* * @brief Initialize the element. * * @param elem The pointer to the element. @@ -109,7 +109,7 @@ static inline void ia_css_circbuf_elem_init( ia_css_circbuf_elem_set_val(elem, 0); } -/** +/* * @brief Copy an element. * * @param src The element as the copy source. @@ -125,7 +125,7 @@ static inline void ia_css_circbuf_elem_cpy( ia_css_circbuf_elem_set_val(dest, src->val); } -/** +/* * @brief Get position in the circular buffer. * * @param cb The pointer to the circular buffer. @@ -151,7 +151,7 @@ static inline uint8_t ia_css_circbuf_get_pos_at_offset( return (base + offset) % cb->desc->size; } -/** +/* * @brief Get the offset between two positions in the circular buffer. * Get the offset from the source position to the terminal position, * along the direction in which the new elements come in. @@ -178,7 +178,7 @@ static inline int ia_css_circbuf_get_offset( return offset; } -/** +/* * @brief Get the maximum number of elements. * * @param cb The pointer to the circular buffer. @@ -196,7 +196,7 @@ static inline uint32_t ia_css_circbuf_get_size( return cb->desc->size; } -/** +/* * @brief Get the number of available elements. * * @param cb The pointer to the circular buffer. @@ -216,7 +216,7 @@ static inline uint32_t ia_css_circbuf_get_num_elems( return (uint32_t)num; } -/** +/* * @brief Test if the circular buffer is empty. * * @param cb The pointer to the circular buffer. @@ -234,7 +234,7 @@ static inline bool ia_css_circbuf_is_empty( return ia_css_circbuf_desc_is_empty(cb->desc); } -/** +/* * @brief Test if the circular buffer is full. * * @param cb The pointer to the circular buffer. @@ -251,7 +251,7 @@ static inline bool ia_css_circbuf_is_full(ia_css_circbuf_t *cb) return ia_css_circbuf_desc_is_full(cb->desc); } -/** +/* * @brief Write a new element into the circular buffer. * Write a new element WITHOUT checking whether the * circular buffer is full or not. So it also overwrites @@ -275,7 +275,7 @@ static inline void ia_css_circbuf_write( cb->desc->end = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, 1); } -/** +/* * @brief Push a value in the circular buffer. * Put a new value at the tail of the circular buffer. * The user should call "ia_css_circbuf_is_full()" @@ -300,7 +300,7 @@ static inline void ia_css_circbuf_push( ia_css_circbuf_write(cb, elem); } -/** +/* * @brief Get the number of free elements. * * @param cb The pointer to the circular buffer. @@ -316,7 +316,7 @@ static inline uint32_t ia_css_circbuf_get_free_elems( return ia_css_circbuf_desc_get_free_elems(cb->desc); } -/** +/* * @brief Peek an element in Circular Buffer. * * @param cb The pointer to the circular buffer. @@ -328,7 +328,7 @@ uint32_t ia_css_circbuf_peek( ia_css_circbuf_t *cb, int offset); -/** +/* * @brief Get an element in Circular Buffer. * * @param cb The pointer to the circular buffer. @@ -340,7 +340,7 @@ uint32_t ia_css_circbuf_peek_from_start( ia_css_circbuf_t *cb, int offset); -/** +/* * @brief Increase Size of a Circular Buffer. * Use 'CAUTION' before using this function, This was added to * support / fix issue with increasing size for tagger only diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h index 971e07f2acc5..090e2e764042 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h @@ -24,7 +24,7 @@ * Portable Data structures * ****************************************************************/ -/** +/* * @brief Data structure for the circular descriptor. */ typedef struct ia_css_circbuf_desc_s ia_css_circbuf_desc_t; @@ -40,7 +40,7 @@ struct ia_css_circbuf_desc_s { static_assert(sizeof(struct ia_css_circbuf_desc_s) == SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT); -/** +/* * @brief Data structure for the circular buffer element. */ typedef struct ia_css_circbuf_elem_s ia_css_circbuf_elem_t; diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h index 64f754f1d49b..3306a7a0fa5e 100644 --- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h +++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_desc.h @@ -17,7 +17,7 @@ * Inline functions. * ****************************************************************/ -/** +/* * @brief Test if the circular buffer is empty. * * @param cb_desc The pointer to the circular buffer descriptor. @@ -33,7 +33,7 @@ static inline bool ia_css_circbuf_desc_is_empty( return (cb_desc->end == cb_desc->start); } -/** +/* * @brief Test if the circular buffer descriptor is full. * * @param cb_desc The pointer to the circular buffer @@ -50,7 +50,7 @@ static inline bool ia_css_circbuf_desc_is_full( return ((cb_desc->end + 1) % cb_desc->size) == cb_desc->start; } -/** +/* * @brief Initialize the circular buffer descriptor * * @param cb_desc The pointer circular buffer descriptor @@ -64,7 +64,7 @@ static inline void ia_css_circbuf_desc_init( cb_desc->size = size; } -/** +/* * @brief Get a position in the circular buffer descriptor. * * @param cb The pointer to the circular buffer descriptor. @@ -89,7 +89,7 @@ static inline uint8_t ia_css_circbuf_desc_get_pos_at_offset( return (base + offset) % cb_desc->size; } -/** +/* * @brief Get the offset between two positions in the circular buffer * descriptor. * Get the offset from the source position to the terminal position, @@ -116,7 +116,7 @@ static inline int ia_css_circbuf_desc_get_offset( return offset; } -/** +/* * @brief Get the number of available elements. * * @param cb_desc The pointer to the circular buffer. @@ -137,7 +137,7 @@ static inline uint32_t ia_css_circbuf_desc_get_num_elems( return (uint32_t)num; } -/** +/* * @brief Get the number of free elements. * * @param cb_desc The pointer to the circular buffer descriptor. diff --git a/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h b/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h index 24cd99a659ca..dce8dd23b47c 100644 --- a/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h +++ b/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h @@ -81,7 +81,7 @@ bool ia_css_util_res_leq( struct ia_css_resolution b); /* ISP2401 */ -/** +/* * @brief Check if resolution is zero * * @param[in] resolution The resolution to check diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h index 989f55bec519..43bb352a8e05 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/csi_rx_private.h @@ -21,7 +21,7 @@ * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Refer to "csi_rx_public.h" for details. */ @@ -35,7 +35,7 @@ static inline hrt_data csi_rx_fe_ctrl_reg_load( hrt_data)); } -/** +/* * @brief Store a value to the register. * Refer to "ibuf_ctrl_public.h" for details. */ @@ -51,7 +51,7 @@ static inline void csi_rx_fe_ctrl_reg_store( value); } -/** +/* * @brief Load the register value. * Refer to "csi_rx_public.h" for details. */ @@ -65,7 +65,7 @@ static inline hrt_data csi_rx_be_ctrl_reg_load( hrt_data)); } -/** +/* * @brief Store a value to the register. * Refer to "ibuf_ctrl_public.h" for details. */ @@ -88,7 +88,7 @@ static inline void csi_rx_be_ctrl_reg_store( * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the state of the csi rx fe dlane process. * Refer to "csi_rx_public.h" for details. */ @@ -103,7 +103,7 @@ static inline void csi_rx_fe_ctrl_get_dlane_state( csi_rx_fe_ctrl_reg_load(ID, _HRT_CSI_RX_DLY_CNT_SETTLE_DLANE_REG_IDX(lane)); } -/** +/* * @brief Get the csi rx fe state. * Refer to "csi_rx_public.h" for details. */ @@ -142,7 +142,7 @@ static inline void csi_rx_fe_ctrl_get_state( } } -/** +/* * @brief dump the csi rx fe state. * Refer to "csi_rx_public.h" for details. */ @@ -180,7 +180,7 @@ static inline void csi_rx_fe_ctrl_dump_state( } } -/** +/* * @brief Get the csi rx be state. * Refer to "csi_rx_public.h" for details. */ @@ -243,7 +243,7 @@ static inline void csi_rx_be_ctrl_get_state( } } -/** +/* * @brief Dump the csi rx be state. * Refer to "csi_rx_public.h" for details. */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h index 4bd8209aaa01..85439d561ba3 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_irq_private.h @@ -15,7 +15,7 @@ | Native command interface (NCI) | + -------------------------------------------------------*/ -/** +/* * @brief Get the isys irq status. * Refer to "isys_irq.h" for details. */ @@ -34,7 +34,7 @@ void isys_irqc_state_get( */ } -/** +/* * @brief Dump the isys irq status. * Refer to "isys_irq.h" for details. */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h index 8e295cd78129..88a763365631 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/isys_stream2mmio_private.h @@ -27,7 +27,7 @@ * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the stream2mmio-controller state. * Refer to "stream2mmio_public.h" for details. */ @@ -45,7 +45,7 @@ STORAGE_CLASS_STREAM2MMIO_C void stream2mmio_get_state( stream2mmio_get_sid_state(ID, i, &state->sid_state[i]); } -/** +/* * @brief Get the state of the stream2mmio-controller sidess. * Refer to "stream2mmio_public.h" for details. */ @@ -76,7 +76,7 @@ STORAGE_CLASS_STREAM2MMIO_C void stream2mmio_get_sid_state( stream2mmio_reg_load(ID, sid_id, STREAM2MMIO_BLOCK_WHEN_NO_CMD_REG_ID); } -/** +/* * @brief Dump the state of the stream2mmio-controller sidess. * Refer to "stream2mmio_public.h" for details. */ @@ -92,7 +92,7 @@ STORAGE_CLASS_STREAM2MMIO_C void stream2mmio_print_sid_state( ia_css_print("\t \t block when no cmd 0x%x\n", state->block_when_no_cmd); } -/** +/* * @brief Dump the ibuf-controller state. * Refer to "stream2mmio_public.h" for details. */ @@ -119,7 +119,7 @@ STORAGE_CLASS_STREAM2MMIO_C void stream2mmio_dump_state( * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Refer to "stream2mmio_public.h" for details. */ @@ -137,7 +137,7 @@ STORAGE_CLASS_STREAM2MMIO_C hrt_data stream2mmio_reg_load( (reg_bank_offset + reg_idx) * sizeof(hrt_data)); } -/** +/* * @brief Store a value to the register. * Refer to "stream2mmio_public.h" for details. */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h index b8b98106bd31..0faf6ffdf55d 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/host/pixelgen_private.h @@ -16,7 +16,7 @@ * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Refer to "pixelgen_public.h" for details. */ @@ -30,7 +30,7 @@ STORAGE_CLASS_PIXELGEN_C hrt_data pixelgen_ctrl_reg_load( hrt_data)); } -/** +/* * @brief Store a value to the register. * Refer to "pixelgen_ctrl_public.h" for details. */ @@ -53,7 +53,7 @@ STORAGE_CLASS_PIXELGEN_C void pixelgen_ctrl_reg_store( * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the pixelgen state. * Refer to "pixelgen_public.h" for details. */ @@ -117,7 +117,7 @@ STORAGE_CLASS_PIXELGEN_C void pixelgen_ctrl_get_state( pixelgen_ctrl_reg_load(ID, _PXG_TPG_B2_REG_IDX); } -/** +/* * @brief Dump the pixelgen state. * Refer to "pixelgen_public.h" for details. */ diff --git a/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h b/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h index 59e0b44bfdc3..b5a6a8f0c3d2 100644 --- a/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h +++ b/drivers/staging/media/atomisp/pci/css_2401_system/pixelgen_global.h @@ -9,7 +9,7 @@ #include <type_support.h> -/** +/* * Pixel-generator. ("pixelgen_global.h") */ /* diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h index 2dc0fb88399f..e4c136660b1e 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/timed_ctrl_global.h @@ -11,7 +11,7 @@ #include "timed_controller_defs.h" -/** +/* * Order of the input bits for the timed controller taken from * ISP_CSS_2401 System Architecture Description valid for * 2400, 2401. diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h index ca33a1e03d8d..f5b0ff414395 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/device_access/device_access.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h index 2002960f078e..e8ce556bfd6a 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/csi_rx_public.h @@ -12,7 +12,7 @@ * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the csi rx frontend state. * Get the state of the csi rx frontend regiester-set. * @@ -22,7 +22,7 @@ void csi_rx_fe_ctrl_get_state( const csi_rx_frontend_ID_t ID, csi_rx_fe_ctrl_state_t *state); -/** +/* * @brief Dump the csi rx frontend state. * Dump the state of the csi rx frontend regiester-set. * @@ -32,7 +32,7 @@ void csi_rx_fe_ctrl_get_state( void csi_rx_fe_ctrl_dump_state( const csi_rx_frontend_ID_t ID, csi_rx_fe_ctrl_state_t *state); -/** +/* * @brief Get the state of the csi rx fe dlane. * Get the state of the register set per dlane process. * @@ -44,7 +44,7 @@ void csi_rx_fe_ctrl_get_dlane_state( const csi_rx_frontend_ID_t ID, const u32 lane, csi_rx_fe_ctrl_lane_t *dlane_state); -/** +/* * @brief Get the csi rx backend state. * Get the state of the csi rx backend regiester-set. * @@ -54,7 +54,7 @@ void csi_rx_fe_ctrl_get_dlane_state( void csi_rx_be_ctrl_get_state( const csi_rx_backend_ID_t ID, csi_rx_be_ctrl_state_t *state); -/** +/* * @brief Dump the csi rx backend state. * Dump the state of the csi rx backend regiester-set. * @@ -71,7 +71,7 @@ void csi_rx_be_ctrl_dump_state( * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Load the value of the register of the csi rx fe. * @@ -83,7 +83,7 @@ void csi_rx_be_ctrl_dump_state( hrt_data csi_rx_fe_ctrl_reg_load( const csi_rx_frontend_ID_t ID, const hrt_address reg); -/** +/* * @brief Store a value to the register. * Store a value to the register of the csi rx fe. * @@ -96,7 +96,7 @@ void csi_rx_fe_ctrl_reg_store( const csi_rx_frontend_ID_t ID, const hrt_address reg, const hrt_data value); -/** +/* * @brief Load the register value. * Load the value of the register of the csirx be. * @@ -108,7 +108,7 @@ void csi_rx_fe_ctrl_reg_store( hrt_data csi_rx_be_ctrl_reg_load( const csi_rx_backend_ID_t ID, const hrt_address reg); -/** +/* * @brief Store a value to the register. * Store a value to the register of the csi rx be. * diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h index 7ed55d427cf6..e4f77e975f4e 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/isys_stream2mmio_public.h @@ -12,7 +12,7 @@ * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the stream2mmio-controller state. * Get the state of the stream2mmio-controller regiester-set. * @@ -23,7 +23,7 @@ STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_get_state( const stream2mmio_ID_t ID, stream2mmio_state_t *state); -/** +/* * @brief Get the state of the stream2mmio-controller sidess. * Get the state of the register set per buf-controller sidess. * @@ -42,7 +42,7 @@ STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_get_sid_state( * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Load the value of the register of the stream2mmio-controller. * @@ -57,7 +57,7 @@ STORAGE_CLASS_STREAM2MMIO_H hrt_data stream2mmio_reg_load( const stream2mmio_sid_ID_t sid_id, const uint32_t reg_idx); -/** +/* * @brief Dump the SID processor state. * Dump the state of the sid regiester-set. * @@ -65,7 +65,7 @@ STORAGE_CLASS_STREAM2MMIO_H hrt_data stream2mmio_reg_load( */ STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_print_sid_state( stream2mmio_sid_state_t *state); -/** +/* * @brief Dump the stream2mmio state. * Dump the state of the ibuf-controller regiester-set. * @@ -75,7 +75,7 @@ STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_print_sid_state( STORAGE_CLASS_STREAM2MMIO_H void stream2mmio_dump_state( const stream2mmio_ID_t ID, stream2mmio_state_t *state); -/** +/* * @brief Store a value to the register. * Store a value to the registe of the stream2mmio-controller. * diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h index dc31ce3cd741..6aabf0b1995f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/pixelgen_public.h @@ -12,7 +12,7 @@ * Native command interface (NCI). * *****************************************************/ -/** +/* * @brief Get the pixelgen state. * Get the state of the pixelgen regiester-set. * @@ -22,7 +22,7 @@ STORAGE_CLASS_PIXELGEN_H void pixelgen_ctrl_get_state( const pixelgen_ID_t ID, pixelgen_ctrl_state_t *state); -/** +/* * @brief Dump the pixelgen state. * Dump the state of the pixelgen regiester-set. * @@ -39,7 +39,7 @@ STORAGE_CLASS_PIXELGEN_H void pixelgen_ctrl_dump_state( * Device level interface (DLI). * *****************************************************/ -/** +/* * @brief Load the register value. * Load the value of the register of the pixelgen * @@ -51,7 +51,7 @@ STORAGE_CLASS_PIXELGEN_H void pixelgen_ctrl_dump_state( STORAGE_CLASS_PIXELGEN_H hrt_data pixelgen_ctrl_reg_load( const pixelgen_ID_t ID, const hrt_address reg); -/** +/* * @brief Store a value to the register. * Store a value to the registe of the pixelgen * diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h index ad83ff97bbd6..1652c9f79349 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/tag_public.h @@ -7,7 +7,7 @@ #ifndef __TAG_PUBLIC_H_INCLUDED__ #define __TAG_PUBLIC_H_INCLUDED__ -/** +/* * @brief Creates the tag description from the given parameters. * @param[in] num_captures * @param[in] skip @@ -21,7 +21,7 @@ sh_css_create_tag_descr(int num_captures, unsigned int exp_id, struct sh_css_tag_descr *tag_descr); -/** +/* * @brief Encodes the members of tag description into a 32-bit value. * @param[in] tag Pointer to the tag description * @return (unsigned int) Encoded 32-bit tag-info diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h index 473d8d4fb9ba..20a5faad0716 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/platform_support.h @@ -7,7 +7,7 @@ #ifndef __PLATFORM_SUPPORT_H_INCLUDED__ #define __PLATFORM_SUPPORT_H_INCLUDED__ -/** +/* * @file * Platform specific includes and functionality. */ diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h index 097be6bd3cb5..cbd290121a28 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h @@ -7,7 +7,7 @@ #ifndef __TYPE_SUPPORT_H_INCLUDED__ #define __TYPE_SUPPORT_H_INCLUDED__ -/** +/* * @file * Platform specific types. * diff --git a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h index 7acfedb541d8..936b17950b3a 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_frame_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_frame_public.h @@ -119,7 +119,7 @@ struct ia_css_frame_info { .raw_bayer_order = IA_CSS_BAYER_ORDER_NUM, \ } -/** +/* * Specifies the DVS loop delay in "frame periods" */ enum ia_css_frame_delay { diff --git a/drivers/staging/media/atomisp/pci/ia_css_host_data.h b/drivers/staging/media/atomisp/pci/ia_css_host_data.h index 0e45650cc1ab..547542577902 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_host_data.h +++ b/drivers/staging/media/atomisp/pci/ia_css_host_data.h @@ -10,7 +10,7 @@ #include <ia_css_types.h> /* ia_css_pipe */ -/** +/* * @brief Allocate structure ia_css_host_data. * * @param[in] size Size of the requested host data @@ -22,7 +22,7 @@ struct ia_css_host_data * ia_css_host_data_allocate(size_t size); -/** +/* * @brief Free structure ia_css_host_data. * * @param[in] me Pointer to structure, if a NULL is passed functions diff --git a/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h b/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h index 2bb06b0ff5db..1d1b704b2bc6 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_pipe_public.h @@ -44,7 +44,7 @@ enum ia_css_pipe_mode { /* Temporary define */ #define IA_CSS_PIPE_MODE_NUM (IA_CSS_PIPE_MODE_YUVPP + 1) -/** +/* * Enumeration of pipe versions. * the order should match with definition in sh_css_defs.h */ @@ -55,7 +55,7 @@ enum ia_css_pipe_version { IA_CSS_PIPE_VERSION_2_7 = 4 /** ISP2.7 pipe */ }; -/** +/* * Pipe configuration structure. * Resolution properties are filled by Driver, kernel configurations are * set by AIC @@ -123,7 +123,7 @@ struct ia_css_pipe_config { to retrieve shading gains which correspond to bayer data. */ }; -/** +/* * Default settings for newly created pipe configurations. */ #define DEFAULT_PIPE_CONFIG { \ @@ -175,7 +175,7 @@ struct ia_css_pipe_info { output at the first valid frame. */ }; -/** +/* * Defaults for ia_css_pipe_info structs. */ #define DEFAULT_PIPE_INFO {\ diff --git a/drivers/staging/media/atomisp/pci/ia_css_prbs.h b/drivers/staging/media/atomisp/pci/ia_css_prbs.h index abdbcb8fda53..3bb1e5dbb4fc 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_prbs.h +++ b/drivers/staging/media/atomisp/pci/ia_css_prbs.h @@ -19,7 +19,7 @@ enum ia_css_prbs_id { IA_CSS_PRBS_ID2 }; -/** +/* * Maximum number of PRBS IDs. * * Make sure the value of this define gets changed to reflect the correct @@ -27,7 +27,7 @@ enum ia_css_prbs_id { */ #define N_CSS_PRBS_IDS (IA_CSS_PRBS_ID2 + 1) -/** +/* * PRBS configuration structure. * * Seed the for the Pseudo Random Bit Sequence. diff --git a/drivers/staging/media/atomisp/pci/ia_css_stream.h b/drivers/staging/media/atomisp/pci/ia_css_stream.h index c8de632a8e12..578dc45785fc 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_stream.h +++ b/drivers/staging/media/atomisp/pci/ia_css_stream.h @@ -13,7 +13,7 @@ #include "ia_css_types.h" #include "ia_css_stream_public.h" -/** +/* * structure to hold all internal stream related information */ struct ia_css_stream { diff --git a/drivers/staging/media/atomisp/pci/ia_css_timer.h b/drivers/staging/media/atomisp/pci/ia_css_timer.h index da752834adf4..5c73e8c61588 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_timer.h +++ b/drivers/staging/media/atomisp/pci/ia_css_timer.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. @@ -42,7 +42,10 @@ struct ia_css_time_meas { clock_value_t end_timer_value; /** measured time in ticks */ }; -/**@brief SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT checks to ensure correct alignment for struct ia_css_clock_tick. */ +/* + * @brief SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT checks to ensure correct alignment + * for struct ia_css_clock_tick. + */ #define SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT sizeof(clock_value_t) /* @brief checks to ensure correct alignment for ia_css_time_meas. */ #define SIZE_OF_IA_CSS_TIME_MEAS_STRUCT (sizeof(clock_value_t) \ diff --git a/drivers/staging/media/atomisp/pci/ia_css_types.h b/drivers/staging/media/atomisp/pci/ia_css_types.h index 2b7db9cda23a..7065eded7a33 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_types.h +++ b/drivers/staging/media/atomisp/pci/ia_css_types.h @@ -53,7 +53,7 @@ #include "isp/kernels/output/output_1.0/ia_css_output_types.h" #define IA_CSS_DVS_STAT_GRID_INFO_SUPPORTED -/** Should be removed after Driver adaptation will be done */ +/* Should be removed after Driver adaptation will be done */ #define IA_CSS_VERSION_MAJOR 2 #define IA_CSS_VERSION_MINOR 0 @@ -421,7 +421,7 @@ struct ia_css_dvs_6axis_config { u32 *ycoords_uv; }; -/** +/* * This specifies the coordinates (x,y) */ struct ia_css_point { @@ -429,7 +429,7 @@ struct ia_css_point { s32 y; /** y coordinate */ }; -/** +/* * Digital zoom: * This feature is currently available only for video, but will become * available for preview and capture as well. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h index 374261d25520..ee2cf2877b7d 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/conversion/conversion_1.0/ia_css_conversion_types.h @@ -7,7 +7,7 @@ #ifndef __IA_CSS_CONVERSION_TYPES_H #define __IA_CSS_CONVERSION_TYPES_H -/** +/* * Conversion Kernel parameters. * Deinterleave bayer quad into isys format * diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h index 0b977eb7ad71..bbd97c71a6fd 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8_types.h @@ -13,7 +13,7 @@ #include "type_support.h" -/** +/* * \brief EED1_8 public parameters. * \details Struct with all parameters for the EED1.8 kernel that can be set * from the CSS API. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h index e32290d1c86b..d6785724fe97 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/hdr/ia_css_hdr_types.h @@ -10,44 +10,46 @@ #define IA_CSS_HDR_MAX_NUM_INPUT_FRAMES (3) -/** +/* * \brief HDR Irradiance Parameters * \detail Currently HDR parameters are used only for testing purposes */ struct ia_css_hdr_irradiance_params { - int test_irr; /** Test parameter */ - int match_shift[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Histogram matching shift parameter */ - int match_mul[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Histogram matching multiplication parameter */ - int thr_low[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Weight map soft threshold low bound parameter */ - int thr_high[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Weight map soft threshold high bound parameter */ - int thr_coeff[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Soft threshold linear function coefficien */ - int thr_shift[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - - 1]; /** Soft threshold precision shift parameter */ - int weight_bpp; /** Weight map bits per pixel */ + /* Test parameter */ + int test_irr; + /* Histogram matching shift parameter */ + int match_shift[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Histogram matching multiplication parameter */ + int match_mul[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Weight map soft threshold low bound parameter */ + int thr_low[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Weight map soft threshold high bound parameter */ + int thr_high[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Soft threshold linear function coefficien */ + int thr_coeff[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Soft threshold precision shift parameter */ + int thr_shift[IA_CSS_HDR_MAX_NUM_INPUT_FRAMES - 1]; + /* Weight map bits per pixel */ + int weight_bpp; }; -/** +/* * \brief HDR Deghosting Parameters * \detail Currently HDR parameters are used only for testing purposes */ struct ia_css_hdr_deghost_params { - int test_deg; /** Test parameter */ + int test_deg; /* Test parameter */ }; -/** +/* * \brief HDR Exclusion Parameters * \detail Currently HDR parameters are used only for testing purposes */ struct ia_css_hdr_exclusion_params { - int test_excl; /** Test parameter */ + int test_excl; /* Test parameter */ }; -/** +/* * \brief HDR public parameters. * \details Struct with all parameters for HDR that can be seet from * the CSS API. Currently, only test parameters are defined. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h index c9a3f7bfaa90..de535503b70e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_param.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h index c1c93b2245c5..69a40a15264b 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/common/ia_css_common_io_types.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h index e6ce0cba44b9..72310781cf7e 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io.host.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h index 429fcdb73f60..9fabb8b2d3b8 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_param.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h index 485ad17cb29b..1daafd96a0cd 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/ipu2_io_ls/yuv444_io_ls/ia_css_yuv444_io_types.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h index 42b760ffac67..676a633336a2 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/tnr/tnr3/ia_css_tnr3_types.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. @@ -12,7 +12,7 @@ Copyright (c) 2010 - 2015, Intel Corporation. * CSS-API header file for Temporal Noise Reduction v3 (TNR3) kernel */ -/** +/* * \brief Number of piecewise linear segments. * \details The parameters to TNR3 are specified as a piecewise linear segment. * The number of such segments is fixed at 3. diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h index c012c1865d1e..fc4b9033951c 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3_types.h @@ -11,25 +11,25 @@ * CSS-API header file for Extra Noise Reduction (XNR) parameters. */ -/** +/* * \brief Scale of the XNR sigma parameters. * \details The define specifies which fixed-point value represents 1.0. */ #define IA_CSS_XNR3_SIGMA_SCALE BIT(10) -/** +/* * \brief Scale of the XNR coring parameters. * \details The define specifies which fixed-point value represents 1.0. */ #define IA_CSS_XNR3_CORING_SCALE BIT(15) -/** +/* * \brief Scale of the XNR blending parameter. * \details The define specifies which fixed-point value represents 1.0. */ #define IA_CSS_XNR3_BLENDING_SCALE BIT(11) -/** +/* * \brief XNR3 Sigma Parameters. * \details Sigma parameters define the strength of the XNR filter. * A higher number means stronger filtering. There are two values for each of @@ -46,7 +46,7 @@ struct ia_css_xnr3_sigma_params { int v1; /** Sigma for V range similarity in bright area */ }; -/** +/* * \brief XNR3 Coring Parameters * \details Coring parameters define the "coring" strength, which is a soft * thresholding technique to avoid false coloring. There are two values for @@ -61,7 +61,7 @@ struct ia_css_xnr3_coring_params { int v1; /** Coring threshold of V channel in bright area */ }; -/** +/* * \brief XNR3 Blending Parameters * \details Blending parameters define the blending strength of filtered * output pixels with the original chroma pixels from before xnr3. The @@ -75,7 +75,7 @@ struct ia_css_xnr3_blending_params { int strength; /** Blending strength */ }; -/** +/* * \brief XNR3 public parameters. * \details Struct with all parameters for the XNR3 kernel that can be set * from the CSS API. diff --git a/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h b/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h index 6a0257359e69..d6ed1fbb0e8e 100644 --- a/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h +++ b/drivers/staging/media/atomisp/pci/isp/modes/interface/input_buf.isp.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h b/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h index 9c682f2ecbb2..5f768af9bc1d 100644 --- a/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h +++ b/drivers/staging/media/atomisp/pci/runtime/binary/interface/ia_css_binary.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h index 3e7dadca6d70..618172f17b63 100644 --- a/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h +++ b/drivers/staging/media/atomisp/pci/runtime/bufq/interface/ia_css_bufq.h @@ -13,7 +13,7 @@ #include "ia_css_err.h" #define BUFQ_EVENT_SIZE 4 -/** +/* * @brief Query the internal frame ID. * * @param[in] key The query key. @@ -29,7 +29,7 @@ bool ia_css_query_internal_queue_id( enum sh_css_queue_id *val ); -/** +/* * @brief Map buffer type to a internal queue id. * * @param[in] thread id Thread in which the buffer type has to be mapped or unmapped @@ -43,13 +43,13 @@ void ia_css_queue_map( bool map ); -/** +/* * @brief Initialize buffer type to a queue id mapping * @return none */ void ia_css_queue_map_init(void); -/** +/* * @brief initializes bufq module * It create instances of * -host to SP buffer queue which is a list with predefined size, @@ -62,7 +62,7 @@ void ia_css_queue_map_init(void); */ void ia_css_bufq_init(void); -/** +/* * @brief Enqueues an item into host to SP buffer queue * * @param thread_index[in] Thread in which the item to be enqueued @@ -77,7 +77,7 @@ int ia_css_bufq_enqueue_buffer( int queue_id, uint32_t item); -/** +/* * @brief Dequeues an item from SP to host buffer queue. * * @param queue_id[in] Specifies the index of the queue in the list where @@ -90,7 +90,7 @@ int ia_css_bufq_dequeue_buffer( int queue_id, uint32_t *item); -/** +/* * @brief Enqueue an event item into host to SP communication event queue. * * @param[in] evt_id The event ID. @@ -107,7 +107,7 @@ int ia_css_bufq_enqueue_psys_event( uint8_t evt_payload_2 ); -/** +/* * @brief Dequeue an item from SP to host communication event queue. * * @param item Object to be dequeued into this item. @@ -119,7 +119,7 @@ int ia_css_bufq_dequeue_psys_event( ); -/** +/* * @brief Enqueue an event item into host to SP EOF event queue. * * @param[in] evt_id The event ID. @@ -129,7 +129,7 @@ int ia_css_bufq_dequeue_psys_event( int ia_css_bufq_enqueue_isys_event( uint8_t evt_id); -/** +/* * @brief Dequeue an item from SP to host communication EOF event queue. * @@ -140,7 +140,7 @@ int ia_css_bufq_enqueue_isys_event( int ia_css_bufq_dequeue_isys_event( u8 item[BUFQ_EVENT_SIZE]); -/** +/* * @brief Enqueue a tagger command item into tagger command queue.. * * @param item Object to be enqueue. @@ -150,7 +150,7 @@ int ia_css_bufq_dequeue_isys_event( int ia_css_bufq_enqueue_tag_cmd( uint32_t item); -/** +/* * @brief Uninitializes bufq module. * * @return 0 or error code upon error. @@ -158,7 +158,7 @@ int ia_css_bufq_enqueue_tag_cmd( */ int ia_css_bufq_deinit(void); -/** +/* * @brief Dump queue states * * @return None diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h index 2d0e906530af..b7ff809eeeab 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h @@ -312,7 +312,7 @@ void ia_css_debug_dump_stream_config( const struct ia_css_stream_config *config, int num_pipes); -/** +/* * @brief Initialize the debug mode. * * WARNING: @@ -324,7 +324,7 @@ void ia_css_debug_dump_stream_config( */ bool ia_css_debug_mode_init(void); -/** +/* * @brief Disable the DMA channel. * * @param[in] dma_ID The ID of the target DMA. @@ -344,7 +344,7 @@ bool ia_css_debug_mode_disable_dma_channel( int dma_ID, int channel_id, int request_type); -/** +/* * @brief Enable the DMA channel. * * @param[in] dma_ID The ID of the target DMA. @@ -363,7 +363,7 @@ bool ia_css_debug_mode_enable_dma_channel( int channel_id, int request_type); -/** +/* * @brief Dump tracer data. * [Currently support is only for SKC] * @@ -373,7 +373,7 @@ bool ia_css_debug_mode_enable_dma_channel( void ia_css_debug_dump_trace(void); /* ISP2401 */ -/** +/* * @brief Program counter dumping (in loop) * * @param[in] id The ID of the SP diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h index 80c58cb934d5..6f6cd77ce91d 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug_pipe.h @@ -13,21 +13,21 @@ #include <ia_css_stream_public.h> #include "ia_css_pipeline.h" -/** +/* * @brief Internal debug support for constructing a pipe graph. * * @return None */ void ia_css_debug_pipe_graph_dump_prologue(void); -/** +/* * @brief Internal debug support for constructing a pipe graph. * * @return None */ void ia_css_debug_pipe_graph_dump_epilogue(void); -/** +/* * @brief Internal debug support for constructing a pipe graph. * @param[in] stage Pipeline stage. * @param[in] id Pipe id. @@ -38,7 +38,7 @@ void ia_css_debug_pipe_graph_dump_stage( struct ia_css_pipeline_stage *stage, enum ia_css_pipe_id id); -/** +/* * @brief Internal debug support for constructing a pipe graph. * @param[in] out_frame Output frame of SP raw copy. * @@ -47,7 +47,7 @@ void ia_css_debug_pipe_graph_dump_stage( void ia_css_debug_pipe_graph_dump_sp_raw_copy( struct ia_css_frame *out_frame); -/** +/* * @brief Internal debug support for constructing a pipe graph. * @param[in] stream_config info about sensor and input formatter. * diff --git a/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h b/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h index 9b058e296c93..f8ce32e9b90d 100644 --- a/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h +++ b/drivers/staging/media/atomisp/pci/runtime/eventq/interface/ia_css_eventq.h @@ -9,7 +9,7 @@ #include "ia_css_queue.h" /* queue APIs */ -/** +/* * @brief HOST receives event from SP. * * @param[in] eventq_handle eventq_handle. @@ -22,7 +22,7 @@ int ia_css_eventq_recv( ia_css_queue_t *eventq_handle, uint8_t *payload); -/** +/* * @brief The Host sends the event to SP. * The caller of this API will be blocked until the event * is sent. diff --git a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h index d6d60508c1bf..095d1853670f 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h +++ b/drivers/staging/media/atomisp/pci/runtime/isp_param/interface/ia_css_isp_param_types.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/** +/* Support for Intel Camera Imaging ISP subsystem. Copyright (c) 2010 - 2015, Intel Corporation. diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h index 29eebe8f9078..8870ff294c1e 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h +++ b/drivers/staging/media/atomisp/pci/runtime/isys/interface/ia_css_isys.h @@ -15,7 +15,7 @@ #include <system_global.h> #include "ia_css_isys_comm.h" -/** +/* * Virtual Input System. (Input System 2401) */ typedef isp2401_input_system_cfg_t ia_css_isys_descr_t; @@ -28,7 +28,7 @@ enum mipi_port_id ia_css_isys_port_to_mipi_port( enum mipi_port_id api_port); -/** +/* * @brief Register one (virtual) stream. This is used to track when all * virtual streams are configured inside the input system. The CSI RX is * only started when all registered streams are configured. @@ -43,7 +43,7 @@ int ia_css_isys_csi_rx_register_stream( enum mipi_port_id port, uint32_t isys_stream_id); -/** +/* * @brief Unregister one (virtual) stream. This is used to track when all * virtual streams are configured inside the input system. The CSI RX is * only started when all registered streams are configured. @@ -97,7 +97,7 @@ int ia_css_isys_convert_stream_format_to_mipi_format( mipi_predictor_t compression, unsigned int *fmt_type); -/** +/* * Virtual Input System. (Input System 2401) */ ia_css_isys_error_t ia_css_isys_stream_create( diff --git a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h index 8b7cbf31a1a2..04d9f1fdb5b0 100644 --- a/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h +++ b/drivers/staging/media/atomisp/pci/runtime/pipeline/interface/ia_css_pipeline.h @@ -219,7 +219,7 @@ int ia_css_pipeline_get_output_stage( */ bool ia_css_pipeline_uses_params(struct ia_css_pipeline *pipeline); -/** +/* * @brief get the SP thread ID. * * @param[in] key The query key, typical use is pipe_num. @@ -231,7 +231,7 @@ bool ia_css_pipeline_uses_params(struct ia_css_pipeline *pipeline); */ bool ia_css_pipeline_get_sp_thread_id(unsigned int key, unsigned int *val); -/** +/* * @brief Get the pipeline io status * * @param[in] None @@ -240,7 +240,7 @@ bool ia_css_pipeline_get_sp_thread_id(unsigned int key, unsigned int *val); */ struct sh_css_sp_pipeline_io_status *ia_css_pipeline_get_pipe_io_status(void); -/** +/* * @brief Map an SP thread to this pipeline * * @param[in] pipe_num @@ -249,7 +249,7 @@ struct sh_css_sp_pipeline_io_status *ia_css_pipeline_get_pipe_io_status(void); */ void ia_css_pipeline_map(unsigned int pipe_num, bool map); -/** +/* * @brief Checks whether the pipeline is mapped to SP threads * * @param[in] Query key, typical use is pipe_num @@ -260,7 +260,7 @@ void ia_css_pipeline_map(unsigned int pipe_num, bool map); */ bool ia_css_pipeline_is_mapped(unsigned int key); -/** +/* * @brief Print pipeline thread mapping * * @param[in] none diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h index 00b903d950df..4c86c19811bb 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr.h @@ -17,12 +17,12 @@ #define STORAGE_CLASS_RMGR_C static inline #endif /* __INLINE_RMGR__ */ -/** +/* * @brief Initialize resource manager (host/common) */ int ia_css_rmgr_init(void); -/** +/* * @brief Uninitialize resource manager (host/common) */ void ia_css_rmgr_uninit(void); diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h index 6820bfc77432..68285334bc88 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/interface/ia_css_rmgr_vbuf.h @@ -12,7 +12,7 @@ #include <ia_css_types.h> #include <system_local.h> -/** +/* * @brief Data structure for the resource handle (host, vbuf) */ struct ia_css_rmgr_vbuf_handle { @@ -21,7 +21,7 @@ struct ia_css_rmgr_vbuf_handle { u32 size; }; -/** +/* * @brief Data structure for the resource pool (host, vbuf) */ struct ia_css_rmgr_vbuf_pool { @@ -32,14 +32,14 @@ struct ia_css_rmgr_vbuf_pool { struct ia_css_rmgr_vbuf_handle **handles; }; -/** +/* * @brief VBUF resource pools */ extern struct ia_css_rmgr_vbuf_pool *vbuf_ref; extern struct ia_css_rmgr_vbuf_pool *vbuf_write; extern struct ia_css_rmgr_vbuf_pool *hmm_buffer_pool; -/** +/* * @brief Initialize the resource pool (host, vbuf) * * @param pool The pointer to the pool @@ -47,7 +47,7 @@ extern struct ia_css_rmgr_vbuf_pool *hmm_buffer_pool; STORAGE_CLASS_RMGR_H int ia_css_rmgr_init_vbuf( struct ia_css_rmgr_vbuf_pool *pool); -/** +/* * @brief Uninitialize the resource pool (host, vbuf) * * @param pool The pointer to the pool @@ -55,7 +55,7 @@ STORAGE_CLASS_RMGR_H int ia_css_rmgr_init_vbuf( STORAGE_CLASS_RMGR_H void ia_css_rmgr_uninit_vbuf( struct ia_css_rmgr_vbuf_pool *pool); -/** +/* * @brief Acquire a handle from the pool (host, vbuf) * * @param pool The pointer to the pool @@ -65,7 +65,7 @@ STORAGE_CLASS_RMGR_H void ia_css_rmgr_acq_vbuf( struct ia_css_rmgr_vbuf_pool *pool, struct ia_css_rmgr_vbuf_handle **handle); -/** +/* * @brief Release a handle to the pool (host, vbuf) * * @param pool The pointer to the pool @@ -75,14 +75,14 @@ STORAGE_CLASS_RMGR_H void ia_css_rmgr_rel_vbuf( struct ia_css_rmgr_vbuf_pool *pool, struct ia_css_rmgr_vbuf_handle **handle); -/** +/* * @brief Retain the reference count for a handle (host, vbuf) * * @param handle The pointer to the handle */ void ia_css_rmgr_refcount_retain_vbuf(struct ia_css_rmgr_vbuf_handle **handle); -/** +/* * @brief Release the reference count for a handle (host, vbuf) * * @param handle The pointer to the handle diff --git a/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h b/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h index 79006c325de6..9208c650fde7 100644 --- a/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h +++ b/drivers/staging/media/atomisp/pci/runtime/tagger/interface/ia_css_tagger_common.h @@ -10,14 +10,14 @@ #include <system_local.h> #include <type_support.h> -/** +/* * @brief The tagger's circular buffer. * * Should be one less than NUM_CONTINUOUS_FRAMES in sh_css_internal.h */ #define MAX_CB_ELEMS_FOR_TAGGER 14 -/** +/* * @brief Data structure for the tagger buffer element. */ typedef struct { diff --git a/drivers/staging/media/atomisp/pci/sh_css_internal.h b/drivers/staging/media/atomisp/pci/sh_css_internal.h index 9155a83fcc03..ec68c16d4272 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_internal.h +++ b/drivers/staging/media/atomisp/pci/sh_css_internal.h @@ -80,7 +80,7 @@ #define SH_CSS_MAX_SP_THREADS 5 -/** +/* * The C99 standard does not specify the exact object representation of structs; * the representation is compiler dependent. * @@ -638,7 +638,7 @@ struct sh_css_sp_output { unsigned int sw_interrupt_value[SH_CSS_NUM_SDW_IRQS]; }; -/** +/* * @brief Data structure for the circular buffer. * The circular buffer is empty if "start == end". The * circular buffer is full if "(end + 1) % size == start". diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.h b/drivers/staging/media/atomisp/pci/sh_css_sp.h index 78aec5b7e8fa..6985ca200f09 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.h +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.h @@ -68,7 +68,7 @@ sh_css_read_host2sp_command(void); void sh_css_init_host2sp_frame_data(void); -/** +/* * @brief Update the offline frame information in host_sp_communication. * * @param[in] frame_num The offline frame number. @@ -80,7 +80,7 @@ sh_css_update_host2sp_offline_frame( struct ia_css_frame *frame, struct ia_css_metadata *metadata); -/** +/* * @brief Update the mipi frame information in host_sp_communication. * * @param[in] frame_num The mipi frame number. @@ -91,7 +91,7 @@ sh_css_update_host2sp_mipi_frame( unsigned int frame_num, struct ia_css_frame *frame); -/** +/* * @brief Update the mipi metadata information in host_sp_communication. * * @param[in] frame_num The mipi frame number. @@ -102,7 +102,7 @@ sh_css_update_host2sp_mipi_metadata( unsigned int frame_num, struct ia_css_metadata *metadata); -/** +/* * @brief Update the nr of mipi frames to use in host_sp_communication. * * @param[in] num_frames The number of mipi frames to use. @@ -110,7 +110,7 @@ sh_css_update_host2sp_mipi_metadata( void sh_css_update_host2sp_num_mipi_frames(unsigned int num_frames); -/** +/* * @brief Update the nr of offline frames to use in host_sp_communication. * * @param[in] num_frames The number of raw frames to use. @@ -170,7 +170,7 @@ sh_css_sp_set_disable_continuous_viewfinder(bool flag); void sh_css_sp_reset_global_vars(void); -/** +/* * @brief Initialize the DMA software-mask in the debug mode. * This API should be ONLY called in the debugging mode. * And it should be always called before the first call of @@ -185,7 +185,7 @@ sh_css_sp_reset_global_vars(void); bool sh_css_sp_init_dma_sw_reg(int dma_id); -/** +/* * @brief Set the DMA software-mask in the debug mode. * This API should be ONLYL called in the debugging mode. Must * call "sh_css_set_dma_sw_reg(...)" before this diff --git a/drivers/staging/media/atomisp/pci/system_global.h b/drivers/staging/media/atomisp/pci/system_global.h index e8a29f73d67a..ee1d9b66ccb1 100644 --- a/drivers/staging/media/atomisp/pci/system_global.h +++ b/drivers/staging/media/atomisp/pci/system_global.h @@ -293,7 +293,7 @@ typedef enum { } stream2mmio_sid_ID_t; /* end of Stream2MMIO */ -/** +/* * Input System 2401: CSI-MIPI recevier. */ typedef enum { @@ -324,7 +324,7 @@ typedef enum { N_ISYS2401_DMA_ID } isys2401_dma_ID_t; -/** +/* * Pixel-generator. ("system_global.h") */ typedef enum { diff --git a/drivers/staging/media/av7110/av7110.c b/drivers/staging/media/av7110/av7110.c index 862aee993889..06c43b5f8a87 100644 --- a/drivers/staging/media/av7110/av7110.c +++ b/drivers/staging/media/av7110/av7110.c @@ -942,16 +942,16 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) (feed->pes_type <= DMX_PES_PCR)) { switch (demux->dmx.frontend->source) { case DMX_MEMORY_FE: - if (feed->ts_type & TS_DECODER) - if (feed->pes_type < 2 && - !(demux->pids[0] & 0x8000) && - !(demux->pids[1] & 0x8000)) { - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); - dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); - ret = av7110_av_start_play(av7110, RP_AV); - if (!ret) - demux->playing = 1; - } + if (feed->pes_type >= 2 || + (demux->pids[0] & 0x8000) || + (demux->pids[1] & 0x8000)) + break; + + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); + dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); + ret = av7110_av_start_play(av7110, RP_AV); + if (!ret) + demux->playing = 1; break; default: ret = dvb_feed_start_pid(feed); diff --git a/drivers/staging/media/ipu7/ipu7-isys.c b/drivers/staging/media/ipu7/ipu7-isys.c index cb2f49f3e0fa..601e5a79ef8e 100644 --- a/drivers/staging/media/ipu7/ipu7-isys.c +++ b/drivers/staging/media/ipu7/ipu7-isys.c @@ -233,6 +233,7 @@ static int isys_notifier_init(struct ipu7_isys *isys) err_parse: fwnode_handle_put(ep); + v4l2_async_nf_cleanup(&isys->notifier); return ret; } @@ -773,6 +774,7 @@ static int isys_probe(struct auxiliary_device *auxdev, return 0; out_cleanup: + isys_notifier_cleanup(isys); isys_unregister_devices(isys); out_cleanup_fw: ipu7_fw_isys_release(isys); diff --git a/drivers/staging/media/ipu7/ipu7.c b/drivers/staging/media/ipu7/ipu7.c index 310e3f24e571..48a35bda4237 100644 --- a/drivers/staging/media/ipu7/ipu7.c +++ b/drivers/staging/media/ipu7/ipu7.c @@ -2343,7 +2343,7 @@ static int ipu7_init_fw_code_region_by_sys(struct ipu7_bus_device *sys, return ret; } - ret = pm_runtime_get_sync(dev); + ret = pm_runtime_resume_and_get(dev); if (ret < 0) { dev_err(dev, "Failed to get runtime PM\n"); return ret; @@ -2702,7 +2702,7 @@ static int ipu7_resume(struct device *dev) if (ret) dev_err(dev, "IPC reset protocol failed!\n"); - ret = pm_runtime_get_sync(&isp->psys->auxdev.dev); + ret = pm_runtime_resume_and_get(&isp->psys->auxdev.dev); if (ret < 0) { dev_err(dev, "Failed to get runtime PM\n"); return 0; diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index a039d925c0fe..c18bf352b199 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -504,8 +504,8 @@ vdec_try_fmt_common(struct amvdec_session *sess, u32 size, case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: fmt_out = find_format(fmts, size, pixmp->pixelformat); if (!fmt_out) { - pixmp->pixelformat = V4L2_PIX_FMT_MPEG2; - fmt_out = find_format(fmts, size, pixmp->pixelformat); + pixmp->pixelformat = fmts[0].pixfmt; + fmt_out = &fmts[0]; } break; case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index bbd186b8035b..96acd52e380c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -285,8 +285,10 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx) ctrl_size = sizeof(ctrl) * CEDRUS_CONTROLS_COUNT + 1; ctx->ctrls = kzalloc(ctrl_size, GFP_KERNEL); - if (!ctx->ctrls) + if (!ctx->ctrls) { + v4l2_ctrl_handler_free(hdl); return -ENOMEM; + } j = 0; for (i = 0; i < CEDRUS_CONTROLS_COUNT; i++) { diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c index e513e6ccb776..eb1fc5b7e2cd 100644 --- a/drivers/staging/media/tegra-video/tegra20.c +++ b/drivers/staging/media/tegra-video/tegra20.c @@ -552,7 +552,8 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan, case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(TEGRA_VI_OUT_1), base); - tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_1), base + chan->start_offset); + tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_1), + base + chan->start_offset); break; /* RAW8 */ case V4L2_PIX_FMT_SRGGB8: @@ -565,7 +566,8 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan, case V4L2_PIX_FMT_SGBRG10: case V4L2_PIX_FMT_SBGGR10: tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(TEGRA_VI_OUT_2), base); - tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_2), base + chan->start_offset); + tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_2), + base + chan->start_offset); break; } } diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 456134a9e8cf..01622013c109 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -1257,6 +1257,7 @@ static int tegra_vi_channels_alloc(struct tegra_vi *vi) struct device_node *parent; struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 }; unsigned int lanes; + int err; int ret = 0; ports = of_get_child_by_name(node, "ports"); @@ -1267,8 +1268,8 @@ static int tegra_vi_channels_alloc(struct tegra_vi *vi) if (!of_node_name_eq(port, "port")) continue; - ret = of_property_read_u32(port, "reg", &port_num); - if (ret < 0) + err = of_property_read_u32(port, "reg", &port_num); + if (err < 0) continue; if (port_num > vi->soc->vi_max_channels) { @@ -1289,10 +1290,10 @@ static int tegra_vi_channels_alloc(struct tegra_vi *vi) ep = of_graph_get_endpoint_by_regs(parent, 0, 0); of_node_put(parent); - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), + err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep); of_node_put(ep); - if (ret) + if (err) continue; lanes = v4l2_ep.bus.mipi_csi2.num_data_lanes; @@ -1468,7 +1469,6 @@ static int tegra_vi_graph_build(struct tegra_vi_channel *chan, struct tegra_vi *vi = chan->vi; struct tegra_vi_graph_entity *ent; struct fwnode_handle *ep = NULL; - struct v4l2_fwnode_link link; struct media_entity *local = entity->entity; struct media_entity *remote; struct media_pad *local_pad; @@ -1478,70 +1478,64 @@ static int tegra_vi_graph_build(struct tegra_vi_channel *chan, dev_dbg(vi->dev, "creating links for entity %s\n", local->name); - while (1) { - ep = fwnode_graph_get_next_endpoint(entity->asd.match.fwnode, - ep); - if (!ep) - break; + fwnode_graph_for_each_endpoint(entity->asd.match.fwnode, ep) { + struct fwnode_handle *remote_parent __free(fwnode_handle) = NULL; + struct fwnode_handle *sink_ep __free(fwnode_handle) = NULL; + int src_idx, sink_idx; - ret = v4l2_fwnode_parse_link(ep, &link); - if (ret < 0) { - dev_err(vi->dev, "failed to parse link for %pOF: %d\n", - to_of_node(ep), ret); + src_idx = media_entity_get_fwnode_pad(local, ep, + MEDIA_PAD_FL_SOURCE); + if (src_idx < 0) { + dev_dbg(vi->dev, "no source pad found for %pfw\n", ep); continue; } - if (link.local_port >= local->num_pads) { - dev_err(vi->dev, "invalid port number %u on %pOF\n", - link.local_port, to_of_node(link.local_node)); - v4l2_fwnode_put_link(&link); - ret = -EINVAL; - break; + remote_parent = fwnode_graph_get_remote_port_parent(ep); + if (!remote_parent) { + dev_dbg(vi->dev, "no remote parent found for %pfw\n", + ep); + continue; } - local_pad = &local->pads[link.local_port]; + local_pad = &local->pads[src_idx]; /* Remote node is vi node. So use channel video entity and pad * as remote/sink. */ - if (link.remote_node == of_fwnode_handle(vi->dev->of_node)) { + if (remote_parent == of_fwnode_handle(vi->dev->of_node)) { remote = &chan->video.entity; remote_pad = &chan->pad; goto create_link; } - /* - * Skip sink ports, they will be processed from the other end - * of the link. - */ - if (local_pad->flags & MEDIA_PAD_FL_SINK) { - dev_dbg(vi->dev, "skipping sink port %pOF:%u\n", - to_of_node(link.local_node), link.local_port); - v4l2_fwnode_put_link(&link); - continue; - } - /* find the remote entity from notifier list */ ent = tegra_vi_graph_find_entity(&chan->notifier.done_list, - link.remote_node); + remote_parent); if (!ent) { - dev_err(vi->dev, "no entity found for %pOF\n", - to_of_node(link.remote_node)); - v4l2_fwnode_put_link(&link); + fwnode_handle_put(ep); + dev_err(vi->dev, "no entity found for %pfw\n", + remote_parent); ret = -ENODEV; break; } remote = ent->entity; - if (link.remote_port >= remote->num_pads) { - dev_err(vi->dev, "invalid port number %u on %pOF\n", - link.remote_port, - to_of_node(link.remote_node)); - v4l2_fwnode_put_link(&link); - ret = -EINVAL; - break; + + sink_ep = fwnode_graph_get_remote_endpoint(ep); + if (!sink_ep) { + dev_dbg(vi->dev, "no sink ep found for %pfw\n", + ep); + continue; + } + + sink_idx = media_entity_get_fwnode_pad(remote, sink_ep, + MEDIA_PAD_FL_SINK); + if (sink_idx < 0) { + dev_dbg(vi->dev, "no sink pad found for %pfw\n", + sink_ep); + continue; } - remote_pad = &remote->pads[link.remote_port]; + remote_pad = &remote->pads[sink_idx]; create_link: dev_dbg(vi->dev, "creating %s:%u -> %s:%u link\n", @@ -1551,8 +1545,8 @@ create_link: ret = media_create_pad_link(local, local_pad->index, remote, remote_pad->index, link_flags); - v4l2_fwnode_put_link(&link); if (ret < 0) { + fwnode_handle_put(ep); dev_err(vi->dev, "failed to create %s:%u -> %s:%u link: %d\n", local->name, local_pad->index, @@ -1561,7 +1555,6 @@ create_link: } } - fwnode_handle_put(ep); return ret; } diff --git a/drivers/staging/media/tegra-video/vip.c b/drivers/staging/media/tegra-video/vip.c index 9ff1f1750a15..5fba11e31e1d 100644 --- a/drivers/staging/media/tegra-video/vip.c +++ b/drivers/staging/media/tegra-video/vip.c @@ -126,7 +126,7 @@ static int tegra_vip_channel_of_parse(struct tegra_vip *vip) if (!ep) { err = -EINVAL; dev_err_probe(dev, err, "%pOF: error getting endpoint node\n", np); - goto err_node_put; + return err; } fwh = of_fwnode_handle(ep); @@ -134,14 +134,14 @@ static int tegra_vip_channel_of_parse(struct tegra_vip *vip) of_node_put(ep); if (err) { dev_err_probe(dev, err, "%pOF: failed to parse v4l2 endpoint\n", np); - goto err_node_put; + return err; } num_pads = of_graph_get_endpoint_count(np); if (num_pads != TEGRA_VIP_PADS_NUM) { err = -EINVAL; dev_err_probe(dev, err, "%pOF: need 2 pads, got %d\n", np, num_pads); - goto err_node_put; + return err; } vip->chan.of_node = of_node_get(np); @@ -149,10 +149,6 @@ static int tegra_vip_channel_of_parse(struct tegra_vip *vip) vip->chan.pads[TEGRA_VIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; return 0; - -err_node_put: - of_node_put(np); - return err; } static int tegra_vip_channel_init(struct tegra_vip *vip) |
