diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-24 18:09:16 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-24 18:09:16 -0700 |
commit | 827060261cf3c7b79ee7185d5aa61c851beb9403 (patch) | |
tree | ea33be6609b189d31d1e56c09c92c967078eb3f8 /drivers | |
parent | 268db333b561c77dee3feb6831806412293b4a7e (diff) | |
parent | 340ce50f75a6bdfe6d1850ca49ef37a8e2765dd1 (diff) | |
download | linux-rpi-827060261cf3c7b79ee7185d5aa61c851beb9403.tar.gz linux-rpi-827060261cf3c7b79ee7185d5aa61c851beb9403.tar.bz2 linux-rpi-827060261cf3c7b79ee7185d5aa61c851beb9403.zip |
Merge tag 'media/v5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- dvb-usb drivers entries got reworked to avoid usage of magic numbers
to refer to data position inside tables
- vcodec driver has gained support for MT8186 and for vp8 and vp9
stateless codecs
- hantro has gained support for Hantro G1 on RK366x
- Added more h264 levels on coda960
- ccs gained support for MIPI CSI-2 28 bits per pixel raw data type
- venus driver gained support for Qualcomm custom compressed pixel
formats
- lots of driver fixes and updates
* tag 'media/v5.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (308 commits)
media: hantro: Enable HOLD_CAPTURE_BUF for H.264
media: hantro: Add H.264 field decoding support
media: hantro: h264: Make dpb entry management more robust
media: hantro: Stop using H.264 parameter pic_num
media: rkvdec: Enable capture buffer holding for H264
media: rkvdec-h264: Add field decoding support
media: rkvdec: Ensure decoded resolution fit coded resolution
media: rkvdec: h264: Fix reference frame_num wrap for second field
media: rkvdec: h264: Validate and use pic width and height in mbs
media: rkvdec: Move H264 SPS validation in rkvdec-h264
media: rkvdec: h264: Fix bit depth wrap in pps packet
media: rkvdec: h264: Fix dpb_valid implementation
media: rkvdec: Stop overclocking the decoder
media: v4l2: Reorder field reflist
media: h264: Sort p/b reflist using frame_num
media: v4l2: Trace calculated p/b0/b1 initial reflist
media: h264: Store all fields into the unordered list
media: h264: Store current picture fields
media: h264: Increase reference lists size to 32
media: h264: Use v4l2_h264_reference for reflist
...
Diffstat (limited to 'drivers')
229 files changed, 8650 insertions, 3171 deletions
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c index 2e12331c12a9..8bf91b5a7d0e 100644 --- a/drivers/media/cec/core/cec-adap.c +++ b/drivers/media/cec/core/cec-adap.c @@ -27,27 +27,6 @@ static void cec_fill_msg_report_features(struct cec_adapter *adap, struct cec_msg *msg, unsigned int la_idx); -/* - * 400 ms is the time it takes for one 16 byte message to be - * transferred and 5 is the maximum number of retries. Add - * another 100 ms as a margin. So if the transmit doesn't - * finish before that time something is really wrong and we - * have to time out. - * - * This is a sign that something it really wrong and a warning - * will be issued. - */ -#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100) - -#define call_op(adap, op, arg...) \ - (adap->ops->op ? adap->ops->op(adap, ## arg) : 0) - -#define call_void_op(adap, op, arg...) \ - do { \ - if (adap->ops->op) \ - adap->ops->op(adap, ## arg); \ - } while (0) - static int cec_log_addr2idx(const struct cec_adapter *adap, u8 log_addr) { int i; @@ -366,38 +345,48 @@ static void cec_data_completed(struct cec_data *data) /* * A pending CEC transmit needs to be cancelled, either because the CEC * adapter is disabled or the transmit takes an impossibly long time to - * finish. + * finish, or the reply timed out. * * This function is called with adap->lock held. */ -static void cec_data_cancel(struct cec_data *data, u8 tx_status) +static void cec_data_cancel(struct cec_data *data, u8 tx_status, u8 rx_status) { + struct cec_adapter *adap = data->adap; + /* * It's either the current transmit, or it is a pending * transmit. Take the appropriate action to clear it. */ - if (data->adap->transmitting == data) { - data->adap->transmitting = NULL; + if (adap->transmitting == data) { + adap->transmitting = NULL; } else { list_del_init(&data->list); if (!(data->msg.tx_status & CEC_TX_STATUS_OK)) - if (!WARN_ON(!data->adap->transmit_queue_sz)) - data->adap->transmit_queue_sz--; + if (!WARN_ON(!adap->transmit_queue_sz)) + adap->transmit_queue_sz--; } if (data->msg.tx_status & CEC_TX_STATUS_OK) { data->msg.rx_ts = ktime_get_ns(); - data->msg.rx_status = CEC_RX_STATUS_ABORTED; + data->msg.rx_status = rx_status; + if (!data->blocking) + data->msg.tx_status = 0; } else { data->msg.tx_ts = ktime_get_ns(); data->msg.tx_status |= tx_status | CEC_TX_STATUS_MAX_RETRIES; data->msg.tx_error_cnt++; data->attempts = 0; + if (!data->blocking) + data->msg.rx_status = 0; } /* Queue transmitted message for monitoring purposes */ - cec_queue_msg_monitor(data->adap, &data->msg, 1); + cec_queue_msg_monitor(adap, &data->msg, 1); + + if (!data->blocking && data->msg.sequence) + /* Allow drivers to process the message first */ + call_op(adap, received, &data->msg); cec_data_completed(data); } @@ -418,15 +407,15 @@ static void cec_flush(struct cec_adapter *adap) while (!list_empty(&adap->transmit_queue)) { data = list_first_entry(&adap->transmit_queue, struct cec_data, list); - cec_data_cancel(data, CEC_TX_STATUS_ABORTED); + cec_data_cancel(data, CEC_TX_STATUS_ABORTED, 0); } if (adap->transmitting) - cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED); + adap->transmit_in_progress_aborted = true; /* Cancel the pending timeout work. */ list_for_each_entry_safe(data, n, &adap->wait_queue, list) { if (cancel_delayed_work(&data->work)) - cec_data_cancel(data, CEC_TX_STATUS_OK); + cec_data_cancel(data, CEC_TX_STATUS_OK, CEC_RX_STATUS_ABORTED); /* * If cancel_delayed_work returned false, then * the cec_wait_timeout function is running, @@ -482,7 +471,7 @@ int cec_thread_func(void *_adap) kthread_should_stop() || (!adap->transmit_in_progress && !list_empty(&adap->transmit_queue)), - msecs_to_jiffies(CEC_XFER_TIMEOUT_MS)); + msecs_to_jiffies(adap->xfer_timeout_ms)); timeout = err == 0; } else { /* Otherwise we just wait for something to happen. */ @@ -508,7 +497,8 @@ int cec_thread_func(void *_adap) * adapter driver, or the CEC bus is in some weird * state. On rare occasions it can happen if there is * so much traffic on the bus that the adapter was - * unable to transmit for CEC_XFER_TIMEOUT_MS (2.1s). + * unable to transmit for xfer_timeout_ms (2.1s by + * default). */ if (adap->transmitting) { pr_warn("cec-%s: message %*ph timed out\n", adap->name, @@ -516,7 +506,7 @@ int cec_thread_func(void *_adap) adap->transmitting->msg.msg); /* Just give up on this. */ cec_data_cancel(adap->transmitting, - CEC_TX_STATUS_TIMEOUT); + CEC_TX_STATUS_TIMEOUT, 0); } else { pr_warn("cec-%s: transmit timed out\n", adap->name); } @@ -572,10 +562,11 @@ int cec_thread_func(void *_adap) if (data->attempts == 0) data->attempts = attempts; + adap->transmit_in_progress_aborted = false; /* Tell the adapter to transmit, cancel on error */ - if (adap->ops->adap_transmit(adap, data->attempts, - signal_free_time, &data->msg)) - cec_data_cancel(data, CEC_TX_STATUS_ABORTED); + if (call_op(adap, adap_transmit, data->attempts, + signal_free_time, &data->msg)) + cec_data_cancel(data, CEC_TX_STATUS_ABORTED, 0); else adap->transmit_in_progress = true; @@ -599,6 +590,8 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, struct cec_msg *msg; unsigned int attempts_made = arb_lost_cnt + nack_cnt + low_drive_cnt + error_cnt; + bool done = status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK); + bool aborted = adap->transmit_in_progress_aborted; dprintk(2, "%s: status 0x%02x\n", __func__, status); if (attempts_made < 1) @@ -619,6 +612,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, goto wake_thread; } adap->transmit_in_progress = false; + adap->transmit_in_progress_aborted = false; msg = &data->msg; @@ -639,8 +633,7 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, * the hardware didn't signal that it retried itself (by setting * CEC_TX_STATUS_MAX_RETRIES), then we will retry ourselves. */ - if (data->attempts > attempts_made && - !(status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK))) { + if (!aborted && data->attempts > attempts_made && !done) { /* Retry this message */ data->attempts -= attempts_made; if (msg->timeout) @@ -655,6 +648,8 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status, goto wake_thread; } + if (aborted && !done) + status |= CEC_TX_STATUS_ABORTED; data->attempts = 0; /* Always set CEC_TX_STATUS_MAX_RETRIES on error */ @@ -733,9 +728,7 @@ static void cec_wait_timeout(struct work_struct *work) /* Mark the message as timed out */ list_del_init(&data->list); - data->msg.rx_ts = ktime_get_ns(); - data->msg.rx_status = CEC_RX_STATUS_TIMEOUT; - cec_data_completed(data); + cec_data_cancel(data, CEC_TX_STATUS_OK, CEC_RX_STATUS_TIMEOUT); unlock: mutex_unlock(&adap->lock); } @@ -921,8 +914,12 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, mutex_lock(&adap->lock); /* Cancel the transmit if it was interrupted */ - if (!data->completed) - cec_data_cancel(data, CEC_TX_STATUS_ABORTED); + if (!data->completed) { + if (data->msg.tx_status & CEC_TX_STATUS_OK) + cec_data_cancel(data, CEC_TX_STATUS_OK, CEC_RX_STATUS_ABORTED); + else + cec_data_cancel(data, CEC_TX_STATUS_ABORTED, 0); + } /* The transmit completed (possibly with an error) */ *msg = data->msg; @@ -1278,17 +1275,22 @@ static int cec_config_log_addr(struct cec_adapter *adap, * While trying to poll the physical address was reset * and the adapter was unconfigured, so bail out. */ - if (!adap->is_configuring) + if (adap->phys_addr == CEC_PHYS_ADDR_INVALID) + return -EINTR; + + /* Also bail out if the PA changed while configuring. */ + if (adap->must_reconfigure) return -EINTR; if (err) return err; /* - * The message was aborted due to a disconnect or + * The message was aborted or timed out due to a disconnect or * unconfigure, just bail out. */ - if (msg.tx_status & CEC_TX_STATUS_ABORTED) + if (msg.tx_status & + (CEC_TX_STATUS_ABORTED | CEC_TX_STATUS_TIMEOUT)) return -EINTR; if (msg.tx_status & CEC_TX_STATUS_OK) return 0; @@ -1314,7 +1316,7 @@ static int cec_config_log_addr(struct cec_adapter *adap, * Message not acknowledged, so this logical * address is free to use. */ - err = adap->ops->adap_log_addr(adap, log_addr); + err = call_op(adap, adap_log_addr, log_addr); if (err) return err; @@ -1331,15 +1333,14 @@ static int cec_config_log_addr(struct cec_adapter *adap, */ static void cec_adap_unconfigure(struct cec_adapter *adap) { - if (!adap->needs_hpd || - adap->phys_addr != CEC_PHYS_ADDR_INVALID) - WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID)); + if (!adap->needs_hpd || adap->phys_addr != CEC_PHYS_ADDR_INVALID) + WARN_ON(call_op(adap, adap_log_addr, CEC_LOG_ADDR_INVALID)); adap->log_addrs.log_addr_mask = 0; - adap->is_configuring = false; adap->is_configured = false; cec_flush(adap); wake_up_interruptible(&adap->kthread_waitq); cec_post_state_event(adap); + call_void_op(adap, adap_configured, false); } /* @@ -1408,6 +1409,7 @@ static int cec_config_thread_func(void *arg) if (las->log_addr_type[0] == CEC_LOG_ADDR_TYPE_UNREGISTERED) goto configured; +reconfigure: for (i = 0; i < las->num_log_addrs; i++) { unsigned int type = las->log_addr_type[i]; const u8 *la_list; @@ -1430,6 +1432,13 @@ static int cec_config_thread_func(void *arg) last_la = la_list[0]; err = cec_config_log_addr(adap, i, last_la); + + if (adap->must_reconfigure) { + adap->must_reconfigure = false; + las->log_addr_mask = 0; + goto reconfigure; + } + if (err > 0) /* Reused last LA */ continue; @@ -1475,6 +1484,7 @@ configured: las->log_addr[i] = CEC_LOG_ADDR_INVALID; adap->is_configured = true; adap->is_configuring = false; + adap->must_reconfigure = false; cec_post_state_event(adap); /* @@ -1521,15 +1531,18 @@ configured: adap->kthread_config = NULL; complete(&adap->config_completion); mutex_unlock(&adap->lock); + call_void_op(adap, adap_configured, true); return 0; unconfigure: for (i = 0; i < las->num_log_addrs; i++) las->log_addr[i] = CEC_LOG_ADDR_INVALID; cec_adap_unconfigure(adap); + adap->is_configuring = false; + adap->must_reconfigure = false; adap->kthread_config = NULL; - mutex_unlock(&adap->lock); complete(&adap->config_completion); + mutex_unlock(&adap->lock); return 0; } @@ -1552,6 +1565,7 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block) "ceccfg-%s", adap->name); if (IS_ERR(adap->kthread_config)) { adap->kthread_config = NULL; + adap->is_configuring = false; } else if (block) { mutex_unlock(&adap->lock); wait_for_completion(&adap->config_completion); @@ -1559,63 +1573,96 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block) } } +/* + * Helper function to enable/disable the CEC adapter. + * + * This function is called with adap->lock held. + */ +static int cec_adap_enable(struct cec_adapter *adap) +{ + bool enable; + int ret = 0; + + enable = adap->monitor_all_cnt || adap->monitor_pin_cnt || + adap->log_addrs.num_log_addrs; + if (adap->needs_hpd) + enable = enable && adap->phys_addr != CEC_PHYS_ADDR_INVALID; + + if (enable == adap->is_enabled) + return 0; + + /* serialize adap_enable */ + mutex_lock(&adap->devnode.lock); + if (enable) { + adap->last_initiator = 0xff; + adap->transmit_in_progress = false; + ret = adap->ops->adap_enable(adap, true); + if (!ret) { + /* + * Enable monitor-all/pin modes if needed. We warn, but + * continue if this fails as this is not a critical error. + */ + if (adap->monitor_all_cnt) + WARN_ON(call_op(adap, adap_monitor_all_enable, true)); + if (adap->monitor_pin_cnt) + WARN_ON(call_op(adap, adap_monitor_pin_enable, true)); + } + } else { + /* Disable monitor-all/pin modes if needed (needs_hpd == 1) */ + if (adap->monitor_all_cnt) + WARN_ON(call_op(adap, adap_monitor_all_enable, false)); + if (adap->monitor_pin_cnt) + WARN_ON(call_op(adap, adap_monitor_pin_enable, false)); + WARN_ON(adap->ops->adap_enable(adap, false)); + adap->last_initiator = 0xff; + adap->transmit_in_progress = false; + adap->transmit_in_progress_aborted = false; + if (adap->transmitting) + cec_data_cancel(adap->transmitting, CEC_TX_STATUS_ABORTED, 0); + } + if (!ret) + adap->is_enabled = enable; + wake_up_interruptible(&adap->kthread_waitq); + mutex_unlock(&adap->devnode.lock); + return ret; +} + /* Set a new physical address and send an event notifying userspace of this. * * This function is called with adap->lock held. */ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) { + bool becomes_invalid = phys_addr == CEC_PHYS_ADDR_INVALID; + bool is_invalid = adap->phys_addr == CEC_PHYS_ADDR_INVALID; + if (phys_addr == adap->phys_addr) return; - if (phys_addr != CEC_PHYS_ADDR_INVALID && adap->devnode.unregistered) + if (!becomes_invalid && adap->devnode.unregistered) return; dprintk(1, "new physical address %x.%x.%x.%x\n", cec_phys_addr_exp(phys_addr)); - if (phys_addr == CEC_PHYS_ADDR_INVALID || - adap->phys_addr != CEC_PHYS_ADDR_INVALID) { + if (becomes_invalid || !is_invalid) { adap->phys_addr = CEC_PHYS_ADDR_INVALID; cec_post_state_event(adap); cec_adap_unconfigure(adap); - /* Disabling monitor all mode should always succeed */ - if (adap->monitor_all_cnt) - WARN_ON(call_op(adap, adap_monitor_all_enable, false)); - /* serialize adap_enable */ - mutex_lock(&adap->devnode.lock); - if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) { - WARN_ON(adap->ops->adap_enable(adap, false)); - adap->transmit_in_progress = false; - wake_up_interruptible(&adap->kthread_waitq); - } - mutex_unlock(&adap->devnode.lock); - if (phys_addr == CEC_PHYS_ADDR_INVALID) - return; - } - - /* serialize adap_enable */ - mutex_lock(&adap->devnode.lock); - adap->last_initiator = 0xff; - adap->transmit_in_progress = false; - - if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) { - if (adap->ops->adap_enable(adap, true)) { - mutex_unlock(&adap->devnode.lock); + if (becomes_invalid) { + cec_adap_enable(adap); return; } } - if (adap->monitor_all_cnt && - call_op(adap, adap_monitor_all_enable, true)) { - if (adap->needs_hpd || list_empty(&adap->devnode.fhs)) - WARN_ON(adap->ops->adap_enable(adap, false)); - mutex_unlock(&adap->devnode.lock); - return; - } - mutex_unlock(&adap->devnode.lock); - adap->phys_addr = phys_addr; + if (is_invalid) + cec_adap_enable(adap); + cec_post_state_event(adap); - if (adap->log_addrs.num_log_addrs) + if (!adap->log_addrs.num_log_addrs) + return; + if (adap->is_configuring) + adap->must_reconfigure = true; + else cec_claim_log_addrs(adap, block); } @@ -1670,19 +1717,24 @@ int __cec_s_log_addrs(struct cec_adapter *adap, struct cec_log_addrs *log_addrs, bool block) { u16 type_mask = 0; + int err; int i; if (adap->devnode.unregistered) return -ENODEV; if (!log_addrs || log_addrs->num_log_addrs == 0) { - cec_adap_unconfigure(adap); + if (!adap->log_addrs.num_log_addrs) + return 0; + if (adap->is_configuring || adap->is_configured) + cec_adap_unconfigure(adap); adap->log_addrs.num_log_addrs = 0; for (i = 0; i < CEC_MAX_LOG_ADDRS; i++) adap->log_addrs.log_addr[i] = CEC_LOG_ADDR_INVALID; adap->log_addrs.osd_name[0] = '\0'; adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE; adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; + cec_adap_enable(adap); return 0; } @@ -1818,9 +1870,10 @@ int __cec_s_log_addrs(struct cec_adapter *adap, log_addrs->log_addr_mask = adap->log_addrs.log_addr_mask; adap->log_addrs = *log_addrs; - if (adap->phys_addr != CEC_PHYS_ADDR_INVALID) + err = cec_adap_enable(adap); + if (!err && adap->phys_addr != CEC_PHYS_ADDR_INVALID) cec_claim_log_addrs(adap, block); - return 0; + return err; } int cec_s_log_addrs(struct cec_adapter *adap, @@ -1922,11 +1975,10 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, msg->msg[1] != CEC_MSG_CDC_MESSAGE) return 0; - if (adap->ops->received) { - /* Allow drivers to process the message first */ - if (adap->ops->received(adap, msg) != -ENOMSG) - return 0; - } + /* Allow drivers to process the message first */ + if (adap->ops->received && !adap->devnode.unregistered && + adap->ops->received(adap, msg) != -ENOMSG) + return 0; /* * REPORT_PHYSICAL_ADDR, CEC_MSG_USER_CONTROL_PRESSED and @@ -2119,20 +2171,25 @@ skip_processing: */ int cec_monitor_all_cnt_inc(struct cec_adapter *adap) { - int ret = 0; + int ret; + + if (adap->monitor_all_cnt++) + return 0; - if (adap->monitor_all_cnt == 0) - ret = call_op(adap, adap_monitor_all_enable, 1); - if (ret == 0) - adap->monitor_all_cnt++; + ret = cec_adap_enable(adap); + if (ret) + adap->monitor_all_cnt--; return ret; } void cec_monitor_all_cnt_dec(struct cec_adapter *adap) { - adap->monitor_all_cnt--; - if (adap->monitor_all_cnt == 0) - WARN_ON(call_op(adap, adap_monitor_all_enable, 0)); + if (WARN_ON(!adap->monitor_all_cnt)) + return; + if (--adap->monitor_all_cnt) + return; + WARN_ON(call_op(adap, adap_monitor_all_enable, false)); + cec_adap_enable(adap); } /* @@ -2142,20 +2199,25 @@ void cec_monitor_all_cnt_dec(struct cec_adapter *adap) */ int cec_monitor_pin_cnt_inc(struct cec_adapter *adap) { - int ret = 0; + int ret; + + if (adap->monitor_pin_cnt++) + return 0; - if (adap->monitor_pin_cnt == 0) - ret = call_op(adap, adap_monitor_pin_enable, 1); - if (ret == 0) - adap->monitor_pin_cnt++; + ret = cec_adap_enable(adap); + if (ret) + adap->monitor_pin_cnt--; return ret; } void cec_monitor_pin_cnt_dec(struct cec_adapter *adap) { - adap->monitor_pin_cnt--; - if (adap->monitor_pin_cnt == 0) - WARN_ON(call_op(adap, adap_monitor_pin_enable, 0)); + if (WARN_ON(!adap->monitor_pin_cnt)) + return; + if (--adap->monitor_pin_cnt) + return; + WARN_ON(call_op(adap, adap_monitor_pin_enable, false)); + cec_adap_enable(adap); } #ifdef CONFIG_DEBUG_FS @@ -2169,6 +2231,7 @@ int cec_adap_status(struct seq_file *file, void *priv) struct cec_data *data; mutex_lock(&adap->lock); + seq_printf(file, "enabled: %d\n", adap->is_enabled); seq_printf(file, "configured: %d\n", adap->is_configured); seq_printf(file, "configuring: %d\n", adap->is_configuring); seq_printf(file, "phys_addr: %x.%x.%x.%x\n", @@ -2183,6 +2246,9 @@ int cec_adap_status(struct seq_file *file, void *priv) if (adap->monitor_all_cnt) seq_printf(file, "file handles in Monitor All mode: %u\n", adap->monitor_all_cnt); + if (adap->monitor_pin_cnt) + seq_printf(file, "file handles in Monitor Pin mode: %u\n", + adap->monitor_pin_cnt); if (adap->tx_timeouts) { seq_printf(file, "transmit timeouts: %u\n", adap->tx_timeouts); diff --git a/drivers/media/cec/core/cec-api.c b/drivers/media/cec/core/cec-api.c index d72ad48c9898..67dc79ef1705 100644 --- a/drivers/media/cec/core/cec-api.c +++ b/drivers/media/cec/core/cec-api.c @@ -586,18 +586,6 @@ static int cec_open(struct inode *inode, struct file *filp) return err; } - /* serialize adap_enable */ - mutex_lock(&devnode->lock); - if (list_empty(&devnode->fhs) && - !adap->needs_hpd && - adap->phys_addr == CEC_PHYS_ADDR_INVALID) { - err = adap->ops->adap_enable(adap, true); - if (err) { - mutex_unlock(&devnode->lock); - kfree(fh); - return err; - } - } filp->private_data = fh; /* Queue up initial state events */ @@ -607,7 +595,8 @@ static int cec_open(struct inode *inode, struct file *filp) adap->conn_info.type != CEC_CONNECTOR_TYPE_NO_CONNECTOR; cec_queue_event_fh(fh, &ev, 0); #ifdef CONFIG_CEC_PIN - if (adap->pin && adap->pin->ops->read_hpd) { + if (adap->pin && adap->pin->ops->read_hpd && + !adap->devnode.unregistered) { err = adap->pin->ops->read_hpd(adap); if (err >= 0) { ev.event = err ? CEC_EVENT_PIN_HPD_HIGH : @@ -615,7 +604,8 @@ static int cec_open(struct inode *inode, struct file *filp) cec_queue_event_fh(fh, &ev, 0); } } - if (adap->pin && adap->pin->ops->read_5v) { + if (adap->pin && adap->pin->ops->read_5v && + !adap->devnode.unregistered) { err = adap->pin->ops->read_5v(adap); if (err >= 0) { ev.event = err ? CEC_EVENT_PIN_5V_HIGH : @@ -625,6 +615,7 @@ static int cec_open(struct inode *inode, struct file *filp) } #endif + mutex_lock(&devnode->lock); mutex_lock(&devnode->lock_fhs); list_add(&fh->list, &devnode->fhs); mutex_unlock(&devnode->lock_fhs); @@ -656,15 +647,10 @@ static int cec_release(struct inode *inode, struct file *filp) cec_monitor_all_cnt_dec(adap); mutex_unlock(&adap->lock); - /* serialize adap_enable */ mutex_lock(&devnode->lock); mutex_lock(&devnode->lock_fhs); list_del(&fh->list); mutex_unlock(&devnode->lock_fhs); - if (cec_is_registered(adap) && list_empty(&devnode->fhs) && - !adap->needs_hpd && adap->phys_addr == CEC_PHYS_ADDR_INVALID) { - WARN_ON(adap->ops->adap_enable(adap, false)); - } mutex_unlock(&devnode->lock); /* Unhook pending transmits from this filehandle. */ diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c index a3ab6a43fb14..af358e901b5f 100644 --- a/drivers/media/cec/core/cec-core.c +++ b/drivers/media/cec/core/cec-core.c @@ -20,6 +20,18 @@ #define CEC_NUM_DEVICES 256 #define CEC_NAME "cec" +/* + * 400 ms is the time it takes for one 16 byte message to be + * transferred and 5 is the maximum number of retries. Add + * another 100 ms as a margin. So if the transmit doesn't + * finish before that time something is really wrong and we + * have to time out. + * + * This is a sign that something it really wrong and a warning + * will be issued. + */ +#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100) + int cec_debug; module_param_named(debug, cec_debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); @@ -204,7 +216,7 @@ static ssize_t cec_error_inj_write(struct file *file, line = strsep(&p, "\n"); if (!*line || *line == '#') continue; - if (!adap->ops->error_inj_parse_line(adap, line)) { + if (!call_op(adap, error_inj_parse_line, line)) { kfree(buf); return -EINVAL; } @@ -217,7 +229,7 @@ static int cec_error_inj_show(struct seq_file *sf, void *unused) { struct cec_adapter *adap = sf->private; - return adap->ops->error_inj_show(adap, sf); + return call_op(adap, error_inj_show, sf); } static int cec_error_inj_open(struct inode *inode, struct file *file) @@ -331,6 +343,8 @@ int cec_register_adapter(struct cec_adapter *adap, adap->owner = parent->driver->owner; adap->devnode.dev.parent = parent; + if (!adap->xfer_timeout_ms) + adap->xfer_timeout_ms = CEC_XFER_TIMEOUT_MS; #ifdef CONFIG_MEDIA_CEC_RC if (adap->capabilities & CEC_CAP_RC) { diff --git a/drivers/media/cec/core/cec-pin-priv.h b/drivers/media/cec/core/cec-pin-priv.h index 7bad5a0b7cb7..8eb5819e6ccb 100644 --- a/drivers/media/cec/core/cec-pin-priv.h +++ b/drivers/media/cec/core/cec-pin-priv.h @@ -12,6 +12,17 @@ #include <linux/atomic.h> #include <media/cec-pin.h> +#define call_pin_op(pin, op, arg...) \ + ((pin && pin->ops->op && !pin->adap->devnode.unregistered) ? \ + pin->ops->op(pin->adap, ## arg) : 0) + +#define call_void_pin_op(pin, op, arg...) \ + do { \ + if (pin && pin->ops->op && \ + !pin->adap->devnode.unregistered) \ + pin->ops->op(pin->adap, ## arg); \ + } while (0) + enum cec_pin_state { /* CEC is off */ CEC_ST_OFF, diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c index 21f0f749713e..68353c5dc501 100644 --- a/drivers/media/cec/core/cec-pin.c +++ b/drivers/media/cec/core/cec-pin.c @@ -135,7 +135,7 @@ static void cec_pin_update(struct cec_pin *pin, bool v, bool force) static bool cec_pin_read(struct cec_pin *pin) { - bool v = pin->ops->read(pin->adap); + bool v = call_pin_op(pin, read); cec_pin_update(pin, v, false); return v; @@ -143,13 +143,13 @@ static bool cec_pin_read(struct cec_pin *pin) static void cec_pin_low(struct cec_pin *pin) { - pin->ops->low(pin->adap); + call_void_pin_op(pin, low); cec_pin_update(pin, false, false); } static bool cec_pin_high(struct cec_pin *pin) { - pin->ops->high(pin->adap); + call_void_pin_op(pin, high); return cec_pin_read(pin); } @@ -1037,11 +1037,14 @@ static int cec_pin_thread_func(void *_adap) for (;;) { wait_event_interruptible(pin->kthread_waitq, - kthread_should_stop() || - pin->work_rx_msg.len || - pin->work_tx_status || - atomic_read(&pin->work_irq_change) || - atomic_read(&pin->work_pin_num_events)); + kthread_should_stop() || + pin->work_rx_msg.len || + pin->work_tx_status || + atomic_read(&pin->work_irq_change) || + atomic_read(&pin->work_pin_num_events)); + + if (kthread_should_stop()) + break; if (pin->work_rx_msg.len) { struct cec_msg *msg = &pin->work_rx_msg; @@ -1086,10 +1089,12 @@ static int cec_pin_thread_func(void *_adap) CEC_PIN_IRQ_UNCHANGED)) { case CEC_PIN_IRQ_DISABLE: if (irq_enabled) { - pin->ops->disable_irq(adap); + call_void_pin_op(pin, disable_irq); irq_enabled = false; } cec_pin_high(pin); + if (pin->state == CEC_ST_OFF) + break; cec_pin_to_idle(pin); hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); @@ -1097,7 +1102,7 @@ static int cec_pin_thread_func(void *_adap) case CEC_PIN_IRQ_ENABLE: if (irq_enabled) break; - pin->enable_irq_failed = !pin->ops->enable_irq(adap); + pin->enable_irq_failed = !call_pin_op(pin, enable_irq); if (pin->enable_irq_failed) { cec_pin_to_idle(pin); hrtimer_start(&pin->timer, ns_to_ktime(0), @@ -1109,15 +1114,7 @@ static int cec_pin_thread_func(void *_adap) default: break; } - if (kthread_should_stop()) - break; } - if (pin->ops->disable_irq && irq_enabled) - pin->ops->disable_irq(adap); - hrtimer_cancel(&pin->timer); - cec_pin_read(pin); - cec_pin_to_idle(pin); - pin->state = CEC_ST_OFF; return 0; } @@ -1126,24 +1123,32 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) struct cec_pin *pin = adap->pin; if (enable) { - atomic_set(&pin->work_pin_num_events, 0); - pin->work_pin_events_rd = pin->work_pin_events_wr = 0; - pin->work_pin_events_dropped = false; cec_pin_read(pin); cec_pin_to_idle(pin); pin->tx_msg.len = 0; pin->timer_ts = ns_to_ktime(0); atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); - pin->kthread = kthread_run(cec_pin_thread_func, adap, - "cec-pin"); - if (IS_ERR(pin->kthread)) { - pr_err("cec-pin: kernel_thread() failed\n"); - return PTR_ERR(pin->kthread); + if (!pin->kthread) { + pin->kthread = kthread_run(cec_pin_thread_func, adap, + "cec-pin"); + if (IS_ERR(pin->kthread)) { + int err = PTR_ERR(pin->kthread); + + pr_err("cec-pin: kernel_thread() failed\n"); + pin->kthread = NULL; + return err; + } } hrtimer_start(&pin->timer, ns_to_ktime(0), HRTIMER_MODE_REL); - } else { - kthread_stop(pin->kthread); + } else if (pin->kthread) { + hrtimer_cancel(&pin->timer); + cec_pin_high(pin); + cec_pin_to_idle(pin); + pin->state = CEC_ST_OFF; + pin->work_tx_status = 0; + atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_DISABLE); + wake_up_interruptible(&pin->kthread_waitq); } return 0; } @@ -1207,7 +1212,7 @@ static void cec_pin_adap_status(struct cec_adapter *adap, seq_printf(file, "state: %s\n", states[pin->state].name); seq_printf(file, "tx_bit: %d\n", pin->tx_bit); seq_printf(file, "rx_bit: %d\n", pin->rx_bit); - seq_printf(file, "cec pin: %d\n", pin->ops->read(adap)); + seq_printf(file, "cec pin: %d\n", call_pin_op(pin, read)); seq_printf(file, "cec pin events dropped: %u\n", pin->work_pin_events_dropped_cnt); seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed); @@ -1260,8 +1265,7 @@ static void cec_pin_adap_status(struct cec_adapter *adap, pin->rx_data_bit_too_long_cnt = 0; pin->rx_low_drive_cnt = 0; pin->tx_low_drive_cnt = 0; - if (pin->ops->status) - pin->ops->status(adap, file); + call_void_pin_op(pin, status, file); } static int cec_pin_adap_monitor_all_enable(struct cec_adapter *adap, @@ -1277,6 +1281,9 @@ static void cec_pin_adap_free(struct cec_adapter *adap) { struct cec_pin *pin = adap->pin; + if (pin->kthread) + kthread_stop(pin->kthread); + pin->kthread = NULL; if (pin->ops->free) pin->ops->free(adap); adap->pin = NULL; @@ -1287,7 +1294,7 @@ static int cec_pin_received(struct cec_adapter *adap, struct cec_msg *msg) { struct cec_pin *pin = adap->pin; - if (pin->ops->received) + if (pin->ops->received && !adap->devnode.unregistered) return pin->ops->received(adap, msg); return -ENOMSG; } @@ -1327,6 +1334,7 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, return ERR_PTR(-ENOMEM); pin->ops = pin_ops; hrtimer_init(&pin->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + atomic_set(&pin->work_pin_num_events, 0); pin->timer.function = cec_pin_timer; init_waitqueue_head(&pin->kthread_waitq); pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT; diff --git a/drivers/media/cec/core/cec-priv.h b/drivers/media/cec/core/cec-priv.h index 9bbd05053d42..b78df931aa74 100644 --- a/drivers/media/cec/core/cec-priv.h +++ b/drivers/media/cec/core/cec-priv.h @@ -17,6 +17,16 @@ pr_info("cec-%s: " fmt, adap->name, ## arg); \ } while (0) +#define call_op(adap, op, arg...) \ + ((adap->ops->op && !adap->devnode.unregistered) ? \ + adap->ops->op(adap, ## arg) : 0) + +#define call_void_op(adap, op, arg...) \ + do { \ + if (adap->ops->op && !adap->devnode.unregistered) \ + adap->ops->op(adap, ## arg); \ + } while (0) + /* devnode to cec_adapter */ #define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode) diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c index 51a6fcfd077d..580905e3d066 100644 --- a/drivers/media/cec/platform/seco/seco-cec.c +++ b/drivers/media/cec/platform/seco/seco-cec.c @@ -31,29 +31,17 @@ struct secocec_data { int irq; }; -#define smb_wr16(cmd, data) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \ - cmd, data, SMBUS_WRITE, NULL) -#define smb_rd16(cmd, res) smb_word_op(CMD_WORD_DATA, SECOCEC_MICRO_ADDRESS, \ +#define smb_wr16(cmd, data) smb_word_op(SECOCEC_MICRO_ADDRESS, \ + cmd, data, SMBUS_WRITE, NULL) +#define smb_rd16(cmd, res) smb_word_op(SECOCEC_MICRO_ADDRESS, \ cmd, 0, SMBUS_READ, res) -static int smb_word_op(short data_format, u16 slave_addr, u8 cmd, u16 data, +static int smb_word_op(u16 slave_addr, u8 cmd, u16 data, u8 operation, u16 *result) { unsigned int count; - short _data_format; int status = 0; - switch (data_format) { - case CMD_BYTE_DATA: - _data_format = BRA_SMB_CMD_BYTE_DATA; - break; - case CMD_WORD_DATA: - _data_format = BRA_SMB_CMD_WORD_DATA; - break; - default: - return -EINVAL; - } - /* Active wait until ready */ for (count = 0; count <= SMBTIMEOUT; ++count) { if (!(inb(HSTS) & BRA_INUSE_STS)) @@ -75,7 +63,7 @@ static int smb_word_op(short data_format, u16 slave_addr, u8 cmd, u16 data, outb((u8)(data >> 8), HDAT1); } - outb(BRA_START + _data_format, HCNT); + outb(BRA_START + BRA_SMB_CMD_WORD_DATA, HCNT); for (count = 0; count <= SMBTIMEOUT; count++) { if (!(inb(HSTS) & BRA_HOST_BUSY)) diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 66215d9106a4..2296765079a4 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -443,7 +443,6 @@ static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability * strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver)); strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); - sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index f8a21c560ad2..fa69158a65b1 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -126,8 +126,7 @@ static void *vb2_dma_sg_alloc(struct vb2_buffer *vb, struct device *dev, * there is no memory consistency guarantee, hence dma-sg ignores DMA * attributes passed from the upper layer. */ - buf->pages = kvmalloc_array(buf->num_pages, sizeof(struct page *), - GFP_KERNEL | __GFP_ZERO); + buf->pages = kvcalloc(buf->num_pages, sizeof(struct page *), GFP_KERNEL); if (!buf->pages) goto fail_pages_array_alloc; diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index 6edf4508c636..075d24ebf44c 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -977,12 +977,6 @@ EXPORT_SYMBOL_GPL(vb2_poll); * and so they simplify the driver code. */ -/* The queue is busy if there is a owner and you are not that owner. */ -static inline bool vb2_queue_is_busy(struct video_device *vdev, struct file *file) -{ - return vdev->queue->owner && vdev->queue->owner != file->private_data; -} - /* vb2 ioctl helpers */ int vb2_ioctl_reqbufs(struct file *file, void *priv, @@ -997,7 +991,7 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv, p->flags = flags; if (res) return res; - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY; res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count); /* If count == 0, then the owner has released all buffers and he @@ -1026,7 +1020,7 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv, return res != -EBUSY ? res : 0; if (res) return res; - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY; res = vb2_create_bufs(vdev->queue, p); @@ -1041,7 +1035,7 @@ int vb2_ioctl_prepare_buf(struct file *file, void *priv, { struct video_device *vdev = video_devdata(file); - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY; return vb2_prepare_buf(vdev->queue, vdev->v4l2_dev->mdev, p); } @@ -1060,7 +1054,7 @@ int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct video_device *vdev = video_devdata(file); - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY; return vb2_qbuf(vdev->queue, vdev->v4l2_dev->mdev, p); } @@ -1070,7 +1064,7 @@ int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct video_device *vdev = video_devdata(file); - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY; return vb2_dqbuf(vdev->queue, p, file->f_flags & O_NONBLOCK); } @@ -1080,7 +1074,7 @@ int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct video_device *vdev = video_devdata(file); - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY; return vb2_streamon(vdev->queue, i); } @@ -1090,7 +1084,7 @@ int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct video_device *vdev = video_devdata(file); - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY; return vb2_streamoff(vdev->queue, i); } @@ -1100,7 +1094,7 @@ int vb2_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *p) { struct video_device *vdev = video_devdata(file); - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) return -EBUSY; return vb2_expbuf(vdev->queue, p); } @@ -1152,7 +1146,7 @@ ssize_t vb2_fop_write(struct file *file, const char __user *buf, return -EINVAL; if (lock && mutex_lock_interruptible(lock)) return -ERESTARTSYS; - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) goto exit; err = vb2_write(vdev->queue, buf, count, ppos, file->f_flags & O_NONBLOCK); @@ -1176,7 +1170,7 @@ ssize_t vb2_fop_read(struct file *file, char __user *buf, return -EINVAL; if (lock && mutex_lock_interruptible(lock)) return -ERESTARTSYS; - if (vb2_queue_is_busy(vdev, file)) + if (vb2_queue_is_busy(vdev->queue, file)) goto exit; err = vb2_read(vdev->queue, buf, count, ppos, file->f_flags & O_NONBLOCK); diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index fae2baabb773..2b20aa6c37b1 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -372,6 +372,7 @@ config VIDEO_OV13B10 config VIDEO_OV2640 tristate "OmniVision OV2640 sensor support" depends on VIDEO_DEV && I2C + select V4L2_ASYNC help This is a Video4Linux2 sensor driver for the OmniVision OV2640 camera. diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 4f5db195e66d..e3a57c178c6b 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -66,6 +66,9 @@ #define ADV7180_HUE_DEF 0 #define ADV7180_HUE_MAX 128 +#define ADV7180_REG_DEF_VALUE_Y 0x000c +#define ADV7180_DEF_VAL_EN 0x1 +#define ADV7180_DEF_VAL_AUTO_EN 0x2 #define ADV7180_REG_CTRL 0x000e #define ADV7180_CTRL_IRQ_SPACE 0x20 @@ -549,6 +552,40 @@ static int adv7180_s_power(struct v4l2_subdev *sd, int on) return ret; } +static const char * const test_pattern_menu[] = { + "Single color", + "Color bars", + "Luma ramp", + "Boundary box", + "Disable", +}; + +static int adv7180_test_pattern(struct adv7180_state *state, int value) +{ + unsigned int reg = 0; + + /* Map menu value into register value */ + if (value < 3) + reg = value; + if (value == 3) + reg = 5; + + adv7180_write(state, ADV7180_REG_ANALOG_CLAMP_CTL, reg); + + if (value == ARRAY_SIZE(test_pattern_menu) - 1) { + reg = adv7180_read(state, ADV7180_REG_DEF_VALUE_Y); + reg &= ~ADV7180_DEF_VAL_EN; + adv7180_write(state, ADV7180_REG_DEF_VALUE_Y, reg); + return 0; + } + + reg = adv7180_read(state, ADV7180_REG_DEF_VALUE_Y); + reg |= ADV7180_DEF_VAL_EN | ADV7180_DEF_VAL_AUTO_EN; + adv7180_write(state, ADV7180_REG_DEF_VALUE_Y, reg); + + return 0; +} + static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) { struct v4l2_subdev *sd = to_adv7180_sd(ctrl); @@ -592,6 +629,9 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00); } break; + case V4L2_CID_TEST_PATTERN: + ret = adv7180_test_pattern(state, val); + break; default: ret = -EINVAL; } @@ -632,6 +672,12 @@ static int adv7180_init_controls(struct adv7180_state *state) ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF); v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL); + v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, &adv7180_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(test_pattern_menu) - 1, + 0, ARRAY_SIZE(test_pattern_menu) - 1, + test_pattern_menu); + state->sd.ctrl_handler = &state->ctrl_hdl; if (state->ctrl_hdl.error) { int err = state->ctrl_hdl.error; diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 03e841b8443f..7609add2aff4 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -121,7 +121,7 @@ void ccs_replace_limit(struct ccs_sensor *sensor, linfo = &ccs_limits[ccs_limit_offsets[limit].info]; - dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %d, 0x%x\n", + dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %u, 0x%x\n", linfo->reg, linfo->name, offset, val, val); ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val); @@ -288,7 +288,7 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor) CCS_FRAME_FORMAT_DESCRIPTOR_4_PIXELS_MASK; } else { dev_dbg(&client->dev, - "invalid frame format model type %d\n", + "invalid frame format model type %u\n", fmt_model_type); return -EINVAL; } @@ -320,7 +320,7 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor) } dev_dbg(&client->dev, - "%s pixels: %d %s (pixelcode %u)\n", + "%s pixels: %u %s (pixelcode %u)\n", what, pixels, which, pixelcode); if (i < ncol_desc) { @@ -353,9 +353,9 @@ static int ccs_read_frame_fmt(struct ccs_sensor *sensor) sensor->image_start = sensor->embedded_end; } - dev_dbg(&client->dev, "embedded data from lines %d to %d\n", + dev_dbg(&client->dev, "embedded data from lines %u to %u\n", sensor->embedded_start, sensor->embedded_end); - dev_dbg(&client->dev, "image data starts at line %d\n", + dev_dbg(&client->dev, "image data starts at line %u\n", sensor->image_start); return 0; @@ -571,7 +571,7 @@ static u32 ccs_pixel_order(struct ccs_sensor *sensor) flip ^= sensor->hvflip_inv_mask; - dev_dbg(&client->dev, "flip %d\n", flip); + dev_dbg(&client->dev, "flip %u\n", flip); return sensor->default_pixel_order ^ flip; } @@ -1056,18 +1056,18 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor) type = CCS_LIM(sensor, DATA_FORMAT_MODEL_TYPE); - dev_dbg(&client->dev, "data_format_model_type %d\n", type); + dev_dbg(&client->dev, "data_format_model_type %u\n", type); rval = ccs_read(sensor, PIXEL_ORDER, &pixel_order); if (rval) return rval; if (pixel_order >= ARRAY_SIZE(pixel_order_str)) { - dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order); + dev_dbg(&client->dev, "bad pixel order %u\n", pixel_order); return -EINVAL; } - dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order, + dev_dbg(&client->dev, "pixel order %u (%s)\n", pixel_order, pixel_order_str[pixel_order]); switch (type) { @@ -1105,7 +1105,7 @@ static int ccs_get_mbus_formats(struct ccs_sensor *sensor) (fmt & CCS_DATA_FORMAT_DESCRIPTOR_COMPRESSED_MASK)) continue; - dev_dbg(&client->dev, "jolly good! %d\n", j); + dev_dbg(&client->dev, "jolly good! %u\n", j); sensor->default_mbus_frame_fmts |= 1 << j; } @@ -1602,8 +1602,11 @@ static int ccs_power_on(struct device *dev) usleep_range(1000, 2000); } while (--retry); - if (!reset) - return -EIO; + if (!reset) { + dev_err(dev, "software reset failed\n"); + rval = -EIO; + goto out_cci_addr_fail; + } } if (sensor->hwcfg.i2c_addr_alt) { @@ -1999,7 +2002,7 @@ static int ccs_enum_mbus_code(struct v4l2_subdev *subdev, mutex_lock(&sensor->mutex); - dev_err(&client->dev, "subdev %s, pad %d, index %d\n", + dev_err(&client->dev, "subdev %s, pad %u, index %u\n", subdev->name, code->pad, code->index); if (subdev != &sensor->src->sd || code->pad != CCS_PAD_SRC) { @@ -2017,7 +2020,7 @@ static int ccs_enum_mbus_code(struct v4l2_subdev *subdev, if (idx == code->index) { code->code = ccs_csi_data_formats[i].code; - dev_err(&client->dev, "found index %d, i %d, code %x\n", + dev_err(&client->dev, "found index %u, i %u, code %x\n", code->index, i, code->code); rval = 0; break; @@ -2386,7 +2389,7 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, max_m = clamp(max_m, CCS_LIM(sensor, SCALER_M_MIN), CCS_LIM(sensor, SCALER_M_MAX)); - dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m); + dev_dbg(&client->dev, "scaling: a %u b %u max_m %u\n", a, b, max_m); min = min(max_m, min(a, b)); max = min(max_m, max(a, b)); @@ -2416,7 +2419,7 @@ static void ccs_set_compose_scaler(struct v4l2_subdev *subdev, sel->r.height, sel->flags); - dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i); + dev_dbg(&client->dev, "trying factor %u (%u)\n", try[i], i); if (this > best) { scale_m = try[i]; @@ -3183,7 +3186,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); u32 rotation; - int i; + unsigned int i; int rval; ep = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, @@ -3221,8 +3224,6 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) goto out_err; } - dev_dbg(dev, "lanes %u\n", hwcfg->lanes); - rval = fwnode_property_read_u32(fwnode, "rotation", &rotation); if (!rval) { switch (rotation) { @@ -3244,7 +3245,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) if (rval) dev_info(dev, "can't get clock-frequency\n"); - dev_dbg(dev, "clk %d, mode %d\n", hwcfg->ext_clk, + dev_dbg(dev, "clk %u, mode %u\n", hwcfg->ext_clk, hwcfg->csi_signalling_mode); if (!bus_cfg.nr_of_link_frequencies) { @@ -3263,7 +3264,7 @@ static int ccs_get_hwconfig(struct ccs_sensor *sensor, struct device *dev) for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i]; - dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]); + dev_dbg(dev, "freq %u: %lld\n", i, hwcfg->op_sys_clock[i]); } v4l2_fwnode_endpoint_free(&bus_cfg); diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c index cd7008ad8f2f..206d74338b9c 100644 --- a/drivers/media/i2c/dw9714.c +++ b/drivers/media/i2c/dw9714.c @@ -183,6 +183,7 @@ static int dw9714_probe(struct i2c_client *client) return 0; err_cleanup: + regulator_disable(dw9714_dev->vcc); v4l2_ctrl_handler_free(&dw9714_dev->ctrls_vcm); media_entity_cleanup(&dw9714_dev->sd.entity); @@ -201,7 +202,6 @@ static int dw9714_remove(struct i2c_client *client) if (ret) { dev_err(&client->dev, "Failed to disable vcc: %d\n", ret); - return ret; } } pm_runtime_set_suspended(&client->dev); diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c index 65c6acf3ced9..c086580efac7 100644 --- a/drivers/media/i2c/dw9768.c +++ b/drivers/media/i2c/dw9768.c @@ -469,11 +469,6 @@ static int dw9768_probe(struct i2c_client *client) dw9768->sd.entity.function = MEDIA_ENT_F_LENS; - /* - * Device is already turned on by i2c-core with ACPI domain PM. - * Attempt to turn off the device to satisfy the privacy LED concerns. - */ - pm_runtime_set_active(dev); pm_runtime_enable(dev); if (!pm_runtime_enabled(dev)) { ret = dw9768_runtime_resume(dev); @@ -488,7 +483,6 @@ static int dw9768_probe(struct i2c_client *client) dev_err(dev, "failed to register V4L2 subdev: %d", ret); goto err_power_off; } - pm_runtime_idle(dev); return 0; diff --git a/drivers/media/i2c/dw9807-vcm.c b/drivers/media/i2c/dw9807-vcm.c index 95e06f13bc9e..01c372925a80 100644 --- a/drivers/media/i2c/dw9807-vcm.c +++ b/drivers/media/i2c/dw9807-vcm.c @@ -295,6 +295,8 @@ static int __maybe_unused dw9807_vcm_resume(struct device *dev) static const struct of_device_id dw9807_of_table[] = { { .compatible = "dongwoon,dw9807-vcm" }, + /* Compatibility for older firmware, NEVER USE THIS IN FIRMWARE! */ + { .compatible = "dongwoon,dw9807" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, dw9807_of_table); diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index be3f6ea55559..a1394d6c1432 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -11,6 +11,7 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-fwnode.h> @@ -101,6 +102,12 @@ struct imx412_mode { struct imx412_reg_list reg_list; }; +static const char * const imx412_supply_names[] = { + "dovdd", /* Digital I/O power */ + "avdd", /* Analog power */ + "dvdd", /* Digital core power */ +}; + /** * struct imx412 - imx412 sensor device structure * @dev: Pointer to generic device @@ -109,6 +116,7 @@ struct imx412_mode { * @pad: Media pad. Only one pad supported * @reset_gpio: Sensor reset gpio * @inclk: Sensor input clock + * @supplies: Regulator supplies * @ctrl_handler: V4L2 control handler * @link_freq_ctrl: Pointer to link frequency control * @pclk_ctrl: Pointer to pixel clock control @@ -128,6 +136,7 @@ struct imx412 { struct media_pad pad; struct gpio_desc *reset_gpio; struct clk *inclk; + struct regulator_bulk_data supplies[ARRAY_SIZE(imx412_supply_names)]; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_ctrl *link_freq_ctrl; struct v4l2_ctrl *pclk_ctrl; @@ -946,6 +955,16 @@ static int imx412_parse_hw_config(struct imx412 *imx412) return -EINVAL; } + /* Get optional DT defined regulators */ + for (i = 0; i < ARRAY_SIZE(imx412_supply_names); i++) + imx412->supplies[i].supply = imx412_supply_names[i]; + + ret = devm_regulator_bulk_get(imx412->dev, + ARRAY_SIZE(imx412_supply_names), + imx412->supplies); + if (ret) + return ret; + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -1011,7 +1030,14 @@ static int imx412_power_on(struct device *dev) struct imx412 *imx412 = to_imx412(sd); int ret; - gpiod_set_value_cansleep(imx412->reset_gpio, 1); + ret = regulator_bulk_enable(ARRAY_SIZE(imx412_supply_names), + imx412->supplies); + if (ret < 0) { + dev_err(dev, "failed to enable regulators\n"); + return ret; + } + + gpiod_set_value_cansleep(imx412->reset_gpio, 0); ret = clk_prepare_enable(imx412->inclk); if (ret) { @@ -1024,7 +1050,9 @@ static int imx412_power_on(struct device *dev) return 0; error_reset: - gpiod_set_value_cansleep(imx412->reset_gpio, 0); + gpiod_set_value_cansleep(imx412->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(imx412_supply_names), + imx412->supplies); return ret; } @@ -1040,10 +1068,13 @@ static int imx412_power_off(struct device *dev) struct v4l2_subdev *sd = dev_get_drvdata(dev); struct imx412 *imx412 = to_imx412(sd); - gpiod_set_value_cansleep(imx412->reset_gpio, 0); - clk_disable_unprepare(imx412->inclk); + gpiod_set_value_cansleep(imx412->reset_gpio, 1); + + regulator_bulk_disable(ARRAY_SIZE(imx412_supply_names), + imx412->supplies); + return 0; } diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index d2a4915ed9f7..3684faa72253 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -1147,22 +1147,18 @@ static int max9286_poc_enable(struct max9286_priv *priv, bool enable) return ret; } -static int max9286_init(struct device *dev) +static int max9286_init(struct max9286_priv *priv) { - struct max9286_priv *priv; - struct i2c_client *client; + struct i2c_client *client = priv->client; int ret; - client = to_i2c_client(dev); - priv = i2c_get_clientdata(client); - ret = max9286_poc_enable(priv, true); if (ret) return ret; ret = max9286_setup(priv); if (ret) { - dev_err(dev, "Unable to setup max9286\n"); + dev_err(&client->dev, "Unable to setup max9286\n"); goto err_poc_disable; } @@ -1172,13 +1168,13 @@ static int max9286_init(struct device *dev) */ ret = max9286_v4l2_register(priv); if (ret) { - dev_err(dev, "Failed to register with V4L2\n"); + dev_err(&client->dev, "Failed to register with V4L2\n"); goto err_poc_disable; } ret = max9286_i2c_mux_init(priv); if (ret) { - dev_err(dev, "Unable to initialize I2C multiplexer\n"); + dev_err(&client->dev, "Unable to initialize I2C multiplexer\n"); goto err_v4l2_register; } @@ -1333,7 +1329,6 @@ static int max9286_probe(struct i2c_client *client) mutex_init(&priv->mutex); priv->client = client; - i2c_set_clientdata(client, priv); priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable", GPIOD_OUT_HIGH); @@ -1369,7 +1364,7 @@ static int max9286_probe(struct i2c_client *client) if (ret) goto err_powerdown; - ret = max9286_init(&client->dev); + ret = max9286_init(priv); if (ret < 0) goto err_cleanup_dt; @@ -1385,7 +1380,7 @@ err_powerdown: static int max9286_remove(struct i2c_client *client) { - struct max9286_priv *priv = i2c_get_clientdata(client); + struct max9286_priv *priv = sd_to_max9286(i2c_get_clientdata(client)); i2c_mux_del_adapters(priv->mux); diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 368fa21e675e..562c62f192c4 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -843,7 +843,7 @@ static int ov5645_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - code->code = MEDIA_BUS_FMT_UYVY8_2X8; + code->code = MEDIA_BUS_FMT_UYVY8_1X16; return 0; } @@ -852,7 +852,7 @@ static int ov5645_enum_frame_size(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_size_enum *fse) { - if (fse->code != MEDIA_BUS_FMT_UYVY8_2X8) + if (fse->code != MEDIA_BUS_FMT_UYVY8_1X16) return -EINVAL; if (fse->index >= ARRAY_SIZE(ov5645_mode_info_data)) @@ -948,7 +948,7 @@ static int ov5645_set_format(struct v4l2_subdev *sd, format->which); __format->width = __crop->width; __format->height = __crop->height; - __format->code = MEDIA_BUS_FMT_UYVY8_2X8; + __format->code = MEDIA_BUS_FMT_UYVY8_1X16; __format->field = V4L2_FIELD_NONE; __format->colorspace = V4L2_COLORSPACE_SRGB; @@ -1283,7 +1283,7 @@ MODULE_DEVICE_TABLE(of, ov5645_of_match); static struct i2c_driver ov5645_i2c_driver = { .driver = { - .of_match_table = of_match_ptr(ov5645_of_match), + .of_match_table = ov5645_of_match, .name = "ov5645", }, .probe_new = ov5645_probe, diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c index 930ff6897044..dfcd33e9ee13 100644 --- a/drivers/media/i2c/ov5648.c +++ b/drivers/media/i2c/ov5648.c @@ -2498,9 +2498,9 @@ static int ov5648_probe(struct i2c_client *client) /* DOVDD: digital I/O */ sensor->dovdd = devm_regulator_get(dev, "dovdd"); - if (IS_ERR(sensor->dvdd)) { + if (IS_ERR(sensor->dovdd)) { dev_err(dev, "cannot get DOVDD (digital I/O) regulator\n"); - ret = PTR_ERR(sensor->dvdd); + ret = PTR_ERR(sensor->dovdd); goto error_endpoint; } diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 439385938a51..910309783885 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1122,7 +1122,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_EXPOSURE: - /* 4 least significant bits of expsoure are fractional part */ + /* 4 least significant bits of exposure are fractional part */ ret = ov5695_write_reg(ov5695->client, OV5695_REG_EXPOSURE, OV5695_REG_VALUE_24BIT, ctrl->val << 4); break; diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index ebb299f207e5..0e7be15bc20a 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -14,6 +14,8 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/types.h> @@ -41,6 +43,29 @@ #define OV7251_TIMING_FORMAT2_MIRROR BIT(2) #define OV7251_PRE_ISP_00 0x5e00 #define OV7251_PRE_ISP_00_TEST_PATTERN BIT(7) +#define OV7251_PLL1_PRE_DIV_REG 0x30b4 +#define OV7251_PLL1_MULT_REG 0x30b3 +#define OV7251_PLL1_DIVIDER_REG 0x30b1 +#define OV7251_PLL1_PIX_DIV_REG 0x30b0 +#define OV7251_PLL1_MIPI_DIV_REG 0x30b5 +#define OV7251_PLL2_PRE_DIV_REG 0x3098 +#define OV7251_PLL2_MULT_REG 0x3099 +#define OV7251_PLL2_DIVIDER_REG 0x309d +#define OV7251_PLL2_SYS_DIV_REG 0x309a +#define OV7251_PLL2_ADC_DIV_REG 0x309b + +#define OV7251_NATIVE_WIDTH 656 +#define OV7251_NATIVE_HEIGHT 496 +#define OV7251_ACTIVE_START_LEFT 4 +#define OV7251_ACTIVE_START_TOP 4 +#define OV7251_ACTIVE_WIDTH 648 +#define OV7251_ACTIVE_HEIGHT 488 + +#define OV7251_FIXED_PPL 928 +#define OV7251_TIMING_VTS_REG 0x380e +#define OV7251_TIMING_MIN_VTS 1 +#define OV7251_TIMING_MAX_VTS 0xffff +#define OV7251_INTEGRATION_MARGIN 20 struct reg_value { u16 reg; @@ -50,6 +75,7 @@ struct reg_value { struct ov7251_mode_info { u32 width; u32 height; + u32 vts; const struct reg_value *data; u32 data_size; u32 pixel_clock; @@ -59,6 +85,43 @@ struct ov7251_mode_info { struct v4l2_fract timeperframe; }; +struct ov7251_pll1_cfg { + unsigned int pre_div; + unsigned int mult; + unsigned int div; + unsigned int pix_div; + unsigned int mipi_div; +}; + +struct ov7251_pll2_cfg { + unsigned int pre_div; + unsigned int mult; + unsigned int div; + unsigned int sys_div; + unsigned int adc_div; +}; + +/* + * Rubbish ordering, but only PLL1 needs to have a separate configuration per + * link frequency and the array member needs to be last. + */ +struct ov7251_pll_cfgs { + const struct ov7251_pll2_cfg *pll2; + const struct ov7251_pll1_cfg *pll1[]; +}; + +enum xclk_rate { + OV7251_19_2_MHZ, + OV7251_24_MHZ, + OV7251_NUM_SUPPORTED_RATES +}; + +enum supported_link_freqs { + OV7251_LINK_FREQ_240_MHZ, + OV7251_LINK_FREQ_319_2_MHZ, + OV7251_NUM_SUPPORTED_LINK_FREQS +}; + struct ov7251 { struct i2c_client *i2c_client; struct device *dev; @@ -74,6 +137,8 @@ struct ov7251 { struct regulator *core_regulator; struct regulator *analog_regulator; + const struct ov7251_pll_cfgs *pll_cfgs; + enum supported_link_freqs link_freq_idx; const struct ov7251_mode_info *current_mode; struct v4l2_ctrl_handler ctrls; @@ -81,6 +146,8 @@ struct ov7251 { struct v4l2_ctrl *link_freq; struct v4l2_ctrl *exposure; struct v4l2_ctrl *gain; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; /* Cached register values */ u8 aec_pk_manual; @@ -99,6 +166,75 @@ static inline struct ov7251 *to_ov7251(struct v4l2_subdev *sd) return container_of(sd, struct ov7251, sd); } +static const struct ov7251_pll1_cfg ov7251_pll1_cfg_19_2_mhz_240_mhz = { + .pre_div = 0x03, + .mult = 0x4b, + .div = 0x01, + .pix_div = 0x0a, + .mipi_div = 0x05, +}; + +static const struct ov7251_pll1_cfg ov7251_pll1_cfg_19_2_mhz_319_2_mhz = { + .pre_div = 0x01, + .mult = 0x85, + .div = 0x04, + .pix_div = 0x0a, + .mipi_div = 0x05, +}; + +static const struct ov7251_pll1_cfg ov7251_pll1_cfg_24_mhz_240_mhz = { + .pre_div = 0x03, + .mult = 0x64, + .div = 0x01, + .pix_div = 0x0a, + .mipi_div = 0x05, +}; + +static const struct ov7251_pll1_cfg ov7251_pll1_cfg_24_mhz_319_2_mhz = { + .pre_div = 0x05, + .mult = 0x85, + .div = 0x02, + .pix_div = 0x0a, + .mipi_div = 0x05, +}; + +static const struct ov7251_pll2_cfg ov7251_pll2_cfg_19_2_mhz = { + .pre_div = 0x04, + .mult = 0x32, + .div = 0x00, + .sys_div = 0x05, + .adc_div = 0x04, +}; + +static const struct ov7251_pll2_cfg ov7251_pll2_cfg_24_mhz = { + .pre_div = 0x04, + .mult = 0x28, + .div = 0x00, + .sys_div = 0x05, + .adc_div = 0x04, +}; + +static const struct ov7251_pll_cfgs ov7251_pll_cfgs_19_2_mhz = { + .pll2 = &ov7251_pll2_cfg_19_2_mhz, + .pll1 = { + [OV7251_LINK_FREQ_240_MHZ] = &ov7251_pll1_cfg_19_2_mhz_240_mhz, + [OV7251_LINK_FREQ_319_2_MHZ] = &ov7251_pll1_cfg_19_2_mhz_319_2_mhz, + }, +}; + +static const struct ov7251_pll_cfgs ov7251_pll_cfgs_24_mhz = { + .pll2 = &ov7251_pll2_cfg_24_mhz, + .pll1 = { + [OV7251_LINK_FREQ_240_MHZ] = &ov7251_pll1_cfg_24_mhz_240_mhz, + [OV7251_LINK_FREQ_319_2_MHZ] = &ov7251_pll1_cfg_24_mhz_319_2_mhz, + }, +}; + +static const struct ov7251_pll_cfgs *ov7251_pll_cfgs[] = { + [OV7251_19_2_MHZ] = &ov7251_pll_cfgs_19_2_mhz, + [OV7251_24_MHZ] = &ov7251_pll_cfgs_24_mhz, +}; + static const struct reg_value ov7251_global_init_setting[] = { { 0x0103, 0x01 }, { 0x303b, 0x02 }, @@ -117,16 +253,6 @@ static const struct reg_value ov7251_setting_vga_30fps[] = { { 0x301c, 0xf0 }, { 0x3023, 0x05 }, { 0x3037, 0xf0 }, - { 0x3098, 0x04 }, /* pll2 pre divider */ - { 0x3099, 0x28 }, /* pll2 multiplier */ - { 0x309a, 0x05 }, /* pll2 sys divider */ - { 0x309b, 0x04 }, /* pll2 adc divider */ - { 0x309d, 0x00 }, /* pll2 divider */ - { 0x30b0, 0x0a }, /* pll1 pix divider */ - { 0x30b1, 0x01 }, /* pll1 divider */ - { 0x30b3, 0x64 }, /* pll1 multiplier */ - { 0x30b4, 0x03 }, /* pll1 pre divider */ - { 0x30b5, 0x05 }, /* pll1 mipi divider */ { 0x3106, 0xda }, { 0x3503, 0x07 }, { 0x3509, 0x10 }, @@ -255,16 +381,6 @@ static const struct reg_value ov7251_setting_vga_60fps[] = { { 0x301c, 0x00 }, { 0x3023, 0x05 }, { 0x3037, 0xf0 }, - { 0x3098, 0x04 }, /* pll2 pre divider */ - { 0x3099, 0x28 }, /* pll2 multiplier */ - { 0x309a, 0x05 }, /* pll2 sys divider */ - { 0x309b, 0x04 }, /* pll2 adc divider */ - { 0x309d, 0x00 }, /* pll2 divider */ - { 0x30b0, 0x0a }, /* pll1 pix divider */ - { 0x30b1, 0x01 }, /* pll1 divider */ - { 0x30b3, 0x64 }, /* pll1 multiplier */ - { 0x30b4, 0x03 }, /* pll1 pre divider */ - { 0x30b5, 0x05 }, /* pll1 mipi divider */ { 0x3106, 0xda }, { 0x3503, 0x07 }, { 0x3509, 0x10 }, @@ -393,16 +509,6 @@ static const struct reg_value ov7251_setting_vga_90fps[] = { { 0x301c, 0x00 }, { 0x3023, 0x05 }, { 0x3037, 0xf0 }, - { 0x3098, 0x04 }, /* pll2 pre divider */ - { 0x3099, 0x28 }, /* pll2 multiplier */ - { 0x309a, 0x05 }, /* pll2 sys divider */ - { 0x309b, 0x04 }, /* pll2 adc divider */ - { 0x309d, 0x00 }, /* pll2 divider */ - { 0x30b0, 0x0a }, /* pll1 pix divider */ - { 0x30b1, 0x01 }, /* pll1 divider */ - { 0x30b3, 0x64 }, /* pll1 multiplier */ - { 0x30b4, 0x03 }, /* pll1 pre divider */ - { 0x30b5, 0x05 }, /* pll1 mipi divider */ { 0x3106, 0xda }, { 0x3503, 0x07 }, { 0x3509, 0x10 }, @@ -518,18 +624,28 @@ static const struct reg_value ov7251_setting_vga_90fps[] = { { 0x5001, 0x80 }, }; +static const unsigned long supported_xclk_rates[] = { + [OV7251_19_2_MHZ] = 19200000, + [OV7251_24_MHZ] = 24000000, +}; + static const s64 link_freq[] = { - 240000000, + [OV7251_LINK_FREQ_240_MHZ] = 240000000, + [OV7251_LINK_FREQ_319_2_MHZ] = 319200000, +}; + +static const s64 pixel_rates[] = { + [OV7251_LINK_FREQ_240_MHZ] = 48000000, + [OV7251_LINK_FREQ_319_2_MHZ] = 63840000, }; static const struct ov7251_mode_info ov7251_mode_info_data[] = { { .width = 640, .height = 480, + .vts = 1724, .data = ov7251_setting_vga_30fps, .data_size = ARRAY_SIZE(ov7251_setting_vga_30fps), - .pixel_clock = 48000000, - .link_freq = 0, /* an index in link_freq[] */ .exposure_max = 1704, .exposure_def = 504, .timeperframe = { @@ -540,10 +656,9 @@ static const struct ov7251_mode_info ov7251_mode_info_data[] = { { .width = 640, .height = 480, + .vts = 860, .data = ov7251_setting_vga_60fps, .data_size = ARRAY_SIZE(ov7251_setting_vga_60fps), - .pixel_clock = 48000000, - .link_freq = 0, /* an index in link_freq[] */ .exposure_max = 840, .exposure_def = 504, .timeperframe = { @@ -554,10 +669,9 @@ static const struct ov7251_mode_info ov7251_mode_info_data[] = { { .width = 640, .height = 480, + .vts = 572, .data = ov7251_setting_vga_90fps, .data_size = ARRAY_SIZE(ov7251_setting_vga_90fps), - .pixel_clock = 48000000, - .link_freq = 0, /* an index in link_freq[] */ .exposure_max = 552, .exposure_def = 504, .timeperframe = { @@ -691,6 +805,63 @@ static int ov7251_read_reg(struct ov7251 *ov7251, u16 reg, u8 *val) return 0; } +static int ov7251_pll_configure(struct ov7251 *ov7251) +{ + const struct ov7251_pll_cfgs *configs; + int ret; + + configs = ov7251->pll_cfgs; + + ret = ov7251_write_reg(ov7251, OV7251_PLL1_PRE_DIV_REG, + configs->pll1[ov7251->link_freq_idx]->pre_div); + if (ret < 0) + return ret; + + ret = ov7251_write_reg(ov7251, OV7251_PLL1_MULT_REG, + configs->pll1[ov7251->link_freq_idx]->mult); + if (ret < 0) + return ret; + ret = ov7251_write_reg(ov7251, OV7251_PLL1_DIVIDER_REG, + configs->pll1[ov7251->link_freq_idx]->div); + if (ret < 0) + return ret; + + ret = ov7251_write_reg(ov7251, OV7251_PLL1_PIX_DIV_REG, + configs->pll1[ov7251->link_freq_idx]->pix_div); + if (ret < 0) + return ret; + + ret = ov7251_write_reg(ov7251, OV7251_PLL1_MIPI_DIV_REG, + configs->pll1[ov7251->link_freq_idx]->mipi_div); + if (ret < 0) + return ret; + + ret = ov7251_write_reg(ov7251, OV7251_PLL2_PRE_DIV_REG, + configs->pll2->pre_div); + if (ret < 0) + return ret; + + ret = ov7251_write_reg(ov7251, OV7251_PLL2_MULT_REG, + configs->pll2->mult); + if (ret < 0) + return ret; + + ret = ov7251_write_reg(ov7251, OV7251_PLL2_DIVIDER_REG, + configs->pll2->div); + if (ret < 0) + return ret; + + ret = ov7251_write_reg(ov7251, OV7251_PLL2_SYS_DIV_REG, + configs->pll2->sys_div); + if (ret < 0) + return ret; + + ret = ov7251_write_reg(ov7251, OV7251_PLL2_ADC_DIV_REG, + configs->pll2->adc_div); + + return ret; +} + static int ov7251_set_exposure(struct ov7251 *ov7251, s32 exposure) { u16 reg; @@ -732,8 +903,11 @@ static int ov7251_set_register_array(struct ov7251 *ov7251, return 0; } -static int ov7251_set_power_on(struct ov7251 *ov7251) +static int ov7251_set_power_on(struct device *dev) { + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov7251 *ov7251 = to_ov7251(sd); int ret; u32 wait_us; @@ -755,51 +929,29 @@ static int ov7251_set_power_on(struct ov7251 *ov7251) DIV_ROUND_UP(ov7251->xclk_freq, 1000)); usleep_range(wait_us, wait_us + 1000); - return 0; -} + ret = ov7251_set_register_array(ov7251, + ov7251_global_init_setting, + ARRAY_SIZE(ov7251_global_init_setting)); + if (ret < 0) { + dev_err(ov7251->dev, "error during global init\n"); + ov7251_regulators_disable(ov7251); + return ret; + } -static void ov7251_set_power_off(struct ov7251 *ov7251) -{ - clk_disable_unprepare(ov7251->xclk); - gpiod_set_value_cansleep(ov7251->enable_gpio, 0); - ov7251_regulators_disable(ov7251); + return ret; } -static int ov7251_s_power(struct v4l2_subdev *sd, int on) +static int ov7251_set_power_off(struct device *dev) { + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov7251 *ov7251 = to_ov7251(sd); - int ret = 0; - - mutex_lock(&ov7251->lock); - - /* If the power state is not modified - no work to do. */ - if (ov7251->power_on == !!on) - goto exit; - - if (on) { - ret = ov7251_set_power_on(ov7251); - if (ret < 0) - goto exit; - ret = ov7251_set_register_array(ov7251, - ov7251_global_init_setting, - ARRAY_SIZE(ov7251_global_init_setting)); - if (ret < 0) { - dev_err(ov7251->dev, "could not set init registers\n"); - ov7251_set_power_off(ov7251); - goto exit; - } - - ov7251->power_on = true; - } else { - ov7251_set_power_off(ov7251); - ov7251->power_on = false; - } - -exit: - mutex_unlock(&ov7251->lock); + clk_disable_unprepare(ov7251->xclk); + gpiod_set_value_cansleep(ov7251->enable_gpio, 0); + ov7251_regulators_disable(ov7251); - return ret; + return 0; } static int ov7251_set_hflip(struct ov7251 *ov7251, s32 value) @@ -858,15 +1010,39 @@ static const char * const ov7251_test_pattern_menu[] = { "Vertical Pattern Bars", }; +static int ov7251_vts_configure(struct ov7251 *ov7251, s32 vblank) +{ + u8 vts[2]; + + vts[0] = ((ov7251->current_mode->height + vblank) & 0xff00) >> 8; + vts[1] = ((ov7251->current_mode->height + vblank) & 0x00ff); + + return ov7251_write_seq_regs(ov7251, OV7251_TIMING_VTS_REG, vts, 2); +} + static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) { struct ov7251 *ov7251 = container_of(ctrl->handler, struct ov7251, ctrls); int ret; + /* If VBLANK is altered we need to update exposure to compensate */ + if (ctrl->id == V4L2_CID_VBLANK) { + int exposure_max; + + exposure_max = ov7251->current_mode->height + ctrl->val - + OV7251_INTEGRATION_MARGIN; + __v4l2_ctrl_modify_range(ov7251->exposure, + ov7251->exposure->minimum, + exposure_max, + ov7251->exposure->step, + min(ov7251->exposure->val, + exposure_max)); + } + /* v4l2_ctrl_lock() locks our mutex */ - if (!ov7251->power_on) + if (!pm_runtime_get_if_in_use(ov7251->dev)) return 0; switch (ctrl->id) { @@ -885,11 +1061,16 @@ static int ov7251_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_VFLIP: ret = ov7251_set_vflip(ov7251, ctrl->val); break; + case V4L2_CID_VBLANK: + ret = ov7251_vts_configure(ov7251, ctrl->val); + break; default: ret = -EINVAL; break; } + pm_runtime_put(ov7251->dev); + return ret; } @@ -1034,6 +1215,7 @@ static int ov7251_set_format(struct v4l2_subdev *sd, { struct ov7251 *ov7251 = to_ov7251(sd); struct v4l2_mbus_framefmt *__format; + int vblank_max, vblank_def; struct v4l2_rect *__crop; const struct ov7251_mode_info *new_mode; int ret = 0; @@ -1052,16 +1234,6 @@ static int ov7251_set_format(struct v4l2_subdev *sd, __crop->height = new_mode->height; if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - ret = __v4l2_ctrl_s_ctrl_int64(ov7251->pixel_clock, - new_mode->pixel_clock); - if (ret < 0) - goto exit; - - ret = __v4l2_ctrl_s_ctrl(ov7251->link_freq, - new_mode->link_freq); - if (ret < 0) - goto exit; - ret = __v4l2_ctrl_modify_range(ov7251->exposure, 1, new_mode->exposure_max, 1, new_mode->exposure_def); @@ -1077,6 +1249,14 @@ static int ov7251_set_format(struct v4l2_subdev *sd, if (ret < 0) goto exit; + vblank_max = OV7251_TIMING_MAX_VTS - new_mode->height; + vblank_def = new_mode->vts - new_mode->height; + ret = __v4l2_ctrl_modify_range(ov7251->vblank, + OV7251_TIMING_MIN_VTS, + vblank_max, 1, vblank_def); + if (ret < 0) + goto exit; + ov7251->current_mode = new_mode; } @@ -1123,13 +1303,29 @@ static int ov7251_get_selection(struct v4l2_subdev *sd, { struct ov7251 *ov7251 = to_ov7251(sd); - if (sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - + switch (sel->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP: mutex_lock(&ov7251->lock); - sel->r = *__ov7251_get_pad_crop(ov7251, sd_state, sel->pad, - sel->which); - mutex_unlock(&ov7251->lock); + sel->r = *__ov7251_get_pad_crop(ov7251, sd_state, sel->pad, + sel->which); + mutex_unlock(&ov7251->lock); + break; + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = OV7251_NATIVE_WIDTH; + sel->r.height = OV7251_NATIVE_HEIGHT; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = OV7251_ACTIVE_START_TOP; + sel->r.left = OV7251_ACTIVE_START_LEFT; + sel->r.width = OV7251_ACTIVE_WIDTH; + sel->r.height = OV7251_ACTIVE_HEIGHT; + break; + default: + return -EINVAL; + } return 0; } @@ -1142,6 +1338,16 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable) mutex_lock(&ov7251->lock); if (enable) { + ret = pm_runtime_get_sync(ov7251->dev); + if (ret < 0) + goto unlock_out; + + ret = ov7251_pll_configure(ov7251); + if (ret) { + dev_err(ov7251->dev, "error configuring PLLs\n"); + goto err_power_down; + } + ret = ov7251_set_register_array(ov7251, ov7251->current_mode->data, ov7251->current_mode->data_size); @@ -1149,23 +1355,30 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable) dev_err(ov7251->dev, "could not set mode %dx%d\n", ov7251->current_mode->width, ov7251->current_mode->height); - goto exit; + goto err_power_down; } ret = __v4l2_ctrl_handler_setup(&ov7251->ctrls); if (ret < 0) { dev_err(ov7251->dev, "could not sync v4l2 controls\n"); - goto exit; + goto err_power_down; } ret = ov7251_write_reg(ov7251, OV7251_SC_MODE_SELECT, OV7251_SC_MODE_SELECT_STREAMING); + if (ret) + goto err_power_down; } else { ret = ov7251_write_reg(ov7251, OV7251_SC_MODE_SELECT, OV7251_SC_MODE_SELECT_SW_STANDBY); + pm_runtime_put(ov7251->dev); } -exit: +unlock_out: mutex_unlock(&ov7251->lock); + return ret; +err_power_down: + pm_runtime_put_noidle(ov7251->dev); + mutex_unlock(&ov7251->lock); return ret; } @@ -1192,16 +1405,6 @@ static int ov7251_set_frame_interval(struct v4l2_subdev *subdev, new_mode = ov7251_find_mode_by_ival(ov7251, &fi->interval); if (new_mode != ov7251->current_mode) { - ret = __v4l2_ctrl_s_ctrl_int64(ov7251->pixel_clock, - new_mode->pixel_clock); - if (ret < 0) - goto exit; - - ret = __v4l2_ctrl_s_ctrl(ov7251->link_freq, - new_mode->link_freq); - if (ret < 0) - goto exit; - ret = __v4l2_ctrl_modify_range(ov7251->exposure, 1, new_mode->exposure_max, 1, new_mode->exposure_def); @@ -1228,10 +1431,6 @@ exit: return ret; } -static const struct v4l2_subdev_core_ops ov7251_core_ops = { - .s_power = ov7251_s_power, -}; - static const struct v4l2_subdev_video_ops ov7251_video_ops = { .s_stream = ov7251_s_stream, .g_frame_interval = ov7251_get_frame_interval, @@ -1249,97 +1448,97 @@ static const struct v4l2_subdev_pad_ops ov7251_subdev_pad_ops = { }; static const struct v4l2_subdev_ops ov7251_subdev_ops = { - .core = &ov7251_core_ops, .video = &ov7251_video_ops, .pad = &ov7251_subdev_pad_ops, }; -static int ov7251_probe(struct i2c_client *client) +static int ov7251_check_hwcfg(struct ov7251 *ov7251) { - struct device *dev = &client->dev; + struct fwnode_handle *fwnode = dev_fwnode(ov7251->dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; struct fwnode_handle *endpoint; - struct ov7251 *ov7251; - u8 chip_id_high, chip_id_low, chip_rev; + unsigned int i, j; int ret; - ov7251 = devm_kzalloc(dev, sizeof(struct ov7251), GFP_KERNEL); - if (!ov7251) - return -ENOMEM; - - ov7251->i2c_client = client; - ov7251->dev = dev; - - endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); - if (!endpoint) { - dev_err(dev, "endpoint node not found\n"); - return -EINVAL; - } + endpoint = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!endpoint) + return -EPROBE_DEFER; /* could be provided by cio2-bridge */ - ret = v4l2_fwnode_endpoint_parse(endpoint, &ov7251->ep); + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); fwnode_handle_put(endpoint); - if (ret < 0) { - dev_err(dev, "parsing endpoint node failed\n"); - return ret; + if (ret) + return dev_err_probe(ov7251->dev, ret, + "parsing endpoint node failed\n"); + + if (!bus_cfg.nr_of_link_frequencies) { + ret = dev_err_probe(ov7251->dev, -EINVAL, + "no link frequencies defined\n"); + goto out_free_bus_cfg; } - if (ov7251->ep.bus_type != V4L2_MBUS_CSI2_DPHY) { - dev_err(dev, "invalid bus type (%u), must be CSI2 (%u)\n", - ov7251->ep.bus_type, V4L2_MBUS_CSI2_DPHY); - return -EINVAL; - } + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { + for (j = 0; j < ARRAY_SIZE(link_freq); j++) + if (bus_cfg.link_frequencies[i] == link_freq[j]) + break; - /* get system clock (xclk) */ - ov7251->xclk = devm_clk_get(dev, "xclk"); - if (IS_ERR(ov7251->xclk)) { - dev_err(dev, "could not get xclk"); - return PTR_ERR(ov7251->xclk); + if (j < ARRAY_SIZE(link_freq)) + break; } - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &ov7251->xclk_freq); - if (ret) { - dev_err(dev, "could not get xclk frequency\n"); - return ret; + if (i == bus_cfg.nr_of_link_frequencies) { + ret = dev_err_probe(ov7251->dev, -EINVAL, + "no supported link freq found\n"); + goto out_free_bus_cfg; } - /* external clock must be 24MHz, allow 1% tolerance */ - if (ov7251->xclk_freq < 23760000 || ov7251->xclk_freq > 24240000) { - dev_err(dev, "external clock frequency %u is not supported\n", - ov7251->xclk_freq); - return -EINVAL; - } + ov7251->link_freq_idx = i; - ret = clk_set_rate(ov7251->xclk, ov7251->xclk_freq); - if (ret) { - dev_err(dev, "could not set xclk frequency\n"); - return ret; - } +out_free_bus_cfg: + v4l2_fwnode_endpoint_free(&bus_cfg); - ov7251->io_regulator = devm_regulator_get(dev, "vdddo"); - if (IS_ERR(ov7251->io_regulator)) { - dev_err(dev, "cannot get io regulator\n"); - return PTR_ERR(ov7251->io_regulator); - } + return ret; +} - ov7251->core_regulator = devm_regulator_get(dev, "vddd"); - if (IS_ERR(ov7251->core_regulator)) { - dev_err(dev, "cannot get core regulator\n"); - return PTR_ERR(ov7251->core_regulator); - } +static int ov7251_detect_chip(struct ov7251 *ov7251) +{ + u8 chip_id_high, chip_id_low, chip_rev; + int ret; - ov7251->analog_regulator = devm_regulator_get(dev, "vdda"); - if (IS_ERR(ov7251->analog_regulator)) { - dev_err(dev, "cannot get analog regulator\n"); - return PTR_ERR(ov7251->analog_regulator); - } + ret = ov7251_read_reg(ov7251, OV7251_CHIP_ID_HIGH, &chip_id_high); + if (ret < 0 || chip_id_high != OV7251_CHIP_ID_HIGH_BYTE) + return dev_err_probe(ov7251->dev, -ENODEV, + "could not read ID high\n"); - ov7251->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); - if (IS_ERR(ov7251->enable_gpio)) { - dev_err(dev, "cannot get enable gpio\n"); - return PTR_ERR(ov7251->enable_gpio); - } + ret = ov7251_read_reg(ov7251, OV7251_CHIP_ID_LOW, &chip_id_low); + if (ret < 0 || chip_id_low != OV7251_CHIP_ID_LOW_BYTE) + return dev_err_probe(ov7251->dev, -ENODEV, + "could not read ID low\n"); - mutex_init(&ov7251->lock); + ret = ov7251_read_reg(ov7251, OV7251_SC_GP_IO_IN1, &chip_rev); + if (ret < 0) + return dev_err_probe(ov7251->dev, -ENODEV, + "could not read revision\n"); + chip_rev >>= 4; + + dev_info(ov7251->dev, + "OV7251 revision %x (%s) detected at address 0x%02x\n", + chip_rev, + chip_rev == 0x4 ? "1A / 1B" : + chip_rev == 0x5 ? "1C / 1D" : + chip_rev == 0x6 ? "1E" : + chip_rev == 0x7 ? "1F" : "unknown", + ov7251->i2c_client->addr); + + return 0; +} + +static int ov7251_init_ctrls(struct ov7251 *ov7251) +{ + int vblank_max, vblank_def; + s64 pixel_rate; + int hblank; v4l2_ctrl_handler_init(&ov7251->ctrls, 7); ov7251->ctrls.lock = &ov7251->lock; @@ -1356,25 +1555,138 @@ static int ov7251_probe(struct i2c_client *client) V4L2_CID_TEST_PATTERN, ARRAY_SIZE(ov7251_test_pattern_menu) - 1, 0, 0, ov7251_test_pattern_menu); + + pixel_rate = pixel_rates[ov7251->link_freq_idx]; ov7251->pixel_clock = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, V4L2_CID_PIXEL_RATE, - 1, INT_MAX, 1, 1); + pixel_rate, INT_MAX, + pixel_rate, pixel_rate); ov7251->link_freq = v4l2_ctrl_new_int_menu(&ov7251->ctrls, &ov7251_ctrl_ops, V4L2_CID_LINK_FREQ, ARRAY_SIZE(link_freq) - 1, - 0, link_freq); + ov7251->link_freq_idx, + link_freq); if (ov7251->link_freq) ov7251->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + if (ov7251->pixel_clock) + ov7251->pixel_clock->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + hblank = OV7251_FIXED_PPL - ov7251->current_mode->width; + ov7251->hblank = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_HBLANK, hblank, hblank, 1, + hblank); + if (ov7251->hblank) + ov7251->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + vblank_max = OV7251_TIMING_MAX_VTS - ov7251->current_mode->height; + vblank_def = ov7251->current_mode->vts - ov7251->current_mode->height; + ov7251->vblank = v4l2_ctrl_new_std(&ov7251->ctrls, &ov7251_ctrl_ops, + V4L2_CID_VBLANK, + OV7251_TIMING_MIN_VTS, vblank_max, 1, + vblank_def); ov7251->sd.ctrl_handler = &ov7251->ctrls; if (ov7251->ctrls.error) { - dev_err(dev, "%s: control initialization error %d\n", - __func__, ov7251->ctrls.error); - ret = ov7251->ctrls.error; - goto free_ctrl; + v4l2_ctrl_handler_free(&ov7251->ctrls); + return ov7251->ctrls.error; + } + + return 0; +} + +static int ov7251_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct ov7251 *ov7251; + unsigned int rate = 0, clk_rate = 0; + int ret; + int i; + + ov7251 = devm_kzalloc(dev, sizeof(struct ov7251), GFP_KERNEL); + if (!ov7251) + return -ENOMEM; + + ov7251->i2c_client = client; + ov7251->dev = dev; + + ret = ov7251_check_hwcfg(ov7251); + if (ret) + return ret; + + /* get system clock (xclk) */ + ov7251->xclk = devm_clk_get_optional(dev, NULL); + if (IS_ERR(ov7251->xclk)) + return dev_err_probe(dev, PTR_ERR(ov7251->xclk), + "could not get xclk"); + + /* + * We could have either a 24MHz or 19.2MHz clock rate from either DT or + * ACPI. We also need to support the IPU3 case which will have both an + * external clock AND a clock-frequency property. + */ + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &rate); + if (ret && !ov7251->xclk) + return dev_err_probe(dev, ret, "invalid clock config\n"); + + clk_rate = clk_get_rate(ov7251->xclk); + ov7251->xclk_freq = clk_rate ? clk_rate : rate; + + if (ov7251->xclk_freq == 0) + return dev_err_probe(dev, -EINVAL, "invalid clock frequency\n"); + + if (!ret && ov7251->xclk) { + ret = clk_set_rate(ov7251->xclk, rate); + if (ret) + return dev_err_probe(dev, ret, + "failed to set clock rate\n"); + } + + for (i = 0; i < ARRAY_SIZE(supported_xclk_rates); i++) + if (ov7251->xclk_freq == supported_xclk_rates[i]) + break; + + if (i == ARRAY_SIZE(supported_xclk_rates)) + return dev_err_probe(dev, -EINVAL, + "clock rate %u Hz is unsupported\n", + ov7251->xclk_freq); + + ov7251->pll_cfgs = ov7251_pll_cfgs[i]; + + ov7251->io_regulator = devm_regulator_get(dev, "vdddo"); + if (IS_ERR(ov7251->io_regulator)) { + dev_err(dev, "cannot get io regulator\n"); + return PTR_ERR(ov7251->io_regulator); + } + + ov7251->core_regulator = devm_regulator_get(dev, "vddd"); + if (IS_ERR(ov7251->core_regulator)) { + dev_err(dev, "cannot get core regulator\n"); + return PTR_ERR(ov7251->core_regulator); + } + + ov7251->analog_regulator = devm_regulator_get(dev, "vdda"); + if (IS_ERR(ov7251->analog_regulator)) { + dev_err(dev, "cannot get analog regulator\n"); + return PTR_ERR(ov7251->analog_regulator); + } + + ov7251->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH); + if (IS_ERR(ov7251->enable_gpio)) { + dev_err(dev, "cannot get enable gpio\n"); + return PTR_ERR(ov7251->enable_gpio); + } + + mutex_init(&ov7251->lock); + + ov7251->current_mode = &ov7251_mode_info_data[0]; + ret = ov7251_init_ctrls(ov7251); + if (ret) { + dev_err_probe(dev, ret, "error during v4l2 ctrl init\n"); + goto destroy_mutex; } v4l2_i2c_subdev_init(&ov7251->sd, client, &ov7251_subdev_ops); @@ -1389,47 +1701,24 @@ static int ov7251_probe(struct i2c_client *client) goto free_ctrl; } - ret = ov7251_s_power(&ov7251->sd, true); - if (ret < 0) { - dev_err(dev, "could not power up OV7251\n"); + ret = ov7251_set_power_on(ov7251->dev); + if (ret) goto free_entity; - } - ret = ov7251_read_reg(ov7251, OV7251_CHIP_ID_HIGH, &chip_id_high); - if (ret < 0 || chip_id_high != OV7251_CHIP_ID_HIGH_BYTE) { - dev_err(dev, "could not read ID high\n"); - ret = -ENODEV; - goto power_down; - } - ret = ov7251_read_reg(ov7251, OV7251_CHIP_ID_LOW, &chip_id_low); - if (ret < 0 || chip_id_low != OV7251_CHIP_ID_LOW_BYTE) { - dev_err(dev, "could not read ID low\n"); - ret = -ENODEV; + ret = ov7251_detect_chip(ov7251); + if (ret) goto power_down; - } - ret = ov7251_read_reg(ov7251, OV7251_SC_GP_IO_IN1, &chip_rev); - if (ret < 0) { - dev_err(dev, "could not read revision\n"); - ret = -ENODEV; - goto power_down; - } - chip_rev >>= 4; - - dev_info(dev, "OV7251 revision %x (%s) detected at address 0x%02x\n", - chip_rev, - chip_rev == 0x4 ? "1A / 1B" : - chip_rev == 0x5 ? "1C / 1D" : - chip_rev == 0x6 ? "1E" : - chip_rev == 0x7 ? "1F" : "unknown", - client->addr); + pm_runtime_set_active(&client->dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(&client->dev); ret = ov7251_read_reg(ov7251, OV7251_PRE_ISP_00, &ov7251->pre_isp_00); if (ret < 0) { dev_err(dev, "could not read test pattern value\n"); ret = -ENODEV; - goto power_down; + goto err_pm_runtime; } ret = ov7251_read_reg(ov7251, OV7251_TIMING_FORMAT1, @@ -1437,7 +1726,7 @@ static int ov7251_probe(struct i2c_client *client) if (ret < 0) { dev_err(dev, "could not read vflip value\n"); ret = -ENODEV; - goto power_down; + goto err_pm_runtime; } ret = ov7251_read_reg(ov7251, OV7251_TIMING_FORMAT2, @@ -1445,10 +1734,12 @@ static int ov7251_probe(struct i2c_client *client) if (ret < 0) { dev_err(dev, "could not read hflip value\n"); ret = -ENODEV; - goto power_down; + goto err_pm_runtime; } - ov7251_s_power(&ov7251->sd, false); + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); ret = v4l2_async_register_subdev(&ov7251->sd); if (ret < 0) { @@ -1460,12 +1751,16 @@ static int ov7251_probe(struct i2c_client *client) return 0; +err_pm_runtime: + pm_runtime_disable(ov7251->dev); + pm_runtime_put_noidle(ov7251->dev); power_down: - ov7251_s_power(&ov7251->sd, false); + ov7251_set_power_off(ov7251->dev); free_entity: media_entity_cleanup(&ov7251->sd.entity); free_ctrl: v4l2_ctrl_handler_free(&ov7251->ctrls); +destroy_mutex: mutex_destroy(&ov7251->lock); return ret; @@ -1481,19 +1776,36 @@ static int ov7251_remove(struct i2c_client *client) v4l2_ctrl_handler_free(&ov7251->ctrls); mutex_destroy(&ov7251->lock); + pm_runtime_disable(ov7251->dev); + if (!pm_runtime_status_suspended(ov7251->dev)) + ov7251_set_power_off(ov7251->dev); + pm_runtime_set_suspended(ov7251->dev); + return 0; } +static const struct dev_pm_ops ov7251_pm_ops = { + SET_RUNTIME_PM_OPS(ov7251_set_power_off, ov7251_set_power_on, NULL) +}; + static const struct of_device_id ov7251_of_match[] = { { .compatible = "ovti,ov7251" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, ov7251_of_match); +static const struct acpi_device_id ov7251_acpi_match[] = { + { "INT347E" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, ov7251_acpi_match); + static struct i2c_driver ov7251_i2c_driver = { .driver = { .of_match_table = ov7251_of_match, + .acpi_match_table = ov7251_acpi_match, .name = "ov7251", + .pm = &ov7251_pm_ops, }, .probe_new = ov7251_probe, .remove = ov7251_remove, diff --git a/drivers/media/i2c/ov7640.c b/drivers/media/i2c/ov7640.c index 010803d58ce8..977cd2d8ad33 100644 --- a/drivers/media/i2c/ov7640.c +++ b/drivers/media/i2c/ov7640.c @@ -13,23 +13,28 @@ MODULE_DESCRIPTION("OmniVision ov7640 sensor driver"); MODULE_LICENSE("GPL v2"); -static const u8 initial_registers[] = { - 0x12, 0x80, - 0x12, 0x54, - 0x14, 0x24, - 0x15, 0x01, - 0x28, 0x20, - 0x75, 0x82, - 0xFF, 0xFF, /* Terminator (reg 0xFF is unused) */ +struct reg_val { + u8 reg; + u8 val; }; -static int write_regs(struct i2c_client *client, const u8 *regs) -{ - int i; +static const struct reg_val regval_init[] = { + {0x12, 0x80}, + {0x12, 0x54}, + {0x14, 0x24}, + {0x15, 0x01}, + {0x28, 0x20}, + {0x75, 0x82}, +}; - for (i = 0; regs[i] != 0xFF; i += 2) - if (i2c_smbus_write_byte_data(client, regs[i], regs[i + 1]) < 0) +static int write_regs(struct i2c_client *client, + const struct reg_val *rv, int len) +{ + while (--len >= 0) { + if (i2c_smbus_write_byte_data(client, rv->reg, rv->val) < 0) return -1; + rv++; + } return 0; } @@ -56,7 +61,7 @@ static int ov7640_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); - if (write_regs(client, initial_registers) < 0) { + if (write_regs(client, regval_init, ARRAY_SIZE(regval_init)) < 0) { v4l_err(client, "error initializing OV7640\n"); return -ENODEV; } diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 196746423116..1be2c0e5bdc1 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -2017,7 +2017,6 @@ static int ov7670_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); v4l2_ctrl_handler_free(&info->hdl); media_entity_cleanup(&info->sd.entity); - ov7670_power_off(sd); return 0; } diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 8785764b7a74..a9728afc81d4 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -63,6 +63,7 @@ #define OV8856_ANAL_GAIN_STEP 1 /* Digital gain controls from sensor */ +#define OV8856_REG_DIGITAL_GAIN 0x350a #define OV8856_REG_MWB_R_GAIN 0x5019 #define OV8856_REG_MWB_G_GAIN 0x501b #define OV8856_REG_MWB_B_GAIN 0x501d @@ -351,7 +352,7 @@ static const struct ov8856_reg lane_2_mode_3280x2464[] = { {0x484b, 0x05}, {0x5000, 0x57}, {0x5001, 0x0a}, - {0x5004, 0x04}, + {0x5004, 0x06}, {0x502e, 0x03}, {0x5030, 0x41}, {0x5795, 0x02}, @@ -543,7 +544,7 @@ static const struct ov8856_reg lane_2_mode_1640x1232[] = { {0x484b, 0x05}, {0x5000, 0x57}, {0x5001, 0x0a}, - {0x5004, 0x04}, + {0x5004, 0x06}, {0x502e, 0x03}, {0x5030, 0x41}, {0x5795, 0x00}, @@ -734,7 +735,7 @@ static const struct ov8856_reg lane_4_mode_3280x2464[] = { {0x484b, 0x05}, {0x5000, 0x57}, {0x5001, 0x0a}, - {0x5004, 0x04}, + {0x5004, 0x06}, {0x502e, 0x03}, {0x5030, 0x41}, {0x5780, 0x14}, @@ -925,7 +926,7 @@ static const struct ov8856_reg lane_4_mode_1640x1232[] = { {0x484b, 0x05}, {0x5000, 0x57}, {0x5001, 0x0a}, - {0x5004, 0x04}, + {0x5004, 0x06}, {0x502e, 0x03}, {0x5030, 0x41}, {0x5780, 0x14}, @@ -1755,19 +1756,7 @@ static int ov8856_identify_module(struct ov8856 *ov8856) static int ov8856_update_digital_gain(struct ov8856 *ov8856, u32 d_gain) { - int ret; - - ret = ov8856_write_reg(ov8856, OV8856_REG_MWB_R_GAIN, - OV8856_REG_VALUE_16BIT, d_gain); - if (ret) - return ret; - - ret = ov8856_write_reg(ov8856, OV8856_REG_MWB_G_GAIN, - OV8856_REG_VALUE_16BIT, d_gain); - if (ret) - return ret; - - return ov8856_write_reg(ov8856, OV8856_REG_MWB_B_GAIN, + return ov8856_write_reg(ov8856, OV8856_REG_DIGITAL_GAIN, OV8856_REG_VALUE_16BIT, d_gain); } diff --git a/drivers/media/i2c/rdacm20.c b/drivers/media/i2c/rdacm20.c index 025a610de893..2615ad154f49 100644 --- a/drivers/media/i2c/rdacm20.c +++ b/drivers/media/i2c/rdacm20.c @@ -47,11 +47,11 @@ #define OV10635_VTS 933 /* - * As the drivers supports a single MEDIA_BUS_FMT_UYVY8_2X8 format we + * As the drivers supports a single MEDIA_BUS_FMT_UYVY8_1X16 format we * can harcode the pixel rate. * * PCLK is fed through the system clock, programmed @88MHz. - * MEDIA_BUS_FMT_UYVY8_2X8 format = 2 samples per pixel. + * MEDIA_BUS_FMT_UYVY8_1X16 format = 2 samples per pixel. * * Pixelrate = PCLK / 2 * FPS = (OV10635_VTS * OV10635_HTS) / PixelRate @@ -409,7 +409,7 @@ static int rdacm20_enum_mbus_code(struct v4l2_subdev *sd, if (code->pad || code->index > 0) return -EINVAL; - code->code = MEDIA_BUS_FMT_UYVY8_2X8; + code->code = MEDIA_BUS_FMT_UYVY8_1X16; return 0; } @@ -425,7 +425,7 @@ static int rdacm20_get_fmt(struct v4l2_subdev *sd, mf->width = OV10635_WIDTH; mf->height = OV10635_HEIGHT; - mf->code = MEDIA_BUS_FMT_UYVY8_2X8; + mf->code = MEDIA_BUS_FMT_UYVY8_1X16; mf->colorspace = V4L2_COLORSPACE_RAW; mf->field = V4L2_FIELD_NONE; mf->ycbcr_enc = V4L2_YCBCR_ENC_601; @@ -611,7 +611,7 @@ static int rdacm20_probe(struct i2c_client *client) goto error_free_ctrls; dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); if (ret < 0) goto error_free_ctrls; diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c index 12ec5467ed1e..ef31cf5f23ca 100644 --- a/drivers/media/i2c/rdacm21.c +++ b/drivers/media/i2c/rdacm21.c @@ -583,7 +583,7 @@ static int rdacm21_probe(struct i2c_client *client) goto error_free_ctrls; dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); if (ret < 0) goto error_free_ctrls; diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index b97dd6149e90..f6ecf6f92bb2 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -213,7 +213,7 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor) for (i++; i < S5K6A3_NUM_SUPPLIES; i++) { ret = regulator_enable(sensor->supplies[i].consumer); if (ret < 0) - goto error_reg_dis; + goto error_clk; } gpio_set_value(sensor->gpio_reset, 1); @@ -226,6 +226,8 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor) msleep(20); return 0; +error_clk: + clk_disable_unprepare(sensor->clock); error_reg_dis: for (--i; i >= 0; --i) regulator_disable(sensor->supplies[i].consumer); diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index cb660b4bfd4b..e08e3579c0a1 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -9,6 +9,7 @@ * - Melexis MLX90640 Thermal Cameras */ +#include <linux/bits.h> #include <linux/delay.h> #include <linux/freezer.h> #include <linux/hwmon.h> @@ -34,6 +35,37 @@ #define VIDEO_I2C_DRIVER "video-i2c" +/* Power control register */ +#define AMG88XX_REG_PCTL 0x00 +#define AMG88XX_PCTL_NORMAL 0x00 +#define AMG88XX_PCTL_SLEEP 0x10 + +/* Reset register */ +#define AMG88XX_REG_RST 0x01 +#define AMG88XX_RST_FLAG 0x30 +#define AMG88XX_RST_INIT 0x3f + +/* Frame rate register */ +#define AMG88XX_REG_FPSC 0x02 +#define AMG88XX_FPSC_1FPS BIT(0) + +/* Thermistor register */ +#define AMG88XX_REG_TTHL 0x0e + +/* Temperature register */ +#define AMG88XX_REG_T01L 0x80 + +/* RAM */ +#define MLX90640_RAM_START_ADDR 0x0400 + +/* EEPROM */ +#define MLX90640_EEPROM_START_ADDR 0x2400 + +/* Control register */ +#define MLX90640_REG_CTL1 0x800d +#define MLX90640_REG_CTL1_MASK GENMASK(9, 7) +#define MLX90640_REG_CTL1_MASK_SHIFT 7 + struct video_i2c_chip; struct video_i2c_buffer { @@ -124,7 +156,7 @@ static int mlx90640_nvram_read(void *priv, unsigned int offset, void *val, { struct video_i2c_data *data = priv; - return regmap_bulk_read(data->regmap, 0x2400 + offset, val, bytes); + return regmap_bulk_read(data->regmap, MLX90640_EEPROM_START_ADDR + offset, val, bytes); } static struct nvmem_config mlx90640_nvram_config = { @@ -135,31 +167,6 @@ static struct nvmem_config mlx90640_nvram_config = { .reg_read = mlx90640_nvram_read, }; -/* Power control register */ -#define AMG88XX_REG_PCTL 0x00 -#define AMG88XX_PCTL_NORMAL 0x00 -#define AMG88XX_PCTL_SLEEP 0x10 - -/* Reset register */ -#define AMG88XX_REG_RST 0x01 -#define AMG88XX_RST_FLAG 0x30 -#define AMG88XX_RST_INIT 0x3f - -/* Frame rate register */ -#define AMG88XX_REG_FPSC 0x02 -#define AMG88XX_FPSC_1FPS BIT(0) - -/* Thermistor register */ -#define AMG88XX_REG_TTHL 0x0e - -/* Temperature register */ -#define AMG88XX_REG_T01L 0x80 - -/* Control register */ -#define MLX90640_REG_CTL1 0x800d -#define MLX90640_REG_CTL1_MASK 0x0380 -#define MLX90640_REG_CTL1_MASK_SHIFT 7 - static int amg88xx_xfer(struct video_i2c_data *data, char *buf) { return regmap_bulk_read(data->regmap, AMG88XX_REG_T01L, buf, @@ -168,7 +175,7 @@ static int amg88xx_xfer(struct video_i2c_data *data, char *buf) static int mlx90640_xfer(struct video_i2c_data *data, char *buf) { - return regmap_bulk_read(data->regmap, 0x400, buf, + return regmap_bulk_read(data->regmap, MLX90640_RAM_START_ADDR, buf, data->chip->buffer_size); } diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index cf5e459b1d96..b8176a3b76d3 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -604,15 +604,8 @@ static void __media_device_unregister_entity(struct media_entity *entity) media_gobj_destroy(&entity->graph_obj); /* invoke entity_notify callbacks to handle entity removal?? */ - - entity->graph_obj.mdev = NULL; } -/** - * media_device_register_entity - Register an entity with a media device - * @mdev: The media device - * @entity: The entity - */ int __must_check media_device_register_entity(struct media_device *mdev, struct media_entity *entity) { @@ -691,16 +684,6 @@ void media_device_unregister_entity(struct media_entity *entity) } EXPORT_SYMBOL_GPL(media_device_unregister_entity); -/** - * media_device_init() - initialize a media device - * @mdev: The media device - * - * The caller is responsible for initializing the media device before - * registration. The following fields must be set: - * - * - dev must point to the parent device - * - model must be filled with the device model name - */ void media_device_init(struct media_device *mdev) { INIT_LIST_HEAD(&mdev->entities); @@ -715,6 +698,10 @@ void media_device_init(struct media_device *mdev) atomic_set(&mdev->request_id, 0); + if (!*mdev->bus_info) + media_set_bus_info(mdev->bus_info, sizeof(mdev->bus_info), + mdev->dev); + dev_dbg(mdev->dev, "Media device initialized\n"); } EXPORT_SYMBOL_GPL(media_device_init); diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 8ab0913d8d82..11f5207f73aa 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -44,6 +44,20 @@ static inline const char *intf_type(struct media_interface *intf) } }; +static inline const char *link_type_name(struct media_link *link) +{ + switch (link->flags & MEDIA_LNK_FL_LINK_TYPE) { + case MEDIA_LNK_FL_DATA_LINK: + return "data"; + case MEDIA_LNK_FL_INTERFACE_LINK: + return "interface"; + case MEDIA_LNK_FL_ANCILLARY_LINK: + return "ancillary"; + default: + return "unknown"; + } +} + __must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum, int idx_max) { @@ -89,9 +103,7 @@ static void dev_dbg_obj(const char *event_name, struct media_gobj *gobj) dev_dbg(gobj->mdev->dev, "%s id %u: %s link id %u ==> id %u\n", - event_name, media_id(gobj), - media_type(link->gobj0) == MEDIA_GRAPH_PAD ? - "data" : "interface", + event_name, media_id(gobj), link_type_name(link), media_id(link->gobj0), media_id(link->gobj1)); break; @@ -295,6 +307,12 @@ static void media_graph_walk_iter(struct media_graph *graph) link = list_entry(link_top(graph), typeof(*link), list); + /* If the link is not a data link, don't follow it */ + if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) != MEDIA_LNK_FL_DATA_LINK) { + link_top(graph) = link_top(graph)->next; + return; + } + /* The link is not enabled so we do not follow. */ if (!(link->flags & MEDIA_LNK_FL_ENABLED)) { link_top(graph) = link_top(graph)->next; @@ -579,26 +597,30 @@ static void __media_entity_remove_link(struct media_entity *entity, struct media_link *rlink, *tmp; struct media_entity *remote; - if (link->source->entity == entity) - remote = link->sink->entity; - else - remote = link->source->entity; + /* Remove the reverse links for a data link. */ + if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == MEDIA_LNK_FL_DATA_LINK) { + if (link->source->entity == entity) + remote = link->sink->entity; + else + remote = link->source->entity; - list_for_each_entry_safe(rlink, tmp, &remote->links, list) { - if (rlink != link->reverse) - continue; + list_for_each_entry_safe(rlink, tmp, &remote->links, list) { + if (rlink != link->reverse) + continue; - if (link->source->entity == entity) - remote->num_backlinks--; + if (link->source->entity == entity) + remote->num_backlinks--; - /* Remove the remote link */ - list_del(&rlink->list); - media_gobj_destroy(&rlink->graph_obj); - kfree(rlink); + /* Remove the remote link */ + list_del(&rlink->list); + media_gobj_destroy(&rlink->graph_obj); + kfree(rlink); - if (--remote->num_links == 0) - break; + if (--remote->num_links == 0) + break; + } } + list_del(&link->list); media_gobj_destroy(&link->graph_obj); kfree(link); @@ -1007,3 +1029,25 @@ void media_remove_intf_links(struct media_interface *intf) mutex_unlock(&mdev->graph_mutex); } EXPORT_SYMBOL_GPL(media_remove_intf_links); + +struct media_link *media_create_ancillary_link(struct media_entity *primary, + struct media_entity *ancillary) +{ + struct media_link *link; + + link = media_add_link(&primary->links); + if (!link) + return ERR_PTR(-ENOMEM); + + link->gobj0 = &primary->graph_obj; + link->gobj1 = &ancillary->graph_obj; + link->flags = MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_ANCILLARY_LINK; + + /* Initialize graph object embedded in the new link */ + media_gobj_create(primary->graph_obj.mdev, MEDIA_GRAPH_LINK, + &link->graph_obj); + + return link; +} +EXPORT_SYMBOL_GPL(media_create_ancillary_link); diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 5ca3d0cc653a..d40b537f4e98 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2435,8 +2435,6 @@ static int bttv_querycap(struct file *file, void *priv, strscpy(cap->driver, "bttv", sizeof(cap->driver)); strscpy(cap->card, btv->video_dev.name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "PCI:%s", pci_name(btv->c.pci)); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; if (no_overlay <= 0) diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index ce3f0141f94e..c8ba7841c720 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -389,8 +389,6 @@ static int cx18_querycap(struct file *file, void *fh, strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); strscpy(vcap->card, cx->card_name, sizeof(vcap->card)); - snprintf(vcap->bus_info, sizeof(vcap->bus_info), - "PCI:%s", pci_name(cx->pci_dev)); vcap->capabilities = cx->v4l2_cap | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index f8f2ff3b00c3..a07b18f2034e 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -2165,7 +2165,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev, err = dma_set_mask(&pci_dev->dev, 0xffffffff); if (err) { pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); - goto fail_ctrl; + goto fail_dma_set_mask; } err = request_irq(pci_dev->irq, cx23885_irq, @@ -2173,7 +2173,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev, if (err < 0) { pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); - goto fail_irq; + goto fail_dma_set_mask; } switch (dev->board) { @@ -2195,7 +2195,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev, return 0; -fail_irq: +fail_dma_set_mask: cx23885_dev_unregister(dev); fail_ctrl: v4l2_ctrl_handler_free(hdl); diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c index 438fdcec6eac..a42f0c03a7ca 100644 --- a/drivers/media/pci/cx25821/cx25821-alsa.c +++ b/drivers/media/pci/cx25821/cx25821-alsa.c @@ -728,8 +728,8 @@ static int cx25821_audio_initdev(struct cx25821_dev *dev) chip->irq = dev->pci->irq; - err = request_irq(dev->pci->irq, cx25821_irq, - IRQF_SHARED, chip->dev->name, chip); + err = devm_request_irq(&dev->pci->dev, dev->pci->irq, cx25821_irq, + IRQF_SHARED, chip->dev->name, chip); if (err < 0) { pr_err("ERROR %s: can't get IRQ %d for ALSA\n", chip->dev->name, diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c index 3078a39f0b95..6627fa9166d3 100644 --- a/drivers/media/pci/cx25821/cx25821-core.c +++ b/drivers/media/pci/cx25821/cx25821-core.c @@ -1332,11 +1332,11 @@ static void cx25821_finidev(struct pci_dev *pci_dev) struct cx25821_dev *dev = get_cx25821(v4l2_dev); cx25821_shutdown(dev); - pci_disable_device(pci_dev); /* unregister stuff */ if (pci_dev->irq) free_irq(pci_dev->irq, dev); + pci_disable_device(pci_dev); cx25821_dev_unregister(dev); v4l2_device_unregister(v4l2_dev); diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index d5da3bd5695d..c1b41a9283c1 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -796,7 +796,6 @@ static int vidioc_querycap(struct file *file, void *priv, struct cx88_core *core = dev->core; strscpy(cap->driver, "cx88_blackbird", sizeof(cap->driver)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); return cx88_querycap(file, core, cap); } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index c17ad9f7d822..d3729be89252 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -808,7 +808,6 @@ static int vidioc_querycap(struct file *file, void *priv, struct cx88_core *core = dev->core; strscpy(cap->driver, "cx8800", sizeof(cap->driver)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); return cx88_querycap(file, core, cap); } diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index 961f844de99c..548156b199cc 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -292,11 +292,8 @@ static const struct v4l2_file_operations dt3155_fops = { static int dt3155_querycap(struct file *filp, void *p, struct v4l2_capability *cap) { - struct dt3155_priv *pd = video_drvdata(filp); - strscpy(cap->driver, DT3155_NAME, sizeof(cap->driver)); strscpy(cap->card, DT3155_NAME " frame grabber", sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev)); return 0; } diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c index 7ccb7b6eaa82..df6c94da2f6a 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.c +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c @@ -25,6 +25,8 @@ static const struct cio2_sensor_config cio2_supported_sensors[] = { CIO2_SENSOR_CONFIG("INT33BE", 1, 419200000), /* Omnivision OV8865 */ CIO2_SENSOR_CONFIG("INT347A", 1, 360000000), + /* Omnivision OV7251 */ + CIO2_SENSOR_CONFIG("INT347E", 1, 319200000), /* Omnivision OV2680 */ CIO2_SENSOR_CONFIG("OVTI2680", 0), }; diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c index 0e9b0503b62a..dbdbdb648a0d 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c @@ -65,6 +65,11 @@ static const struct ipu3_cio2_fmt formats[] = { .fourcc = V4L2_PIX_FMT_IPU3_SRGGB10, .mipicode = 0x2b, .bpp = 10, + }, { + .mbus_code = MEDIA_BUS_FMT_Y10_1X10, + .fourcc = V4L2_PIX_FMT_IPU3_Y10, + .mipicode = 0x2b, + .bpp = 10, }, }; @@ -1046,12 +1051,8 @@ static const struct vb2_ops cio2_vb2_ops = { static int cio2_v4l2_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct cio2_device *cio2 = video_drvdata(file); - strscpy(cap->driver, CIO2_NAME, sizeof(cap->driver)); strscpy(cap->card, CIO2_DEVICE_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "PCI:%s", pci_name(cio2->pci_dev)); return 0; } @@ -1777,8 +1778,6 @@ static int cio2_pci_probe(struct pci_dev *pci_dev, cio2->media_dev.dev = dev; strscpy(cio2->media_dev.model, CIO2_DEVICE_NAME, sizeof(cio2->media_dev.model)); - snprintf(cio2->media_dev.bus_info, sizeof(cio2->media_dev.bus_info), - "PCI:%s", pci_name(cio2->pci_dev)); cio2->media_dev.hw_revision = 0; media_device_init(&cio2->media_dev); diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index fee460e2ca86..7947dcd615e8 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -732,7 +732,6 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); strscpy(vcap->card, itv->card_name, sizeof(vcap->card)); - snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 8944e4bd4638..5d87efd9b95c 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1012,7 +1012,6 @@ static int vidioc_querycap(struct file *file, void *fh, { strscpy(cap->driver, "meye", sizeof(cap->driver)); strscpy(cap->card, "meye", sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev)); return 0; } diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 48543ad3d595..4d8974c9fcc9 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1475,7 +1475,6 @@ int saa7134_querycap(struct file *file, void *priv, strscpy(cap->driver, "saa7134", sizeof(cap->driver)); strscpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; @@ -1833,8 +1832,7 @@ static int saa7134_overlay(struct file *file, void *priv, unsigned int on) spin_lock_irqsave(&dev->slock, flags); start_preview(dev); spin_unlock_irqrestore(&dev->slock, flags); - } - if (!on) { + } else { if (priv != dev->overlay_owner) return -EINVAL; spin_lock_irqsave(&dev->slock, flags); diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 1d1d32e043f1..c1b6a0596801 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -490,7 +490,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, dev->name, sizeof(cap->driver)); strscpy(cap->card, saa7164_boards[dev->board].name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index cb2e09f0841d..a6738baab688 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -201,7 +201,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, dev->name, sizeof(cap->driver)); strscpy(cap->card, saa7164_boards[dev->board].name, sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 7766cadb73ea..80d20e2a2099 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -764,13 +764,10 @@ static int solo_enc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct solo_enc_dev *solo_enc = video_drvdata(file); - struct solo_dev *solo_dev = solo_enc->solo_dev; strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver)); snprintf(cap->card, sizeof(cap->card), "Softlogic 6x10 Enc %d", solo_enc->ch); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", - pci_name(solo_dev->pdev)); return 0; } diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index 24ef0c446bef..e18cc41fca83 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -372,12 +372,8 @@ static const struct vb2_ops solo_video_qops = { static int solo_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct solo_dev *solo_dev = video_drvdata(file); - strscpy(cap->driver, SOLO6X10_NAME, sizeof(cap->driver)); strscpy(cap->card, "Softlogic 6x10", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", - pci_name(solo_dev->pdev)); return 0; } diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 524912f20d9f..8535e49a4c4f 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -401,12 +401,8 @@ static const struct v4l2_file_operations vip_fops = { static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct sta2x11_vip *vip = video_drvdata(file); - strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", - pci_name(vip->pdev)); return 0; } diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c index 9131265c2b87..197ed8978102 100644 --- a/drivers/media/pci/tw5864/tw5864-video.c +++ b/drivers/media/pci/tw5864/tw5864-video.c @@ -604,7 +604,6 @@ static int tw5864_querycap(struct file *file, void *priv, strscpy(cap->driver, "tw5864", sizeof(cap->driver)); snprintf(cap->card, sizeof(cap->card), "TW5864 Encoder %d", input->nr); - sprintf(cap->bus_info, "PCI:%s", pci_name(input->root->pci)); return 0; } diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index fe94944d0531..0cbc5b038073 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -712,12 +712,9 @@ static int tw68_s_input(struct file *file, void *priv, unsigned int i) static int tw68_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct tw68_dev *dev = video_drvdata(file); - strscpy(cap->driver, "tw68", sizeof(cap->driver)); strscpy(cap->card, "Techwell Capture Card", sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); return 0; } diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index b227e9e78ebd..6344a479119f 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -762,8 +762,6 @@ static int tw686x_querycap(struct file *file, void *priv, strscpy(cap->driver, "tw686x", sizeof(cap->driver)); strscpy(cap->card, dev->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "PCI:%s", pci_name(dev->pci_dev)); return 0; } diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c index 4a3d06c70e34..2423714afcb9 100644 --- a/drivers/media/platform/allegro-dvt/allegro-core.c +++ b/drivers/media/platform/allegro-dvt/allegro-core.c @@ -3249,13 +3249,8 @@ static int allegro_release(struct file *file) static int allegro_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); - struct allegro_dev *dev = video_get_drvdata(vdev); - strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, "Allegro DVT Video Encoder", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&dev->plat_dev->dev)); return 0; } diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index 8f8dfd6ce2c6..3c02aa2a54aa 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -26,8 +26,8 @@ #include "vpu_cmds.h" #include "vpu_rpc.h" -#define VDEC_FRAME_DEPTH 256 #define VDEC_MIN_BUFFER_CAP 8 +#define VDEC_MIN_BUFFER_OUT 8 struct vdec_fs_info { char name[8]; @@ -63,8 +63,6 @@ struct vdec_t { bool is_source_changed; u32 source_change; u32 drain; - u32 ts_pre_count; - u32 frame_depth; }; static const struct vpu_format vdec_formats[] = { @@ -164,6 +162,12 @@ static int vdec_ctrl_init(struct vpu_inst *inst) if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + if (inst->ctrl_handler.error) { + ret = inst->ctrl_handler.error; + v4l2_ctrl_handler_free(&inst->ctrl_handler); + return ret; + } + ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler); if (ret) { dev_err(inst->dev, "[%d] setup ctrls fail, ret = %d\n", inst->id, ret); @@ -470,7 +474,7 @@ static int vdec_drain(struct vpu_inst *inst) if (!vdec->drain) return 0; - if (v4l2_m2m_num_src_bufs_ready(inst->fh.m2m_ctx)) + if (!vpu_is_source_empty(inst)) return 0; if (!vdec->params.frame_count) { @@ -589,11 +593,8 @@ static bool vdec_check_ready(struct vpu_inst *inst, unsigned int type) { struct vdec_t *vdec = inst->priv; - if (V4L2_TYPE_IS_OUTPUT(type)) { - if (vdec->ts_pre_count >= vdec->frame_depth) - return false; + if (V4L2_TYPE_IS_OUTPUT(type)) return true; - } if (vdec->req_frame_count) return true; @@ -601,12 +602,21 @@ static bool vdec_check_ready(struct vpu_inst *inst, unsigned int type) return false; } +static struct vb2_v4l2_buffer *vdec_get_src_buffer(struct vpu_inst *inst, u32 count) +{ + if (count > 1) + vpu_skip_frame(inst, count - 1); + + return vpu_next_src_buf(inst); +} + static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) { struct vdec_t *vdec = inst->priv; struct vpu_dec_pic_info *info = arg; struct vpu_vb2_buffer *vpu_buf; struct vb2_v4l2_buffer *vbuf; + struct vb2_v4l2_buffer *src_buf; int ret = 0; if (!info || info->id >= ARRAY_SIZE(vdec->slots)) @@ -620,14 +630,21 @@ static int vdec_frame_decoded(struct vpu_inst *inst, void *arg) goto exit; } vbuf = &vpu_buf->m2m_buf.vb; + src_buf = vdec_get_src_buffer(inst, info->consumed_count); + if (src_buf) { + v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true); + if (info->consumed_count) { + v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } else { + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_DECODED); + } + } if (vpu_get_buffer_state(vbuf) == VPU_BUF_STATE_DECODED) dev_info(inst->dev, "[%d] buf[%d] has been decoded\n", inst->id, info->id); vpu_set_buffer_state(vbuf, VPU_BUF_STATE_DECODED); vdec->decoded_frame_count++; - if (vdec->ts_pre_count >= info->consumed_count) - vdec->ts_pre_count -= info->consumed_count; - else - vdec->ts_pre_count = 0; exit: vpu_inst_unlock(inst); @@ -683,10 +700,9 @@ static void vdec_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) vpu_set_buffer_state(vbuf, VPU_BUF_STATE_READY); vb2_set_plane_payload(&vbuf->vb2_buf, 0, inst->cap_format.sizeimage[0]); vb2_set_plane_payload(&vbuf->vb2_buf, 1, inst->cap_format.sizeimage[1]); - vbuf->vb2_buf.timestamp = frame->timestamp; vbuf->field = inst->cap_format.field; vbuf->sequence = sequence; - dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, frame->timestamp); + dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); vpu_inst_lock(inst); @@ -708,7 +724,6 @@ static void vdec_stop_done(struct vpu_inst *inst) vdec->fixed_fmt = false; vdec->params.end_flag = 0; vdec->drain = 0; - vdec->ts_pre_count = 0; vdec->params.frame_count = 0; vdec->decoded_frame_count = 0; vdec->display_frame_count = 0; @@ -782,7 +797,7 @@ static void vdec_init_fmt(struct vpu_inst *inst) if (vdec->codec_info.progressive) inst->cap_format.field = V4L2_FIELD_NONE; else - inst->cap_format.field = V4L2_FIELD_SEQ_BT; + inst->cap_format.field = V4L2_FIELD_SEQ_TB; if (vdec->codec_info.color_primaries == V4L2_COLORSPACE_DEFAULT) vdec->codec_info.color_primaries = V4L2_COLORSPACE_REC709; if (vdec->codec_info.transfer_chars == V4L2_XFER_FUNC_DEFAULT) @@ -1244,18 +1259,14 @@ static int vdec_process_output(struct vpu_inst *inst, struct vb2_buffer *vb) if (free_space < vb2_get_plane_payload(vb, 0) + 0x40000) return -ENOMEM; + vpu_set_buffer_state(vbuf, VPU_BUF_STATE_INUSE); ret = vpu_iface_input_frame(inst, vb); if (ret < 0) return -ENOMEM; dev_dbg(inst->dev, "[%d][INPUT TS]%32lld\n", inst->id, vb->timestamp); - vdec->ts_pre_count++; vdec->params.frame_count++; - v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf); - vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); - if (vdec->drain) vdec_drain(inst); @@ -1318,7 +1329,6 @@ static void vdec_abort(struct vpu_inst *inst) vdec->sequence); vdec->params.end_flag = 0; vdec->drain = 0; - vdec->ts_pre_count = 0; vdec->params.frame_count = 0; vdec->decoded_frame_count = 0; vdec->display_frame_count = 0; @@ -1525,10 +1535,6 @@ static int vdec_get_debug_info(struct vpu_inst *inst, char *str, u32 size, u32 i vdec->drain, vdec->eos_received, vdec->source_change); break; case 8: - num = scnprintf(str, size, "ts_pre_count = %d, frame_depth = %d\n", - vdec->ts_pre_count, vdec->frame_depth); - break; - case 9: num = scnprintf(str, size, "fps = %d/%d\n", vdec->codec_info.frame_rate.numerator, vdec->codec_info.frame_rate.denominator); @@ -1562,12 +1568,8 @@ static struct vpu_inst_ops vdec_inst_ops = { static void vdec_init(struct file *file) { struct vpu_inst *inst = to_inst(file); - struct vdec_t *vdec; struct v4l2_format f; - vdec = inst->priv; - vdec->frame_depth = VDEC_FRAME_DEPTH; - memset(&f, 0, sizeof(f)); f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; @@ -1612,36 +1614,18 @@ static int vdec_open(struct file *file) vdec->fixed_fmt = false; inst->min_buffer_cap = VDEC_MIN_BUFFER_CAP; + inst->min_buffer_out = VDEC_MIN_BUFFER_OUT; vdec_init(file); return 0; } -static __poll_t vdec_poll(struct file *file, poll_table *wait) -{ - struct vpu_inst *inst = to_inst(file); - struct vb2_queue *src_q, *dst_q; - __poll_t ret; - - ret = v4l2_m2m_fop_poll(file, wait); - src_q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx); - dst_q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx); - if (vb2_is_streaming(src_q) && !vb2_is_streaming(dst_q)) - ret &= (~EPOLLERR); - if (!src_q->error && !dst_q->error && - (vb2_is_streaming(src_q) && list_empty(&src_q->queued_list)) && - (vb2_is_streaming(dst_q) && list_empty(&dst_q->queued_list))) - ret &= (~EPOLLERR); - - return ret; -} - static const struct v4l2_file_operations vdec_fops = { .owner = THIS_MODULE, .open = vdec_open, .release = vpu_v4l2_close, .unlocked_ioctl = video_ioctl2, - .poll = vdec_poll, + .poll = v4l2_m2m_fop_poll, .mmap = v4l2_m2m_fop_mmap, }; diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c index d33c2748e4b7..43d61d82f58c 100644 --- a/drivers/media/platform/amphion/venc.c +++ b/drivers/media/platform/amphion/venc.c @@ -33,6 +33,8 @@ #define VENC_CAPTURE_ENABLE BIT(1) #define VENC_ENABLE_MASK (VENC_OUTPUT_ENABLE | VENC_CAPTURE_ENABLE) #define VENC_MAX_BUF_CNT 8 +#define VENC_MIN_BUFFER_OUT 6 +#define VENC_MIN_BUFFER_CAP 6 struct venc_t { struct vpu_encode_params params; @@ -281,6 +283,9 @@ static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *parm if (!parm) return -EINVAL; + if (!V4L2_TYPE_IS_OUTPUT(parm->type)) + return -EINVAL; + if (!vpu_helper_check_type(inst, parm->type)) return -EINVAL; @@ -302,6 +307,9 @@ static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *parm if (!parm) return -EINVAL; + if (!V4L2_TYPE_IS_OUTPUT(parm->type)) + return -EINVAL; + if (!vpu_helper_check_type(inst, parm->type)) return -EINVAL; @@ -423,7 +431,7 @@ static int venc_drain(struct vpu_inst *inst) if (inst->state != VPU_CODEC_STATE_DRAIN) return 0; - if (v4l2_m2m_num_src_bufs_ready(inst->fh.m2m_ctx)) + if (!vpu_is_source_empty(inst)) return 0; if (!venc->input_ready) @@ -680,6 +688,12 @@ static int venc_ctrl_init(struct vpu_inst *inst) ~(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); + if (inst->ctrl_handler.error) { + ret = inst->ctrl_handler.error; + v4l2_ctrl_handler_free(&inst->ctrl_handler); + return ret; + } + ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler); if (ret) { dev_err(inst->dev, "[%d] setup ctrls fail, ret = %d\n", inst->id, ret); @@ -775,10 +789,20 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vbuf) { struct venc_t *venc = inst->priv; + struct vb2_v4l2_buffer *src_buf; if (!vbuf) return -EAGAIN; + src_buf = vpu_find_buf_by_sequence(inst, inst->out_format.type, frame->info.frame_id); + if (src_buf) { + v4l2_m2m_buf_copy_metadata(src_buf, vbuf, true); + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); + v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, src_buf); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + } else { + vbuf->vb2_buf.timestamp = frame->info.timestamp; + } if (!venc_get_enable(inst->priv, vbuf->vb2_buf.type)) { v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); return 0; @@ -800,11 +824,10 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst, } vb2_set_plane_payload(&vbuf->vb2_buf, 0, frame->bytesused); vbuf->sequence = frame->info.frame_id; - vbuf->vb2_buf.timestamp = frame->info.timestamp; vbuf->field = inst->cap_format.field; vbuf->flags |= frame->info.pic_type; vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); - dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, frame->info.timestamp); + dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); venc->ready_count++; @@ -860,33 +883,6 @@ static int venc_frame_encoded(struct vpu_inst *inst, void *arg) return ret; } -static void venc_buf_done(struct vpu_inst *inst, struct vpu_frame_info *frame) -{ - struct vb2_v4l2_buffer *vbuf; - - if (!inst->fh.m2m_ctx) - return; - - vpu_inst_lock(inst); - if (!venc_get_enable(inst->priv, frame->type)) - goto exit; - vbuf = vpu_find_buf_by_sequence(inst, frame->type, frame->sequence); - if (!vbuf) { - dev_err(inst->dev, "[%d] can't find buf: type %d, sequence %d\n", - inst->id, frame->type, frame->sequence); - goto exit; - } - - vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); - if (V4L2_TYPE_IS_OUTPUT(frame->type)) - v4l2_m2m_src_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf); - else - v4l2_m2m_dst_buf_remove_by_buf(inst->fh.m2m_ctx, vbuf); - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); -exit: - vpu_inst_unlock(inst); -} - static void venc_set_last_buffer_dequeued(struct vpu_inst *inst) { struct venc_t *venc = inst->priv; @@ -1252,7 +1248,6 @@ static struct vpu_inst_ops venc_inst_ops = { .check_ready = venc_check_ready, .input_done = venc_input_done, .get_one_frame = venc_frame_encoded, - .buf_done = venc_buf_done, .stop_done = venc_stop_done, .event_notify = venc_event_notify, .release = venc_release, @@ -1333,6 +1328,8 @@ static int venc_open(struct file *file) if (ret) return ret; + inst->min_buffer_out = VENC_MIN_BUFFER_OUT; + inst->min_buffer_cap = VENC_MIN_BUFFER_CAP; venc_init(file); return 0; diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c index 376196bea178..da62bd718fb8 100644 --- a/drivers/media/platform/amphion/vpu_dbg.c +++ b/drivers/media/platform/amphion/vpu_dbg.c @@ -413,10 +413,6 @@ int vpu_inst_create_dbgfs_file(struct vpu_inst *inst) vpu->debugfs, inst, &vpu_dbg_inst_fops); - if (!inst->debugfs) { - dev_err(inst->dev, "vpu create debugfs %s fail\n", name); - return -EINVAL; - } return 0; } @@ -451,10 +447,6 @@ int vpu_core_create_dbgfs_file(struct vpu_core *core) vpu->debugfs, core, &vpu_dbg_core_fops); - if (!core->debugfs) { - dev_err(core->dev, "vpu create debugfs %s fail\n", name); - return -EINVAL; - } } if (!core->debugfs_fwlog) { scnprintf(name, sizeof(name), "fwlog.%d", core->id); @@ -463,10 +455,6 @@ int vpu_core_create_dbgfs_file(struct vpu_core *core) vpu->debugfs, core, &vpu_dbg_fwlog_fops); - if (!core->debugfs_fwlog) { - dev_err(core->dev, "vpu create debugfs %s fail\n", name); - return -EINVAL; - } } return 0; diff --git a/drivers/media/platform/amphion/vpu_defs.h b/drivers/media/platform/amphion/vpu_defs.h index 282664202dcf..667637eedb5d 100644 --- a/drivers/media/platform/amphion/vpu_defs.h +++ b/drivers/media/platform/amphion/vpu_defs.h @@ -69,8 +69,8 @@ enum { VPU_MSG_ID_BS_ERROR, VPU_MSG_ID_UNSUPPORTED, VPU_MSG_ID_TIMESTAMP_INFO, - VPU_MSG_ID_FIRMWARE_XCPT, + VPU_MSG_ID_PIC_SKIPPED, }; enum VPU_ENC_MEMORY_RESOURSE { diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c index 446a9de0cc11..f29c223eefce 100644 --- a/drivers/media/platform/amphion/vpu_malone.c +++ b/drivers/media/platform/amphion/vpu_malone.c @@ -170,6 +170,7 @@ enum { VID_API_EVENT_DEC_CHECK_RES = 0x24, VID_API_EVENT_DEC_CFG_INFO = 0x25, VID_API_EVENT_UNSUPPORTED_STREAM = 0x26, + VID_API_EVENT_PIC_SKIPPED = 0x27, VID_API_EVENT_STR_SUSPENDED = 0x30, VID_API_EVENT_SNAPSHOT_DONE = 0x40, VID_API_EVENT_FW_STATUS = 0xF0, @@ -703,6 +704,7 @@ static struct vpu_pair malone_msgs[] = { {VPU_MSG_ID_BS_ERROR, VID_API_EVENT_BS_ERROR}, {VPU_MSG_ID_UNSUPPORTED, VID_API_EVENT_UNSUPPORTED_STREAM}, {VPU_MSG_ID_FIRMWARE_XCPT, VID_API_EVENT_FIRMWARE_XCPT}, + {VPU_MSG_ID_PIC_SKIPPED, VID_API_EVENT_PIC_SKIPPED}, }; static void vpu_malone_pack_fs_alloc(struct vpu_rpc_event *pkt, @@ -1556,7 +1558,7 @@ int vpu_malone_input_frame(struct vpu_shared_addr *shared, * merge the data to next frame */ vbuf = to_vb2_v4l2_buffer(vb); - if (vpu_vb_is_codecconfig(vbuf) && (s64)vb->timestamp < 0) { + if (vpu_vb_is_codecconfig(vbuf)) { inst->extra_size += size; return 0; } diff --git a/drivers/media/platform/amphion/vpu_msgs.c b/drivers/media/platform/amphion/vpu_msgs.c index 58502c51ddb3..d5850df8f1d5 100644 --- a/drivers/media/platform/amphion/vpu_msgs.c +++ b/drivers/media/platform/amphion/vpu_msgs.c @@ -166,6 +166,13 @@ static void vpu_session_handle_firmware_xcpt(struct vpu_inst *inst, struct vpu_r vpu_v4l2_set_error(inst); } +static void vpu_session_handle_pic_skipped(struct vpu_inst *inst, struct vpu_rpc_event *pkt) +{ + vpu_inst_lock(inst); + vpu_skip_frame(inst, 1); + vpu_inst_unlock(inst); +} + static struct vpu_msg_handler handlers[] = { {VPU_MSG_ID_START_DONE, vpu_session_handle_start_done}, {VPU_MSG_ID_STOP_DONE, vpu_session_handle_stop_done}, @@ -181,6 +188,7 @@ static struct vpu_msg_handler handlers[] = { {VPU_MSG_ID_PIC_EOS, vpu_session_handle_eos}, {VPU_MSG_ID_UNSUPPORTED, vpu_session_handle_error}, {VPU_MSG_ID_FIRMWARE_XCPT, vpu_session_handle_firmware_xcpt}, + {VPU_MSG_ID_PIC_SKIPPED, vpu_session_handle_pic_skipped}, }; static int vpu_session_handle_msg(struct vpu_inst *inst, struct vpu_rpc_event *msg) diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 9c0704cd5766..446f07d09d0b 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -73,10 +73,10 @@ void vpu_v4l2_set_error(struct vpu_inst *inst) if (inst->fh.m2m_ctx) { src_q = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx); dst_q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx); - if (src_q) - src_q->error = 1; - if (dst_q) - dst_q->error = 1; + src_q->error = 1; + dst_q->error = 1; + wake_up(&src_q->done_wq); + wake_up(&dst_q->done_wq); } vpu_inst_unlock(inst); } @@ -127,6 +127,19 @@ int vpu_set_last_buffer_dequeued(struct vpu_inst *inst) return 0; } +bool vpu_is_source_empty(struct vpu_inst *inst) +{ + struct v4l2_m2m_buffer *buf = NULL; + + if (!inst->fh.m2m_ctx) + return true; + v4l2_m2m_for_each_src_buf(inst->fh.m2m_ctx, buf) { + if (vpu_get_buffer_state(&buf->vb) == VPU_BUF_STATE_IDLE) + return false; + } + return true; +} + const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; @@ -234,6 +247,49 @@ int vpu_process_capture_buffer(struct vpu_inst *inst) return call_vop(inst, process_capture, &vbuf->vb2_buf); } +struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst) +{ + struct vb2_v4l2_buffer *src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx); + + if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) + return NULL; + + while (vpu_vb_is_codecconfig(src_buf)) { + v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); + + src_buf = v4l2_m2m_next_src_buf(inst->fh.m2m_ctx); + if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) + return NULL; + } + + return src_buf; +} + +void vpu_skip_frame(struct vpu_inst *inst, int count) +{ + struct vb2_v4l2_buffer *src_buf; + enum vb2_buffer_state state; + int i = 0; + + if (count <= 0) + return; + + while (i < count) { + src_buf = v4l2_m2m_src_buf_remove(inst->fh.m2m_ctx); + if (!src_buf || vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_IDLE) + return; + if (vpu_get_buffer_state(src_buf) == VPU_BUF_STATE_DECODED) + state = VB2_BUF_STATE_DONE; + else + state = VB2_BUF_STATE_ERROR; + i++; + vpu_set_buffer_state(src_buf, VPU_BUF_STATE_IDLE); + v4l2_m2m_buf_done(src_buf, state); + } +} + struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence) { struct v4l2_m2m_buffer *buf = NULL; @@ -342,6 +398,10 @@ static int vpu_vb2_queue_setup(struct vb2_queue *vq, return 0; } + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + *buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_out); + else + *buf_count = max_t(unsigned int, *buf_count, inst->min_buffer_cap); *plane_count = cur_fmt->num_planes; for (i = 0; i < cur_fmt->num_planes; i++) psize[i] = cur_fmt->sizeimage[i]; diff --git a/drivers/media/platform/amphion/vpu_v4l2.h b/drivers/media/platform/amphion/vpu_v4l2.h index 90fa7ea67495..795ca33a6a50 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.h +++ b/drivers/media/platform/amphion/vpu_v4l2.h @@ -19,6 +19,8 @@ int vpu_v4l2_close(struct file *file); const struct vpu_format *vpu_try_fmt_common(struct vpu_inst *inst, struct v4l2_format *f); int vpu_process_output_buffer(struct vpu_inst *inst); int vpu_process_capture_buffer(struct vpu_inst *inst); +struct vb2_v4l2_buffer *vpu_next_src_buf(struct vpu_inst *inst); +void vpu_skip_frame(struct vpu_inst *inst, int count); struct vb2_v4l2_buffer *vpu_find_buf_by_sequence(struct vpu_inst *inst, u32 type, u32 sequence); struct vb2_v4l2_buffer *vpu_find_buf_by_idx(struct vpu_inst *inst, u32 type, u32 idx); void vpu_v4l2_set_error(struct vpu_inst *inst); @@ -27,6 +29,7 @@ int vpu_notify_source_change(struct vpu_inst *inst); int vpu_set_last_buffer_dequeued(struct vpu_inst *inst); void vpu_vb2_buffers_return(struct vpu_inst *inst, unsigned int type, enum vb2_buffer_state state); int vpu_get_num_buffers(struct vpu_inst *inst, u32 type); +bool vpu_is_source_empty(struct vpu_inst *inst); dma_addr_t vpu_get_vb_phy_addr(struct vb2_buffer *vb, u32 plane_no); unsigned int vpu_get_vb_length(struct vb2_buffer *vb, u32 plane_no); diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c index b937dbcbe9e0..20f795ccc11b 100644 --- a/drivers/media/platform/aspeed/aspeed-video.c +++ b/drivers/media/platform/aspeed/aspeed-video.c @@ -1993,6 +1993,7 @@ static int aspeed_video_probe(struct platform_device *pdev) rc = aspeed_video_setup_video(video); if (rc) { + aspeed_video_free_buf(video, &video->jpeg); clk_unprepare(video->vclk); clk_unprepare(video->eclk); return rc; @@ -2024,8 +2025,7 @@ static int aspeed_video_remove(struct platform_device *pdev) v4l2_device_unregister(v4l2_dev); - dma_free_coherent(video->dev, VE_JPEG_HEADER_SIZE, video->jpeg.virt, - video->jpeg.dma); + aspeed_video_free_buf(video, &video->jpeg); of_reserved_mem_device_release(dev); diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c index db15770d5b88..2f07a50035c8 100644 --- a/drivers/media/platform/atmel/atmel-isc-base.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -401,6 +401,7 @@ static void isc_stop_streaming(struct vb2_queue *vq) struct isc_buffer *buf; int ret; + mutex_lock(&isc->awb_mutex); v4l2_ctrl_activate(isc->do_wb_ctrl, false); isc->stop = true; @@ -410,6 +411,8 @@ static void isc_stop_streaming(struct vb2_queue *vq) v4l2_err(&isc->v4l2_dev, "Timeout waiting for end of the capture\n"); + mutex_unlock(&isc->awb_mutex); + /* Disable DMA interrupt */ regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE); @@ -442,7 +445,7 @@ static void isc_buffer_queue(struct vb2_buffer *vb) spin_lock_irqsave(&isc->dma_queue_lock, flags); if (!isc->cur_frm && list_empty(&isc->dma_queue) && - vb2_is_streaming(vb->vb2_queue)) { + vb2_start_streaming_called(vb->vb2_queue)) { isc->cur_frm = buf; isc_start_dma(isc); } else @@ -1029,7 +1032,7 @@ static int isc_s_fmt_vid_cap(struct file *file, void *priv, { struct isc_device *isc = video_drvdata(file); - if (vb2_is_streaming(&isc->vb2_vidq)) + if (vb2_is_busy(&isc->vb2_vidq)) return -EBUSY; return isc_set_fmt(isc, f); @@ -1397,10 +1400,6 @@ static void isc_awb_work(struct work_struct *w) u32 min, max; int ret; - /* streaming is not active anymore */ - if (isc->stop) - return; - if (ctrls->hist_stat != HIST_ENABLED) return; @@ -1455,7 +1454,24 @@ static void isc_awb_work(struct work_struct *w) } regmap_write(regmap, ISC_HIS_CFG + isc->offsets.his, hist_id | baysel | ISC_HIS_CFG_RAR); + + /* + * We have to make sure the streaming has not stopped meanwhile. + * ISC requires a frame to clock the internal profile update. + * To avoid issues, lock the sequence with a mutex + */ + mutex_lock(&isc->awb_mutex); + + /* streaming is not active anymore */ + if (isc->stop) { + mutex_unlock(&isc->awb_mutex); + return; + }; + isc_update_profile(isc); + + mutex_unlock(&isc->awb_mutex); + /* if awb has been disabled, we don't need to start another histogram */ if (ctrls->awb) regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); @@ -1534,6 +1550,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) isc_update_awb_ctrls(isc); + mutex_lock(&isc->awb_mutex); if (vb2_is_streaming(&isc->vb2_vidq)) { /* * If we are streaming, we can update profile to @@ -1548,6 +1565,7 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl) */ v4l2_ctrl_activate(isc->do_wb_ctrl, false); } + mutex_unlock(&isc->awb_mutex); /* if we have autowhitebalance on, start histogram procedure */ if (ctrls->awb == ISC_WB_AUTO && @@ -1729,6 +1747,7 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier, { struct isc_device *isc = container_of(notifier->v4l2_dev, struct isc_device, v4l2_dev); + mutex_destroy(&isc->awb_mutex); cancel_work_sync(&isc->awb_work); video_unregister_device(&isc->video_dev); v4l2_ctrl_handler_free(&isc->ctrls.handler); @@ -1838,6 +1857,8 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) isc->current_subdev = container_of(notifier, struct isc_subdev_entity, notifier); mutex_init(&isc->lock); + mutex_init(&isc->awb_mutex); + init_completion(&isc->comp); /* Initialize videobuf2 queue */ @@ -1906,6 +1927,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) return 0; isc_async_complete_err: + mutex_destroy(&isc->awb_mutex); mutex_destroy(&isc->lock); return ret; } diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h index 07fa6dbf8460..ff60ba020cb9 100644 --- a/drivers/media/platform/atmel/atmel-isc.h +++ b/drivers/media/platform/atmel/atmel-isc.h @@ -218,6 +218,7 @@ struct isc_reg_offsets { * * @lock: lock for serializing userspace file operations * with ISC operations + * @awb_mutex: serialize access to streaming status from awb work queue * @awb_lock: lock for serializing awb work queue operations * with DMA/buffer operations * @@ -272,7 +273,7 @@ struct isc_device { struct video_device video_dev; struct vb2_queue vb2_vidq; - spinlock_t dma_queue_lock; /* serialize access to dma queue */ + spinlock_t dma_queue_lock; struct list_head dma_queue; struct isc_buffer *cur_frm; unsigned int sequence; @@ -289,8 +290,9 @@ struct isc_device { struct isc_ctrls ctrls; struct work_struct awb_work; - struct mutex lock; /* serialize access to file operations */ - spinlock_t awb_lock; /* serialize access to DMA buffers from awb work queue */ + struct mutex lock; + struct mutex awb_mutex; + spinlock_t awb_lock; struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c index c5b9563e36cb..9881d89a645b 100644 --- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -60,56 +60,39 @@ static const struct isc_format sama5d2_controller_formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB444, - }, - { + }, { .fourcc = V4L2_PIX_FMT_ARGB555, - }, - { + }, { .fourcc = V4L2_PIX_FMT_RGB565, - }, - { + }, { .fourcc = V4L2_PIX_FMT_ABGR32, - }, - { + }, { .fourcc = V4L2_PIX_FMT_XBGR32, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUV420, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUYV, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUV422P, - }, - { + }, { .fourcc = V4L2_PIX_FMT_GREY, - }, - { + }, { .fourcc = V4L2_PIX_FMT_Y10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SBGGR8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGBRG8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGRBG8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SRGGB8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SBGGR10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGBRG10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGRBG10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SRGGB10, }, }; @@ -291,7 +274,7 @@ static void isc_sama5d2_config_rlp(struct isc_device *isc) * Thus, if the YCYC mode is selected, replace it with the * sama5d2-compliant mode which is YYCC . */ - if ((rlp_mode & ISC_RLP_CFG_MODE_YCYC) == ISC_RLP_CFG_MODE_YCYC) { + if ((rlp_mode & ISC_RLP_CFG_MODE_MASK) == ISC_RLP_CFG_MODE_YCYC) { rlp_mode &= ~ISC_RLP_CFG_MODE_MASK; rlp_mode |= ISC_RLP_CFG_MODE_YYCC; } @@ -562,7 +545,7 @@ static int atmel_isc_probe(struct platform_device *pdev) ret = clk_prepare_enable(isc->ispck); if (ret) { dev_err(dev, "failed to enable ispck: %d\n", ret); - goto cleanup_subdev; + goto disable_pm; } /* ispck should be greater or equal to hclock */ @@ -580,6 +563,9 @@ static int atmel_isc_probe(struct platform_device *pdev) unprepare_clk: clk_disable_unprepare(isc->ispck); +disable_pm: + pm_runtime_disable(dev); + cleanup_subdev: isc_subdev_cleanup(isc); diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c index 07a80b08bc54..83b175070c06 100644 --- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c +++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c @@ -63,65 +63,45 @@ static const struct isc_format sama7g5_controller_formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB444, - }, - { + }, { .fourcc = V4L2_PIX_FMT_ARGB555, - }, - { + }, { .fourcc = V4L2_PIX_FMT_RGB565, - }, - { + }, { .fourcc = V4L2_PIX_FMT_ABGR32, - }, - { + }, { .fourcc = V4L2_PIX_FMT_XBGR32, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUV420, - }, - { + }, { .fourcc = V4L2_PIX_FMT_UYVY, - }, - { + }, { .fourcc = V4L2_PIX_FMT_VYUY, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUYV, - }, - { + }, { .fourcc = V4L2_PIX_FMT_YUV422P, - }, - { + }, { .fourcc = V4L2_PIX_FMT_GREY, - }, - { + }, { .fourcc = V4L2_PIX_FMT_Y10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_Y16, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SBGGR8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGBRG8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGRBG8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SRGGB8, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SBGGR10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGBRG10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SGRBG10, - }, - { + }, { .fourcc = V4L2_PIX_FMT_SRGGB10, }, }; @@ -225,7 +205,6 @@ static struct isc_format sama7g5_formats_list[] = { .mbus_code = MEDIA_BUS_FMT_Y10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, }, - }; static void isc_sama7g5_config_csc(struct isc_device *isc) diff --git a/drivers/media/platform/atmel/microchip-csi2dc.c b/drivers/media/platform/atmel/microchip-csi2dc.c index 2487978db1f1..d5b359f607ae 100644 --- a/drivers/media/platform/atmel/microchip-csi2dc.c +++ b/drivers/media/platform/atmel/microchip-csi2dc.c @@ -454,6 +454,10 @@ static int csi2dc_init_cfg(struct v4l2_subdev *csi2dc_sd, return 0; } +static const struct media_entity_operations csi2dc_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + static const struct v4l2_subdev_pad_ops csi2dc_pad_ops = { .enum_mbus_code = csi2dc_enum_mbus_code, .set_fmt = csi2dc_set_fmt, @@ -683,6 +687,7 @@ static int csi2dc_probe(struct platform_device *pdev) csi2dc->csi2dc_sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; csi2dc->csi2dc_sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + csi2dc->csi2dc_sd.entity.ops = &csi2dc_entity_ops; platform_set_drvdata(pdev, csi2dc); diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c index 8f8c36056354..58e405b69f67 100644 --- a/drivers/media/platform/cadence/cdns-csi2tx.c +++ b/drivers/media/platform/cadence/cdns-csi2tx.c @@ -15,6 +15,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> +#include <media/mipi-csi2.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -121,12 +122,12 @@ static const struct csi2tx_fmt csi2tx_formats[] = { { .mbus = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 2, - .dt = 0x1e, + .dt = MIPI_CSI2_DT_YUV422_8B, }, { .mbus = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 3, - .dt = 0x24, + .dt = MIPI_CSI2_DT_RGB888, }, }; diff --git a/drivers/media/platform/chips-media/coda-bit.c b/drivers/media/platform/chips-media/coda-bit.c index c484c008ab02..2736a902e3df 100644 --- a/drivers/media/platform/chips-media/coda-bit.c +++ b/drivers/media/platform/chips-media/coda-bit.c @@ -326,6 +326,8 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) struct coda_buffer_meta *meta; u32 start; + lockdep_assert_held(&ctx->bitstream_mutex); + if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) return; @@ -2174,7 +2176,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx) (!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) { coda_dbg(1, ctx, "bitstream payload: %d, skipping\n", coda_get_bitstream_payload(ctx)); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); return -EAGAIN; } @@ -2184,7 +2185,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx) if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to start decoding\n"); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); return -EAGAIN; } else { ctx->initialized = 1; diff --git a/drivers/media/platform/chips-media/coda-common.c b/drivers/media/platform/chips-media/coda-common.c index a57822b05070..af71eea04dbd 100644 --- a/drivers/media/platform/chips-media/coda-common.c +++ b/drivers/media/platform/chips-media/coda-common.c @@ -657,6 +657,8 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, const struct coda_q_data *q_data_src; const struct coda_codec *codec; struct vb2_queue *src_vq; + int hscale = 0; + int vscale = 0; int ret; bool use_vdoa; @@ -673,8 +675,13 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, */ src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (vb2_is_streaming(src_vq)) { - f->fmt.pix.width = q_data_src->width; - f->fmt.pix.height = q_data_src->height; + if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && + ctx->dev->devtype->product == CODA_960) { + hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width); + vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height); + } + f->fmt.pix.width = q_data_src->width >> hscale; + f->fmt.pix.height = q_data_src->height >> vscale; if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { if (ctx->params.jpeg_chroma_subsampling == @@ -704,8 +711,8 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv, /* The decoders always write complete macroblocks or MCUs */ if (ctx->inst_type == CODA_INST_DECODER) { - f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16); - f->fmt.pix.height = round_up(f->fmt.pix.height, 16); + f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16 >> hscale); + f->fmt.pix.height = round_up(f->fmt.pix.height, 16 >> vscale); if (codec->src_fourcc == V4L2_PIX_FMT_JPEG && f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) { f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * @@ -850,17 +857,26 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv, struct coda_q_data *q_data_src; const struct coda_codec *codec; struct v4l2_rect r; + int hscale = 0; + int vscale = 0; int ret; + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + + if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && + ctx->dev->devtype->product == CODA_960) { + hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width); + vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height); + } + ret = coda_try_fmt_vid_cap(file, priv, f); if (ret) return ret; - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); r.left = 0; r.top = 0; - r.width = q_data_src->width; - r.height = q_data_src->height; + r.width = q_data_src->width >> hscale; + r.height = q_data_src->height >> vscale; ret = coda_s_fmt(ctx, f, &r); if (ret) @@ -1091,17 +1107,6 @@ static int coda_s_selection(struct file *file, void *fh, } } -static int coda_try_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *ec) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - - if (ctx->inst_type != CODA_INST_ENCODER) - return -ENOTTY; - - return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); -} - static void coda_wake_up_capture_queue(struct coda_ctx *ctx) { struct vb2_queue *dst_vq; @@ -1120,7 +1125,7 @@ static int coda_encoder_cmd(struct file *file, void *fh, struct vb2_v4l2_buffer *buf; int ret; - ret = coda_try_encoder_cmd(file, fh, ec); + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); if (ret < 0) return ret; @@ -1149,17 +1154,6 @@ static int coda_encoder_cmd(struct file *file, void *fh, return 0; } -static int coda_try_decoder_cmd(struct file *file, void *fh, - struct v4l2_decoder_cmd *dc) -{ - struct coda_ctx *ctx = fh_to_ctx(fh); - - if (ctx->inst_type != CODA_INST_DECODER) - return -ENOTTY; - - return v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); -} - static bool coda_mark_last_meta(struct coda_ctx *ctx) { struct coda_buffer_meta *meta; @@ -1216,7 +1210,7 @@ static int coda_decoder_cmd(struct file *file, void *fh, bool wakeup; int ret; - ret = coda_try_decoder_cmd(file, fh, dc); + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); if (ret < 0) return ret; @@ -1291,9 +1285,6 @@ static int coda_enum_framesizes(struct file *file, void *fh, struct coda_q_data *q_data_dst; const struct coda_codec *codec; - if (ctx->inst_type != CODA_INST_ENCODER) - return -ENOTTY; - if (fsize->index) return -EINVAL; @@ -1324,7 +1315,8 @@ static int coda_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *f) { struct coda_ctx *ctx = fh_to_ctx(fh); - int i; + struct coda_q_data *q_data; + const struct coda_codec *codec; if (f->index) return -EINVAL; @@ -1333,12 +1325,19 @@ static int coda_enum_frameintervals(struct file *file, void *fh, if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV) return -EINVAL; - for (i = 0; i < CODA_MAX_FORMATS; i++) { - if (f->pixel_format == ctx->cvd->src_formats[i] || - f->pixel_format == ctx->cvd->dst_formats[i]) - break; + if (coda_format_normalize_yuv(f->pixel_format) == V4L2_PIX_FMT_YUV420) { + q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + codec = coda_find_codec(ctx->dev, f->pixel_format, + q_data->fourcc); + } else { + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, + f->pixel_format); } - if (i == CODA_MAX_FORMATS) + if (!codec) + return -EINVAL; + + if (f->width < MIN_W || f->width > codec->max_w || + f->height < MIN_H || f->height > codec->max_h) return -EINVAL; f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; @@ -1498,9 +1497,9 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_g_selection = coda_g_selection, .vidioc_s_selection = coda_s_selection, - .vidioc_try_encoder_cmd = coda_try_encoder_cmd, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, .vidioc_encoder_cmd = coda_encoder_cmd, - .vidioc_try_decoder_cmd = coda_try_decoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, .vidioc_decoder_cmd = coda_decoder_cmd, .vidioc_g_parm = coda_g_parm, @@ -1535,12 +1534,8 @@ static void coda_pic_run_work(struct work_struct *work) mutex_lock(&dev->coda_mutex); ret = ctx->ops->prepare_run(ctx); - if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) { - mutex_unlock(&dev->coda_mutex); - mutex_unlock(&ctx->buffer_mutex); - /* job_finish scheduled by prepare_decode */ - return; - } + if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) + goto out; if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { @@ -1562,6 +1557,7 @@ static void coda_pic_run_work(struct work_struct *work) ctx->ops->seq_end_work) queue_work(dev->workqueue, &ctx->seq_end_work); +out: mutex_unlock(&dev->coda_mutex); mutex_unlock(&ctx->buffer_mutex); @@ -1665,13 +1661,18 @@ static void set_default_params(struct coda_ctx *ctx) csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h); ctx->params.codec_mode = ctx->codec->mode; - if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG) - ctx->colorspace = V4L2_COLORSPACE_JPEG; - else + if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG || + ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) { + ctx->colorspace = V4L2_COLORSPACE_SRGB; + ctx->xfer_func = V4L2_XFER_FUNC_SRGB; + ctx->ycbcr_enc = V4L2_YCBCR_ENC_601; + ctx->quantization = V4L2_QUANTIZATION_FULL_RANGE; + } else { ctx->colorspace = V4L2_COLORSPACE_REC709; - ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; - ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - ctx->quantization = V4L2_QUANTIZATION_DEFAULT; + ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; + ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + ctx->quantization = V4L2_QUANTIZATION_DEFAULT; + } ctx->params.framerate = 30; /* Default formats for output and input queues */ @@ -2011,13 +2012,13 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) */ if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) { buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - ret = coda_jpeg_decode_header(ctx, &buf->vb2_buf); - if (ret < 0) { - v4l2_err(v4l2_dev, - "failed to decode JPEG header: %d\n", - ret); - goto err; - } + coda_jpeg_decode_header(ctx, &buf->vb2_buf); + /* + * We have to start streaming even if the first buffer + * does not contain a valid JPEG image. The error will + * be caught during device run and will be signalled + * via the capture buffer error flag. + */ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); q_data_dst->width = round_up(q_data_src->width, 16); @@ -2344,8 +2345,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0); v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, - V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, - V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, 0x0, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE); if (ctx->dev->devtype->product == CODA_HX4 || ctx->dev->devtype->product == CODA_7541) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, @@ -2359,12 +2360,15 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) if (ctx->dev->devtype->product == CODA_960) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, - V4L2_MPEG_VIDEO_H264_LEVEL_4_0, - ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + V4L2_MPEG_VIDEO_H264_LEVEL_4_2, + ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0)), + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2)), V4L2_MPEG_VIDEO_H264_LEVEL_4_0); } v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, @@ -2426,7 +2430,7 @@ static void coda_decode_ctrls(struct coda_ctx *ctx) ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, - ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), V4L2_MPEG_VIDEO_H264_PROFILE_HIGH); @@ -2901,6 +2905,23 @@ static int coda_register_device(struct coda_dev *dev, int i) v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); + if (dev->devtype->vdevs[i]->type == CODA_INST_ENCODER) { + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + if (dev->devtype->vdevs[i]->dst_formats[0] == V4L2_PIX_FMT_JPEG) { + v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); + } + } else { + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMESIZES); + v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(vfd, VIDIOC_G_PARM); + v4l2_disable_ioctl(vfd, VIDIOC_S_PARM); + } + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); if (!ret) v4l2_info(&dev->v4l2_dev, "%s registered as %s\n", diff --git a/drivers/media/platform/chips-media/coda-jpeg.c b/drivers/media/platform/chips-media/coda-jpeg.c index a72f4655e5ad..a0b22b07f69a 100644 --- a/drivers/media/platform/chips-media/coda-jpeg.c +++ b/drivers/media/platform/chips-media/coda-jpeg.c @@ -283,7 +283,8 @@ int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb) ret = v4l2_jpeg_parse_header(buf, len, &header); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to parse header\n"); + v4l2_err(&dev->v4l2_dev, "failed to parse JPEG header: %pe\n", + ERR_PTR(ret)); return ret; } @@ -1328,6 +1329,7 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) struct coda_q_data *q_data_src, *q_data_dst; struct vb2_v4l2_buffer *src_buf, *dst_buf; int chroma_interleave; + int scl_hor_mode, scl_ver_mode; src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1335,27 +1337,24 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); dst_fourcc = q_data_dst->fourcc; + scl_hor_mode = coda_jpeg_scale(q_data_src->width, q_data_dst->width); + scl_ver_mode = coda_jpeg_scale(q_data_src->height, q_data_dst->height); + if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 0) vb2_set_plane_payload(&src_buf->vb2_buf, 0, vb2_plane_size(&src_buf->vb2_buf, 0)); chroma_format = coda9_jpeg_chroma_format(q_data_dst->fourcc); - if (chroma_format < 0) { - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); + if (chroma_format < 0) return chroma_format; - } ret = coda_jpeg_decode_header(ctx, &src_buf->vb2_buf); if (ret < 0) { - v4l2_err(&dev->v4l2_dev, "failed to decode JPEG header: %d\n", - ret); - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); return ret; } @@ -1386,7 +1385,11 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) coda_write(dev, 0, CODA9_REG_JPEG_ROT_INFO); coda_write(dev, bus_req_num[chroma_format], CODA9_REG_JPEG_OP_INFO); coda_write(dev, mcu_info[chroma_format], CODA9_REG_JPEG_MCU_INFO); - coda_write(dev, 0, CODA9_REG_JPEG_SCL_INFO); + if (scl_hor_mode || scl_ver_mode) + val = CODA9_JPEG_SCL_ENABLE | (scl_hor_mode << 2) | scl_ver_mode; + else + val = 0; + coda_write(dev, val, CODA9_REG_JPEG_SCL_INFO); coda_write(dev, chroma_interleave, CODA9_REG_JPEG_DPB_CONFIG); coda_write(dev, ctx->params.jpeg_restart_interval, CODA9_REG_JPEG_RST_INTVAL); @@ -1396,7 +1399,6 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx) if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to set up Huffman tables: %d\n", ret); - v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); return ret; } } diff --git a/drivers/media/platform/chips-media/coda.h b/drivers/media/platform/chips-media/coda.h index dcf35641c603..ddfd0a32c653 100644 --- a/drivers/media/platform/chips-media/coda.h +++ b/drivers/media/platform/chips-media/coda.h @@ -380,6 +380,13 @@ u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, u8 level_idc); +static inline int coda_jpeg_scale(int src, int dst) +{ + return (dst <= src / 8) ? 3 : + (dst <= src / 4) ? 2 : + (dst <= src / 2) ? 1 : 0; +} + bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_jpeg_write_tables(struct coda_ctx *ctx); diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c index 03dcf8bf705e..ae97ce4ead98 100644 --- a/drivers/media/platform/marvell/cafe-driver.c +++ b/drivers/media/platform/marvell/cafe-driver.c @@ -497,7 +497,6 @@ static int cafe_pci_probe(struct pci_dev *pdev, mcam->plat_power_up = cafe_ctlr_power_up; mcam->plat_power_down = cafe_ctlr_power_down; mcam->dev = &pdev->dev; - snprintf(mcam->bus_info, sizeof(mcam->bus_info), "PCI:%s", pci_name(pdev)); /* * Vmalloc mode for buffers is traditional with this driver. * We *might* be able to run DMA_contig, especially on a system diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c index ab5485dfc20c..bc5b0a0168ec 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c @@ -137,8 +137,6 @@ static int mtk_jpeg_querycap(struct file *file, void *priv, strscpy(cap->driver, jpeg->variant->dev_name, sizeof(cap->driver)); strscpy(cap->card, jpeg->variant->dev_name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(jpeg->dev)); return 0; } diff --git a/drivers/media/platform/mediatek/vcodec/Kconfig b/drivers/media/platform/mediatek/vcodec/Kconfig index c5c76753c626..74b00eb1bc97 100644 --- a/drivers/media/platform/mediatek/vcodec/Kconfig +++ b/drivers/media/platform/mediatek/vcodec/Kconfig @@ -22,6 +22,7 @@ config VIDEO_MEDIATEK_VCODEC select VIDEO_MEDIATEK_VCODEC_VPU if VIDEO_MEDIATEK_VPU select VIDEO_MEDIATEK_VCODEC_SCP if MTK_SCP select V4L2_H264 + select V4L2_VP9 select MEDIA_CONTROLLER select MEDIA_CONTROLLER_REQUEST_API help diff --git a/drivers/media/platform/mediatek/vcodec/Makefile b/drivers/media/platform/mediatek/vcodec/Makefile index 359619653a0e..93e7a343b5b0 100644 --- a/drivers/media/platform/mediatek/vcodec/Makefile +++ b/drivers/media/platform/mediatek/vcodec/Makefile @@ -7,8 +7,12 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec/vdec_vp8_if.o \ + vdec/vdec_vp8_req_if.o \ vdec/vdec_vp9_if.o \ + vdec/vdec_vp9_req_lat_if.o \ vdec/vdec_h264_req_if.o \ + vdec/vdec_h264_req_common.o \ + vdec/vdec_h264_req_multi_if.o \ mtk_vcodec_dec_drv.o \ vdec_drv_if.o \ vdec_vpu_if.o \ diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c index 130ecef2e766..52e5d36aa912 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c @@ -26,7 +26,7 @@ mtk_vdec_find_format(struct v4l2_format *f, const struct mtk_video_fmt *fmt; unsigned int k; - for (k = 0; k < dec_pdata->num_formats; k++) { + for (k = 0; k < *dec_pdata->num_formats; k++) { fmt = &dec_pdata->vdec_formats[k]; if (fmt->fourcc == f->fmt.pix_mp.pixelformat) return fmt; @@ -47,14 +47,7 @@ static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx, static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) { - struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); - - /* Use M2M stateless helper if relevant */ - if (ctx->dev->vdec_pdata->uses_stateless_api) - return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, - cmd); - else - return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); + return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); } @@ -69,10 +62,6 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, if (ret) return ret; - /* Use M2M stateless helper if relevant */ - if (ctx->dev->vdec_pdata->uses_stateless_api) - return v4l2_m2m_ioctl_stateless_decoder_cmd(file, priv, cmd); - mtk_v4l2_debug(1, "decoder cmd=%u", cmd->cmd); dst_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); @@ -152,13 +141,15 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) q_data->coded_height = DFT_CFG_HEIGHT; q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt; q_data->field = V4L2_FIELD_NONE; + ctx->max_width = MTK_VDEC_MAX_W; + ctx->max_height = MTK_VDEC_MAX_H; v4l_bound_align_image(&q_data->coded_width, MTK_VDEC_MIN_W, - MTK_VDEC_MAX_W, 4, + ctx->max_width, 4, &q_data->coded_height, MTK_VDEC_MIN_H, - MTK_VDEC_MAX_H, 5, 6); + ctx->max_height, 5, 6); q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; q_data->bytesperline[0] = q_data->coded_width; @@ -217,7 +208,7 @@ static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh, } } -static int vidioc_try_fmt(struct v4l2_format *f, +static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f, const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; @@ -225,9 +216,9 @@ static int vidioc_try_fmt(struct v4l2_format *f, pix_fmt_mp->field = V4L2_FIELD_NONE; pix_fmt_mp->width = - clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, MTK_VDEC_MAX_W); + clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, ctx->max_width); pix_fmt_mp->height = - clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, MTK_VDEC_MAX_H); + clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, ctx->max_height); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { pix_fmt_mp->num_planes = 1; @@ -245,16 +236,16 @@ static int vidioc_try_fmt(struct v4l2_format *f, tmp_h = pix_fmt_mp->height; v4l_bound_align_image(&pix_fmt_mp->width, MTK_VDEC_MIN_W, - MTK_VDEC_MAX_W, 6, + ctx->max_width, 6, &pix_fmt_mp->height, MTK_VDEC_MIN_H, - MTK_VDEC_MAX_H, 6, 9); + ctx->max_height, 6, 9); if (pix_fmt_mp->width < tmp_w && - (pix_fmt_mp->width + 64) <= MTK_VDEC_MAX_W) + (pix_fmt_mp->width + 64) <= ctx->max_width) pix_fmt_mp->width += 64; if (pix_fmt_mp->height < tmp_h && - (pix_fmt_mp->height + 64) <= MTK_VDEC_MAX_H) + (pix_fmt_mp->height + 64) <= ctx->max_height) pix_fmt_mp->height += 64; mtk_v4l2_debug(0, @@ -294,7 +285,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, fmt = mtk_vdec_find_format(f, dec_pdata); } - return vidioc_try_fmt(f, fmt); + return vidioc_try_fmt(ctx, f, fmt); } static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, @@ -317,7 +308,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, return -EINVAL; } - return vidioc_try_fmt(f, fmt); + return vidioc_try_fmt(ctx, f, fmt); } static int vidioc_vdec_g_selection(struct file *file, void *priv, @@ -444,8 +435,15 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, if (fmt == NULL) return -EINVAL; + if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED) && + fmt->fourcc != V4L2_PIX_FMT_VP8_FRAME) { + mtk_v4l2_debug(3, "4K is enabled"); + ctx->max_width = VCODEC_DEC_4K_CODED_WIDTH; + ctx->max_height = VCODEC_DEC_4K_CODED_HEIGHT; + } + q_data->fmt = fmt; - vidioc_try_fmt(f, q_data->fmt); + vidioc_try_fmt(ctx, f, q_data->fmt); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage; q_data->coded_width = pix_mp->width; @@ -466,6 +464,8 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, } ctx->state = MTK_STATE_INIT; } + } else { + ctx->capture_fourcc = fmt->fourcc; } /* @@ -476,11 +476,14 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, ctx->picinfo.pic_w = pix_mp->width; ctx->picinfo.pic_h = pix_mp->height; + /* + * If get pic info fail, need to use the default pic info params, or + * v4l2-compliance will fail + */ ret = vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo); if (ret) { mtk_v4l2_err("[%d]Error!! Get GET_PARAM_PICTURE_INFO Fail", ctx->id); - return -EINVAL; } ctx->last_decoded_picinfo = ctx->picinfo; @@ -523,20 +526,15 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, if (fsize->index != 0) return -EINVAL; - for (i = 0; i < dec_pdata->num_framesizes; ++i) { + for (i = 0; i < *dec_pdata->num_framesizes; ++i) { if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc) continue; fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise; - if (!(ctx->dev->dec_capability & - VCODEC_CAPABILITY_4K_DISABLED)) { - mtk_v4l2_debug(3, "4K is enabled"); - fsize->stepwise.max_width = - VCODEC_DEC_4K_CODED_WIDTH; - fsize->stepwise.max_height = - VCODEC_DEC_4K_CODED_HEIGHT; - } + + fsize->stepwise.max_width = ctx->max_width; + fsize->stepwise.max_height = ctx->max_height; mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d", ctx->dev->dec_capability, fsize->stepwise.min_width, @@ -545,6 +543,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, fsize->stepwise.min_height, fsize->stepwise.max_height, fsize->stepwise.step_height); + return 0; } @@ -559,7 +558,7 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, const struct mtk_video_fmt *fmt; int i, j = 0; - for (i = 0; i < dec_pdata->num_formats; i++) { + for (i = 0; i < *dec_pdata->num_formats; i++) { if (output_queue && dec_pdata->vdec_formats[i].type != MTK_FMT_DEC) continue; @@ -572,7 +571,7 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv, ++j; } - if (i == dec_pdata->num_formats) + if (i == *dec_pdata->num_formats) return -EINVAL; fmt = &dec_pdata->vdec_formats[i]; @@ -737,6 +736,8 @@ int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) i, vb2_plane_size(vb, i), q_data->sizeimage[i]); } + if (!V4L2_TYPE_IS_OUTPUT(vb->type)) + vb2_set_plane_payload(vb, i, q_data->sizeimage[i]); } return 0; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.h index 66cd6d2242c3..4572f92826f2 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.h @@ -69,6 +69,7 @@ extern const struct media_device_ops mtk_vcodec_media_ops; extern const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata; extern const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata; extern const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata; +extern const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata; /* diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c index df7b25e9cbc8..995e6e2fb1ab 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c @@ -193,9 +193,6 @@ static int fops_vcodec_open(struct file *file) mtk_vcodec_dec_set_default_params(ctx); if (v4l2_fh_is_singular(&ctx->fh)) { - ret = mtk_vcodec_dec_pw_on(dev, MTK_VDEC_LAT0); - if (ret < 0) - goto err_load_fw; /* * Does nothing if firmware was already loaded. */ @@ -252,8 +249,6 @@ static int fops_vcodec_release(struct file *file) v4l2_m2m_ctx_release(ctx->m2m_ctx); mtk_vcodec_dec_release(ctx); - if (v4l2_fh_is_singular(&ctx->fh)) - mtk_vcodec_dec_pw_off(dev, MTK_VDEC_LAT0); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); @@ -400,6 +395,9 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } if (dev->vdec_pdata->uses_stateless_api) { + v4l2_disable_ioctl(vfd_dec, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd_dec, VIDIOC_TRY_DECODER_CMD); + dev->mdev_dec.dev = &pdev->dev; strscpy(dev->mdev_dec.model, MTK_VCODEC_DEC_NAME, sizeof(dev->mdev_dec.model)); @@ -463,6 +461,10 @@ static const struct of_device_id mtk_vcodec_match[] = { .compatible = "mediatek,mt8192-vcodec-dec", .data = &mtk_lat_sig_core_pdata, }, + { + .compatible = "mediatek,mt8186-vcodec-dec", + .data = &mtk_vdec_single_core_pdata, + }, {}, }; @@ -487,7 +489,8 @@ static int mtk_vcodec_dec_remove(struct platform_device *pdev) video_unregister_device(dev->vfd_dec); v4l2_device_unregister(&dev->v4l2_dev); - pm_runtime_disable(dev->pm.dev); + if (!dev->vdec_pdata->is_subdev_supported) + pm_runtime_disable(dev->pm.dev); mtk_vcodec_fw_release(dev->fw_handler); return 0; } diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c index 7e0c2644bf7b..0fb7e5ba635b 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c @@ -57,74 +57,31 @@ int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm * } EXPORT_SYMBOL_GPL(mtk_vcodec_init_dec_clk); -int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; int ret; - if (vdec_dev->vdec_pdata->is_subdev_supported) { - subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { - mtk_v4l2_err("Failed to get hw dev\n"); - return -EINVAL; - } - pm = &subdev_dev->pm; - } else { - pm = &vdec_dev->pm; - } - ret = pm_runtime_resume_and_get(pm->dev); if (ret) mtk_v4l2_err("pm_runtime_resume_and_get fail %d", ret); return ret; } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_on); -void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; int ret; - if (vdec_dev->vdec_pdata->is_subdev_supported) { - subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { - mtk_v4l2_err("Failed to get hw dev\n"); - return; - } - pm = &subdev_dev->pm; - } else { - pm = &vdec_dev->pm; - } - ret = pm_runtime_put_sync(pm->dev); if (ret) mtk_v4l2_err("pm_runtime_put_sync fail %d", ret); } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_pw_off); -void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; struct mtk_vcodec_clk *dec_clk; int ret, i; - if (vdec_dev->vdec_pdata->is_subdev_supported) { - subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { - mtk_v4l2_err("Failed to get hw dev\n"); - return; - } - pm = &subdev_dev->pm; - enable_irq(subdev_dev->dec_irq); - } else { - pm = &vdec_dev->pm; - enable_irq(vdec_dev->dec_irq); - } - dec_clk = &pm->vdec_clk; for (i = 0; i < dec_clk->clk_num; i++) { ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk); @@ -140,30 +97,119 @@ error: for (i -= 1; i >= 0; i--) clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_on); -void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +static void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm) { - struct mtk_vdec_hw_dev *subdev_dev; - struct mtk_vcodec_pm *pm; struct mtk_vcodec_clk *dec_clk; int i; + dec_clk = &pm->vdec_clk; + for (i = dec_clk->clk_num - 1; i >= 0; i--) + clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); +} + +static void mtk_vcodec_dec_enable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +{ + struct mtk_vdec_hw_dev *subdev_dev; + + if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) + return; + if (vdec_dev->vdec_pdata->is_subdev_supported) { subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); - if (!subdev_dev) { + if (subdev_dev) + enable_irq(subdev_dev->dec_irq); + else + mtk_v4l2_err("Failed to get hw dev\n"); + } else { + enable_irq(vdec_dev->dec_irq); + } +} + +static void mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_idx) +{ + struct mtk_vdec_hw_dev *subdev_dev; + + if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) + return; + + if (vdec_dev->vdec_pdata->is_subdev_supported) { + subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); + if (subdev_dev) + disable_irq(subdev_dev->dec_irq); + else mtk_v4l2_err("Failed to get hw dev\n"); - return; - } - pm = &subdev_dev->pm; - disable_irq(subdev_dev->dec_irq); } else { - pm = &vdec_dev->pm; disable_irq(vdec_dev->dec_irq); } +} - dec_clk = &pm->vdec_clk; - for (i = dec_clk->clk_num - 1; i >= 0; i--) - clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk); +static struct mtk_vcodec_pm *mtk_vcodec_dec_get_pm(struct mtk_vcodec_dev *vdec_dev, + int hw_idx) +{ + struct mtk_vdec_hw_dev *subdev_dev; + + if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) + return NULL; + + if (vdec_dev->vdec_pdata->is_subdev_supported) { + subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx); + if (subdev_dev) + return &subdev_dev->pm; + + mtk_v4l2_err("Failed to get hw dev\n"); + return NULL; + } + + return &vdec_dev->pm; +} + +static void mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dev *vdec_dev, + int hw_idx) +{ + struct mtk_vcodec_pm *pm; + + pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx); + if (pm) { + mtk_vcodec_dec_pw_on(pm); + mtk_vcodec_dec_clock_on(pm); + } +} + +static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev, + int hw_idx) +{ + struct mtk_vcodec_pm *pm; + + pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx); + if (pm) { + mtk_vcodec_dec_clock_off(pm); + mtk_vcodec_dec_pw_off(pm); + } +} + +void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) +{ + mutex_lock(&ctx->dev->dec_mutex[hw_idx]); + + if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) && + hw_idx == MTK_VDEC_CORE) + mtk_vcodec_dec_child_dev_on(ctx->dev, MTK_VDEC_LAT0); + mtk_vcodec_dec_child_dev_on(ctx->dev, hw_idx); + + mtk_vcodec_dec_enable_irq(ctx->dev, hw_idx); +} +EXPORT_SYMBOL_GPL(mtk_vcodec_dec_enable_hardware); + +void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx) +{ + mtk_vcodec_dec_disable_irq(ctx->dev, hw_idx); + + mtk_vcodec_dec_child_dev_off(ctx->dev, hw_idx); + if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) && + hw_idx == MTK_VDEC_CORE) + mtk_vcodec_dec_child_dev_off(ctx->dev, MTK_VDEC_LAT0); + + mutex_unlock(&ctx->dev->dec_mutex[hw_idx]); } -EXPORT_SYMBOL_GPL(mtk_vcodec_dec_clock_off); +EXPORT_SYMBOL_GPL(mtk_vcodec_dec_disable_hardware); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.h index 3cc721bbfaf6..dbcf3cabe6f3 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.h @@ -11,9 +11,7 @@ int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm); -int mtk_vcodec_dec_pw_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx); -void mtk_vcodec_dec_pw_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx); -void mtk_vcodec_dec_clock_on(struct mtk_vcodec_dev *vdec_dev, int hw_idx); -void mtk_vcodec_dec_clock_off(struct mtk_vcodec_dev *vdec_dev, int hw_idx); +void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx); +void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx); #endif /* _MTK_VCODEC_DEC_PM_H_ */ diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c index 04ca43c77e5f..9c7e6145cebb 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c @@ -37,7 +37,9 @@ static const struct mtk_video_fmt mtk_video_formats[] = { }, }; -#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) +static const unsigned int num_supported_formats = + ARRAY_SIZE(mtk_video_formats); + #define DEFAULT_OUT_FMT_IDX 0 #define DEFAULT_CAP_FMT_IDX 3 @@ -59,7 +61,8 @@ static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { }, }; -#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) +static const unsigned int num_supported_framesize = + ARRAY_SIZE(mtk_vdec_framesizes); /* * This function tries to clean all display buffers, the buffers will return @@ -90,11 +93,6 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) vb = &dstbuf->m2m_buf.vb; mutex_lock(&ctx->lock); if (dstbuf->used) { - vb2_set_plane_payload(&vb->vb2_buf, 0, ctx->picinfo.fb_sz[0]); - if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) - vb2_set_plane_payload(&vb->vb2_buf, 1, - ctx->picinfo.fb_sz[1]); - mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d", ctx->id, disp_frame_buffer->status, vb->vb2_buf.index, dstbuf->queued_in_vb2); @@ -235,7 +233,7 @@ static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, unsigned int k; dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; - for (k = 0; k < NUM_FORMATS; k++) { + for (k = 0; k < num_supported_formats; k++) { fmt = &mtk_video_formats[k]; if (fmt->fourcc == pixelformat) { mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)", @@ -613,16 +611,15 @@ static struct vb2_ops mtk_vdec_frame_vb2_ops = { }; const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = { - .chip = MTK_MT8173, .init_vdec_params = mtk_init_vdec_params, .ctrls_setup = mtk_vcodec_dec_ctrls_setup, .vdec_vb2_ops = &mtk_vdec_frame_vb2_ops, .vdec_formats = mtk_video_formats, - .num_formats = NUM_FORMATS, + .num_formats = &num_supported_formats, .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .num_framesizes = &num_supported_framesize, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, .is_subdev_supported = false, diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c index 23d997ac114d..16d55785d84b 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c @@ -76,69 +76,102 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = { .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, }, .codec_type = V4L2_PIX_FMT_H264_SLICE, - } -}; - -#define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) - -static const struct mtk_video_fmt mtk_video_formats[] = { + }, + { + .cfg = { + .id = V4L2_CID_STATELESS_VP8_FRAME, + }, + .codec_type = V4L2_PIX_FMT_VP8_FRAME, + }, { - .fourcc = V4L2_PIX_FMT_H264_SLICE, - .type = MTK_FMT_DEC, - .num_planes = 1, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE, + .min = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .def = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP8_PROFILE_3, + }, + .codec_type = V4L2_PIX_FMT_VP8_FRAME, }, { - .fourcc = V4L2_PIX_FMT_MM21, - .type = MTK_FMT_FRAME, - .num_planes = 2, + .cfg = { + .id = V4L2_CID_STATELESS_VP9_FRAME, + }, + .codec_type = V4L2_PIX_FMT_VP9_FRAME, }, -}; - -#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) -#define DEFAULT_OUT_FMT_IDX 0 -#define DEFAULT_CAP_FMT_IDX 1 - -static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { { - .fourcc = V4L2_PIX_FMT_H264_SLICE, - .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, - MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + .min = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .def = V4L2_MPEG_VIDEO_VP9_PROFILE_0, + .max = V4L2_MPEG_VIDEO_VP9_PROFILE_3, + }, + .codec_type = V4L2_PIX_FMT_VP9_FRAME, }, }; -#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) +#define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls) -static void mtk_vdec_stateless_set_dst_payload(struct mtk_vcodec_ctx *ctx, - struct vdec_fb *fb) +static struct mtk_video_fmt mtk_video_formats[5]; +static struct mtk_codec_framesizes mtk_vdec_framesizes[3]; + +static struct mtk_video_fmt default_out_format; +static struct mtk_video_fmt default_cap_format; +static unsigned int num_formats; +static unsigned int num_framesizes; + +static struct v4l2_frmsize_stepwise stepwise_fhd = { + .min_width = MTK_VDEC_MIN_W, + .max_width = MTK_VDEC_MAX_W, + .step_width = 16, + .min_height = MTK_VDEC_MIN_H, + .max_height = MTK_VDEC_MAX_H, + .step_height = 16 +}; + +static void mtk_vdec_stateless_cap_to_disp(struct mtk_vcodec_ctx *ctx, int error, + struct media_request *src_buf_req) { - struct mtk_video_dec_buf *vdec_frame_buf = - container_of(fb, struct mtk_video_dec_buf, frame_buffer); - struct vb2_v4l2_buffer *vb = &vdec_frame_buf->m2m_buf.vb; - unsigned int cap_y_size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; + struct vb2_v4l2_buffer *vb2_dst; + enum vb2_buffer_state state; - vb2_set_plane_payload(&vb->vb2_buf, 0, cap_y_size); - if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { - unsigned int cap_c_size = - ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]; + if (error) + state = VB2_BUF_STATE_ERROR; + else + state = VB2_BUF_STATE_DONE; - vb2_set_plane_payload(&vb->vb2_buf, 1, cap_c_size); - } + vb2_dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(vb2_dst, state); + + mtk_v4l2_debug(2, "free frame buffer id:%d to done list", + vb2_dst->vb2_buf.index); + + if (src_buf_req) + v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl); } -static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx, - struct vb2_v4l2_buffer *vb2_v4l2) +static struct vdec_fb *vdec_get_cap_buffer(struct mtk_vcodec_ctx *ctx) { - struct mtk_video_dec_buf *framebuf = - container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); - struct vdec_fb *pfb = &framebuf->frame_buffer; - struct vb2_buffer *dst_buf = &vb2_v4l2->vb2_buf; + struct mtk_video_dec_buf *framebuf; + struct vb2_v4l2_buffer *vb2_v4l2; + struct vb2_buffer *dst_buf; + struct vdec_fb *pfb; + + vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + if (!vb2_v4l2) { + mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id); + return NULL; + } + + dst_buf = &vb2_v4l2->vb2_buf; + framebuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb); - pfb->base_y.va = NULL; + pfb = &framebuf->frame_buffer; + pfb->base_y.va = vb2_plane_vaddr(dst_buf, 0); pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); pfb->base_y.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[0]; if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { - pfb->base_c.va = NULL; + pfb->base_c.va = vb2_plane_vaddr(dst_buf, 1); pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1); pfb->base_c.size = ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]; @@ -162,12 +195,12 @@ static void mtk_vdec_worker(struct work_struct *work) struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx, decode_work); struct mtk_vcodec_dev *dev = ctx->dev; - struct vb2_v4l2_buffer *vb2_v4l2_src, *vb2_v4l2_dst; + struct vb2_v4l2_buffer *vb2_v4l2_src; struct vb2_buffer *vb2_src; struct mtk_vcodec_mem *bs_src; struct mtk_video_dec_buf *dec_buf_src; struct media_request *src_buf_req; - struct vdec_fb *dst_buf; + enum vb2_buffer_state state; bool res_chg = false; int ret; @@ -178,13 +211,6 @@ static void mtk_vdec_worker(struct work_struct *work) return; } - vb2_v4l2_dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); - if (!vb2_v4l2_dst) { - v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); - mtk_v4l2_debug(1, "[%d] no available destination buffer", ctx->id); - return; - } - vb2_src = &vb2_v4l2_src->vb2_buf; dec_buf_src = container_of(vb2_v4l2_src, struct mtk_video_dec_buf, m2m_buf.vb); @@ -193,9 +219,15 @@ static void mtk_vdec_worker(struct work_struct *work) mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, vb2_src->vb2_queue->type, vb2_src->index, vb2_src); - bs_src->va = NULL; + bs_src->va = vb2_plane_vaddr(vb2_src, 0); bs_src->dma_addr = vb2_dma_contig_plane_dma_addr(vb2_src, 0); bs_src->size = (size_t)vb2_src->planes[0].bytesused; + if (!bs_src->va) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_err("[%d] id=%d source buffer is NULL", ctx->id, + vb2_src->index); + return; + } mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", ctx->id, bs_src->va, &bs_src->dma_addr, bs_src->size, vb2_src); @@ -206,9 +238,7 @@ static void mtk_vdec_worker(struct work_struct *work) else mtk_v4l2_err("vb2 buffer media request is NULL"); - dst_buf = vdec_get_cap_buffer(ctx, vb2_v4l2_dst); - v4l2_m2m_buf_copy_metadata(vb2_v4l2_src, vb2_v4l2_dst, true); - ret = vdec_if_decode(ctx, bs_src, dst_buf, &res_chg); + ret = vdec_if_decode(ctx, bs_src, NULL, &res_chg); if (ret) { mtk_v4l2_err(" <===[%d], src_buf[%d] sz=0x%zx pts=%llu vdec_if_decode() ret=%d res_chg=%d===>", ctx->id, vb2_src->index, bs_src->size, @@ -220,12 +250,17 @@ static void mtk_vdec_worker(struct work_struct *work) } } - mtk_vdec_stateless_set_dst_payload(ctx, dst_buf); - - v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx, - ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - - v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl); + state = ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE; + if (!IS_VDEC_LAT_ARCH(dev->vdec_pdata->hw_arch) || + ctx->current_codec == V4L2_PIX_FMT_VP8_FRAME || ret) { + v4l2_m2m_buf_done_and_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx, state); + if (src_buf_req) + v4l2_ctrl_request_complete(src_buf_req, &ctx->ctrl_hdl); + } else { + v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(vb2_v4l2_src, state); + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + } } static void vb2ops_vdec_stateless_buf_queue(struct vb2_buffer *vb) @@ -307,6 +342,77 @@ const struct media_device_ops mtk_vcodec_media_ops = { .req_queue = v4l2_m2m_request_queue, }; +static void mtk_vcodec_add_formats(unsigned int fourcc, + struct mtk_vcodec_ctx *ctx) +{ + struct mtk_vcodec_dev *dev = ctx->dev; + const struct mtk_vcodec_dec_pdata *pdata = dev->vdec_pdata; + int count_formats = *pdata->num_formats; + int count_framesizes = *pdata->num_framesizes; + + switch (fourcc) { + case V4L2_PIX_FMT_H264_SLICE: + case V4L2_PIX_FMT_VP8_FRAME: + case V4L2_PIX_FMT_VP9_FRAME: + mtk_video_formats[count_formats].fourcc = fourcc; + mtk_video_formats[count_formats].type = MTK_FMT_DEC; + mtk_video_formats[count_formats].num_planes = 1; + + mtk_vdec_framesizes[count_framesizes].fourcc = fourcc; + mtk_vdec_framesizes[count_framesizes].stepwise = stepwise_fhd; + num_framesizes++; + break; + case V4L2_PIX_FMT_MM21: + case V4L2_PIX_FMT_MT21C: + mtk_video_formats[count_formats].fourcc = fourcc; + mtk_video_formats[count_formats].type = MTK_FMT_FRAME; + mtk_video_formats[count_formats].num_planes = 2; + break; + default: + mtk_v4l2_err("Can not add unsupported format type"); + return; + } + + num_formats++; + mtk_v4l2_debug(3, "num_formats: %d num_frames:%d dec_capability: 0x%x", + count_formats, count_framesizes, ctx->dev->dec_capability); +} + +static void mtk_vcodec_get_supported_formats(struct mtk_vcodec_ctx *ctx) +{ + int cap_format_count = 0, out_format_count = 0; + + if (num_formats && num_framesizes) + return; + + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MM21) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_MM21, ctx); + cap_format_count++; + } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MT21C) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_MT21C, ctx); + cap_format_count++; + } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_H264_SLICE) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_H264_SLICE, ctx); + out_format_count++; + } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_VP8_FRAME) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_VP8_FRAME, ctx); + out_format_count++; + } + if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_VP9_FRAME) { + mtk_vcodec_add_formats(V4L2_PIX_FMT_VP9_FRAME, ctx); + out_format_count++; + } + + if (cap_format_count) + default_cap_format = mtk_video_formats[cap_format_count - 1]; + if (out_format_count) + default_out_format = + mtk_video_formats[cap_format_count + out_format_count - 1]; +} + static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) { struct vb2_queue *src_vq; @@ -314,6 +420,11 @@ static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx) src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (!ctx->dev->vdec_pdata->is_subdev_supported) + ctx->dev->dec_capability |= + MTK_VDEC_FORMAT_H264_SLICE | MTK_VDEC_FORMAT_MM21; + mtk_vcodec_get_supported_formats(ctx); + /* Support request api for output plane */ src_vq->supports_requests = true; src_vq->requires_requests = true; @@ -343,38 +454,59 @@ static struct vb2_ops mtk_vdec_request_vb2_ops = { }; const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = { - .chip = MTK_MT8183, .init_vdec_params = mtk_init_vdec_params, .ctrls_setup = mtk_vcodec_dec_ctrls_setup, .vdec_vb2_ops = &mtk_vdec_request_vb2_ops, .vdec_formats = mtk_video_formats, - .num_formats = NUM_FORMATS, - .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], - .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], + .num_formats = &num_formats, + .default_out_fmt = &default_out_format, + .default_cap_fmt = &default_cap_format, .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, + .cap_to_disp = mtk_vdec_stateless_cap_to_disp, + .get_cap_buffer = vdec_get_cap_buffer, .is_subdev_supported = false, .hw_arch = MTK_VDEC_PURE_SINGLE_CORE, }; /* This platform data is used for one lat and one core architecture. */ const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = { - .chip = MTK_MT8192, .init_vdec_params = mtk_init_vdec_params, .ctrls_setup = mtk_vcodec_dec_ctrls_setup, .vdec_vb2_ops = &mtk_vdec_request_vb2_ops, .vdec_formats = mtk_video_formats, - .num_formats = NUM_FORMATS, - .default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX], - .default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX], + .num_formats = &num_formats, + .default_out_fmt = &default_out_format, + .default_cap_fmt = &default_cap_format, .vdec_framesizes = mtk_vdec_framesizes, - .num_framesizes = NUM_SUPPORTED_FRAMESIZE, + .num_framesizes = &num_framesizes, .uses_stateless_api = true, .worker = mtk_vdec_worker, .flush_decoder = mtk_vdec_flush_decoder, + .cap_to_disp = mtk_vdec_stateless_cap_to_disp, + .get_cap_buffer = vdec_get_cap_buffer, .is_subdev_supported = true, .hw_arch = MTK_VDEC_LAT_SINGLE_CORE, }; + +const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = { + .init_vdec_params = mtk_init_vdec_params, + .ctrls_setup = mtk_vcodec_dec_ctrls_setup, + .vdec_vb2_ops = &mtk_vdec_request_vb2_ops, + .vdec_formats = mtk_video_formats, + .num_formats = &num_formats, + .default_out_fmt = &default_out_format, + .default_cap_fmt = &default_cap_format, + .vdec_framesizes = mtk_vdec_framesizes, + .num_framesizes = &num_framesizes, + .uses_stateless_api = true, + .worker = mtk_vdec_worker, + .flush_decoder = mtk_vdec_flush_decoder, + .cap_to_disp = mtk_vdec_stateless_cap_to_disp, + .get_cap_buffer = vdec_get_cap_buffer, + .is_subdev_supported = true, + .hw_arch = MTK_VDEC_PURE_SINGLE_CORE, +}; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h index 813901c4be5e..a29041a0b7e0 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h @@ -274,6 +274,7 @@ struct vdec_pic_info { * to be used with encoder and stateful decoder. * @is_flushing: set to true if flushing is in progress. * @current_codec: current set input codec, in V4L2 pixel format + * @capture_fourcc: capture queue type in V4L2 pixel format * * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding @@ -284,6 +285,8 @@ struct vdec_pic_info { * mtk_video_dec_buf. * @hw_id: hardware index used to identify different hardware. * + * @max_width: hardware supported max width + * @max_height: hardware supported max height * @msg_queue: msg queue used to store lat buffer information. */ struct mtk_vcodec_ctx { @@ -319,6 +322,7 @@ struct mtk_vcodec_ctx { bool is_flushing; u32 current_codec; + u32 capture_fourcc; enum v4l2_colorspace colorspace; enum v4l2_ycbcr_encoding ycbcr_enc; @@ -329,16 +333,11 @@ struct mtk_vcodec_ctx { struct mutex lock; int hw_id; + unsigned int max_width; + unsigned int max_height; struct vdec_msg_queue msg_queue; }; -enum mtk_chip { - MTK_MT8173, - MTK_MT8183, - MTK_MT8192, - MTK_MT8195, -}; - /* * enum mtk_vdec_hw_arch - Used to separate different hardware architecture */ @@ -347,13 +346,26 @@ enum mtk_vdec_hw_arch { MTK_VDEC_LAT_SINGLE_CORE, }; +/* + * struct mtk_vdec_format_types - Structure used to get supported + * format types according to decoder capability + */ +enum mtk_vdec_format_types { + MTK_VDEC_FORMAT_MM21 = 0x20, + MTK_VDEC_FORMAT_MT21C = 0x40, + MTK_VDEC_FORMAT_H264_SLICE = 0x100, + MTK_VDEC_FORMAT_VP8_FRAME = 0x200, + MTK_VDEC_FORMAT_VP9_FRAME = 0x400, +}; + /** * struct mtk_vcodec_dec_pdata - compatible data for each IC * @init_vdec_params: init vdec params * @ctrls_setup: init vcodec dec ctrls * @worker: worker to start a decode job * @flush_decoder: function that flushes the decoder - * + * @get_cap_buffer: get capture buffer from capture queue + * @cap_to_disp: put capture buffer to disp list for lat and core arch * @vdec_vb2_ops: struct vb2_ops * * @vdec_formats: supported video decoder formats @@ -364,7 +376,6 @@ enum mtk_vdec_hw_arch { * @vdec_framesizes: supported video decoder frame sizes * @num_framesizes: count of video decoder frame sizes * - * @chip: chip this decoder is compatible with * @hw_arch: hardware arch is used to separate pure_sin_core and lat_sin_core * * @is_subdev_supported: whether support parent-node architecture(subdev) @@ -376,18 +387,20 @@ struct mtk_vcodec_dec_pdata { int (*ctrls_setup)(struct mtk_vcodec_ctx *ctx); void (*worker)(struct work_struct *work); int (*flush_decoder)(struct mtk_vcodec_ctx *ctx); + struct vdec_fb *(*get_cap_buffer)(struct mtk_vcodec_ctx *ctx); + void (*cap_to_disp)(struct mtk_vcodec_ctx *ctx, int error, + struct media_request *src_buf_req); struct vb2_ops *vdec_vb2_ops; const struct mtk_video_fmt *vdec_formats; - const int num_formats; + const int *num_formats; const struct mtk_video_fmt *default_out_fmt; const struct mtk_video_fmt *default_cap_fmt; const struct mtk_codec_framesizes *vdec_framesizes; - const int num_framesizes; + const int *num_framesizes; - enum mtk_chip chip; enum mtk_vdec_hw_arch hw_arch; bool is_subdev_supported; @@ -397,8 +410,6 @@ struct mtk_vcodec_dec_pdata { /** * struct mtk_vcodec_enc_pdata - compatible data for each IC * - * @chip: chip this encoder is compatible with - * * @uses_ext: whether the encoder uses the extended firmware messaging format * @min_bitrate: minimum supported encoding bitrate * @max_bitrate: maximum supported encoding bitrate @@ -409,8 +420,6 @@ struct mtk_vcodec_dec_pdata { * @core_id: stand for h264 or vp8 encode index */ struct mtk_vcodec_enc_pdata { - enum mtk_chip chip; - bool uses_ext; unsigned long min_bitrate; unsigned long max_bitrate; diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c index 5172cfe0db4a..95e8c29ccc65 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc_drv.c @@ -376,7 +376,6 @@ err_enc_pm: } static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = { - .chip = MTK_MT8173, .capture_formats = mtk_video_formats_capture_h264, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), .output_formats = mtk_video_formats_output, @@ -387,7 +386,6 @@ static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = { }; static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = { - .chip = MTK_MT8173, .capture_formats = mtk_video_formats_capture_vp8, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_vp8), .output_formats = mtk_video_formats_output, @@ -398,7 +396,6 @@ static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = { }; static const struct mtk_vcodec_enc_pdata mt8183_pdata = { - .chip = MTK_MT8183, .uses_ext = true, .capture_formats = mtk_video_formats_capture_h264, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), @@ -410,7 +407,6 @@ static const struct mtk_vcodec_enc_pdata mt8183_pdata = { }; static const struct mtk_vcodec_enc_pdata mt8192_pdata = { - .chip = MTK_MT8192, .uses_ext = true, .capture_formats = mtk_video_formats_capture_h264, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), @@ -422,7 +418,6 @@ static const struct mtk_vcodec_enc_pdata mt8192_pdata = { }; static const struct mtk_vcodec_enc_pdata mt8195_pdata = { - .chip = MTK_MT8195, .uses_ext = true, .capture_formats = mtk_video_formats_capture_h264, .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.c index 94b39ae5c2e1..556e54aadac9 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.c +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.c @@ -65,3 +65,9 @@ int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, return fw->ops->ipi_send(fw, id, buf, len, wait); } EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_send); + +int mtk_vcodec_fw_get_type(struct mtk_vcodec_fw *fw) +{ + return fw->type; +} +EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_type); diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.h index 15ab6b8e3ae2..16824114657f 100644 --- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.h +++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_fw.h @@ -39,5 +39,6 @@ int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id, const char *name, void *priv); int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf, unsigned int len, unsigned int wait); +int mtk_vcodec_fw_get_type(struct mtk_vcodec_fw *fw); #endif /* _MTK_VCODEC_FW_H_ */ diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c new file mode 100644 index 000000000000..ca628321d272 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Yunfei Dong <yunfei.dong@mediatek.com> + */ + +#include "vdec_h264_req_common.h" + +/* get used parameters for sps/pps */ +#define GET_MTK_VDEC_FLAG(cond, flag) \ + { dst_param->cond = ((src_param->flags & flag) ? (1) : (0)); } +#define GET_MTK_VDEC_PARAM(param) \ + { dst_param->param = src_param->param; } + +void mtk_vdec_h264_get_ref_list(u8 *ref_list, + const struct v4l2_h264_reference *v4l2_ref_list, + int num_valid) +{ + u32 i; + + /* + * TODO The firmware does not support field decoding. Future + * implementation must use v4l2_ref_list[i].fields to obtain + * the reference field parity. + */ + + for (i = 0; i < num_valid; i++) + ref_list[i] = v4l2_ref_list[i].index; + + /* + * The firmware expects unused reflist entries to have the value 0x20. + */ + memset(&ref_list[num_valid], 0x20, 32 - num_valid); +} + +void *mtk_vdec_h264_get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id); + + if (!ctrl) + return ERR_PTR(-EINVAL); + + return ctrl->p_cur.p; +} + +void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, + struct slice_api_h264_decode_param *decode_params, + struct mtk_h264_dpb_info *h264_dpb_info) +{ + const struct slice_h264_dpb_entry *dpb; + struct vb2_queue *vq; + struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vb2_v4l2; + int index, vb2_index; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + + for (index = 0; index < V4L2_H264_NUM_DPB_ENTRIES; index++) { + dpb = &decode_params->dpb[index]; + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) { + h264_dpb_info[index].reference_flag = 0; + continue; + } + + vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0); + if (vb2_index < 0) { + dev_err(&ctx->dev->plat_dev->dev, + "Reference invalid: dpb_index(%d) reference_ts(%lld)", + index, dpb->reference_ts); + continue; + } + + /* 1 for short term reference, 2 for long term reference */ + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) + h264_dpb_info[index].reference_flag = 1; + else + h264_dpb_info[index].reference_flag = 2; + + vb = vq->bufs[vb2_index]; + vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); + h264_dpb_info[index].field = vb2_v4l2->field; + + h264_dpb_info[index].y_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + h264_dpb_info[index].c_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 1); + else + h264_dpb_info[index].c_dma_addr = + h264_dpb_info[index].y_dma_addr + + ctx->picinfo.fb_sz[0]; + } +} + +void mtk_vdec_h264_copy_sps_params(struct mtk_h264_sps_param *dst_param, + const struct v4l2_ctrl_h264_sps *src_param) +{ + GET_MTK_VDEC_PARAM(chroma_format_idc); + GET_MTK_VDEC_PARAM(bit_depth_luma_minus8); + GET_MTK_VDEC_PARAM(bit_depth_chroma_minus8); + GET_MTK_VDEC_PARAM(log2_max_frame_num_minus4); + GET_MTK_VDEC_PARAM(pic_order_cnt_type); + GET_MTK_VDEC_PARAM(log2_max_pic_order_cnt_lsb_minus4); + GET_MTK_VDEC_PARAM(max_num_ref_frames); + GET_MTK_VDEC_PARAM(pic_width_in_mbs_minus1); + GET_MTK_VDEC_PARAM(pic_height_in_map_units_minus1); + + GET_MTK_VDEC_FLAG(separate_colour_plane_flag, + V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE); + GET_MTK_VDEC_FLAG(qpprime_y_zero_transform_bypass_flag, + V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS); + GET_MTK_VDEC_FLAG(delta_pic_order_always_zero_flag, + V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); + GET_MTK_VDEC_FLAG(frame_mbs_only_flag, + V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); + GET_MTK_VDEC_FLAG(mb_adaptive_frame_field_flag, + V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); + GET_MTK_VDEC_FLAG(direct_8x8_inference_flag, + V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); +} + +void mtk_vdec_h264_copy_pps_params(struct mtk_h264_pps_param *dst_param, + const struct v4l2_ctrl_h264_pps *src_param) +{ + GET_MTK_VDEC_PARAM(num_ref_idx_l0_default_active_minus1); + GET_MTK_VDEC_PARAM(num_ref_idx_l1_default_active_minus1); + GET_MTK_VDEC_PARAM(weighted_bipred_idc); + GET_MTK_VDEC_PARAM(pic_init_qp_minus26); + GET_MTK_VDEC_PARAM(chroma_qp_index_offset); + GET_MTK_VDEC_PARAM(second_chroma_qp_index_offset); + + GET_MTK_VDEC_FLAG(entropy_coding_mode_flag, + V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); + GET_MTK_VDEC_FLAG(pic_order_present_flag, + V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); + GET_MTK_VDEC_FLAG(weighted_pred_flag, + V4L2_H264_PPS_FLAG_WEIGHTED_PRED); + GET_MTK_VDEC_FLAG(deblocking_filter_control_present_flag, + V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); + GET_MTK_VDEC_FLAG(constrained_intra_pred_flag, + V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); + GET_MTK_VDEC_FLAG(redundant_pic_cnt_present_flag, + V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); + GET_MTK_VDEC_FLAG(transform_8x8_mode_flag, + V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); + GET_MTK_VDEC_FLAG(scaling_matrix_present_flag, + V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); +} + +void mtk_vdec_h264_copy_slice_hd_params(struct mtk_h264_slice_hd_param *dst_param, + const struct v4l2_ctrl_h264_slice_params *src_param, + const struct v4l2_ctrl_h264_decode_params *dec_param) +{ + int temp; + + GET_MTK_VDEC_PARAM(first_mb_in_slice); + GET_MTK_VDEC_PARAM(slice_type); + GET_MTK_VDEC_PARAM(cabac_init_idc); + GET_MTK_VDEC_PARAM(slice_qp_delta); + GET_MTK_VDEC_PARAM(disable_deblocking_filter_idc); + GET_MTK_VDEC_PARAM(slice_alpha_c0_offset_div2); + GET_MTK_VDEC_PARAM(slice_beta_offset_div2); + GET_MTK_VDEC_PARAM(num_ref_idx_l0_active_minus1); + GET_MTK_VDEC_PARAM(num_ref_idx_l1_active_minus1); + + dst_param->frame_num = dec_param->frame_num; + dst_param->pic_order_cnt_lsb = dec_param->pic_order_cnt_lsb; + + dst_param->delta_pic_order_cnt_bottom = + dec_param->delta_pic_order_cnt_bottom; + dst_param->delta_pic_order_cnt0 = + dec_param->delta_pic_order_cnt0; + dst_param->delta_pic_order_cnt1 = + dec_param->delta_pic_order_cnt1; + + temp = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC; + dst_param->field_pic_flag = temp ? 1 : 0; + + temp = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD; + dst_param->bottom_field_flag = temp ? 1 : 0; + + GET_MTK_VDEC_FLAG(direct_spatial_mv_pred_flag, + V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED); +} + +void mtk_vdec_h264_copy_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix, + const struct v4l2_ctrl_h264_scaling_matrix *src_matrix) +{ + memcpy(dst_matrix->scaling_list_4x4, src_matrix->scaling_list_4x4, + sizeof(dst_matrix->scaling_list_4x4)); + + memcpy(dst_matrix->scaling_list_8x8, src_matrix->scaling_list_8x8, + sizeof(dst_matrix->scaling_list_8x8)); +} + +void +mtk_vdec_h264_copy_decode_params(struct slice_api_h264_decode_param *dst_params, + const struct v4l2_ctrl_h264_decode_params *src_params, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) +{ + struct slice_h264_dpb_entry *dst_entry; + const struct v4l2_h264_dpb_entry *src_entry; + int i; + + for (i = 0; i < ARRAY_SIZE(dst_params->dpb); i++) { + dst_entry = &dst_params->dpb[i]; + src_entry = &dpb[i]; + + dst_entry->reference_ts = src_entry->reference_ts; + dst_entry->frame_num = src_entry->frame_num; + dst_entry->pic_num = src_entry->pic_num; + dst_entry->top_field_order_cnt = src_entry->top_field_order_cnt; + dst_entry->bottom_field_order_cnt = + src_entry->bottom_field_order_cnt; + dst_entry->flags = src_entry->flags; + } + + /* num_slices is a leftover from the old H.264 support and is ignored + * by the firmware. + */ + dst_params->num_slices = 0; + dst_params->nal_ref_idc = src_params->nal_ref_idc; + dst_params->top_field_order_cnt = src_params->top_field_order_cnt; + dst_params->bottom_field_order_cnt = src_params->bottom_field_order_cnt; + dst_params->flags = src_params->flags; +} + +static bool mtk_vdec_h264_dpb_entry_match(const struct v4l2_h264_dpb_entry *a, + const struct v4l2_h264_dpb_entry *b) +{ + return a->top_field_order_cnt == b->top_field_order_cnt && + a->bottom_field_order_cnt == b->bottom_field_order_cnt; +} + +/* + * Move DPB entries of dec_param that refer to a frame already existing in dpb + * into the already existing slot in dpb, and move other entries into new slots. + * + * This function is an adaptation of the similarly-named function in + * hantro_h264.c. + */ +void mtk_vdec_h264_update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param, + struct v4l2_h264_dpb_entry *dpb) +{ + DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(in_use, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, }; + unsigned int i, j; + + /* Disable all entries by default, and mark the ones in use. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + set_bit(i, in_use); + dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; + } + + /* Try to match new DPB entries with existing ones by their POCs. */ + for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + + if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + /* + * To cut off some comparisons, iterate only on target DPB + * entries were already used. + */ + for_each_set_bit(j, in_use, ARRAY_SIZE(dec_param->dpb)) { + struct v4l2_h264_dpb_entry *cdpb; + + cdpb = &dpb[j]; + if (!mtk_vdec_h264_dpb_entry_match(cdpb, ndpb)) + continue; + + *cdpb = *ndpb; + set_bit(j, used); + /* Don't reiterate on this one. */ + clear_bit(j, in_use); + break; + } + + if (j == ARRAY_SIZE(dec_param->dpb)) + set_bit(i, new); + } + + /* For entries that could not be matched, use remaining free slots. */ + for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { + const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; + struct v4l2_h264_dpb_entry *cdpb; + + /* + * Both arrays are of the same sizes, so there is no way + * we can end up with no space in target array, unless + * something is buggy. + */ + j = find_first_zero_bit(used, ARRAY_SIZE(dec_param->dpb)); + if (WARN_ON(j >= ARRAY_SIZE(dec_param->dpb))) + return; + + cdpb = &dpb[j]; + *cdpb = *ndpb; + set_bit(j, used); + } +} + +unsigned int mtk_vdec_h264_get_mv_buf_size(unsigned int width, unsigned int height) +{ + int unit_size = (width / MB_UNIT_LEN) * (height / MB_UNIT_LEN) + 8; + + return HW_MB_STORE_SZ * unit_size; +} + +int mtk_vdec_h264_find_start_code(unsigned char *data, unsigned int data_sz) +{ + if (data_sz > 3 && data[0] == 0 && data[1] == 0 && data[2] == 1) + return 3; + + if (data_sz > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 && + data[3] == 1) + return 4; + + return -1; +} diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.h b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.h new file mode 100644 index 000000000000..53d0a7c962a9 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.h @@ -0,0 +1,277 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Yunfei Dong <yunfei.dong@mediatek.com> + */ + +#ifndef _VDEC_H264_REQ_COMMON_H_ +#define _VDEC_H264_REQ_COMMON_H_ + +#include <linux/module.h> +#include <linux/slab.h> +#include <media/v4l2-h264.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> + +#include "../mtk_vcodec_drv.h" + +#define NAL_NON_IDR_SLICE 0x01 +#define NAL_IDR_SLICE 0x05 +#define NAL_TYPE(value) ((value) & 0x1F) + +#define BUF_PREDICTION_SZ (64 * 4096) +#define MB_UNIT_LEN 16 + +/* motion vector size (bytes) for every macro block */ +#define HW_MB_STORE_SZ 64 + +#define H264_MAX_MV_NUM 32 + +/** + * struct mtk_h264_dpb_info - h264 dpb information + * + * @y_dma_addr: Y bitstream physical address + * @c_dma_addr: CbCr bitstream physical address + * @reference_flag: reference picture flag (short/long term reference picture) + * @field: field picture flag + */ +struct mtk_h264_dpb_info { + dma_addr_t y_dma_addr; + dma_addr_t c_dma_addr; + int reference_flag; + int field; +}; + +/* + * struct mtk_h264_sps_param - parameters for sps + */ +struct mtk_h264_sps_param { + unsigned char chroma_format_idc; + unsigned char bit_depth_luma_minus8; + unsigned char bit_depth_chroma_minus8; + unsigned char log2_max_frame_num_minus4; + unsigned char pic_order_cnt_type; + unsigned char log2_max_pic_order_cnt_lsb_minus4; + unsigned char max_num_ref_frames; + unsigned char separate_colour_plane_flag; + unsigned short pic_width_in_mbs_minus1; + unsigned short pic_height_in_map_units_minus1; + unsigned int max_frame_nums; + unsigned char qpprime_y_zero_transform_bypass_flag; + unsigned char delta_pic_order_always_zero_flag; + unsigned char frame_mbs_only_flag; + unsigned char mb_adaptive_frame_field_flag; + unsigned char direct_8x8_inference_flag; + unsigned char reserved[3]; +}; + +/* + * struct mtk_h264_pps_param - parameters for pps + */ +struct mtk_h264_pps_param { + unsigned char num_ref_idx_l0_default_active_minus1; + unsigned char num_ref_idx_l1_default_active_minus1; + unsigned char weighted_bipred_idc; + char pic_init_qp_minus26; + char chroma_qp_index_offset; + char second_chroma_qp_index_offset; + unsigned char entropy_coding_mode_flag; + unsigned char pic_order_present_flag; + unsigned char deblocking_filter_control_present_flag; + unsigned char constrained_intra_pred_flag; + unsigned char weighted_pred_flag; + unsigned char redundant_pic_cnt_present_flag; + unsigned char transform_8x8_mode_flag; + unsigned char scaling_matrix_present_flag; + unsigned char reserved[2]; +}; + +/* + * struct mtk_h264_slice_hd_param - parameters for slice header + */ +struct mtk_h264_slice_hd_param { + unsigned int first_mb_in_slice; + unsigned int field_pic_flag; + unsigned int slice_type; + unsigned int frame_num; + int pic_order_cnt_lsb; + int delta_pic_order_cnt_bottom; + unsigned int bottom_field_flag; + unsigned int direct_spatial_mv_pred_flag; + int delta_pic_order_cnt0; + int delta_pic_order_cnt1; + unsigned int cabac_init_idc; + int slice_qp_delta; + unsigned int disable_deblocking_filter_idc; + int slice_alpha_c0_offset_div2; + int slice_beta_offset_div2; + unsigned int num_ref_idx_l0_active_minus1; + unsigned int num_ref_idx_l1_active_minus1; + unsigned int reserved; +}; + +/* + * struct slice_api_h264_scaling_matrix - parameters for scaling list + */ +struct slice_api_h264_scaling_matrix { + unsigned char scaling_list_4x4[6][16]; + unsigned char scaling_list_8x8[6][64]; +}; + +/* + * struct slice_h264_dpb_entry - each dpb information + */ +struct slice_h264_dpb_entry { + unsigned long long reference_ts; + unsigned short frame_num; + unsigned short pic_num; + /* Note that field is indicated by v4l2_buffer.field */ + int top_field_order_cnt; + int bottom_field_order_cnt; + unsigned int flags; +}; + +/* + * struct slice_api_h264_decode_param - parameters for decode. + */ +struct slice_api_h264_decode_param { + struct slice_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; + unsigned short num_slices; + unsigned short nal_ref_idc; + unsigned char ref_pic_list_p0[32]; + unsigned char ref_pic_list_b0[32]; + unsigned char ref_pic_list_b1[32]; + int top_field_order_cnt; + int bottom_field_order_cnt; + unsigned int flags; +}; + +/** + * struct h264_fb - h264 decode frame buffer information + * + * @vdec_fb_va: virtual address of struct vdec_fb + * @y_fb_dma: dma address of Y frame buffer (luma) + * @c_fb_dma: dma address of C frame buffer (chroma) + * @poc: picture order count of frame buffer + * @reserved: for 8 bytes alignment + */ +struct h264_fb { + u64 vdec_fb_va; + u64 y_fb_dma; + u64 c_fb_dma; + s32 poc; + u32 reserved; +}; + +/** + * mtk_vdec_h264_get_ref_list - translate V4L2 reference list + * + * @ref_list: Mediatek reference picture list + * @v4l2_ref_list: V4L2 reference picture list + * @num_valid: used reference number + */ +void mtk_vdec_h264_get_ref_list(u8 *ref_list, + const struct v4l2_h264_reference *v4l2_ref_list, + int num_valid); + +/** + * mtk_vdec_h264_get_ctrl_ptr - get each CID contrl address. + * + * @ctx: v4l2 ctx + * @id: CID control ID + * + * Return: returns CID ctrl address. + */ +void *mtk_vdec_h264_get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id); + +/** + * mtk_vdec_h264_fill_dpb_info - get each CID contrl address. + * + * @ctx: v4l2 ctx + * @decode_params: slice decode params + * @h264_dpb_info: dpb buffer information + */ +void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx, + struct slice_api_h264_decode_param *decode_params, + struct mtk_h264_dpb_info *h264_dpb_info); + +/** + * mtk_vdec_h264_copy_sps_params - get sps params. + * + * @dst_param: sps params for hw decoder + * @src_param: sps params from user driver + */ +void mtk_vdec_h264_copy_sps_params(struct mtk_h264_sps_param *dst_param, + const struct v4l2_ctrl_h264_sps *src_param); + +/** + * mtk_vdec_h264_copy_pps_params - get pps params. + * + * @dst_param: pps params for hw decoder + * @src_param: pps params from user driver + */ +void mtk_vdec_h264_copy_pps_params(struct mtk_h264_pps_param *dst_param, + const struct v4l2_ctrl_h264_pps *src_param); + +/** + * mtk_vdec_h264_copy_slice_hd_params - get slice header params. + * + * @dst_param: slice params for hw decoder + * @src_param: slice params from user driver + * @dec_param: decode params from user driver + */ +void mtk_vdec_h264_copy_slice_hd_params(struct mtk_h264_slice_hd_param *dst_param, + const struct v4l2_ctrl_h264_slice_params *src_param, + const struct v4l2_ctrl_h264_decode_params *dec_param); + +/** + * mtk_vdec_h264_copy_scaling_matrix - get each CID contrl address. + * + * @dst_matrix: scaling list params for hw decoder + * @src_matrix: scaling list params from user driver + */ +void mtk_vdec_h264_copy_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix, + const struct v4l2_ctrl_h264_scaling_matrix *src_matrix); + +/** + * mtk_vdec_h264_copy_decode_params - get decode params. + * + * @dst_params: dst params for hw decoder + * @src_params: decode params from user driver + * @dpb: dpb information + */ +void +mtk_vdec_h264_copy_decode_params(struct slice_api_h264_decode_param *dst_params, + const struct v4l2_ctrl_h264_decode_params *src_params, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]); + +/** + * mtk_vdec_h264_update_dpb - updata dpb list. + * + * @dec_param: v4l2 control decode params + * @dpb: dpb entry informaton + */ +void mtk_vdec_h264_update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param, + struct v4l2_h264_dpb_entry *dpb); + +/** + * mtk_vdec_h264_find_start_code - find h264 start code using sofeware. + * + * @data: input buffer address + * @data_sz: input buffer size + * + * Return: returns start code position. + */ +int mtk_vdec_h264_find_start_code(unsigned char *data, unsigned int data_sz); + +/** + * mtk_vdec_h264_get_mv_buf_size - get mv buffer size. + * + * @width: picture width + * @height: picture height + * + * Return: returns mv buffer size. + */ +unsigned int mtk_vdec_h264_get_mv_buf_size(unsigned int width, unsigned int height); + +#endif diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_if.c index 43542de11e9c..4bc05ab5afea 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_if.c @@ -12,109 +12,7 @@ #include "../vdec_drv_base.h" #include "../vdec_drv_if.h" #include "../vdec_vpu_if.h" - -#define BUF_PREDICTION_SZ (64 * 4096) -#define MB_UNIT_LEN 16 - -/* get used parameters for sps/pps */ -#define GET_MTK_VDEC_FLAG(cond, flag) \ - { dst_param->cond = ((src_param->flags & (flag)) ? (1) : (0)); } -#define GET_MTK_VDEC_PARAM(param) \ - { dst_param->param = src_param->param; } -/* motion vector size (bytes) for every macro block */ -#define HW_MB_STORE_SZ 64 - -#define H264_MAX_FB_NUM 17 -#define H264_MAX_MV_NUM 32 -#define HDR_PARSING_BUF_SZ 1024 - -/** - * struct mtk_h264_dpb_info - h264 dpb information - * @y_dma_addr: Y bitstream physical address - * @c_dma_addr: CbCr bitstream physical address - * @reference_flag: reference picture flag (short/long term reference picture) - * @field: field picture flag - */ -struct mtk_h264_dpb_info { - dma_addr_t y_dma_addr; - dma_addr_t c_dma_addr; - int reference_flag; - int field; -}; - -/* - * struct mtk_h264_sps_param - parameters for sps - */ -struct mtk_h264_sps_param { - unsigned char chroma_format_idc; - unsigned char bit_depth_luma_minus8; - unsigned char bit_depth_chroma_minus8; - unsigned char log2_max_frame_num_minus4; - unsigned char pic_order_cnt_type; - unsigned char log2_max_pic_order_cnt_lsb_minus4; - unsigned char max_num_ref_frames; - unsigned char separate_colour_plane_flag; - unsigned short pic_width_in_mbs_minus1; - unsigned short pic_height_in_map_units_minus1; - unsigned int max_frame_nums; - unsigned char qpprime_y_zero_transform_bypass_flag; - unsigned char delta_pic_order_always_zero_flag; - unsigned char frame_mbs_only_flag; - unsigned char mb_adaptive_frame_field_flag; - unsigned char direct_8x8_inference_flag; - unsigned char reserved[3]; -}; - -/* - * struct mtk_h264_pps_param - parameters for pps - */ -struct mtk_h264_pps_param { - unsigned char num_ref_idx_l0_default_active_minus1; - unsigned char num_ref_idx_l1_default_active_minus1; - unsigned char weighted_bipred_idc; - char pic_init_qp_minus26; - char chroma_qp_index_offset; - char second_chroma_qp_index_offset; - unsigned char entropy_coding_mode_flag; - unsigned char pic_order_present_flag; - unsigned char deblocking_filter_control_present_flag; - unsigned char constrained_intra_pred_flag; - unsigned char weighted_pred_flag; - unsigned char redundant_pic_cnt_present_flag; - unsigned char transform_8x8_mode_flag; - unsigned char scaling_matrix_present_flag; - unsigned char reserved[2]; -}; - -struct slice_api_h264_scaling_matrix { - unsigned char scaling_list_4x4[6][16]; - unsigned char scaling_list_8x8[6][64]; -}; - -struct slice_h264_dpb_entry { - unsigned long long reference_ts; - unsigned short frame_num; - unsigned short pic_num; - /* Note that field is indicated by v4l2_buffer.field */ - int top_field_order_cnt; - int bottom_field_order_cnt; - unsigned int flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ -}; - -/* - * struct slice_api_h264_decode_param - parameters for decode. - */ -struct slice_api_h264_decode_param { - struct slice_h264_dpb_entry dpb[16]; - unsigned short num_slices; - unsigned short nal_ref_idc; - unsigned char ref_pic_list_p0[32]; - unsigned char ref_pic_list_b0[32]; - unsigned char ref_pic_list_b1[32]; - int top_field_order_cnt; - int bottom_field_order_cnt; - unsigned int flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ -}; +#include "vdec_h264_req_common.h" /* * struct mtk_h264_dec_slice_param - parameters for decode current frame @@ -128,22 +26,6 @@ struct mtk_h264_dec_slice_param { }; /** - * struct h264_fb - h264 decode frame buffer information - * @vdec_fb_va : virtual address of struct vdec_fb - * @y_fb_dma : dma address of Y frame buffer (luma) - * @c_fb_dma : dma address of C frame buffer (chroma) - * @poc : picture order count of frame buffer - * @reserved : for 8 bytes alignment - */ -struct h264_fb { - u64 vdec_fb_va; - u64 y_fb_dma; - u64 c_fb_dma; - s32 poc; - u32 reserved; -}; - -/** * struct vdec_h264_dec_info - decode information * @dpb_sz : decoding picture buffer size * @resolution_changed : resoltion change happen @@ -212,285 +94,65 @@ struct vdec_h264_slice_inst { struct v4l2_h264_dpb_entry dpb[16]; }; -static void *get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id) -{ - struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id); - - return ctrl->p_cur.p; -} - -static void get_h264_dpb_list(struct vdec_h264_slice_inst *inst, - struct mtk_h264_dec_slice_param *slice_param) -{ - struct vb2_queue *vq; - struct vb2_buffer *vb; - struct vb2_v4l2_buffer *vb2_v4l2; - u64 index; - - vq = v4l2_m2m_get_vq(inst->ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - - for (index = 0; index < ARRAY_SIZE(slice_param->decode_params.dpb); index++) { - const struct slice_h264_dpb_entry *dpb; - int vb2_index; - - dpb = &slice_param->decode_params.dpb[index]; - if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) { - slice_param->h264_dpb_info[index].reference_flag = 0; - continue; - } - - vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0); - if (vb2_index < 0) { - mtk_vcodec_err(inst, "Reference invalid: dpb_index(%lld) reference_ts(%lld)", - index, dpb->reference_ts); - continue; - } - /* 1 for short term reference, 2 for long term reference */ - if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM)) - slice_param->h264_dpb_info[index].reference_flag = 1; - else - slice_param->h264_dpb_info[index].reference_flag = 2; - - vb = vq->bufs[vb2_index]; - vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); - slice_param->h264_dpb_info[index].field = vb2_v4l2->field; - - slice_param->h264_dpb_info[index].y_dma_addr = - vb2_dma_contig_plane_dma_addr(vb, 0); - if (inst->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) { - slice_param->h264_dpb_info[index].c_dma_addr = - vb2_dma_contig_plane_dma_addr(vb, 1); - } - } -} - -static void get_h264_sps_parameters(struct mtk_h264_sps_param *dst_param, - const struct v4l2_ctrl_h264_sps *src_param) -{ - GET_MTK_VDEC_PARAM(chroma_format_idc); - GET_MTK_VDEC_PARAM(bit_depth_luma_minus8); - GET_MTK_VDEC_PARAM(bit_depth_chroma_minus8); - GET_MTK_VDEC_PARAM(log2_max_frame_num_minus4); - GET_MTK_VDEC_PARAM(pic_order_cnt_type); - GET_MTK_VDEC_PARAM(log2_max_pic_order_cnt_lsb_minus4); - GET_MTK_VDEC_PARAM(max_num_ref_frames); - GET_MTK_VDEC_PARAM(pic_width_in_mbs_minus1); - GET_MTK_VDEC_PARAM(pic_height_in_map_units_minus1); - - GET_MTK_VDEC_FLAG(separate_colour_plane_flag, - V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE); - GET_MTK_VDEC_FLAG(qpprime_y_zero_transform_bypass_flag, - V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS); - GET_MTK_VDEC_FLAG(delta_pic_order_always_zero_flag, - V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO); - GET_MTK_VDEC_FLAG(frame_mbs_only_flag, - V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY); - GET_MTK_VDEC_FLAG(mb_adaptive_frame_field_flag, - V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD); - GET_MTK_VDEC_FLAG(direct_8x8_inference_flag, - V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE); -} - -static void get_h264_pps_parameters(struct mtk_h264_pps_param *dst_param, - const struct v4l2_ctrl_h264_pps *src_param) -{ - GET_MTK_VDEC_PARAM(num_ref_idx_l0_default_active_minus1); - GET_MTK_VDEC_PARAM(num_ref_idx_l1_default_active_minus1); - GET_MTK_VDEC_PARAM(weighted_bipred_idc); - GET_MTK_VDEC_PARAM(pic_init_qp_minus26); - GET_MTK_VDEC_PARAM(chroma_qp_index_offset); - GET_MTK_VDEC_PARAM(second_chroma_qp_index_offset); - - GET_MTK_VDEC_FLAG(entropy_coding_mode_flag, - V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE); - GET_MTK_VDEC_FLAG(pic_order_present_flag, - V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT); - GET_MTK_VDEC_FLAG(weighted_pred_flag, - V4L2_H264_PPS_FLAG_WEIGHTED_PRED); - GET_MTK_VDEC_FLAG(deblocking_filter_control_present_flag, - V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT); - GET_MTK_VDEC_FLAG(constrained_intra_pred_flag, - V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED); - GET_MTK_VDEC_FLAG(redundant_pic_cnt_present_flag, - V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT); - GET_MTK_VDEC_FLAG(transform_8x8_mode_flag, - V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE); - GET_MTK_VDEC_FLAG(scaling_matrix_present_flag, - V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); -} - -static void -get_h264_scaling_matrix(struct slice_api_h264_scaling_matrix *dst_matrix, - const struct v4l2_ctrl_h264_scaling_matrix *src_matrix) +static int get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst) { - memcpy(dst_matrix->scaling_list_4x4, src_matrix->scaling_list_4x4, - sizeof(dst_matrix->scaling_list_4x4)); - - memcpy(dst_matrix->scaling_list_8x8, src_matrix->scaling_list_8x8, - sizeof(dst_matrix->scaling_list_8x8)); -} - -static void -get_h264_decode_parameters(struct slice_api_h264_decode_param *dst_params, - const struct v4l2_ctrl_h264_decode_params *src_params, - const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dst_params->dpb); i++) { - struct slice_h264_dpb_entry *dst_entry = &dst_params->dpb[i]; - const struct v4l2_h264_dpb_entry *src_entry = &dpb[i]; - - dst_entry->reference_ts = src_entry->reference_ts; - dst_entry->frame_num = src_entry->frame_num; - dst_entry->pic_num = src_entry->pic_num; - dst_entry->top_field_order_cnt = src_entry->top_field_order_cnt; - dst_entry->bottom_field_order_cnt = - src_entry->bottom_field_order_cnt; - dst_entry->flags = src_entry->flags; - } - - /* - * num_slices is a leftover from the old H.264 support and is ignored - * by the firmware. - */ - dst_params->num_slices = 0; - dst_params->nal_ref_idc = src_params->nal_ref_idc; - dst_params->top_field_order_cnt = src_params->top_field_order_cnt; - dst_params->bottom_field_order_cnt = src_params->bottom_field_order_cnt; - dst_params->flags = src_params->flags; -} - -static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, - const struct v4l2_h264_dpb_entry *b) -{ - return a->top_field_order_cnt == b->top_field_order_cnt && - a->bottom_field_order_cnt == b->bottom_field_order_cnt; -} - -/* - * Move DPB entries of dec_param that refer to a frame already existing in dpb - * into the already existing slot in dpb, and move other entries into new slots. - * - * This function is an adaptation of the similarly-named function in - * hantro_h264.c. - */ -static void update_dpb(const struct v4l2_ctrl_h264_decode_params *dec_param, - struct v4l2_h264_dpb_entry *dpb) -{ - DECLARE_BITMAP(new, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - DECLARE_BITMAP(in_use, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - DECLARE_BITMAP(used, ARRAY_SIZE(dec_param->dpb)) = { 0, }; - unsigned int i, j; - - /* Disable all entries by default, and mark the ones in use. */ - for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - set_bit(i, in_use); - dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; - } - - /* Try to match new DPB entries with existing ones by their POCs. */ - for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { - const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; - - if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) - continue; - - /* - * To cut off some comparisons, iterate only on target DPB - * entries were already used. - */ - for_each_set_bit(j, in_use, ARRAY_SIZE(dec_param->dpb)) { - struct v4l2_h264_dpb_entry *cdpb; - - cdpb = &dpb[j]; - if (!dpb_entry_match(cdpb, ndpb)) - continue; - - *cdpb = *ndpb; - set_bit(j, used); - /* Don't reiterate on this one. */ - clear_bit(j, in_use); - break; - } - - if (j == ARRAY_SIZE(dec_param->dpb)) - set_bit(i, new); - } - - /* For entries that could not be matched, use remaining free slots. */ - for_each_set_bit(i, new, ARRAY_SIZE(dec_param->dpb)) { - const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; - struct v4l2_h264_dpb_entry *cdpb; - - /* - * Both arrays are of the same sizes, so there is no way - * we can end up with no space in target array, unless - * something is buggy. - */ - j = find_first_zero_bit(used, ARRAY_SIZE(dec_param->dpb)); - if (WARN_ON(j >= ARRAY_SIZE(dec_param->dpb))) - return; - - cdpb = &dpb[j]; - *cdpb = *ndpb; - set_bit(j, used); - } -} - -/* - * The firmware expects unused reflist entries to have the value 0x20. - */ -static void fixup_ref_list(u8 *ref_list, size_t num_valid) -{ - memset(&ref_list[num_valid], 0x20, 32 - num_valid); -} - -static void get_vdec_decode_parameters(struct vdec_h264_slice_inst *inst) -{ - const struct v4l2_ctrl_h264_decode_params *dec_params = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); - const struct v4l2_ctrl_h264_sps *sps = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); - const struct v4l2_ctrl_h264_pps *pps = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); - const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + const struct v4l2_ctrl_h264_decode_params *dec_params; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; struct mtk_h264_dec_slice_param *slice_param = &inst->h264_slice_param; struct v4l2_h264_reflist_builder reflist_builder; + struct v4l2_h264_reference v4l2_p0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b1_reflist[V4L2_H264_REF_LIST_LEN]; u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0; u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0; u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1; - update_dpb(dec_params, inst->dpb); + dec_params = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + if (IS_ERR(dec_params)) + return PTR_ERR(dec_params); + + sps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); + if (IS_ERR(sps)) + return PTR_ERR(sps); - get_h264_sps_parameters(&slice_param->sps, sps); - get_h264_pps_parameters(&slice_param->pps, pps); - get_h264_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix); - get_h264_decode_parameters(&slice_param->decode_params, dec_params, - inst->dpb); - get_h264_dpb_list(inst, slice_param); + pps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); + if (IS_ERR(pps)) + return PTR_ERR(pps); + + scaling_matrix = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + if (IS_ERR(scaling_matrix)) + return PTR_ERR(scaling_matrix); + + mtk_vdec_h264_update_dpb(dec_params, inst->dpb); + + mtk_vdec_h264_copy_sps_params(&slice_param->sps, sps); + mtk_vdec_h264_copy_pps_params(&slice_param->pps, pps); + mtk_vdec_h264_copy_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix); + mtk_vdec_h264_copy_decode_params(&slice_param->decode_params, + dec_params, inst->dpb); + mtk_vdec_h264_fill_dpb_info(inst->ctx, &slice_param->decode_params, + slice_param->h264_dpb_info); /* Build the reference lists */ v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps, inst->dpb); - v4l2_h264_build_p_ref_list(&reflist_builder, p0_reflist); - v4l2_h264_build_b_ref_lists(&reflist_builder, b0_reflist, b1_reflist); + v4l2_h264_build_p_ref_list(&reflist_builder, v4l2_p0_reflist); + v4l2_h264_build_b_ref_lists(&reflist_builder, v4l2_b0_reflist, + v4l2_b1_reflist); + /* Adapt the built lists to the firmware's expectations */ - fixup_ref_list(p0_reflist, reflist_builder.num_valid); - fixup_ref_list(b0_reflist, reflist_builder.num_valid); - fixup_ref_list(b1_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(p0_reflist, v4l2_p0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b0_reflist, v4l2_b0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b1_reflist, v4l2_b1_reflist, reflist_builder.num_valid); memcpy(&inst->vsi_ctx.h264_slice_params, slice_param, sizeof(inst->vsi_ctx.h264_slice_params)); -} - -static unsigned int get_mv_buf_size(unsigned int width, unsigned int height) -{ - int unit_size = (width / MB_UNIT_LEN) * (height / MB_UNIT_LEN) + 8; - return HW_MB_STORE_SZ * unit_size; + return 0; } static int allocate_predication_buf(struct vdec_h264_slice_inst *inst) @@ -525,7 +187,7 @@ static int alloc_mv_buf(struct vdec_h264_slice_inst *inst, int i; int err; struct mtk_vcodec_mem *mem = NULL; - unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h); + unsigned int buf_sz = mtk_vdec_h264_get_mv_buf_size(pic->buf_w, pic->buf_h); mtk_v4l2_debug(3, "size = 0x%x", buf_sz); for (i = 0; i < H264_MAX_MV_NUM; i++) { @@ -670,33 +332,46 @@ static void vdec_h264_slice_deinit(void *h_vdec) } static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, - struct vdec_fb *fb, bool *res_chg) + struct vdec_fb *unused, bool *res_chg) { struct vdec_h264_slice_inst *inst = h_vdec; const struct v4l2_ctrl_h264_decode_params *dec_params = - get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info; + struct mtk_video_dec_buf *dst_buf_info; + struct vdec_fb *fb; u32 data[2]; u64 y_fb_dma; u64 c_fb_dma; int err; + inst->num_nalu++; /* bs NULL means flush decoder */ if (!bs) return vpu_dec_reset(vpu); + fb = inst->ctx->dev->vdec_pdata->get_cap_buffer(inst->ctx); + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer); + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p", - ++inst->num_nalu, y_fb_dma, c_fb_dma, fb); + inst->num_nalu, y_fb_dma, c_fb_dma, fb); inst->vsi_ctx.dec.bs_dma = (uint64_t)bs->dma_addr; inst->vsi_ctx.dec.y_fb_dma = y_fb_dma; inst->vsi_ctx.dec.c_fb_dma = c_fb_dma; inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb; - get_vdec_decode_parameters(inst); + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &dst_buf_info->m2m_buf.vb, true); + err = get_vdec_decode_parameters(inst); + if (err) + goto err_free_fb_out; + data[0] = bs->size; /* * Reconstruct the first byte of the NAL unit, as the firmware requests diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c new file mode 100644 index 000000000000..784d01f8bd50 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c @@ -0,0 +1,808 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Yunfei Dong <yunfei.dong@mediatek.com> + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <media/v4l2-h264.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> + +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_drv_base.h" +#include "../vdec_drv_if.h" +#include "../vdec_vpu_if.h" +#include "vdec_h264_req_common.h" + +/** + * enum vdec_h264_core_dec_err_type - core decode error type + * + * @TRANS_BUFFER_FULL: trans buffer is full + * @SLICE_HEADER_FULL: slice header buffer is full + */ +enum vdec_h264_core_dec_err_type { + TRANS_BUFFER_FULL = 1, + SLICE_HEADER_FULL, +}; + +/** + * struct vdec_h264_slice_lat_dec_param - parameters for decode current frame + * + * @sps: h264 sps syntax parameters + * @pps: h264 pps syntax parameters + * @slice_header: h264 slice header syntax parameters + * @scaling_matrix: h264 scaling list parameters + * @decode_params: decoder parameters of each frame used for hardware decode + * @h264_dpb_info: dpb reference list + */ +struct vdec_h264_slice_lat_dec_param { + struct mtk_h264_sps_param sps; + struct mtk_h264_pps_param pps; + struct mtk_h264_slice_hd_param slice_header; + struct slice_api_h264_scaling_matrix scaling_matrix; + struct slice_api_h264_decode_param decode_params; + struct mtk_h264_dpb_info h264_dpb_info[V4L2_H264_NUM_DPB_ENTRIES]; +}; + +/** + * struct vdec_h264_slice_info - decode information + * + * @nal_info: nal info of current picture + * @timeout: Decode timeout: 1 timeout, 0 no timeount + * @bs_buf_size: bitstream size + * @bs_buf_addr: bitstream buffer dma address + * @y_fb_dma: Y frame buffer dma address + * @c_fb_dma: C frame buffer dma address + * @vdec_fb_va: VDEC frame buffer struct virtual address + * @crc: Used to check whether hardware's status is right + */ +struct vdec_h264_slice_info { + u16 nal_info; + u16 timeout; + u32 bs_buf_size; + u64 bs_buf_addr; + u64 y_fb_dma; + u64 c_fb_dma; + u64 vdec_fb_va; + u32 crc[8]; +}; + +/** + * struct vdec_h264_slice_vsi - shared memory for decode information exchange + * between SCP and Host. + * + * @wdma_err_addr: wdma error dma address + * @wdma_start_addr: wdma start dma address + * @wdma_end_addr: wdma end dma address + * @slice_bc_start_addr: slice bc start dma address + * @slice_bc_end_addr: slice bc end dma address + * @row_info_start_addr: row info start dma address + * @row_info_end_addr: row info end dma address + * @trans_start: trans start dma address + * @trans_end: trans end dma address + * @wdma_end_addr_offset: wdma end address offset + * + * @mv_buf_dma: HW working motion vector buffer + * dma address (AP-W, VPU-R) + * @dec: decode information (AP-R, VPU-W) + * @h264_slice_params: decode parameters for hw used + */ +struct vdec_h264_slice_vsi { + /* LAT dec addr */ + u64 wdma_err_addr; + u64 wdma_start_addr; + u64 wdma_end_addr; + u64 slice_bc_start_addr; + u64 slice_bc_end_addr; + u64 row_info_start_addr; + u64 row_info_end_addr; + u64 trans_start; + u64 trans_end; + u64 wdma_end_addr_offset; + + u64 mv_buf_dma[H264_MAX_MV_NUM]; + struct vdec_h264_slice_info dec; + struct vdec_h264_slice_lat_dec_param h264_slice_params; +}; + +/** + * struct vdec_h264_slice_share_info - shared information used to exchange + * message between lat and core + * + * @sps: sequence header information from user space + * @dec_params: decoder params from user space + * @h264_slice_params: decoder params used for hardware + * @trans_start: trans start dma address + * @trans_end: trans end dma address + * @nal_info: nal info of current picture + */ +struct vdec_h264_slice_share_info { + struct v4l2_ctrl_h264_sps sps; + struct v4l2_ctrl_h264_decode_params dec_params; + struct vdec_h264_slice_lat_dec_param h264_slice_params; + u64 trans_start; + u64 trans_end; + u16 nal_info; +}; + +/** + * struct vdec_h264_slice_inst - h264 decoder instance + * + * @slice_dec_num: how many picture be decoded + * @ctx: point to mtk_vcodec_ctx + * @pred_buf: HW working predication buffer + * @mv_buf: HW working motion vector buffer + * @vpu: VPU instance + * @vsi: vsi used for lat + * @vsi_core: vsi used for core + * + * @vsi_ctx: Local VSI data for this decoding context + * @h264_slice_param: the parameters that hardware use to decode + * + * @resolution_changed:resolution changed + * @realloc_mv_buf: reallocate mv buffer + * @cap_num_planes: number of capture queue plane + * + * @dpb: decoded picture buffer used to store reference + * buffer information + *@is_field_bitstream: is field bitstream + */ +struct vdec_h264_slice_inst { + unsigned int slice_dec_num; + struct mtk_vcodec_ctx *ctx; + struct mtk_vcodec_mem pred_buf; + struct mtk_vcodec_mem mv_buf[H264_MAX_MV_NUM]; + struct vdec_vpu_inst vpu; + struct vdec_h264_slice_vsi *vsi; + struct vdec_h264_slice_vsi *vsi_core; + + struct vdec_h264_slice_vsi vsi_ctx; + struct vdec_h264_slice_lat_dec_param h264_slice_param; + + unsigned int resolution_changed; + unsigned int realloc_mv_buf; + unsigned int cap_num_planes; + + struct v4l2_h264_dpb_entry dpb[16]; + bool is_field_bitstream; +}; + +static int vdec_h264_slice_fill_decode_parameters(struct vdec_h264_slice_inst *inst, + struct vdec_h264_slice_share_info *share_info) +{ + struct vdec_h264_slice_lat_dec_param *slice_param = &inst->vsi->h264_slice_params; + const struct v4l2_ctrl_h264_decode_params *dec_params; + const struct v4l2_ctrl_h264_scaling_matrix *src_matrix; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + + dec_params = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + if (IS_ERR(dec_params)) + return PTR_ERR(dec_params); + + src_matrix = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + if (IS_ERR(src_matrix)) + return PTR_ERR(src_matrix); + + sps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); + if (IS_ERR(sps)) + return PTR_ERR(sps); + + pps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); + if (IS_ERR(pps)) + return PTR_ERR(pps); + + if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) { + mtk_vcodec_err(inst, "No support for H.264 field decoding."); + inst->is_field_bitstream = true; + return -EINVAL; + } + + mtk_vdec_h264_copy_sps_params(&slice_param->sps, sps); + mtk_vdec_h264_copy_pps_params(&slice_param->pps, pps); + mtk_vdec_h264_copy_scaling_matrix(&slice_param->scaling_matrix, src_matrix); + + memcpy(&share_info->sps, sps, sizeof(*sps)); + memcpy(&share_info->dec_params, dec_params, sizeof(*dec_params)); + + return 0; +} + +static int get_vdec_sig_decode_parameters(struct vdec_h264_slice_inst *inst) +{ + const struct v4l2_ctrl_h264_decode_params *dec_params; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; + const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; + struct vdec_h264_slice_lat_dec_param *slice_param = &inst->h264_slice_param; + struct v4l2_h264_reflist_builder reflist_builder; + struct v4l2_h264_reference v4l2_p0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b1_reflist[V4L2_H264_REF_LIST_LEN]; + u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0; + u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0; + u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1; + + dec_params = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + if (IS_ERR(dec_params)) + return PTR_ERR(dec_params); + + sps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SPS); + if (IS_ERR(sps)) + return PTR_ERR(sps); + + pps = mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_PPS); + if (IS_ERR(pps)) + return PTR_ERR(pps); + + scaling_matrix = + mtk_vdec_h264_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_H264_SCALING_MATRIX); + if (IS_ERR(scaling_matrix)) + return PTR_ERR(scaling_matrix); + + mtk_vdec_h264_update_dpb(dec_params, inst->dpb); + + mtk_vdec_h264_copy_sps_params(&slice_param->sps, sps); + mtk_vdec_h264_copy_pps_params(&slice_param->pps, pps); + mtk_vdec_h264_copy_scaling_matrix(&slice_param->scaling_matrix, scaling_matrix); + + mtk_vdec_h264_copy_decode_params(&slice_param->decode_params, dec_params, inst->dpb); + mtk_vdec_h264_fill_dpb_info(inst->ctx, &slice_param->decode_params, + slice_param->h264_dpb_info); + + /* Build the reference lists */ + v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps, inst->dpb); + v4l2_h264_build_p_ref_list(&reflist_builder, v4l2_p0_reflist); + v4l2_h264_build_b_ref_lists(&reflist_builder, v4l2_b0_reflist, v4l2_b1_reflist); + + /* Adapt the built lists to the firmware's expectations */ + mtk_vdec_h264_get_ref_list(p0_reflist, v4l2_p0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b0_reflist, v4l2_b0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b1_reflist, v4l2_b1_reflist, reflist_builder.num_valid); + + memcpy(&inst->vsi_ctx.h264_slice_params, slice_param, + sizeof(inst->vsi_ctx.h264_slice_params)); + + return 0; +} + +static void vdec_h264_slice_fill_decode_reflist(struct vdec_h264_slice_inst *inst, + struct vdec_h264_slice_lat_dec_param *slice_param, + struct vdec_h264_slice_share_info *share_info) +{ + struct v4l2_ctrl_h264_decode_params *dec_params = &share_info->dec_params; + struct v4l2_ctrl_h264_sps *sps = &share_info->sps; + struct v4l2_h264_reflist_builder reflist_builder; + struct v4l2_h264_reference v4l2_p0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b0_reflist[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference v4l2_b1_reflist[V4L2_H264_REF_LIST_LEN]; + u8 *p0_reflist = slice_param->decode_params.ref_pic_list_p0; + u8 *b0_reflist = slice_param->decode_params.ref_pic_list_b0; + u8 *b1_reflist = slice_param->decode_params.ref_pic_list_b1; + + mtk_vdec_h264_update_dpb(dec_params, inst->dpb); + + mtk_vdec_h264_copy_decode_params(&slice_param->decode_params, dec_params, + inst->dpb); + mtk_vdec_h264_fill_dpb_info(inst->ctx, &slice_param->decode_params, + slice_param->h264_dpb_info); + + mtk_v4l2_debug(3, "cur poc = %d\n", dec_params->bottom_field_order_cnt); + /* Build the reference lists */ + v4l2_h264_init_reflist_builder(&reflist_builder, dec_params, sps, + inst->dpb); + v4l2_h264_build_p_ref_list(&reflist_builder, v4l2_p0_reflist); + v4l2_h264_build_b_ref_lists(&reflist_builder, v4l2_b0_reflist, v4l2_b1_reflist); + + /* Adapt the built lists to the firmware's expectations */ + mtk_vdec_h264_get_ref_list(p0_reflist, v4l2_p0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b0_reflist, v4l2_b0_reflist, reflist_builder.num_valid); + mtk_vdec_h264_get_ref_list(b1_reflist, v4l2_b1_reflist, reflist_builder.num_valid); +} + +static int vdec_h264_slice_alloc_mv_buf(struct vdec_h264_slice_inst *inst, + struct vdec_pic_info *pic) +{ + unsigned int buf_sz = mtk_vdec_h264_get_mv_buf_size(pic->buf_w, pic->buf_h); + struct mtk_vcodec_mem *mem; + int i, err; + + mtk_v4l2_debug(3, "size = 0x%x", buf_sz); + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + mem->size = buf_sz; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "failed to allocate mv buf"); + return err; + } + } + + return 0; +} + +static void vdec_h264_slice_free_mv_buf(struct vdec_h264_slice_inst *inst) +{ + int i; + struct mtk_vcodec_mem *mem; + + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + } +} + +static void vdec_h264_slice_get_pic_info(struct vdec_h264_slice_inst *inst) +{ + struct mtk_vcodec_ctx *ctx = inst->ctx; + u32 data[3]; + + data[0] = ctx->picinfo.pic_w; + data[1] = ctx->picinfo.pic_h; + data[2] = ctx->capture_fourcc; + vpu_dec_get_param(&inst->vpu, data, 3, GET_PARAM_PIC_INFO); + + ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, VCODEC_DEC_ALIGNED_64); + ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, VCODEC_DEC_ALIGNED_64); + ctx->picinfo.fb_sz[0] = inst->vpu.fb_sz[0]; + ctx->picinfo.fb_sz[1] = inst->vpu.fb_sz[1]; + inst->cap_num_planes = + ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes; + + mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->picinfo.buf_w, ctx->picinfo.buf_h); + mtk_vcodec_debug(inst, "Y/C(%d, %d)", ctx->picinfo.fb_sz[0], + ctx->picinfo.fb_sz[1]); + + if (ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w || + ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h) { + inst->resolution_changed = true; + if (ctx->last_decoded_picinfo.buf_w != ctx->picinfo.buf_w || + ctx->last_decoded_picinfo.buf_h != ctx->picinfo.buf_h) + inst->realloc_mv_buf = true; + + mtk_v4l2_debug(1, "resChg: (%d %d) : old(%d, %d) -> new(%d, %d)", + inst->resolution_changed, + inst->realloc_mv_buf, + ctx->last_decoded_picinfo.pic_w, + ctx->last_decoded_picinfo.pic_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h); + } +} + +static void vdec_h264_slice_get_crop_info(struct vdec_h264_slice_inst *inst, + struct v4l2_rect *cr) +{ + cr->left = 0; + cr->top = 0; + cr->width = inst->ctx->picinfo.pic_w; + cr->height = inst->ctx->picinfo.pic_h; + + mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d", + cr->left, cr->top, cr->width, cr->height); +} + +static int vdec_h264_slice_init(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_h264_slice_inst *inst; + int err, vsi_size; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->ctx = ctx; + + inst->vpu.id = SCP_IPI_VDEC_LAT; + inst->vpu.core_id = SCP_IPI_VDEC_CORE; + inst->vpu.ctx = ctx; + inst->vpu.codec_type = ctx->current_codec; + inst->vpu.capture_type = ctx->capture_fourcc; + + err = vpu_dec_init(&inst->vpu); + if (err) { + mtk_vcodec_err(inst, "vdec_h264 init err=%d", err); + goto error_free_inst; + } + + vsi_size = round_up(sizeof(struct vdec_h264_slice_vsi), VCODEC_DEC_ALIGNED_64); + inst->vsi = inst->vpu.vsi; + inst->vsi_core = + (struct vdec_h264_slice_vsi *)(((char *)inst->vpu.vsi) + vsi_size); + inst->resolution_changed = true; + inst->realloc_mv_buf = true; + + mtk_vcodec_debug(inst, "lat struct size = %d,%d,%d,%d vsi: %d\n", + (int)sizeof(struct mtk_h264_sps_param), + (int)sizeof(struct mtk_h264_pps_param), + (int)sizeof(struct vdec_h264_slice_lat_dec_param), + (int)sizeof(struct mtk_h264_dpb_info), + vsi_size); + mtk_vcodec_debug(inst, "lat H264 instance >> %p, codec_type = 0x%x", + inst, inst->vpu.codec_type); + + ctx->drv_handle = inst; + return 0; + +error_free_inst: + kfree(inst); + return err; +} + +static void vdec_h264_slice_deinit(void *h_vdec) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + + mtk_vcodec_debug_enter(inst); + + vpu_dec_deinit(&inst->vpu); + vdec_h264_slice_free_mv_buf(inst); + vdec_msg_queue_deinit(&inst->ctx->msg_queue, inst->ctx); + + kfree(inst); +} + +static int vdec_h264_slice_core_decode(struct vdec_lat_buf *lat_buf) +{ + struct vdec_fb *fb; + u64 vdec_fb_va; + u64 y_fb_dma, c_fb_dma; + int err, timeout, i; + struct mtk_vcodec_ctx *ctx = lat_buf->ctx; + struct vdec_h264_slice_inst *inst = ctx->drv_handle; + struct vb2_v4l2_buffer *vb2_v4l2; + struct vdec_h264_slice_share_info *share_info = lat_buf->private_data; + struct mtk_vcodec_mem *mem; + struct vdec_vpu_inst *vpu = &inst->vpu; + + mtk_vcodec_debug(inst, "[h264-core] vdec_h264 core decode"); + memcpy(&inst->vsi_core->h264_slice_params, &share_info->h264_slice_params, + sizeof(share_info->h264_slice_params)); + + fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx); + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; + vdec_fb_va = (unsigned long)fb; + + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1) + c_fb_dma = + y_fb_dma + inst->ctx->picinfo.buf_w * inst->ctx->picinfo.buf_h; + else + c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; + + mtk_vcodec_debug(inst, "[h264-core] y/c addr = 0x%llx 0x%llx", y_fb_dma, + c_fb_dma); + + inst->vsi_core->dec.y_fb_dma = y_fb_dma; + inst->vsi_core->dec.c_fb_dma = c_fb_dma; + inst->vsi_core->dec.vdec_fb_va = vdec_fb_va; + inst->vsi_core->dec.nal_info = share_info->nal_info; + inst->vsi_core->wdma_start_addr = + lat_buf->ctx->msg_queue.wdma_addr.dma_addr; + inst->vsi_core->wdma_end_addr = + lat_buf->ctx->msg_queue.wdma_addr.dma_addr + + lat_buf->ctx->msg_queue.wdma_addr.size; + inst->vsi_core->wdma_err_addr = lat_buf->wdma_err_addr.dma_addr; + inst->vsi_core->slice_bc_start_addr = lat_buf->slice_bc_addr.dma_addr; + inst->vsi_core->slice_bc_end_addr = lat_buf->slice_bc_addr.dma_addr + + lat_buf->slice_bc_addr.size; + inst->vsi_core->trans_start = share_info->trans_start; + inst->vsi_core->trans_end = share_info->trans_end; + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + inst->vsi_core->mv_buf_dma[i] = mem->dma_addr; + } + + vb2_v4l2 = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, vb2_v4l2, true); + + vdec_h264_slice_fill_decode_reflist(inst, &inst->vsi_core->h264_slice_params, + share_info); + + err = vpu_dec_core(vpu); + if (err) { + mtk_vcodec_err(inst, "core decode err=%d", err); + goto vdec_dec_end; + } + + /* wait decoder done interrupt */ + timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); + if (timeout) + mtk_vcodec_err(inst, "core decode timeout: pic_%d", + ctx->decoded_frame_cnt); + inst->vsi_core->dec.timeout = !!timeout; + + vpu_dec_core_end(vpu); + mtk_vcodec_debug(inst, "pic[%d] crc: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + ctx->decoded_frame_cnt, + inst->vsi_core->dec.crc[0], inst->vsi_core->dec.crc[1], + inst->vsi_core->dec.crc[2], inst->vsi_core->dec.crc[3], + inst->vsi_core->dec.crc[4], inst->vsi_core->dec.crc[5], + inst->vsi_core->dec.crc[6], inst->vsi_core->dec.crc[7]); + +vdec_dec_end: + vdec_msg_queue_update_ube_rptr(&lat_buf->ctx->msg_queue, share_info->trans_end); + ctx->dev->vdec_pdata->cap_to_disp(ctx, !!err, lat_buf->src_buf_req); + mtk_vcodec_debug(inst, "core decode done err=%d", err); + ctx->decoded_frame_cnt++; + return 0; +} + +static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info; + int nal_start_idx, err, timeout = 0, i; + unsigned int data[2]; + struct vdec_lat_buf *lat_buf; + struct vdec_h264_slice_share_info *share_info; + unsigned char *buf; + struct mtk_vcodec_mem *mem; + + if (vdec_msg_queue_init(&inst->ctx->msg_queue, inst->ctx, + vdec_h264_slice_core_decode, + sizeof(*share_info))) + return -ENOMEM; + + /* bs NULL means flush decoder */ + if (!bs) { + vdec_msg_queue_wait_lat_buf_full(&inst->ctx->msg_queue); + return vpu_dec_reset(vpu); + } + + if (inst->is_field_bitstream) + return -EINVAL; + + lat_buf = vdec_msg_queue_dqbuf(&inst->ctx->msg_queue.lat_ctx); + if (!lat_buf) { + mtk_vcodec_err(inst, "failed to get lat buffer"); + return -EINVAL; + } + share_info = lat_buf->private_data; + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + + buf = (unsigned char *)bs->va; + nal_start_idx = mtk_vdec_h264_find_start_code(buf, bs->size); + if (nal_start_idx < 0) { + err = -EINVAL; + goto err_free_fb_out; + } + + inst->vsi->dec.nal_info = buf[nal_start_idx]; + inst->vsi->dec.bs_buf_addr = (u64)bs->dma_addr; + inst->vsi->dec.bs_buf_size = bs->size; + + lat_buf->src_buf_req = src_buf_info->m2m_buf.vb.vb2_buf.req_obj.req; + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, &lat_buf->ts_info, true); + + err = vdec_h264_slice_fill_decode_parameters(inst, share_info); + if (err) + goto err_free_fb_out; + + *res_chg = inst->resolution_changed; + if (inst->resolution_changed) { + mtk_vcodec_debug(inst, "- resolution changed -"); + if (inst->realloc_mv_buf) { + err = vdec_h264_slice_alloc_mv_buf(inst, &inst->ctx->picinfo); + inst->realloc_mv_buf = false; + if (err) + goto err_free_fb_out; + } + inst->resolution_changed = false; + } + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + inst->vsi->mv_buf_dma[i] = mem->dma_addr; + } + inst->vsi->wdma_start_addr = lat_buf->ctx->msg_queue.wdma_addr.dma_addr; + inst->vsi->wdma_end_addr = lat_buf->ctx->msg_queue.wdma_addr.dma_addr + + lat_buf->ctx->msg_queue.wdma_addr.size; + inst->vsi->wdma_err_addr = lat_buf->wdma_err_addr.dma_addr; + inst->vsi->slice_bc_start_addr = lat_buf->slice_bc_addr.dma_addr; + inst->vsi->slice_bc_end_addr = lat_buf->slice_bc_addr.dma_addr + + lat_buf->slice_bc_addr.size; + + inst->vsi->trans_end = inst->ctx->msg_queue.wdma_rptr_addr; + inst->vsi->trans_start = inst->ctx->msg_queue.wdma_wptr_addr; + mtk_vcodec_debug(inst, "lat:trans(0x%llx 0x%llx) err:0x%llx", + inst->vsi->wdma_start_addr, + inst->vsi->wdma_end_addr, + inst->vsi->wdma_err_addr); + + mtk_vcodec_debug(inst, "slice(0x%llx 0x%llx) rprt((0x%llx 0x%llx))", + inst->vsi->slice_bc_start_addr, + inst->vsi->slice_bc_end_addr, + inst->vsi->trans_start, + inst->vsi->trans_end); + err = vpu_dec_start(vpu, data, 2); + if (err) { + mtk_vcodec_debug(inst, "lat decode err: %d", err); + goto err_scp_decode; + } + + /* wait decoder done interrupt */ + timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0); + inst->vsi->dec.timeout = !!timeout; + + err = vpu_dec_end(vpu); + if (err == SLICE_HEADER_FULL || timeout || err == TRANS_BUFFER_FULL) { + err = -EINVAL; + goto err_scp_decode; + } + + share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr + + inst->vsi->wdma_end_addr_offset; + share_info->trans_start = inst->ctx->msg_queue.wdma_wptr_addr; + share_info->nal_info = inst->vsi->dec.nal_info; + vdec_msg_queue_update_ube_wptr(&lat_buf->ctx->msg_queue, share_info->trans_end); + + memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params, + sizeof(share_info->h264_slice_params)); + vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf); + + inst->slice_dec_num++; + return 0; + +err_scp_decode: +err_free_fb_out: + vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf); + mtk_vcodec_err(inst, "slice dec number: %d err: %d", inst->slice_dec_num, err); + return err; +} + +static int vdec_h264_slice_single_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *unused, bool *res_chg) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info, *dst_buf_info; + struct vdec_fb *fb; + unsigned char *buf; + unsigned int data[2], i; + u64 y_fb_dma, c_fb_dma; + struct mtk_vcodec_mem *mem; + int err, nal_start_idx; + + /* bs NULL means flush decoder */ + if (!bs) + return vpu_dec_reset(vpu); + + fb = inst->ctx->dev->vdec_pdata->get_cap_buffer(inst->ctx); + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer); + + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; + c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; + mtk_vcodec_debug(inst, "[h264-dec] [%d] y_dma=%llx c_dma=%llx", + inst->ctx->decoded_frame_cnt, y_fb_dma, c_fb_dma); + + inst->vsi_ctx.dec.bs_buf_addr = (u64)bs->dma_addr; + inst->vsi_ctx.dec.bs_buf_size = bs->size; + inst->vsi_ctx.dec.y_fb_dma = y_fb_dma; + inst->vsi_ctx.dec.c_fb_dma = c_fb_dma; + inst->vsi_ctx.dec.vdec_fb_va = (u64)(uintptr_t)fb; + + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &dst_buf_info->m2m_buf.vb, true); + err = get_vdec_sig_decode_parameters(inst); + if (err) + goto err_free_fb_out; + + buf = (unsigned char *)bs->va; + nal_start_idx = mtk_vdec_h264_find_start_code(buf, bs->size); + if (nal_start_idx < 0) { + err = -EINVAL; + goto err_free_fb_out; + } + inst->vsi_ctx.dec.nal_info = buf[nal_start_idx]; + + *res_chg = inst->resolution_changed; + if (inst->resolution_changed) { + mtk_vcodec_debug(inst, "- resolution changed -"); + if (inst->realloc_mv_buf) { + err = vdec_h264_slice_alloc_mv_buf(inst, &inst->ctx->picinfo); + inst->realloc_mv_buf = false; + if (err) + goto err_free_fb_out; + } + inst->resolution_changed = false; + + for (i = 0; i < H264_MAX_MV_NUM; i++) { + mem = &inst->mv_buf[i]; + inst->vsi_ctx.mv_buf_dma[i] = mem->dma_addr; + } + } + + memcpy(inst->vpu.vsi, &inst->vsi_ctx, sizeof(inst->vsi_ctx)); + err = vpu_dec_start(vpu, data, 2); + if (err) + goto err_free_fb_out; + + /* wait decoder done interrupt */ + err = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); + if (err) + mtk_vcodec_err(inst, "decode timeout: pic_%d", + inst->ctx->decoded_frame_cnt); + + inst->vsi->dec.timeout = !!err; + err = vpu_dec_end(vpu); + if (err) + goto err_free_fb_out; + + memcpy(&inst->vsi_ctx, inst->vpu.vsi, sizeof(inst->vsi_ctx)); + mtk_vcodec_debug(inst, "pic[%d] crc: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + inst->ctx->decoded_frame_cnt, + inst->vsi_ctx.dec.crc[0], inst->vsi_ctx.dec.crc[1], + inst->vsi_ctx.dec.crc[2], inst->vsi_ctx.dec.crc[3], + inst->vsi_ctx.dec.crc[4], inst->vsi_ctx.dec.crc[5], + inst->vsi_ctx.dec.crc[6], inst->vsi_ctx.dec.crc[7]); + + inst->ctx->decoded_frame_cnt++; + return 0; + +err_free_fb_out: + mtk_vcodec_err(inst, "dec frame number: %d err: %d", + inst->ctx->decoded_frame_cnt, err); + return err; +} + +static int vdec_h264_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *unused, bool *res_chg) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + int ret; + + if (!h_vdec) + return -EINVAL; + + if (inst->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE) + ret = vdec_h264_slice_single_decode(h_vdec, bs, unused, res_chg); + else + ret = vdec_h264_slice_lat_decode(h_vdec, bs, unused, res_chg); + + return ret; +} + +static int vdec_h264_slice_get_param(void *h_vdec, enum vdec_get_param_type type, + void *out) +{ + struct vdec_h264_slice_inst *inst = h_vdec; + + switch (type) { + case GET_PARAM_PIC_INFO: + vdec_h264_slice_get_pic_info(inst); + break; + case GET_PARAM_DPB_SIZE: + *(unsigned int *)out = 6; + break; + case GET_PARAM_CROP_INFO: + vdec_h264_slice_get_crop_info(inst, out); + break; + default: + mtk_vcodec_err(inst, "invalid get parameter type=%d", type); + return -EINVAL; + } + return 0; +} + +const struct vdec_common_if vdec_h264_slice_multi_if = { + .init = vdec_h264_slice_init, + .decode = vdec_h264_slice_decode, + .get_param = vdec_h264_slice_get_param, + .deinit = vdec_h264_slice_deinit, +}; diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c new file mode 100644 index 000000000000..eef102f3f4f3 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: Yunfei Dong <yunfei.dong@mediatek.com> + */ + +#include <linux/slab.h> +#include <media/v4l2-mem2mem.h> +#include <media/videobuf2-dma-contig.h> +#include <uapi/linux/v4l2-controls.h> + +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_drv_base.h" +#include "../vdec_drv_if.h" +#include "../vdec_vpu_if.h" + +/* Decoding picture buffer size (3 reference frames plus current frame) */ +#define VP8_DPB_SIZE 4 + +/* HW working buffer size (bytes) */ +#define VP8_SEG_ID_SZ SZ_256K +#define VP8_PP_WRAPY_SZ SZ_64K +#define VP8_PP_WRAPC_SZ SZ_64K +#define VP8_VLD_PRED_SZ SZ_64K + +/** + * struct vdec_vp8_slice_info - decode misc information + * + * @vld_wrapper_dma: vld wrapper dma address + * @seg_id_buf_dma: seg id dma address + * @wrap_y_dma: wrap y dma address + * @wrap_c_dma: wrap y dma address + * @cur_y_fb_dma: current plane Y frame buffer dma address + * @cur_c_fb_dma: current plane C frame buffer dma address + * @bs_dma: bitstream dma address + * @bs_sz: bitstream size + * @resolution_changed:resolution change flag 1 - changed, 0 - not change + * @frame_header_type: current frame header type + * @wait_key_frame: wait key frame coming + * @crc: used to check whether hardware's status is right + * @reserved: reserved, currently unused + */ +struct vdec_vp8_slice_info { + u64 vld_wrapper_dma; + u64 seg_id_buf_dma; + u64 wrap_y_dma; + u64 wrap_c_dma; + u64 cur_y_fb_dma; + u64 cur_c_fb_dma; + u64 bs_dma; + u32 bs_sz; + u32 resolution_changed; + u32 frame_header_type; + u32 crc[8]; + u32 reserved; +}; + +/** + * struct vdec_vp8_slice_dpb_info - vp8 reference information + * + * @y_dma_addr: Y bitstream physical address + * @c_dma_addr: CbCr bitstream physical address + * @reference_flag: reference picture flag + * @reserved: 64bit align + */ +struct vdec_vp8_slice_dpb_info { + dma_addr_t y_dma_addr; + dma_addr_t c_dma_addr; + int reference_flag; + int reserved; +}; + +/** + * struct vdec_vp8_slice_vsi - VPU shared information + * + * @dec: decoding information + * @pic: picture information + * @vp8_dpb_info: reference buffer information + */ +struct vdec_vp8_slice_vsi { + struct vdec_vp8_slice_info dec; + struct vdec_pic_info pic; + struct vdec_vp8_slice_dpb_info vp8_dpb_info[3]; +}; + +/** + * struct vdec_vp8_slice_inst - VP8 decoder instance + * + * @seg_id_buf: seg buffer + * @wrap_y_buf: wrapper y buffer + * @wrap_c_buf: wrapper c buffer + * @vld_wrapper_buf: vld wrapper buffer + * @ctx: V4L2 context + * @vpu: VPU instance for decoder + * @vsi: VPU share information + */ +struct vdec_vp8_slice_inst { + struct mtk_vcodec_mem seg_id_buf; + struct mtk_vcodec_mem wrap_y_buf; + struct mtk_vcodec_mem wrap_c_buf; + struct mtk_vcodec_mem vld_wrapper_buf; + struct mtk_vcodec_ctx *ctx; + struct vdec_vpu_inst vpu; + struct vdec_vp8_slice_vsi *vsi; +}; + +static void *vdec_vp8_slice_get_ctrl_ptr(struct mtk_vcodec_ctx *ctx, int id) +{ + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, id); + + if (!ctrl) + return ERR_PTR(-EINVAL); + + return ctrl->p_cur.p; +} + +static void vdec_vp8_slice_get_pic_info(struct vdec_vp8_slice_inst *inst) +{ + struct mtk_vcodec_ctx *ctx = inst->ctx; + unsigned int data[3]; + + data[0] = ctx->picinfo.pic_w; + data[1] = ctx->picinfo.pic_h; + data[2] = ctx->capture_fourcc; + vpu_dec_get_param(&inst->vpu, data, 3, GET_PARAM_PIC_INFO); + + ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, 64); + ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, 64); + ctx->picinfo.fb_sz[0] = inst->vpu.fb_sz[0]; + ctx->picinfo.fb_sz[1] = inst->vpu.fb_sz[1]; + + inst->vsi->pic.pic_w = ctx->picinfo.pic_w; + inst->vsi->pic.pic_h = ctx->picinfo.pic_h; + inst->vsi->pic.buf_w = ctx->picinfo.buf_w; + inst->vsi->pic.buf_h = ctx->picinfo.buf_h; + inst->vsi->pic.fb_sz[0] = ctx->picinfo.fb_sz[0]; + inst->vsi->pic.fb_sz[1] = ctx->picinfo.fb_sz[1]; + mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->picinfo.buf_w, ctx->picinfo.buf_h); + mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)", + ctx->picinfo.fb_sz[0], ctx->picinfo.fb_sz[1]); +} + +static int vdec_vp8_slice_alloc_working_buf(struct vdec_vp8_slice_inst *inst) +{ + int err; + struct mtk_vcodec_mem *mem; + + mem = &inst->seg_id_buf; + mem->size = VP8_SEG_ID_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "Cannot allocate working buffer"); + return err; + } + inst->vsi->dec.seg_id_buf_dma = (u64)mem->dma_addr; + + mem = &inst->wrap_y_buf; + mem->size = VP8_PP_WRAPY_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "cannot allocate WRAP Y buffer"); + return err; + } + inst->vsi->dec.wrap_y_dma = (u64)mem->dma_addr; + + mem = &inst->wrap_c_buf; + mem->size = VP8_PP_WRAPC_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "cannot allocate WRAP C buffer"); + return err; + } + inst->vsi->dec.wrap_c_dma = (u64)mem->dma_addr; + + mem = &inst->vld_wrapper_buf; + mem->size = VP8_VLD_PRED_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "cannot allocate vld wrapper buffer"); + return err; + } + inst->vsi->dec.vld_wrapper_dma = (u64)mem->dma_addr; + + return 0; +} + +static void vdec_vp8_slice_free_working_buf(struct vdec_vp8_slice_inst *inst) +{ + struct mtk_vcodec_mem *mem; + + mem = &inst->seg_id_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + inst->vsi->dec.seg_id_buf_dma = 0; + + mem = &inst->wrap_y_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + inst->vsi->dec.wrap_y_dma = 0; + + mem = &inst->wrap_c_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + inst->vsi->dec.wrap_c_dma = 0; + + mem = &inst->vld_wrapper_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + inst->vsi->dec.vld_wrapper_dma = 0; +} + +static u64 vdec_vp8_slice_get_ref_by_ts(const struct v4l2_ctrl_vp8_frame *frame_header, + int index) +{ + switch (index) { + case 0: + return frame_header->last_frame_ts; + case 1: + return frame_header->golden_frame_ts; + case 2: + return frame_header->alt_frame_ts; + default: + break; + } + + return -1; +} + +static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst) +{ + const struct v4l2_ctrl_vp8_frame *frame_header; + struct mtk_vcodec_ctx *ctx = inst->ctx; + struct vb2_queue *vq; + struct vb2_buffer *vb; + u64 referenct_ts; + int index, vb2_index; + + frame_header = vdec_vp8_slice_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_VP8_FRAME); + if (IS_ERR(frame_header)) + return PTR_ERR(frame_header); + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + for (index = 0; index < 3; index++) { + referenct_ts = vdec_vp8_slice_get_ref_by_ts(frame_header, index); + vb2_index = vb2_find_timestamp(vq, referenct_ts, 0); + if (vb2_index < 0) { + if (!V4L2_VP8_FRAME_IS_KEY_FRAME(frame_header)) + mtk_vcodec_err(inst, "reference invalid: index(%d) ts(%lld)", + index, referenct_ts); + inst->vsi->vp8_dpb_info[index].reference_flag = 0; + continue; + } + inst->vsi->vp8_dpb_info[index].reference_flag = 1; + + vb = vq->bufs[vb2_index]; + inst->vsi->vp8_dpb_info[index].y_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + inst->vsi->vp8_dpb_info[index].c_dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 1); + else + inst->vsi->vp8_dpb_info[index].c_dma_addr = + inst->vsi->vp8_dpb_info[index].y_dma_addr + + ctx->picinfo.fb_sz[0]; + } + + inst->vsi->dec.frame_header_type = frame_header->flags >> 1; + + return 0; +} + +static int vdec_vp8_slice_init(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_vp8_slice_inst *inst; + int err; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->ctx = ctx; + + inst->vpu.id = SCP_IPI_VDEC_LAT; + inst->vpu.core_id = SCP_IPI_VDEC_CORE; + inst->vpu.ctx = ctx; + inst->vpu.codec_type = ctx->current_codec; + inst->vpu.capture_type = ctx->capture_fourcc; + + err = vpu_dec_init(&inst->vpu); + if (err) { + mtk_vcodec_err(inst, "vdec_vp8 init err=%d", err); + goto error_free_inst; + } + + inst->vsi = inst->vpu.vsi; + err = vdec_vp8_slice_alloc_working_buf(inst); + if (err) + goto error_deinit; + + mtk_vcodec_debug(inst, "vp8 struct size = %d vsi: %d\n", + (int)sizeof(struct v4l2_ctrl_vp8_frame), + (int)sizeof(struct vdec_vp8_slice_vsi)); + mtk_vcodec_debug(inst, "vp8:%p, codec_type = 0x%x vsi: 0x%p", + inst, inst->vpu.codec_type, inst->vpu.vsi); + + ctx->drv_handle = inst; + return 0; + +error_deinit: + vpu_dec_deinit(&inst->vpu); +error_free_inst: + kfree(inst); + return err; +} + +static int vdec_vp8_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp8_slice_inst *inst = h_vdec; + struct vdec_vpu_inst *vpu = &inst->vpu; + struct mtk_video_dec_buf *src_buf_info, *dst_buf_info; + unsigned int data; + u64 y_fb_dma, c_fb_dma; + int err, timeout; + + /* Resolution changes are never initiated by us */ + *res_chg = false; + + /* bs NULL means flush decoder */ + if (!bs) + return vpu_dec_reset(vpu); + + src_buf_info = container_of(bs, struct mtk_video_dec_buf, bs_buffer); + + fb = inst->ctx->dev->vdec_pdata->get_cap_buffer(inst->ctx); + dst_buf_info = container_of(fb, struct mtk_video_dec_buf, frame_buffer); + + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; + if (inst->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 1) + c_fb_dma = y_fb_dma + + inst->ctx->picinfo.buf_w * inst->ctx->picinfo.buf_h; + else + c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; + + inst->vsi->dec.bs_dma = (u64)bs->dma_addr; + inst->vsi->dec.bs_sz = bs->size; + inst->vsi->dec.cur_y_fb_dma = y_fb_dma; + inst->vsi->dec.cur_c_fb_dma = c_fb_dma; + + mtk_vcodec_debug(inst, "frame[%d] bs(%zu 0x%llx) y/c(0x%llx 0x%llx)", + inst->ctx->decoded_frame_cnt, + bs->size, (u64)bs->dma_addr, + y_fb_dma, c_fb_dma); + + v4l2_m2m_buf_copy_metadata(&src_buf_info->m2m_buf.vb, + &dst_buf_info->m2m_buf.vb, true); + + err = vdec_vp8_slice_get_decode_parameters(inst); + if (err) + goto error; + + err = vpu_dec_start(vpu, &data, 1); + if (err) { + mtk_vcodec_debug(inst, "vp8 dec start err!"); + goto error; + } + + if (inst->vsi->dec.resolution_changed) { + mtk_vcodec_debug(inst, "- resolution_changed -"); + *res_chg = true; + return 0; + } + + /* wait decode done interrupt */ + timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, + 50, MTK_VDEC_CORE); + + err = vpu_dec_end(vpu); + if (err || timeout) + mtk_vcodec_debug(inst, "vp8 dec error timeout:%d err: %d pic_%d", + timeout, err, inst->ctx->decoded_frame_cnt); + + mtk_vcodec_debug(inst, "pic[%d] crc: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + inst->ctx->decoded_frame_cnt, + inst->vsi->dec.crc[0], inst->vsi->dec.crc[1], + inst->vsi->dec.crc[2], inst->vsi->dec.crc[3], + inst->vsi->dec.crc[4], inst->vsi->dec.crc[5], + inst->vsi->dec.crc[6], inst->vsi->dec.crc[7]); + + inst->ctx->decoded_frame_cnt++; +error: + return err; +} + +static int vdec_vp8_slice_get_param(void *h_vdec, enum vdec_get_param_type type, void *out) +{ + struct vdec_vp8_slice_inst *inst = h_vdec; + + switch (type) { + case GET_PARAM_PIC_INFO: + vdec_vp8_slice_get_pic_info(inst); + break; + case GET_PARAM_CROP_INFO: + mtk_vcodec_debug(inst, "No need to get vp8 crop information."); + break; + case GET_PARAM_DPB_SIZE: + *((unsigned int *)out) = VP8_DPB_SIZE; + break; + default: + mtk_vcodec_err(inst, "invalid get parameter type=%d", type); + return -EINVAL; + } + + return 0; +} + +static void vdec_vp8_slice_deinit(void *h_vdec) +{ + struct vdec_vp8_slice_inst *inst = h_vdec; + + mtk_vcodec_debug_enter(inst); + + vpu_dec_deinit(&inst->vpu); + vdec_vp8_slice_free_working_buf(inst); + kfree(inst); +} + +const struct vdec_common_if vdec_vp8_slice_if = { + .init = vdec_vp8_slice_init, + .decode = vdec_vp8_slice_decode, + .get_param = vdec_vp8_slice_get_param, + .deinit = vdec_vp8_slice_deinit, +}; diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c new file mode 100644 index 000000000000..023aba4ec2c4 --- /dev/null +++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c @@ -0,0 +1,2030 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + * Author: George Sun <george.sun@mediatek.com> + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <media/videobuf2-dma-contig.h> +#include <media/v4l2-vp9.h> + +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_drv_base.h" +#include "../vdec_drv_if.h" +#include "../vdec_vpu_if.h" + +/* reset_frame_context defined in VP9 spec */ +#define VP9_RESET_FRAME_CONTEXT_NONE0 0 +#define VP9_RESET_FRAME_CONTEXT_NONE1 1 +#define VP9_RESET_FRAME_CONTEXT_SPEC 2 +#define VP9_RESET_FRAME_CONTEXT_ALL 3 + +#define VP9_TILE_BUF_SIZE 4096 +#define VP9_PROB_BUF_SIZE 2560 +#define VP9_COUNTS_BUF_SIZE 16384 + +#define HDR_FLAG(x) (!!((hdr)->flags & V4L2_VP9_FRAME_FLAG_##x)) +#define LF_FLAG(x) (!!((lf)->flags & V4L2_VP9_LOOP_FILTER_FLAG_##x)) +#define SEG_FLAG(x) (!!((seg)->flags & V4L2_VP9_SEGMENTATION_FLAG_##x)) +#define VP9_BAND_6(band) ((band) == 0 ? 3 : 6) + +/* + * struct vdec_vp9_slice_frame_ctx - vp9 prob tables footprint + */ +struct vdec_vp9_slice_frame_ctx { + struct { + u8 probs[6][3]; + u8 padding[2]; + } coef_probs[4][2][2][6]; + + u8 y_mode_prob[4][16]; + u8 switch_interp_prob[4][16]; + u8 seg[32]; /* ignore */ + u8 comp_inter_prob[16]; + u8 comp_ref_prob[16]; + u8 single_ref_prob[5][2]; + u8 single_ref_prob_padding[6]; + + u8 joint[3]; + u8 joint_padding[13]; + struct { + u8 sign; + u8 classes[10]; + u8 padding[5]; + } sign_classes[2]; + struct { + u8 class0[1]; + u8 bits[10]; + u8 padding[5]; + } class0_bits[2]; + struct { + u8 class0_fp[2][3]; + u8 fp[3]; + u8 class0_hp; + u8 hp; + u8 padding[5]; + } class0_fp_hp[2]; + + u8 uv_mode_prob[10][16]; + u8 uv_mode_prob_padding[2][16]; + + u8 partition_prob[16][4]; + + u8 inter_mode_probs[7][4]; + u8 skip_probs[4]; + + u8 tx_p8x8[2][4]; + u8 tx_p16x16[2][4]; + u8 tx_p32x32[2][4]; + u8 intra_inter_prob[8]; +}; + +/* + * struct vdec_vp9_slice_frame_counts - vp9 counts tables footprint + */ +struct vdec_vp9_slice_frame_counts { + union { + struct { + u32 band_0[3]; + u32 padding0[1]; + u32 band_1_5[5][6]; + u32 padding1[2]; + } eob_branch[4][2][2]; + u32 eob_branch_space[256 * 4]; + }; + + struct { + u32 band_0[3][4]; + u32 band_1_5[5][6][4]; + } coef_probs[4][2][2]; + + u32 intra_inter[4][2]; + u32 comp_inter[5][2]; + u32 comp_inter_padding[2]; + u32 comp_ref[5][2]; + u32 comp_ref_padding[2]; + u32 single_ref[5][2][2]; + u32 inter_mode[7][4]; + u32 y_mode[4][12]; + u32 uv_mode[10][10]; + u32 partition[16][4]; + u32 switchable_interp[4][4]; + + u32 tx_p8x8[2][2]; + u32 tx_p16x16[2][4]; + u32 tx_p32x32[2][4]; + + u32 skip[3][4]; + + u32 joint[4]; + + struct { + u32 sign[2]; + u32 class0[2]; + u32 classes[12]; + u32 bits[10][2]; + u32 padding[4]; + u32 class0_fp[2][4]; + u32 fp[4]; + u32 class0_hp[2]; + u32 hp[2]; + } mvcomp[2]; + + u32 reserved[126][4]; +}; + +/** + * struct vdec_vp9_slice_counts_map - vp9 counts tables to map + * v4l2_vp9_frame_symbol_counts + * @skip: skip counts. + * @y_mode: Y prediction mode counts. + * @filter: interpolation filter counts. + * @mv_joint: motion vector joint counts. + * @sign: motion vector sign counts. + * @classes: motion vector class counts. + * @class0: motion vector class0 bit counts. + * @bits: motion vector bits counts. + * @class0_fp: motion vector class0 fractional bit counts. + * @fp: motion vector fractional bit counts. + * @class0_hp: motion vector class0 high precision fractional bit counts. + * @hp: motion vector high precision fractional bit counts. + */ +struct vdec_vp9_slice_counts_map { + u32 skip[3][2]; + u32 y_mode[4][10]; + u32 filter[4][3]; + u32 sign[2][2]; + u32 classes[2][11]; + u32 class0[2][2]; + u32 bits[2][10][2]; + u32 class0_fp[2][2][4]; + u32 fp[2][4]; + u32 class0_hp[2][2]; + u32 hp[2][2]; +}; + +/* + * struct vdec_vp9_slice_uncompressed_header - vp9 uncompressed header syntax + * used for decoding + */ +struct vdec_vp9_slice_uncompressed_header { + u8 profile; + u8 last_frame_type; + u8 frame_type; + + u8 last_show_frame; + u8 show_frame; + u8 error_resilient_mode; + + u8 bit_depth; + u8 padding0[1]; + u16 last_frame_width; + u16 last_frame_height; + u16 frame_width; + u16 frame_height; + + u8 intra_only; + u8 reset_frame_context; + u8 ref_frame_sign_bias[4]; + u8 allow_high_precision_mv; + u8 interpolation_filter; + + u8 refresh_frame_context; + u8 frame_parallel_decoding_mode; + u8 frame_context_idx; + + /* loop_filter_params */ + u8 loop_filter_level; + u8 loop_filter_sharpness; + u8 loop_filter_delta_enabled; + s8 loop_filter_ref_deltas[4]; + s8 loop_filter_mode_deltas[2]; + + /* quantization_params */ + u8 base_q_idx; + s8 delta_q_y_dc; + s8 delta_q_uv_dc; + s8 delta_q_uv_ac; + + /* segmentation_params */ + u8 segmentation_enabled; + u8 segmentation_update_map; + u8 segmentation_tree_probs[7]; + u8 padding1[1]; + u8 segmentation_temporal_udpate; + u8 segmentation_pred_prob[3]; + u8 segmentation_update_data; + u8 segmentation_abs_or_delta_update; + u8 feature_enabled[8]; + s16 feature_value[8][4]; + + /* tile_info */ + u8 tile_cols_log2; + u8 tile_rows_log2; + u8 padding2[2]; + + u16 uncompressed_header_size; + u16 header_size_in_bytes; + + /* LAT OUT, CORE IN */ + u32 dequant[8][4]; +}; + +/* + * struct vdec_vp9_slice_compressed_header - vp9 compressed header syntax + * used for decoding. + */ +struct vdec_vp9_slice_compressed_header { + u8 tx_mode; + u8 ref_mode; + u8 comp_fixed_ref; + u8 comp_var_ref[2]; + u8 padding[3]; +}; + +/* + * struct vdec_vp9_slice_tiles - vp9 tile syntax + */ +struct vdec_vp9_slice_tiles { + u32 size[4][64]; + u32 mi_rows[4]; + u32 mi_cols[64]; + u8 actual_rows; + u8 padding[7]; +}; + +/* + * struct vdec_vp9_slice_reference - vp9 reference frame information + */ +struct vdec_vp9_slice_reference { + u16 frame_width; + u16 frame_height; + u8 bit_depth; + u8 subsampling_x; + u8 subsampling_y; + u8 padding; +}; + +/* + * struct vdec_vp9_slice_frame - vp9 syntax used for decoding + */ +struct vdec_vp9_slice_frame { + struct vdec_vp9_slice_uncompressed_header uh; + struct vdec_vp9_slice_compressed_header ch; + struct vdec_vp9_slice_tiles tiles; + struct vdec_vp9_slice_reference ref[3]; +}; + +/* + * struct vdec_vp9_slice_init_vsi - VSI used to initialize instance + */ +struct vdec_vp9_slice_init_vsi { + unsigned int architecture; + unsigned int reserved; + u64 core_vsi; + /* default frame context's position in MicroP */ + u64 default_frame_ctx; +}; + +/* + * struct vdec_vp9_slice_mem - memory address and size + */ +struct vdec_vp9_slice_mem { + union { + u64 buf; + dma_addr_t dma_addr; + }; + union { + size_t size; + dma_addr_t dma_addr_end; + u64 padding; + }; +}; + +/* + * struct vdec_vp9_slice_bs - input buffer for decoding + */ +struct vdec_vp9_slice_bs { + struct vdec_vp9_slice_mem buf; + struct vdec_vp9_slice_mem frame; +}; + +/* + * struct vdec_vp9_slice_fb - frame buffer for decoding + */ +struct vdec_vp9_slice_fb { + struct vdec_vp9_slice_mem y; + struct vdec_vp9_slice_mem c; +}; + +/* + * struct vdec_vp9_slice_state - decoding state + */ +struct vdec_vp9_slice_state { + int err; + unsigned int full; + unsigned int timeout; + unsigned int perf; + + unsigned int crc[12]; +}; + +/** + * struct vdec_vp9_slice_vsi - exchange decoding information + * between Main CPU and MicroP + * + * @bs: input buffer + * @fb: output buffer + * @ref: 3 reference buffers + * @mv: mv working buffer + * @seg: segmentation working buffer + * @tile: tile buffer + * @prob: prob table buffer, used to set/update prob table + * @counts: counts table buffer, used to update prob table + * @ube: general buffer + * @trans: trans buffer position in general buffer + * @err_map: error buffer + * @row_info: row info buffer + * @frame: decoding syntax + * @state: decoding state + */ +struct vdec_vp9_slice_vsi { + /* used in LAT stage */ + struct vdec_vp9_slice_bs bs; + /* used in Core stage */ + struct vdec_vp9_slice_fb fb; + struct vdec_vp9_slice_fb ref[3]; + + struct vdec_vp9_slice_mem mv[2]; + struct vdec_vp9_slice_mem seg[2]; + struct vdec_vp9_slice_mem tile; + struct vdec_vp9_slice_mem prob; + struct vdec_vp9_slice_mem counts; + + /* LAT stage's output, Core stage's input */ + struct vdec_vp9_slice_mem ube; + struct vdec_vp9_slice_mem trans; + struct vdec_vp9_slice_mem err_map; + struct vdec_vp9_slice_mem row_info; + + /* decoding parameters */ + struct vdec_vp9_slice_frame frame; + + struct vdec_vp9_slice_state state; +}; + +/** + * struct vdec_vp9_slice_pfc - per-frame context that contains a local vsi. + * pass it from lat to core + * + * @vsi: local vsi. copy to/from remote vsi before/after decoding + * @ref_idx: reference buffer index + * @seq: picture sequence + * @state: decoding state + */ +struct vdec_vp9_slice_pfc { + struct vdec_vp9_slice_vsi vsi; + + u64 ref_idx[3]; + + int seq; + + /* LAT/Core CRC */ + struct vdec_vp9_slice_state state[2]; +}; + +/* + * enum vdec_vp9_slice_resolution_level + */ +enum vdec_vp9_slice_resolution_level { + VP9_RES_NONE, + VP9_RES_FHD, + VP9_RES_4K, + VP9_RES_8K, +}; + +/* + * struct vdec_vp9_slice_ref - picture's width & height should kept + * for later decoding as reference picture + */ +struct vdec_vp9_slice_ref { + unsigned int width; + unsigned int height; +}; + +/** + * struct vdec_vp9_slice_instance - represent one vp9 instance + * + * @ctx: pointer to codec's context + * @vpu: VPU instance + * @seq: global picture sequence + * @level: level of current resolution + * @width: width of last picture + * @height: height of last picture + * @frame_type: frame_type of last picture + * @irq: irq to Main CPU or MicroP + * @show_frame: show_frame of last picture + * @dpb: picture information (width/height) for reference + * @mv: mv working buffer + * @seg: segmentation working buffer + * @tile: tile buffer + * @prob: prob table buffer, used to set/update prob table + * @counts: counts table buffer, used to update prob table + * @frame_ctx: 4 frame context according to VP9 Spec + * @frame_ctx_helper: 4 frame context according to newest kernel spec + * @dirty: state of each frame context + * @init_vsi: vsi used for initialized VP9 instance + * @vsi: vsi used for decoding/flush ... + * @core_vsi: vsi used for Core stage + * @counts_map: used map to counts_helper + * @counts_helper: counts table according to newest kernel spec + */ +struct vdec_vp9_slice_instance { + struct mtk_vcodec_ctx *ctx; + struct vdec_vpu_inst vpu; + + int seq; + + enum vdec_vp9_slice_resolution_level level; + + /* for resolution change and get_pic_info */ + unsigned int width; + unsigned int height; + + /* for last_frame_type */ + unsigned int frame_type; + unsigned int irq; + + unsigned int show_frame; + + /* maintain vp9 reference frame state */ + struct vdec_vp9_slice_ref dpb[VB2_MAX_FRAME]; + + /* + * normal working buffers + * mv[0]/seg[0]/tile/prob/counts is used for LAT + * mv[1]/seg[1] is used for CORE + */ + struct mtk_vcodec_mem mv[2]; + struct mtk_vcodec_mem seg[2]; + struct mtk_vcodec_mem tile; + struct mtk_vcodec_mem prob; + struct mtk_vcodec_mem counts; + + /* 4 prob tables */ + struct vdec_vp9_slice_frame_ctx frame_ctx[4]; + /*4 helper tables */ + struct v4l2_vp9_frame_context frame_ctx_helper; + unsigned char dirty[4]; + + /* MicroP vsi */ + union { + struct vdec_vp9_slice_init_vsi *init_vsi; + struct vdec_vp9_slice_vsi *vsi; + }; + struct vdec_vp9_slice_vsi *core_vsi; + + struct vdec_vp9_slice_counts_map counts_map; + struct v4l2_vp9_frame_symbol_counts counts_helper; +}; + +/* + * all VP9 instances could share this default frame context. + */ +static struct vdec_vp9_slice_frame_ctx *vdec_vp9_slice_default_frame_ctx; +static DEFINE_MUTEX(vdec_vp9_slice_frame_ctx_lock); + +static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf); + +static int vdec_vp9_slice_init_default_frame_ctx(struct vdec_vp9_slice_instance *instance) +{ + struct vdec_vp9_slice_frame_ctx *remote_frame_ctx; + struct vdec_vp9_slice_frame_ctx *frame_ctx; + struct mtk_vcodec_ctx *ctx; + struct vdec_vp9_slice_init_vsi *vsi; + int ret = 0; + + ctx = instance->ctx; + vsi = instance->vpu.vsi; + if (!ctx || !vsi) + return -EINVAL; + + remote_frame_ctx = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, + (u32)vsi->default_frame_ctx); + if (!remote_frame_ctx) { + mtk_vcodec_err(instance, "failed to map default frame ctx\n"); + return -EINVAL; + } + + mutex_lock(&vdec_vp9_slice_frame_ctx_lock); + if (vdec_vp9_slice_default_frame_ctx) + goto out; + + frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_KERNEL); + if (!frame_ctx) { + ret = -ENOMEM; + goto out; + } + + memcpy(frame_ctx, remote_frame_ctx, sizeof(*frame_ctx)); + vdec_vp9_slice_default_frame_ctx = frame_ctx; + +out: + mutex_unlock(&vdec_vp9_slice_frame_ctx_lock); + + return ret; +} + +static int vdec_vp9_slice_alloc_working_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + enum vdec_vp9_slice_resolution_level level; + /* super blocks */ + unsigned int max_sb_w; + unsigned int max_sb_h; + unsigned int max_w; + unsigned int max_h; + unsigned int w; + unsigned int h; + size_t size; + int ret; + int i; + + w = vsi->frame.uh.frame_width; + h = vsi->frame.uh.frame_height; + + if (w > VCODEC_DEC_4K_CODED_WIDTH || + h > VCODEC_DEC_4K_CODED_HEIGHT) { + return -EINVAL; + } else if (w > MTK_VDEC_MAX_W || h > MTK_VDEC_MAX_H) { + /* 4K */ + level = VP9_RES_4K; + max_w = VCODEC_DEC_4K_CODED_WIDTH; + max_h = VCODEC_DEC_4K_CODED_HEIGHT; + } else { + /* FHD */ + level = VP9_RES_FHD; + max_w = MTK_VDEC_MAX_W; + max_h = MTK_VDEC_MAX_H; + } + + if (level == instance->level) + return 0; + + mtk_vcodec_debug(instance, "resolution level changed, from %u to %u, %ux%u", + instance->level, level, w, h); + + max_sb_w = DIV_ROUND_UP(max_w, 64); + max_sb_h = DIV_ROUND_UP(max_h, 64); + ret = -ENOMEM; + + /* + * Lat-flush must wait core idle, otherwise core will + * use released buffers + */ + + size = (max_sb_w * max_sb_h + 2) * 576; + for (i = 0; i < 2; i++) { + if (instance->mv[i].va) + mtk_vcodec_mem_free(ctx, &instance->mv[i]); + instance->mv[i].size = size; + if (mtk_vcodec_mem_alloc(ctx, &instance->mv[i])) + goto err; + } + + size = (max_sb_w * max_sb_h * 32) + 256; + for (i = 0; i < 2; i++) { + if (instance->seg[i].va) + mtk_vcodec_mem_free(ctx, &instance->seg[i]); + instance->seg[i].size = size; + if (mtk_vcodec_mem_alloc(ctx, &instance->seg[i])) + goto err; + } + + if (!instance->tile.va) { + instance->tile.size = VP9_TILE_BUF_SIZE; + if (mtk_vcodec_mem_alloc(ctx, &instance->tile)) + goto err; + } + + if (!instance->prob.va) { + instance->prob.size = VP9_PROB_BUF_SIZE; + if (mtk_vcodec_mem_alloc(ctx, &instance->prob)) + goto err; + } + + if (!instance->counts.va) { + instance->counts.size = VP9_COUNTS_BUF_SIZE; + if (mtk_vcodec_mem_alloc(ctx, &instance->counts)) + goto err; + } + + instance->level = level; + return 0; + +err: + instance->level = VP9_RES_NONE; + return ret; +} + +static void vdec_vp9_slice_free_working_buffer(struct vdec_vp9_slice_instance *instance) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + int i; + + for (i = 0; i < ARRAY_SIZE(instance->mv); i++) { + if (instance->mv[i].va) + mtk_vcodec_mem_free(ctx, &instance->mv[i]); + } + for (i = 0; i < ARRAY_SIZE(instance->seg); i++) { + if (instance->seg[i].va) + mtk_vcodec_mem_free(ctx, &instance->seg[i]); + } + if (instance->tile.va) + mtk_vcodec_mem_free(ctx, &instance->tile); + if (instance->prob.va) + mtk_vcodec_mem_free(ctx, &instance->prob); + if (instance->counts.va) + mtk_vcodec_mem_free(ctx, &instance->counts); + + instance->level = VP9_RES_NONE; +} + +static void vdec_vp9_slice_vsi_from_remote(struct vdec_vp9_slice_vsi *vsi, + struct vdec_vp9_slice_vsi *remote_vsi, + int skip) +{ + struct vdec_vp9_slice_frame *rf; + struct vdec_vp9_slice_frame *f; + + /* + * compressed header + * dequant + * buffer position + * decode state + */ + if (!skip) { + rf = &remote_vsi->frame; + f = &vsi->frame; + memcpy(&f->ch, &rf->ch, sizeof(f->ch)); + memcpy(&f->uh.dequant, &rf->uh.dequant, sizeof(f->uh.dequant)); + memcpy(&vsi->trans, &remote_vsi->trans, sizeof(vsi->trans)); + } + + memcpy(&vsi->state, &remote_vsi->state, sizeof(vsi->state)); +} + +static void vdec_vp9_slice_vsi_to_remote(struct vdec_vp9_slice_vsi *vsi, + struct vdec_vp9_slice_vsi *remote_vsi) +{ + memcpy(remote_vsi, vsi, sizeof(*vsi)); +} + +static int vdec_vp9_slice_tile_offset(int idx, int mi_num, int tile_log2) +{ + int sbs = (mi_num + 7) >> 3; + int offset = ((idx * sbs) >> tile_log2) << 3; + + return offset < mi_num ? offset : mi_num; +} + +static int vdec_vp9_slice_setup_lat_from_src_buf(struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf) +{ + struct vb2_v4l2_buffer *src; + struct vb2_v4l2_buffer *dst; + + src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx); + if (!src) + return -EINVAL; + + lat_buf->src_buf_req = src->vb2_buf.req_obj.req; + + dst = &lat_buf->ts_info; + v4l2_m2m_buf_copy_metadata(src, dst, true); + return 0; +} + +static void vdec_vp9_slice_setup_hdr(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_ctrl_vp9_frame *hdr) +{ + int i; + + uh->profile = hdr->profile; + uh->last_frame_type = instance->frame_type; + uh->frame_type = !HDR_FLAG(KEY_FRAME); + uh->last_show_frame = instance->show_frame; + uh->show_frame = HDR_FLAG(SHOW_FRAME); + uh->error_resilient_mode = HDR_FLAG(ERROR_RESILIENT); + uh->bit_depth = hdr->bit_depth; + uh->last_frame_width = instance->width; + uh->last_frame_height = instance->height; + uh->frame_width = hdr->frame_width_minus_1 + 1; + uh->frame_height = hdr->frame_height_minus_1 + 1; + uh->intra_only = HDR_FLAG(INTRA_ONLY); + /* map v4l2 enum to values defined in VP9 spec for firmware */ + switch (hdr->reset_frame_context) { + case V4L2_VP9_RESET_FRAME_CTX_NONE: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_NONE0; + break; + case V4L2_VP9_RESET_FRAME_CTX_SPEC: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_SPEC; + break; + case V4L2_VP9_RESET_FRAME_CTX_ALL: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_ALL; + break; + default: + uh->reset_frame_context = VP9_RESET_FRAME_CONTEXT_NONE0; + break; + } + /* + * ref_frame_sign_bias specifies the intended direction + * of the motion vector in time for each reference frame. + * - INTRA_FRAME = 0, + * - LAST_FRAME = 1, + * - GOLDEN_FRAME = 2, + * - ALTREF_FRAME = 3, + * ref_frame_sign_bias[INTRA_FRAME] is always 0 + * and VDA only passes another 3 directions + */ + uh->ref_frame_sign_bias[0] = 0; + for (i = 0; i < 3; i++) + uh->ref_frame_sign_bias[i + 1] = + !!(hdr->ref_frame_sign_bias & (1 << i)); + uh->allow_high_precision_mv = HDR_FLAG(ALLOW_HIGH_PREC_MV); + uh->interpolation_filter = hdr->interpolation_filter; + uh->refresh_frame_context = HDR_FLAG(REFRESH_FRAME_CTX); + uh->frame_parallel_decoding_mode = HDR_FLAG(PARALLEL_DEC_MODE); + uh->frame_context_idx = hdr->frame_context_idx; + + /* tile info */ + uh->tile_cols_log2 = hdr->tile_cols_log2; + uh->tile_rows_log2 = hdr->tile_rows_log2; + + uh->uncompressed_header_size = hdr->uncompressed_header_size; + uh->header_size_in_bytes = hdr->compressed_header_size; +} + +static void vdec_vp9_slice_setup_frame_ctx(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_ctrl_vp9_frame *hdr) +{ + int error_resilient_mode; + int reset_frame_context; + int key_frame; + int intra_only; + int i; + + key_frame = HDR_FLAG(KEY_FRAME); + intra_only = HDR_FLAG(INTRA_ONLY); + error_resilient_mode = HDR_FLAG(ERROR_RESILIENT); + reset_frame_context = uh->reset_frame_context; + + /* + * according to "6.2 Uncompressed header syntax" in + * "VP9 Bitstream & Decoding Process Specification", + * reset @frame_context_idx when (FrameIsIntra || error_resilient_mode) + */ + if (key_frame || intra_only || error_resilient_mode) { + /* + * @reset_frame_context specifies + * whether the frame context should be + * reset to default values: + * 0 or 1 means do not reset any frame context + * 2 resets just the context specified in the frame header + * 3 resets all contexts + */ + if (key_frame || error_resilient_mode || + reset_frame_context == 3) { + /* use default table */ + for (i = 0; i < 4; i++) + instance->dirty[i] = 0; + } else if (reset_frame_context == 2) { + instance->dirty[uh->frame_context_idx] = 0; + } + uh->frame_context_idx = 0; + } +} + +static void vdec_vp9_slice_setup_loop_filter(struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_vp9_loop_filter *lf) +{ + int i; + + uh->loop_filter_level = lf->level; + uh->loop_filter_sharpness = lf->sharpness; + uh->loop_filter_delta_enabled = LF_FLAG(DELTA_ENABLED); + for (i = 0; i < 4; i++) + uh->loop_filter_ref_deltas[i] = lf->ref_deltas[i]; + for (i = 0; i < 2; i++) + uh->loop_filter_mode_deltas[i] = lf->mode_deltas[i]; +} + +static void vdec_vp9_slice_setup_quantization(struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_vp9_quantization *quant) +{ + uh->base_q_idx = quant->base_q_idx; + uh->delta_q_y_dc = quant->delta_q_y_dc; + uh->delta_q_uv_dc = quant->delta_q_uv_dc; + uh->delta_q_uv_ac = quant->delta_q_uv_ac; +} + +static void vdec_vp9_slice_setup_segmentation(struct vdec_vp9_slice_uncompressed_header *uh, + struct v4l2_vp9_segmentation *seg) +{ + int i; + int j; + + uh->segmentation_enabled = SEG_FLAG(ENABLED); + uh->segmentation_update_map = SEG_FLAG(UPDATE_MAP); + for (i = 0; i < 7; i++) + uh->segmentation_tree_probs[i] = seg->tree_probs[i]; + uh->segmentation_temporal_udpate = SEG_FLAG(TEMPORAL_UPDATE); + for (i = 0; i < 3; i++) + uh->segmentation_pred_prob[i] = seg->pred_probs[i]; + uh->segmentation_update_data = SEG_FLAG(UPDATE_DATA); + uh->segmentation_abs_or_delta_update = SEG_FLAG(ABS_OR_DELTA_UPDATE); + for (i = 0; i < 8; i++) { + uh->feature_enabled[i] = seg->feature_enabled[i]; + for (j = 0; j < 4; j++) + uh->feature_value[i][j] = seg->feature_data[i][j]; + } +} + +static int vdec_vp9_slice_setup_tile(struct vdec_vp9_slice_vsi *vsi, + struct v4l2_ctrl_vp9_frame *hdr) +{ + unsigned int rows_log2; + unsigned int cols_log2; + unsigned int rows; + unsigned int cols; + unsigned int mi_rows; + unsigned int mi_cols; + struct vdec_vp9_slice_tiles *tiles; + int offset; + int start; + int end; + int i; + + rows_log2 = hdr->tile_rows_log2; + cols_log2 = hdr->tile_cols_log2; + rows = 1 << rows_log2; + cols = 1 << cols_log2; + tiles = &vsi->frame.tiles; + tiles->actual_rows = 0; + + if (rows > 4 || cols > 64) + return -EINVAL; + + /* setup mi rows/cols information */ + mi_rows = (hdr->frame_height_minus_1 + 1 + 7) >> 3; + mi_cols = (hdr->frame_width_minus_1 + 1 + 7) >> 3; + + for (i = 0; i < rows; i++) { + start = vdec_vp9_slice_tile_offset(i, mi_rows, rows_log2); + end = vdec_vp9_slice_tile_offset(i + 1, mi_rows, rows_log2); + offset = end - start; + tiles->mi_rows[i] = (offset + 7) >> 3; + if (tiles->mi_rows[i]) + tiles->actual_rows++; + } + + for (i = 0; i < cols; i++) { + start = vdec_vp9_slice_tile_offset(i, mi_cols, cols_log2); + end = vdec_vp9_slice_tile_offset(i + 1, mi_cols, cols_log2); + offset = end - start; + tiles->mi_cols[i] = (offset + 7) >> 3; + } + + return 0; +} + +static void vdec_vp9_slice_setup_state(struct vdec_vp9_slice_vsi *vsi) +{ + memset(&vsi->state, 0, sizeof(vsi->state)); +} + +static void vdec_vp9_slice_setup_ref_idx(struct vdec_vp9_slice_pfc *pfc, + struct v4l2_ctrl_vp9_frame *hdr) +{ + pfc->ref_idx[0] = hdr->last_frame_ts; + pfc->ref_idx[1] = hdr->golden_frame_ts; + pfc->ref_idx[2] = hdr->alt_frame_ts; +} + +static int vdec_vp9_slice_setup_pfc(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc) +{ + struct v4l2_ctrl_vp9_frame *hdr; + struct vdec_vp9_slice_uncompressed_header *uh; + struct v4l2_ctrl *hdr_ctrl; + struct vdec_vp9_slice_vsi *vsi; + int ret; + + /* frame header */ + hdr_ctrl = v4l2_ctrl_find(&instance->ctx->ctrl_hdl, V4L2_CID_STATELESS_VP9_FRAME); + if (!hdr_ctrl || !hdr_ctrl->p_cur.p) + return -EINVAL; + + hdr = hdr_ctrl->p_cur.p; + vsi = &pfc->vsi; + uh = &vsi->frame.uh; + + /* setup vsi information */ + vdec_vp9_slice_setup_hdr(instance, uh, hdr); + vdec_vp9_slice_setup_frame_ctx(instance, uh, hdr); + vdec_vp9_slice_setup_loop_filter(uh, &hdr->lf); + vdec_vp9_slice_setup_quantization(uh, &hdr->quant); + vdec_vp9_slice_setup_segmentation(uh, &hdr->seg); + ret = vdec_vp9_slice_setup_tile(vsi, hdr); + if (ret) + return ret; + vdec_vp9_slice_setup_state(vsi); + + /* core stage needs buffer index to get ref y/c ... */ + vdec_vp9_slice_setup_ref_idx(pfc, hdr); + + pfc->seq = instance->seq; + instance->seq++; + + 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) +{ + int i; + + vsi->bs.buf.dma_addr = bs->dma_addr; + vsi->bs.buf.size = bs->size; + vsi->bs.frame.dma_addr = bs->dma_addr; + vsi->bs.frame.size = bs->size; + + for (i = 0; i < 2; i++) { + vsi->mv[i].dma_addr = instance->mv[i].dma_addr; + vsi->mv[i].size = instance->mv[i].size; + } + for (i = 0; i < 2; i++) { + vsi->seg[i].dma_addr = instance->seg[i].dma_addr; + vsi->seg[i].size = instance->seg[i].size; + } + vsi->tile.dma_addr = instance->tile.dma_addr; + vsi->tile.size = instance->tile.size; + vsi->prob.dma_addr = instance->prob.dma_addr; + vsi->prob.size = instance->prob.size; + vsi->counts.dma_addr = instance->counts.dma_addr; + vsi->counts.size = instance->counts.size; + + vsi->ube.dma_addr = lat_buf->ctx->msg_queue.wdma_addr.dma_addr; + vsi->ube.size = lat_buf->ctx->msg_queue.wdma_addr.size; + vsi->trans.dma_addr = lat_buf->ctx->msg_queue.wdma_wptr_addr; + /* used to store trans end */ + vsi->trans.dma_addr_end = lat_buf->ctx->msg_queue.wdma_rptr_addr; + vsi->err_map.dma_addr = lat_buf->wdma_err_addr.dma_addr; + vsi->err_map.size = lat_buf->wdma_err_addr.size; + + 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) +{ + struct vdec_vp9_slice_frame_ctx *frame_ctx; + struct vdec_vp9_slice_uncompressed_header *uh; + + uh = &vsi->frame.uh; + + mtk_vcodec_debug(instance, "ctx dirty %u idx %d\n", + instance->dirty[uh->frame_context_idx], + uh->frame_context_idx); + + if (instance->dirty[uh->frame_context_idx]) + frame_ctx = &instance->frame_ctx[uh->frame_context_idx]; + 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, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *buf) +{ + struct vdec_vp9_slice_uncompressed_header *uh; + + /* reset segment buffer */ + uh = &vsi->frame.uh; + if (uh->frame_type == 0 || + uh->intra_only || + uh->error_resilient_mode || + uh->frame_width != instance->width || + uh->frame_height != instance->height) { + mtk_vcodec_debug(instance, "reset seg\n"); + memset(buf->va, 0, buf->size); + } +} + +/* + * parse tiles according to `6.4 Decode tiles syntax` + * in "vp9-bitstream-specification" + * + * frame contains uncompress header, compressed header and several tiles. + * this function parses tiles' position and size, stores them to tile buffer + * for decoding. + */ +static int vdec_vp9_slice_setup_tile_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi, + struct mtk_vcodec_mem *bs) +{ + struct vdec_vp9_slice_uncompressed_header *uh; + unsigned int rows_log2; + unsigned int cols_log2; + unsigned int rows; + unsigned int cols; + unsigned int mi_row; + unsigned int mi_col; + unsigned int offset; + unsigned int pa; + unsigned int size; + struct vdec_vp9_slice_tiles *tiles; + unsigned char *pos; + unsigned char *end; + unsigned char *va; + unsigned int *tb; + int i; + int j; + + uh = &vsi->frame.uh; + rows_log2 = uh->tile_rows_log2; + cols_log2 = uh->tile_cols_log2; + rows = 1 << rows_log2; + cols = 1 << cols_log2; + + if (rows > 4 || cols > 64) { + mtk_vcodec_err(instance, "tile_rows %u tile_cols %u\n", + rows, cols); + return -EINVAL; + } + + offset = uh->uncompressed_header_size + + uh->header_size_in_bytes; + if (bs->size <= offset) { + mtk_vcodec_err(instance, "bs size %zu tile offset %u\n", + bs->size, offset); + return -EINVAL; + } + + tiles = &vsi->frame.tiles; + /* setup tile buffer */ + + va = (unsigned char *)bs->va; + pos = va + offset; + end = va + bs->size; + /* truncated */ + pa = (unsigned int)bs->dma_addr + offset; + tb = instance->tile.va; + for (i = 0; i < rows; i++) { + for (j = 0; j < cols; j++) { + if (i == rows - 1 && + j == cols - 1) { + size = (unsigned int)(end - pos); + } else { + if (end - pos < 4) + return -EINVAL; + + size = (pos[0] << 24) | (pos[1] << 16) | + (pos[2] << 8) | pos[3]; + pos += 4; + pa += 4; + offset += 4; + if (end - pos < size) + return -EINVAL; + } + tiles->size[i][j] = size; + if (tiles->mi_rows[i]) { + *tb++ = (size << 3) + ((offset << 3) & 0x7f); + *tb++ = pa & ~0xf; + *tb++ = (pa << 3) & 0x7f; + mi_row = (tiles->mi_rows[i] - 1) & 0x1ff; + mi_col = (tiles->mi_cols[j] - 1) & 0x3f; + *tb++ = (mi_row << 6) + mi_col; + } + pos += size; + pa += size; + offset += size; + } + } + + return 0; +} + +static int vdec_vp9_slice_setup_lat(struct vdec_vp9_slice_instance *instance, + struct mtk_vcodec_mem *bs, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; + int ret; + + ret = vdec_vp9_slice_setup_lat_from_src_buf(instance, lat_buf); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_pfc(instance, pfc); + if (ret) + goto err; + + ret = vdec_vp9_slice_alloc_working_buffer(instance, vsi); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_lat_buffer(instance, vsi, bs, lat_buf); + if (ret) + goto err; + + 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; + + ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs); + if (ret) + goto err; + + return 0; + +err: + return ret; +} + +static +void vdec_vp9_slice_map_counts_eob_coef(unsigned int i, unsigned int j, unsigned int k, + struct vdec_vp9_slice_frame_counts *counts, + struct v4l2_vp9_frame_symbol_counts *counts_helper) +{ + u32 l = 0, m; + + /* + * helper eo -> mtk eo + * helpre e1 -> mtk c3 + * helper c0 -> c0 + * helper c1 -> c1 + * helper c2 -> c2 + */ + for (m = 0; m < 3; m++) { + counts_helper->coeff[i][j][k][l][m] = + (u32 (*)[3]) & counts->coef_probs[i][j][k].band_0[m]; + counts_helper->eob[i][j][k][l][m][0] = + &counts->eob_branch[i][j][k].band_0[m]; + counts_helper->eob[i][j][k][l][m][1] = + &counts->coef_probs[i][j][k].band_0[m][3]; + } + + for (l = 1; l < 6; l++) { + for (m = 0; m < 6; m++) { + counts_helper->coeff[i][j][k][l][m] = + (u32 (*)[3]) & counts->coef_probs[i][j][k].band_1_5[l - 1][m]; + counts_helper->eob[i][j][k][l][m][0] = + &counts->eob_branch[i][j][k].band_1_5[l - 1][m]; + counts_helper->eob[i][j][k][l][m][1] = + &counts->coef_probs[i][j][k].band_1_5[l - 1][m][3]; + } + } +} + +static void vdec_vp9_slice_counts_map_helper(struct vdec_vp9_slice_counts_map *counts_map, + struct vdec_vp9_slice_frame_counts *counts, + struct v4l2_vp9_frame_symbol_counts *counts_helper) +{ + int i, j, k; + + counts_helper->partition = &counts->partition; + counts_helper->intra_inter = &counts->intra_inter; + counts_helper->tx32p = &counts->tx_p32x32; + counts_helper->tx16p = &counts->tx_p16x16; + counts_helper->tx8p = &counts->tx_p8x8; + counts_helper->uv_mode = &counts->uv_mode; + + counts_helper->comp = &counts->comp_inter; + counts_helper->comp_ref = &counts->comp_ref; + counts_helper->single_ref = &counts->single_ref; + counts_helper->mv_mode = &counts->inter_mode; + counts_helper->mv_joint = &counts->joint; + + for (i = 0; i < ARRAY_SIZE(counts_map->skip); i++) + memcpy(counts_map->skip[i], counts->skip[i], + sizeof(counts_map->skip[0])); + counts_helper->skip = &counts_map->skip; + + for (i = 0; i < ARRAY_SIZE(counts_map->y_mode); i++) + memcpy(counts_map->y_mode[i], counts->y_mode[i], + sizeof(counts_map->y_mode[0])); + counts_helper->y_mode = &counts_map->y_mode; + + for (i = 0; i < ARRAY_SIZE(counts_map->filter); i++) + memcpy(counts_map->filter[i], counts->switchable_interp[i], + sizeof(counts_map->filter[0])); + counts_helper->filter = &counts_map->filter; + + for (i = 0; i < ARRAY_SIZE(counts_map->sign); i++) + memcpy(counts_map->sign[i], counts->mvcomp[i].sign, + sizeof(counts_map->sign[0])); + counts_helper->sign = &counts_map->sign; + + for (i = 0; i < ARRAY_SIZE(counts_map->classes); i++) + memcpy(counts_map->classes[i], counts->mvcomp[i].classes, + sizeof(counts_map->classes[0])); + counts_helper->classes = &counts_map->classes; + + for (i = 0; i < ARRAY_SIZE(counts_map->class0); i++) + memcpy(counts_map->class0[i], counts->mvcomp[i].class0, + sizeof(counts_map->class0[0])); + counts_helper->class0 = &counts_map->class0; + + for (i = 0; i < ARRAY_SIZE(counts_map->bits); i++) + for (j = 0; j < ARRAY_SIZE(counts_map->bits[0]); j++) + memcpy(counts_map->bits[i][j], counts->mvcomp[i].bits[j], + sizeof(counts_map->bits[0][0])); + counts_helper->bits = &counts_map->bits; + + for (i = 0; i < ARRAY_SIZE(counts_map->class0_fp); i++) + for (j = 0; j < ARRAY_SIZE(counts_map->class0_fp[0]); j++) + memcpy(counts_map->class0_fp[i][j], counts->mvcomp[i].class0_fp[j], + sizeof(counts_map->class0_fp[0][0])); + counts_helper->class0_fp = &counts_map->class0_fp; + + for (i = 0; i < ARRAY_SIZE(counts_map->fp); i++) + memcpy(counts_map->fp[i], counts->mvcomp[i].fp, + sizeof(counts_map->fp[0])); + counts_helper->fp = &counts_map->fp; + + for (i = 0; i < ARRAY_SIZE(counts_map->class0_hp); i++) + memcpy(counts_map->class0_hp[i], counts->mvcomp[i].class0_hp, + sizeof(counts_map->class0_hp[0])); + counts_helper->class0_hp = &counts_map->class0_hp; + + for (i = 0; i < ARRAY_SIZE(counts_map->hp); i++) + memcpy(counts_map->hp[i], counts->mvcomp[i].hp, sizeof(counts_map->hp[0])); + + counts_helper->hp = &counts_map->hp; + + for (i = 0; i < 4; i++) + for (j = 0; j < 2; j++) + for (k = 0; k < 2; k++) + vdec_vp9_slice_map_counts_eob_coef(i, j, k, counts, counts_helper); +} + +static void vdec_vp9_slice_map_to_coef(unsigned int i, unsigned int j, unsigned int k, + struct vdec_vp9_slice_frame_ctx *frame_ctx, + struct v4l2_vp9_frame_context *frame_ctx_helper) +{ + u32 l, m; + + for (l = 0; l < ARRAY_SIZE(frame_ctx_helper->coef[0][0][0]); l++) { + for (m = 0; m < VP9_BAND_6(l); m++) { + memcpy(frame_ctx_helper->coef[i][j][k][l][m], + frame_ctx->coef_probs[i][j][k][l].probs[m], + sizeof(frame_ctx_helper->coef[i][j][k][l][0])); + } + } +} + +static void vdec_vp9_slice_map_from_coef(unsigned int i, unsigned int j, unsigned int k, + struct vdec_vp9_slice_frame_ctx *frame_ctx, + struct v4l2_vp9_frame_context *frame_ctx_helper) +{ + u32 l, m; + + for (l = 0; l < ARRAY_SIZE(frame_ctx_helper->coef[0][0][0]); l++) { + for (m = 0; m < VP9_BAND_6(l); m++) { + memcpy(frame_ctx->coef_probs[i][j][k][l].probs[m], + frame_ctx_helper->coef[i][j][k][l][m], + sizeof(frame_ctx_helper->coef[i][j][k][l][0])); + } + } +} + +static +void vdec_vp9_slice_framectx_map_helper(bool frame_is_intra, + struct vdec_vp9_slice_frame_ctx *pre_frame_ctx, + struct vdec_vp9_slice_frame_ctx *frame_ctx, + struct v4l2_vp9_frame_context *frame_ctx_helper) +{ + struct v4l2_vp9_frame_mv_context *mv = &frame_ctx_helper->mv; + u32 i, j, k; + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->coef); i++) + for (j = 0; j < ARRAY_SIZE(frame_ctx_helper->coef[0]); j++) + for (k = 0; k < ARRAY_SIZE(frame_ctx_helper->coef[0][0]); k++) + vdec_vp9_slice_map_to_coef(i, j, k, pre_frame_ctx, + frame_ctx_helper); + + /* + * use previous prob when frame is not intra or + * we should use the prob updated by the compressed header parse + */ + if (!frame_is_intra) + frame_ctx = pre_frame_ctx; + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx8); i++) + memcpy(frame_ctx_helper->tx8[i], frame_ctx->tx_p8x8[i], + sizeof(frame_ctx_helper->tx8[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx16); i++) + memcpy(frame_ctx_helper->tx16[i], frame_ctx->tx_p16x16[i], + sizeof(frame_ctx_helper->tx16[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx32); i++) + memcpy(frame_ctx_helper->tx32[i], frame_ctx->tx_p32x32[i], + sizeof(frame_ctx_helper->tx32[0])); + + memcpy(frame_ctx_helper->skip, frame_ctx->skip_probs, sizeof(frame_ctx_helper->skip)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->inter_mode); i++) + memcpy(frame_ctx_helper->inter_mode[i], frame_ctx->inter_mode_probs[i], + sizeof(frame_ctx_helper->inter_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->interp_filter); i++) + memcpy(frame_ctx_helper->interp_filter[i], frame_ctx->switch_interp_prob[i], + sizeof(frame_ctx_helper->interp_filter[0])); + + memcpy(frame_ctx_helper->is_inter, frame_ctx->intra_inter_prob, + sizeof(frame_ctx_helper->is_inter)); + + memcpy(frame_ctx_helper->comp_mode, frame_ctx->comp_inter_prob, + sizeof(frame_ctx_helper->comp_mode)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->single_ref); i++) + memcpy(frame_ctx_helper->single_ref[i], frame_ctx->single_ref_prob[i], + sizeof(frame_ctx_helper->single_ref[0])); + + memcpy(frame_ctx_helper->comp_ref, frame_ctx->comp_ref_prob, + sizeof(frame_ctx_helper->comp_ref)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->y_mode); i++) + memcpy(frame_ctx_helper->y_mode[i], frame_ctx->y_mode_prob[i], + sizeof(frame_ctx_helper->y_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->uv_mode); i++) + memcpy(frame_ctx_helper->uv_mode[i], frame_ctx->uv_mode_prob[i], + sizeof(frame_ctx_helper->uv_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->partition); i++) + memcpy(frame_ctx_helper->partition[i], frame_ctx->partition_prob[i], + sizeof(frame_ctx_helper->partition[0])); + + memcpy(mv->joint, frame_ctx->joint, sizeof(mv->joint)); + + for (i = 0; i < ARRAY_SIZE(mv->sign); i++) + mv->sign[i] = frame_ctx->sign_classes[i].sign; + + for (i = 0; i < ARRAY_SIZE(mv->classes); i++) + memcpy(mv->classes[i], frame_ctx->sign_classes[i].classes, + sizeof(mv->classes[i])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_bit); i++) + mv->class0_bit[i] = frame_ctx->class0_bits[i].class0[0]; + + for (i = 0; i < ARRAY_SIZE(mv->bits); i++) + memcpy(mv->bits[i], frame_ctx->class0_bits[i].bits, sizeof(mv->bits[0])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_fr); i++) + for (j = 0; j < ARRAY_SIZE(mv->class0_fr[0]); j++) + memcpy(mv->class0_fr[i][j], frame_ctx->class0_fp_hp[i].class0_fp[j], + sizeof(mv->class0_fr[0][0])); + + for (i = 0; i < ARRAY_SIZE(mv->fr); i++) + memcpy(mv->fr[i], frame_ctx->class0_fp_hp[i].fp, sizeof(mv->fr[0])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_hp); i++) + mv->class0_hp[i] = frame_ctx->class0_fp_hp[i].class0_hp; + + for (i = 0; i < ARRAY_SIZE(mv->hp); i++) + mv->hp[i] = frame_ctx->class0_fp_hp[i].hp; +} + +static void vdec_vp9_slice_helper_map_framectx(struct v4l2_vp9_frame_context *frame_ctx_helper, + struct vdec_vp9_slice_frame_ctx *frame_ctx) +{ + struct v4l2_vp9_frame_mv_context *mv = &frame_ctx_helper->mv; + u32 i, j, k; + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx8); i++) + memcpy(frame_ctx->tx_p8x8[i], frame_ctx_helper->tx8[i], + sizeof(frame_ctx_helper->tx8[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx16); i++) + memcpy(frame_ctx->tx_p16x16[i], frame_ctx_helper->tx16[i], + sizeof(frame_ctx_helper->tx16[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->tx32); i++) + memcpy(frame_ctx->tx_p32x32[i], frame_ctx_helper->tx32[i], + sizeof(frame_ctx_helper->tx32[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->coef); i++) + for (j = 0; j < ARRAY_SIZE(frame_ctx_helper->coef[0]); j++) + for (k = 0; k < ARRAY_SIZE(frame_ctx_helper->coef[0][0]); k++) + vdec_vp9_slice_map_from_coef(i, j, k, frame_ctx, + frame_ctx_helper); + + memcpy(frame_ctx->skip_probs, frame_ctx_helper->skip, sizeof(frame_ctx_helper->skip)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->inter_mode); i++) + memcpy(frame_ctx->inter_mode_probs[i], frame_ctx_helper->inter_mode[i], + sizeof(frame_ctx_helper->inter_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->interp_filter); i++) + memcpy(frame_ctx->switch_interp_prob[i], frame_ctx_helper->interp_filter[i], + sizeof(frame_ctx_helper->interp_filter[0])); + + memcpy(frame_ctx->intra_inter_prob, frame_ctx_helper->is_inter, + sizeof(frame_ctx_helper->is_inter)); + + memcpy(frame_ctx->comp_inter_prob, frame_ctx_helper->comp_mode, + sizeof(frame_ctx_helper->comp_mode)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->single_ref); i++) + memcpy(frame_ctx->single_ref_prob[i], frame_ctx_helper->single_ref[i], + sizeof(frame_ctx_helper->single_ref[0])); + + memcpy(frame_ctx->comp_ref_prob, frame_ctx_helper->comp_ref, + sizeof(frame_ctx_helper->comp_ref)); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->y_mode); i++) + memcpy(frame_ctx->y_mode_prob[i], frame_ctx_helper->y_mode[i], + sizeof(frame_ctx_helper->y_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->uv_mode); i++) + memcpy(frame_ctx->uv_mode_prob[i], frame_ctx_helper->uv_mode[i], + sizeof(frame_ctx_helper->uv_mode[0])); + + for (i = 0; i < ARRAY_SIZE(frame_ctx_helper->partition); i++) + memcpy(frame_ctx->partition_prob[i], frame_ctx_helper->partition[i], + sizeof(frame_ctx_helper->partition[0])); + + memcpy(frame_ctx->joint, mv->joint, sizeof(mv->joint)); + + for (i = 0; i < ARRAY_SIZE(mv->sign); i++) + frame_ctx->sign_classes[i].sign = mv->sign[i]; + + for (i = 0; i < ARRAY_SIZE(mv->classes); i++) + memcpy(frame_ctx->sign_classes[i].classes, mv->classes[i], + sizeof(mv->classes[i])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_bit); i++) + frame_ctx->class0_bits[i].class0[0] = mv->class0_bit[i]; + + for (i = 0; i < ARRAY_SIZE(mv->bits); i++) + memcpy(frame_ctx->class0_bits[i].bits, mv->bits[i], sizeof(mv->bits[0])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_fr); i++) + for (j = 0; j < ARRAY_SIZE(mv->class0_fr[0]); j++) + memcpy(frame_ctx->class0_fp_hp[i].class0_fp[j], mv->class0_fr[i][j], + sizeof(mv->class0_fr[0][0])); + + for (i = 0; i < ARRAY_SIZE(mv->fr); i++) + memcpy(frame_ctx->class0_fp_hp[i].fp, mv->fr[i], sizeof(mv->fr[0])); + + for (i = 0; i < ARRAY_SIZE(mv->class0_hp); i++) + frame_ctx->class0_fp_hp[i].class0_hp = mv->class0_hp[i]; + + for (i = 0; i < ARRAY_SIZE(mv->hp); i++) + frame_ctx->class0_fp_hp[i].hp = mv->hp[i]; +} + +static int vdec_vp9_slice_update_prob(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_vsi *vsi) +{ + struct vdec_vp9_slice_frame_ctx *pre_frame_ctx; + struct v4l2_vp9_frame_context *pre_frame_ctx_helper; + struct vdec_vp9_slice_frame_ctx *frame_ctx; + struct vdec_vp9_slice_frame_counts *counts; + struct v4l2_vp9_frame_symbol_counts *counts_helper; + struct vdec_vp9_slice_uncompressed_header *uh; + bool frame_is_intra; + bool use_128; + + uh = &vsi->frame.uh; + pre_frame_ctx = &instance->frame_ctx[uh->frame_context_idx]; + pre_frame_ctx_helper = &instance->frame_ctx_helper; + frame_ctx = (struct vdec_vp9_slice_frame_ctx *)instance->prob.va; + counts = (struct vdec_vp9_slice_frame_counts *)instance->counts.va; + counts_helper = &instance->counts_helper; + + if (!uh->refresh_frame_context) + return 0; + + if (!uh->frame_parallel_decoding_mode) { + vdec_vp9_slice_counts_map_helper(&instance->counts_map, counts, counts_helper); + + frame_is_intra = !vsi->frame.uh.frame_type || vsi->frame.uh.intra_only; + /* check default prob */ + if (!instance->dirty[uh->frame_context_idx]) + vdec_vp9_slice_framectx_map_helper(frame_is_intra, + vdec_vp9_slice_default_frame_ctx, + frame_ctx, + pre_frame_ctx_helper); + else + vdec_vp9_slice_framectx_map_helper(frame_is_intra, + pre_frame_ctx, + frame_ctx, + pre_frame_ctx_helper); + + use_128 = !frame_is_intra && !vsi->frame.uh.last_frame_type; + v4l2_vp9_adapt_coef_probs(pre_frame_ctx_helper, + counts_helper, + use_128, + frame_is_intra); + if (!frame_is_intra) + v4l2_vp9_adapt_noncoef_probs(pre_frame_ctx_helper, + counts_helper, + V4L2_VP9_REFERENCE_MODE_SINGLE_REFERENCE, + vsi->frame.uh.interpolation_filter, + vsi->frame.ch.tx_mode, + vsi->frame.uh.allow_high_precision_mv ? + V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV : 0); + vdec_vp9_slice_helper_map_framectx(pre_frame_ctx_helper, pre_frame_ctx); + } else { + memcpy(pre_frame_ctx, frame_ctx, sizeof(*frame_ctx)); + } + + instance->dirty[uh->frame_context_idx] = 1; + + return 0; +} + +static int vdec_vp9_slice_update_lat(struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi; + + vsi = &pfc->vsi; + memcpy(&pfc->state[0], &vsi->state, sizeof(vsi->state)); + + mtk_vcodec_debug(instance, "Frame %u LAT CRC 0x%08x %lx %lx\n", + pfc->seq, vsi->state.crc[0], + (unsigned long)vsi->trans.dma_addr, + (unsigned long)vsi->trans.dma_addr_end); + + /* buffer full, need to re-decode */ + if (vsi->state.full) { + /* buffer not enough */ + if (vsi->trans.dma_addr_end - vsi->trans.dma_addr == + vsi->ube.size) + return -ENOMEM; + return -EAGAIN; + } + + vdec_vp9_slice_update_prob(instance, vsi); + + instance->width = vsi->frame.uh.frame_width; + instance->height = vsi->frame.uh.frame_height; + instance->frame_type = vsi->frame.uh.frame_type; + instance->show_frame = vsi->frame.uh.show_frame; + + return 0; +} + +static int vdec_vp9_slice_setup_core_to_dst_buf(struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf) +{ + struct vb2_v4l2_buffer *dst; + + dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx); + if (!dst) + return -EINVAL; + + v4l2_m2m_buf_copy_metadata(&lat_buf->ts_info, dst, true); + return 0; +} + +static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *instance, + struct vdec_vp9_slice_pfc *pfc, + struct vdec_vp9_slice_vsi *vsi, + struct vdec_fb *fb, + struct vdec_lat_buf *lat_buf) +{ + struct vb2_buffer *vb; + struct vb2_queue *vq; + struct vdec_vp9_slice_reference *ref; + int plane; + int size; + int idx; + int w; + int h; + int i; + + plane = instance->ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes; + w = vsi->frame.uh.frame_width; + h = vsi->frame.uh.frame_height; + size = ALIGN(w, 64) * ALIGN(h, 64); + + /* frame buffer */ + vsi->fb.y.dma_addr = fb->base_y.dma_addr; + if (plane == 1) + vsi->fb.c.dma_addr = fb->base_y.dma_addr + size; + else + vsi->fb.c.dma_addr = fb->base_c.dma_addr; + + /* reference buffers */ + vq = v4l2_m2m_get_vq(instance->ctx->m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (!vq) + return -EINVAL; + + /* get current output buffer */ + vb = &v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx)->vb2_buf; + if (!vb) + return -EINVAL; + + /* update internal buffer's width/height */ + for (i = 0; i < vq->num_buffers; i++) { + if (vb == vq->bufs[i]) { + instance->dpb[i].width = w; + instance->dpb[i].height = h; + break; + } + } + + /* + * get buffer's width/height from instance + * get buffer address from vb2buf + */ + for (i = 0; i < 3; i++) { + ref = &vsi->frame.ref[i]; + idx = vb2_find_timestamp(vq, pfc->ref_idx[i], 0); + if (idx < 0) { + ref->frame_width = w; + ref->frame_height = h; + memset(&vsi->ref[i], 0, sizeof(vsi->ref[i])); + } else { + ref->frame_width = instance->dpb[idx].width; + ref->frame_height = instance->dpb[idx].height; + vb = vq->bufs[idx]; + vsi->ref[i].y.dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 0); + if (plane == 1) + vsi->ref[i].c.dma_addr = + vsi->ref[i].y.dma_addr + size; + else + vsi->ref[i].c.dma_addr = + vb2_dma_contig_plane_dma_addr(vb, 1); + } + } + + return 0; +} + +static int vdec_vp9_slice_setup_core(struct vdec_vp9_slice_instance *instance, + struct vdec_fb *fb, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi = &pfc->vsi; + int ret; + + vdec_vp9_slice_setup_state(vsi); + + ret = vdec_vp9_slice_setup_core_to_dst_buf(instance, lat_buf); + if (ret) + goto err; + + ret = vdec_vp9_slice_setup_core_buffer(instance, pfc, vsi, fb, lat_buf); + if (ret) + goto err; + + vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[1]); + + return 0; + +err: + return ret; +} + +static int vdec_vp9_slice_update_core(struct vdec_vp9_slice_instance *instance, + struct vdec_lat_buf *lat_buf, + struct vdec_vp9_slice_pfc *pfc) +{ + struct vdec_vp9_slice_vsi *vsi; + + vsi = &pfc->vsi; + memcpy(&pfc->state[1], &vsi->state, sizeof(vsi->state)); + + mtk_vcodec_debug(instance, "Frame %u Y_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[0], vsi->state.crc[1], + vsi->state.crc[2], vsi->state.crc[3]); + mtk_vcodec_debug(instance, "Frame %u C_CRC %08x %08x %08x %08x\n", + pfc->seq, + vsi->state.crc[4], vsi->state.crc[5], + vsi->state.crc[6], vsi->state.crc[7]); + + return 0; +} + +static int vdec_vp9_slice_init(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_vp9_slice_instance *instance; + struct vdec_vp9_slice_init_vsi *vsi; + int ret; + + instance = kzalloc(sizeof(*instance), GFP_KERNEL); + if (!instance) + return -ENOMEM; + + instance->ctx = ctx; + instance->vpu.id = SCP_IPI_VDEC_LAT; + instance->vpu.core_id = SCP_IPI_VDEC_CORE; + instance->vpu.ctx = ctx; + instance->vpu.codec_type = ctx->current_codec; + + ret = vpu_dec_init(&instance->vpu); + if (ret) { + mtk_vcodec_err(instance, "failed to init vpu dec, ret %d\n", ret); + goto error_vpu_init; + } + + /* init vsi and global flags */ + + vsi = instance->vpu.vsi; + if (!vsi) { + mtk_vcodec_err(instance, "failed to get VP9 vsi\n"); + ret = -EINVAL; + goto error_vsi; + } + instance->init_vsi = vsi; + instance->core_vsi = mtk_vcodec_fw_map_dm_addr(ctx->dev->fw_handler, + (u32)vsi->core_vsi); + if (!instance->core_vsi) { + mtk_vcodec_err(instance, "failed to get VP9 core vsi\n"); + ret = -EINVAL; + goto error_vsi; + } + + instance->irq = 1; + + ret = vdec_vp9_slice_init_default_frame_ctx(instance); + if (ret) + goto error_default_frame_ctx; + + ctx->drv_handle = instance; + + return 0; + +error_default_frame_ctx: +error_vsi: + vpu_dec_deinit(&instance->vpu); +error_vpu_init: + kfree(instance); + return ret; +} + +static void vdec_vp9_slice_deinit(void *h_vdec) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + + if (!instance) + return; + + vpu_dec_deinit(&instance->vpu); + vdec_vp9_slice_free_working_buffer(instance); + vdec_msg_queue_deinit(&instance->ctx->msg_queue, instance->ctx); + kfree(instance); +} + +static int vdec_vp9_slice_flush(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + + mtk_vcodec_debug(instance, "flush ...\n"); + + vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue); + return vpu_dec_reset(&instance->vpu); +} + +static void vdec_vp9_slice_get_pic_info(struct vdec_vp9_slice_instance *instance) +{ + struct mtk_vcodec_ctx *ctx = instance->ctx; + unsigned int data[3]; + + mtk_vcodec_debug(instance, "w %u h %u\n", + ctx->picinfo.pic_w, ctx->picinfo.pic_h); + + data[0] = ctx->picinfo.pic_w; + data[1] = ctx->picinfo.pic_h; + data[2] = ctx->capture_fourcc; + vpu_dec_get_param(&instance->vpu, data, 3, GET_PARAM_PIC_INFO); + + ctx->picinfo.buf_w = ALIGN(ctx->picinfo.pic_w, 64); + ctx->picinfo.buf_h = ALIGN(ctx->picinfo.pic_h, 64); + ctx->picinfo.fb_sz[0] = instance->vpu.fb_sz[0]; + ctx->picinfo.fb_sz[1] = instance->vpu.fb_sz[1]; +} + +static void vdec_vp9_slice_get_dpb_size(struct vdec_vp9_slice_instance *instance, + unsigned int *dpb_sz) +{ + /* refer VP9 specification */ + *dpb_sz = 9; +} + +static int vdec_vp9_slice_get_param(void *h_vdec, enum vdec_get_param_type type, void *out) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + + switch (type) { + case GET_PARAM_PIC_INFO: + vdec_vp9_slice_get_pic_info(instance); + break; + case GET_PARAM_DPB_SIZE: + vdec_vp9_slice_get_dpb_size(instance, out); + break; + case GET_PARAM_CROP_INFO: + mtk_vcodec_debug(instance, "No need to get vp9 crop information."); + break; + default: + mtk_vcodec_err(instance, "invalid get parameter type=%d\n", + type); + return -EINVAL; + } + + return 0; +} + +static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp9_slice_instance *instance = h_vdec; + struct vdec_lat_buf *lat_buf; + struct vdec_vp9_slice_pfc *pfc; + struct vdec_vp9_slice_vsi *vsi; + struct mtk_vcodec_ctx *ctx; + int ret; + + if (!instance || !instance->ctx) + return -EINVAL; + ctx = instance->ctx; + + /* init msgQ for the first time */ + if (vdec_msg_queue_init(&ctx->msg_queue, ctx, + vdec_vp9_slice_core_decode, + sizeof(*pfc))) + return -ENOMEM; + + /* bs NULL means flush decoder */ + if (!bs) + return vdec_vp9_slice_flush(h_vdec, bs, fb, res_chg); + + lat_buf = vdec_msg_queue_dqbuf(&instance->ctx->msg_queue.lat_ctx); + if (!lat_buf) { + mtk_vcodec_err(instance, "Failed to get VP9 lat buf\n"); + return -EBUSY; + } + pfc = (struct vdec_vp9_slice_pfc *)lat_buf->private_data; + if (!pfc) + return -EINVAL; + vsi = &pfc->vsi; + + ret = vdec_vp9_slice_setup_lat(instance, bs, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, "Failed to setup VP9 lat ret %d\n", ret); + return ret; + } + vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi); + + ret = vpu_dec_start(&instance->vpu, NULL, 0); + if (ret) { + mtk_vcodec_err(instance, "Failed to dec VP9 ret %d\n", ret); + return ret; + } + + if (instance->irq) { + ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0); + /* update remote vsi if decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 decode timeout %d pic %d\n", ret, pfc->seq); + WRITE_ONCE(instance->vsi->state.timeout, 1); + } + vpu_dec_end(&instance->vpu); + } + + vdec_vp9_slice_vsi_from_remote(vsi, instance->vsi, 0); + ret = vdec_vp9_slice_update_lat(instance, lat_buf, pfc); + + /* LAT trans full, no more UBE or decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 decode error: %d\n", ret); + return ret; + } + + mtk_vcodec_debug(instance, "lat dma addr: 0x%lx 0x%lx\n", + (unsigned long)pfc->vsi.trans.dma_addr, + (unsigned long)pfc->vsi.trans.dma_addr_end); + + vdec_msg_queue_update_ube_wptr(&ctx->msg_queue, + vsi->trans.dma_addr_end + + ctx->msg_queue.wdma_addr.dma_addr); + vdec_msg_queue_qbuf(&ctx->dev->msg_queue_core_ctx, lat_buf); + + return 0; +} + +static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf) +{ + struct vdec_vp9_slice_instance *instance; + struct vdec_vp9_slice_pfc *pfc; + struct mtk_vcodec_ctx *ctx = NULL; + struct vdec_fb *fb = NULL; + int ret = -EINVAL; + + if (!lat_buf) + goto err; + + pfc = lat_buf->private_data; + ctx = lat_buf->ctx; + if (!pfc || !ctx) + goto err; + + instance = ctx->drv_handle; + if (!instance) + goto err; + + fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx); + if (!fb) { + ret = -EBUSY; + goto err; + } + + ret = vdec_vp9_slice_setup_core(instance, fb, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, "vdec_vp9_slice_setup_core\n"); + goto err; + } + vdec_vp9_slice_vsi_to_remote(&pfc->vsi, instance->core_vsi); + + ret = vpu_dec_core(&instance->vpu); + if (ret) { + mtk_vcodec_err(instance, "vpu_dec_core\n"); + goto err; + } + + if (instance->irq) { + ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE); + /* update remote vsi if decode timeout */ + if (ret) { + mtk_vcodec_err(instance, "VP9 core timeout pic %d\n", pfc->seq); + WRITE_ONCE(instance->core_vsi->state.timeout, 1); + } + vpu_dec_core_end(&instance->vpu); + } + + vdec_vp9_slice_vsi_from_remote(&pfc->vsi, instance->core_vsi, 1); + ret = vdec_vp9_slice_update_core(instance, lat_buf, pfc); + if (ret) { + mtk_vcodec_err(instance, "vdec_vp9_slice_update_core\n"); + goto err; + } + + pfc->vsi.trans.dma_addr_end += ctx->msg_queue.wdma_addr.dma_addr; + mtk_vcodec_debug(instance, "core dma_addr_end 0x%lx\n", + (unsigned long)pfc->vsi.trans.dma_addr_end); + vdec_msg_queue_update_ube_rptr(&ctx->msg_queue, pfc->vsi.trans.dma_addr_end); + ctx->dev->vdec_pdata->cap_to_disp(ctx, 0, lat_buf->src_buf_req); + + return 0; + +err: + if (ctx && pfc) { + /* always update read pointer */ + vdec_msg_queue_update_ube_rptr(&ctx->msg_queue, pfc->vsi.trans.dma_addr_end); + + if (fb) + ctx->dev->vdec_pdata->cap_to_disp(ctx, 1, lat_buf->src_buf_req); + } + return ret; +} + +const struct vdec_common_if vdec_vp9_slice_lat_if = { + .init = vdec_vp9_slice_init, + .decode = vdec_vp9_slice_lat_decode, + .get_param = vdec_vp9_slice_get_param, + .deinit = vdec_vp9_slice_deinit, +}; diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c index 05a5b240e906..27b4b35039cf 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c @@ -16,16 +16,27 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { + enum mtk_vdec_hw_arch hw_arch = ctx->dev->vdec_pdata->hw_arch; int ret = 0; switch (fourcc) { case V4L2_PIX_FMT_H264_SLICE: - ctx->dec_if = &vdec_h264_slice_if; + if (!ctx->dev->vdec_pdata->is_subdev_supported) { + ctx->dec_if = &vdec_h264_slice_if; + ctx->hw_id = MTK_VDEC_CORE; + } else { + ctx->dec_if = &vdec_h264_slice_multi_if; + ctx->hw_id = IS_VDEC_LAT_ARCH(hw_arch) ? MTK_VDEC_LAT0 : MTK_VDEC_CORE; + } break; case V4L2_PIX_FMT_H264: ctx->dec_if = &vdec_h264_if; ctx->hw_id = MTK_VDEC_CORE; break; + case V4L2_PIX_FMT_VP8_FRAME: + ctx->dec_if = &vdec_vp8_slice_if; + ctx->hw_id = MTK_VDEC_CORE; + break; case V4L2_PIX_FMT_VP8: ctx->dec_if = &vdec_vp8_if; ctx->hw_id = MTK_VDEC_CORE; @@ -34,15 +45,17 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) ctx->dec_if = &vdec_vp9_if; ctx->hw_id = MTK_VDEC_CORE; break; + case V4L2_PIX_FMT_VP9_FRAME: + ctx->dec_if = &vdec_vp9_slice_lat_if; + ctx->hw_id = MTK_VDEC_LAT0; + break; default: return -EINVAL; } - mtk_vdec_lock(ctx); - mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id); + mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id); ret = ctx->dec_if->init(ctx); - mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id); - mtk_vdec_unlock(ctx); + mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id); return ret; } @@ -70,15 +83,11 @@ int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, if (!ctx->drv_handle) return -EIO; - mtk_vdec_lock(ctx); - + mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id); mtk_vcodec_set_curr_ctx(ctx->dev, ctx, ctx->hw_id); - mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id); ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg); - mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id); mtk_vcodec_set_curr_ctx(ctx->dev, NULL, ctx->hw_id); - - mtk_vdec_unlock(ctx); + mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id); return ret; } @@ -103,11 +112,9 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx) if (!ctx->drv_handle) return; - mtk_vdec_lock(ctx); - mtk_vcodec_dec_clock_on(ctx->dev, ctx->hw_id); + mtk_vcodec_dec_enable_hardware(ctx, ctx->hw_id); ctx->dec_if->deinit(ctx->drv_handle); - mtk_vcodec_dec_clock_off(ctx->dev, ctx->hw_id); - mtk_vdec_unlock(ctx); + mtk_vcodec_dec_disable_hardware(ctx, ctx->hw_id); ctx->drv_handle = NULL; } diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h index d467e8af4a84..076306ff2dd4 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.h @@ -56,8 +56,11 @@ struct vdec_fb_node { extern const struct vdec_common_if vdec_h264_if; extern const struct vdec_common_if vdec_h264_slice_if; +extern const struct vdec_common_if vdec_h264_slice_multi_if; extern const struct vdec_common_if vdec_vp8_if; +extern const struct vdec_common_if vdec_vp8_slice_if; extern const struct vdec_common_if vdec_vp9_if; +extern const struct vdec_common_if vdec_vp9_slice_lat_if; /** * vdec_if_init() - initialize decode driver diff --git a/drivers/media/platform/mediatek/vcodec/vdec_ipi_msg.h b/drivers/media/platform/mediatek/vcodec/vdec_ipi_msg.h index bf54d6d9a857..47070be2a991 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_ipi_msg.h +++ b/drivers/media/platform/mediatek/vcodec/vdec_ipi_msg.h @@ -20,6 +20,7 @@ enum vdec_ipi_msgid { AP_IPIMSG_DEC_RESET = 0xA004, AP_IPIMSG_DEC_CORE = 0xA005, AP_IPIMSG_DEC_CORE_END = 0xA006, + AP_IPIMSG_DEC_GET_PARAM = 0xA007, VPU_IPIMSG_DEC_INIT_ACK = 0xB000, VPU_IPIMSG_DEC_START_ACK = 0xB001, @@ -28,6 +29,7 @@ enum vdec_ipi_msgid { VPU_IPIMSG_DEC_RESET_ACK = 0xB004, VPU_IPIMSG_DEC_CORE_ACK = 0xB005, VPU_IPIMSG_DEC_CORE_END_ACK = 0xB006, + VPU_IPIMSG_DEC_GET_PARAM_ACK = 0xB007, }; /** @@ -114,4 +116,38 @@ struct vdec_vpu_ipi_init_ack { uint32_t inst_id; }; +/** + * struct vdec_ap_ipi_get_param - for AP_IPIMSG_DEC_GET_PARAM + * @msg_id : AP_IPIMSG_DEC_GET_PARAM + * @inst_id : instance ID. Used if the ABI version >= 2. + * @data : picture information + * @param_type : get param type + * @codec_type : Codec fourcc + */ +struct vdec_ap_ipi_get_param { + u32 msg_id; + u32 inst_id; + u32 data[4]; + u32 param_type; + u32 codec_type; +}; + +/** + * struct vdec_vpu_ipi_get_param_ack - for VPU_IPIMSG_DEC_GET_PARAM_ACK + * @msg_id : VPU_IPIMSG_DEC_GET_PARAM_ACK + * @status : VPU execution result + * @ap_inst_addr : AP vcodec_vpu_inst instance address + * @data : picture information from SCP. + * @param_type : get param type + * @reserved : reserved param + */ +struct vdec_vpu_ipi_get_param_ack { + u32 msg_id; + s32 status; + u64 ap_inst_addr; + u32 data[4]; + u32 param_type; + u32 reserved; +}; + #endif diff --git a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c index 4b062a8128b4..ae500980ad45 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c @@ -212,11 +212,13 @@ static void vdec_msg_queue_core_work(struct work_struct *work) return; ctx = lat_buf->ctx; + mtk_vcodec_dec_enable_hardware(ctx, MTK_VDEC_CORE); mtk_vcodec_set_curr_ctx(dev, ctx, MTK_VDEC_CORE); lat_buf->core_decode(lat_buf); mtk_vcodec_set_curr_ctx(dev, NULL, MTK_VDEC_CORE); + mtk_vcodec_dec_disable_hardware(ctx, MTK_VDEC_CORE); vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf); if (!list_empty(&ctx->msg_queue.lat_ctx.ready_queue)) { diff --git a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h index b6ba66d3e026..c43d427f5f54 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h +++ b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.h @@ -43,6 +43,7 @@ struct vdec_msg_queue_ctx { * @wdma_err_addr: wdma error address used for lat hardware * @slice_bc_addr: slice bc address used for lat hardware * @ts_info: need to set timestamp from output to capture + * @src_buf_req: output buffer media request object * * @private_data: shared information used to lat and core hardware * @ctx: mtk vcodec context information @@ -54,6 +55,7 @@ struct vdec_lat_buf { struct mtk_vcodec_mem wdma_err_addr; struct mtk_vcodec_mem slice_bc_addr; struct vb2_v4l2_buffer ts_info; + struct media_request *src_buf_req; void *private_data; struct mtk_vcodec_ctx *ctx; diff --git a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c index dd35d2c5f920..35f4d5583084 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c @@ -6,6 +6,7 @@ #include "mtk_vcodec_drv.h" #include "mtk_vcodec_util.h" +#include "vdec_drv_if.h" #include "vdec_ipi_msg.h" #include "vdec_vpu_if.h" #include "mtk_vcodec_fw.h" @@ -33,8 +34,8 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) */ vpu->inst_id = 0xdeadbeef; - /* Firmware version field does not exist on MT8173. */ - if (vpu->ctx->dev->vdec_pdata->chip == MTK_MT8173) + /* VPU firmware does not contain a version field. */ + if (mtk_vcodec_fw_get_type(vpu->ctx->dev->fw_handler) == VPU) return; /* Check firmware version. */ @@ -54,6 +55,26 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg) } } +static void handle_get_param_msg_ack(const struct vdec_vpu_ipi_get_param_ack *msg) +{ + struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) + (unsigned long)msg->ap_inst_addr; + + mtk_vcodec_debug(vpu, "+ ap_inst_addr = 0x%llx", msg->ap_inst_addr); + + /* param_type is enum vdec_get_param_type */ + switch (msg->param_type) { + case GET_PARAM_PIC_INFO: + vpu->fb_sz[0] = msg->data[0]; + vpu->fb_sz[1] = msg->data[1]; + break; + default: + mtk_vcodec_err(vpu, "invalid get param type=%d", msg->param_type); + vpu->failure = 1; + break; + } +} + /* * vpu_dec_ipi_handler - Handler for VPU ipi message. * @@ -89,6 +110,9 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) case VPU_IPIMSG_DEC_CORE_END_ACK: break; + case VPU_IPIMSG_DEC_GET_PARAM_ACK: + handle_get_param_msg_ack(data); + break; default: mtk_vcodec_err(vpu, "invalid msg=%X", msg->msg_id); break; @@ -217,6 +241,31 @@ int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len) return err; } +int vpu_dec_get_param(struct vdec_vpu_inst *vpu, uint32_t *data, + unsigned int len, unsigned int param_type) +{ + struct vdec_ap_ipi_get_param msg; + int err; + + mtk_vcodec_debug_enter(vpu); + + if (len > ARRAY_SIZE(msg.data)) { + mtk_vcodec_err(vpu, "invalid len = %d\n", len); + return -EINVAL; + } + + memset(&msg, 0, sizeof(msg)); + msg.msg_id = AP_IPIMSG_DEC_GET_PARAM; + msg.inst_id = vpu->inst_id; + memcpy(msg.data, data, sizeof(unsigned int) * len); + msg.param_type = param_type; + msg.codec_type = vpu->codec_type; + + err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg)); + mtk_vcodec_debug(vpu, "- ret=%d", err); + return err; +} + int vpu_dec_core(struct vdec_vpu_inst *vpu) { return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_CORE); diff --git a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.h b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.h index 4cb3c7f5a3ad..0436bba91457 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.h +++ b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.h @@ -28,6 +28,8 @@ struct mtk_vcodec_ctx; * @wq : wait queue to wait VPU message ack * @handler : ipi handler for each decoder * @codec_type : use codec type to separate different codecs + * @capture_type: used capture type to separate different capture format + * @fb_sz : frame buffer size of each plane */ struct vdec_vpu_inst { int id; @@ -42,6 +44,8 @@ struct vdec_vpu_inst { wait_queue_head_t wq; mtk_vcodec_ipi_handler handler; unsigned int codec_type; + unsigned int capture_type; + unsigned int fb_sz[2]; }; /** @@ -104,4 +108,15 @@ int vpu_dec_core(struct vdec_vpu_inst *vpu); */ int vpu_dec_core_end(struct vdec_vpu_inst *vpu); +/** + * vpu_dec_get_param - get param from scp + * + * @vpu : instance for vdec_vpu_inst + * @data: meta data to pass bitstream info to VPU decoder + * @len : meta data length + * @param_type : get param type + */ +int vpu_dec_get_param(struct vdec_vpu_inst *vpu, uint32_t *data, + unsigned int len, unsigned int param_type); + #endif diff --git a/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c b/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c index e7899d8a3e4e..d3570c4c177d 100644 --- a/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c +++ b/drivers/media/platform/mediatek/vcodec/venc_vpu_if.c @@ -18,7 +18,7 @@ static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data) msg->vpu_inst_addr); /* Firmware version field value is unspecified on MT8173. */ - if (vpu->ctx->dev->venc_pdata->chip == MTK_MT8173) + if (mtk_vcodec_fw_get_type(vpu->ctx->dev->fw_handler) == VPU) return; /* Check firmware version. */ diff --git a/drivers/media/platform/nvidia/tegra-vde/h264.c b/drivers/media/platform/nvidia/tegra-vde/h264.c index d8e5534e80c8..88f81a134ba0 100644 --- a/drivers/media/platform/nvidia/tegra-vde/h264.c +++ b/drivers/media/platform/nvidia/tegra-vde/h264.c @@ -45,9 +45,9 @@ struct tegra_vde_h264_decoder_ctx { }; struct h264_reflists { - u8 p[V4L2_H264_NUM_DPB_ENTRIES]; - u8 b0[V4L2_H264_NUM_DPB_ENTRIES]; - u8 b1[V4L2_H264_NUM_DPB_ENTRIES]; + struct v4l2_h264_reference p[V4L2_H264_NUM_DPB_ENTRIES]; + struct v4l2_h264_reference b0[V4L2_H264_NUM_DPB_ENTRIES]; + struct v4l2_h264_reference b1[V4L2_H264_NUM_DPB_ENTRIES]; }; static int tegra_vde_wait_mbe(struct tegra_vde *vde) @@ -765,10 +765,10 @@ static int tegra_vde_h264_setup_frames(struct tegra_ctx *ctx, struct tegra_m2m_buffer *tb = vb_to_tegra_buf(&dst->vb2_buf); struct tegra_ctx_h264 *h = &ctx->h264; struct v4l2_h264_reflist_builder b; + struct v4l2_h264_reference *dpb_id; struct h264_reflists reflists; struct vb2_buffer *ref; unsigned int i; - u8 *dpb_id; int err; /* @@ -811,14 +811,16 @@ static int tegra_vde_h264_setup_frames(struct tegra_ctx *ctx, } for (i = 0; i < b.num_valid; i++) { - ref = get_ref_buf(ctx, dst, dpb_id[i]); + int dpb_idx = dpb_id[i].index; - err = tegra_vde_h264_setup_frame(ctx, h264, &b, ref, dpb_id[i], + ref = get_ref_buf(ctx, dst, dpb_idx); + + err = tegra_vde_h264_setup_frame(ctx, h264, &b, ref, dpb_idx, h264->dpb_frames_nb++); if (err) return err; - if (b.refs[dpb_id[i]].pic_order_count < b.cur_pic_order_count) + if (b.refs[dpb_idx].top_field_order_cnt < b.cur_pic_order_count) h264->dpb_ref_frames_with_earlier_poc_nb++; } @@ -880,6 +882,9 @@ static int tegra_vde_h264_setup_context(struct tegra_ctx *ctx, if (h->pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) return -EOPNOTSUPP; + if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) + return -EOPNOTSUPP; + if (h->sps->profile_idc == 66) h264->baseline_profile = 1; diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig index 5afa373e534f..1ac0a6e91111 100644 --- a/drivers/media/platform/nxp/Kconfig +++ b/drivers/media/platform/nxp/Kconfig @@ -11,7 +11,6 @@ config VIDEO_IMX_MIPI_CSIS select MEDIA_CONTROLLER select V4L2_FWNODE select VIDEO_V4L2_SUBDEV_API - default n help Video4Linux2 sub-device driver for the MIPI CSI-2 CSIS receiver v3.3/v3.6.3 found on some i.MX7 and i.MX8 SoCs. @@ -21,7 +20,6 @@ config VIDEO_VIU depends on V4L_PLATFORM_DRIVERS depends on VIDEO_DEV && (PPC_MPC512x || COMPILE_TEST) && I2C select VIDEOBUF_DMA_CONTIG - default y help Support for Freescale VIU video driver. This device captures video data, or overlays video on DIU frame buffer. diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h index ae70d3a0dc24..d838e875616c 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h @@ -102,11 +102,11 @@ enum mxc_jpeg_image_format { MXC_JPEG_INVALID = -1, MXC_JPEG_YUV420 = 0x0, /* 2 Plannar, Y=1st plane UV=2nd plane */ MXC_JPEG_YUV422 = 0x1, /* 1 Plannar, YUYV sequence */ - MXC_JPEG_RGB = 0x2, /* RGBRGB packed format */ + MXC_JPEG_BGR = 0x2, /* BGR packed format */ MXC_JPEG_YUV444 = 0x3, /* 1 Plannar, YUVYUV sequence */ MXC_JPEG_GRAY = 0x4, /* Y8 or Y12 or Single Component */ MXC_JPEG_RESERVED = 0x5, - MXC_JPEG_ARGB = 0x6, + MXC_JPEG_ABGR = 0x6, }; #include "mxc-jpeg.h" diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index d1ec1f4b506b..f36b512bae51 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -8,7 +8,7 @@ * Baseline and extended sequential jpeg decoding is supported. * Progressive jpeg decoding is not supported by the IP. * Supports encode and decode of various formats: - * YUV444, YUV422, YUV420, RGB, ARGB, Gray + * YUV444, YUV422, YUV420, BGR, ABGR, Gray * YUV420 is the only multi-planar format supported. * Minimum resolution is 64 x 64, maximum 8192 x 8192. * To achieve 8192 x 8192, modify in defconfig: CONFIG_CMA_SIZE_MBYTES=320 @@ -73,8 +73,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .flags = MXC_JPEG_FMT_TYPE_ENC, }, { - .name = "RGB", /*RGBRGB packed format*/ - .fourcc = V4L2_PIX_FMT_RGB24, + .name = "BGR", /*BGR packed format*/ + .fourcc = V4L2_PIX_FMT_BGR24, .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 3, .depth = 24, @@ -82,10 +82,11 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { - .name = "ARGB", /* ARGBARGB packed format */ - .fourcc = V4L2_PIX_FMT_ARGB32, + .name = "ABGR", /* ABGR packed format */ + .fourcc = V4L2_PIX_FMT_ABGR32, .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 4, .depth = 32, @@ -93,6 +94,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { .name = "YUV420", /* 1st plane = Y, 2nd plane = UV */ @@ -104,6 +106,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 4, .v_align = 4, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { .name = "YUV422", /* YUYV */ @@ -115,6 +118,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 4, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { .name = "YUV444", /* YUVYUV */ @@ -126,6 +130,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, { .name = "Gray", /* Gray (Y8/Y12) or Single Comp */ @@ -137,6 +142,7 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, }, }; @@ -309,6 +315,9 @@ struct mxc_jpeg_src_buf { /* mxc-jpeg specific */ bool dht_needed; bool jpeg_parse_error; + const struct mxc_jpeg_fmt *fmt; + int w; + int h; }; static inline struct mxc_jpeg_src_buf *vb2_to_mxc_buf(struct vb2_buffer *vb) @@ -321,6 +330,9 @@ static unsigned int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-3)"); +static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision); +static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q); + static void _bswap16(u16 *a) { *a = ((*a & 0x00FF) << 8) | ((*a & 0xFF00) >> 8); @@ -408,10 +420,10 @@ static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(u32 fourcc) return MXC_JPEG_YUV420; case V4L2_PIX_FMT_YUV24: return MXC_JPEG_YUV444; - case V4L2_PIX_FMT_RGB24: - return MXC_JPEG_RGB; - case V4L2_PIX_FMT_ARGB32: - return MXC_JPEG_ARGB; + case V4L2_PIX_FMT_BGR24: + return MXC_JPEG_BGR; + case V4L2_PIX_FMT_ABGR32: + return MXC_JPEG_ABGR; default: return MXC_JPEG_INVALID; } @@ -684,11 +696,11 @@ static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof, sof->comp[0].h = 0x2; break; case V4L2_PIX_FMT_YUV24: - case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: default: sof->components_no = 3; break; - case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_ABGR32: sof->components_no = 4; break; case V4L2_PIX_FMT_GREY: @@ -716,11 +728,11 @@ static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos, sos->components_no = 3; break; case V4L2_PIX_FMT_YUV24: - case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: default: sos->components_no = 3; break; - case V4L2_PIX_FMT_ARGB32: + case V4L2_PIX_FMT_ABGR32: sos->components_no = 4; break; case V4L2_PIX_FMT_GREY: @@ -751,8 +763,8 @@ static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr, memcpy(cfg + offset, jpeg_soi, ARRAY_SIZE(jpeg_soi)); offset += ARRAY_SIZE(jpeg_soi); - if (fourcc == V4L2_PIX_FMT_RGB24 || - fourcc == V4L2_PIX_FMT_ARGB32) { + if (fourcc == V4L2_PIX_FMT_BGR24 || + fourcc == V4L2_PIX_FMT_ABGR32) { memcpy(cfg + offset, jpeg_app14, sizeof(jpeg_app14)); offset += sizeof(jpeg_app14); } else { @@ -916,6 +928,67 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, mxc_jpeg_set_desc(cfg_desc_handle, reg, slot); } +static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, + struct mxc_jpeg_src_buf *jpeg_src_buf) +{ + struct device *dev = ctx->mxc_jpeg->dev; + struct mxc_jpeg_q_data *q_data_cap; + + if (!jpeg_src_buf->fmt) + return false; + + q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (q_data_cap->fmt != jpeg_src_buf->fmt || + q_data_cap->w != jpeg_src_buf->w || + q_data_cap->h != jpeg_src_buf->h) { + dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%c%c%c%c\n", + q_data_cap->w, q_data_cap->h, + jpeg_src_buf->w, jpeg_src_buf->h, + (jpeg_src_buf->fmt->fourcc & 0xff), + (jpeg_src_buf->fmt->fourcc >> 8) & 0xff, + (jpeg_src_buf->fmt->fourcc >> 16) & 0xff, + (jpeg_src_buf->fmt->fourcc >> 24) & 0xff); + + /* + * set-up the capture queue with the pixelformat and resolution + * detected from the jpeg output stream + */ + q_data_cap->w = jpeg_src_buf->w; + q_data_cap->h = jpeg_src_buf->h; + q_data_cap->fmt = jpeg_src_buf->fmt; + q_data_cap->w_adjusted = q_data_cap->w; + q_data_cap->h_adjusted = q_data_cap->h; + + /* + * align up the resolution for CAST IP, + * but leave the buffer resolution unchanged + */ + v4l_bound_align_image(&q_data_cap->w_adjusted, + q_data_cap->w_adjusted, /* adjust up */ + MXC_JPEG_MAX_WIDTH, + q_data_cap->fmt->h_align, + &q_data_cap->h_adjusted, + q_data_cap->h_adjusted, /* adjust up */ + MXC_JPEG_MAX_HEIGHT, + q_data_cap->fmt->v_align, + 0); + + /* setup bytesperline/sizeimage for capture queue */ + mxc_jpeg_bytesperline(q_data_cap, jpeg_src_buf->fmt->precision); + mxc_jpeg_sizeimage(q_data_cap); + notify_src_chg(ctx); + ctx->source_change = 1; + } + return ctx->source_change ? true : false; +} + +static int mxc_jpeg_job_ready(void *priv) +{ + struct mxc_jpeg_ctx *ctx = priv; + + return ctx->source_change ? 0 : 1; +} + static void mxc_jpeg_device_run(void *priv) { struct mxc_jpeg_ctx *ctx = priv; @@ -963,6 +1036,13 @@ static void mxc_jpeg_device_run(void *priv) return; } + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) { + if (ctx->source_change || mxc_jpeg_source_change(ctx, jpeg_src_buf)) { + spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags); + v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx); + return; + } + } mxc_jpeg_enable(reg); mxc_jpeg_set_l_endian(reg, 1); @@ -1009,6 +1089,7 @@ static void mxc_jpeg_set_last_buffer_dequeued(struct mxc_jpeg_ctx *ctx) q->last_buffer_dequeued = true; wake_up(&q->done_wq); ctx->stopped = 0; + ctx->header_parsed = false; } static int mxc_jpeg_decoder_cmd(struct file *file, void *priv, @@ -1081,6 +1162,8 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, /* Handle CREATE_BUFS situation - *nplanes != 0 */ if (*nplanes) { + if (*nplanes != q_data->fmt->colplanes) + return -EINVAL; for (i = 0; i < *nplanes; i++) { if (sizes[i] < q_data->sizeimage[i]) return -EINVAL; @@ -1102,6 +1185,8 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, q->type); int ret; + if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(q->type)) + ctx->source_change = 0; dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx); q_data->sequence = 0; @@ -1175,14 +1260,17 @@ static u32 mxc_jpeg_get_image_format(struct device *dev, for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) if (mxc_formats[i].subsampling == header->frame.subsampling && - mxc_formats[i].nc == header->frame.num_components) { + mxc_formats[i].nc == header->frame.num_components && + mxc_formats[i].precision == header->frame.precision) { fourcc = mxc_formats[i].fourcc; break; } if (fourcc == 0) { - dev_err(dev, "Could not identify image format nc=%d, subsampling=%d\n", + dev_err(dev, + "Could not identify image format nc=%d, subsampling=%d, precision=%d\n", header->frame.num_components, - header->frame.subsampling); + header->frame.subsampling, + header->frame.precision); return fourcc; } /* @@ -1190,9 +1278,9 @@ static u32 mxc_jpeg_get_image_format(struct device *dev, * encoded with 3 components have RGB colorspace, see Recommendation * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding */ - if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_RGB24) { + if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_BGR24) { if (header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB) - fourcc = V4L2_PIX_FMT_RGB24; + fourcc = V4L2_PIX_FMT_BGR24; else fourcc = V4L2_PIX_FMT_YUV24; } @@ -1200,26 +1288,29 @@ static u32 mxc_jpeg_get_image_format(struct device *dev, return fourcc; } -static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, - u32 precision) +static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision) { /* Bytes distance between the leftmost pixels in two adjacent lines */ if (q->fmt->fourcc == V4L2_PIX_FMT_JPEG) { /* bytesperline unused for compressed formats */ q->bytesperline[0] = 0; q->bytesperline[1] = 0; - } else if (q->fmt->fourcc == V4L2_PIX_FMT_NV12M) { + } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420) { /* When the image format is planar the bytesperline value * applies to the first plane and is divided by the same factor * as the width field for the other planes */ - q->bytesperline[0] = q->w * (precision / 8) * - (q->fmt->depth / 8); + q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8); q->bytesperline[1] = q->bytesperline[0]; + } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) { + q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * 2; + q->bytesperline[1] = 0; + } else if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_444) { + q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8) * q->fmt->nc; + q->bytesperline[1] = 0; } else { - /* single plane formats */ - q->bytesperline[0] = q->w * (precision / 8) * - (q->fmt->depth / 8); + /* grayscale */ + q->bytesperline[0] = q->w * DIV_ROUND_UP(precision, 8); q->bytesperline[1] = 0; } } @@ -1245,17 +1336,17 @@ static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q) } } -static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, - u8 *src_addr, u32 size, bool *dht_needed) +static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) { struct device *dev = ctx->mxc_jpeg->dev; - struct mxc_jpeg_q_data *q_data_out, *q_data_cap; - enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - bool src_chg = false; + struct mxc_jpeg_q_data *q_data_out; u32 fourcc; struct v4l2_jpeg_header header; struct mxc_jpeg_sof *psof = NULL; struct mxc_jpeg_sos *psos = NULL; + struct mxc_jpeg_src_buf *jpeg_src_buf = vb2_to_mxc_buf(vb); + u8 *src_addr = (u8 *)vb2_plane_vaddr(vb, 0); + u32 size = vb2_get_plane_payload(vb, 0); int ret; memset(&header, 0, sizeof(header)); @@ -1266,7 +1357,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, } /* if DHT marker present, no need to inject default one */ - *dht_needed = (header.num_dht == 0); + jpeg_src_buf->dht_needed = (header.num_dht == 0); q_data_out = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); @@ -1274,16 +1365,15 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, dev_warn(dev, "Invalid user resolution 0x0"); dev_warn(dev, "Keeping resolution from JPEG: %dx%d", header.frame.width, header.frame.height); - q_data_out->w = header.frame.width; - q_data_out->h = header.frame.height; } else if (header.frame.width != q_data_out->w || header.frame.height != q_data_out->h) { dev_err(dev, "Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)", header.frame.width, header.frame.height, q_data_out->w, q_data_out->h); - return -EINVAL; } + q_data_out->w = header.frame.width; + q_data_out->h = header.frame.height; if (header.frame.width % 8 != 0 || header.frame.height % 8 != 0) { dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n", header.frame.width, header.frame.height); @@ -1316,51 +1406,13 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, if (fourcc == 0) return -EINVAL; - /* - * set-up the capture queue with the pixelformat and resolution - * detected from the jpeg output stream - */ - q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type); - if (q_data_cap->w != header.frame.width || - q_data_cap->h != header.frame.height) - src_chg = true; - q_data_cap->w = header.frame.width; - q_data_cap->h = header.frame.height; - q_data_cap->fmt = mxc_jpeg_find_format(ctx, fourcc); - q_data_cap->w_adjusted = q_data_cap->w; - q_data_cap->h_adjusted = q_data_cap->h; - /* - * align up the resolution for CAST IP, - * but leave the buffer resolution unchanged - */ - v4l_bound_align_image(&q_data_cap->w_adjusted, - q_data_cap->w_adjusted, /* adjust up */ - MXC_JPEG_MAX_WIDTH, - q_data_cap->fmt->h_align, - &q_data_cap->h_adjusted, - q_data_cap->h_adjusted, /* adjust up */ - MXC_JPEG_MAX_HEIGHT, - q_data_cap->fmt->v_align, - 0); - dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%c%c%c%c\n", - q_data_cap->w, q_data_cap->h, - q_data_cap->w_adjusted, q_data_cap->h_adjusted, - (fourcc & 0xff), - (fourcc >> 8) & 0xff, - (fourcc >> 16) & 0xff, - (fourcc >> 24) & 0xff); - - /* setup bytesperline/sizeimage for capture queue */ - mxc_jpeg_bytesperline(q_data_cap, header.frame.precision); - mxc_jpeg_sizeimage(q_data_cap); + jpeg_src_buf->fmt = mxc_jpeg_find_format(ctx, fourcc); + jpeg_src_buf->w = header.frame.width; + jpeg_src_buf->h = header.frame.height; + ctx->header_parsed = true; - /* - * if the CAPTURE format was updated with new values, regardless of - * whether they match the values set by the client or not, signal - * a source change event - */ - if (src_chg) - notify_src_chg(ctx); + if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) + mxc_jpeg_source_change(ctx, jpeg_src_buf); return 0; } @@ -1381,10 +1433,7 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb) jpeg_src_buf = vb2_to_mxc_buf(vb); jpeg_src_buf->jpeg_parse_error = false; - ret = mxc_jpeg_parse(ctx, - (u8 *)vb2_plane_vaddr(vb, 0), - vb2_get_plane_payload(vb, 0), - &jpeg_src_buf->dht_needed); + ret = mxc_jpeg_parse(ctx, vb); if (ret) jpeg_src_buf->jpeg_parse_error = true; @@ -1422,7 +1471,6 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) i, vb2_plane_size(vb, i), sizeimage); return -EINVAL; } - vb2_set_plane_payload(vb, i, sizeimage); } return 0; } @@ -1440,6 +1488,7 @@ static void mxc_jpeg_buf_finish(struct vb2_buffer *vb) if (list_empty(&q->done_list)) { vbuf->flags |= V4L2_BUF_FLAG_LAST; ctx->stopped = 0; + ctx->header_parsed = false; } } @@ -1470,7 +1519,6 @@ static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; src_vq->lock = &ctx->mxc_jpeg->lock; src_vq->dev = ctx->mxc_jpeg->dev; - src_vq->allow_zero_bytesused = 1; /* keep old userspace apps working */ ret = vb2_queue_init(src_vq); if (ret) @@ -1510,7 +1558,7 @@ static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx) q[i]->h = MXC_JPEG_DEFAULT_HEIGHT; q[i]->w_adjusted = MXC_JPEG_DEFAULT_WIDTH; q[i]->h_adjusted = MXC_JPEG_DEFAULT_HEIGHT; - mxc_jpeg_bytesperline(q[i], 8); + mxc_jpeg_bytesperline(q[i], q[i]->fmt->precision); mxc_jpeg_sizeimage(q[i]); } } @@ -1569,12 +1617,8 @@ free: static int mxc_jpeg_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file); - strscpy(cap->driver, MXC_JPEG_NAME " codec", sizeof(cap->driver)); strscpy(cap->card, MXC_JPEG_NAME " codec", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(mxc_jpeg->dev)); cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; @@ -1585,26 +1629,42 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type); - if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) + if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) { return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, MXC_JPEG_FMT_TYPE_ENC); - else + } else if (!ctx->header_parsed) { return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, MXC_JPEG_FMT_TYPE_RAW); + } else { + /* For the decoder CAPTURE queue, only enumerate the raw formats + * supported for the format currently active on OUTPUT + * (more precisely what was propagated on capture queue + * after jpeg parse on the output buffer) + */ + if (f->index) + return -EINVAL; + f->pixelformat = q_data->fmt->fourcc; + strscpy(f->description, q_data->fmt->name, sizeof(f->description)); + return 0; + } } static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv, struct v4l2_fmtdesc *f) { struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + u32 type = ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? MXC_JPEG_FMT_TYPE_ENC : + MXC_JPEG_FMT_TYPE_RAW; + int ret; + ret = enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, type); + if (ret) + return ret; if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) - return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, - MXC_JPEG_FMT_TYPE_ENC); - else - return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, - MXC_JPEG_FMT_TYPE_RAW); + f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION; + return 0; } static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fmt, @@ -1652,7 +1712,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fm } /* calculate bytesperline & sizeimage into the tmp_q */ - mxc_jpeg_bytesperline(&tmp_q, 8); + mxc_jpeg_bytesperline(&tmp_q, fmt->precision); mxc_jpeg_sizeimage(&tmp_q); /* adjust user format according to our calculations */ @@ -1819,12 +1879,40 @@ static int mxc_jpeg_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { int ret; + struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv); + struct vb2_queue *dst_vq; + struct mxc_jpeg_q_data *q_data_cap; + enum v4l2_buf_type cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + struct v4l2_format fc; ret = mxc_jpeg_try_fmt_vid_out(file, priv, f); if (ret) return ret; - return mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); + ret = mxc_jpeg_s_fmt(mxc_jpeg_fh_to_ctx(priv), f); + if (ret) + return ret; + + if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE) + return 0; + + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, cap_type); + if (!dst_vq) + return -EINVAL; + + if (vb2_is_busy(dst_vq)) + return 0; + + q_data_cap = mxc_jpeg_get_q_data(ctx, cap_type); + if (q_data_cap->w == f->fmt.pix_mp.width && q_data_cap->h == f->fmt.pix_mp.height) + return 0; + memset(&fc, 0, sizeof(fc)); + fc.type = cap_type; + fc.fmt.pix_mp.pixelformat = q_data_cap->fmt->fourcc; + fc.fmt.pix_mp.width = f->fmt.pix_mp.width; + fc.fmt.pix_mp.height = f->fmt.pix_mp.height; + + return mxc_jpeg_s_fmt_vid_cap(file, priv, &fc); } static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, @@ -1962,6 +2050,7 @@ static const struct v4l2_file_operations mxc_jpeg_fops = { }; static const struct v4l2_m2m_ops mxc_jpeg_m2m_ops = { + .job_ready = mxc_jpeg_job_ready, .device_run = mxc_jpeg_device_run, }; @@ -2213,9 +2302,33 @@ static int mxc_jpeg_runtime_suspend(struct device *dev) } #endif +#ifdef CONFIG_PM_SLEEP +static int mxc_jpeg_suspend(struct device *dev) +{ + struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); + + v4l2_m2m_suspend(jpeg->m2m_dev); + return pm_runtime_force_suspend(dev); +} + +static int mxc_jpeg_resume(struct device *dev) +{ + struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; + + v4l2_m2m_resume(jpeg->m2m_dev); + return ret; +} +#endif + static const struct dev_pm_ops mxc_jpeg_pm_ops = { SET_RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend, mxc_jpeg_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume) }; static int mxc_jpeg_remove(struct platform_device *pdev) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index f53f004ba851..760eaf5387a1 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -17,7 +17,7 @@ #define MXC_JPEG_FMT_TYPE_RAW 1 #define MXC_JPEG_DEFAULT_WIDTH 1280 #define MXC_JPEG_DEFAULT_HEIGHT 720 -#define MXC_JPEG_DEFAULT_PFMT V4L2_PIX_FMT_RGB24 +#define MXC_JPEG_DEFAULT_PFMT V4L2_PIX_FMT_BGR24 #define MXC_JPEG_MIN_WIDTH 64 #define MXC_JPEG_MIN_HEIGHT 64 #define MXC_JPEG_MAX_WIDTH 0x2000 @@ -49,6 +49,7 @@ enum mxc_jpeg_mode { * @h_align: horizontal alignment order (align to 2^h_align) * @v_align: vertical alignment order (align to 2^v_align) * @flags: flags describing format applicability + * @precision: jpeg sample precision */ struct mxc_jpeg_fmt { const char *name; @@ -60,6 +61,7 @@ struct mxc_jpeg_fmt { int h_align; int v_align; u32 flags; + u8 precision; }; struct mxc_jpeg_desc { @@ -93,6 +95,8 @@ struct mxc_jpeg_ctx { unsigned int stopping; unsigned int stopped; unsigned int slot; + unsigned int source_change; + bool header_parsed; }; struct mxc_jpeg_slot_data { diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 0a72734db55e..80b1c021d14a 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -243,12 +243,6 @@ #define MIPI_CSI2_DATA_TYPE_RAW14 0x2d #define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x)) -enum { - ST_POWERED = 1, - ST_STREAMING = 2, - ST_SUSPENDED = 4, -}; - struct mipi_csis_event { bool debug; u32 mask; @@ -310,7 +304,7 @@ struct mipi_csis_info { unsigned int num_clocks; }; -struct csi_state { +struct mipi_csis_device { struct device *dev; void __iomem *regs; struct clk_bulk_data *clks; @@ -328,10 +322,9 @@ struct csi_state { u32 hs_settle; u32 clk_settle; - struct mutex lock; /* Protect csis_fmt, format_mbus and state */ + struct mutex lock; /* Protect csis_fmt and format_mbus */ const struct csis_pix_format *csis_fmt; struct v4l2_mbus_framefmt format_mbus[CSIS_PADS_NUM]; - u32 state; spinlock_t slock; /* Protect events */ struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; @@ -470,6 +463,34 @@ static const struct csis_pix_format mipi_csis_formats[] = { .output = MEDIA_BUS_FMT_SRGGB14_1X14, .data_type = MIPI_CSI2_DATA_TYPE_RAW14, .width = 14, + }, + /* JPEG */ + { + .code = MEDIA_BUS_FMT_JPEG_1X8, + .output = MEDIA_BUS_FMT_JPEG_1X8, + /* + * Map JPEG_1X8 to the RAW8 datatype. + * + * The CSI-2 specification suggests in Annex A "JPEG8 Data + * Format (informative)" to transmit JPEG data using one of the + * Data Types aimed to represent arbitrary data, such as the + * "User Defined Data Type 1" (0x30). + * + * However, when configured with a User Defined Data Type, the + * CSIS outputs data in quad pixel mode regardless of the mode + * selected in the MIPI_CSIS_ISP_CONFIG_CH register. Neither of + * the IP cores connected to the CSIS in i.MX SoCs (CSI bridge + * or ISI) support quad pixel mode, so this will never work in + * practice. + * + * Some sensors (such as the OV5640) send JPEG data using the + * RAW8 data type. This is usable and works, so map the JPEG + * format to RAW8. If the CSIS ends up being integrated in an + * SoC that can support quad pixel mode, this will have to be + * revisited. + */ + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .width = 8, } }; @@ -487,59 +508,60 @@ static const struct csis_pix_format *find_csis_format(u32 code) * Hardware configuration */ -static inline u32 mipi_csis_read(struct csi_state *state, u32 reg) +static inline u32 mipi_csis_read(struct mipi_csis_device *csis, u32 reg) { - return readl(state->regs + reg); + return readl(csis->regs + reg); } -static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val) +static inline void mipi_csis_write(struct mipi_csis_device *csis, u32 reg, + u32 val) { - writel(val, state->regs + reg); + writel(val, csis->regs + reg); } -static void mipi_csis_enable_interrupts(struct csi_state *state, bool on) +static void mipi_csis_enable_interrupts(struct mipi_csis_device *csis, bool on) { - mipi_csis_write(state, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0); - mipi_csis_write(state, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0); + mipi_csis_write(csis, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0); + mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0); } -static void mipi_csis_sw_reset(struct csi_state *state) +static void mipi_csis_sw_reset(struct mipi_csis_device *csis) { - u32 val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + u32 val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, + mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_RESET); usleep_range(10, 20); } -static void mipi_csis_system_enable(struct csi_state *state, int on) +static void mipi_csis_system_enable(struct mipi_csis_device *csis, int on) { u32 val, mask; - val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); if (on) val |= MIPI_CSIS_CMN_CTRL_ENABLE; else val &= ~MIPI_CSIS_CMN_CTRL_ENABLE; - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); + mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val); - val = mipi_csis_read(state, MIPI_CSIS_DPHY_CMN_CTRL); + val = mipi_csis_read(csis, MIPI_CSIS_DPHY_CMN_CTRL); val &= ~MIPI_CSIS_DPHY_CMN_CTRL_ENABLE; if (on) { - mask = (1 << (state->bus.num_data_lanes + 1)) - 1; + mask = (1 << (csis->bus.num_data_lanes + 1)) - 1; val |= (mask & MIPI_CSIS_DPHY_CMN_CTRL_ENABLE); } - mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, val); + mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val); } -/* Called with the state.lock mutex held */ -static void __mipi_csis_set_format(struct csi_state *state) +/* Called with the csis.lock mutex held */ +static void __mipi_csis_set_format(struct mipi_csis_device *csis) { - struct v4l2_mbus_framefmt *mf = &state->format_mbus[CSIS_PAD_SINK]; + struct v4l2_mbus_framefmt *mf = &csis->format_mbus[CSIS_PAD_SINK]; u32 val; /* Color format */ - val = mipi_csis_read(state, MIPI_CSIS_ISP_CONFIG_CH(0)); + val = mipi_csis_read(csis, MIPI_CSIS_ISP_CONFIG_CH(0)); val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK | MIPI_CSIS_ISPCFG_PIXEL_MASK); @@ -556,28 +578,28 @@ static void __mipi_csis_set_format(struct csi_state *state) * * TODO: Verify which other formats require DUAL (or QUAD) modes. */ - if (state->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) + if (csis->csis_fmt->data_type == MIPI_CSI2_DATA_TYPE_YUV422_8) val |= MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; - val |= MIPI_CSIS_ISPCFG_FMT(state->csis_fmt->data_type); - mipi_csis_write(state, MIPI_CSIS_ISP_CONFIG_CH(0), val); + val |= MIPI_CSIS_ISPCFG_FMT(csis->csis_fmt->data_type); + mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val); /* Pixel resolution */ val = mf->width | (mf->height << 16); - mipi_csis_write(state, MIPI_CSIS_ISP_RESOL_CH(0), val); + mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), val); } -static int mipi_csis_calculate_params(struct csi_state *state) +static int mipi_csis_calculate_params(struct mipi_csis_device *csis) { s64 link_freq; u32 lane_rate; /* Calculate the line rate from the pixel rate. */ - link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler, - state->csis_fmt->width, - state->bus.num_data_lanes * 2); + link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler, + csis->csis_fmt->width, + csis->bus.num_data_lanes * 2); if (link_freq < 0) { - dev_err(state->dev, "Unable to obtain link frequency: %d\n", + dev_err(csis->dev, "Unable to obtain link frequency: %d\n", (int)link_freq); return link_freq; } @@ -585,7 +607,7 @@ static int mipi_csis_calculate_params(struct csi_state *state) lane_rate = link_freq * 2; if (lane_rate < 80000000 || lane_rate > 1500000000) { - dev_dbg(state->dev, "Out-of-bound lane rate %u\n", lane_rate); + dev_dbg(csis->dev, "Out-of-bound lane rate %u\n", lane_rate); return -EINVAL; } @@ -595,57 +617,57 @@ static int mipi_csis_calculate_params(struct csi_state *state) * (which is documented as corresponding to CSI-2 v0.87 to v1.00) until * we figure out how to compute it correctly. */ - state->hs_settle = (lane_rate - 5000000) / 45000000; - state->clk_settle = 0; + csis->hs_settle = (lane_rate - 5000000) / 45000000; + csis->clk_settle = 0; - dev_dbg(state->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n", - lane_rate, state->clk_settle, state->hs_settle); + dev_dbg(csis->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n", + lane_rate, csis->clk_settle, csis->hs_settle); - if (state->debug.hs_settle < 0xff) { - dev_dbg(state->dev, "overriding Ths_settle with %u\n", - state->debug.hs_settle); - state->hs_settle = state->debug.hs_settle; + if (csis->debug.hs_settle < 0xff) { + dev_dbg(csis->dev, "overriding Ths_settle with %u\n", + csis->debug.hs_settle); + csis->hs_settle = csis->debug.hs_settle; } - if (state->debug.clk_settle < 4) { - dev_dbg(state->dev, "overriding Tclk_settle with %u\n", - state->debug.clk_settle); - state->clk_settle = state->debug.clk_settle; + if (csis->debug.clk_settle < 4) { + dev_dbg(csis->dev, "overriding Tclk_settle with %u\n", + csis->debug.clk_settle); + csis->clk_settle = csis->debug.clk_settle; } return 0; } -static void mipi_csis_set_params(struct csi_state *state) +static void mipi_csis_set_params(struct mipi_csis_device *csis) { - int lanes = state->bus.num_data_lanes; + int lanes = csis->bus.num_data_lanes; u32 val; - val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK; val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET; - if (state->info->version == MIPI_CSIS_V3_3) + if (csis->info->version == MIPI_CSIS_V3_3) val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); + mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val); - __mipi_csis_set_format(state); + __mipi_csis_set_format(csis); - mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, - MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle) | - MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(state->clk_settle)); + mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, + MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) | + MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(csis->clk_settle)); val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET) | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET) | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET); - mipi_csis_write(state, MIPI_CSIS_ISP_SYNC_CH(0), val); + mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(0), val); - val = mipi_csis_read(state, MIPI_CSIS_CLK_CTRL); + val = mipi_csis_read(csis, MIPI_CSIS_CLK_CTRL); val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC; val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15); val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK; - mipi_csis_write(state, MIPI_CSIS_CLK_CTRL, val); + mipi_csis_write(csis, MIPI_CSIS_CLK_CTRL, val); - mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_L, + mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_L, MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_715MV | MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_FREQ_3MHZ | MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_2V | @@ -653,95 +675,95 @@ static void mipi_csis_set_params(struct csi_state *state) MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_715MV | MIPI_CSIS_DPHY_BCTRL_L_LP_CD_HYS_60MV | MIPI_CSIS_DPHY_BCTRL_L_B_DPHYCTRL(20000000)); - mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_H, 0); + mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_H, 0); /* Update the shadow register. */ - val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, + val = mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); + mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL); } -static int mipi_csis_clk_enable(struct csi_state *state) +static int mipi_csis_clk_enable(struct mipi_csis_device *csis) { - return clk_bulk_prepare_enable(state->info->num_clocks, state->clks); + return clk_bulk_prepare_enable(csis->info->num_clocks, csis->clks); } -static void mipi_csis_clk_disable(struct csi_state *state) +static void mipi_csis_clk_disable(struct mipi_csis_device *csis) { - clk_bulk_disable_unprepare(state->info->num_clocks, state->clks); + clk_bulk_disable_unprepare(csis->info->num_clocks, csis->clks); } -static int mipi_csis_clk_get(struct csi_state *state) +static int mipi_csis_clk_get(struct mipi_csis_device *csis) { unsigned int i; int ret; - state->clks = devm_kcalloc(state->dev, state->info->num_clocks, - sizeof(*state->clks), GFP_KERNEL); + csis->clks = devm_kcalloc(csis->dev, csis->info->num_clocks, + sizeof(*csis->clks), GFP_KERNEL); - if (!state->clks) + if (!csis->clks) return -ENOMEM; - for (i = 0; i < state->info->num_clocks; i++) - state->clks[i].id = mipi_csis_clk_id[i]; + for (i = 0; i < csis->info->num_clocks; i++) + csis->clks[i].id = mipi_csis_clk_id[i]; - ret = devm_clk_bulk_get(state->dev, state->info->num_clocks, - state->clks); + ret = devm_clk_bulk_get(csis->dev, csis->info->num_clocks, + csis->clks); if (ret < 0) return ret; /* Set clock rate */ - ret = clk_set_rate(state->clks[MIPI_CSIS_CLK_WRAP].clk, - state->clk_frequency); + ret = clk_set_rate(csis->clks[MIPI_CSIS_CLK_WRAP].clk, + csis->clk_frequency); if (ret < 0) - dev_err(state->dev, "set rate=%d failed: %d\n", - state->clk_frequency, ret); + dev_err(csis->dev, "set rate=%d failed: %d\n", + csis->clk_frequency, ret); return ret; } -static void mipi_csis_start_stream(struct csi_state *state) +static void mipi_csis_start_stream(struct mipi_csis_device *csis) { - mipi_csis_sw_reset(state); - mipi_csis_set_params(state); - mipi_csis_system_enable(state, true); - mipi_csis_enable_interrupts(state, true); + mipi_csis_sw_reset(csis); + mipi_csis_set_params(csis); + mipi_csis_system_enable(csis, true); + mipi_csis_enable_interrupts(csis, true); } -static void mipi_csis_stop_stream(struct csi_state *state) +static void mipi_csis_stop_stream(struct mipi_csis_device *csis) { - mipi_csis_enable_interrupts(state, false); - mipi_csis_system_enable(state, false); + mipi_csis_enable_interrupts(csis, false); + mipi_csis_system_enable(csis, false); } static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) { - struct csi_state *state = dev_id; + struct mipi_csis_device *csis = dev_id; unsigned long flags; unsigned int i; u32 status; u32 dbg_status; - status = mipi_csis_read(state, MIPI_CSIS_INT_SRC); - dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC); + status = mipi_csis_read(csis, MIPI_CSIS_INT_SRC); + dbg_status = mipi_csis_read(csis, MIPI_CSIS_DBG_INTR_SRC); - spin_lock_irqsave(&state->slock, flags); + spin_lock_irqsave(&csis->slock, flags); /* Update the event/error counters */ - if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug.enable) { + if ((status & MIPI_CSIS_INT_SRC_ERRORS) || csis->debug.enable) { for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) { - struct mipi_csis_event *event = &state->events[i]; + struct mipi_csis_event *event = &csis->events[i]; if ((!event->debug && (status & event->mask)) || (event->debug && (dbg_status & event->mask))) event->counter++; } } - spin_unlock_irqrestore(&state->slock, flags); + spin_unlock_irqrestore(&csis->slock, flags); - mipi_csis_write(state, MIPI_CSIS_INT_SRC, status); - mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status); + mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status); + mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_SRC, dbg_status); return IRQ_HANDLED; } @@ -750,47 +772,47 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) * PHY regulator and reset */ -static int mipi_csis_phy_enable(struct csi_state *state) +static int mipi_csis_phy_enable(struct mipi_csis_device *csis) { - if (state->info->version != MIPI_CSIS_V3_3) + if (csis->info->version != MIPI_CSIS_V3_3) return 0; - return regulator_enable(state->mipi_phy_regulator); + return regulator_enable(csis->mipi_phy_regulator); } -static int mipi_csis_phy_disable(struct csi_state *state) +static int mipi_csis_phy_disable(struct mipi_csis_device *csis) { - if (state->info->version != MIPI_CSIS_V3_3) + if (csis->info->version != MIPI_CSIS_V3_3) return 0; - return regulator_disable(state->mipi_phy_regulator); + return regulator_disable(csis->mipi_phy_regulator); } -static void mipi_csis_phy_reset(struct csi_state *state) +static void mipi_csis_phy_reset(struct mipi_csis_device *csis) { - if (state->info->version != MIPI_CSIS_V3_3) + if (csis->info->version != MIPI_CSIS_V3_3) return; - reset_control_assert(state->mrst); + reset_control_assert(csis->mrst); msleep(20); - reset_control_deassert(state->mrst); + reset_control_deassert(csis->mrst); } -static int mipi_csis_phy_init(struct csi_state *state) +static int mipi_csis_phy_init(struct mipi_csis_device *csis) { - if (state->info->version != MIPI_CSIS_V3_3) + if (csis->info->version != MIPI_CSIS_V3_3) return 0; /* Get MIPI PHY reset and regulator. */ - state->mrst = devm_reset_control_get_exclusive(state->dev, NULL); - if (IS_ERR(state->mrst)) - return PTR_ERR(state->mrst); + csis->mrst = devm_reset_control_get_exclusive(csis->dev, NULL); + if (IS_ERR(csis->mrst)) + return PTR_ERR(csis->mrst); - state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy"); - if (IS_ERR(state->mipi_phy_regulator)) - return PTR_ERR(state->mipi_phy_regulator); + csis->mipi_phy_regulator = devm_regulator_get(csis->dev, "phy"); + if (IS_ERR(csis->mipi_phy_regulator)) + return PTR_ERR(csis->mipi_phy_regulator); - return regulator_set_voltage(state->mipi_phy_regulator, 1000000, + return regulator_set_voltage(csis->mipi_phy_regulator, 1000000, 1000000); } @@ -798,36 +820,36 @@ static int mipi_csis_phy_init(struct csi_state *state) * Debug */ -static void mipi_csis_clear_counters(struct csi_state *state) +static void mipi_csis_clear_counters(struct mipi_csis_device *csis) { unsigned long flags; unsigned int i; - spin_lock_irqsave(&state->slock, flags); + spin_lock_irqsave(&csis->slock, flags); for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) - state->events[i].counter = 0; - spin_unlock_irqrestore(&state->slock, flags); + csis->events[i].counter = 0; + spin_unlock_irqrestore(&csis->slock, flags); } -static void mipi_csis_log_counters(struct csi_state *state, bool non_errors) +static void mipi_csis_log_counters(struct mipi_csis_device *csis, bool non_errors) { unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS : MIPI_CSIS_NUM_EVENTS - 8; unsigned long flags; unsigned int i; - spin_lock_irqsave(&state->slock, flags); + spin_lock_irqsave(&csis->slock, flags); for (i = 0; i < num_events; ++i) { - if (state->events[i].counter > 0 || state->debug.enable) - dev_info(state->dev, "%s events: %d\n", - state->events[i].name, - state->events[i].counter); + if (csis->events[i].counter > 0 || csis->debug.enable) + dev_info(csis->dev, "%s events: %d\n", + csis->events[i].name, + csis->events[i].counter); } - spin_unlock_irqrestore(&state->slock, flags); + spin_unlock_irqrestore(&csis->slock, flags); } -static int mipi_csis_dump_regs(struct csi_state *state) +static int mipi_csis_dump_regs(struct mipi_csis_device *csis) { static const struct { u32 offset; @@ -851,135 +873,134 @@ static int mipi_csis_dump_regs(struct csi_state *state) unsigned int i; u32 cfg; - dev_info(state->dev, "--- REGISTERS ---\n"); + if (!pm_runtime_get_if_in_use(csis->dev)) + return 0; + + dev_info(csis->dev, "--- REGISTERS ---\n"); for (i = 0; i < ARRAY_SIZE(registers); i++) { - cfg = mipi_csis_read(state, registers[i].offset); - dev_info(state->dev, "%14s: 0x%08x\n", registers[i].name, cfg); + cfg = mipi_csis_read(csis, registers[i].offset); + dev_info(csis->dev, "%14s: 0x%08x\n", registers[i].name, cfg); } + pm_runtime_put(csis->dev); + return 0; } static int mipi_csis_dump_regs_show(struct seq_file *m, void *private) { - struct csi_state *state = m->private; + struct mipi_csis_device *csis = m->private; - return mipi_csis_dump_regs(state); + return mipi_csis_dump_regs(csis); } DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs); -static void mipi_csis_debugfs_init(struct csi_state *state) +static void mipi_csis_debugfs_init(struct mipi_csis_device *csis) { - state->debug.hs_settle = UINT_MAX; - state->debug.clk_settle = UINT_MAX; + csis->debug.hs_settle = UINT_MAX; + csis->debug.clk_settle = UINT_MAX; - state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL); + csis->debugfs_root = debugfs_create_dir(dev_name(csis->dev), NULL); - debugfs_create_bool("debug_enable", 0600, state->debugfs_root, - &state->debug.enable); - debugfs_create_file("dump_regs", 0600, state->debugfs_root, state, + debugfs_create_bool("debug_enable", 0600, csis->debugfs_root, + &csis->debug.enable); + debugfs_create_file("dump_regs", 0600, csis->debugfs_root, csis, &mipi_csis_dump_regs_fops); - debugfs_create_u32("tclk_settle", 0600, state->debugfs_root, - &state->debug.clk_settle); - debugfs_create_u32("ths_settle", 0600, state->debugfs_root, - &state->debug.hs_settle); + debugfs_create_u32("tclk_settle", 0600, csis->debugfs_root, + &csis->debug.clk_settle); + debugfs_create_u32("ths_settle", 0600, csis->debugfs_root, + &csis->debug.hs_settle); } -static void mipi_csis_debugfs_exit(struct csi_state *state) +static void mipi_csis_debugfs_exit(struct mipi_csis_device *csis) { - debugfs_remove_recursive(state->debugfs_root); + debugfs_remove_recursive(csis->debugfs_root); } /* ----------------------------------------------------------------------------- * V4L2 subdev operations */ -static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev) +static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev *sdev) { - return container_of(sdev, struct csi_state, sd); + return container_of(sdev, struct mipi_csis_device, sd); } static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); int ret; - if (enable) { - ret = mipi_csis_calculate_params(state); - if (ret < 0) - return ret; + if (!enable) { + mutex_lock(&csis->lock); - mipi_csis_clear_counters(state); + v4l2_subdev_call(csis->src_sd, video, s_stream, 0); - ret = pm_runtime_resume_and_get(state->dev); - if (ret < 0) - return ret; + mipi_csis_stop_stream(csis); + if (csis->debug.enable) + mipi_csis_log_counters(csis, true); + + mutex_unlock(&csis->lock); - ret = v4l2_subdev_call(state->src_sd, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) - goto done; + pm_runtime_put(csis->dev); + + return 0; } - mutex_lock(&state->lock); + ret = mipi_csis_calculate_params(csis); + if (ret < 0) + return ret; - if (enable) { - if (state->state & ST_SUSPENDED) { - ret = -EBUSY; - goto unlock; - } + mipi_csis_clear_counters(csis); - mipi_csis_start_stream(state); - ret = v4l2_subdev_call(state->src_sd, video, s_stream, 1); - if (ret < 0) - goto unlock; + ret = pm_runtime_resume_and_get(csis->dev); + if (ret < 0) + return ret; - mipi_csis_log_counters(state, true); + mutex_lock(&csis->lock); - state->state |= ST_STREAMING; - } else { - v4l2_subdev_call(state->src_sd, video, s_stream, 0); - ret = v4l2_subdev_call(state->src_sd, core, s_power, 0); - if (ret == -ENOIOCTLCMD) - ret = 0; - mipi_csis_stop_stream(state); - state->state &= ~ST_STREAMING; - if (state->debug.enable) - mipi_csis_log_counters(state, true); - } + mipi_csis_start_stream(csis); + ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1); + if (ret < 0) + goto error; -unlock: - mutex_unlock(&state->lock); + mipi_csis_log_counters(csis, true); -done: - if (!enable || ret < 0) - pm_runtime_put(state->dev); + mutex_unlock(&csis->lock); + + return 0; + +error: + mipi_csis_stop_stream(csis); + mutex_unlock(&csis->lock); + pm_runtime_put(csis->dev); return ret; } static struct v4l2_mbus_framefmt * -mipi_csis_get_format(struct csi_state *state, +mipi_csis_get_format(struct mipi_csis_device *csis, struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence which, unsigned int pad) { if (which == V4L2_SUBDEV_FORMAT_TRY) - return v4l2_subdev_get_try_format(&state->sd, sd_state, pad); + return v4l2_subdev_get_try_format(&csis->sd, sd_state, pad); - return &state->format_mbus[pad]; + return &csis->format_mbus[pad]; } static int mipi_csis_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct v4l2_mbus_framefmt *fmt_sink; struct v4l2_mbus_framefmt *fmt_source; enum v4l2_subdev_format_whence which; which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_sink = mipi_csis_get_format(state, sd_state, which, CSIS_PAD_SINK); + fmt_sink = mipi_csis_get_format(csis, sd_state, which, CSIS_PAD_SINK); fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH; @@ -993,15 +1014,7 @@ static int mipi_csis_init_cfg(struct v4l2_subdev *sd, V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace, fmt_sink->ycbcr_enc); - /* - * When called from mipi_csis_subdev_init() to initialize the active - * configuration, cfg is NULL, which indicates there's no source pad - * configuration to set. - */ - if (!sd_state) - return 0; - - fmt_source = mipi_csis_get_format(state, sd_state, which, + fmt_source = mipi_csis_get_format(csis, sd_state, which, CSIS_PAD_SOURCE); *fmt_source = *fmt_sink; @@ -1012,15 +1025,15 @@ static int mipi_csis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct v4l2_mbus_framefmt *fmt; - fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, sdformat->pad); - mutex_lock(&state->lock); + mutex_lock(&csis->lock); sdformat->format = *fmt; - mutex_unlock(&state->lock); + mutex_unlock(&csis->lock); return 0; } @@ -1029,7 +1042,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); /* * The CSIS can't transcode in any way, the source format is identical @@ -1041,7 +1054,7 @@ static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - fmt = mipi_csis_get_format(state, sd_state, code->which, + fmt = mipi_csis_get_format(csis, sd_state, code->which, code->pad); code->code = fmt->code; return 0; @@ -1062,7 +1075,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *sdformat) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct csis_pix_format const *csis_fmt; struct v4l2_mbus_framefmt *fmt; unsigned int align; @@ -1110,10 +1123,10 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, &sdformat->format.height, 1, CSIS_MAX_PIX_HEIGHT, 0, 0); - fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, sdformat->pad); - mutex_lock(&state->lock); + mutex_lock(&csis->lock); fmt->code = csis_fmt->code; fmt->width = sdformat->format.width; @@ -1126,7 +1139,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, sdformat->format = *fmt; /* Propagate the format from sink to source. */ - fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + fmt = mipi_csis_get_format(csis, sd_state, sdformat->which, CSIS_PAD_SOURCE); *fmt = sdformat->format; @@ -1135,22 +1148,20 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, /* Store the CSIS format descriptor for active formats. */ if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) - state->csis_fmt = csis_fmt; + csis->csis_fmt = csis_fmt; - mutex_unlock(&state->lock); + mutex_unlock(&csis->lock); return 0; } static int mipi_csis_log_status(struct v4l2_subdev *sd) { - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - mutex_lock(&state->lock); - mipi_csis_log_counters(state, true); - if (state->debug.enable && (state->state & ST_POWERED)) - mipi_csis_dump_regs(state); - mutex_unlock(&state->lock); + mipi_csis_log_counters(csis, true); + if (csis->debug.enable) + mipi_csis_dump_regs(csis); return 0; } @@ -1185,10 +1196,10 @@ static int mipi_csis_link_setup(struct media_entity *entity, const struct media_pad *remote_pad, u32 flags) { struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); struct v4l2_subdev *remote_sd; - dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name, + dev_dbg(csis->dev, "link setup %s -> %s", remote_pad->entity->name, local_pad->entity->name); /* We only care about the link to the source. */ @@ -1198,12 +1209,12 @@ static int mipi_csis_link_setup(struct media_entity *entity, remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); if (flags & MEDIA_LNK_FL_ENABLED) { - if (state->src_sd) + if (csis->src_sd) return -EBUSY; - state->src_sd = remote_sd; + csis->src_sd = remote_sd; } else { - state->src_sd = NULL; + csis->src_sd = NULL; } return 0; @@ -1219,18 +1230,18 @@ static const struct media_entity_operations mipi_csis_entity_ops = { * Async subdev notifier */ -static struct csi_state * +static struct mipi_csis_device * mipi_notifier_to_csis_state(struct v4l2_async_notifier *n) { - return container_of(n, struct csi_state, notifier); + return container_of(n, struct mipi_csis_device, notifier); } static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { - struct csi_state *state = mipi_notifier_to_csis_state(notifier); - struct media_pad *sink = &state->sd.entity.pads[CSIS_PAD_SINK]; + struct mipi_csis_device *csis = mipi_notifier_to_csis_state(notifier); + struct media_pad *sink = &csis->sd.entity.pads[CSIS_PAD_SINK]; return v4l2_create_fwnode_links_to_pad(sd, sink, 0); } @@ -1239,7 +1250,7 @@ static const struct v4l2_async_notifier_operations mipi_csis_notify_ops = { .bound = mipi_csis_notify_bound, }; -static int mipi_csis_async_register(struct csi_state *state) +static int mipi_csis_async_register(struct mipi_csis_device *csis) { struct v4l2_fwnode_endpoint vep = { .bus_type = V4L2_MBUS_CSI2_DPHY, @@ -1249,9 +1260,9 @@ static int mipi_csis_async_register(struct csi_state *state) unsigned int i; int ret; - v4l2_async_nf_init(&state->notifier); + v4l2_async_nf_init(&csis->notifier); - ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0, + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0, FWNODE_GRAPH_ENDPOINT_NEXT); if (!ep) return -ENOTCONN; @@ -1262,19 +1273,19 @@ static int mipi_csis_async_register(struct csi_state *state) for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) { if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) { - dev_err(state->dev, + dev_err(csis->dev, "data lanes reordering is not supported"); ret = -EINVAL; goto err_parse; } } - state->bus = vep.bus.mipi_csi2; + csis->bus = vep.bus.mipi_csi2; - dev_dbg(state->dev, "data lanes: %d\n", state->bus.num_data_lanes); - dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags); + dev_dbg(csis->dev, "data lanes: %d\n", csis->bus.num_data_lanes); + dev_dbg(csis->dev, "flags: 0x%08x\n", csis->bus.flags); - asd = v4l2_async_nf_add_fwnode_remote(&state->notifier, ep, + asd = v4l2_async_nf_add_fwnode_remote(&csis->notifier, ep, struct v4l2_async_subdev); if (IS_ERR(asd)) { ret = PTR_ERR(asd); @@ -1283,13 +1294,13 @@ static int mipi_csis_async_register(struct csi_state *state) fwnode_handle_put(ep); - state->notifier.ops = &mipi_csis_notify_ops; + csis->notifier.ops = &mipi_csis_notify_ops; - ret = v4l2_async_subdev_nf_register(&state->sd, &state->notifier); + ret = v4l2_async_subdev_nf_register(&csis->sd, &csis->notifier); if (ret) return ret; - return v4l2_async_register_subdev(&state->sd); + return v4l2_async_register_subdev(&csis->sd); err_parse: fwnode_handle_put(ep); @@ -1301,97 +1312,63 @@ err_parse: * Suspend/resume */ -static int mipi_csis_pm_suspend(struct device *dev, bool runtime) +static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); int ret = 0; - mutex_lock(&state->lock); - if (state->state & ST_POWERED) { - mipi_csis_stop_stream(state); - ret = mipi_csis_phy_disable(state); - if (ret) - goto unlock; - mipi_csis_clk_disable(state); - state->state &= ~ST_POWERED; - if (!runtime) - state->state |= ST_SUSPENDED; - } + mutex_lock(&csis->lock); + + ret = mipi_csis_phy_disable(csis); + if (ret) + goto unlock; + + mipi_csis_clk_disable(csis); unlock: - mutex_unlock(&state->lock); + mutex_unlock(&csis->lock); return ret ? -EAGAIN : 0; } -static int mipi_csis_pm_resume(struct device *dev, bool runtime) +static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); int ret = 0; - mutex_lock(&state->lock); - if (!runtime && !(state->state & ST_SUSPENDED)) - goto unlock; - - if (!(state->state & ST_POWERED)) { - ret = mipi_csis_phy_enable(state); - if (ret) - goto unlock; + mutex_lock(&csis->lock); - state->state |= ST_POWERED; - mipi_csis_clk_enable(state); - } - if (state->state & ST_STREAMING) - mipi_csis_start_stream(state); + ret = mipi_csis_phy_enable(csis); + if (ret) + goto unlock; - state->state &= ~ST_SUSPENDED; + mipi_csis_clk_enable(csis); unlock: - mutex_unlock(&state->lock); + mutex_unlock(&csis->lock); return ret ? -EAGAIN : 0; } -static int __maybe_unused mipi_csis_suspend(struct device *dev) -{ - return mipi_csis_pm_suspend(dev, false); -} - -static int __maybe_unused mipi_csis_resume(struct device *dev) -{ - return mipi_csis_pm_resume(dev, false); -} - -static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) -{ - return mipi_csis_pm_suspend(dev, true); -} - -static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) -{ - return mipi_csis_pm_resume(dev, true); -} - static const struct dev_pm_ops mipi_csis_pm_ops = { SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume) }; /* ----------------------------------------------------------------------------- * Probe/remove & platform driver */ -static int mipi_csis_subdev_init(struct csi_state *state) +static int mipi_csis_subdev_init(struct mipi_csis_device *csis) { - struct v4l2_subdev *sd = &state->sd; + struct v4l2_subdev *sd = &csis->sd; v4l2_subdev_init(sd, &mipi_csis_subdev_ops); sd->owner = THIS_MODULE; snprintf(sd->name, sizeof(sd->name), "csis-%s", - dev_name(state->dev)); + dev_name(csis->dev)); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->ctrl_handler = NULL; @@ -1399,26 +1376,26 @@ static int mipi_csis_subdev_init(struct csi_state *state) sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; sd->entity.ops = &mipi_csis_entity_ops; - sd->dev = state->dev; + sd->dev = csis->dev; - state->csis_fmt = &mipi_csis_formats[0]; + csis->csis_fmt = &mipi_csis_formats[0]; mipi_csis_init_cfg(sd, NULL); - state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK + csis->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; - state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE + csis->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT; return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, - state->pads); + csis->pads); } -static int mipi_csis_parse_dt(struct csi_state *state) +static int mipi_csis_parse_dt(struct mipi_csis_device *csis) { - struct device_node *node = state->dev->of_node; + struct device_node *node = csis->dev->of_node; if (of_property_read_u32(node, "clock-frequency", - &state->clk_frequency)) - state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + &csis->clk_frequency)) + csis->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; return 0; } @@ -1426,102 +1403,102 @@ static int mipi_csis_parse_dt(struct csi_state *state) static int mipi_csis_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct csi_state *state; + struct mipi_csis_device *csis; int irq; int ret; - state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); - if (!state) + csis = devm_kzalloc(dev, sizeof(*csis), GFP_KERNEL); + if (!csis) return -ENOMEM; - mutex_init(&state->lock); - spin_lock_init(&state->slock); + mutex_init(&csis->lock); + spin_lock_init(&csis->slock); - state->dev = dev; - state->info = of_device_get_match_data(dev); + csis->dev = dev; + csis->info = of_device_get_match_data(dev); - memcpy(state->events, mipi_csis_events, sizeof(state->events)); + memcpy(csis->events, mipi_csis_events, sizeof(csis->events)); /* Parse DT properties. */ - ret = mipi_csis_parse_dt(state); + ret = mipi_csis_parse_dt(csis); if (ret < 0) { dev_err(dev, "Failed to parse device tree: %d\n", ret); return ret; } /* Acquire resources. */ - state->regs = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(state->regs)) - return PTR_ERR(state->regs); + csis->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(csis->regs)) + return PTR_ERR(csis->regs); irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - ret = mipi_csis_phy_init(state); + ret = mipi_csis_phy_init(csis); if (ret < 0) return ret; - ret = mipi_csis_clk_get(state); + ret = mipi_csis_clk_get(csis); if (ret < 0) return ret; /* Reset PHY and enable the clocks. */ - mipi_csis_phy_reset(state); + mipi_csis_phy_reset(csis); - ret = mipi_csis_clk_enable(state); + ret = mipi_csis_clk_enable(csis); if (ret < 0) { - dev_err(state->dev, "failed to enable clocks: %d\n", ret); + dev_err(csis->dev, "failed to enable clocks: %d\n", ret); return ret; } /* Now that the hardware is initialized, request the interrupt. */ ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0, - dev_name(dev), state); + dev_name(dev), csis); if (ret) { dev_err(dev, "Interrupt request failed\n"); goto disable_clock; } /* Initialize and register the subdev. */ - ret = mipi_csis_subdev_init(state); + ret = mipi_csis_subdev_init(csis); if (ret < 0) goto disable_clock; - platform_set_drvdata(pdev, &state->sd); + platform_set_drvdata(pdev, &csis->sd); - ret = mipi_csis_async_register(state); + ret = mipi_csis_async_register(csis); if (ret < 0) { dev_err(dev, "async register failed: %d\n", ret); goto cleanup; } /* Initialize debugfs. */ - mipi_csis_debugfs_init(state); + mipi_csis_debugfs_init(csis); /* Enable runtime PM. */ pm_runtime_enable(dev); if (!pm_runtime_enabled(dev)) { - ret = mipi_csis_pm_resume(dev, true); + ret = mipi_csis_runtime_resume(dev); if (ret < 0) goto unregister_all; } dev_info(dev, "lanes: %d, freq: %u\n", - state->bus.num_data_lanes, state->clk_frequency); + csis->bus.num_data_lanes, csis->clk_frequency); return 0; unregister_all: - mipi_csis_debugfs_exit(state); + mipi_csis_debugfs_exit(csis); cleanup: - media_entity_cleanup(&state->sd.entity); - v4l2_async_nf_unregister(&state->notifier); - v4l2_async_nf_cleanup(&state->notifier); - v4l2_async_unregister_subdev(&state->sd); + media_entity_cleanup(&csis->sd.entity); + v4l2_async_nf_unregister(&csis->notifier); + v4l2_async_nf_cleanup(&csis->notifier); + v4l2_async_unregister_subdev(&csis->sd); disable_clock: - mipi_csis_clk_disable(state); - mutex_destroy(&state->lock); + mipi_csis_clk_disable(csis); + mutex_destroy(&csis->lock); return ret; } @@ -1529,18 +1506,18 @@ disable_clock: static int mipi_csis_remove(struct platform_device *pdev) { struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct csi_state *state = mipi_sd_to_csis_state(sd); + struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd); - mipi_csis_debugfs_exit(state); - v4l2_async_nf_unregister(&state->notifier); - v4l2_async_nf_cleanup(&state->notifier); - v4l2_async_unregister_subdev(&state->sd); + mipi_csis_debugfs_exit(csis); + v4l2_async_nf_unregister(&csis->notifier); + v4l2_async_nf_cleanup(&csis->notifier); + v4l2_async_unregister_subdev(&csis->sd); pm_runtime_disable(&pdev->dev); - mipi_csis_pm_suspend(&pdev->dev, true); - mipi_csis_clk_disable(state); - media_entity_cleanup(&state->sd.entity); - mutex_destroy(&state->lock); + mipi_csis_runtime_suspend(&pdev->dev); + mipi_csis_clk_disable(csis); + media_entity_cleanup(&csis->sd.entity); + mutex_destroy(&csis->lock); pm_runtime_set_suspended(&pdev->dev); return 0; diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 5dc1ddbe6d65..307bb1dc4589 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -576,12 +576,8 @@ static const struct vb2_ops msm_video_vb2_q_ops = { static int video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct camss_video *video = video_drvdata(file); - strscpy(cap->driver, "qcom-camss", sizeof(cap->driver)); strscpy(cap->card, "Qualcomm Camera Subsystem", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(video->camss->dev)); return 0; } diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index c3023340d95c..d33825553edc 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -261,6 +261,7 @@ struct venc_controls { u32 header_mode; bool aud_enable; + u32 intra_refresh_type; u32 intra_refresh_period; struct { diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 0bca95d01650..5c1104379c49 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -90,12 +90,28 @@ bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt) } EXPORT_SYMBOL_GPL(venus_helper_check_codec); +static void free_dpb_buf(struct venus_inst *inst, struct intbuf *buf) +{ + ida_free(&inst->dpb_ids, buf->dpb_out_tag); + + list_del_init(&buf->list); + dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da, + buf->attrs); + kfree(buf); +} + int venus_helper_queue_dpb_bufs(struct venus_inst *inst) { - struct intbuf *buf; + struct intbuf *buf, *next; + unsigned int dpb_size = 0; int ret = 0; - list_for_each_entry(buf, &inst->dpbbufs, list) { + if (inst->dpb_buftype == HFI_BUFFER_OUTPUT) + dpb_size = inst->output_buf_size; + else if (inst->dpb_buftype == HFI_BUFFER_OUTPUT2) + dpb_size = inst->output2_buf_size; + + list_for_each_entry_safe(buf, next, &inst->dpbbufs, list) { struct hfi_frame_data fdata; memset(&fdata, 0, sizeof(fdata)); @@ -106,6 +122,12 @@ int venus_helper_queue_dpb_bufs(struct venus_inst *inst) if (buf->owned_by == FIRMWARE) continue; + /* free buffer from previous sequence which was released later */ + if (dpb_size > buf->size) { + free_dpb_buf(inst, buf); + continue; + } + fdata.clnt_data = buf->dpb_out_tag; ret = hfi_session_process_buf(inst, &fdata); @@ -127,13 +149,7 @@ int venus_helper_free_dpb_bufs(struct venus_inst *inst) list_for_each_entry_safe(buf, n, &inst->dpbbufs, list) { if (buf->owned_by == FIRMWARE) continue; - - ida_free(&inst->dpb_ids, buf->dpb_out_tag); - - list_del_init(&buf->list); - dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da, - buf->attrs); - kfree(buf); + free_dpb_buf(inst, buf); } if (list_empty(&inst->dpbbufs)) @@ -592,6 +608,10 @@ static u32 to_hfi_raw_fmt(u32 v4l2_fmt) return HFI_COLOR_FORMAT_NV12; case V4L2_PIX_FMT_NV21: return HFI_COLOR_FORMAT_NV21; + case V4L2_PIX_FMT_QC08C: + return HFI_COLOR_FORMAT_NV12_UBWC; + case V4L2_PIX_FMT_QC10C: + return HFI_COLOR_FORMAT_YUV420_TP10_UBWC; default: break; } @@ -1174,7 +1194,8 @@ int venus_helper_set_format_constraints(struct venus_inst *inst) if (!IS_V6(inst->core)) return 0; - if (inst->opb_fmt == HFI_COLOR_FORMAT_NV12_UBWC) + if (inst->opb_fmt == HFI_COLOR_FORMAT_NV12_UBWC || + inst->opb_fmt == HFI_COLOR_FORMAT_YUV420_TP10_UBWC) return 0; pconstraint.buffer_type = HFI_BUFFER_OUTPUT2; @@ -1745,27 +1766,6 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt, if (!caps) return -EINVAL; - if (inst->bit_depth == VIDC_BITDEPTH_10 && - inst->session_type == VIDC_SESSION_TYPE_DEC) { - found_ubwc = - find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, - HFI_COLOR_FORMAT_YUV420_TP10_UBWC); - found = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT2, - HFI_COLOR_FORMAT_NV12); - if (found_ubwc && found) { - /* - * Hard-code DPB buffers to be 10bit UBWC and decoder - * output buffers in 8bit NV12 until V4L2 is able to - * expose compressed/tiled formats to applications. - */ - *out_fmt = HFI_COLOR_FORMAT_YUV420_TP10_UBWC; - *out2_fmt = HFI_COLOR_FORMAT_NV12; - return 0; - } - - return -EINVAL; - } - if (ubwc) { ubwc_fmt = fmt | HFI_COLOR_FORMAT_UBWC_BASE; found_ubwc = find_fmt_from_caps(caps, HFI_BUFFER_OUTPUT, @@ -1797,6 +1797,29 @@ int venus_helper_get_out_fmts(struct venus_inst *inst, u32 v4l2_fmt, } EXPORT_SYMBOL_GPL(venus_helper_get_out_fmts); +bool venus_helper_check_format(struct venus_inst *inst, u32 v4l2_pixfmt) +{ + struct venus_core *core = inst->core; + u32 fmt = to_hfi_raw_fmt(v4l2_pixfmt); + struct hfi_plat_caps *caps; + u32 buftype; + + if (!fmt) + return false; + + caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type); + if (!caps) + return false; + + if (inst->session_type == VIDC_SESSION_TYPE_DEC) + buftype = HFI_BUFFER_OUTPUT2; + else + buftype = HFI_BUFFER_OUTPUT; + + return find_fmt_from_caps(caps, buftype, fmt); +} +EXPORT_SYMBOL_GPL(venus_helper_check_format); + int venus_helper_set_stride(struct venus_inst *inst, unsigned int width, unsigned int height) { diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index 32619c3e8c97..358e4f39c9c0 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -55,6 +55,7 @@ void venus_helper_init_instance(struct venus_inst *inst); int venus_helper_session_init(struct venus_inst *inst); int venus_helper_get_out_fmts(struct venus_inst *inst, u32 fmt, u32 *out_fmt, u32 *out2_fmt, bool ubwc); +bool venus_helper_check_format(struct venus_inst *inst, u32 v4l2_pixfmt); int venus_helper_alloc_dpb_bufs(struct venus_inst *inst); int venus_helper_free_dpb_bufs(struct venus_inst *inst); int venus_helper_intbufs_alloc(struct venus_inst *inst); diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index 4e2151fb47f0..1968f09ad177 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -104,6 +104,9 @@ int hfi_core_deinit(struct venus_core *core, bool blocking) mutex_lock(&core->lock); } + if (!core->ops) + goto unlock; + ret = core->ops->core_deinit(core); if (!ret) diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v4.c b/drivers/media/platform/qcom/venus/hfi_platform_v4.c index 3f7f5277a50e..e3f0a90a567b 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform_v4.c +++ b/drivers/media/platform/qcom/venus/hfi_platform_v4.c @@ -55,7 +55,7 @@ static const struct hfi_plat_caps caps[] = { .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, .fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, .fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010}, - .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10}, + .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC}, .num_fmts = 7, }, { .codec = HFI_VIDEO_CODEC_VP8, @@ -106,7 +106,7 @@ static const struct hfi_plat_caps caps[] = { .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, .fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, .fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010}, - .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10}, + .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC}, .num_fmts = 7, }, { .codec = HFI_VIDEO_CODEC_MPEG2, diff --git a/drivers/media/platform/qcom/venus/hfi_platform_v6.c b/drivers/media/platform/qcom/venus/hfi_platform_v6.c index c10618e44f5d..4e8af645f8b9 100644 --- a/drivers/media/platform/qcom/venus/hfi_platform_v6.c +++ b/drivers/media/platform/qcom/venus/hfi_platform_v6.c @@ -55,7 +55,7 @@ static const struct hfi_plat_caps caps[] = { .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, .fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, .fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010}, - .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10}, + .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC}, .num_fmts = 7, }, { .codec = HFI_VIDEO_CODEC_VP8, @@ -106,7 +106,7 @@ static const struct hfi_plat_caps caps[] = { .fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12}, .fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21}, .fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010}, - .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10}, + .fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC}, .num_fmts = 7, }, { .codec = HFI_VIDEO_CODEC_MPEG2, diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 3a75a27632fb..9a34662fea38 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -1583,8 +1583,10 @@ static int venus_suspend_3xx(struct venus_core *core) */ ret = readx_poll_timeout(venus_cpu_and_video_core_idle, hdev, val, val, 1500, 100 * 1500); - if (ret) + if (ret) { + dev_err(dev, "wait for cpu and video core idle fail (%d)\n", ret); return ret; + } ret = venus_prepare_power_collapse(hdev, false); if (ret) { diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 91da3f509724..ac0bb45d07f4 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -31,6 +31,14 @@ */ static const struct venus_format vdec_formats[] = { { + .pixfmt = V4L2_PIX_FMT_QC08C, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, { + .pixfmt = V4L2_PIX_FMT_QC10C, + .num_planes = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + },{ .pixfmt = V4L2_PIX_FMT_NV12, .num_planes = 1, .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, @@ -106,6 +114,14 @@ find_format(struct venus_inst *inst, u32 pixfmt, u32 type) !venus_helper_check_codec(inst, fmt[i].pixfmt)) return NULL; + if (V4L2_TYPE_IS_CAPTURE(type) && + !venus_helper_check_format(inst, fmt[i].pixfmt)) + return NULL; + + if (V4L2_TYPE_IS_CAPTURE(type) && fmt[i].pixfmt == V4L2_PIX_FMT_QC10C && + !(inst->bit_depth == VIDC_BITDEPTH_10)) + return NULL; + return &fmt[i]; } @@ -124,8 +140,17 @@ find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) if (fmt[i].type != type) continue; - valid = type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || - venus_helper_check_codec(inst, fmt[i].pixfmt); + + if (V4L2_TYPE_IS_OUTPUT(type)) { + valid = venus_helper_check_codec(inst, fmt[i].pixfmt); + } else if (V4L2_TYPE_IS_CAPTURE(type)) { + valid = venus_helper_check_format(inst, fmt[i].pixfmt); + + if (fmt[i].pixfmt == V4L2_PIX_FMT_QC10C && + !(inst->bit_depth == VIDC_BITDEPTH_10)) + valid = false; + } + if (k == index && valid) break; if (valid) @@ -676,8 +701,8 @@ static int vdec_output_conf(struct venus_inst *inst) struct venus_core *core = inst->core; struct hfi_enable en = { .enable = 1 }; struct hfi_buffer_requirements bufreq; - u32 width = inst->out_width; - u32 height = inst->out_height; + u32 width = inst->width; + u32 height = inst->height; u32 out_fmt, out2_fmt; bool ubwc = false; u32 ptype; @@ -1200,6 +1225,8 @@ static void vdec_stop_streaming(struct vb2_queue *q) struct venus_inst *inst = vb2_get_drv_priv(q); int ret = -EINVAL; + vdec_pm_get_put(inst); + mutex_lock(&inst->lock); if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) @@ -1525,7 +1552,7 @@ static const struct hfi_inst_ops vdec_hfi_ops = { static void vdec_inst_init(struct venus_inst *inst) { inst->hfi_codec = HFI_VIDEO_CODEC_H264; - inst->fmt_out = &vdec_formats[6]; + inst->fmt_out = &vdec_formats[8]; inst->fmt_cap = &vdec_formats[0]; inst->width = frame_width_min(inst); inst->height = ALIGN(frame_height_min(inst), 32); diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index adea4c3b8c20..86918aea1d24 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -893,8 +893,12 @@ static int venc_set_properties(struct venus_inst *inst) mbs++; mbs /= ctr->intra_refresh_period; - intra_refresh.mode = HFI_INTRA_REFRESH_RANDOM; intra_refresh.cir_mbs = mbs; + if (ctr->intra_refresh_type == + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC) + intra_refresh.mode = HFI_INTRA_REFRESH_CYCLIC; + else + intra_refresh.mode = HFI_INTRA_REFRESH_RANDOM; } ptype = HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH; diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index ea5805e71c14..ed44e5800759 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -316,6 +316,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: ctr->mastering = *ctrl->p_new.p_hdr10_mastering; break; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE: + ctr->intra_refresh_type = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: ctr->intra_refresh_period = ctrl->val; break; @@ -582,6 +585,11 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY, v4l2_ctrl_ptr_create(NULL)); + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC, + 0, V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, 0, ((4096 * 2304) >> 8), 1, 0); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c index 64cb05b3907c..49bdcfba010b 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c @@ -94,8 +94,6 @@ static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin, strscpy(mdev->driver_name, KBUILD_MODNAME, sizeof(mdev->driver_name)); strscpy(mdev->model, match->compatible, sizeof(mdev->model)); - snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", - dev_name(mdev->dev)); media_device_init(mdev); @@ -891,7 +889,6 @@ static const struct media_device_ops rvin_csi2_media_ops = { static int rvin_csi2_create_link(struct rvin_group *group, unsigned int id, const struct rvin_group_route *route) - { struct media_entity *source = &group->remotes[route->csi].subdev->entity; struct media_entity *sink = &group->vin[id]->vdev.entity; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c index 2272f1c96aaf..6644b498929d 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c @@ -77,6 +77,7 @@ /* Register bit fields for R-Car VIN */ /* Video n Main Control Register bits */ +#define VNMC_INF_MASK (7 << 16) #define VNMC_DPINE (1 << 27) /* Gen3 specific */ #define VNMC_SCLE (1 << 26) /* Gen3 specific */ #define VNMC_FOC (1 << 21) @@ -88,6 +89,7 @@ #define VNMC_INF_RAW8 (4 << 16) #define VNMC_INF_YUV16 (5 << 16) #define VNMC_INF_RGB888 (6 << 16) +#define VNMC_INF_RGB666 (7 << 16) #define VNMC_VUP (1 << 10) #define VNMC_IM_ODD (0 << 3) #define VNMC_IM_ODD_EVEN (1 << 3) @@ -707,6 +709,29 @@ static int rvin_setup(struct rvin_dev *vin) break; } + /* Make sure input interface and input format is valid. */ + if (vin->info->model == RCAR_GEN3) { + switch (vnmc & VNMC_INF_MASK) { + case VNMC_INF_YUV8_BT656: + case VNMC_INF_YUV10_BT656: + case VNMC_INF_YUV16: + case VNMC_INF_RGB666: + if (vin->is_csi) { + vin_err(vin, "Invalid setting in MIPI CSI2\n"); + return -EINVAL; + } + break; + case VNMC_INF_RAW8: + if (!vin->is_csi) { + vin_err(vin, "Invalid setting in Digital Pins\n"); + return -EINVAL; + } + break; + default: + break; + } + } + /* Enable VSYNC Field Toggle mode after one VSYNC input */ if (vin->info->model == RCAR_GEN3) dmr2 = VNDMR2_FTEV; diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c index 2e60b9fce03b..2e2aa9d746ee 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c @@ -255,6 +255,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, { struct v4l2_subdev *sd = vin_to_source(vin); struct v4l2_subdev_state *sd_state; + static struct lock_class_key key; struct v4l2_subdev_format format = { .which = which, .pad = vin->parallel.source_pad, @@ -263,7 +264,11 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, u32 width, height; int ret; - sd_state = v4l2_subdev_alloc_state(sd); + /* + * FIXME: Drop this call, drivers are not supposed to use + * __v4l2_subdev_state_alloc(). + */ + sd_state = __v4l2_subdev_state_alloc(sd, "rvin:state->lock", &key); if (IS_ERR(sd_state)) return PTR_ERR(sd_state); @@ -299,7 +304,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, rvin_format_align(vin, pix); done: - v4l2_subdev_free_state(sd_state); + __v4l2_subdev_state_free(sd_state); return ret; } @@ -307,12 +312,8 @@ done: static int rvin_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct rvin_dev *vin = video_drvdata(file); - strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, "R_Car_VIN", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(vin->dev)); return 0; } diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c index 293beba131e2..2f4377cfbb42 100644 --- a/drivers/media/platform/renesas/rcar_jpu.c +++ b/drivers/media/platform/renesas/rcar_jpu.c @@ -670,8 +670,6 @@ static int jpu_querycap(struct file *file, void *priv, strscpy(cap->card, DRV_NAME " decoder", sizeof(cap->card)); strscpy(cap->driver, DRV_NAME, sizeof(cap->driver)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(ctx->jpu->dev)); memset(cap->reserved, 0, sizeof(cap->reserved)); return 0; diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c index 2e8dbacc414e..f70f91b006b7 100644 --- a/drivers/media/platform/renesas/renesas-ceu.c +++ b/drivers/media/platform/renesas/renesas-ceu.c @@ -1606,15 +1606,15 @@ struct ceu_data { u32 irq_mask; }; -static const struct ceu_data ceu_data_rz = { - .irq_mask = CEU_CETCR_ALL_IRQS_RZ, -}; - static const struct ceu_data ceu_data_sh4 = { .irq_mask = CEU_CETCR_ALL_IRQS_SH4, }; #if IS_ENABLED(CONFIG_OF) +static const struct ceu_data ceu_data_rz = { + .irq_mask = CEU_CETCR_ALL_IRQS_RZ, +}; + static const struct of_device_id ceu_of_match[] = { { .compatible = "renesas,r7s72100-ceu", .data = &ceu_data_rz }, { .compatible = "renesas,r8a7740-ceu", .data = &ceu_data_rz }, diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c index 502c7d9d6890..1f73c48eb738 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c @@ -243,8 +243,6 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) mdev->dev = vsp1->dev; mdev->hw_revision = vsp1->version; strscpy(mdev->model, vsp1->info->model, sizeof(mdev->model)); - snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", - dev_name(mdev->dev)); media_device_init(mdev); vsp1->media_ops.link_setup = vsp1_entity_link_setup; diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c index 823c15facd1b..a116a3362f9e 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c @@ -613,6 +613,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, const char *name, unsigned int num_pads, const struct v4l2_subdev_ops *ops, u32 function) { + static struct lock_class_key key; struct v4l2_subdev *subdev; unsigned int i; int ret; @@ -675,7 +676,12 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, * Allocate the pad configuration to store formats and selection * rectangles. */ - entity->config = v4l2_subdev_alloc_state(&entity->subdev); + /* + * FIXME: Drop this call, drivers are not supposed to use + * __v4l2_subdev_state_alloc(). + */ + entity->config = __v4l2_subdev_state_alloc(&entity->subdev, + "vsp1:config->lock", &key); if (IS_ERR(entity->config)) { media_entity_cleanup(&entity->subdev.entity); return PTR_ERR(entity->config); @@ -690,6 +696,6 @@ void vsp1_entity_destroy(struct vsp1_entity *entity) entity->ops->destroy(entity); if (entity->subdev.ctrl_handler) v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); - v4l2_subdev_free_state(entity->config); + __v4l2_subdev_state_free(entity->config); media_entity_cleanup(&entity->subdev.entity); } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c index 5e5013d2cd2a..f22449dd654c 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c @@ -434,8 +434,6 @@ static int histo_v4l2_querycap(struct file *file, void *fh, strscpy(cap->driver, "vsp1", sizeof(cap->driver)); strscpy(cap->card, histo->video.name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(histo->entity.vsp1->dev)); return 0; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c index 85587c1b6a37..75083cb234fe 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c @@ -291,11 +291,11 @@ static void rpf_configure_partition(struct vsp1_entity *entity, + crop.left * fmtinfo->bpp[0] / 8; if (format->num_planes > 1) { + unsigned int bpl = format->plane_fmt[1].bytesperline; unsigned int offset; - offset = crop.top * format->plane_fmt[1].bytesperline - + crop.left / fmtinfo->hsub - * fmtinfo->bpp[1] / 8; + offset = crop.top / fmtinfo->vsub * bpl + + crop.left / fmtinfo->hsub * fmtinfo->bpp[1] / 8; mem.addr[1] += offset; mem.addr[2] += offset; } diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c index 044eb5778820..51219b1b6ea9 100644 --- a/drivers/media/platform/renesas/vsp1/vsp1_video.c +++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c @@ -959,8 +959,6 @@ vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap) strscpy(cap->driver, "vsp1", sizeof(cap->driver)); strscpy(cap->card, video->video.name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(video->vsp1->dev)); return 0; } @@ -1032,7 +1030,7 @@ vsp1_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type) struct vsp1_pipeline *pipe; int ret; - if (video->queue.owner && video->queue.owner != file->private_data) + if (vb2_queue_is_busy(&video->queue, file)) return -EBUSY; /* @@ -1129,21 +1127,11 @@ static int vsp1_video_open(struct file *file) static int vsp1_video_release(struct file *file) { struct vsp1_video *video = video_drvdata(file); - struct v4l2_fh *vfh = file->private_data; - mutex_lock(&video->lock); - if (video->queue.owner == vfh) { - vb2_queue_release(&video->queue); - video->queue.owner = NULL; - } - mutex_unlock(&video->lock); + vb2_fop_release(file); vsp1_device_put(video->vsp1); - v4l2_fh_release(file); - - file->private_data = NULL; - return 0; } diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 3d3d1062e212..2f8df74ad0fd 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -865,7 +865,7 @@ static int rga_probe(struct platform_device *pdev) ret = pm_runtime_resume_and_get(rga->dev); if (ret < 0) - goto rel_vdev; + goto rel_m2m; rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF; rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F; @@ -881,7 +881,7 @@ static int rga_probe(struct platform_device *pdev) DMA_ATTR_WRITE_COMBINE); if (!rga->cmdbuf_virt) { ret = -ENOMEM; - goto rel_vdev; + goto rel_m2m; } rga->src_mmu_pages = @@ -918,6 +918,8 @@ free_src_pages: free_dma: dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt, rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE); +rel_m2m: + v4l2_m2m_release(rga->m2m_dev); rel_vdev: video_device_release(vfd); unreg_v4l2_dev: diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 2a35bf24e54e..4415c7248c2f 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -14,6 +14,8 @@ #include <linux/pm_runtime.h> #include <linux/videodev2.h> #include <linux/vmalloc.h> + +#include <media/mipi-csi2.h> #include <media/v4l2-event.h> #include "rkisp1-common.h" @@ -62,112 +64,112 @@ static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = { }, { .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .mipi_dt = MIPI_CSI2_DT_RAW10, .bayer_pat = RKISP1_RAW_RGGB, .bus_width = 10, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .mipi_dt = MIPI_CSI2_DT_RAW10, .bayer_pat = RKISP1_RAW_BGGR, .bus_width = 10, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .mipi_dt = MIPI_CSI2_DT_RAW10, .bayer_pat = RKISP1_RAW_GBRG, .bus_width = 10, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW10, + .mipi_dt = MIPI_CSI2_DT_RAW10, .bayer_pat = RKISP1_RAW_GRBG, .bus_width = 10, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .mipi_dt = MIPI_CSI2_DT_RAW12, .bayer_pat = RKISP1_RAW_RGGB, .bus_width = 12, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .mipi_dt = MIPI_CSI2_DT_RAW12, .bayer_pat = RKISP1_RAW_BGGR, .bus_width = 12, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .mipi_dt = MIPI_CSI2_DT_RAW12, .bayer_pat = RKISP1_RAW_GBRG, .bus_width = 12, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW12, + .mipi_dt = MIPI_CSI2_DT_RAW12, .bayer_pat = RKISP1_RAW_GRBG, .bus_width = 12, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .mipi_dt = MIPI_CSI2_DT_RAW8, .bayer_pat = RKISP1_RAW_RGGB, .bus_width = 8, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .mipi_dt = MIPI_CSI2_DT_RAW8, .bayer_pat = RKISP1_RAW_BGGR, .bus_width = 8, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .mipi_dt = MIPI_CSI2_DT_RAW8, .bayer_pat = RKISP1_RAW_GBRG, .bus_width = 8, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, - .mipi_dt = RKISP1_CIF_CSI2_DT_RAW8, + .mipi_dt = MIPI_CSI2_DT_RAW8, .bayer_pat = RKISP1_RAW_GRBG, .bus_width = 8, .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC, }, { .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR, .bus_width = 16, .direction = RKISP1_ISP_SD_SINK, }, { .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB, .bus_width = 16, .direction = RKISP1_ISP_SD_SINK, }, { .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY, .bus_width = 16, .direction = RKISP1_ISP_SD_SINK, }, { .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, - .mipi_dt = RKISP1_CIF_CSI2_DT_YUV422_8b, + .mipi_dt = MIPI_CSI2_DT_YUV422_8B, .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY, .bus_width = 16, .direction = RKISP1_ISP_SD_SINK, diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index d326214c7e07..82f8d33d98b3 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -333,17 +333,6 @@ /* MIPI_DATA_SEL */ #define RKISP1_CIF_MIPI_DATA_SEL_VC(a) (((a) & 0x3) << 6) #define RKISP1_CIF_MIPI_DATA_SEL_DT(a) (((a) & 0x3F) << 0) -/* MIPI DATA_TYPE */ -#define RKISP1_CIF_CSI2_DT_YUV420_8b 0x18 -#define RKISP1_CIF_CSI2_DT_YUV420_10b 0x19 -#define RKISP1_CIF_CSI2_DT_YUV422_8b 0x1E -#define RKISP1_CIF_CSI2_DT_YUV422_10b 0x1F -#define RKISP1_CIF_CSI2_DT_RGB565 0x22 -#define RKISP1_CIF_CSI2_DT_RGB666 0x23 -#define RKISP1_CIF_CSI2_DT_RGB888 0x24 -#define RKISP1_CIF_CSI2_DT_RAW8 0x2A -#define RKISP1_CIF_CSI2_DT_RAW10 0x2B -#define RKISP1_CIF_CSI2_DT_RAW12 0x2C /* MIPI_IMSC, MIPI_RIS, MIPI_MIS, MIPI_ICR, MIPI_ISR */ #define RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(a) (((a) & 0xF) << 0) diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c index f1cf847d1cc2..b7854ce5fb8e 100644 --- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c @@ -285,13 +285,8 @@ static const struct vb2_ops gsc_m2m_qops = { static int gsc_m2m_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct gsc_ctx *ctx = fh_to_ctx(fh); - struct gsc_dev *gsc = ctx->gsc_dev; - strscpy(cap->driver, GSC_MODULE_NAME, sizeof(cap->driver)); strscpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&gsc->pdev->dev)); return 0; } diff --git a/drivers/media/platform/samsung/exynos4-is/common.c b/drivers/media/platform/samsung/exynos4-is/common.c index 023f624d29d5..26ee2388edfd 100644 --- a/drivers/media/platform/samsung/exynos4-is/common.c +++ b/drivers/media/platform/samsung/exynos4-is/common.c @@ -41,8 +41,6 @@ void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap) { strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); strscpy(cap->card, dev->driver->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev_name(dev)); } EXPORT_SYMBOL(__fimc_vidioc_querycap); diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c index e55e411038f4..e3072d69c49f 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c @@ -140,7 +140,7 @@ static int fimc_is_enable_clocks(struct fimc_is *is) dev_err(&is->pdev->dev, "clock %s enable failed\n", fimc_is_clocks[i]); for (--i; i >= 0; i--) - clk_disable(is->clocks[i]); + clk_disable_unprepare(is->clocks[i]); return ret; } pr_debug("enabled clock: %s\n", fimc_is_clocks[i]); @@ -830,7 +830,7 @@ static int fimc_is_probe(struct platform_device *pdev) ret = pm_runtime_resume_and_get(dev); if (ret < 0) - goto err_irq; + goto err_pm_disable; vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); @@ -864,6 +864,8 @@ err_pm: pm_runtime_put_noidle(dev); if (!pm_runtime_enabled(dev)) fimc_is_runtime_suspend(dev); +err_pm_disable: + pm_runtime_disable(dev); err_irq: free_irq(is->irq, is); err_clk: diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.h b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.h index edcb3a5e3cb9..2dd4ddbc748a 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.h @@ -32,7 +32,7 @@ static inline int fimc_isp_video_device_register(struct fimc_isp *isp, return 0; } -void fimc_isp_video_device_unregister(struct fimc_isp *isp, +static inline void fimc_isp_video_device_unregister(struct fimc_isp *isp, enum v4l2_buf_type type) { } diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 2e8f476efc5c..1a396b7cd9a9 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -646,12 +646,8 @@ static void fimc_lite_try_compose(struct fimc_lite *fimc, struct v4l2_rect *r) static int fimc_lite_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct fimc_lite *fimc = video_drvdata(file); - strscpy(cap->driver, FIMC_LITE_DRV_NAME, sizeof(cap->driver)); strscpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&fimc->pdev->dev)); return 0; } diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c index 5479bc8d474d..456287186ad8 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c @@ -1257,8 +1257,6 @@ static int s5p_jpeg_querycap(struct file *file, void *priv, strscpy(cap->card, S5P_JPEG_M2M_NAME " decoder", sizeof(cap->card)); } - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(ctx->jpeg->dev)); return 0; } diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-s5p.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-s5p.c index 01b47b3df1e7..33e6e85dfd78 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-s5p.c +++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-s5p.c @@ -52,7 +52,6 @@ void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode) { unsigned long reg, m; - m = S5P_PROC_MODE_DECOMPR; if (mode == S5P_JPEG_ENCODE) m = S5P_PROC_MODE_COMPR; else diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c index 4b89df8bfd18..268ffe4da53c 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -288,8 +288,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver)); strscpy(cap->card, dev->vfd_dec->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&dev->plat_dev->dev)); return 0; } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index a8877d805b29..b65e506665af 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -1309,8 +1309,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver)); strscpy(cap->card, dev->vfd_enc->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&dev->plat_dev->dev)); return 0; } diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c index 5aa79d9277c8..dd74cc43920d 100644 --- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c @@ -1394,8 +1394,7 @@ err_remove: bdisp_debugfs_remove(bdisp); v4l2_device_unregister(&bdisp->v4l2_dev); err_clk: - if (!IS_ERR(bdisp->clock)) - clk_unprepare(bdisp->clock); + clk_unprepare(bdisp->clock); err_wq: destroy_workqueue(bdisp->work_queue); return ret; diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h index 5ab7ca448cf9..f8d97841f366 100644 --- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h +++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.h @@ -13,7 +13,6 @@ #include <linux/dvb/dmx.h> #include <linux/dvb/frontend.h> #include <linux/gpio.h> -#include <linux/version.h> #include <media/dmxdev.h> #include <media/dvb_demux.h> diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c index c887a31ebb54..420ad4d8df5d 100644 --- a/drivers/media/platform/st/sti/delta/delta-v4l2.c +++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c @@ -1859,7 +1859,7 @@ static int delta_probe(struct platform_device *pdev) if (ret) { dev_err(delta->dev, "%s failed to initialize firmware ipc channel\n", DELTA_PREFIX); - goto err; + goto err_pm_disable; } /* register all available decoders */ @@ -1873,7 +1873,7 @@ static int delta_probe(struct platform_device *pdev) if (ret) { dev_err(delta->dev, "%s failed to register V4L2 device\n", DELTA_PREFIX); - goto err; + goto err_pm_disable; } delta->work_queue = create_workqueue(DELTA_NAME); @@ -1898,6 +1898,8 @@ err_work_queue: destroy_workqueue(delta->work_queue); err_v4l2: v4l2_device_unregister(&delta->v4l2_dev); +err_pm_disable: + pm_runtime_disable(dev); err: return ret; } diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index c4c65d852525..09a743cd7004 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -1997,8 +1997,6 @@ static int dcmi_probe(struct platform_device *pdev) /* Initialize media device */ strscpy(dcmi->mdev.model, DRV_NAME, sizeof(dcmi->mdev.model)); - snprintf(dcmi->mdev.bus_info, sizeof(dcmi->mdev.bus_info), - "platform:%s", DRV_NAME); dcmi->mdev.dev = &pdev->dev; media_device_init(&dcmi->mdev); diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index 80a10f238bbe..18e6c65f4737 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -173,8 +173,6 @@ static int sun4i_csi_probe(struct platform_device *pdev) strscpy(csi->mdev.model, "Allwinner Video Capture Device", sizeof(csi->mdev.model)); csi->mdev.hw_revision = 0; - snprintf(csi->mdev.bus_info, sizeof(csi->mdev.bus_info), "platform:%s", - dev_name(csi->dev)); media_device_init(&csi->mdev); csi->v4l.mdev = &csi->mdev; diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c index 3872027ed2fa..48702134ccc5 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c @@ -53,12 +53,8 @@ const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc, static int sun4i_csi_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct sun4i_csi *csi = video_drvdata(file); - strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, "sun4i-csi", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(csi->dev)); return 0; } diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index fc96921b0583..a971587dbbd1 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -733,8 +733,6 @@ static int sun6i_csi_v4l2_init(struct sun6i_csi *csi) strscpy(csi->media_dev.model, "Allwinner Video Capture Device", sizeof(csi->media_dev.model)); csi->media_dev.hw_revision = 0; - snprintf(csi->media_dev.bus_info, sizeof(csi->media_dev.bus_info), - "platform:%s", dev_name(csi->dev)); media_device_init(&csi->media_dev); v4l2_async_nf_init(&csi->notifier); diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c index 6b43a1525b45..e69fed117fea 100644 --- a/drivers/media/platform/ti/cal/cal-camerarx.c +++ b/drivers/media/platform/ti/cal/cal-camerarx.c @@ -583,6 +583,33 @@ done: return ret; } +int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy, + struct v4l2_mbus_frame_desc *desc) +{ + struct media_pad *pad; + int ret; + + if (!phy->source) + return -EPIPE; + + pad = media_entity_remote_pad(&phy->pads[CAL_CAMERARX_PAD_SINK]); + if (!pad) + return -EPIPE; + + ret = v4l2_subdev_call(phy->source, pad, get_frame_desc, pad->index, + desc); + if (ret) + return ret; + + if (desc->type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + dev_err(phy->cal->dev, + "Frame descriptor does not describe CSI-2 link"); + return -EINVAL; + } + + return 0; +} + /* ------------------------------------------------------------------ * V4L2 Subdev Operations * ------------------------------------------------------------------ diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c index 3e936a2ca36c..07ae1a34e6b0 100644 --- a/drivers/media/platform/ti/cal/cal-video.c +++ b/drivers/media/platform/ti/cal/cal-video.c @@ -47,13 +47,9 @@ static char *fourcc_to_str(u32 fmt) static int cal_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct cal_ctx *ctx = video_drvdata(file); - strscpy(cap->driver, CAL_MODULE_NAME, sizeof(cap->driver)); strscpy(cap->card, CAL_MODULE_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev_name(ctx->cal->dev)); return 0; } diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c index 4a4a6c5983f7..425b4f4b7ed7 100644 --- a/drivers/media/platform/ti/cal/cal.c +++ b/drivers/media/platform/ti/cal/cal.c @@ -469,10 +469,57 @@ static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) return stopped; } +static int +cal_get_remote_frame_desc_entry(struct cal_camerarx *phy, + struct v4l2_mbus_frame_desc_entry *entry) +{ + struct v4l2_mbus_frame_desc fd; + int ret; + + ret = cal_camerarx_get_remote_frame_desc(phy, &fd); + if (ret) { + if (ret != -ENOIOCTLCMD) + dev_err(phy->cal->dev, + "Failed to get remote frame desc: %d\n", ret); + return ret; + } + + if (fd.num_entries == 0) { + dev_err(phy->cal->dev, + "No streams found in the remote frame descriptor\n"); + + return -ENODEV; + } + + if (fd.num_entries > 1) + dev_dbg(phy->cal->dev, + "Multiple streams not supported in remote frame descriptor, using the first one\n"); + + *entry = fd.entry[0]; + + return 0; +} + int cal_ctx_prepare(struct cal_ctx *ctx) { + struct v4l2_mbus_frame_desc_entry entry; int ret; + ret = cal_get_remote_frame_desc_entry(ctx->phy, &entry); + + if (ret == -ENOIOCTLCMD) { + ctx->vc = 0; + ctx->datatype = CAL_CSI2_CTX_DT_ANY; + } else if (!ret) { + ctx_dbg(2, ctx, "Framedesc: len %u, vc %u, dt %#x\n", + entry.length, entry.bus.csi2.vc, entry.bus.csi2.dt); + + ctx->vc = entry.bus.csi2.vc; + ctx->datatype = entry.bus.csi2.dt; + } else { + return ret; + } + ctx->use_pix_proc = !ctx->fmtinfo->meta; if (ctx->use_pix_proc) { @@ -884,8 +931,6 @@ static int cal_media_init(struct cal_dev *cal) mdev->dev = cal->dev; mdev->hw_revision = cal->revision; strscpy(mdev->model, "CAL", sizeof(mdev->model)); - snprintf(mdev->bus_info, sizeof(mdev->bus_info), "platform:%s", - dev_name(mdev->dev)); media_device_init(mdev); /* @@ -936,8 +981,6 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) ctx->dma_ctx = inst; ctx->csi2_ctx = inst; ctx->cport = inst; - ctx->vc = 0; - ctx->datatype = CAL_CSI2_CTX_DT_ANY; ret = cal_ctx_v4l2_init(ctx); if (ret) diff --git a/drivers/media/platform/ti/cal/cal.h b/drivers/media/platform/ti/cal/cal.h index 527e22d022f3..61409ddced98 100644 --- a/drivers/media/platform/ti/cal/cal.h +++ b/drivers/media/platform/ti/cal/cal.h @@ -323,6 +323,8 @@ const struct cal_format_info *cal_format_by_code(u32 code); void cal_quickdump_regs(struct cal_dev *cal); +int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy, + struct v4l2_mbus_frame_desc *desc); void cal_camerarx_disable(struct cal_camerarx *phy); void cal_camerarx_i913_errata(struct cal_camerarx *phy); struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, diff --git a/drivers/media/platform/ti/davinci/dm355_ccdc.c b/drivers/media/platform/ti/davinci/dm355_ccdc.c index e06d113dfe96..8fe55d1b972c 100644 --- a/drivers/media/platform/ti/davinci/dm355_ccdc.c +++ b/drivers/media/platform/ti/davinci/dm355_ccdc.c @@ -918,8 +918,7 @@ static int dm355_ccdc_remove(struct platform_device *pdev) iounmap(ccdc_cfg.base_addr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); + release_mem_region(res->start, resource_size(res)); vpfe_unregister_ccdc_device(&ccdc_hw_dev); return 0; } diff --git a/drivers/media/platform/ti/davinci/dm644x_ccdc.c b/drivers/media/platform/ti/davinci/dm644x_ccdc.c index c6378c4e0074..e4073e99914c 100644 --- a/drivers/media/platform/ti/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/ti/davinci/dm644x_ccdc.c @@ -839,8 +839,7 @@ static int dm644x_ccdc_remove(struct platform_device *pdev) iounmap(ccdc_cfg.base_addr); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) - release_mem_region(res->start, resource_size(res)); + release_mem_region(res->start, resource_size(res)); vpfe_unregister_ccdc_device(&ccdc_hw_dev); return 0; } diff --git a/drivers/media/platform/ti/davinci/isif.c b/drivers/media/platform/ti/davinci/isif.c index c53cecd072b1..69e862de014f 100644 --- a/drivers/media/platform/ti/davinci/isif.c +++ b/drivers/media/platform/ti/davinci/isif.c @@ -1107,8 +1107,7 @@ static int isif_remove(struct platform_device *pdev) isif_cfg.linear_tbl1_addr = NULL; while (i < 3) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); - if (res) - release_mem_region(res->start, resource_size(res)); + release_mem_region(res->start, resource_size(res)); i++; } vpfe_unregister_ccdc_device(&isif_hw_dev); diff --git a/drivers/media/platform/ti/davinci/vpbe_display.c b/drivers/media/platform/ti/davinci/vpbe_display.c index bf3c3e76b921..9ea70817538e 100644 --- a/drivers/media/platform/ti/davinci/vpbe_display.c +++ b/drivers/media/platform/ti/davinci/vpbe_display.c @@ -630,8 +630,6 @@ static int vpbe_display_querycap(struct file *file, void *priv, snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpbe_dev->pdev)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(vpbe_dev->pdev)); strscpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card)); return 0; diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c index bf76c5c83743..b91eec899eb5 100644 --- a/drivers/media/platform/ti/davinci/vpif_capture.c +++ b/drivers/media/platform/ti/davinci/vpif_capture.c @@ -1067,8 +1067,6 @@ static int vpif_querycap(struct file *file, void *priv, struct vpif_capture_config *config = vpif_dev->platform_data; strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(vpif_dev)); strscpy(cap->card, config->card_name, sizeof(cap->card)); return 0; diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c index fca148b66471..5d524acc995d 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.c +++ b/drivers/media/platform/ti/davinci/vpif_display.c @@ -585,8 +585,6 @@ static int vpif_querycap(struct file *file, void *priv, struct vpif_display_config *config = vpif_dev->platform_data; strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(vpif_dev)); strscpy(cap->card, config->card_name, sizeof(cap->card)); return 0; @@ -1286,8 +1284,7 @@ static __init int vpif_probe(struct platform_device *pdev) goto probe_subdev_out; } - if (vpif_obj.sd[i]) - vpif_obj.sd[i]->grp_id = 1 << i; + vpif_obj.sd[i]->grp_id = 1 << i; } err = vpif_probe_complete(); if (err) diff --git a/drivers/media/platform/ti/omap3isp/ispcsiphy.c b/drivers/media/platform/ti/omap3isp/ispcsiphy.c index 6dc7359c5131..1bde76c0adbe 100644 --- a/drivers/media/platform/ti/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/ti/omap3isp/ispcsiphy.c @@ -31,7 +31,8 @@ static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, switch (iface) { default: - /* Should not happen in practice, but let's keep the compiler happy. */ + /* Should not happen in practice, but let's keep the compiler happy. */ + return; case ISP_INTERFACE_CCP2B_PHY1: reg &= ~OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2; shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT; diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index fda8fc0e4814..b31e5913a4cd 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -442,9 +442,7 @@ static int video_mux_probe(struct platform_device *pdev) vmux->mux = devm_mux_control_get(dev, NULL); if (IS_ERR(vmux->mux)) { ret = PTR_ERR(vmux->mux); - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get mux: %d\n", ret); - return ret; + return dev_err_probe(dev, ret, "Failed to get mux\n"); } mutex_init(&vmux->lock); diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index cca03bd2cc42..616a38feb641 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -4,10 +4,10 @@ # menuconfig RADIO_ADAPTERS - bool "Radio Adapters" + tristate "Radio Adapters" depends on VIDEO_DEV depends on MEDIA_RADIO_SUPPORT - default y + default VIDEO_DEV help Say Y here to enable selecting AM/FM radio adapters. diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index de107e2cbcd6..1a5dbae24ef4 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -144,8 +144,6 @@ static int maxiradio_probe(struct pci_dev *pdev, dev->tea.v4l2_dev = v4l2_dev; dev->tea.radio_nr = radio_nr; strscpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card)); - snprintf(dev->tea.bus_info, sizeof(dev->tea.bus_info), - "PCI:%s", pci_name(pdev)); retval = -ENODEV; diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c index a50701cfbbd7..d3063ddb472e 100644 --- a/drivers/media/rc/gpio-ir-tx.c +++ b/drivers/media/rc/gpio-ir-tx.c @@ -62,8 +62,13 @@ static void delay_until(ktime_t until) return; /* udelay more than 1ms may not work */ - delta = min(delta, 1000); + if (delta >= 1000) { + mdelay(delta / 1000); + continue; + } + udelay(delta); + break; } } diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 54da6f60079b..735b925da998 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -153,6 +153,24 @@ struct imon_context { const struct imon_usb_dev_descr *dev_descr; /* device description with key */ /* table for front panels */ + /* + * Fields for deferring free_imon_context(). + * + * Since reference to "struct imon_context" is stored into + * "struct file"->private_data, we need to remember + * how many file descriptors might access this "struct imon_context". + */ + refcount_t users; + /* + * Use a flag for telling display_open()/vfd_write()/lcd_write() that + * imon_disconnect() was already called. + */ + bool disconnected; + /* + * We need to wait for RCU grace period in order to allow + * display_open() to safely check ->disconnected and increment ->users. + */ + struct rcu_head rcu; }; #define TOUCH_TIMEOUT (HZ/30) @@ -160,18 +178,18 @@ struct imon_context { /* vfd character device file operations */ static const struct file_operations vfd_fops = { .owner = THIS_MODULE, - .open = &display_open, - .write = &vfd_write, - .release = &display_close, + .open = display_open, + .write = vfd_write, + .release = display_close, .llseek = noop_llseek, }; /* lcd character device file operations */ static const struct file_operations lcd_fops = { .owner = THIS_MODULE, - .open = &display_open, - .write = &lcd_write, - .release = &display_close, + .open = display_open, + .write = lcd_write, + .release = display_close, .llseek = noop_llseek, }; @@ -439,9 +457,6 @@ static struct usb_driver imon_driver = { .id_table = imon_usb_id_table, }; -/* to prevent races between open() and disconnect(), probing, etc */ -static DEFINE_MUTEX(driver_lock); - /* Module bookkeeping bits */ MODULE_AUTHOR(MOD_AUTHOR); MODULE_DESCRIPTION(MOD_DESC); @@ -481,9 +496,11 @@ static void free_imon_context(struct imon_context *ictx) struct device *dev = ictx->dev; usb_free_urb(ictx->tx_urb); + WARN_ON(ictx->dev_present_intf0); usb_free_urb(ictx->rx_urb_intf0); + WARN_ON(ictx->dev_present_intf1); usb_free_urb(ictx->rx_urb_intf1); - kfree(ictx); + kfree_rcu(ictx, rcu); dev_dbg(dev, "%s: iMON context freed\n", __func__); } @@ -499,9 +516,6 @@ static int display_open(struct inode *inode, struct file *file) int subminor; int retval = 0; - /* prevent races with disconnect */ - mutex_lock(&driver_lock); - subminor = iminor(inode); interface = usb_find_interface(&imon_driver, subminor); if (!interface) { @@ -509,13 +523,16 @@ static int display_open(struct inode *inode, struct file *file) retval = -ENODEV; goto exit; } - ictx = usb_get_intfdata(interface); - if (!ictx) { + rcu_read_lock(); + ictx = usb_get_intfdata(interface); + if (!ictx || ictx->disconnected || !refcount_inc_not_zero(&ictx->users)) { + rcu_read_unlock(); pr_err("no context found for minor %d\n", subminor); retval = -ENODEV; goto exit; } + rcu_read_unlock(); mutex_lock(&ictx->lock); @@ -533,8 +550,10 @@ static int display_open(struct inode *inode, struct file *file) mutex_unlock(&ictx->lock); + if (retval && refcount_dec_and_test(&ictx->users)) + free_imon_context(ictx); + exit: - mutex_unlock(&driver_lock); return retval; } @@ -544,16 +563,9 @@ exit: */ static int display_close(struct inode *inode, struct file *file) { - struct imon_context *ictx = NULL; + struct imon_context *ictx = file->private_data; int retval = 0; - ictx = file->private_data; - - if (!ictx) { - pr_err("no context for device\n"); - return -ENODEV; - } - mutex_lock(&ictx->lock); if (!ictx->display_supported) { @@ -568,6 +580,8 @@ static int display_close(struct inode *inode, struct file *file) } mutex_unlock(&ictx->lock); + if (refcount_dec_and_test(&ictx->users)) + free_imon_context(ictx); return retval; } @@ -934,15 +948,12 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, int offset; int seq; int retval = 0; - struct imon_context *ictx; + struct imon_context *ictx = file->private_data; static const unsigned char vfd_packet6[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; - ictx = file->private_data; - if (!ictx) { - pr_err_ratelimited("no context for device\n"); + if (ictx->disconnected) return -ENODEV; - } mutex_lock(&ictx->lock); @@ -1018,13 +1029,10 @@ static ssize_t lcd_write(struct file *file, const char __user *buf, size_t n_bytes, loff_t *pos) { int retval = 0; - struct imon_context *ictx; + struct imon_context *ictx = file->private_data; - ictx = file->private_data; - if (!ictx) { - pr_err_ratelimited("no context for device\n"); + if (ictx->disconnected) return -ENODEV; - } mutex_lock(&ictx->lock); @@ -2404,7 +2412,6 @@ static int imon_probe(struct usb_interface *interface, int ifnum, sysfs_err; int ret = 0; struct imon_context *ictx = NULL; - struct imon_context *first_if_ctx = NULL; u16 vendor, product; usbdev = usb_get_dev(interface_to_usbdev(interface)); @@ -2416,17 +2423,12 @@ static int imon_probe(struct usb_interface *interface, dev_dbg(dev, "%s: found iMON device (%04x:%04x, intf%d)\n", __func__, vendor, product, ifnum); - /* prevent races probing devices w/multiple interfaces */ - mutex_lock(&driver_lock); - first_if = usb_ifnum_to_if(usbdev, 0); if (!first_if) { ret = -ENODEV; goto fail; } - first_if_ctx = usb_get_intfdata(first_if); - if (ifnum == 0) { ictx = imon_init_intf0(interface, id); if (!ictx) { @@ -2434,9 +2436,11 @@ static int imon_probe(struct usb_interface *interface, ret = -ENODEV; goto fail; } + refcount_set(&ictx->users, 1); } else { /* this is the secondary interface on the device */ + struct imon_context *first_if_ctx = usb_get_intfdata(first_if); /* fail early if first intf failed to register */ if (!first_if_ctx) { @@ -2450,14 +2454,13 @@ static int imon_probe(struct usb_interface *interface, ret = -ENODEV; goto fail; } + refcount_inc(&ictx->users); } usb_set_intfdata(interface, ictx); if (ifnum == 0) { - mutex_lock(&ictx->lock); - if (product == 0xffdc && ictx->rf_device) { sysfs_err = sysfs_create_group(&interface->dev.kobj, &imon_rf_attr_group); @@ -2468,21 +2471,17 @@ static int imon_probe(struct usb_interface *interface, if (ictx->display_supported) imon_init_display(ictx, interface); - - mutex_unlock(&ictx->lock); } dev_info(dev, "iMON device (%04x:%04x, intf%d) on usb<%d:%d> initialized\n", vendor, product, ifnum, usbdev->bus->busnum, usbdev->devnum); - mutex_unlock(&driver_lock); usb_put_dev(usbdev); return 0; fail: - mutex_unlock(&driver_lock); usb_put_dev(usbdev); dev_err(dev, "unable to register, err %d\n", ret); @@ -2498,10 +2497,8 @@ static void imon_disconnect(struct usb_interface *interface) struct device *dev; int ifnum; - /* prevent races with multi-interface device probing and display_open */ - mutex_lock(&driver_lock); - ictx = usb_get_intfdata(interface); + ictx->disconnected = true; dev = ictx->dev; ifnum = interface->cur_altsetting->desc.bInterfaceNumber; @@ -2523,7 +2520,6 @@ static void imon_disconnect(struct usb_interface *interface) if (ifnum == 0) { ictx->dev_present_intf0 = false; usb_kill_urb(ictx->rx_urb_intf0); - usb_put_dev(ictx->usbdev_intf0); input_unregister_device(ictx->idev); rc_unregister_device(ictx->rdev); if (ictx->display_supported) { @@ -2532,21 +2528,20 @@ static void imon_disconnect(struct usb_interface *interface) else if (ictx->display_type == IMON_DISPLAY_TYPE_VFD) usb_deregister_dev(interface, &imon_vfd_class); } + usb_put_dev(ictx->usbdev_intf0); } else { ictx->dev_present_intf1 = false; usb_kill_urb(ictx->rx_urb_intf1); - usb_put_dev(ictx->usbdev_intf1); if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { - input_unregister_device(ictx->touch); del_timer_sync(&ictx->ttimer); + input_unregister_device(ictx->touch); } + usb_put_dev(ictx->usbdev_intf1); } - if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) + if (refcount_dec_and_test(&ictx->users)) free_imon_context(ictx); - mutex_unlock(&driver_lock); - dev_dbg(dev, "%s: iMON device (intf%d) disconnected\n", __func__, ifnum); } @@ -2578,7 +2573,7 @@ static int imon_resume(struct usb_interface *intf) usb_rx_callback_intf0, ictx, ictx->rx_endpoint_intf0->bInterval); - rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_ATOMIC); + rc = usb_submit_urb(ictx->rx_urb_intf0, GFP_NOIO); } else { usb_fill_int_urb(ictx->rx_urb_intf1, ictx->usbdev_intf1, @@ -2588,7 +2583,7 @@ static int imon_resume(struct usb_interface *intf) usb_rx_callback_intf1, ictx, ictx->rx_endpoint_intf1->bInterval); - rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC); + rc = usb_submit_urb(ictx->rx_urb_intf1, GFP_NOIO); } return rc; diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c index 63e1dbf0a4e9..abdb62b16e98 100644 --- a/drivers/media/rc/meson-ir-tx.c +++ b/drivers/media/rc/meson-ir-tx.c @@ -323,10 +323,8 @@ static int __init meson_irtx_probe(struct platform_device *pdev) return PTR_ERR(ir->reg_base); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "no irq resource found\n"); + if (irq < 0) return -ENODEV; - } ir->dev = dev; ir->carrier = MIRTX_DEFAULT_CARRIER; diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c index 36b5b6227412..5f294784923c 100644 --- a/drivers/media/usb/dvb-usb/a800.c +++ b/drivers/media/usb/dvb-usb/a800.c @@ -72,11 +72,17 @@ static int a800_probe(struct usb_interface *intf, } /* do not change the order of the ID table */ -static struct usb_device_id a800_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_WARM) }, - { } /* Terminating entry */ +enum { + AVERMEDIA_DVBT_USB2_COLD, + AVERMEDIA_DVBT_USB2_WARM, }; + +static struct usb_device_id a800_table[] = { + DVB_USB_DEV(AVERMEDIA, AVERMEDIA_DVBT_USB2_COLD), + DVB_USB_DEV(AVERMEDIA, AVERMEDIA_DVBT_USB2_WARM), + { } +}; + MODULE_DEVICE_TABLE (usb, a800_table); static struct dvb_usb_device_properties a800_properties = { @@ -132,8 +138,8 @@ static struct dvb_usb_device_properties a800_properties = { .num_device_descs = 1, .devices = { { "AVerMedia AverTV DVB-T USB 2.0 (A800)", - { &a800_table[0], NULL }, - { &a800_table[1], NULL }, + { &a800_table[AVERMEDIA_DVBT_USB2_COLD], NULL }, + { &a800_table[AVERMEDIA_DVBT_USB2_WARM], NULL }, }, } }; diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c index b6a2436d16e9..0827bf3d4e8c 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -994,19 +994,16 @@ static int af9005_usb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr); } -enum af9005_usb_table_entry { +enum { AFATECH_AF9005, - TERRATEC_AF9005, - ANSONIC_AF9005, + TERRATEC_CINERGY_T_USB_XE, + ANSONIC_DVBT_USB, }; static struct usb_device_id af9005_usb_table[] = { - [AFATECH_AF9005] = {USB_DEVICE(USB_VID_AFATECH, - USB_PID_AFATECH_AF9005)}, - [TERRATEC_AF9005] = {USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_T_USB_XE)}, - [ANSONIC_AF9005] = {USB_DEVICE(USB_VID_ANSONIC, - USB_PID_ANSONIC_DVBT_USB)}, + DVB_USB_DEV(AFATECH, AFATECH_AF9005), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_T_USB_XE), + DVB_USB_DEV(ANSONIC, ANSONIC_DVBT_USB), { } }; @@ -1071,11 +1068,11 @@ static struct dvb_usb_device_properties af9005_properties = { .warm_ids = {NULL}, }, {.name = "TerraTec Cinergy T USB XE", - .cold_ids = {&af9005_usb_table[TERRATEC_AF9005], NULL}, + .cold_ids = {&af9005_usb_table[TERRATEC_CINERGY_T_USB_XE], NULL}, .warm_ids = {NULL}, }, {.name = "Ansonic DVB-T USB1.1 stick", - .cold_ids = {&af9005_usb_table[ANSONIC_AF9005], NULL}, + .cold_ids = {&af9005_usb_table[ANSONIC_DVBT_USB], NULL}, .warm_ids = {NULL}, }, {NULL}, diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c index 86788771175b..cf15988dfb51 100644 --- a/drivers/media/usb/dvb-usb/az6027.c +++ b/drivers/media/usb/dvb-usb/az6027.c @@ -1080,16 +1080,27 @@ static int az6027_identify_state(struct usb_device *udev, } +enum { + AZUREWAVE_AZ6027, + TERRATEC_DVBS2CI_V1, + TERRATEC_DVBS2CI_V2, + TECHNISAT_USB2_HDCI_V1, + TECHNISAT_USB2_HDCI_V2, + ELGATO_EYETV_SAT, + ELGATO_EYETV_SAT_V2, + ELGATO_EYETV_SAT_V3, +}; + static struct usb_device_id az6027_usb_table[] = { - { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_AZ6027) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V1) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V2) }, - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) }, - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V2) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V3) }, - { }, + DVB_USB_DEV(AZUREWAVE, AZUREWAVE_AZ6027), + DVB_USB_DEV(TERRATEC, TERRATEC_DVBS2CI_V1), + DVB_USB_DEV(TERRATEC, TERRATEC_DVBS2CI_V2), + DVB_USB_DEV(TECHNISAT, TECHNISAT_USB2_HDCI_V1), + DVB_USB_DEV(TECHNISAT, TECHNISAT_USB2_HDCI_V2), + DVB_USB_DEV(ELGATO, ELGATO_EYETV_SAT), + DVB_USB_DEV(ELGATO, ELGATO_EYETV_SAT_V2), + DVB_USB_DEV(ELGATO, ELGATO_EYETV_SAT_V3), + { } }; MODULE_DEVICE_TABLE(usb, az6027_usb_table); @@ -1141,35 +1152,35 @@ static struct dvb_usb_device_properties az6027_properties = { .devices = { { .name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)", - .cold_ids = { &az6027_usb_table[0], NULL }, + .cold_ids = { &az6027_usb_table[AZUREWAVE_AZ6027], NULL }, .warm_ids = { NULL }, }, { .name = "TERRATEC S7", - .cold_ids = { &az6027_usb_table[1], NULL }, + .cold_ids = { &az6027_usb_table[TERRATEC_DVBS2CI_V1], NULL }, .warm_ids = { NULL }, }, { .name = "TERRATEC S7 MKII", - .cold_ids = { &az6027_usb_table[2], NULL }, + .cold_ids = { &az6027_usb_table[TERRATEC_DVBS2CI_V2], NULL }, .warm_ids = { NULL }, }, { .name = "Technisat SkyStar USB 2 HD CI", - .cold_ids = { &az6027_usb_table[3], NULL }, + .cold_ids = { &az6027_usb_table[TECHNISAT_USB2_HDCI_V1], NULL }, .warm_ids = { NULL }, }, { .name = "Technisat SkyStar USB 2 HD CI", - .cold_ids = { &az6027_usb_table[4], NULL }, + .cold_ids = { &az6027_usb_table[TECHNISAT_USB2_HDCI_V2], NULL }, .warm_ids = { NULL }, }, { .name = "Elgato EyeTV Sat", - .cold_ids = { &az6027_usb_table[5], NULL }, + .cold_ids = { &az6027_usb_table[ELGATO_EYETV_SAT], NULL }, .warm_ids = { NULL }, }, { .name = "Elgato EyeTV Sat", - .cold_ids = { &az6027_usb_table[6], NULL }, + .cold_ids = { &az6027_usb_table[ELGATO_EYETV_SAT_V2], NULL }, .warm_ids = { NULL }, }, { .name = "Elgato EyeTV Sat", - .cold_ids = { &az6027_usb_table[7], NULL }, + .cold_ids = { &az6027_usb_table[ELGATO_EYETV_SAT_V3], NULL }, .warm_ids = { NULL }, }, { NULL }, diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c index 23f1093d28f8..4926c954e29a 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c @@ -193,9 +193,13 @@ static int cinergyt2_usb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr); } +enum { + TERRATEC_CINERGY_T2, +}; + static struct usb_device_id cinergyt2_usb_table[] = { - { USB_DEVICE(USB_VID_TERRATEC, 0x0038) }, - { 0 } + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_T2), + { } }; MODULE_DEVICE_TABLE(usb, cinergyt2_usb_table); @@ -240,7 +244,7 @@ static const struct dvb_usb_device_properties cinergyt2_properties = { .devices = { { .name = "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver", .cold_ids = {NULL}, - .warm_ids = { &cinergyt2_usb_table[0], NULL }, + .warm_ids = { &cinergyt2_usb_table[TERRATEC_CINERGY_T2], NULL }, }, { NULL }, } diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 265b960db499..1d98d3465e28 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -1692,72 +1692,30 @@ static void cxusb_disconnect(struct usb_interface *intf) dvb_usb_device_exit(intf); } -static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { - [MEDION_MD95700] = { - USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) - }, - [DVICO_BLUEBIRD_LG064F_COLD] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) - }, - [DVICO_BLUEBIRD_LG064F_WARM] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) - }, - [DVICO_BLUEBIRD_DUAL_1_COLD] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) - }, - [DVICO_BLUEBIRD_DUAL_1_WARM] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) - }, - [DVICO_BLUEBIRD_LGZ201_COLD] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) - }, - [DVICO_BLUEBIRD_LGZ201_WARM] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) - }, - [DVICO_BLUEBIRD_TH7579_COLD] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) - }, - [DVICO_BLUEBIRD_TH7579_WARM] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) - }, - [DIGITALNOW_BLUEBIRD_DUAL_1_COLD] = { - USB_DEVICE(USB_VID_DVICO, - USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) - }, - [DIGITALNOW_BLUEBIRD_DUAL_1_WARM] = { - USB_DEVICE(USB_VID_DVICO, - USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) - }, - [DVICO_BLUEBIRD_DUAL_2_COLD] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) - }, - [DVICO_BLUEBIRD_DUAL_2_WARM] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) - }, - [DVICO_BLUEBIRD_DUAL_4] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4) - }, - [DVICO_BLUEBIRD_DVB_T_NANO_2] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) - }, - [DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM] = { - USB_DEVICE(USB_VID_DVICO, - USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) - }, - [AVERMEDIA_VOLAR_A868R] = { - USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) - }, - [DVICO_BLUEBIRD_DUAL_4_REV_2] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) - }, - [CONEXANT_D680_DMB] = { - USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) - }, - [MYGICA_D689] = { - USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) - }, - {} /* Terminating entry */ +static struct usb_device_id cxusb_table[] = { + DVB_USB_DEV(MEDION, MEDION_MD95700), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LG064F_COLD), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LG064F_WARM), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_1_COLD), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_1_WARM), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LGZ201_COLD), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_LGZ201_WARM), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_TH7579_COLD), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_TH7579_WARM), + DVB_USB_DEV(DVICO, DIGITALNOW_BLUEBIRD_DUAL_1_COLD), + DVB_USB_DEV(DVICO, DIGITALNOW_BLUEBIRD_DUAL_1_WARM), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_2_COLD), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_2_WARM), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_4), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DVB_T_NANO_2), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM), + DVB_USB_DEV(AVERMEDIA, AVERMEDIA_VOLAR_A868R), + DVB_USB_DEV(DVICO, DVICO_BLUEBIRD_DUAL_4_REV_2), + DVB_USB_DEV(CONEXANT, CONEXANT_D680_DMB), + DVB_USB_DEV(CONEXANT, MYGICA_D689), + { } }; + MODULE_DEVICE_TABLE(usb, cxusb_table); static struct dvb_usb_device_properties cxusb_medion_properties = { diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 08fcf120daf1..7f8bebfa3e8e 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -3816,99 +3816,187 @@ fail_demod_device: /* DVB-USB and USB stuff follows */ +enum { + DIBCOM_STK7700P, + DIBCOM_STK7700P_PC, + HAUPPAUGE_NOVA_T_500, + HAUPPAUGE_NOVA_T_500_2, + HAUPPAUGE_NOVA_T_STICK, + AVERMEDIA_VOLAR, + COMPRO_VIDEOMATE_U500, + UNIWILL_STK7700P, + LEADTEK_WINFAST_DTV_DONGLE_STK7700P, + HAUPPAUGE_NOVA_T_STICK_2, + AVERMEDIA_VOLAR_2, + PINNACLE_PCTV2000E, + TERRATEC_CINERGY_DT_XS_DIVERSITY, + HAUPPAUGE_NOVA_TD_STICK, + DIBCOM_STK7700D, + DIBCOM_STK7070P, + PINNACLE_PCTV_DVB_T_FLASH, + DIBCOM_STK7070PD, + PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T, + COMPRO_VIDEOMATE_U500_PC, + AVERMEDIA_EXPRESS, + GIGABYTE_U7000, + ULTIMA_ARTEC_T14BR, + ASUS_U3000, + ASUS_U3100, + HAUPPAUGE_NOVA_T_STICK_3, + HAUPPAUGE_MYTV_T, + TERRATEC_CINERGY_HT_USB_XE, + PINNACLE_EXPRESSCARD_320CX, + PINNACLE_PCTV72E, + PINNACLE_PCTV73E, + YUAN_EC372S, + TERRATEC_CINERGY_HT_EXPRESS, + TERRATEC_CINERGY_T_XXS, + LEADTEK_WINFAST_DTV_DONGLE_STK7700P_2, + HAUPPAUGE_NOVA_TD_STICK_52009, + HAUPPAUGE_NOVA_T_500_3, + GIGABYTE_U8000, + YUAN_STK7700PH, + ASUS_U3000H, + PINNACLE_PCTV801E, + PINNACLE_PCTV801E_SE, + TERRATEC_CINERGY_T_EXPRESS, + TERRATEC_CINERGY_DT_XS_DIVERSITY_2, + SONY_PLAYTV, + YUAN_PD378S, + HAUPPAUGE_TIGER_ATSC, + HAUPPAUGE_TIGER_ATSC_B210, + YUAN_MC770, + ELGATO_EYETV_DTT, + ELGATO_EYETV_DTT_Dlx, + LEADTEK_WINFAST_DTV_DONGLE_H, + TERRATEC_T3, + TERRATEC_T5, + YUAN_STK7700D, + YUAN_STK7700D_2, + PINNACLE_PCTV73A, + PCTV_PINNACLE_PCTV73ESE, + PCTV_PINNACLE_PCTV282E, + DIBCOM_STK7770P, + TERRATEC_CINERGY_T_XXS_2, + DIBCOM_STK807XPVR, + DIBCOM_STK807XP, + PIXELVIEW_SBTVD, + EVOLUTEPC_TVWAY_PLUS, + PINNACLE_PCTV73ESE, + PINNACLE_PCTV282E, + DIBCOM_STK8096GP, + ELGATO_EYETV_DIVERSITY, + DIBCOM_NIM9090M, + DIBCOM_NIM8096MD, + DIBCOM_NIM9090MD, + DIBCOM_NIM7090, + DIBCOM_TFE7090PVR, + TECHNISAT_AIRSTAR_TELESTICK_2, + MEDION_CREATIX_CTX1921, + PINNACLE_PCTV340E, + PINNACLE_PCTV340E_SE, + DIBCOM_TFE7790P, + DIBCOM_TFE8096P, + ELGATO_EYETV_DTT_2, + PCTV_2002E, + PCTV_2002E_SE, + PCTV_DIBCOM_STK8096PVR, + DIBCOM_STK8096PVR, + HAMA_DVBT_HYBRID, + MICROSOFT_XBOX_ONE_TUNER, +}; + struct usb_device_id dib0700_usb_id_table[] = { -/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) }, -/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) }, - { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) }, - { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) }, - { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) }, -/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) }, - { USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) }, -/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) }, - { USB_DEVICE(USB_VID_PINNACLE, - USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) }, - { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) }, -/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) }, - { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) }, - { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) }, -/* 25 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_USB_XE) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_EXPRESSCARD_320CX) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV72E) }, -/* 30 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73E) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_EC372S) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) }, - { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, -/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, - { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U8000) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700PH) }, - { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000H) }, -/* 40 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV801E_SE) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_EXPRESS) }, - { USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2) }, - { USB_DEVICE(USB_VID_SONY, USB_PID_SONY_PLAYTV) }, -/* 45 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_PD378S) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_TIGER_ATSC_B210) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_MC770) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT) }, -/* 50 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_Dlx) }, - { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_H) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T3) }, - { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_T5) }, - { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D) }, -/* 55 */{ USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_STK7700D_2) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73A) }, - { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV73ESE) }, - { USB_DEVICE(USB_VID_PCTV, USB_PID_PINNACLE_PCTV282E) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7770P) }, -/* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) }, - { USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x000, 0x3f00) }, - { USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) }, -/* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096GP) }, - { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DIVERSITY) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090M) }, -/* 70 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM8096MD) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM9090MD) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM7090) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) }, - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) }, -/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV340E_SE) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7790P) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE8096P) }, -/* 80 */{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_DTT_2) }, - { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E) }, - { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E_SE) }, - { USB_DEVICE(USB_VID_PCTV, USB_PID_DIBCOM_STK8096PVR) }, - { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096PVR) }, -/* 85 */{ USB_DEVICE(USB_VID_HAMA, USB_PID_HAMA_DVBT_HYBRID) }, - { USB_DEVICE(USB_VID_MICROSOFT, USB_PID_XBOX_ONE_TUNER) }, - { 0 } /* Terminating entry */ + DVB_USB_DEV(DIBCOM, DIBCOM_STK7700P), + DVB_USB_DEV(DIBCOM, DIBCOM_STK7700P_PC), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_NOVA_T_500), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_NOVA_T_500_2), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_NOVA_T_STICK), + DVB_USB_DEV(AVERMEDIA, AVERMEDIA_VOLAR), + DVB_USB_DEV(COMPRO, COMPRO_VIDEOMATE_U500), + DVB_USB_DEV(UNIWILL, UNIWILL_STK7700P), + DVB_USB_DEV(LEADTEK, LEADTEK_WINFAST_DTV_DONGLE_STK7700P), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_NOVA_T_STICK_2), + DVB_USB_DEV(AVERMEDIA, AVERMEDIA_VOLAR_2), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV2000E), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_DT_XS_DIVERSITY), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_NOVA_TD_STICK), + DVB_USB_DEV(DIBCOM, DIBCOM_STK7700D), + DVB_USB_DEV(DIBCOM, DIBCOM_STK7070P), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_DVB_T_FLASH), + DVB_USB_DEV(DIBCOM, DIBCOM_STK7070PD), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T), + DVB_USB_DEV(COMPRO, COMPRO_VIDEOMATE_U500_PC), + DVB_USB_DEV(AVERMEDIA, AVERMEDIA_EXPRESS), + DVB_USB_DEV(GIGABYTE, GIGABYTE_U7000), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_ARTEC_T14BR), + DVB_USB_DEV(ASUS, ASUS_U3000), + DVB_USB_DEV(ASUS, ASUS_U3100), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_NOVA_T_STICK_3), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_MYTV_T), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_HT_USB_XE), + DVB_USB_DEV(PINNACLE, PINNACLE_EXPRESSCARD_320CX), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV72E), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV73E), + DVB_USB_DEV(YUAN, YUAN_EC372S), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_HT_EXPRESS), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_T_XXS), + DVB_USB_DEV(LEADTEK, LEADTEK_WINFAST_DTV_DONGLE_STK7700P_2), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_NOVA_TD_STICK_52009), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_NOVA_T_500_3), + DVB_USB_DEV(GIGABYTE, GIGABYTE_U8000), + DVB_USB_DEV(YUAN, YUAN_STK7700PH), + DVB_USB_DEV(ASUS, ASUS_U3000H), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV801E), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV801E_SE), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_T_EXPRESS), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_DT_XS_DIVERSITY_2), + DVB_USB_DEV(SONY, SONY_PLAYTV), + DVB_USB_DEV(YUAN, YUAN_PD378S), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_TIGER_ATSC), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_TIGER_ATSC_B210), + DVB_USB_DEV(YUAN, YUAN_MC770), + DVB_USB_DEV(ELGATO, ELGATO_EYETV_DTT), + DVB_USB_DEV(ELGATO, ELGATO_EYETV_DTT_Dlx), + DVB_USB_DEV(LEADTEK, LEADTEK_WINFAST_DTV_DONGLE_H), + DVB_USB_DEV(TERRATEC, TERRATEC_T3), + DVB_USB_DEV(TERRATEC, TERRATEC_T5), + DVB_USB_DEV(YUAN, YUAN_STK7700D), + DVB_USB_DEV(YUAN, YUAN_STK7700D_2), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV73A), + DVB_USB_DEV(PCTV, PCTV_PINNACLE_PCTV73ESE), + DVB_USB_DEV(PCTV, PCTV_PINNACLE_PCTV282E), + DVB_USB_DEV(DIBCOM, DIBCOM_STK7770P), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_T_XXS_2), + DVB_USB_DEV(DIBCOM, DIBCOM_STK807XPVR), + DVB_USB_DEV(DIBCOM, DIBCOM_STK807XP), + DVB_USB_DEV_VER(PIXELVIEW, PIXELVIEW_SBTVD, 0x000, 0x3f00), + DVB_USB_DEV(EVOLUTEPC, EVOLUTEPC_TVWAY_PLUS), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV73ESE), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV282E), + DVB_USB_DEV(DIBCOM, DIBCOM_STK8096GP), + DVB_USB_DEV(ELGATO, ELGATO_EYETV_DIVERSITY), + DVB_USB_DEV(DIBCOM, DIBCOM_NIM9090M), + DVB_USB_DEV(DIBCOM, DIBCOM_NIM8096MD), + DVB_USB_DEV(DIBCOM, DIBCOM_NIM9090MD), + DVB_USB_DEV(DIBCOM, DIBCOM_NIM7090), + DVB_USB_DEV(DIBCOM, DIBCOM_TFE7090PVR), + DVB_USB_DEV(TECHNISAT, TECHNISAT_AIRSTAR_TELESTICK_2), + DVB_USB_DEV(MEDION, MEDION_CREATIX_CTX1921), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV340E), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV340E_SE), + DVB_USB_DEV(DIBCOM, DIBCOM_TFE7790P), + DVB_USB_DEV(DIBCOM, DIBCOM_TFE8096P), + DVB_USB_DEV(ELGATO, ELGATO_EYETV_DTT_2), + DVB_USB_DEV(PCTV, PCTV_2002E), + DVB_USB_DEV(PCTV, PCTV_2002E_SE), + DVB_USB_DEV(PCTV, PCTV_DIBCOM_STK8096PVR), + DVB_USB_DEV(DIBCOM, DIBCOM_STK8096PVR), + DVB_USB_DEV(HAMA, HAMA_DVBT_HYBRID), + DVB_USB_DEV(MICROSOFT, MICROSOFT_XBOX_ONE_TUNER), + { } }; + MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); #define DIB0700_DEFAULT_DEVICE_PROPERTIES \ @@ -3962,35 +4050,35 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 8, .devices = { { "DiBcom STK7700P reference design", - { &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] }, + { &dib0700_usb_id_table[DIBCOM_STK7700P], &dib0700_usb_id_table[DIBCOM_STK7700P_PC] }, { NULL }, }, { "Hauppauge Nova-T Stick", - { &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL }, + { &dib0700_usb_id_table[HAUPPAUGE_NOVA_T_STICK], &dib0700_usb_id_table[HAUPPAUGE_NOVA_T_STICK_2], NULL }, { NULL }, }, { "AVerMedia AVerTV DVB-T Volar", - { &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] }, + { &dib0700_usb_id_table[AVERMEDIA_VOLAR], &dib0700_usb_id_table[AVERMEDIA_VOLAR_2] }, { NULL }, }, { "Compro Videomate U500", - { &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] }, + { &dib0700_usb_id_table[COMPRO_VIDEOMATE_U500], &dib0700_usb_id_table[COMPRO_VIDEOMATE_U500_PC] }, { NULL }, }, { "Uniwill STK7700P based (Hama and others)", - { &dib0700_usb_id_table[7], NULL }, + { &dib0700_usb_id_table[UNIWILL_STK7700P], NULL }, { NULL }, }, { "Leadtek Winfast DTV Dongle (STK7700P based)", - { &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] }, + { &dib0700_usb_id_table[LEADTEK_WINFAST_DTV_DONGLE_STK7700P], &dib0700_usb_id_table[LEADTEK_WINFAST_DTV_DONGLE_STK7700P_2] }, { NULL }, }, { "AVerMedia AVerTV DVB-T Express", - { &dib0700_usb_id_table[20] }, + { &dib0700_usb_id_table[AVERMEDIA_EXPRESS] }, { NULL }, }, { "Gigabyte U7000", - { &dib0700_usb_id_table[21], NULL }, + { &dib0700_usb_id_table[GIGABYTE_U7000], NULL }, { NULL }, } }, @@ -4030,7 +4118,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "Hauppauge Nova-T 500 Dual DVB-T", - { &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL }, + { &dib0700_usb_id_table[HAUPPAUGE_NOVA_T_500], &dib0700_usb_id_table[HAUPPAUGE_NOVA_T_500_2], NULL }, { NULL }, }, }, @@ -4078,23 +4166,23 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 5, .devices = { { "Pinnacle PCTV 2000e", - { &dib0700_usb_id_table[11], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV2000E], NULL }, { NULL }, }, { "Terratec Cinergy DT XS Diversity", - { &dib0700_usb_id_table[12], NULL }, + { &dib0700_usb_id_table[TERRATEC_CINERGY_DT_XS_DIVERSITY], NULL }, { NULL }, }, { "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity", - { &dib0700_usb_id_table[13], NULL }, + { &dib0700_usb_id_table[HAUPPAUGE_NOVA_TD_STICK], NULL }, { NULL }, }, { "DiBcom STK7700D reference design", - { &dib0700_usb_id_table[14], NULL }, + { &dib0700_usb_id_table[DIBCOM_STK7700D], NULL }, { NULL }, }, { "YUAN High-Tech DiBcom STK7700D", - { &dib0700_usb_id_table[55], NULL }, + { &dib0700_usb_id_table[YUAN_STK7700D_2], NULL }, { NULL }, }, @@ -4131,15 +4219,15 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 3, .devices = { { "ASUS My Cinema U3000 Mini DVBT Tuner", - { &dib0700_usb_id_table[23], NULL }, + { &dib0700_usb_id_table[ASUS_U3000], NULL }, { NULL }, }, { "Yuan EC372S", - { &dib0700_usb_id_table[31], NULL }, + { &dib0700_usb_id_table[YUAN_EC372S], NULL }, { NULL }, }, { "Terratec Cinergy T Express", - { &dib0700_usb_id_table[42], NULL }, + { &dib0700_usb_id_table[TERRATEC_CINERGY_T_EXPRESS], NULL }, { NULL }, } }, @@ -4176,51 +4264,51 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 12, .devices = { { "DiBcom STK7070P reference design", - { &dib0700_usb_id_table[15], NULL }, + { &dib0700_usb_id_table[DIBCOM_STK7070P], NULL }, { NULL }, }, { "Pinnacle PCTV DVB-T Flash Stick", - { &dib0700_usb_id_table[16], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV_DVB_T_FLASH], NULL }, { NULL }, }, { "Artec T14BR DVB-T", - { &dib0700_usb_id_table[22], NULL }, + { &dib0700_usb_id_table[ULTIMA_ARTEC_T14BR], NULL }, { NULL }, }, { "ASUS My Cinema U3100 Mini DVBT Tuner", - { &dib0700_usb_id_table[24], NULL }, + { &dib0700_usb_id_table[ASUS_U3100], NULL }, { NULL }, }, { "Hauppauge Nova-T Stick", - { &dib0700_usb_id_table[25], NULL }, + { &dib0700_usb_id_table[HAUPPAUGE_NOVA_T_STICK_3], NULL }, { NULL }, }, { "Hauppauge Nova-T MyTV.t", - { &dib0700_usb_id_table[26], NULL }, + { &dib0700_usb_id_table[HAUPPAUGE_MYTV_T], NULL }, { NULL }, }, { "Pinnacle PCTV 72e", - { &dib0700_usb_id_table[29], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV72E], NULL }, { NULL }, }, { "Pinnacle PCTV 73e", - { &dib0700_usb_id_table[30], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV73E], NULL }, { NULL }, }, { "Elgato EyeTV DTT", - { &dib0700_usb_id_table[49], NULL }, + { &dib0700_usb_id_table[ELGATO_EYETV_DTT], NULL }, { NULL }, }, { "Yuan PD378S", - { &dib0700_usb_id_table[45], NULL }, + { &dib0700_usb_id_table[YUAN_PD378S], NULL }, { NULL }, }, { "Elgato EyeTV Dtt Dlx PD378S", - { &dib0700_usb_id_table[50], NULL }, + { &dib0700_usb_id_table[ELGATO_EYETV_DTT_Dlx], NULL }, { NULL }, }, { "Elgato EyeTV DTT rev. 2", - { &dib0700_usb_id_table[80], NULL }, + { &dib0700_usb_id_table[ELGATO_EYETV_DTT_2], NULL }, { NULL }, }, }, @@ -4257,15 +4345,15 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 3, .devices = { { "Pinnacle PCTV 73A", - { &dib0700_usb_id_table[56], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV73A], NULL }, { NULL }, }, { "Pinnacle PCTV 73e SE", - { &dib0700_usb_id_table[57], &dib0700_usb_id_table[65], NULL }, + { &dib0700_usb_id_table[PCTV_PINNACLE_PCTV73ESE], &dib0700_usb_id_table[PINNACLE_PCTV73ESE], NULL }, { NULL }, }, { "Pinnacle PCTV 282e", - { &dib0700_usb_id_table[58], &dib0700_usb_id_table[66], NULL }, + { &dib0700_usb_id_table[PCTV_PINNACLE_PCTV282E], &dib0700_usb_id_table[PINNACLE_PCTV282E], NULL }, { NULL }, }, }, @@ -4314,15 +4402,15 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 3, .devices = { { "Hauppauge Nova-TD Stick (52009)", - { &dib0700_usb_id_table[35], NULL }, + { &dib0700_usb_id_table[HAUPPAUGE_NOVA_TD_STICK_52009], NULL }, { NULL }, }, { "PCTV 2002e", - { &dib0700_usb_id_table[81], NULL }, + { &dib0700_usb_id_table[PCTV_2002E], NULL }, { NULL }, }, { "PCTV 2002e SE", - { &dib0700_usb_id_table[82], NULL }, + { &dib0700_usb_id_table[PCTV_2002E_SE], NULL }, { NULL }, }, }, @@ -4371,24 +4459,24 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 5, .devices = { { "DiBcom STK7070PD reference design", - { &dib0700_usb_id_table[17], NULL }, + { &dib0700_usb_id_table[DIBCOM_STK7070PD], NULL }, { NULL }, }, { "Pinnacle PCTV Dual DVB-T Diversity Stick", - { &dib0700_usb_id_table[18], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T], NULL }, { NULL }, }, { "Hauppauge Nova-TD-500 (84xxx)", - { &dib0700_usb_id_table[36], NULL }, + { &dib0700_usb_id_table[HAUPPAUGE_NOVA_T_500_3], NULL }, { NULL }, }, { "Terratec Cinergy DT USB XS Diversity/ T5", - { &dib0700_usb_id_table[43], - &dib0700_usb_id_table[53], NULL}, + { &dib0700_usb_id_table[TERRATEC_CINERGY_DT_XS_DIVERSITY_2], + &dib0700_usb_id_table[TERRATEC_T5], NULL}, { NULL }, }, { "Sony PlayTV", - { &dib0700_usb_id_table[44], NULL }, + { &dib0700_usb_id_table[SONY_PLAYTV], NULL }, { NULL }, }, }, @@ -4437,7 +4525,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "Elgato EyeTV Diversity", - { &dib0700_usb_id_table[68], NULL }, + { &dib0700_usb_id_table[ELGATO_EYETV_DIVERSITY], NULL }, { NULL }, }, }, @@ -4474,43 +4562,43 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 10, .devices = { { "Terratec Cinergy HT USB XE", - { &dib0700_usb_id_table[27], NULL }, + { &dib0700_usb_id_table[TERRATEC_CINERGY_HT_USB_XE], NULL }, { NULL }, }, { "Pinnacle Expresscard 320cx", - { &dib0700_usb_id_table[28], NULL }, + { &dib0700_usb_id_table[PINNACLE_EXPRESSCARD_320CX], NULL }, { NULL }, }, { "Terratec Cinergy HT Express", - { &dib0700_usb_id_table[32], NULL }, + { &dib0700_usb_id_table[TERRATEC_CINERGY_HT_EXPRESS], NULL }, { NULL }, }, { "Gigabyte U8000-RH", - { &dib0700_usb_id_table[37], NULL }, + { &dib0700_usb_id_table[GIGABYTE_U8000], NULL }, { NULL }, }, { "YUAN High-Tech STK7700PH", - { &dib0700_usb_id_table[38], NULL }, + { &dib0700_usb_id_table[YUAN_STK7700PH], NULL }, { NULL }, }, { "Asus My Cinema-U3000Hybrid", - { &dib0700_usb_id_table[39], NULL }, + { &dib0700_usb_id_table[ASUS_U3000H], NULL }, { NULL }, }, { "YUAN High-Tech MC770", - { &dib0700_usb_id_table[48], NULL }, + { &dib0700_usb_id_table[YUAN_MC770], NULL }, { NULL }, }, { "Leadtek WinFast DTV Dongle H", - { &dib0700_usb_id_table[51], NULL }, + { &dib0700_usb_id_table[LEADTEK_WINFAST_DTV_DONGLE_H], NULL }, { NULL }, }, { "YUAN High-Tech STK7700D", - { &dib0700_usb_id_table[54], NULL }, + { &dib0700_usb_id_table[YUAN_STK7700D], NULL }, { NULL }, }, { "Hama DVB=T Hybrid USB Stick", - { &dib0700_usb_id_table[85], NULL }, + { &dib0700_usb_id_table[HAMA_DVBT_HYBRID], NULL }, { NULL }, }, }, @@ -4542,11 +4630,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 2, .devices = { { "Pinnacle PCTV HD Pro USB Stick", - { &dib0700_usb_id_table[40], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV801E], NULL }, { NULL }, }, { "Pinnacle PCTV HD USB Stick", - { &dib0700_usb_id_table[41], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV801E_SE], NULL }, { NULL }, }, }, @@ -4578,11 +4666,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 2, .devices = { { "Hauppauge ATSC MiniCard (B200)", - { &dib0700_usb_id_table[46], NULL }, + { &dib0700_usb_id_table[HAUPPAUGE_TIGER_ATSC], NULL }, { NULL }, }, { "Hauppauge ATSC MiniCard (B210)", - { &dib0700_usb_id_table[47], NULL }, + { &dib0700_usb_id_table[HAUPPAUGE_TIGER_ATSC_B210], NULL }, { NULL }, }, }, @@ -4608,21 +4696,21 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 4, .devices = { { "DiBcom STK7770P reference design", - { &dib0700_usb_id_table[59], NULL }, + { &dib0700_usb_id_table[DIBCOM_STK7770P], NULL }, { NULL }, }, { "Terratec Cinergy T USB XXS (HD)/ T3", - { &dib0700_usb_id_table[33], - &dib0700_usb_id_table[52], - &dib0700_usb_id_table[60], NULL}, + { &dib0700_usb_id_table[TERRATEC_CINERGY_T_XXS], + &dib0700_usb_id_table[TERRATEC_T3], + &dib0700_usb_id_table[TERRATEC_CINERGY_T_XXS_2], NULL}, { NULL }, }, { "TechniSat AirStar TeleStick 2", - { &dib0700_usb_id_table[74], NULL }, + { &dib0700_usb_id_table[TECHNISAT_AIRSTAR_TELESTICK_2], NULL }, { NULL }, }, { "Medion CTX1921 DVB-T USB", - { &dib0700_usb_id_table[75], NULL }, + { &dib0700_usb_id_table[MEDION_CREATIX_CTX1921], NULL }, { NULL }, }, }, @@ -4658,15 +4746,15 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 3, .devices = { { "DiBcom STK807xP reference design", - { &dib0700_usb_id_table[62], NULL }, + { &dib0700_usb_id_table[DIBCOM_STK807XP], NULL }, { NULL }, }, { "Prolink Pixelview SBTVD", - { &dib0700_usb_id_table[63], NULL }, + { &dib0700_usb_id_table[PIXELVIEW_SBTVD], NULL }, { NULL }, }, { "EvolutePC TVWay+", - { &dib0700_usb_id_table[64], NULL }, + { &dib0700_usb_id_table[EVOLUTEPC_TVWAY_PLUS], NULL }, { NULL }, }, }, @@ -4715,7 +4803,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom STK807xPVR reference design", - { &dib0700_usb_id_table[61], NULL }, + { &dib0700_usb_id_table[DIBCOM_STK807XPVR], NULL }, { NULL }, }, }, @@ -4752,7 +4840,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom STK8096GP reference design", - { &dib0700_usb_id_table[67], NULL }, + { &dib0700_usb_id_table[DIBCOM_STK8096GP], NULL }, { NULL }, }, }, @@ -4789,7 +4877,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom STK9090M reference design", - { &dib0700_usb_id_table[69], NULL }, + { &dib0700_usb_id_table[DIBCOM_NIM9090M], NULL }, { NULL }, }, }, @@ -4826,7 +4914,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom NIM8096MD reference design", - { &dib0700_usb_id_table[70], NULL }, + { &dib0700_usb_id_table[DIBCOM_NIM8096MD], NULL }, { NULL }, }, }, @@ -4863,7 +4951,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom NIM9090MD reference design", - { &dib0700_usb_id_table[71], NULL }, + { &dib0700_usb_id_table[DIBCOM_NIM9090MD], NULL }, { NULL }, }, }, @@ -4900,7 +4988,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom NIM7090 reference design", - { &dib0700_usb_id_table[72], NULL }, + { &dib0700_usb_id_table[DIBCOM_NIM7090], NULL }, { NULL }, }, }, @@ -4951,7 +5039,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom TFE7090PVR reference design", - { &dib0700_usb_id_table[73], NULL }, + { &dib0700_usb_id_table[DIBCOM_TFE7090PVR], NULL }, { NULL }, }, }, @@ -4983,11 +5071,11 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 2, .devices = { { "Pinnacle PCTV 340e HD Pro USB Stick", - { &dib0700_usb_id_table[76], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV340E], NULL }, { NULL }, }, { "Pinnacle PCTV Hybrid Stick Solo", - { &dib0700_usb_id_table[77], NULL }, + { &dib0700_usb_id_table[PINNACLE_PCTV340E_SE], NULL }, { NULL }, }, }, @@ -5023,7 +5111,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom TFE7790P reference design", - { &dib0700_usb_id_table[78], NULL }, + { &dib0700_usb_id_table[DIBCOM_TFE7790P], NULL }, { NULL }, }, }, @@ -5061,7 +5149,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom TFE8096P reference design", - { &dib0700_usb_id_table[79], NULL }, + { &dib0700_usb_id_table[DIBCOM_TFE8096P], NULL }, { NULL }, }, }, @@ -5114,8 +5202,8 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "DiBcom STK8096-PVR reference design", - { &dib0700_usb_id_table[83], - &dib0700_usb_id_table[84], NULL}, + { &dib0700_usb_id_table[PCTV_DIBCOM_STK8096PVR], + &dib0700_usb_id_table[DIBCOM_STK8096PVR], NULL}, { NULL }, }, }, @@ -5145,7 +5233,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { .num_device_descs = 1, .devices = { { "Microsoft Xbox One Digital TV Tuner", - { &dib0700_usb_id_table[86], NULL }, + { &dib0700_usb_id_table[MICROSOFT_XBOX_ONE_TUNER], NULL }, { NULL }, }, }, diff --git a/drivers/media/usb/dvb-usb/dibusb-mb.c b/drivers/media/usb/dvb-usb/dibusb-mb.c index e9dc27f73970..2cd88cab4c98 100644 --- a/drivers/media/usb/dvb-usb/dibusb-mb.c +++ b/drivers/media/usb/dvb-usb/dibusb-mb.c @@ -121,56 +121,77 @@ static int dibusb_probe(struct usb_interface *intf, } /* do not change the order of the ID table */ -static struct usb_device_id dibusb_dib3000mb_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM) }, -/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) }, -/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) }, -/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) }, -/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) }, -/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) }, -/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) }, -/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) }, -/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) }, -/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) }, -/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) }, -/* 12 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) }, -/* 13 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) }, -/* 14 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) }, -/* 15 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_COLD) }, -/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) }, -/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) }, -/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) }, -/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) }, -/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) }, -/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) }, -/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) }, -/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) }, - -/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */ -/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) }, -/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) }, -/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) }, - -/* 27 */ { USB_DEVICE(USB_VID_KWORLD, USB_PID_KWORLD_VSTREAM_COLD) }, - -/* 28 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, -/* 29 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, - -/* - * XXX: As Artec just 'forgot' to program the EEPROM on some Artec T1 devices - * we don't catch these faulty IDs (namely 'Cypress FX1 USB controller') that - * have been left on the device. If you don't have such a device but an Artec - * device that's supposed to work with this driver but is not detected by it, - * free to enable CONFIG_DVB_USB_DIBUSB_MB_FAULTY via your kernel config. - */ +enum { + WIDEVIEW_DVBT_USB_COLD, + WIDEVIEW_DVBT_USB_WARM, + COMPRO_DVBU2000_COLD, + COMPRO_DVBU2000_WARM, + COMPRO_DVBU2000_UNK_COLD, + DIBCOM_MOD3000_COLD, + DIBCOM_MOD3000_WARM, + EMPIA_VSTREAM_COLD, + EMPIA_VSTREAM_WARM, + GRANDTEC_DVBT_USB_COLD, + GRANDTEC_DVBT_USB_WARM, + GRANDTEC_MOD3000_COLD, + GRANDTEC_MOD3000_WARM, + UNK_HYPER_PALTEK_COLD, + UNK_HYPER_PALTEK_WARM, + VISIONPLUS_VP7041_COLD, + VISIONPLUS_VP7041_WARM, + TWINHAN_VP7041_COLD, + TWINHAN_VP7041_WARM, + ULTIMA_TVBOX_COLD, + ULTIMA_TVBOX_WARM, + ULTIMA_TVBOX_AN2235_COLD, + ULTIMA_TVBOX_AN2235_WARM, + ADSTECH_USB2_COLD, + ADSTECH_USB2_WARM, + KYE_DVB_T_COLD, + KYE_DVB_T_WARM, + KWORLD_VSTREAM_COLD, + ULTIMA_TVBOX_USB2_COLD, + ULTIMA_TVBOX_USB2_WARM, + ULTIMA_TVBOX_ANCHOR_COLD, +}; +static struct usb_device_id dibusb_dib3000mb_table[] = { + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_DVBT_USB_COLD), + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_DVBT_USB_WARM), + DVB_USB_DEV(COMPRO, COMPRO_DVBU2000_COLD), + DVB_USB_DEV(COMPRO, COMPRO_DVBU2000_WARM), + DVB_USB_DEV(COMPRO_UNK, COMPRO_DVBU2000_UNK_COLD), + DVB_USB_DEV(DIBCOM, DIBCOM_MOD3000_COLD), + DVB_USB_DEV(DIBCOM, DIBCOM_MOD3000_WARM), + DVB_USB_DEV(EMPIA, EMPIA_VSTREAM_COLD), + DVB_USB_DEV(EMPIA, EMPIA_VSTREAM_WARM), + DVB_USB_DEV(GRANDTEC, GRANDTEC_DVBT_USB_COLD), + DVB_USB_DEV(GRANDTEC, GRANDTEC_DVBT_USB_WARM), + DVB_USB_DEV(GRANDTEC, GRANDTEC_MOD3000_COLD), + DVB_USB_DEV(GRANDTEC, GRANDTEC_MOD3000_WARM), + DVB_USB_DEV(HYPER_PALTEK, UNK_HYPER_PALTEK_COLD), + DVB_USB_DEV(HYPER_PALTEK, UNK_HYPER_PALTEK_WARM), + DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7041_COLD), + DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7041_WARM), + DVB_USB_DEV(TWINHAN, TWINHAN_VP7041_COLD), + DVB_USB_DEV(TWINHAN, TWINHAN_VP7041_WARM), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_TVBOX_COLD), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_TVBOX_WARM), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_TVBOX_AN2235_COLD), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_TVBOX_AN2235_WARM), + DVB_USB_DEV(ADSTECH, ADSTECH_USB2_COLD), + DVB_USB_DEV(ADSTECH, ADSTECH_USB2_WARM), + DVB_USB_DEV(KYE, KYE_DVB_T_COLD), + DVB_USB_DEV(KYE, KYE_DVB_T_WARM), + DVB_USB_DEV(KWORLD, KWORLD_VSTREAM_COLD), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_TVBOX_USB2_COLD), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_TVBOX_USB2_WARM), #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY -/* 30 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) }, + DVB_USB_DEV(ANCHOR, ULTIMA_TVBOX_ANCHOR_COLD), #endif - - { } /* Terminating entry */ + { } }; + MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table); static struct dvb_usb_device_properties dibusb1_1_properties = { @@ -226,40 +247,40 @@ static struct dvb_usb_device_properties dibusb1_1_properties = { .num_device_descs = 9, .devices = { { "AVerMedia AverTV DVBT USB1.1", - { &dibusb_dib3000mb_table[0], NULL }, - { &dibusb_dib3000mb_table[1], NULL }, + { &dibusb_dib3000mb_table[WIDEVIEW_DVBT_USB_COLD], NULL }, + { &dibusb_dib3000mb_table[WIDEVIEW_DVBT_USB_WARM], NULL }, }, { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)", - { &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL}, - { &dibusb_dib3000mb_table[3], NULL }, + { &dibusb_dib3000mb_table[COMPRO_DVBU2000_COLD], &dibusb_dib3000mb_table[COMPRO_DVBU2000_UNK_COLD], NULL}, + { &dibusb_dib3000mb_table[COMPRO_DVBU2000_WARM], NULL }, }, { "DiBcom USB1.1 DVB-T reference design (MOD3000)", - { &dibusb_dib3000mb_table[5], NULL }, - { &dibusb_dib3000mb_table[6], NULL }, + { &dibusb_dib3000mb_table[DIBCOM_MOD3000_COLD], NULL }, + { &dibusb_dib3000mb_table[DIBCOM_MOD3000_WARM], NULL }, }, { "KWorld V-Stream XPERT DTV - DVB-T USB1.1", - { &dibusb_dib3000mb_table[7], NULL }, - { &dibusb_dib3000mb_table[8], NULL }, + { &dibusb_dib3000mb_table[EMPIA_VSTREAM_COLD], NULL }, + { &dibusb_dib3000mb_table[EMPIA_VSTREAM_WARM], NULL }, }, { "Grandtec USB1.1 DVB-T", - { &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL }, - { &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL }, + { &dibusb_dib3000mb_table[GRANDTEC_DVBT_USB_COLD], &dibusb_dib3000mb_table[GRANDTEC_MOD3000_COLD], NULL }, + { &dibusb_dib3000mb_table[GRANDTEC_DVBT_USB_WARM], &dibusb_dib3000mb_table[GRANDTEC_MOD3000_WARM], NULL }, }, { "Unknown USB1.1 DVB-T device ???? please report the name to the author", - { &dibusb_dib3000mb_table[13], NULL }, - { &dibusb_dib3000mb_table[14], NULL }, + { &dibusb_dib3000mb_table[UNK_HYPER_PALTEK_COLD], NULL }, + { &dibusb_dib3000mb_table[UNK_HYPER_PALTEK_WARM], NULL }, }, { "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device", - { &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL}, - { &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL}, + { &dibusb_dib3000mb_table[VISIONPLUS_VP7041_COLD], &dibusb_dib3000mb_table[TWINHAN_VP7041_COLD], NULL}, + { &dibusb_dib3000mb_table[VISIONPLUS_VP7041_WARM], &dibusb_dib3000mb_table[TWINHAN_VP7041_WARM], NULL}, }, { "Artec T1 USB1.1 TVBOX with AN2135", - { &dibusb_dib3000mb_table[19], NULL }, - { &dibusb_dib3000mb_table[20], NULL }, + { &dibusb_dib3000mb_table[ULTIMA_TVBOX_COLD], NULL }, + { &dibusb_dib3000mb_table[ULTIMA_TVBOX_WARM], NULL }, }, { "VideoWalker DVB-T USB", - { &dibusb_dib3000mb_table[25], NULL }, - { &dibusb_dib3000mb_table[26], NULL }, + { &dibusb_dib3000mb_table[KYE_DVB_T_COLD], NULL }, + { &dibusb_dib3000mb_table[KYE_DVB_T_WARM], NULL }, }, } }; @@ -319,12 +340,12 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = { #endif .devices = { { "Artec T1 USB1.1 TVBOX with AN2235", - { &dibusb_dib3000mb_table[21], NULL }, - { &dibusb_dib3000mb_table[22], NULL }, + { &dibusb_dib3000mb_table[ULTIMA_TVBOX_AN2235_COLD], NULL }, + { &dibusb_dib3000mb_table[ULTIMA_TVBOX_AN2235_WARM], NULL }, }, #ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)", - { &dibusb_dib3000mb_table[30], NULL }, + { &dibusb_dib3000mb_table[ULTIMA_TVBOX_ANCHOR_COLD], NULL }, { NULL }, }, { NULL }, @@ -384,11 +405,11 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = { .num_device_descs = 2, .devices = { { "KWorld/ADSTech Instant DVB-T USB2.0", - { &dibusb_dib3000mb_table[23], NULL }, - { &dibusb_dib3000mb_table[24], NULL }, + { &dibusb_dib3000mb_table[ADSTECH_USB2_COLD], NULL }, + { &dibusb_dib3000mb_table[ADSTECH_USB2_WARM], NULL }, }, { "KWorld Xpert DVB-T USB2.0", - { &dibusb_dib3000mb_table[27], NULL }, + { &dibusb_dib3000mb_table[KWORLD_VSTREAM_COLD], NULL }, { NULL } }, { NULL }, @@ -446,8 +467,8 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = { .num_device_descs = 1, .devices = { { "Artec T1 USB2.0", - { &dibusb_dib3000mb_table[28], NULL }, - { &dibusb_dib3000mb_table[29], NULL }, + { &dibusb_dib3000mb_table[ULTIMA_TVBOX_USB2_COLD], NULL }, + { &dibusb_dib3000mb_table[ULTIMA_TVBOX_USB2_WARM], NULL }, }, { NULL }, } diff --git a/drivers/media/usb/dvb-usb/dibusb-mc.c b/drivers/media/usb/dvb-usb/dibusb-mc.c index e2689977c8c8..00cb016f6266 100644 --- a/drivers/media/usb/dvb-usb/dibusb-mc.c +++ b/drivers/media/usb/dvb-usb/dibusb-mc.c @@ -24,25 +24,45 @@ static int dibusb_mc_probe(struct usb_interface *intf, } /* do not change the order of the ID table */ -static struct usb_device_id dibusb_dib3000mc_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) }, -/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) }, -/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? ) -/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) }, -/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) }, -/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) }, -/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) }, -/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) }, -/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) }, -/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) }, -/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) }, -/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) }, -/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) }, -/* 14 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD) }, -/* 15 */ { USB_DEVICE(USB_VID_HUMAX_COEX, USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM) }, - { } /* Terminating entry */ +enum { + DIBCOM_MOD3001_COLD, + DIBCOM_MOD3001_WARM, + ULTIMA_TVBOX_USB2_COLD, + ULTIMA_TVBOX_USB2_WARM, + LITEON_DVB_T_COLD, + LITEON_DVB_T_WARM, + EMPIA_DIGIVOX_MINI_SL_COLD, + EMPIA_DIGIVOX_MINI_SL_WARM, + GRANDTEC_DVBT_USB2_COLD, + GRANDTEC_DVBT_USB2_WARM, + ULTIMA_ARTEC_T14_COLD, + ULTIMA_ARTEC_T14_WARM, + LEADTEK_WINFAST_DTV_DONGLE_COLD, + LEADTEK_WINFAST_DTV_DONGLE_WARM, + HUMAX_DVB_T_STICK_HIGH_SPEED_COLD, + HUMAX_DVB_T_STICK_HIGH_SPEED_WARM, }; + +static struct usb_device_id dibusb_dib3000mc_table[] = { + DVB_USB_DEV(DIBCOM, DIBCOM_MOD3001_COLD), + DVB_USB_DEV(DIBCOM, DIBCOM_MOD3001_WARM), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_TVBOX_USB2_COLD), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_TVBOX_USB2_WARM), + DVB_USB_DEV(LITEON, LITEON_DVB_T_COLD), + DVB_USB_DEV(LITEON, LITEON_DVB_T_WARM), + DVB_USB_DEV(EMPIA, EMPIA_DIGIVOX_MINI_SL_COLD), + DVB_USB_DEV(EMPIA, EMPIA_DIGIVOX_MINI_SL_WARM), + DVB_USB_DEV(GRANDTEC, GRANDTEC_DVBT_USB2_COLD), + DVB_USB_DEV(GRANDTEC, GRANDTEC_DVBT_USB2_WARM), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_ARTEC_T14_COLD), + DVB_USB_DEV(ULTIMA_ELECTRONIC, ULTIMA_ARTEC_T14_WARM), + DVB_USB_DEV(LEADTEK, LEADTEK_WINFAST_DTV_DONGLE_COLD), + DVB_USB_DEV(LEADTEK, LEADTEK_WINFAST_DTV_DONGLE_WARM), + DVB_USB_DEV(HUMAX_COEX, HUMAX_DVB_T_STICK_HIGH_SPEED_COLD), + DVB_USB_DEV(HUMAX_COEX, HUMAX_DVB_T_STICK_HIGH_SPEED_WARM), + { } +}; + MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table); static struct dvb_usb_device_properties dibusb_mc_properties = { @@ -95,37 +115,37 @@ static struct dvb_usb_device_properties dibusb_mc_properties = { .num_device_descs = 8, .devices = { { "DiBcom USB2.0 DVB-T reference design (MOD3000P)", - { &dibusb_dib3000mc_table[0], NULL }, - { &dibusb_dib3000mc_table[1], NULL }, + { &dibusb_dib3000mc_table[DIBCOM_MOD3001_COLD], NULL }, + { &dibusb_dib3000mc_table[DIBCOM_MOD3001_WARM], NULL }, }, { "Artec T1 USB2.0 TVBOX (please check the warm ID)", - { &dibusb_dib3000mc_table[2], NULL }, - { &dibusb_dib3000mc_table[3], NULL }, + { &dibusb_dib3000mc_table[ULTIMA_TVBOX_USB2_COLD], NULL }, + { &dibusb_dib3000mc_table[ULTIMA_TVBOX_USB2_WARM], NULL }, }, { "LITE-ON USB2.0 DVB-T Tuner", /* Also rebranded as Intuix S800, Toshiba */ - { &dibusb_dib3000mc_table[4], NULL }, - { &dibusb_dib3000mc_table[5], NULL }, + { &dibusb_dib3000mc_table[LITEON_DVB_T_COLD], NULL }, + { &dibusb_dib3000mc_table[LITEON_DVB_T_WARM], NULL }, }, { "MSI Digivox Mini SL", - { &dibusb_dib3000mc_table[6], NULL }, - { &dibusb_dib3000mc_table[7], NULL }, + { &dibusb_dib3000mc_table[EMPIA_DIGIVOX_MINI_SL_COLD], NULL }, + { &dibusb_dib3000mc_table[EMPIA_DIGIVOX_MINI_SL_WARM], NULL }, }, { "GRAND - USB2.0 DVB-T adapter", - { &dibusb_dib3000mc_table[8], NULL }, - { &dibusb_dib3000mc_table[9], NULL }, + { &dibusb_dib3000mc_table[GRANDTEC_DVBT_USB2_COLD], NULL }, + { &dibusb_dib3000mc_table[GRANDTEC_DVBT_USB2_WARM], NULL }, }, { "Artec T14 - USB2.0 DVB-T", - { &dibusb_dib3000mc_table[10], NULL }, - { &dibusb_dib3000mc_table[11], NULL }, + { &dibusb_dib3000mc_table[ULTIMA_ARTEC_T14_COLD], NULL }, + { &dibusb_dib3000mc_table[ULTIMA_ARTEC_T14_WARM], NULL }, }, { "Leadtek - USB2.0 Winfast DTV dongle", - { &dibusb_dib3000mc_table[12], NULL }, - { &dibusb_dib3000mc_table[13], NULL }, + { &dibusb_dib3000mc_table[LEADTEK_WINFAST_DTV_DONGLE_COLD], NULL }, + { &dibusb_dib3000mc_table[LEADTEK_WINFAST_DTV_DONGLE_WARM], NULL }, }, { "Humax/Coex DVB-T USB Stick 2.0 High Speed", - { &dibusb_dib3000mc_table[14], NULL }, - { &dibusb_dib3000mc_table[15], NULL }, + { &dibusb_dib3000mc_table[HUMAX_DVB_T_STICK_HIGH_SPEED_COLD], NULL }, + { &dibusb_dib3000mc_table[HUMAX_DVB_T_STICK_HIGH_SPEED_WARM], NULL }, }, { NULL }, } diff --git a/drivers/media/usb/dvb-usb/digitv.c b/drivers/media/usb/dvb-usb/digitv.c index 4e3b3c064bcf..2756815a780b 100644 --- a/drivers/media/usb/dvb-usb/digitv.c +++ b/drivers/media/usb/dvb-usb/digitv.c @@ -291,10 +291,15 @@ static int digitv_probe(struct usb_interface *intf, return ret; } -static struct usb_device_id digitv_table [] = { - { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) }, - { } /* Terminating entry */ +enum { + ANCHOR_NEBULA_DIGITV, }; + +static struct usb_device_id digitv_table[] = { + DVB_USB_DEV(ANCHOR, ANCHOR_NEBULA_DIGITV), + { } +}; + MODULE_DEVICE_TABLE (usb, digitv_table); static struct dvb_usb_device_properties digitv_properties = { @@ -343,7 +348,7 @@ static struct dvb_usb_device_properties digitv_properties = { .num_device_descs = 1, .devices = { { "Nebula Electronics uDigiTV DVB-T USB2.0)", - { &digitv_table[0], NULL }, + { &digitv_table[ANCHOR_NEBULA_DIGITV], NULL }, { NULL }, }, { NULL }, diff --git a/drivers/media/usb/dvb-usb/dtt200u.c b/drivers/media/usb/dvb-usb/dtt200u.c index 24efa023d827..e6ee56b3a9dd 100644 --- a/drivers/media/usb/dvb-usb/dtt200u.c +++ b/drivers/media/usb/dvb-usb/dtt200u.c @@ -158,19 +158,33 @@ static int dtt200u_usb_probe(struct usb_interface *intf, return -ENODEV; } -static struct usb_device_id dtt200u_usb_table [] = { - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) }, - { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) }, - { USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD) }, - { 0 }, +enum { + WIDEVIEW_DTT200U_COLD, + WIDEVIEW_DTT200U_WARM, + WIDEVIEW_WT220U_COLD, + WIDEVIEW_WT220U_WARM, + WIDEVIEW_WT220U_ZL0353_COLD, + WIDEVIEW_WT220U_ZL0353_WARM, + WIDEVIEW_WT220U_FC_COLD, + WIDEVIEW_WT220U_FC_WARM, + WIDEVIEW_WT220U_ZAP250_COLD, + MIGLIA_WT220U_ZAP250_COLD, }; + +static struct usb_device_id dtt200u_usb_table[] = { + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_DTT200U_COLD), + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_DTT200U_WARM), + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_WT220U_COLD), + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_WT220U_WARM), + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_WT220U_ZL0353_COLD), + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_WT220U_ZL0353_WARM), + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_WT220U_FC_COLD), + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_WT220U_FC_WARM), + DVB_USB_DEV(WIDEVIEW, WIDEVIEW_WT220U_ZAP250_COLD), + DVB_USB_DEV(MIGLIA, MIGLIA_WT220U_ZAP250_COLD), + { } +}; + MODULE_DEVICE_TABLE(usb, dtt200u_usb_table); static struct dvb_usb_device_properties dtt200u_properties = { @@ -218,8 +232,8 @@ static struct dvb_usb_device_properties dtt200u_properties = { .num_device_descs = 1, .devices = { { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)", - .cold_ids = { &dtt200u_usb_table[0], NULL }, - .warm_ids = { &dtt200u_usb_table[1], NULL }, + .cold_ids = { &dtt200u_usb_table[WIDEVIEW_DTT200U_COLD], NULL }, + .warm_ids = { &dtt200u_usb_table[WIDEVIEW_DTT200U_WARM], NULL }, }, { NULL }, } @@ -270,8 +284,8 @@ static struct dvb_usb_device_properties wt220u_properties = { .num_device_descs = 1, .devices = { { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", - .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL }, - .warm_ids = { &dtt200u_usb_table[3], NULL }, + .cold_ids = { &dtt200u_usb_table[WIDEVIEW_WT220U_COLD], &dtt200u_usb_table[WIDEVIEW_WT220U_ZAP250_COLD], NULL }, + .warm_ids = { &dtt200u_usb_table[WIDEVIEW_WT220U_WARM], NULL }, }, { NULL }, } @@ -322,8 +336,8 @@ static struct dvb_usb_device_properties wt220u_fc_properties = { .num_device_descs = 1, .devices = { { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)", - .cold_ids = { &dtt200u_usb_table[6], NULL }, - .warm_ids = { &dtt200u_usb_table[7], NULL }, + .cold_ids = { &dtt200u_usb_table[WIDEVIEW_WT220U_FC_COLD], NULL }, + .warm_ids = { &dtt200u_usb_table[WIDEVIEW_WT220U_FC_WARM], NULL }, }, { NULL }, } @@ -374,8 +388,8 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = { .num_device_descs = 1, .devices = { { .name = "WideView WT-220U PenType Receiver (based on ZL353)", - .cold_ids = { &dtt200u_usb_table[4], NULL }, - .warm_ids = { &dtt200u_usb_table[5], NULL }, + .cold_ids = { &dtt200u_usb_table[WIDEVIEW_WT220U_ZL0353_COLD], NULL }, + .warm_ids = { &dtt200u_usb_table[WIDEVIEW_WT220U_ZL0353_WARM], NULL }, }, { NULL }, } @@ -393,7 +407,7 @@ static struct dvb_usb_device_properties wt220u_miglia_properties = { .num_device_descs = 1, .devices = { { .name = "WideView WT-220U PenType Receiver (Miglia)", - .cold_ids = { &dtt200u_usb_table[9], NULL }, + .cold_ids = { &dtt200u_usb_table[MIGLIA_WT220U_ZAP250_COLD], NULL }, /* This device turns into WT220U_ZL0353_WARM when fw has been uploaded */ .warm_ids = { NULL }, diff --git a/drivers/media/usb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c index 1c13e493322c..56c9d521a34a 100644 --- a/drivers/media/usb/dvb-usb/dtv5100.c +++ b/drivers/media/usb/dvb-usb/dtv5100.c @@ -162,10 +162,15 @@ static int dtv5100_probe(struct usb_interface *intf, return 0; } +enum { + AME_DTV5100, +}; + static struct usb_device_id dtv5100_table[] = { - { USB_DEVICE(0x06be, 0xa232) }, - { } /* Terminating entry */ + DVB_USB_DEV(AME, AME_DTV5100), + { } }; + MODULE_DEVICE_TABLE(usb, dtv5100_table); static struct dvb_usb_device_properties dtv5100_properties = { @@ -201,7 +206,7 @@ static struct dvb_usb_device_properties dtv5100_properties = { { .name = "AME DTV-5100 USB2.0 DVB-T", .cold_ids = { NULL }, - .warm_ids = { &dtv5100_table[0], NULL }, + .warm_ids = { &dtv5100_table[AME_DTV5100], NULL }, }, } }; diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index ca75ebdc10b3..0ca764282c76 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -1771,10 +1771,10 @@ enum dw2102_table_entry { PROF_7500, GENIATECH_SU3000, HAUPPAUGE_MAX_S2, - TERRATEC_CINERGY_S2, + TERRATEC_CINERGY_S2_R1, TEVII_S480_1, TEVII_S480_2, - X3M_SPC1400HD, + GENIATECH_X3M_SPC1400HD, TEVII_S421, TEVII_S632, TERRATEC_CINERGY_S2_R2, @@ -1784,7 +1784,7 @@ enum dw2102_table_entry { TERRATEC_CINERGY_S2_2, GOTVIEW_SAT_HD, GENIATECH_T220, - TECHNOTREND_S2_4600, + TECHNOTREND_CONNECT_S2_4600, TEVII_S482_1, TEVII_S482_2, TERRATEC_CINERGY_S2_BOX, @@ -1792,42 +1792,36 @@ enum dw2102_table_entry { }; static struct usb_device_id dw2102_table[] = { - [CYPRESS_DW2102] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2102)}, - [CYPRESS_DW2101] = {USB_DEVICE(USB_VID_CYPRESS, 0x2101)}, - [CYPRESS_DW2104] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW2104)}, - [TEVII_S650] = {USB_DEVICE(0x9022, USB_PID_TEVII_S650)}, - [TERRATEC_CINERGY_S] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S)}, - [CYPRESS_DW3101] = {USB_DEVICE(USB_VID_CYPRESS, USB_PID_DW3101)}, - [TEVII_S630] = {USB_DEVICE(0x9022, USB_PID_TEVII_S630)}, - [PROF_1100] = {USB_DEVICE(0x3011, USB_PID_PROF_1100)}, - [TEVII_S660] = {USB_DEVICE(0x9022, USB_PID_TEVII_S660)}, - [PROF_7500] = {USB_DEVICE(0x3034, 0x7500)}, - [GENIATECH_SU3000] = {USB_DEVICE(0x1f4d, 0x3000)}, - [HAUPPAUGE_MAX_S2] = {USB_DEVICE(0x2040, 0xd900)}, - [TERRATEC_CINERGY_S2] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R1)}, - [TEVII_S480_1] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_1)}, - [TEVII_S480_2] = {USB_DEVICE(0x9022, USB_PID_TEVII_S480_2)}, - [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)}, - [TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)}, - [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, - [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_S2_R2)}, - [TERRATEC_CINERGY_S2_R3] = {USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_S2_R3)}, - [TERRATEC_CINERGY_S2_R4] = {USB_DEVICE(USB_VID_TERRATEC, - USB_PID_TERRATEC_CINERGY_S2_R4)}, - [TERRATEC_CINERGY_S2_1] = {USB_DEVICE(USB_VID_TERRATEC_2, - USB_PID_TERRATEC_CINERGY_S2_1)}, - [TERRATEC_CINERGY_S2_2] = {USB_DEVICE(USB_VID_TERRATEC_2, - USB_PID_TERRATEC_CINERGY_S2_2)}, - [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, - [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)}, - [TECHNOTREND_S2_4600] = {USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_S2_4600)}, - [TEVII_S482_1] = {USB_DEVICE(0x9022, 0xd483)}, - [TEVII_S482_2] = {USB_DEVICE(0x9022, 0xd484)}, - [TERRATEC_CINERGY_S2_BOX] = {USB_DEVICE(USB_VID_TERRATEC, 0x0105)}, - [TEVII_S662] = {USB_DEVICE(0x9022, USB_PID_TEVII_S662)}, + DVB_USB_DEV(CYPRESS, CYPRESS_DW2102), + DVB_USB_DEV(CYPRESS, CYPRESS_DW2101), + DVB_USB_DEV(CYPRESS, CYPRESS_DW2104), + DVB_USB_DEV(TEVII, TEVII_S650), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S), + DVB_USB_DEV(CYPRESS, CYPRESS_DW3101), + DVB_USB_DEV(TEVII, TEVII_S630), + DVB_USB_DEV(PROF_1, PROF_1100), + DVB_USB_DEV(TEVII, TEVII_S660), + DVB_USB_DEV(PROF_2, PROF_7500), + DVB_USB_DEV(GTEK, GENIATECH_SU3000), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_MAX_S2), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_R1), + DVB_USB_DEV(TEVII, TEVII_S480_1), + DVB_USB_DEV(TEVII, TEVII_S480_2), + DVB_USB_DEV(GTEK, GENIATECH_X3M_SPC1400HD), + DVB_USB_DEV(TEVII, TEVII_S421), + DVB_USB_DEV(TEVII, TEVII_S632), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_R2), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_R3), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_R4), + DVB_USB_DEV(TERRATEC_2, TERRATEC_CINERGY_S2_1), + DVB_USB_DEV(TERRATEC_2, TERRATEC_CINERGY_S2_2), + DVB_USB_DEV(GOTVIEW, GOTVIEW_SAT_HD), + DVB_USB_DEV(GTEK, GENIATECH_T220), + DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_4600), + DVB_USB_DEV(TEVII, TEVII_S482_1), + DVB_USB_DEV(TEVII, TEVII_S482_2), + DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_BOX), + DVB_USB_DEV(TEVII, TEVII_S662), { } }; @@ -1889,18 +1883,18 @@ static int dw2102_load_firmware(struct usb_device *dev, case USB_PID_TEVII_S650: dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC; fallthrough; - case USB_PID_DW2104: + case USB_PID_CYPRESS_DW2104: reset = 1; dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1, DW210X_WRITE_MSG); fallthrough; - case USB_PID_DW3101: + case USB_PID_CYPRESS_DW3101: reset = 0; dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); break; case USB_PID_TERRATEC_CINERGY_S: - case USB_PID_DW2102: + case USB_PID_CYPRESS_DW2102: dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0, DW210X_WRITE_MSG); dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2, @@ -2350,11 +2344,11 @@ static struct dvb_usb_device_properties su3000_properties = { { NULL }, }, { "Terratec Cinergy S2 USB HD", - { &dw2102_table[TERRATEC_CINERGY_S2], NULL }, + { &dw2102_table[TERRATEC_CINERGY_S2_R1], NULL }, { NULL }, }, { "X3M TV SPC1400HD PCI", - { &dw2102_table[X3M_SPC1400HD], NULL }, + { &dw2102_table[GENIATECH_X3M_SPC1400HD], NULL }, { NULL }, }, { "Terratec Cinergy S2 USB HD Rev.2", @@ -2525,7 +2519,7 @@ static struct dvb_usb_device_properties tt_s2_4600_properties = { .num_device_descs = 5, .devices = { { "TechnoTrend TT-connect S2-4600", - { &dw2102_table[TECHNOTREND_S2_4600], NULL }, + { &dw2102_table[TECHNOTREND_CONNECT_S2_4600], NULL }, { NULL }, }, { "TeVii S482 (tuner 1)", diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c index b4f661bb5648..b2b27a86dfe5 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.c +++ b/drivers/media/usb/dvb-usb/gp8psk.c @@ -310,15 +310,25 @@ static int gp8psk_usb_probe(struct usb_interface *intf, return ret; } -static struct usb_device_id gp8psk_usb_table [] = { - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) }, - { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) }, -/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */ - { 0 }, +enum { + GENPIX_8PSK_REV_1_COLD, + GENPIX_8PSK_REV_1_WARM, + GENPIX_8PSK_REV_2, + GENPIX_SKYWALKER_1, + GENPIX_SKYWALKER_2, + GENPIX_SKYWALKER_CW3K, }; + +static struct usb_device_id gp8psk_usb_table[] = { + DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_1_COLD), + DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_1_WARM), + DVB_USB_DEV(GENPIX, GENPIX_8PSK_REV_2), + DVB_USB_DEV(GENPIX, GENPIX_SKYWALKER_1), + DVB_USB_DEV(GENPIX, GENPIX_SKYWALKER_2), + DVB_USB_DEV(GENPIX, GENPIX_SKYWALKER_CW3K), + { } +}; + MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); static struct dvb_usb_device_properties gp8psk_properties = { @@ -355,20 +365,20 @@ static struct dvb_usb_device_properties gp8psk_properties = { .num_device_descs = 4, .devices = { { .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver", - .cold_ids = { &gp8psk_usb_table[0], NULL }, - .warm_ids = { &gp8psk_usb_table[1], NULL }, + .cold_ids = { &gp8psk_usb_table[GENPIX_8PSK_REV_1_COLD], NULL }, + .warm_ids = { &gp8psk_usb_table[GENPIX_8PSK_REV_1_WARM], NULL }, }, { .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver", .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[2], NULL }, + .warm_ids = { &gp8psk_usb_table[GENPIX_8PSK_REV_2], NULL }, }, { .name = "Genpix SkyWalker-1 DVB-S receiver", .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[3], NULL }, + .warm_ids = { &gp8psk_usb_table[GENPIX_SKYWALKER_1], NULL }, }, { .name = "Genpix SkyWalker-2 DVB-S receiver", .cold_ids = { NULL }, - .warm_ids = { &gp8psk_usb_table[4], NULL }, + .warm_ids = { &gp8psk_usb_table[GENPIX_SKYWALKER_2], NULL }, }, { NULL }, } diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index 691e05833db1..548199cd86f6 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -897,20 +897,29 @@ static int m920x_probe(struct usb_interface *intf, return ret; } -static struct usb_device_id m920x_table [] = { - { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_MSI_DIGI_VOX_MINI_II) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD) }, - { USB_DEVICE(USB_VID_ANUBIS_ELECTRONIC, - USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM) }, - { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_COLD) }, - { USB_DEVICE(USB_VID_DPOSH, USB_PID_DPOSH_M9206_WARM) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_PINNACLE_PCTV310E) }, - { USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_TWINHAN_VP7049) }, - { } /* Terminating entry */ +enum { + MSI_MEGASKY580, + ANUBIS_MSI_DIGI_VOX_MINI_II, + ANUBIS_LIFEVIEW_TV_WALKER_TWIN_COLD, + ANUBIS_LIFEVIEW_TV_WALKER_TWIN_WARM, + DPOSH_M9206_COLD, + DPOSH_M9206_WARM, + VISIONPLUS_PINNACLE_PCTV310E, + AZUREWAVE_TWINHAN_VP7049, }; + +static struct usb_device_id m920x_table[] = { + DVB_USB_DEV(MSI, MSI_MEGASKY580), + DVB_USB_DEV(ANUBIS_ELECTRONIC, ANUBIS_MSI_DIGI_VOX_MINI_II), + DVB_USB_DEV(ANUBIS_ELECTRONIC, ANUBIS_LIFEVIEW_TV_WALKER_TWIN_COLD), + DVB_USB_DEV(ANUBIS_ELECTRONIC, ANUBIS_LIFEVIEW_TV_WALKER_TWIN_WARM), + DVB_USB_DEV(DPOSH, DPOSH_M9206_COLD), + DVB_USB_DEV(DPOSH, DPOSH_M9206_WARM), + DVB_USB_DEV(VISIONPLUS, VISIONPLUS_PINNACLE_PCTV310E), + DVB_USB_DEV(AZUREWAVE, AZUREWAVE_TWINHAN_VP7049), + { } +}; + MODULE_DEVICE_TABLE (usb, m920x_table); static struct dvb_usb_device_properties megasky_properties = { @@ -962,7 +971,7 @@ static struct dvb_usb_device_properties megasky_properties = { .num_device_descs = 1, .devices = { { "MSI Mega Sky 580 DVB-T USB2.0", - { &m920x_table[0], NULL }, + { &m920x_table[MSI_MEGASKY580], NULL }, { NULL }, } } @@ -1010,7 +1019,7 @@ static struct dvb_usb_device_properties digivox_mini_ii_properties = { .num_device_descs = 1, .devices = { { "MSI DIGI VOX mini II DVB-T USB2.0", - { &m920x_table[1], NULL }, + { &m920x_table[ANUBIS_MSI_DIGI_VOX_MINI_II], NULL }, { NULL }, }, } @@ -1097,8 +1106,8 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = { .num_device_descs = 1, .devices = { { .name = "LifeView TV Walker Twin DVB-T USB2.0", - .cold_ids = { &m920x_table[2], NULL }, - .warm_ids = { &m920x_table[3], NULL }, + .cold_ids = { &m920x_table[ANUBIS_LIFEVIEW_TV_WALKER_TWIN_COLD], NULL }, + .warm_ids = { &m920x_table[ANUBIS_LIFEVIEW_TV_WALKER_TWIN_WARM], NULL }, }, } }; @@ -1139,8 +1148,8 @@ static struct dvb_usb_device_properties dposh_properties = { .num_device_descs = 1, .devices = { { .name = "Dposh DVB-T USB2.0", - .cold_ids = { &m920x_table[4], NULL }, - .warm_ids = { &m920x_table[5], NULL }, + .cold_ids = { &m920x_table[DPOSH_M9206_COLD], NULL }, + .warm_ids = { &m920x_table[DPOSH_M9206_WARM], NULL }, }, } }; @@ -1195,7 +1204,7 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = { .num_device_descs = 1, .devices = { { "Pinnacle PCTV 310e", - { &m920x_table[6], NULL }, + { &m920x_table[VISIONPLUS_PINNACLE_PCTV310E], NULL }, { NULL }, } } @@ -1250,7 +1259,7 @@ static struct dvb_usb_device_properties vp7049_properties = { .num_device_descs = 1, .devices = { { "DTV-DVB UDTT7049", - { &m920x_table[7], NULL }, + { &m920x_table[AZUREWAVE_TWINHAN_VP7049], NULL }, { NULL }, } } diff --git a/drivers/media/usb/dvb-usb/nova-t-usb2.c b/drivers/media/usb/dvb-usb/nova-t-usb2.c index 9c0eb0d40822..4782d0780913 100644 --- a/drivers/media/usb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/usb/dvb-usb/nova-t-usb2.c @@ -160,11 +160,17 @@ static int nova_t_probe(struct usb_interface *intf, } /* do not change the order of the ID table */ -static struct usb_device_id nova_t_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) }, - { } /* Terminating entry */ +enum { + HAUPPAUGE_WINTV_NOVA_T_USB2_COLD, + HAUPPAUGE_WINTV_NOVA_T_USB2_WARM, }; + +static struct usb_device_id nova_t_table[] = { + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_WINTV_NOVA_T_USB2_COLD), + DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_WINTV_NOVA_T_USB2_WARM), + { } +}; + MODULE_DEVICE_TABLE(usb, nova_t_table); static struct dvb_usb_device_properties nova_t_properties = { @@ -221,8 +227,8 @@ static struct dvb_usb_device_properties nova_t_properties = { .num_device_descs = 1, .devices = { { "Hauppauge WinTV-NOVA-T usb2", - { &nova_t_table[0], NULL }, - { &nova_t_table[1], NULL }, + { &nova_t_table[HAUPPAUGE_WINTV_NOVA_T_USB2_COLD], NULL }, + { &nova_t_table[HAUPPAUGE_WINTV_NOVA_T_USB2_WARM], NULL }, }, { NULL }, } diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c index e8d784b9d119..0da86f58aff6 100644 --- a/drivers/media/usb/dvb-usb/opera1.c +++ b/drivers/media/usb/dvb-usb/opera1.c @@ -425,10 +425,15 @@ static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state) return 0; } +enum { + CYPRESS_OPERA1_COLD, + OPERA1_WARM, +}; + static struct usb_device_id opera1_table[] = { - {USB_DEVICE(USB_VID_CYPRESS, USB_PID_OPERA1_COLD)}, - {USB_DEVICE(USB_VID_OPERA1, USB_PID_OPERA1_WARM)}, - {} + DVB_USB_DEV(CYPRESS, CYPRESS_OPERA1_COLD), + DVB_USB_DEV(OPERA1, OPERA1_WARM), + { } }; MODULE_DEVICE_TABLE(usb, opera1_table); @@ -540,8 +545,8 @@ static struct dvb_usb_device_properties opera1_properties = { .num_device_descs = 1, .devices = { {"Opera1 DVB-S USB2.0", - {&opera1_table[0], NULL}, - {&opera1_table[1], NULL}, + {&opera1_table[CYPRESS_OPERA1_COLD], NULL}, + {&opera1_table[OPERA1_WARM], NULL}, }, } }; diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index 9b78b40abc6d..f0794c68c622 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -951,13 +951,19 @@ static int pctv452e_tuner_attach(struct dvb_usb_adapter *a) return 0; } +enum { + PINNACLE_PCTV_452E, + TECHNOTREND_CONNECT_S2_3600, + TECHNOTREND_CONNECT_S2_3650_CI, +}; + static struct usb_device_id pctv452e_usb_table[] = { - {USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_452E)}, - {USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_S2_3600)}, - {USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_S2_3650_CI)}, - {} + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_452E), + DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_3600), + DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_3650_CI), + { } }; + MODULE_DEVICE_TABLE(usb, pctv452e_usb_table); static struct dvb_usb_device_properties pctv452e_properties = { @@ -1006,7 +1012,7 @@ static struct dvb_usb_device_properties pctv452e_properties = { .devices = { { .name = "PCTV HDTV USB", .cold_ids = { NULL, NULL }, /* this is a warm only device */ - .warm_ids = { &pctv452e_usb_table[0], NULL } + .warm_ids = { &pctv452e_usb_table[PINNACLE_PCTV_452E], NULL } }, { NULL }, } @@ -1060,11 +1066,11 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = { .devices = { { .name = "Technotrend TT Connect S2-3600", .cold_ids = { NULL, NULL }, /* this is a warm only device */ - .warm_ids = { &pctv452e_usb_table[1], NULL } + .warm_ids = { &pctv452e_usb_table[TECHNOTREND_CONNECT_S2_3600], NULL } }, { .name = "Technotrend TT Connect S2-3650-CI", .cold_ids = { NULL, NULL }, - .warm_ids = { &pctv452e_usb_table[2], NULL } + .warm_ids = { &pctv452e_usb_table[TECHNOTREND_CONNECT_S2_3650_CI], NULL } }, { NULL }, } diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index a9ed26ce1be6..9c77911fcad4 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -689,10 +689,15 @@ static int technisat_usb2_rc_query(struct dvb_usb_device *d) } /* DVB-USB and USB stuff follows */ +enum { + TECHNISAT_USB2_DVB_S2, +}; + static struct usb_device_id technisat_usb2_id_table[] = { - { USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_DVB_S2) }, - { 0 } /* Terminating entry */ + DVB_USB_DEV(TECHNISAT, TECHNISAT_USB2_DVB_S2), + { } }; + MODULE_DEVICE_TABLE(usb, technisat_usb2_id_table); /* device description */ @@ -738,7 +743,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = { .num_device_descs = 1, .devices = { { "Technisat SkyStar USB HD (DVB-S/S2)", - { &technisat_usb2_id_table[0], NULL }, + { &technisat_usb2_id_table[TECHNISAT_USB2_DVB_S2], NULL }, { NULL }, }, }, diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c index 294274fd8f55..373ffa7f641e 100644 --- a/drivers/media/usb/dvb-usb/ttusb2.c +++ b/drivers/media/usb/dvb-usb/ttusb2.c @@ -630,17 +630,23 @@ static int ttusb2_probe(struct usb_interface *intf, return -ENODEV; } -static struct usb_device_id ttusb2_table [] = { - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) }, - { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) }, - { USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_S2400) }, - { USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_CT3650) }, - { USB_DEVICE(USB_VID_TECHNOTREND, - USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM) }, - {} /* Terminating entry */ +enum { + PINNACLE_PCTV_400E, + PINNACLE_PCTV_450E, + TECHNOTREND_CONNECT_S2400, + TECHNOTREND_CONNECT_CT3650, + TECHNOTREND_CONNECT_S2400_8KEEPROM, +}; + +static struct usb_device_id ttusb2_table[] = { + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_400E), + DVB_USB_DEV(PINNACLE, PINNACLE_PCTV_450E), + DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2400), + DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_CT3650), + DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2400_8KEEPROM), + { } }; + MODULE_DEVICE_TABLE (usb, ttusb2_table); static struct dvb_usb_device_properties ttusb2_properties = { @@ -688,11 +694,11 @@ static struct dvb_usb_device_properties ttusb2_properties = { .num_device_descs = 2, .devices = { { "Pinnacle 400e DVB-S USB2.0", - { &ttusb2_table[0], NULL }, + { &ttusb2_table[PINNACLE_PCTV_400E], NULL }, { NULL }, }, { "Pinnacle 450e DVB-S USB2.0", - { &ttusb2_table[1], NULL }, + { &ttusb2_table[PINNACLE_PCTV_450E], NULL }, { NULL }, }, } @@ -743,11 +749,11 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = { .num_device_descs = 2, .devices = { { "Technotrend TT-connect S-2400", - { &ttusb2_table[2], NULL }, + { &ttusb2_table[TECHNOTREND_CONNECT_S2400], NULL }, { NULL }, }, { "Technotrend TT-connect S-2400 (8kB EEPROM)", - { &ttusb2_table[4], NULL }, + { &ttusb2_table[TECHNOTREND_CONNECT_S2400_8KEEPROM], NULL }, { NULL }, }, } @@ -823,7 +829,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { .num_device_descs = 1, .devices = { { "Technotrend TT-connect CT-3650", - .warm_ids = { &ttusb2_table[3], NULL }, + .warm_ids = { &ttusb2_table[TECHNOTREND_CONNECT_CT3650], NULL }, }, } }; diff --git a/drivers/media/usb/dvb-usb/umt-010.c b/drivers/media/usb/dvb-usb/umt-010.c index 2181993771ae..464699b0b75b 100644 --- a/drivers/media/usb/dvb-usb/umt-010.c +++ b/drivers/media/usb/dvb-usb/umt-010.c @@ -81,11 +81,17 @@ static int umt_probe(struct usb_interface *intf, } /* do not change the order of the ID table */ -static struct usb_device_id umt_table [] = { -/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) }, -/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) }, - { } /* Terminating entry */ +enum { + HANFTEK_UMT_010_COLD, + HANFTEK_UMT_010_WARM, }; + +static struct usb_device_id umt_table[] = { + DVB_USB_DEV(HANFTEK, HANFTEK_UMT_010_COLD), + DVB_USB_DEV(HANFTEK, HANFTEK_UMT_010_WARM), + { } +}; + MODULE_DEVICE_TABLE (usb, umt_table); static struct dvb_usb_device_properties umt_properties = { @@ -127,8 +133,8 @@ static struct dvb_usb_device_properties umt_properties = { .num_device_descs = 1, .devices = { { "Hanftek UMT-010 DVB-T USB2.0", - { &umt_table[0], NULL }, - { &umt_table[1], NULL }, + { &umt_table[HANFTEK_UMT_010_COLD], NULL }, + { &umt_table[HANFTEK_UMT_010_WARM], NULL }, }, } }; diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c index a1d9e4801a2b..5b6740cbd1d1 100644 --- a/drivers/media/usb/dvb-usb/vp702x.c +++ b/drivers/media/usb/dvb-usb/vp702x.c @@ -369,12 +369,19 @@ static void vp702x_usb_disconnect(struct usb_interface *intf) dvb_usb_device_exit(intf); } -static struct usb_device_id vp702x_usb_table [] = { - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) }, -// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) }, -// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) }, - { 0 }, +enum { + VISIONPLUS_VP7021_COLD, + VISIONPLUS_VP7020_COLD, + VISIONPLUS_VP7020_WARM, }; + +static struct usb_device_id vp702x_usb_table[] = { + DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7021_COLD), +// DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_COLD), +// DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_WARM), + { } +}; + MODULE_DEVICE_TABLE(usb, vp702x_usb_table); static struct dvb_usb_device_properties vp702x_properties = { @@ -421,12 +428,12 @@ static struct dvb_usb_device_properties vp702x_properties = { .num_device_descs = 1, .devices = { { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)", - .cold_ids = { &vp702x_usb_table[0], NULL }, + .cold_ids = { &vp702x_usb_table[VISIONPLUS_VP7021_COLD], NULL }, .warm_ids = { NULL }, }, /* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)", - .cold_ids = { &vp702x_usb_table[2], NULL }, - .warm_ids = { &vp702x_usb_table[3], NULL }, + .cold_ids = { &vp702x_usb_table[VISIONPLUS_VP7020_COLD], NULL }, + .warm_ids = { &vp702x_usb_table[VISIONPLUS_VP7020_WARM], NULL }, }, */ { NULL }, } diff --git a/drivers/media/usb/dvb-usb/vp7045.c b/drivers/media/usb/dvb-usb/vp7045.c index 23e3a90af1f4..1dc2b18d44d8 100644 --- a/drivers/media/usb/dvb-usb/vp7045.c +++ b/drivers/media/usb/dvb-usb/vp7045.c @@ -172,13 +172,21 @@ static int vp7045_usb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr); } -static struct usb_device_id vp7045_usb_table [] = { - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) }, - { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) }, - { 0 }, +enum { + VISIONPLUS_VP7045_COLD, + VISIONPLUS_VP7045_WARM, + VISIONPLUS_TINYUSB2_COLD, + VISIONPLUS_TINYUSB2_WARM, }; + +static struct usb_device_id vp7045_usb_table[] = { + DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7045_COLD), + DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7045_WARM), + DVB_USB_DEV(VISIONPLUS, VISIONPLUS_TINYUSB2_COLD), + DVB_USB_DEV(VISIONPLUS, VISIONPLUS_TINYUSB2_WARM), + { } +}; + MODULE_DEVICE_TABLE(usb, vp7045_usb_table); static struct dvb_usb_device_properties vp7045_properties = { @@ -221,12 +229,12 @@ static struct dvb_usb_device_properties vp7045_properties = { .num_device_descs = 2, .devices = { { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)", - .cold_ids = { &vp7045_usb_table[0], NULL }, - .warm_ids = { &vp7045_usb_table[1], NULL }, + .cold_ids = { &vp7045_usb_table[VISIONPLUS_VP7045_COLD], NULL }, + .warm_ids = { &vp7045_usb_table[VISIONPLUS_VP7045_WARM], NULL }, }, { .name = "DigitalNow TinyUSB 2 DVB-t Receiver", - .cold_ids = { &vp7045_usb_table[2], NULL }, - .warm_ids = { &vp7045_usb_table[3], NULL }, + .cold_ids = { &vp7045_usb_table[VISIONPLUS_TINYUSB2_COLD], NULL }, + .warm_ids = { &vp7045_usb_table[VISIONPLUS_TINYUSB2_WARM], NULL }, }, { NULL }, } diff --git a/drivers/media/usb/gspca/spca561.c b/drivers/media/usb/gspca/spca561.c index d608a518c141..431527ed602b 100644 --- a/drivers/media/usb/gspca/spca561.c +++ b/drivers/media/usb/gspca/spca561.c @@ -510,7 +510,7 @@ static void setexposure(struct gspca_dev *gspca_dev, s32 val) /* We choose to use the high bits setting the fixed framerate divisor asap, as setting high basic exposure setting without the fixed divider in combination with high gains makes the cam stop */ - int table[] = { 0, 450, 550, 625, EXPOSURE_MAX }; + static const int table[] = { 0, 450, 550, 625, EXPOSURE_MAX }; for (i = 0; i < ARRAY_SIZE(table) - 1; i++) { if (val <= table[i + 1]) { diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index cd7b118d5929..a9666373af6b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -2569,6 +2569,11 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, } while (0); mutex_unlock(&pvr2_unit_mtx); + INIT_WORK(&hdw->workpoll, pvr2_hdw_worker_poll); + + if (hdw->unit_number == -1) + goto fail; + cnt1 = 0; cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2"); cnt1 += cnt2; @@ -2580,8 +2585,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1; hdw->name[cnt1] = 0; - INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll); - pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s", hdw->unit_number,hdw->name); diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 5b822214ccc5..787edb3d47c2 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -150,25 +150,18 @@ int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value) int stk_camera_read_reg(struct stk_camera *dev, u16 index, u8 *value) { struct usb_device *udev = dev->udev; - unsigned char *buf; int ret; - buf = kmalloc(sizeof(u8), GFP_KERNEL); - if (!buf) - return -ENOMEM; - ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x00, index, - buf, + &dev->read_reg_scratch, sizeof(u8), 500); if (ret >= 0) - *value = *buf; - - kfree(buf); + *value = dev->read_reg_scratch; if (ret < 0) return ret; diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h index 14519e5308b1..136decffe9ce 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.h +++ b/drivers/media/usb/stkwebcam/stk-webcam.h @@ -105,6 +105,8 @@ struct stk_camera { struct list_head sio_avail; struct list_head sio_full; unsigned sequence; + + u8 read_reg_scratch; }; #define vdev_to_camera(d) container_of(d, struct stk_camera, vdev) diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index b4f6edf968bc..0e78233fc8a0 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -2188,11 +2188,21 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain, if (map == NULL) return -ENOMEM; + /* For UVCIOC_CTRL_MAP custom control */ + if (mapping->name) { + map->name = kstrdup(mapping->name, GFP_KERNEL); + if (!map->name) { + kfree(map); + return -ENOMEM; + } + } + INIT_LIST_HEAD(&map->ev_subs); size = sizeof(*mapping->menu_info) * mapping->menu_count; map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL); if (map->menu_info == NULL) { + kfree(map->name); kfree(map); return -ENOMEM; } diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index dda0f0aa78b8..6c86faecbea2 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -155,6 +155,11 @@ static struct uvc_format_desc uvc_fmts[] = { .fcc = V4L2_PIX_FMT_H264, }, { + .name = "H.265", + .guid = UVC_GUID_FORMAT_H265, + .fcc = V4L2_PIX_FMT_HEVC, + }, + { .name = "Greyscale 8 L/R (Y8I)", .guid = UVC_GUID_FORMAT_Y8I, .fcc = V4L2_PIX_FMT_Y8I, @@ -1009,9 +1014,7 @@ static int uvc_parse_streaming(struct uvc_device *dev, streaming->header.bEndpointAddress); if (ep == NULL) continue; - - psize = le16_to_cpu(ep->desc.wMaxPacketSize); - psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); + psize = uvc_endpoint_max_bpi(dev->udev, ep); if (psize > streaming->maxpsize) streaming->maxpsize = psize; } @@ -2443,7 +2446,7 @@ static int uvc_probe(struct usb_interface *intf, "Forcing device quirks to 0x%x by module parameter for testing purpose.\n", dev->quirks); dev_info(&dev->udev->dev, - "Please report required quirks to the linux-uvc-devel mailing list.\n"); + "Please report required quirks to the linux-media mailing list.\n"); } if (dev->info->uvc_version) { diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 711556d13d03..648dcd579e81 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -42,12 +42,12 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, map->id = xmap->id; /* Non standard control id. */ if (v4l2_ctrl_get_name(map->id) == NULL) { - map->name = kmemdup(xmap->name, sizeof(xmap->name), - GFP_KERNEL); - if (!map->name) { - ret = -ENOMEM; + if (xmap->name[0] == '\0') { + ret = -EINVAL; goto free_map; } + xmap->name[sizeof(xmap->name) - 1] = '\0'; + map->name = xmap->name; } memcpy(map->entity, xmap->entity, sizeof(map->entity)); map->selector = xmap->selector; @@ -871,29 +871,31 @@ static int uvc_ioctl_enum_input(struct file *file, void *fh, struct uvc_video_chain *chain = handle->chain; const struct uvc_entity *selector = chain->selector; struct uvc_entity *iterm = NULL; + struct uvc_entity *it; u32 index = input->index; - int pin = 0; if (selector == NULL || (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { if (index != 0) return -EINVAL; - list_for_each_entry(iterm, &chain->entities, chain) { - if (UVC_ENTITY_IS_ITERM(iterm)) + list_for_each_entry(it, &chain->entities, chain) { + if (UVC_ENTITY_IS_ITERM(it)) { + iterm = it; break; + } } - pin = iterm->id; } else if (index < selector->bNrInPins) { - pin = selector->baSourceID[index]; - list_for_each_entry(iterm, &chain->entities, chain) { - if (!UVC_ENTITY_IS_ITERM(iterm)) + list_for_each_entry(it, &chain->entities, chain) { + if (!UVC_ENTITY_IS_ITERM(it)) continue; - if (iterm->id == pin) + if (it->id == selector->baSourceID[index]) { + iterm = it; break; + } } } - if (iterm == NULL || iterm->id != pin) + if (iterm == NULL) return -EINVAL; memset(input, 0, sizeof(*input)); diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 1b4cc934109e..6d3dfa4e0bb2 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -383,7 +383,6 @@ int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe) { struct uvc_streaming_control probe_min, probe_max; - u16 bandwidth; unsigned int i; int ret; @@ -421,8 +420,7 @@ int uvc_probe_video(struct uvc_streaming *stream, if (stream->intf->num_altsetting == 1) break; - bandwidth = probe->dwMaxPayloadTransferSize; - if (bandwidth <= stream->maxpsize) + if (probe->dwMaxPayloadTransferSize <= stream->maxpsize) break; if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) { @@ -1756,25 +1754,17 @@ static void uvc_video_stop_transfer(struct uvc_streaming *stream, /* * Compute the maximum number of bytes per interval for an endpoint. */ -static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev, - struct usb_host_endpoint *ep) +u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep) { u16 psize; - u16 mult; switch (dev->speed) { case USB_SPEED_SUPER: case USB_SPEED_SUPER_PLUS: return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); - case USB_SPEED_HIGH: - psize = usb_endpoint_maxp(&ep->desc); - mult = usb_endpoint_maxp_mult(&ep->desc); - return psize * mult; - case USB_SPEED_WIRELESS: - psize = usb_endpoint_maxp(&ep->desc); - return psize; default: psize = usb_endpoint_maxp(&ep->desc); + psize *= usb_endpoint_maxp_mult(&ep->desc); return psize; } } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 143230b3275b..c5b4febd2d94 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -139,6 +139,9 @@ #define UVC_GUID_FORMAT_H264 \ { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_H265 \ + { 'H', '2', '6', '5', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} #define UVC_GUID_FORMAT_Y8I \ { 'Y', '8', 'I', ' ', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} @@ -911,6 +914,7 @@ void uvc_simplify_fraction(u32 *numerator, u32 *denominator, u32 uvc_fraction_to_interval(u32 numerator, u32 denominator); struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, u8 epaddr); +u16 uvc_endpoint_max_bpi(struct usb_device *dev, struct usb_host_endpoint *ep); /* Quirks support */ void uvc_video_decode_isight(struct uvc_urb *uvc_urb, diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index ad9224a18853..2d47c10de062 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -1118,7 +1118,7 @@ static void tuner_status(struct dvb_frontend *fe) if (t->mode != V4L2_TUNER_RADIO) return; if (fe_tuner_ops->get_status) { - u32 tuner_status; + u32 tuner_status = 0; fe_tuner_ops->get_status(&t->fe, &tuner_status); if (tuner_status & TUNER_STATUS_LOCKED) @@ -1258,7 +1258,7 @@ static int tuner_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) if (vt->type == t->mode) { vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; if (fe_tuner_ops->get_status) { - u32 tuner_status; + u32 tuner_status = 0; fe_tuner_ops->get_status(&t->fe, &tuner_status); vt->rxsubchans = diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 0404267f1ae4..c6995718237a 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -275,6 +275,24 @@ v4l2_async_nf_try_complete(struct v4l2_async_notifier *notifier) static int v4l2_async_nf_try_all_subdevs(struct v4l2_async_notifier *notifier); +static int v4l2_async_create_ancillary_links(struct v4l2_async_notifier *n, + struct v4l2_subdev *sd) +{ + struct media_link *link = NULL; + +#if IS_ENABLED(CONFIG_MEDIA_CONTROLLER) + + if (sd->entity.function != MEDIA_ENT_F_LENS && + sd->entity.function != MEDIA_ENT_F_FLASH) + return 0; + + link = media_create_ancillary_link(&n->sd->entity, &sd->entity); + +#endif + + return IS_ERR(link) ? PTR_ERR(link) : 0; +} + static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd, @@ -293,6 +311,19 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, return ret; } + /* + * Depending of the function of the entities involved, we may want to + * create links between them (for example between a sensor and its lens + * or between a sensor's source pad and the connected device's sink + * pad). + */ + ret = v4l2_async_create_ancillary_links(notifier, sd); + if (ret) { + v4l2_async_nf_call_unbind(notifier, sd, asd); + v4l2_device_unregister_subdev(sd); + return ret; + } + /* Remove from the waiting list */ list_del(&asd->list); sd->asd = asd; @@ -662,7 +693,7 @@ __v4l2_async_nf_add_fwnode_remote(struct v4l2_async_notifier *notif, struct v4l2_async_subdev *asd; struct fwnode_handle *remote; - remote = fwnode_graph_get_remote_port_parent(endpoint); + remote = fwnode_graph_get_remote_endpoint(endpoint); if (!remote) return ERR_PTR(-ENOTCONN); diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index 8968cec8454e..949c1884d9c1 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -1140,9 +1140,8 @@ int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl, INIT_LIST_HEAD(&hdl->ctrls); INIT_LIST_HEAD(&hdl->ctrl_refs); hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8; - hdl->buckets = kvmalloc_array(hdl->nr_of_buckets, - sizeof(hdl->buckets[0]), - GFP_KERNEL | __GFP_ZERO); + hdl->buckets = kvcalloc(hdl->nr_of_buckets, sizeof(hdl->buckets[0]), + GFP_KERNEL); hdl->error = hdl->buckets ? 0 : -ENOMEM; v4l2_ctrl_handler_init_request(hdl); return hdl->error; diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index 54ca4e6b820b..16f42d2fd359 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -572,6 +572,11 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "VBV/CPB Limit", NULL, }; + static const char * const intra_refresh_period_type[] = { + "Random", + "Cyclic", + NULL, + }; switch (id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: @@ -705,6 +710,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return hevc_start_code; case V4L2_CID_CAMERA_ORIENTATION: return camera_orientation; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE: + return intra_refresh_period_type; default: return NULL; } @@ -834,6 +841,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: return "Decoder Slice Interface"; case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: return "MPEG4 Loop Filter Enable"; case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "Number of Intra Refresh MBs"; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE: return "Intra Refresh Period Type"; case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: return "Intra Refresh Period"; case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: return "Frame Level Rate Control Enable"; case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control"; @@ -1360,6 +1368,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_STATELESS_H264_DECODE_MODE: case V4L2_CID_STATELESS_H264_START_CODE: case V4L2_CID_CAMERA_ORIENTATION: + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index afceb35e500c..3d85a8600f57 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -61,6 +61,10 @@ static const struct v4l2_fwnode_bus_conv { V4L2_FWNODE_BUS_TYPE_BT656, V4L2_MBUS_BT656, "Bt.656", + }, { + V4L2_FWNODE_BUS_TYPE_DPI, + V4L2_MBUS_DPI, + "DPI", } }; diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c index 5633a242520a..72bd64f65198 100644 --- a/drivers/media/v4l2-core/v4l2-h264.c +++ b/drivers/media/v4l2-core/v4l2-h264.c @@ -12,6 +12,12 @@ #include <media/v4l2-h264.h> +/* + * Size of the tempory buffer allocated when printing reference lists. The + * output will be truncated if the size is too small. + */ +static const int tmp_str_size = 1024; + /** * v4l2_h264_init_reflist_builder() - Initialize a P/B0/B1 reference list * builder @@ -34,62 +40,96 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, cur_frame_num = dec_params->frame_num; memset(b, 0, sizeof(*b)); - if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) + if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) { b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt, dec_params->top_field_order_cnt); - else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + b->cur_pic_fields = V4L2_H264_FRAME_REF; + } else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) { b->cur_pic_order_count = dec_params->bottom_field_order_cnt; - else + b->cur_pic_fields = V4L2_H264_BOTTOM_FIELD_REF; + } else { b->cur_pic_order_count = dec_params->top_field_order_cnt; + b->cur_pic_fields = V4L2_H264_TOP_FIELD_REF; + } for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { - u32 pic_order_count; - if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) continue; - b->refs[i].pic_num = dpb[i].pic_num; if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) b->refs[i].longterm = true; /* * Handle frame_num wraparound as described in section * '8.2.4.1 Decoding process for picture numbers' of the spec. - * TODO: This logic will have to be adjusted when we start - * supporting interlaced content. + * For long term references, frame_num is set to + * long_term_frame_idx which requires no wrapping. */ - if (dpb[i].frame_num > cur_frame_num) + if (!b->refs[i].longterm && dpb[i].frame_num > cur_frame_num) b->refs[i].frame_num = (int)dpb[i].frame_num - max_frame_num; else b->refs[i].frame_num = dpb[i].frame_num; - if (dpb[i].fields == V4L2_H264_FRAME_REF) - pic_order_count = min(dpb[i].top_field_order_cnt, - dpb[i].bottom_field_order_cnt); - else if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) - pic_order_count = dpb[i].bottom_field_order_cnt; - else - pic_order_count = dpb[i].top_field_order_cnt; + b->refs[i].top_field_order_cnt = dpb[i].top_field_order_cnt; + b->refs[i].bottom_field_order_cnt = dpb[i].bottom_field_order_cnt; + + if (b->cur_pic_fields == V4L2_H264_FRAME_REF) { + u8 fields = V4L2_H264_FRAME_REF; + + b->unordered_reflist[b->num_valid].index = i; + b->unordered_reflist[b->num_valid].fields = fields; + b->num_valid++; + continue; + } + + if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF) { + u8 fields = V4L2_H264_TOP_FIELD_REF; + + b->unordered_reflist[b->num_valid].index = i; + b->unordered_reflist[b->num_valid].fields = fields; + b->num_valid++; + } + + if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) { + u8 fields = V4L2_H264_BOTTOM_FIELD_REF; - b->refs[i].pic_order_count = pic_order_count; - b->unordered_reflist[b->num_valid] = i; - b->num_valid++; + b->unordered_reflist[b->num_valid].index = i; + b->unordered_reflist[b->num_valid].fields = fields; + b->num_valid++; + } } for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++) - b->unordered_reflist[i] = i; + b->unordered_reflist[i].index = i; } EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder); +static s32 v4l2_h264_get_poc(const struct v4l2_h264_reflist_builder *b, + const struct v4l2_h264_reference *ref) +{ + switch (ref->fields) { + case V4L2_H264_FRAME_REF: + return min(b->refs[ref->index].top_field_order_cnt, + b->refs[ref->index].bottom_field_order_cnt); + case V4L2_H264_TOP_FIELD_REF: + return b->refs[ref->index].top_field_order_cnt; + case V4L2_H264_BOTTOM_FIELD_REF: + return b->refs[ref->index].bottom_field_order_cnt; + } + + /* not reached */ + return 0; +} + static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb, const void *data) { const struct v4l2_h264_reflist_builder *builder = data; u8 idxa, idxb; - idxa = *((u8 *)ptra); - idxb = *((u8 *)ptrb); + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || idxb >= V4L2_H264_NUM_DPB_ENTRIES)) @@ -104,15 +144,19 @@ static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb, } /* - * Short term pics in descending pic num order, long term ones in - * ascending order. + * For frames, short term pics are in descending pic num order and long + * term ones in ascending order. For fields, the same direction is used + * but with frame_num (wrapped). For frames, the value of pic_num and + * frame_num are the same (see formula (8-28) and (8-29)). For this + * reason we can use frame_num only and share this function between + * frames and fields reflist. */ if (!builder->refs[idxa].longterm) return builder->refs[idxb].frame_num < builder->refs[idxa].frame_num ? -1 : 1; - return builder->refs[idxa].pic_num < builder->refs[idxb].pic_num ? + return builder->refs[idxa].frame_num < builder->refs[idxb].frame_num ? -1 : 1; } @@ -123,8 +167,8 @@ static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb, s32 poca, pocb; u8 idxa, idxb; - idxa = *((u8 *)ptra); - idxb = *((u8 *)ptrb); + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || idxb >= V4L2_H264_NUM_DPB_ENTRIES)) @@ -138,14 +182,14 @@ static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb, return 1; } - /* Long term pics in ascending pic num order. */ + /* Long term pics in ascending frame num order. */ if (builder->refs[idxa].longterm) - return builder->refs[idxa].pic_num < - builder->refs[idxb].pic_num ? + return builder->refs[idxa].frame_num < + builder->refs[idxb].frame_num ? -1 : 1; - poca = builder->refs[idxa].pic_order_count; - pocb = builder->refs[idxb].pic_order_count; + poca = v4l2_h264_get_poc(builder, ptra); + pocb = v4l2_h264_get_poc(builder, ptrb); /* * Short term pics with POC < cur POC first in POC descending order @@ -168,8 +212,8 @@ static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb, s32 poca, pocb; u8 idxa, idxb; - idxa = *((u8 *)ptra); - idxb = *((u8 *)ptrb); + idxa = ((struct v4l2_h264_reference *)ptra)->index; + idxb = ((struct v4l2_h264_reference *)ptrb)->index; if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || idxb >= V4L2_H264_NUM_DPB_ENTRIES)) @@ -183,14 +227,14 @@ static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb, return 1; } - /* Long term pics in ascending pic num order. */ + /* Long term pics in ascending frame num order. */ if (builder->refs[idxa].longterm) - return builder->refs[idxa].pic_num < - builder->refs[idxb].pic_num ? + return builder->refs[idxa].frame_num < + builder->refs[idxb].frame_num ? -1 : 1; - poca = builder->refs[idxa].pic_order_count; - pocb = builder->refs[idxb].pic_order_count; + poca = v4l2_h264_get_poc(builder, ptra); + pocb = v4l2_h264_get_poc(builder, ptrb); /* * Short term pics with POC > cur POC first in POC ascending order @@ -206,12 +250,135 @@ static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb, return poca < pocb ? -1 : 1; } +/* + * The references need to be reordered so that references are alternating + * between top and bottom field references starting with the current picture + * parity. This has to be done for short term and long term references + * separately. + */ +static void reorder_field_reflist(const struct v4l2_h264_reflist_builder *b, + struct v4l2_h264_reference *reflist) +{ + struct v4l2_h264_reference tmplist[V4L2_H264_REF_LIST_LEN]; + u8 lt, i = 0, j = 0, k = 0; + + memcpy(tmplist, reflist, sizeof(tmplist[0]) * b->num_valid); + + for (lt = 0; lt <= 1; lt++) { + do { + for (; i < b->num_valid && b->refs[tmplist[i].index].longterm == lt; i++) { + if (tmplist[i].fields == b->cur_pic_fields) { + reflist[k++] = tmplist[i++]; + break; + } + } + + for (; j < b->num_valid && b->refs[tmplist[j].index].longterm == lt; j++) { + if (tmplist[j].fields != b->cur_pic_fields) { + reflist[k++] = tmplist[j++]; + break; + } + } + } while ((i < b->num_valid && b->refs[tmplist[i].index].longterm == lt) || + (j < b->num_valid && b->refs[tmplist[j].index].longterm == lt)); + } +} + +static char ref_type_to_char(u8 ref_type) +{ + switch (ref_type) { + case V4L2_H264_FRAME_REF: + return 'f'; + case V4L2_H264_TOP_FIELD_REF: + return 't'; + case V4L2_H264_BOTTOM_FIELD_REF: + return 'b'; + } + + return '?'; +} + +static const char *format_ref_list_p(const struct v4l2_h264_reflist_builder *builder, + struct v4l2_h264_reference *reflist, + char **out_str) +{ + int n = 0, i; + + *out_str = kmalloc(tmp_str_size, GFP_KERNEL); + + n += snprintf(*out_str + n, tmp_str_size - n, "|"); + + for (i = 0; i < builder->num_valid; i++) { + /* this is pic_num for frame and frame_num (wrapped) for field, + * but for frame pic_num is equal to frame_num (wrapped). + */ + int frame_num = builder->refs[reflist[i].index].frame_num; + bool longterm = builder->refs[reflist[i].index].longterm; + + n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|", + frame_num, longterm ? 'l' : 's', + ref_type_to_char(reflist[i].fields)); + } + + return *out_str; +} + +static void print_ref_list_p(const struct v4l2_h264_reflist_builder *builder, + struct v4l2_h264_reference *reflist) +{ + char *buf = NULL; + + pr_debug("ref_pic_list_p (cur_poc %u%c) %s\n", + builder->cur_pic_order_count, + ref_type_to_char(builder->cur_pic_fields), + format_ref_list_p(builder, reflist, &buf)); + + kfree(buf); +} + +static const char *format_ref_list_b(const struct v4l2_h264_reflist_builder *builder, + struct v4l2_h264_reference *reflist, + char **out_str) +{ + int n = 0, i; + + *out_str = kmalloc(tmp_str_size, GFP_KERNEL); + + n += snprintf(*out_str + n, tmp_str_size - n, "|"); + + for (i = 0; i < builder->num_valid; i++) { + int frame_num = builder->refs[reflist[i].index].frame_num; + u32 poc = v4l2_h264_get_poc(builder, reflist + i); + bool longterm = builder->refs[reflist[i].index].longterm; + + n += scnprintf(*out_str + n, tmp_str_size - n, "%i%c%c|", + longterm ? frame_num : poc, + longterm ? 'l' : 's', + ref_type_to_char(reflist[i].fields)); + } + + return *out_str; +} + +static void print_ref_list_b(const struct v4l2_h264_reflist_builder *builder, + struct v4l2_h264_reference *reflist, u8 list_num) +{ + char *buf = NULL; + + pr_debug("ref_pic_list_b%u (cur_poc %u%c) %s", + list_num, builder->cur_pic_order_count, + ref_type_to_char(builder->cur_pic_fields), + format_ref_list_b(builder, reflist, &buf)); + + kfree(buf); +} + /** * v4l2_h264_build_p_ref_list() - Build the P reference list * * @builder: reference list builder context - * @reflist: 16-bytes array used to store the P reference list. Each entry - * is an index in the DPB + * @reflist: 32 sized array used to store the P reference list. Each entry + * is a v4l2_h264_reference structure * * This functions builds the P reference lists. This procedure is describe in * section '8.2.4 Decoding process for reference picture lists construction' @@ -220,12 +387,17 @@ static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb, */ void v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder, - u8 *reflist) + struct v4l2_h264_reference *reflist) { memcpy(reflist, builder->unordered_reflist, sizeof(builder->unordered_reflist[0]) * builder->num_valid); sort_r(reflist, builder->num_valid, sizeof(*reflist), v4l2_h264_p_ref_list_cmp, NULL, builder); + + if (builder->cur_pic_fields != V4L2_H264_FRAME_REF) + reorder_field_reflist(builder, reflist); + + print_ref_list_p(builder, reflist); } EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list); @@ -233,10 +405,10 @@ EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list); * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists * * @builder: reference list builder context - * @b0_reflist: 16-bytes array used to store the B0 reference list. Each entry - * is an index in the DPB - * @b1_reflist: 16-bytes array used to store the B1 reference list. Each entry - * is an index in the DPB + * @b0_reflist: 32 sized array used to store the B0 reference list. Each entry + * is a v4l2_h264_reference structure + * @b1_reflist: 32 sized array used to store the B1 reference list. Each entry + * is a v4l2_h264_reference structure * * This functions builds the B0/B1 reference lists. This procedure is described * in section '8.2.4 Decoding process for reference picture lists construction' @@ -245,7 +417,8 @@ EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list); */ void v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, - u8 *b0_reflist, u8 *b1_reflist) + struct v4l2_h264_reference *b0_reflist, + struct v4l2_h264_reference *b1_reflist) { memcpy(b0_reflist, builder->unordered_reflist, sizeof(builder->unordered_reflist[0]) * builder->num_valid); @@ -257,9 +430,17 @@ v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist), v4l2_h264_b1_ref_list_cmp, NULL, builder); + if (builder->cur_pic_fields != V4L2_H264_FRAME_REF) { + reorder_field_reflist(builder, b0_reflist); + reorder_field_reflist(builder, b1_reflist); + } + if (builder->num_valid > 1 && !memcmp(b1_reflist, b0_reflist, builder->num_valid)) swap(b1_reflist[0], b1_reflist[1]); + + print_ref_list_b(builder, b0_reflist, 0); + print_ref_list_b(builder, b1_reflist, 1); } EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists); diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 96e307fe3aab..21470de62d72 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -18,6 +18,7 @@ #include <linux/videodev2.h> +#include <media/media-device.h> /* for media_set_bus_info() */ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> @@ -1052,6 +1053,9 @@ static int v4l_querycap(const struct v4l2_ioctl_ops *ops, cap->device_caps = vfd->device_caps; cap->capabilities = vfd->device_caps | V4L2_CAP_DEVICE_CAPS; + media_set_bus_info(cap->bus_info, sizeof(cap->bus_info), + vfd->dev_parent); + ret = ops->vidioc_querycap(file, fh, cap); /* @@ -1265,6 +1269,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_Y16_BE: descr = "16-bit Greyscale BE"; break; case V4L2_PIX_FMT_Y10BPACK: descr = "10-bit Greyscale (Packed)"; break; case V4L2_PIX_FMT_Y10P: descr = "10-bit Greyscale (MIPI Packed)"; break; + case V4L2_PIX_FMT_IPU3_Y10: descr = "10-bit greyscale (IPU3 Packed)"; break; case V4L2_PIX_FMT_Y8I: descr = "Interleaved 8-bit Greyscale"; break; case V4L2_PIX_FMT_Y12I: descr = "Interleaved 12-bit Greyscale"; break; case V4L2_PIX_FMT_Z16: descr = "16-bit Depth"; break; @@ -1441,6 +1446,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_SE401: descr = "GSPCA SE401"; break; case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break; case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break; + case V4L2_PIX_FMT_QC08C: descr = "QCOM Compressed 8-bit Format"; break; + case V4L2_PIX_FMT_QC10C: descr = "QCOM Compressed 10-bit Format"; break; default: if (fmt->description[0]) return; diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 675e22895ebe..6469f9a25a4e 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -68,16 +68,16 @@ static const char * const m2m_entity_name[] = { * struct v4l2_m2m_dev - per-device context * @source: &struct media_entity pointer with the source entity * Used only when the M2M device is registered via - * v4l2_m2m_unregister_media_controller(). + * v4l2_m2m_register_media_controller(). * @source_pad: &struct media_pad with the source pad. * Used only when the M2M device is registered via - * v4l2_m2m_unregister_media_controller(). + * v4l2_m2m_register_media_controller(). * @sink: &struct media_entity pointer with the sink entity * Used only when the M2M device is registered via - * v4l2_m2m_unregister_media_controller(). + * v4l2_m2m_register_media_controller(). * @sink_pad: &struct media_pad with the sink pad. * Used only when the M2M device is registered via - * v4l2_m2m_unregister_media_controller(). + * v4l2_m2m_register_media_controller(). * @proc: &struct media_entity pointer with the M2M device itself. * @proc_pads: &struct media_pad with the @proc pads. * Used only when the M2M device is registered via @@ -336,6 +336,7 @@ static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev, if (src && dst && dst->is_held && dst->vb2_buf.copied_timestamp && dst->vb2_buf.timestamp != src->vb2_buf.timestamp) { + dprintk("Timestamp mismatch, returning held capture buffer\n"); dst->is_held = false; v4l2_m2m_dst_buf_remove(m2m_ctx); v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 30eb50407db5..5c27bac772ea 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -27,8 +27,9 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) { struct v4l2_subdev_state *state; + static struct lock_class_key key; - state = v4l2_subdev_alloc_state(sd); + state = __v4l2_subdev_state_alloc(sd, "fh->state->lock", &key); if (IS_ERR(state)) return PTR_ERR(state); @@ -39,7 +40,7 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) static void subdev_fh_free(struct v4l2_subdev_fh *fh) { - v4l2_subdev_free_state(fh->state); + __v4l2_subdev_state_free(fh->state); fh->state = NULL; } @@ -63,7 +64,7 @@ static int subdev_open(struct file *file) v4l2_fh_init(&subdev_fh->vfh, vdev); v4l2_fh_add(&subdev_fh->vfh); file->private_data = &subdev_fh->vfh; -#if defined(CONFIG_MEDIA_CONTROLLER) + if (sd->v4l2_dev->mdev && sd->entity.graph_obj.mdev->dev) { struct module *owner; @@ -74,7 +75,6 @@ static int subdev_open(struct file *file) } subdev_fh->owner = owner; } -#endif if (sd->internal_ops && sd->internal_ops->open) { ret = sd->internal_ops->open(sd, subdev_fh); @@ -318,14 +318,55 @@ static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, sd->ops->pad->get_mbus_config(sd, pad, config); } +#ifdef CONFIG_MEDIA_CONTROLLER +/* + * Create state-management wrapper for pad ops dealing with subdev state. The + * wrapper handles the case where the caller does not provide the called + * subdev's state. This should be removed when all the callers are fixed. + */ +#define DEFINE_STATE_WRAPPER(f, arg_type) \ + static int call_##f##_state(struct v4l2_subdev *sd, \ + struct v4l2_subdev_state *_state, \ + arg_type *arg) \ + { \ + struct v4l2_subdev_state *state = _state; \ + int ret; \ + if (!_state) \ + state = v4l2_subdev_lock_and_get_active_state(sd); \ + ret = call_##f(sd, state, arg); \ + if (!_state && state) \ + v4l2_subdev_unlock_state(state); \ + return ret; \ + } + +#else /* CONFIG_MEDIA_CONTROLLER */ + +#define DEFINE_STATE_WRAPPER(f, arg_type) \ + static int call_##f##_state(struct v4l2_subdev *sd, \ + struct v4l2_subdev_state *state, \ + arg_type *arg) \ + { \ + return call_##f(sd, state, arg); \ + } + +#endif /* CONFIG_MEDIA_CONTROLLER */ + +DEFINE_STATE_WRAPPER(get_fmt, struct v4l2_subdev_format); +DEFINE_STATE_WRAPPER(set_fmt, struct v4l2_subdev_format); +DEFINE_STATE_WRAPPER(enum_mbus_code, struct v4l2_subdev_mbus_code_enum); +DEFINE_STATE_WRAPPER(enum_frame_size, struct v4l2_subdev_frame_size_enum); +DEFINE_STATE_WRAPPER(enum_frame_interval, struct v4l2_subdev_frame_interval_enum); +DEFINE_STATE_WRAPPER(get_selection, struct v4l2_subdev_selection); +DEFINE_STATE_WRAPPER(set_selection, struct v4l2_subdev_selection); + static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = { - .get_fmt = call_get_fmt, - .set_fmt = call_set_fmt, - .enum_mbus_code = call_enum_mbus_code, - .enum_frame_size = call_enum_frame_size, - .enum_frame_interval = call_enum_frame_interval, - .get_selection = call_get_selection, - .set_selection = call_set_selection, + .get_fmt = call_get_fmt_state, + .set_fmt = call_set_fmt_state, + .enum_mbus_code = call_enum_mbus_code_state, + .enum_frame_size = call_enum_frame_size_state, + .enum_frame_interval = call_enum_frame_interval_state, + .get_selection = call_get_selection_state, + .set_selection = call_set_selection_state, .get_edid = call_get_edid, .set_edid = call_set_edid, .dv_timings_cap = call_dv_timings_cap, @@ -345,12 +386,50 @@ const struct v4l2_subdev_ops v4l2_subdev_call_wrappers = { EXPORT_SYMBOL(v4l2_subdev_call_wrappers); #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) -static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) + +static struct v4l2_subdev_state * +subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh, + unsigned int cmd, void *arg) +{ + u32 which; + + switch (cmd) { + default: + return NULL; + case VIDIOC_SUBDEV_G_FMT: + case VIDIOC_SUBDEV_S_FMT: + which = ((struct v4l2_subdev_format *)arg)->which; + break; + case VIDIOC_SUBDEV_G_CROP: + case VIDIOC_SUBDEV_S_CROP: + which = ((struct v4l2_subdev_crop *)arg)->which; + break; + case VIDIOC_SUBDEV_ENUM_MBUS_CODE: + which = ((struct v4l2_subdev_mbus_code_enum *)arg)->which; + break; + case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: + which = ((struct v4l2_subdev_frame_size_enum *)arg)->which; + break; + case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: + which = ((struct v4l2_subdev_frame_interval_enum *)arg)->which; + break; + case VIDIOC_SUBDEV_G_SELECTION: + case VIDIOC_SUBDEV_S_SELECTION: + which = ((struct v4l2_subdev_selection *)arg)->which; + break; + } + + return which == V4L2_SUBDEV_FORMAT_TRY ? + subdev_fh->state : + v4l2_subdev_get_unlocked_active_state(sd); +} + +static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg, + struct v4l2_subdev_state *state) { struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); struct v4l2_fh *vfh = file->private_data; - struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags); int rval; @@ -476,7 +555,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(format->reserved, 0, sizeof(format->reserved)); memset(format->format.reserved, 0, sizeof(format->format.reserved)); - return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->state, format); + return v4l2_subdev_call(sd, pad, get_fmt, state, format); } case VIDIOC_SUBDEV_S_FMT: { @@ -487,7 +566,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(format->reserved, 0, sizeof(format->reserved)); memset(format->format.reserved, 0, sizeof(format->format.reserved)); - return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->state, format); + return v4l2_subdev_call(sd, pad, set_fmt, state, format); } case VIDIOC_SUBDEV_G_CROP: { @@ -501,7 +580,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) sel.target = V4L2_SEL_TGT_CROP; rval = v4l2_subdev_call( - sd, pad, get_selection, subdev_fh->state, &sel); + sd, pad, get_selection, state, &sel); crop->rect = sel.r; @@ -523,7 +602,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) sel.r = crop->rect; rval = v4l2_subdev_call( - sd, pad, set_selection, subdev_fh->state, &sel); + sd, pad, set_selection, state, &sel); crop->rect = sel.r; @@ -534,7 +613,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_mbus_code_enum *code = arg; memset(code->reserved, 0, sizeof(code->reserved)); - return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->state, + return v4l2_subdev_call(sd, pad, enum_mbus_code, state, code); } @@ -542,7 +621,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_frame_size_enum *fse = arg; memset(fse->reserved, 0, sizeof(fse->reserved)); - return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->state, + return v4l2_subdev_call(sd, pad, enum_frame_size, state, fse); } @@ -567,7 +646,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_frame_interval_enum *fie = arg; memset(fie->reserved, 0, sizeof(fie->reserved)); - return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->state, + return v4l2_subdev_call(sd, pad, enum_frame_interval, state, fie); } @@ -576,7 +655,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( - sd, pad, get_selection, subdev_fh->state, sel); + sd, pad, get_selection, state, sel); } case VIDIOC_SUBDEV_S_SELECTION: { @@ -587,7 +666,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( - sd, pad, set_selection, subdev_fh->state, sel); + sd, pad, set_selection, state, sel); } case VIDIOC_G_EDID: { @@ -666,8 +745,24 @@ static long subdev_do_ioctl_lock(struct file *file, unsigned int cmd, void *arg) if (lock && mutex_lock_interruptible(lock)) return -ERESTARTSYS; - if (video_is_registered(vdev)) - ret = subdev_do_ioctl(file, cmd, arg); + + if (video_is_registered(vdev)) { + struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); + struct v4l2_fh *vfh = file->private_data; + struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); + struct v4l2_subdev_state *state; + + state = subdev_ioctl_get_state(sd, subdev_fh, cmd, arg); + + if (state) + v4l2_subdev_lock_state(state); + + ret = subdev_do_ioctl(file, cmd, arg, state); + + if (state) + v4l2_subdev_unlock_state(state); + } + if (lock) mutex_unlock(lock); return ret; @@ -824,7 +919,7 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad, fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; fmt->pad = pad->index; - return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); + return v4l2_subdev_call_state_active(sd, pad, get_fmt, fmt); } WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L, @@ -862,7 +957,9 @@ int v4l2_subdev_link_validate(struct media_link *link) } EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate); -struct v4l2_subdev_state *v4l2_subdev_alloc_state(struct v4l2_subdev *sd) +struct v4l2_subdev_state * +__v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name, + struct lock_class_key *lock_key) { struct v4l2_subdev_state *state; int ret; @@ -871,17 +968,29 @@ struct v4l2_subdev_state *v4l2_subdev_alloc_state(struct v4l2_subdev *sd) if (!state) return ERR_PTR(-ENOMEM); + __mutex_init(&state->_lock, lock_name, lock_key); + if (sd->state_lock) + state->lock = sd->state_lock; + else + state->lock = &state->_lock; + if (sd->entity.num_pads) { - state->pads = kvmalloc_array(sd->entity.num_pads, - sizeof(*state->pads), - GFP_KERNEL | __GFP_ZERO); + state->pads = kvcalloc(sd->entity.num_pads, + sizeof(*state->pads), GFP_KERNEL); if (!state->pads) { ret = -ENOMEM; goto err; } } + /* + * There can be no race at this point, but we lock the state anyway to + * satisfy lockdep checks. + */ + v4l2_subdev_lock_state(state); ret = v4l2_subdev_call(sd, pad, init_cfg, state); + v4l2_subdev_unlock_state(state); + if (ret < 0 && ret != -ENOIOCTLCMD) goto err; @@ -895,17 +1004,63 @@ err: return ERR_PTR(ret); } -EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_state); +EXPORT_SYMBOL_GPL(__v4l2_subdev_state_alloc); -void v4l2_subdev_free_state(struct v4l2_subdev_state *state) +void __v4l2_subdev_state_free(struct v4l2_subdev_state *state) { if (!state) return; + mutex_destroy(&state->_lock); + kvfree(state->pads); kfree(state); } -EXPORT_SYMBOL_GPL(v4l2_subdev_free_state); +EXPORT_SYMBOL_GPL(__v4l2_subdev_state_free); + +int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name, + struct lock_class_key *key) +{ + struct v4l2_subdev_state *state; + + state = __v4l2_subdev_state_alloc(sd, name, key); + if (IS_ERR(state)) + return PTR_ERR(state); + + sd->active_state = state; + + return 0; +} +EXPORT_SYMBOL_GPL(__v4l2_subdev_init_finalize); + +void v4l2_subdev_cleanup(struct v4l2_subdev *sd) +{ + __v4l2_subdev_state_free(sd->active_state); + sd->active_state = NULL; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_cleanup); + +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + +int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt; + + if (format->pad >= sd->entity.num_pads) + return -EINVAL; + + fmt = v4l2_subdev_get_pad_format(sd, state, format->pad); + if (!fmt) + return -EINVAL; + + format->format = *fmt; + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_get_fmt); + +#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */ #endif /* CONFIG_MEDIA_CONTROLLER */ diff --git a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c index d96aaa4bc75d..39604752785b 100644 --- a/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c +++ b/drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c @@ -254,7 +254,7 @@ void rmgr_pop_handle(struct ia_css_rmgr_vbuf_pool *pool, void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool, struct ia_css_rmgr_vbuf_handle **handle) { - struct ia_css_rmgr_vbuf_handle h; + struct ia_css_rmgr_vbuf_handle h = { 0 }; if ((!pool) || (!handle) || (!*handle)) { IA_CSS_LOG("Invalid inputs"); @@ -272,7 +272,7 @@ void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool, h.size = (*handle)->size; /* release ref to current buffer */ ia_css_rmgr_refcount_release_vbuf(handle); - *handle = &h; + **handle = h; } /* get new buffer for needed size */ if ((*handle)->vptr == 0x0) { diff --git a/drivers/staging/media/av7110/av7110_av.c b/drivers/staging/media/av7110/av7110_av.c index 91f4866c7e59..ab7cf496b454 100644 --- a/drivers/staging/media/av7110/av7110_av.c +++ b/drivers/staging/media/av7110/av7110_av.c @@ -595,10 +595,10 @@ static int find_pes_header(u8 const *buf, long int length, int *frags) case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : + case ECM_STREAM: + case EMM_STREAM: + case PADDING_STREAM: + case DSM_CC_STREAM: case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: @@ -659,10 +659,10 @@ void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : + case ECM_STREAM: + case EMM_STREAM: + case PADDING_STREAM: + case DSM_CC_STREAM: case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: @@ -770,22 +770,22 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, if (length > 3 && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) switch (buf[3]) { - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - case PRIVATE_STREAM1: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - pes_start = 1; - break; + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM: + case EMM_STREAM: + case PADDING_STREAM: + case DSM_CC_STREAM: + case ISO13522_STREAM: + case PRIVATE_STREAM1: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + pes_start = 1; + break; - default: - break; + default: + break; } while (c < length) { diff --git a/drivers/staging/media/hantro/TODO b/drivers/staging/media/hantro/TODO index 1d7fed936019..8483ff482146 100644 --- a/drivers/staging/media/hantro/TODO +++ b/drivers/staging/media/hantro/TODO @@ -1,6 +1,2 @@ -* Support for VP8, VP9 and H264 is planned for this driver. - - Given the V4L controls for those CODECs will be part of - the uABI, it will be required to have the driver in staging. - - For this reason, we are keeping this driver in staging for now. +The V4L controls for the HEVC CODEC are not yet part of the stable uABI, +we are keeping this driver in staging until the HEVC uABI has been merged. diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index 357f83b86809..26308bb29adc 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -475,5 +475,7 @@ void hantro_postproc_disable(struct hantro_ctx *ctx); void hantro_postproc_enable(struct hantro_ctx *ctx); void hantro_postproc_free(struct hantro_ctx *ctx); int hantro_postproc_alloc(struct hantro_ctx *ctx); +int hanto_postproc_enum_framesizes(struct hantro_ctx *ctx, + struct v4l2_frmsizeenum *fsize); #endif /* HANTRO_H_ */ diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index dc768884cb79..ac232b5f7825 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -56,6 +56,10 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts) return hantro_get_dec_buf_addr(ctx, buf); } +static const struct v4l2_event hantro_eos_event = { + .type = V4L2_EVENT_EOS +}; + static void hantro_job_finish_no_pm(struct hantro_dev *vpu, struct hantro_ctx *ctx, enum vb2_buffer_state result) @@ -73,6 +77,12 @@ static void hantro_job_finish_no_pm(struct hantro_dev *vpu, src->sequence = ctx->sequence_out++; dst->sequence = ctx->sequence_cap++; + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src)) { + dst->flags |= V4L2_BUF_FLAG_LAST; + v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event); + v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); + } + v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, result); } @@ -628,6 +638,7 @@ static const struct of_device_id of_hantro_match[] = { { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, }, { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, + { .compatible = "rockchip,rk3568-vpu", .data = &rk3568_vpu_variant, }, #endif #ifdef CONFIG_VIDEO_HANTRO_IMX8M { .compatible = "nxp,imx8mm-vpu-g1", .data = &imx8mm_vpu_g1_variant, }, @@ -809,10 +820,13 @@ static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid) snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible, funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec"); - if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) + if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) { vpu->encoder = func; - else + } else { vpu->decoder = func; + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); + } video_set_drvdata(vfd, vpu); diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c index f49dbfb8a843..9de7f05eff2a 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -126,7 +126,7 @@ static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) static void set_ref(struct hantro_ctx *ctx) { - const u8 *b0_reflist, *b1_reflist, *p_reflist; + const struct v4l2_h264_reference *b0_reflist, *b1_reflist, *p_reflist; struct hantro_dev *vpu = ctx->dev; int reg_num; u32 reg; @@ -157,12 +157,12 @@ static void set_ref(struct hantro_ctx *ctx) */ reg_num = 0; for (i = 0; i < 15; i += 3) { - reg = G1_REG_BD_REF_PIC_BINIT_RLIST_F0(b0_reflist[i]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_F1(b0_reflist[i + 1]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_F2(b0_reflist[i + 2]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_B0(b1_reflist[i]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_B1(b1_reflist[i + 1]) | - G1_REG_BD_REF_PIC_BINIT_RLIST_B2(b1_reflist[i + 2]); + reg = G1_REG_BD_REF_PIC_BINIT_RLIST_F0(b0_reflist[i].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_F1(b0_reflist[i + 1].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_F2(b0_reflist[i + 2].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B0(b1_reflist[i].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B1(b1_reflist[i + 1].index) | + G1_REG_BD_REF_PIC_BINIT_RLIST_B2(b1_reflist[i + 2].index); vdpu_write_relaxed(vpu, reg, G1_REG_BD_REF_PIC(reg_num++)); } @@ -171,12 +171,12 @@ static void set_ref(struct hantro_ctx *ctx) * of forward and backward reference picture lists and first 4 entries * of P forward picture list. */ - reg = G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(b0_reflist[15]) | - G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(b1_reflist[15]) | - G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(p_reflist[0]) | - G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(p_reflist[1]) | - G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(p_reflist[2]) | - G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(p_reflist[3]); + reg = G1_REG_BD_P_REF_PIC_BINIT_RLIST_F15(b0_reflist[15].index) | + G1_REG_BD_P_REF_PIC_BINIT_RLIST_B15(b1_reflist[15].index) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F0(p_reflist[0].index) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F1(p_reflist[1].index) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F2(p_reflist[2].index) | + G1_REG_BD_P_REF_PIC_PINIT_RLIST_F3(p_reflist[3].index); vdpu_write_relaxed(vpu, reg, G1_REG_BD_P_REF_PIC); /* @@ -185,12 +185,12 @@ static void set_ref(struct hantro_ctx *ctx) */ reg_num = 0; for (i = 4; i < HANTRO_H264_DPB_SIZE; i += 6) { - reg = G1_REG_FWD_PIC_PINIT_RLIST_F0(p_reflist[i]) | - G1_REG_FWD_PIC_PINIT_RLIST_F1(p_reflist[i + 1]) | - G1_REG_FWD_PIC_PINIT_RLIST_F2(p_reflist[i + 2]) | - G1_REG_FWD_PIC_PINIT_RLIST_F3(p_reflist[i + 3]) | - G1_REG_FWD_PIC_PINIT_RLIST_F4(p_reflist[i + 4]) | - G1_REG_FWD_PIC_PINIT_RLIST_F5(p_reflist[i + 5]); + reg = G1_REG_FWD_PIC_PINIT_RLIST_F0(p_reflist[i].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F1(p_reflist[i + 1].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F2(p_reflist[i + 2].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F3(p_reflist[i + 3].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F4(p_reflist[i + 4].index) | + G1_REG_FWD_PIC_PINIT_RLIST_F5(p_reflist[i + 5].index); vdpu_write_relaxed(vpu, reg, G1_REG_FWD_PIC(reg_num++)); } diff --git a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c index c524af41baf5..5df6f08e26f5 100644 --- a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c +++ b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c @@ -8,6 +8,20 @@ #include "hantro_hw.h" #include "hantro_g2_regs.h" +#define G2_ALIGN 16 + +static size_t hantro_hevc_chroma_offset(struct hantro_ctx *ctx) +{ + return ctx->dst_fmt.width * ctx->dst_fmt.height; +} + +static size_t hantro_hevc_motion_vectors_offset(struct hantro_ctx *ctx) +{ + size_t cr_offset = hantro_hevc_chroma_offset(ctx); + + return ALIGN((cr_offset * 3) / 2, G2_ALIGN); +} + static void prepare_tile_info_buffer(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; @@ -60,7 +74,7 @@ static void prepare_tile_info_buffer(struct hantro_ctx *ctx) no_chroma = 1; for (j = 0, tmp_w = 0; j < num_tile_cols - 1; j++) { tmp_w += pps->column_width_minus1[j] + 1; - *p++ = pps->column_width_minus1[j + 1]; + *p++ = pps->column_width_minus1[j] + 1; *p++ = h; if (i == 0 && h == 1 && ctb_size == 16) no_chroma = 1; @@ -180,13 +194,8 @@ static void set_params(struct hantro_ctx *ctx) hantro_reg_write(vpu, &g2_max_cu_qpd_depth, 0); } - if (pps->flags & V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT) { - hantro_reg_write(vpu, &g2_cb_qp_offset, pps->pps_cb_qp_offset); - hantro_reg_write(vpu, &g2_cr_qp_offset, pps->pps_cr_qp_offset); - } else { - hantro_reg_write(vpu, &g2_cb_qp_offset, 0); - hantro_reg_write(vpu, &g2_cr_qp_offset, 0); - } + hantro_reg_write(vpu, &g2_cb_qp_offset, pps->pps_cb_qp_offset); + hantro_reg_write(vpu, &g2_cr_qp_offset, pps->pps_cr_qp_offset); hantro_reg_write(vpu, &g2_filt_offset_beta, pps->pps_beta_offset_div2); hantro_reg_write(vpu, &g2_filt_offset_tc, pps->pps_tc_offset_div2); @@ -335,7 +344,6 @@ static void set_ref_pic_list(struct hantro_ctx *ctx) static int set_ref(struct hantro_ctx *ctx) { const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; - const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps; const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params; const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb; @@ -343,8 +351,8 @@ static int set_ref(struct hantro_ctx *ctx) struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *vb2_dst; struct hantro_decoded_buffer *dst; - size_t cr_offset = hantro_hevc_chroma_offset(sps); - size_t mv_offset = hantro_hevc_motion_vectors_offset(sps); + size_t cr_offset = hantro_hevc_chroma_offset(ctx); + size_t mv_offset = hantro_hevc_motion_vectors_offset(ctx); u32 max_ref_frames; u16 dpb_longterm_e; static const struct hantro_reg cur_poc[] = { @@ -406,8 +414,8 @@ static int set_ref(struct hantro_ctx *ctx) set_ref_pic_list(ctx); - /* We will only keep the references picture that are still used */ - ctx->hevc_dec.ref_bufs_used = 0; + /* We will only keep the reference pictures that are still used */ + hantro_hevc_ref_init(ctx); /* Set up addresses of DPB buffers */ dpb_longterm_e = 0; @@ -448,8 +456,6 @@ static int set_ref(struct hantro_ctx *ctx) hantro_write_addr(vpu, G2_OUT_CHROMA_ADDR, chroma_addr); hantro_write_addr(vpu, G2_OUT_MV_ADDR, mv_addr); - hantro_hevc_ref_remove_unused(ctx); - for (; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) { hantro_write_addr(vpu, G2_REF_LUMA_ADDR(i), 0); hantro_write_addr(vpu, G2_REF_CHROMA_ADDR(i), 0); diff --git a/drivers/staging/media/hantro/hantro_g2_regs.h b/drivers/staging/media/hantro/hantro_g2_regs.h index b7c6f9877b9d..877d663a8181 100644 --- a/drivers/staging/media/hantro/hantro_g2_regs.h +++ b/drivers/staging/media/hantro/hantro_g2_regs.h @@ -290,6 +290,10 @@ #define g2_buswidth G2_DEC_REG(58, 8, 0x7) #define g2_max_burst G2_DEC_REG(58, 0, 0xff) +#define g2_down_scale_e G2_DEC_REG(184, 7, 0x1) +#define g2_down_scale_y G2_DEC_REG(184, 2, 0x3) +#define g2_down_scale_x G2_DEC_REG(184, 0, 0x3) + #define G2_REG_CONFIG G2_SWREG(58) #define G2_REG_CONFIG_DEC_CLK_GATE_E BIT(16) #define G2_REG_CONFIG_DEC_CLK_GATE_IDLE_E BIT(17) @@ -312,6 +316,8 @@ #define G2_TILE_FILTER_ADDR (G2_SWREG(179)) #define G2_TILE_SAO_ADDR (G2_SWREG(181)) #define G2_TILE_BSD_ADDR (G2_SWREG(183)) +#define G2_DS_DST (G2_SWREG(186)) +#define G2_DS_DST_CHR (G2_SWREG(188)) #define g2_strm_buffer_len G2_DEC_REG(258, 0, 0xffffffff) #define g2_strm_start_offset G2_DEC_REG(259, 0, 0xffffffff) diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c index 0b4d2491be3b..4e9a0ecf5c13 100644 --- a/drivers/staging/media/hantro/hantro_h264.c +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -22,6 +22,12 @@ #define POC_BUFFER_SIZE 34 #define SCALING_LIST_SIZE (6 * 16 + 2 * 64) +/* + * For valid and long term reference marking, index are reversed, so bit 31 + * indicates the status of the picture 0. + */ +#define REF_BIT(i) BIT(32 - 1 - (i)) + /* Data structure describing auxiliary buffer format. */ struct hantro_h264_dec_priv_tbl { u32 cabac_table[CABAC_INIT_BUFFER_SIZE]; @@ -227,6 +233,7 @@ static void prepare_table(struct hantro_ctx *ctx) { const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; + const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; u32 dpb_longterm = 0; @@ -237,20 +244,45 @@ static void prepare_table(struct hantro_ctx *ctx) tbl->poc[i * 2] = dpb[i].top_field_order_cnt; tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; + if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_VALID)) + continue; + /* * Set up bit maps of valid and long term DPBs. - * NOTE: The bits are reversed, i.e. MSb is DPB 0. + * NOTE: The bits are reversed, i.e. MSb is DPB 0. For frame + * decoding, bit 31 to 15 are used, while for field decoding, + * all bits are used, with bit 31 being a top field, 30 a bottom + * field and so on. */ - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + if (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) { + if (dpb[i].fields & V4L2_H264_TOP_FIELD_REF) + dpb_valid |= REF_BIT(i * 2); + + if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF) + dpb_valid |= REF_BIT(i * 2 + 1); + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) { + dpb_longterm |= REF_BIT(i * 2); + dpb_longterm |= REF_BIT(i * 2 + 1); + } + } else { + dpb_valid |= REF_BIT(i); + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + dpb_longterm |= REF_BIT(i); + } + } + ctx->h264_dec.dpb_valid = dpb_valid; + ctx->h264_dec.dpb_longterm = dpb_longterm; + + if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || + !(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { + tbl->poc[32] = ctx->h264_dec.cur_poc; + tbl->poc[33] = 0; + } else { + tbl->poc[32] = dec_param->top_field_order_cnt; + tbl->poc[33] = dec_param->bottom_field_order_cnt; } - ctx->h264_dec.dpb_valid = dpb_valid << 16; - ctx->h264_dec.dpb_longterm = dpb_longterm << 16; - - tbl->poc[32] = dec_param->top_field_order_cnt; - tbl->poc[33] = dec_param->bottom_field_order_cnt; assemble_scaling_list(ctx); } @@ -258,8 +290,7 @@ static void prepare_table(struct hantro_ctx *ctx) static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, const struct v4l2_h264_dpb_entry *b) { - return a->top_field_order_cnt == b->top_field_order_cnt && - a->bottom_field_order_cnt == b->bottom_field_order_cnt; + return a->reference_ts == b->reference_ts; } static void update_dpb(struct hantro_ctx *ctx) @@ -273,13 +304,13 @@ static void update_dpb(struct hantro_ctx *ctx) /* Disable all entries by default. */ for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) - ctx->h264_dec.dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; + ctx->h264_dec.dpb[i].flags = 0; /* Try to match new DPB entries with existing ones by their POCs. */ for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; - if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID)) continue; /* @@ -290,8 +321,7 @@ static void update_dpb(struct hantro_ctx *ctx) struct v4l2_h264_dpb_entry *cdpb; cdpb = &ctx->h264_dec.dpb[j]; - if (cdpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE || - !dpb_entry_match(cdpb, ndpb)) + if (!dpb_entry_match(cdpb, ndpb)) continue; *cdpb = *ndpb; @@ -328,6 +358,8 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, { struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; dma_addr_t dma_addr = 0; + s32 cur_poc = ctx->h264_dec.cur_poc; + u32 flags; if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) dma_addr = hantro_get_ref(ctx, dpb[dpb_idx].reference_ts); @@ -345,7 +377,12 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, dma_addr = hantro_get_dec_buf_addr(ctx, buf); } - return dma_addr; + flags = dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD ? 0x2 : 0; + flags |= abs(dpb[dpb_idx].top_field_order_cnt - cur_poc) < + abs(dpb[dpb_idx].bottom_field_order_cnt - cur_poc) ? + 0x1 : 0; + + return dma_addr | flags; } u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, unsigned int dpb_idx) @@ -354,11 +391,50 @@ u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, unsigned int dpb_idx) if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) return 0; - if (dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - return dpb->pic_num; return dpb->frame_num; } +/* + * Removes all references with the same parity as the current picture from the + * reference list. The remaining list will have references with the opposite + * parity. This is effectively a deduplication of references since each buffer + * stores two fields. For this reason, each buffer is found twice in the + * reference list. + * + * This technique has been chosen through trial and error. This simple approach + * resulted in the highest conformance score. Note that this method may suffer + * worse quality in the case an opposite reference frame has been lost. If this + * becomes a problem in the future, it should be possible to add a preprocessing + * to identify un-paired fields and avoid removing them. + */ +static void deduplicate_reflist(struct v4l2_h264_reflist_builder *b, + struct v4l2_h264_reference *reflist) +{ + int write_idx = 0; + int i; + + if (b->cur_pic_fields == V4L2_H264_FRAME_REF) { + write_idx = b->num_valid; + goto done; + } + + for (i = 0; i < b->num_valid; i++) { + if (!(b->cur_pic_fields == reflist[i].fields)) { + reflist[write_idx++] = reflist[i]; + continue; + } + } + +done: + /* Should not happen unless we have a bug in the reflist builder. */ + if (WARN_ON(write_idx > 16)) + write_idx = 16; + + /* Clear the remaining, some streams fails otherwise */ + for (; write_idx < 16; write_idx++) + reflist[write_idx].index = 15; +} + int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) { struct hantro_h264_dec_hw_ctx *h264_ctx = &ctx->h264_dec; @@ -390,15 +466,29 @@ int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) /* Update the DPB with new refs. */ update_dpb(ctx); - /* Prepare data in memory. */ - prepare_table(ctx); - /* Build the P/B{0,1} ref lists. */ v4l2_h264_init_reflist_builder(&reflist_builder, ctrls->decode, ctrls->sps, ctx->h264_dec.dpb); + h264_ctx->cur_poc = reflist_builder.cur_pic_order_count; + + /* Prepare data in memory. */ + prepare_table(ctx); + v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, h264_ctx->reflists.b1); + + /* + * Reduce ref lists to at most 16 entries, Hantro hardware will deduce + * the actual picture lists in field through the dpb_valid, + * dpb_longterm bitmap along with the current frame parity. + */ + if (reflist_builder.cur_pic_fields != V4L2_H264_FRAME_REF) { + deduplicate_reflist(&reflist_builder, h264_ctx->reflists.p); + deduplicate_reflist(&reflist_builder, h264_ctx->reflists.b0); + deduplicate_reflist(&reflist_builder, h264_ctx->reflists.b1); + } + return 0; } diff --git a/drivers/staging/media/hantro/hantro_hevc.c b/drivers/staging/media/hantro/hantro_hevc.c index b49a41d7ae91..f86c98e19177 100644 --- a/drivers/staging/media/hantro/hantro_hevc.c +++ b/drivers/staging/media/hantro/hantro_hevc.c @@ -25,32 +25,11 @@ #define MAX_TILE_COLS 20 #define MAX_TILE_ROWS 22 -#define UNUSED_REF -1 - -#define G2_ALIGN 16 - -size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps) -{ - int bytes_per_pixel = sps->bit_depth_luma_minus8 == 0 ? 1 : 2; - - return sps->pic_width_in_luma_samples * - sps->pic_height_in_luma_samples * bytes_per_pixel; -} - -size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps) -{ - size_t cr_offset = hantro_hevc_chroma_offset(sps); - - return ALIGN((cr_offset * 3) / 2, G2_ALIGN); -} - -static void hantro_hevc_ref_init(struct hantro_ctx *ctx) +void hantro_hevc_ref_init(struct hantro_ctx *ctx) { struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; - int i; - for (i = 0; i < NUM_REF_PICTURES; i++) - hevc_dec->ref_bufs_poc[i] = UNUSED_REF; + hevc_dec->ref_bufs_used = 0; } dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, @@ -59,7 +38,7 @@ dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; int i; - /* Find the reference buffer in already know ones */ + /* Find the reference buffer in already known ones */ for (i = 0; i < NUM_REF_PICTURES; i++) { if (hevc_dec->ref_bufs_poc[i] == poc) { hevc_dec->ref_bufs_used |= 1 << i; @@ -77,7 +56,7 @@ int hantro_hevc_add_ref_buf(struct hantro_ctx *ctx, int poc, dma_addr_t addr) /* Add a new reference buffer */ for (i = 0; i < NUM_REF_PICTURES; i++) { - if (hevc_dec->ref_bufs_poc[i] == UNUSED_REF) { + if (!(hevc_dec->ref_bufs_used & 1 << i)) { hevc_dec->ref_bufs_used |= 1 << i; hevc_dec->ref_bufs_poc[i] = poc; hevc_dec->ref_bufs[i].dma = addr; @@ -88,23 +67,6 @@ int hantro_hevc_add_ref_buf(struct hantro_ctx *ctx, int poc, dma_addr_t addr) return -EINVAL; } -void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx) -{ - struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec; - int i; - - /* Just tag buffer as unused, do not free them */ - for (i = 0; i < NUM_REF_PICTURES; i++) { - if (hevc_dec->ref_bufs_poc[i] == UNUSED_REF) - continue; - - if (hevc_dec->ref_bufs_used & (1 << i)) - continue; - - hevc_dec->ref_bufs_poc[i] = UNUSED_REF; - } -} - static int tile_buffer_reallocate(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index ed018e293ba0..52a960f6fa4a 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -69,9 +69,9 @@ struct hantro_h264_dec_ctrls { * @b1: B1 reflist */ struct hantro_h264_dec_reflists { - u8 p[HANTRO_H264_DPB_SIZE]; - u8 b0[HANTRO_H264_DPB_SIZE]; - u8 b1[HANTRO_H264_DPB_SIZE]; + struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN]; }; /** @@ -83,6 +83,7 @@ struct hantro_h264_dec_reflists { * @ctrls: V4L2 controls attached to a run * @dpb_longterm: DPB long-term * @dpb_valid: DPB valid + * @cur_poc: Current picture order count */ struct hantro_h264_dec_hw_ctx { struct hantro_aux_buf priv; @@ -91,6 +92,7 @@ struct hantro_h264_dec_hw_ctx { struct hantro_h264_dec_ctrls ctrls; u32 dpb_longterm; u32 dpb_valid; + s32 cur_poc; }; /** @@ -245,12 +247,16 @@ struct hantro_postproc_ctx { /** * struct hantro_postproc_ops - post-processor operations * - * @enable: Enable the post-processor block. Optional. - * @disable: Disable the post-processor block. Optional. + * @enable: Enable the post-processor block. Optional. + * @disable: Disable the post-processor block. Optional. + * @enum_framesizes: Enumerate possible scaled output formats. + * Returns zero if OK, a negative value in error cases. + * Optional. */ struct hantro_postproc_ops { void (*enable)(struct hantro_ctx *ctx); void (*disable)(struct hantro_ctx *ctx); + int (*enum_framesizes)(struct hantro_ctx *ctx, struct v4l2_frmsizeenum *fsize); }; /** @@ -300,6 +306,7 @@ extern const struct hantro_variant rk3066_vpu_variant; extern const struct hantro_variant rk3288_vpu_variant; extern const struct hantro_variant rk3328_vpu_variant; extern const struct hantro_variant rk3399_vpu_variant; +extern const struct hantro_variant rk3568_vpu_variant; extern const struct hantro_variant sama5d4_vdec_variant; extern const struct hantro_variant sunxi_vpu_variant; @@ -337,11 +344,9 @@ int hantro_hevc_dec_init(struct hantro_ctx *ctx); void hantro_hevc_dec_exit(struct hantro_ctx *ctx); int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx); int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx); +void hantro_hevc_ref_init(struct hantro_ctx *ctx); dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, int poc); int hantro_hevc_add_ref_buf(struct hantro_ctx *ctx, int poc, dma_addr_t addr); -void hantro_hevc_ref_remove_unused(struct hantro_ctx *ctx); -size_t hantro_hevc_chroma_offset(const struct v4l2_ctrl_hevc_sps *sps); -size_t hantro_hevc_motion_vectors_offset(const struct v4l2_ctrl_hevc_sps *sps); static inline unsigned short hantro_vp9_num_sbs(unsigned short dimension) { diff --git a/drivers/staging/media/hantro/hantro_postproc.c b/drivers/staging/media/hantro/hantro_postproc.c index 248abe5423f0..ab168c1c0d28 100644 --- a/drivers/staging/media/hantro/hantro_postproc.c +++ b/drivers/staging/media/hantro/hantro_postproc.c @@ -100,21 +100,58 @@ static void hantro_postproc_g1_enable(struct hantro_ctx *ctx) HANTRO_PP_REG_WRITE(vpu, display_width, ctx->dst_fmt.width); } +static int down_scale_factor(struct hantro_ctx *ctx) +{ + if (ctx->src_fmt.width == ctx->dst_fmt.width) + return 0; + + return DIV_ROUND_CLOSEST(ctx->src_fmt.width, ctx->dst_fmt.width); +} + static void hantro_postproc_g2_enable(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; struct vb2_v4l2_buffer *dst_buf; size_t chroma_offset = ctx->dst_fmt.width * ctx->dst_fmt.height; + int down_scale = down_scale_factor(ctx); dma_addr_t dst_dma; dst_buf = hantro_get_dst_buf(ctx); dst_dma = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - hantro_write_addr(vpu, G2_RS_OUT_LUMA_ADDR, dst_dma); - hantro_write_addr(vpu, G2_RS_OUT_CHROMA_ADDR, dst_dma + chroma_offset); + if (down_scale) { + hantro_reg_write(vpu, &g2_down_scale_e, 1); + hantro_reg_write(vpu, &g2_down_scale_y, down_scale >> 2); + hantro_reg_write(vpu, &g2_down_scale_x, down_scale >> 2); + hantro_write_addr(vpu, G2_DS_DST, dst_dma); + hantro_write_addr(vpu, G2_DS_DST_CHR, dst_dma + (chroma_offset >> down_scale)); + } else { + hantro_write_addr(vpu, G2_RS_OUT_LUMA_ADDR, dst_dma); + hantro_write_addr(vpu, G2_RS_OUT_CHROMA_ADDR, dst_dma + chroma_offset); + } hantro_reg_write(vpu, &g2_out_rs_e, 1); } +static int hantro_postproc_g2_enum_framesizes(struct hantro_ctx *ctx, + struct v4l2_frmsizeenum *fsize) +{ + /** + * G2 scaler can scale down by 0, 2, 4 or 8 + * use fsize->index has power of 2 diviser + **/ + if (fsize->index > 3) + return -EINVAL; + + if (!ctx->src_fmt.width || !ctx->src_fmt.height) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = ctx->src_fmt.width >> fsize->index; + fsize->discrete.height = ctx->src_fmt.height >> fsize->index; + + return 0; +} + void hantro_postproc_free(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; @@ -197,6 +234,17 @@ void hantro_postproc_enable(struct hantro_ctx *ctx) vpu->variant->postproc_ops->enable(ctx); } +int hanto_postproc_enum_framesizes(struct hantro_ctx *ctx, + struct v4l2_frmsizeenum *fsize) +{ + struct hantro_dev *vpu = ctx->dev; + + if (vpu->variant->postproc_ops && vpu->variant->postproc_ops->enum_framesizes) + return vpu->variant->postproc_ops->enum_framesizes(ctx, fsize); + + return -EINVAL; +} + const struct hantro_postproc_ops hantro_g1_postproc_ops = { .enable = hantro_postproc_g1_enable, .disable = hantro_postproc_g1_disable, @@ -205,4 +253,5 @@ const struct hantro_postproc_ops hantro_g1_postproc_ops = { const struct hantro_postproc_ops hantro_g2_postproc_ops = { .enable = hantro_postproc_g2_enable, .disable = hantro_postproc_g2_disable, + .enum_framesizes = hantro_postproc_g2_enum_framesizes, }; diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c index 67148ba346f5..22ad182ee972 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.c +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -116,12 +116,6 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, struct hantro_ctx *ctx = fh_to_ctx(priv); const struct hantro_fmt *fmt; - if (fsize->index != 0) { - vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", - fsize->index); - return -EINVAL; - } - fmt = hantro_find_format(ctx, fsize->pixel_format); if (!fmt) { vpu_debug(0, "unsupported bitstream format (%08x)\n", @@ -129,9 +123,14 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, return -EINVAL; } - /* This only makes sense for coded formats */ - if (fmt->codec_mode == HANTRO_MODE_NONE) + /* For non-coded formats check if postprocessing scaling is possible */ + if (fmt->codec_mode == HANTRO_MODE_NONE && hantro_needs_postproc(ctx, fmt)) { + return hanto_postproc_enum_framesizes(ctx, fsize); + } else if (fsize->index != 0) { + vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", + fsize->index); return -EINVAL; + } fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; fsize->stepwise = fmt->frmsize; @@ -409,6 +408,30 @@ hantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) } } +static void +hantro_update_requires_hold_capture_buf(struct hantro_ctx *ctx, u32 fourcc) +{ + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + switch (fourcc) { + case V4L2_PIX_FMT_JPEG: + case V4L2_PIX_FMT_MPEG2_SLICE: + case V4L2_PIX_FMT_VP8_FRAME: + case V4L2_PIX_FMT_HEVC_SLICE: + case V4L2_PIX_FMT_VP9_FRAME: + vq->subsystem_flags &= ~(VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF); + break; + case V4L2_PIX_FMT_H264_SLICE: + vq->subsystem_flags |= VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; + break; + default: + break; + } +} + static int hantro_set_fmt_out(struct hantro_ctx *ctx, struct v4l2_pix_format_mplane *pix_mp) { @@ -472,6 +495,7 @@ static int hantro_set_fmt_out(struct hantro_ctx *ctx, ctx->dst_fmt.quantization = pix_mp->quantization; hantro_update_requires_request(ctx, pix_mp->pixelformat); + hantro_update_requires_hold_capture_buf(ctx, pix_mp->pixelformat); vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode); vpu_debug(0, "fmt - w: %d, h: %d\n", @@ -628,6 +652,38 @@ static int vidioc_s_selection(struct file *file, void *priv, return 0; } +static const struct v4l2_event hantro_eos_event = { + .type = V4L2_EVENT_EOS +}; + +static int vidioc_encoder_cmd(struct file *file, void *priv, + struct v4l2_encoder_cmd *ec) +{ + struct hantro_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, ec); + if (ret < 0) + return ret; + + if (!vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)) || + !vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx))) + return 0; + + ret = v4l2_m2m_ioctl_encoder_cmd(file, priv, ec); + if (ret < 0) + return ret; + + if (ec->cmd == V4L2_ENC_CMD_STOP && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) + v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event); + + if (ec->cmd == V4L2_ENC_CMD_START) + vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); + + return 0; +} + const struct v4l2_ioctl_ops hantro_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_framesizes = vidioc_enum_framesizes, @@ -657,6 +713,9 @@ const struct v4l2_ioctl_ops hantro_ioctl_ops = { .vidioc_g_selection = vidioc_g_selection, .vidioc_s_selection = vidioc_s_selection, + + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = vidioc_encoder_cmd, }; static int @@ -733,8 +792,12 @@ static int hantro_buf_prepare(struct vb2_buffer *vb) * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets * it to buffer length). */ - if (V4L2_TYPE_IS_CAPTURE(vq->type)) - vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage); + if (V4L2_TYPE_IS_CAPTURE(vq->type)) { + if (ctx->is_encoder) + vb2_set_plane_payload(vb, 0, 0); + else + vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage); + } return 0; } @@ -744,6 +807,22 @@ static void hantro_buf_queue(struct vb2_buffer *vb) struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && + vb2_is_streaming(vb->vb2_queue) && + v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { + unsigned int i; + + for (i = 0; i < vb->num_planes; i++) + vb2_set_plane_payload(vb, i, 0); + + vbuf->field = V4L2_FIELD_NONE; + vbuf->sequence = ctx->sequence_cap++; + + v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); + v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event); + return; + } + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } @@ -759,6 +838,8 @@ static int hantro_start_streaming(struct vb2_queue *q, unsigned int count) struct hantro_ctx *ctx = vb2_get_drv_priv(q); int ret = 0; + v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); + if (V4L2_TYPE_IS_OUTPUT(q->type)) ctx->sequence_out = 0; else @@ -831,6 +912,12 @@ static void hantro_stop_streaming(struct vb2_queue *q) hantro_return_bufs(q, v4l2_m2m_src_buf_remove); else hantro_return_bufs(q, v4l2_m2m_dst_buf_remove); + + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); + + if (V4L2_TYPE_IS_OUTPUT(q->type) && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) + v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event); } static void hantro_buf_request_complete(struct vb2_buffer *vb) diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c index 64a6330475eb..46c1a83bcc4e 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c @@ -298,7 +298,7 @@ static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) static void set_ref(struct hantro_ctx *ctx) { - const u8 *b0_reflist, *b1_reflist, *p_reflist; + const struct v4l2_h264_reference *b0_reflist, *b1_reflist, *p_reflist; struct hantro_dev *vpu = ctx->dev; u32 reg; int i; @@ -307,20 +307,20 @@ static void set_ref(struct hantro_ctx *ctx) b1_reflist = ctx->h264_dec.reflists.b1; p_reflist = ctx->h264_dec.reflists.p; - reg = VDPU_REG_PINIT_RLIST_F9(p_reflist[9]) | - VDPU_REG_PINIT_RLIST_F8(p_reflist[8]) | - VDPU_REG_PINIT_RLIST_F7(p_reflist[7]) | - VDPU_REG_PINIT_RLIST_F6(p_reflist[6]) | - VDPU_REG_PINIT_RLIST_F5(p_reflist[5]) | - VDPU_REG_PINIT_RLIST_F4(p_reflist[4]); + reg = VDPU_REG_PINIT_RLIST_F9(p_reflist[9].index) | + VDPU_REG_PINIT_RLIST_F8(p_reflist[8].index) | + VDPU_REG_PINIT_RLIST_F7(p_reflist[7].index) | + VDPU_REG_PINIT_RLIST_F6(p_reflist[6].index) | + VDPU_REG_PINIT_RLIST_F5(p_reflist[5].index) | + VDPU_REG_PINIT_RLIST_F4(p_reflist[4].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(74)); - reg = VDPU_REG_PINIT_RLIST_F15(p_reflist[15]) | - VDPU_REG_PINIT_RLIST_F14(p_reflist[14]) | - VDPU_REG_PINIT_RLIST_F13(p_reflist[13]) | - VDPU_REG_PINIT_RLIST_F12(p_reflist[12]) | - VDPU_REG_PINIT_RLIST_F11(p_reflist[11]) | - VDPU_REG_PINIT_RLIST_F10(p_reflist[10]); + reg = VDPU_REG_PINIT_RLIST_F15(p_reflist[15].index) | + VDPU_REG_PINIT_RLIST_F14(p_reflist[14].index) | + VDPU_REG_PINIT_RLIST_F13(p_reflist[13].index) | + VDPU_REG_PINIT_RLIST_F12(p_reflist[12].index) | + VDPU_REG_PINIT_RLIST_F11(p_reflist[11].index) | + VDPU_REG_PINIT_RLIST_F10(p_reflist[10].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(75)); reg = VDPU_REG_REFER1_NBR(hantro_h264_get_ref_nbr(ctx, 1)) | @@ -355,54 +355,54 @@ static void set_ref(struct hantro_ctx *ctx) VDPU_REG_REFER14_NBR(hantro_h264_get_ref_nbr(ctx, 14)); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(83)); - reg = VDPU_REG_BINIT_RLIST_F5(b0_reflist[5]) | - VDPU_REG_BINIT_RLIST_F4(b0_reflist[4]) | - VDPU_REG_BINIT_RLIST_F3(b0_reflist[3]) | - VDPU_REG_BINIT_RLIST_F2(b0_reflist[2]) | - VDPU_REG_BINIT_RLIST_F1(b0_reflist[1]) | - VDPU_REG_BINIT_RLIST_F0(b0_reflist[0]); + reg = VDPU_REG_BINIT_RLIST_F5(b0_reflist[5].index) | + VDPU_REG_BINIT_RLIST_F4(b0_reflist[4].index) | + VDPU_REG_BINIT_RLIST_F3(b0_reflist[3].index) | + VDPU_REG_BINIT_RLIST_F2(b0_reflist[2].index) | + VDPU_REG_BINIT_RLIST_F1(b0_reflist[1].index) | + VDPU_REG_BINIT_RLIST_F0(b0_reflist[0].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(100)); - reg = VDPU_REG_BINIT_RLIST_F11(b0_reflist[11]) | - VDPU_REG_BINIT_RLIST_F10(b0_reflist[10]) | - VDPU_REG_BINIT_RLIST_F9(b0_reflist[9]) | - VDPU_REG_BINIT_RLIST_F8(b0_reflist[8]) | - VDPU_REG_BINIT_RLIST_F7(b0_reflist[7]) | - VDPU_REG_BINIT_RLIST_F6(b0_reflist[6]); + reg = VDPU_REG_BINIT_RLIST_F11(b0_reflist[11].index) | + VDPU_REG_BINIT_RLIST_F10(b0_reflist[10].index) | + VDPU_REG_BINIT_RLIST_F9(b0_reflist[9].index) | + VDPU_REG_BINIT_RLIST_F8(b0_reflist[8].index) | + VDPU_REG_BINIT_RLIST_F7(b0_reflist[7].index) | + VDPU_REG_BINIT_RLIST_F6(b0_reflist[6].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(101)); - reg = VDPU_REG_BINIT_RLIST_F15(b0_reflist[15]) | - VDPU_REG_BINIT_RLIST_F14(b0_reflist[14]) | - VDPU_REG_BINIT_RLIST_F13(b0_reflist[13]) | - VDPU_REG_BINIT_RLIST_F12(b0_reflist[12]); + reg = VDPU_REG_BINIT_RLIST_F15(b0_reflist[15].index) | + VDPU_REG_BINIT_RLIST_F14(b0_reflist[14].index) | + VDPU_REG_BINIT_RLIST_F13(b0_reflist[13].index) | + VDPU_REG_BINIT_RLIST_F12(b0_reflist[12].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(102)); - reg = VDPU_REG_BINIT_RLIST_B5(b1_reflist[5]) | - VDPU_REG_BINIT_RLIST_B4(b1_reflist[4]) | - VDPU_REG_BINIT_RLIST_B3(b1_reflist[3]) | - VDPU_REG_BINIT_RLIST_B2(b1_reflist[2]) | - VDPU_REG_BINIT_RLIST_B1(b1_reflist[1]) | - VDPU_REG_BINIT_RLIST_B0(b1_reflist[0]); + reg = VDPU_REG_BINIT_RLIST_B5(b1_reflist[5].index) | + VDPU_REG_BINIT_RLIST_B4(b1_reflist[4].index) | + VDPU_REG_BINIT_RLIST_B3(b1_reflist[3].index) | + VDPU_REG_BINIT_RLIST_B2(b1_reflist[2].index) | + VDPU_REG_BINIT_RLIST_B1(b1_reflist[1].index) | + VDPU_REG_BINIT_RLIST_B0(b1_reflist[0].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(103)); - reg = VDPU_REG_BINIT_RLIST_B11(b1_reflist[11]) | - VDPU_REG_BINIT_RLIST_B10(b1_reflist[10]) | - VDPU_REG_BINIT_RLIST_B9(b1_reflist[9]) | - VDPU_REG_BINIT_RLIST_B8(b1_reflist[8]) | - VDPU_REG_BINIT_RLIST_B7(b1_reflist[7]) | - VDPU_REG_BINIT_RLIST_B6(b1_reflist[6]); + reg = VDPU_REG_BINIT_RLIST_B11(b1_reflist[11].index) | + VDPU_REG_BINIT_RLIST_B10(b1_reflist[10].index) | + VDPU_REG_BINIT_RLIST_B9(b1_reflist[9].index) | + VDPU_REG_BINIT_RLIST_B8(b1_reflist[8].index) | + VDPU_REG_BINIT_RLIST_B7(b1_reflist[7].index) | + VDPU_REG_BINIT_RLIST_B6(b1_reflist[6].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(104)); - reg = VDPU_REG_BINIT_RLIST_B15(b1_reflist[15]) | - VDPU_REG_BINIT_RLIST_B14(b1_reflist[14]) | - VDPU_REG_BINIT_RLIST_B13(b1_reflist[13]) | - VDPU_REG_BINIT_RLIST_B12(b1_reflist[12]); + reg = VDPU_REG_BINIT_RLIST_B15(b1_reflist[15].index) | + VDPU_REG_BINIT_RLIST_B14(b1_reflist[14].index) | + VDPU_REG_BINIT_RLIST_B13(b1_reflist[13].index) | + VDPU_REG_BINIT_RLIST_B12(b1_reflist[12].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(105)); - reg = VDPU_REG_PINIT_RLIST_F3(p_reflist[3]) | - VDPU_REG_PINIT_RLIST_F2(p_reflist[2]) | - VDPU_REG_PINIT_RLIST_F1(p_reflist[1]) | - VDPU_REG_PINIT_RLIST_F0(p_reflist[0]); + reg = VDPU_REG_PINIT_RLIST_F3(p_reflist[3].index) | + VDPU_REG_PINIT_RLIST_F2(p_reflist[2].index) | + VDPU_REG_PINIT_RLIST_F1(p_reflist[1].index) | + VDPU_REG_PINIT_RLIST_F0(p_reflist[0].index); vdpu_write_relaxed(vpu, reg, VDPU_SWREG(106)); reg = VDPU_REG_REFER_LTERM_E(ctx->h264_dec.dpb_longterm); diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c index 163cf92eafca..fc96501f3bc8 100644 --- a/drivers/staging/media/hantro/rockchip_vpu_hw.c +++ b/drivers/staging/media/hantro/rockchip_vpu_hw.c @@ -545,6 +545,20 @@ const struct hantro_variant rk3399_vpu_variant = { .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) }; +const struct hantro_variant rk3568_vpu_variant = { + .dec_offset = 0x400, + .dec_fmts = rk3399_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), + .codec = HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER | HANTRO_H264_DECODER, + .codec_ops = rk3399_vpu_codec_ops, + .irqs = rockchip_vdpu2_irqs, + .num_irqs = ARRAY_SIZE(rockchip_vdpu2_irqs), + .init = rockchip_vpu_hw_init, + .clk_names = rockchip_vpu_clk_names, + .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) +}; + const struct hantro_variant px30_vpu_variant = { .enc_offset = 0x0, .enc_fmts = rockchip_vpu_enc_fmts, diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.c b/drivers/staging/media/ipu3/ipu3-css-fw.c index 981693eed815..2b659b0ccca1 100644 --- a/drivers/staging/media/ipu3/ipu3-css-fw.c +++ b/drivers/staging/media/ipu3/ipu3-css-fw.c @@ -117,7 +117,9 @@ int imgu_css_fw_init(struct imgu_css *css) unsigned int i, j, binary_nr; int r; - r = request_firmware(&css->fw, IMGU_FW_NAME, css->dev); + r = request_firmware(&css->fw, IMGU_FW_NAME_20161208, css->dev); + if (r == -ENOENT) + r = request_firmware(&css->fw, IMGU_FW_NAME, css->dev); if (r) return r; diff --git a/drivers/staging/media/ipu3/ipu3-css-fw.h b/drivers/staging/media/ipu3/ipu3-css-fw.h index c0bc57fd678a..f9403da75785 100644 --- a/drivers/staging/media/ipu3/ipu3-css-fw.h +++ b/drivers/staging/media/ipu3/ipu3-css-fw.h @@ -6,7 +6,9 @@ /******************* Firmware file definitions *******************/ -#define IMGU_FW_NAME "intel/ipu3-fw.bin" +#define IMGU_FW_NAME "intel/ipu3-fw.bin" +#define IMGU_FW_NAME_20161208 \ + "intel/irci_irci_ecr-master_20161208_0213_20170112_1500.bin" typedef u32 imgu_fw_ptr; diff --git a/drivers/staging/media/ipu3/ipu3-css-params.c b/drivers/staging/media/ipu3/ipu3-css-params.c index d9e3c3785075..76ad802d694e 100644 --- a/drivers/staging/media/ipu3/ipu3-css-params.c +++ b/drivers/staging/media/ipu3/ipu3-css-params.c @@ -2556,6 +2556,15 @@ int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe, /* Enable only for rightmost stripe, disable left */ acc->af.stripes[0].grid_cfg.y_start &= ~IPU3_UAPI_GRID_Y_START_EN; + acc->af.stripes[1].grid_cfg.x_start = + (acc->af.stripes[1].grid_cfg.x_start - + acc->stripe.down_scaled_stripes[1].offset) & + IPU3_UAPI_GRID_START_MASK; + b_w_log2 = acc->af.stripes[1].grid_cfg.block_width_log2; + acc->af.stripes[1].grid_cfg.x_end = + imgu_css_grid_end(acc->af.stripes[1].grid_cfg.x_start, + acc->af.stripes[1].grid_cfg.width, + b_w_log2); } else if (acc->af.config.grid_cfg.x_end <= acc->stripe.bds_out_stripes[0].width - min_overlap) { /* Enable only for leftmost stripe, disable right */ @@ -2627,6 +2636,17 @@ int imgu_css_cfg_acc(struct imgu_css *css, unsigned int pipe, acc->stripe.down_scaled_stripes[1].offset + min_overlap) { /* Enable only for rightmost stripe, disable left */ acc->awb.stripes[0].rgbs_thr_b &= ~IPU3_UAPI_AWB_RGBS_THR_B_EN; + + acc->awb.stripes[1].grid.x_start = + (acc->awb.stripes[1].grid.x_start - + acc->stripe.down_scaled_stripes[1].offset) & + IPU3_UAPI_GRID_START_MASK; + + b_w_log2 = acc->awb.stripes[1].grid.block_width_log2; + acc->awb.stripes[1].grid.x_end = + imgu_css_grid_end(acc->awb.stripes[1].grid.x_start, + acc->awb.stripes[1].grid.width, + b_w_log2); } else if (acc->awb.config.grid.x_end <= acc->stripe.bds_out_stripes[0].width - min_overlap) { /* Enable only for leftmost stripe, disable right */ diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index 0473457b4e64..d1c539cefba8 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -485,6 +485,7 @@ static int imgu_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) pipe = node->pipe; imgu_pipe = &imgu->imgu_pipe[pipe]; + atomic_set(&node->sequence, 0); r = media_pipeline_start(&node->vdev.entity, &imgu_pipe->pipeline); if (r < 0) goto fail_return_bufs; diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c index 8e1e9e46e604..0c453b37f8c4 100644 --- a/drivers/staging/media/ipu3/ipu3.c +++ b/drivers/staging/media/ipu3/ipu3.c @@ -440,6 +440,16 @@ fail_start_streaming: return r; } +static void imgu_video_nodes_exit(struct imgu_device *imgu) +{ + int i; + + for (i = 0; i < IMGU_MAX_PIPE_NUM; i++) + imgu_dummybufs_cleanup(imgu, i); + + imgu_v4l2_unregister(imgu); +} + static int imgu_video_nodes_init(struct imgu_device *imgu) { struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL }; @@ -489,24 +499,11 @@ static int imgu_video_nodes_init(struct imgu_device *imgu) return 0; out_cleanup: - for (j = 0; j < IMGU_MAX_PIPE_NUM; j++) - imgu_dummybufs_cleanup(imgu, j); - - imgu_v4l2_unregister(imgu); + imgu_video_nodes_exit(imgu); return r; } -static void imgu_video_nodes_exit(struct imgu_device *imgu) -{ - int i; - - for (i = 0; i < IMGU_MAX_PIPE_NUM; i++) - imgu_dummybufs_cleanup(imgu, i); - - imgu_v4l2_unregister(imgu); -} - /**************** PCI interface ****************/ static irqreturn_t imgu_isr_threaded(int irq, void *imgu_ptr) diff --git a/drivers/staging/media/rkvdec/TODO b/drivers/staging/media/rkvdec/TODO index e0f0f12f0ac5..2c0779383276 100644 --- a/drivers/staging/media/rkvdec/TODO +++ b/drivers/staging/media/rkvdec/TODO @@ -1,6 +1,6 @@ -* Support for VP9 is planned for this driver. +* Support for HEVC is planned for this driver. - Given the V4L controls for those CODECs will be part of + Given the V4L controls for that CODEC will be part of the uABI, it will be required to have the driver in staging. For this reason, we are keeping this driver in staging for now. diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c index 951e19231da2..2992fb87cf72 100644 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c @@ -97,13 +97,10 @@ struct rkvdec_h264_priv_tbl { u8 err_info[RKV_ERROR_INFO_SIZE]; }; -#define RKVDEC_H264_DPB_SIZE 16 - struct rkvdec_h264_reflists { - u8 p[RKVDEC_H264_DPB_SIZE]; - u8 b0[RKVDEC_H264_DPB_SIZE]; - u8 b1[RKVDEC_H264_DPB_SIZE]; - u8 num_valid; + struct v4l2_h264_reference p[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference b0[V4L2_H264_REF_LIST_LEN]; + struct v4l2_h264_reference b1[V4L2_H264_REF_LIST_LEN]; }; struct rkvdec_h264_run { @@ -112,6 +109,7 @@ struct rkvdec_h264_run { const struct v4l2_ctrl_h264_sps *sps; const struct v4l2_ctrl_h264_pps *pps; const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix; + int ref_buf_idx[V4L2_H264_NUM_DPB_ENTRIES]; }; struct rkvdec_h264_ctx { @@ -661,8 +659,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, WRITE_PPS(0xff, PROFILE_IDC); WRITE_PPS(1, CONSTRAINT_SET3_FLAG); WRITE_PPS(sps->chroma_format_idc, CHROMA_FORMAT_IDC); - WRITE_PPS(sps->bit_depth_luma_minus8 + 8, BIT_DEPTH_LUMA); - WRITE_PPS(sps->bit_depth_chroma_minus8 + 8, BIT_DEPTH_CHROMA); + WRITE_PPS(sps->bit_depth_luma_minus8, BIT_DEPTH_LUMA); + WRITE_PPS(sps->bit_depth_chroma_minus8, BIT_DEPTH_CHROMA); WRITE_PPS(0, QPPRIME_Y_ZERO_TRANSFORM_BYPASS_FLAG); WRITE_PPS(sps->log2_max_frame_num_minus4, LOG2_MAX_FRAME_NUM_MINUS4); WRITE_PPS(sps->max_num_ref_frames, MAX_NUM_REF_FRAMES); @@ -671,8 +669,17 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4); WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO), DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG); - WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.width, 16), PIC_WIDTH_IN_MBS); - WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.height, 16), PIC_HEIGHT_IN_MBS); + + /* + * Use the SPS values since they are already in macroblocks + * dimensions, height can be field height (halved) if + * V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows + * decoding smaller images into larger allocation which can be used + * to implementing SVC spatial layer support. + */ + WRITE_PPS(sps->pic_width_in_mbs_minus1 + 1, PIC_WIDTH_IN_MBS); + WRITE_PPS(sps->pic_height_in_map_units_minus1 + 1, PIC_HEIGHT_IN_MBS); + WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY), FRAME_MBS_ONLY_FLAG); WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD), @@ -725,15 +732,38 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, } } +static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx, + struct rkvdec_h264_run *run) +{ + const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; + u32 i; + + for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { + struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; + const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb; + struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; + int buf_idx = -1; + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) { + buf_idx = vb2_find_timestamp(cap_q, + dpb[i].reference_ts, 0); + if (buf_idx < 0) + pr_debug("No buffer for reference_ts %llu", + dpb[i].reference_ts); + } + + run->ref_buf_idx[i] = buf_idx; + } +} + static void assemble_hw_rps(struct rkvdec_ctx *ctx, + struct v4l2_h264_reflist_builder *builder, struct rkvdec_h264_run *run) { const struct v4l2_ctrl_h264_decode_params *dec_params = run->decode_params; const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; struct rkvdec_h264_ctx *h264_ctx = ctx->priv; - const struct v4l2_ctrl_h264_sps *sps = run->sps; struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; - u32 max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); u32 *hw_rps = priv_tbl->rps; u32 i, j; @@ -751,39 +781,36 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) continue; - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM || - dpb[i].frame_num < dec_params->frame_num) { - p[i] = dpb[i].frame_num; - continue; - } - - p[i] = dpb[i].frame_num - max_frame_num; + p[i] = builder->refs[i].frame_num; } for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { - for (i = 0; i < h264_ctx->reflists.num_valid; i++) { - u8 dpb_valid = 0; - u8 idx = 0; + for (i = 0; i < builder->num_valid; i++) { + struct v4l2_h264_reference *ref; + bool dpb_valid; + bool bottom; switch (j) { case 0: - idx = h264_ctx->reflists.p[i]; + ref = &h264_ctx->reflists.p[i]; break; case 1: - idx = h264_ctx->reflists.b0[i]; + ref = &h264_ctx->reflists.b0[i]; break; case 2: - idx = h264_ctx->reflists.b1[i]; + ref = &h264_ctx->reflists.b1[i]; break; } - if (idx >= ARRAY_SIZE(dec_params->dpb)) + if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb))) continue; - dpb_valid = !!(dpb[idx].flags & - V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); + + dpb_valid = run->ref_buf_idx[ref->index] >= 0; + bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF; set_ps_field(hw_rps, DPB_INFO(i, j), - idx | dpb_valid << 4); + ref->index | dpb_valid << 4); + set_ps_field(hw_rps, BOTTOM_FLAG(i, j), bottom); } } } @@ -859,13 +886,8 @@ get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run, unsigned int dpb_idx) { struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; - const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb; struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q; - int buf_idx = -1; - - if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - buf_idx = vb2_find_timestamp(cap_q, - dpb[dpb_idx].reference_ts, 0); + int buf_idx = run->ref_buf_idx[dpb_idx]; /* * If a DPB entry is unused or invalid, address of current destination @@ -976,10 +998,6 @@ static void config_registers(struct rkvdec_ctx *ctx, rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15); } - /* - * Since support frame mode only - * top_field_order_cnt is the same as bottom_field_order_cnt - */ reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt); writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0); @@ -1021,13 +1039,61 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, return 0; } +static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx, + const struct v4l2_ctrl_h264_sps *sps) +{ + unsigned int width, height; + + /* + * TODO: The hardware supports 10-bit and 4:2:2 profiles, + * but it's currently broken in the driver. + * Reject them for now, until it's fixed. + */ + if (sps->chroma_format_idc > 1) + /* Only 4:0:0 and 4:2:0 are supported */ + return -EINVAL; + if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) + /* Luma and chroma bit depth mismatch */ + return -EINVAL; + if (sps->bit_depth_luma_minus8 != 0) + /* Only 8-bit is supported */ + return -EINVAL; + + width = (sps->pic_width_in_mbs_minus1 + 1) * 16; + height = (sps->pic_height_in_map_units_minus1 + 1) * 16; + + /* + * When frame_mbs_only_flag is not set, this is field height, + * which is half the final height (see (7-18) in the + * specification) + */ + if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) + height *= 2; + + if (width > ctx->coded_fmt.fmt.pix_mp.width || + height > ctx->coded_fmt.fmt.pix_mp.height) + return -EINVAL; + + return 0; +} + static int rkvdec_h264_start(struct rkvdec_ctx *ctx) { struct rkvdec_dev *rkvdec = ctx->dev; struct rkvdec_h264_priv_tbl *priv_tbl; struct rkvdec_h264_ctx *h264_ctx; + struct v4l2_ctrl *ctrl; int ret; + ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, + V4L2_CID_STATELESS_H264_SPS); + if (!ctrl) + return -EINVAL; + + ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); + if (ret) + return ret; + h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL); if (!h264_ctx) return -ENOMEM; @@ -1095,14 +1161,14 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) /* Build the P/B{0,1} ref lists. */ v4l2_h264_init_reflist_builder(&reflist_builder, run.decode_params, run.sps, run.decode_params->dpb); - h264_ctx->reflists.num_valid = reflist_builder.num_valid; v4l2_h264_build_p_ref_list(&reflist_builder, h264_ctx->reflists.p); v4l2_h264_build_b_ref_lists(&reflist_builder, h264_ctx->reflists.b0, h264_ctx->reflists.b1); assemble_hw_scaling_list(ctx, &run); assemble_hw_pps(ctx, &run); - assemble_hw_rps(ctx, &run); + lookup_ref_buf_idx(ctx, &run); + assemble_hw_rps(ctx, &reflist_builder, &run); config_registers(ctx, &run); rkvdec_run_postamble(ctx, &run.base); @@ -1122,9 +1188,18 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) return 0; } +static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) +{ + if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) + return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); + + return 0; +} + const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops = { .adjust_fmt = rkvdec_h264_adjust_fmt, .start = rkvdec_h264_start, .stop = rkvdec_h264_stop, .run = rkvdec_h264_run, + .try_ctrl = rkvdec_h264_try_ctrl, }; diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index c0cf3488f970..7bab7586918c 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -29,23 +29,12 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) { - if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) { - const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps; - /* - * TODO: The hardware supports 10-bit and 4:2:2 profiles, - * but it's currently broken in the driver. - * Reject them for now, until it's fixed. - */ - if (sps->chroma_format_idc > 1) - /* Only 4:0:0 and 4:2:0 are supported */ - return -EINVAL; - if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) - /* Luma and chroma bit depth mismatch */ - return -EINVAL; - if (sps->bit_depth_luma_minus8 != 0) - /* Only 8-bit is supported */ - return -EINVAL; - } + struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); + const struct rkvdec_coded_fmt_desc *desc = ctx->coded_fmt_desc; + + if (desc->ops->try_ctrl) + return desc->ops->try_ctrl(ctx, ctrl); + return 0; } @@ -138,6 +127,7 @@ static const struct rkvdec_coded_fmt_desc rkvdec_coded_fmts[] = { .ops = &rkvdec_h264_fmt_ops, .num_decoded_fmts = ARRAY_SIZE(rkvdec_h264_vp9_decoded_fmts), .decoded_fmts = rkvdec_h264_vp9_decoded_fmts, + .subsystem_flags = VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF, }, { .fourcc = V4L2_PIX_FMT_VP9_FRAME, @@ -268,6 +258,8 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, pix_mp->pixelformat = coded_desc->decoded_fmts[0]; /* Always apply the frmsize constraint of the coded end. */ + pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width); + pix_mp->height = max(pix_mp->height, ctx->coded_fmt.fmt.pix_mp.height); v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height, &coded_desc->frmsize); @@ -394,6 +386,9 @@ static int rkvdec_s_output_fmt(struct file *file, void *priv, cap_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; cap_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + /* Enable format specific queue features */ + vq->subsystem_flags |= desc->subsystem_flags; + return 0; } @@ -1027,12 +1022,6 @@ static int rkvdec_probe(struct platform_device *pdev) if (ret) return ret; - /* - * Bump ACLK to max. possible freq. (500 MHz) to improve performance - * When 4k video playback. - */ - clk_set_rate(rkvdec->clocks[0].clk, 500 * 1000 * 1000); - rkvdec->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rkvdec->regs)) return PTR_ERR(rkvdec->regs); diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h index 2f4ea1786b93..633335ebb9c4 100644 --- a/drivers/staging/media/rkvdec/rkvdec.h +++ b/drivers/staging/media/rkvdec/rkvdec.h @@ -72,6 +72,7 @@ struct rkvdec_coded_fmt_ops { void (*done)(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *src_buf, struct vb2_v4l2_buffer *dst_buf, enum vb2_buffer_state result); + int (*try_ctrl)(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl); }; struct rkvdec_coded_fmt_desc { @@ -81,6 +82,7 @@ struct rkvdec_coded_fmt_desc { const struct rkvdec_coded_fmt_ops *ops; unsigned int num_decoded_fmts; const u32 *decoded_fmts; + u32 subsystem_flags; }; struct rkvdec_dev { diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index d1f43f465c22..8e184aa4c252 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -491,6 +491,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, struct v4l2_pix_format *pix) { const struct tegra_video_format *fmtinfo; + static struct lock_class_key key; struct v4l2_subdev *subdev; struct v4l2_subdev_format fmt; struct v4l2_subdev_state *sd_state; @@ -507,7 +508,12 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, if (!subdev) return -ENODEV; - sd_state = v4l2_subdev_alloc_state(subdev); + /* + * FIXME: Drop this call, drivers are not supposed to use + * __v4l2_subdev_state_alloc(). + */ + sd_state = __v4l2_subdev_state_alloc(subdev, "tegra:state->lock", + &key); if (IS_ERR(sd_state)) return PTR_ERR(sd_state); /* @@ -558,7 +564,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, v4l2_fill_pix_format(pix, &fmt.format); tegra_channel_fmt_align(chan, pix, fmtinfo->bpp); - v4l2_subdev_free_state(sd_state); + __v4l2_subdev_state_free(sd_state); return 0; } |