mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-31 04:01:48 -04:00
media fixes for v4.20-rc8
-----BEGIN PGP SIGNATURE-----
iQIcBAABAgAGBQJcG4K3AAoJEAhfPr2O5OEV7r4P/iRRCZ1aBbImMW+mPD5fhmhj
FmQod3njuaVQzjBizPexEvmQ6Qz4vSr1JnpiKTPaYOlooOtT4TNAw7Hx/6SdCLkl
a1+T0ads5FGQGMKQ/xQ+/dnp8UDdhllKYR+aVilfHpnZcltLtydtnhqYDZi98PRQ
2XYPCX5wRIDoJ5HKb1KygpGt4wxU1Re08X0ZDokPzN5DCQ3HGzs/SPOA8WPIo4kc
rxT3QivhsfSVPX+Bu7UrurskvZ4cOvii1sXtxMWvsanDoDfY+XUPvSBL9syU6hzF
KFdbIJNDQDy5m87crrZmOwHygj2nzJubpbdE3m5ulDRUvc1f4FYDeqdn5GJZ8fzQ
32+NFCboupZaJdfKWl1DtM8E6vlqiEa5/Xnkw5CEQ0mt6VmVob+YlmH8iLyxDZ7L
c49r/k4UqbrsP/sgwi7mAbwFrNmve5ZPVBJKgcu+W1x3U8j+r3MBb2G+rFT0Mimx
Z6IKS0KuOXIoOS71ADL+6Z6KmczvZGgMVpSaSl1IAZw/xAY8JCYqcyPCvtBYM3N6
6iRC4uET9KxbIdyPz0cbyLvdhdTTiBMQFEHzYBH0AwFJhWYFqilmetNu5MjLo6hb
0BHM5FOhpyxDmL1bKNvFNb8T8SbpDraWvbTso2XFhAl1kTWpA7yRZlSqcFBU7M22
wgc/mwBUJoGzZBHizyp6
=G3om
-----END PGP SIGNATURE-----
Merge tag 'media/v4.20-6' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
"First set of media patches contains:
- Three new platform drivers: aspeed-video seco-sed and sun5i-csi;
- One new sensor driver: imx214;
- Support for Xbox DVD Movie Playback kit remote controller;
- Removal of the legacy friio driver. The functionalities were ported
to another driver, already merged;
- New staging driver: Rockchip VPU;
- Added license text or SPDX tags to all media documentation files;
- Usual set of cleanup, fixes and enhancements"
* tag 'media/v4.20-6' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (263 commits)
media: cx23885: only reset DMA on problematic CPUs
media: ddbridge: Move asm includes after linux ones
media: drxk_hard: check if parameter is not NULL
media: docs: fix some GPL licensing ambiguity at the text
media: platform: Add Aspeed Video Engine driver
media: dt-bindings: media: Add Aspeed Video Engine binding documentation
media: vimc: fix start stream when link is disabled
media: v4l2-device: Link subdevices to their parent devices if available
media: siano: Use kmemdup instead of duplicating its function
media: rockchip vpu: remove some unused vars
media: cedrus: don't initialize pointers with zero
media: cetrus: return an error if alloc fails
media: cedrus: Add device-tree compatible and variant for A64 support
media: cedrus: Add device-tree compatible and variant for H5 support
media: dt-bindings: media: cedrus: Add compatibles for the A64 and H5
media: video-i2c: check if chip struct has set_power function
media: video-i2c: support runtime PM
media: staging: media: imx: Use of_node_name_eq for node name comparisons
media: v4l2-subdev: document controls need _FL_HAS_DEVNODE
media: vivid: Improve timestamping
...
This commit is contained in:
commit
5813540b58
780 changed files with 17553 additions and 3643 deletions
|
|
@ -455,7 +455,7 @@ int cec_thread_func(void *_adap)
|
|||
(adap->needs_hpd &&
|
||||
(!adap->is_configured && !adap->is_configuring)) ||
|
||||
kthread_should_stop() ||
|
||||
(!adap->transmitting &&
|
||||
(!adap->transmit_in_progress &&
|
||||
!list_empty(&adap->transmit_queue)),
|
||||
msecs_to_jiffies(CEC_XFER_TIMEOUT_MS));
|
||||
timeout = err == 0;
|
||||
|
|
@ -463,7 +463,7 @@ int cec_thread_func(void *_adap)
|
|||
/* Otherwise we just wait for something to happen. */
|
||||
wait_event_interruptible(adap->kthread_waitq,
|
||||
kthread_should_stop() ||
|
||||
(!adap->transmitting &&
|
||||
(!adap->transmit_in_progress &&
|
||||
!list_empty(&adap->transmit_queue)));
|
||||
}
|
||||
|
||||
|
|
@ -488,6 +488,7 @@ int cec_thread_func(void *_adap)
|
|||
pr_warn("cec-%s: message %*ph timed out\n", adap->name,
|
||||
adap->transmitting->msg.len,
|
||||
adap->transmitting->msg.msg);
|
||||
adap->transmit_in_progress = false;
|
||||
adap->tx_timeouts++;
|
||||
/* Just give up on this. */
|
||||
cec_data_cancel(adap->transmitting,
|
||||
|
|
@ -499,7 +500,7 @@ int cec_thread_func(void *_adap)
|
|||
* If we are still transmitting, or there is nothing new to
|
||||
* transmit, then just continue waiting.
|
||||
*/
|
||||
if (adap->transmitting || list_empty(&adap->transmit_queue))
|
||||
if (adap->transmit_in_progress || list_empty(&adap->transmit_queue))
|
||||
goto unlock;
|
||||
|
||||
/* Get a new message to transmit */
|
||||
|
|
@ -545,6 +546,8 @@ int cec_thread_func(void *_adap)
|
|||
if (adap->ops->adap_transmit(adap, data->attempts,
|
||||
signal_free_time, &data->msg))
|
||||
cec_data_cancel(data, CEC_TX_STATUS_ABORTED);
|
||||
else
|
||||
adap->transmit_in_progress = true;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&adap->lock);
|
||||
|
|
@ -575,14 +578,17 @@ void cec_transmit_done_ts(struct cec_adapter *adap, u8 status,
|
|||
data = adap->transmitting;
|
||||
if (!data) {
|
||||
/*
|
||||
* This can happen if a transmit was issued and the cable is
|
||||
* This might happen if a transmit was issued and the cable is
|
||||
* unplugged while the transmit is ongoing. Ignore this
|
||||
* transmit in that case.
|
||||
*/
|
||||
dprintk(1, "%s was called without an ongoing transmit!\n",
|
||||
__func__);
|
||||
goto unlock;
|
||||
if (!adap->transmit_in_progress)
|
||||
dprintk(1, "%s was called without an ongoing transmit!\n",
|
||||
__func__);
|
||||
adap->transmit_in_progress = false;
|
||||
goto wake_thread;
|
||||
}
|
||||
adap->transmit_in_progress = false;
|
||||
|
||||
msg = &data->msg;
|
||||
|
||||
|
|
@ -648,7 +654,6 @@ wake_thread:
|
|||
* for transmitting or to retry the current message.
|
||||
*/
|
||||
wake_up_interruptible(&adap->kthread_waitq);
|
||||
unlock:
|
||||
mutex_unlock(&adap->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cec_transmit_done_ts);
|
||||
|
|
@ -1432,6 +1437,13 @@ configured:
|
|||
las->log_addr[i],
|
||||
cec_phys_addr_exp(adap->phys_addr));
|
||||
cec_transmit_msg_fh(adap, &msg, NULL, false);
|
||||
|
||||
/* Report Vendor ID */
|
||||
if (adap->log_addrs.vendor_id != CEC_VENDOR_ID_NONE) {
|
||||
cec_msg_device_vendor_id(&msg,
|
||||
adap->log_addrs.vendor_id);
|
||||
cec_transmit_msg_fh(adap, &msg, NULL, false);
|
||||
}
|
||||
}
|
||||
adap->kthread_config = NULL;
|
||||
complete(&adap->config_completion);
|
||||
|
|
@ -1496,8 +1508,11 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
|
|||
if (adap->monitor_all_cnt)
|
||||
WARN_ON(call_op(adap, adap_monitor_all_enable, false));
|
||||
mutex_lock(&adap->devnode.lock);
|
||||
if (adap->needs_hpd || list_empty(&adap->devnode.fhs))
|
||||
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;
|
||||
|
|
@ -1505,6 +1520,7 @@ void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block)
|
|||
|
||||
mutex_lock(&adap->devnode.lock);
|
||||
adap->last_initiator = 0xff;
|
||||
adap->transmit_in_progress = false;
|
||||
|
||||
if ((adap->needs_hpd || list_empty(&adap->devnode.fhs)) &&
|
||||
adap->ops->adap_enable(adap, true)) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@ int cec_debug;
|
|||
module_param_named(debug, cec_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "debug level (0-2)");
|
||||
|
||||
static bool debug_phys_addr;
|
||||
module_param(debug_phys_addr, bool, 0644);
|
||||
MODULE_PARM_DESC(debug_phys_addr, "add CEC_CAP_PHYS_ADDR if set");
|
||||
|
||||
static dev_t cec_dev_t;
|
||||
|
||||
/* Active devices */
|
||||
|
|
@ -270,6 +274,8 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
|||
adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0;
|
||||
adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE;
|
||||
adap->capabilities = caps;
|
||||
if (debug_phys_addr)
|
||||
adap->capabilities |= CEC_CAP_PHYS_ADDR;
|
||||
adap->needs_hpd = caps & CEC_CAP_NEEDS_HPD;
|
||||
adap->available_log_addrs = available_las;
|
||||
adap->sequence = 0;
|
||||
|
|
|
|||
|
|
@ -601,8 +601,9 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
|
|||
break;
|
||||
/* Was the message ACKed? */
|
||||
ack = cec_msg_is_broadcast(&pin->tx_msg) ? v : !v;
|
||||
if (!ack && !pin->tx_ignore_nack_until_eom &&
|
||||
pin->tx_bit / 10 < pin->tx_msg.len && !pin->tx_post_eom) {
|
||||
if (!ack && (!pin->tx_ignore_nack_until_eom ||
|
||||
pin->tx_bit / 10 == pin->tx_msg.len - 1) &&
|
||||
!pin->tx_post_eom) {
|
||||
/*
|
||||
* Note: the CEC spec is ambiguous regarding
|
||||
* what action to take when a NACK appears
|
||||
|
|
|
|||
|
|
@ -1769,7 +1769,7 @@ typedef struct { u16 __; u8 _; } __packed x24;
|
|||
unsigned s; \
|
||||
\
|
||||
for (s = 0; s < len; s++) { \
|
||||
u8 chr = font8x16[text[s] * 16 + line]; \
|
||||
u8 chr = font8x16[(u8)text[s] * 16 + line]; \
|
||||
\
|
||||
if (hdiv == 2 && tpg->hflip) { \
|
||||
pos[3] = (chr & (0x01 << 6) ? fg : bg); \
|
||||
|
|
|
|||
|
|
@ -679,11 +679,9 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
|
|||
* are not in use and can be freed.
|
||||
*/
|
||||
mutex_lock(&q->mmap_lock);
|
||||
if (q->memory == VB2_MEMORY_MMAP && __buffers_in_use(q)) {
|
||||
mutex_unlock(&q->mmap_lock);
|
||||
dprintk(1, "memory in use, cannot free\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
if (debug && q->memory == VB2_MEMORY_MMAP &&
|
||||
__buffers_in_use(q))
|
||||
dprintk(1, "memory in use, orphaning buffers\n");
|
||||
|
||||
/*
|
||||
* Call queue_cancel to clean up any buffers in the
|
||||
|
|
@ -812,6 +810,9 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
|
|||
memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
|
||||
q->memory = memory;
|
||||
q->waiting_for_buffers = !q->is_output;
|
||||
} else if (q->memory != memory) {
|
||||
dprintk(1, "memory model mismatch\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
|
||||
|
|
@ -2143,9 +2144,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
|
|||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&q->mmap_lock);
|
||||
|
||||
if (vb2_fileio_is_active(q)) {
|
||||
dprintk(1, "mmap: file io in progress\n");
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2153,7 +2158,7 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
|
|||
*/
|
||||
ret = __find_plane_by_offset(q, off, &buffer, &plane);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto unlock;
|
||||
|
||||
vb = q->bufs[buffer];
|
||||
|
||||
|
|
@ -2166,11 +2171,13 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
|
|||
if (length < (vma->vm_end - vma->vm_start)) {
|
||||
dprintk(1,
|
||||
"MMAP invalid, as it would overflow buffer length\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
mutex_lock(&q->mmap_lock);
|
||||
ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&q->mmap_lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -158,7 +158,6 @@ static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
|
|||
return;
|
||||
|
||||
check_once = true;
|
||||
WARN_ON(1);
|
||||
|
||||
pr_warn("use of bytesused == 0 is deprecated and will be removed in the future,\n");
|
||||
if (vb->vb2_queue->allow_zero_bytesused)
|
||||
|
|
@ -627,7 +626,7 @@ EXPORT_SYMBOL(vb2_querybuf);
|
|||
|
||||
static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
|
||||
{
|
||||
*caps = 0;
|
||||
*caps = V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
|
||||
if (q->io_modes & VB2_MMAP)
|
||||
*caps |= V4L2_BUF_CAP_SUPPORTS_MMAP;
|
||||
if (q->io_modes & VB2_USERPTR)
|
||||
|
|
|
|||
|
|
@ -917,6 +917,9 @@ static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
|
|||
"DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
|
||||
fe->dvb->num, fe->id);
|
||||
|
||||
dprintk("frequency interval: tuner: %u...%u, frontend: %u...%u",
|
||||
tuner_min, tuner_max, frontend_min, frontend_max);
|
||||
|
||||
/* If the standard is for satellite, convert frequencies to kHz */
|
||||
switch (c->delivery_system) {
|
||||
case SYS_DVBS:
|
||||
|
|
@ -2587,8 +2590,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
|
|||
u8 last = 1;
|
||||
|
||||
if (dvb_frontend_debug)
|
||||
dprintk("%s switch command: 0x%04lx\n",
|
||||
__func__, swcmd);
|
||||
dprintk("switch command: 0x%04lx\n",
|
||||
swcmd);
|
||||
nexttime = ktime_get_boottime();
|
||||
if (dvb_frontend_debug)
|
||||
tv[0] = nexttime;
|
||||
|
|
@ -2611,8 +2614,8 @@ static int dvb_frontend_handle_ioctl(struct file *file,
|
|||
dvb_frontend_sleep_until(&nexttime, 8000);
|
||||
}
|
||||
if (dvb_frontend_debug) {
|
||||
dprintk("%s(%d): switch delay (should be 32k followed by all 8k)\n",
|
||||
__func__, fe->dvb->num);
|
||||
dprintk("(adapter %d): switch delay (should be 32k followed by all 8k)\n",
|
||||
fe->dvb->num);
|
||||
for (i = 1; i < 10; i++)
|
||||
pr_info("%d: %d\n", i,
|
||||
(int)ktime_us_delta(tv[i], tv[i - 1]));
|
||||
|
|
|
|||
|
|
@ -1137,16 +1137,8 @@ static int af9033_probe(struct i2c_client *client,
|
|||
buf[4], buf[5], buf[6], buf[7]);
|
||||
|
||||
/* Sleep as chip seems to be partly active by default */
|
||||
switch (dev->cfg.tuner) {
|
||||
case AF9033_TUNER_IT9135_38:
|
||||
case AF9033_TUNER_IT9135_51:
|
||||
case AF9033_TUNER_IT9135_52:
|
||||
case AF9033_TUNER_IT9135_60:
|
||||
case AF9033_TUNER_IT9135_61:
|
||||
case AF9033_TUNER_IT9135_62:
|
||||
/* IT9135 did not like to sleep at that early */
|
||||
break;
|
||||
default:
|
||||
/* IT9135 did not like to sleep at that early */
|
||||
if (dev->is_af9035) {
|
||||
ret = regmap_write(dev->regmap, 0x80004c, 0x01);
|
||||
if (ret)
|
||||
goto err_regmap_exit;
|
||||
|
|
|
|||
|
|
@ -1072,45 +1072,45 @@ static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg)
|
|||
void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dib0090_state *state = fe->tuner_priv;
|
||||
u16 *bb_ramp = (u16 *)&bb_ramp_pwm_normal; /* default baseband config */
|
||||
u16 *rf_ramp = NULL;
|
||||
const u16 *bb_ramp = bb_ramp_pwm_normal; /* default baseband config */
|
||||
const u16 *rf_ramp = NULL;
|
||||
u8 en_pwm_rf_mux = 1;
|
||||
|
||||
/* reset the AGC */
|
||||
if (state->config->use_pwm_agc) {
|
||||
if (state->current_band == BAND_CBAND) {
|
||||
if (state->identity.in_soc) {
|
||||
bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
|
||||
bb_ramp = bb_ramp_pwm_normal_socs;
|
||||
if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
|
||||
rf_ramp = (u16 *)&rf_ramp_pwm_cband_8090;
|
||||
rf_ramp = rf_ramp_pwm_cband_8090;
|
||||
else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1) {
|
||||
if (state->config->is_dib7090e) {
|
||||
if (state->rf_ramp == NULL)
|
||||
rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
|
||||
rf_ramp = rf_ramp_pwm_cband_7090e_sensitivity;
|
||||
else
|
||||
rf_ramp = (u16 *)state->rf_ramp;
|
||||
rf_ramp = state->rf_ramp;
|
||||
} else
|
||||
rf_ramp = (u16 *)&rf_ramp_pwm_cband_7090p;
|
||||
rf_ramp = rf_ramp_pwm_cband_7090p;
|
||||
}
|
||||
} else
|
||||
rf_ramp = (u16 *)&rf_ramp_pwm_cband;
|
||||
rf_ramp = rf_ramp_pwm_cband;
|
||||
} else
|
||||
|
||||
if (state->current_band == BAND_VHF) {
|
||||
if (state->identity.in_soc) {
|
||||
bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
|
||||
bb_ramp = bb_ramp_pwm_normal_socs;
|
||||
/* rf_ramp = &rf_ramp_pwm_vhf_socs; */ /* TODO */
|
||||
} else
|
||||
rf_ramp = (u16 *)&rf_ramp_pwm_vhf;
|
||||
rf_ramp = rf_ramp_pwm_vhf;
|
||||
} else if (state->current_band == BAND_UHF) {
|
||||
if (state->identity.in_soc) {
|
||||
bb_ramp = (u16 *)&bb_ramp_pwm_normal_socs;
|
||||
bb_ramp = bb_ramp_pwm_normal_socs;
|
||||
if (state->identity.version == SOC_8090_P1G_11R1 || state->identity.version == SOC_8090_P1G_21R1)
|
||||
rf_ramp = (u16 *)&rf_ramp_pwm_uhf_8090;
|
||||
rf_ramp = rf_ramp_pwm_uhf_8090;
|
||||
else if (state->identity.version == SOC_7090_P1G_11R1 || state->identity.version == SOC_7090_P1G_21R1)
|
||||
rf_ramp = (u16 *)&rf_ramp_pwm_uhf_7090;
|
||||
rf_ramp = rf_ramp_pwm_uhf_7090;
|
||||
} else
|
||||
rf_ramp = (u16 *)&rf_ramp_pwm_uhf;
|
||||
rf_ramp = rf_ramp_pwm_uhf;
|
||||
}
|
||||
if (rf_ramp)
|
||||
dib0090_set_rframp_pwm(state, rf_ramp);
|
||||
|
|
@ -1416,9 +1416,9 @@ int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity)
|
|||
}
|
||||
|
||||
if (cfg_sensitivity)
|
||||
state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_sensitivity;
|
||||
state->rf_ramp = rf_ramp_pwm_cband_7090e_sensitivity;
|
||||
else
|
||||
state->rf_ramp = (const u16 *)&rf_ramp_pwm_cband_7090e_aci;
|
||||
state->rf_ramp = rf_ramp_pwm_cband_7090e_aci;
|
||||
dib0090_pwm_gain_reset(fe);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1871,10 +1871,13 @@ static u32 dib7000p_get_time_us(struct dvb_frontend *demod)
|
|||
break;
|
||||
}
|
||||
|
||||
interleaving = interleaving;
|
||||
|
||||
denom = bits_per_symbol * rate_num * fft_div * 384;
|
||||
|
||||
/*
|
||||
* FIXME: check if the math makes sense. If so, fill the
|
||||
* interleaving var.
|
||||
*/
|
||||
|
||||
/* If calculus gets wrong, wait for 1s for the next stats */
|
||||
if (!denom)
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1474,9 +1474,11 @@ static int scu_command(struct drxk_state *state,
|
|||
|
||||
/* assume that the command register is ready
|
||||
since it is checked afterwards */
|
||||
for (ii = parameter_len - 1; ii >= 0; ii -= 1) {
|
||||
buffer[cnt++] = (parameter[ii] & 0xFF);
|
||||
buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
|
||||
if (parameter) {
|
||||
for (ii = parameter_len - 1; ii >= 0; ii -= 1) {
|
||||
buffer[cnt++] = (parameter[ii] & 0xFF);
|
||||
buffer[cnt++] = ((parameter[ii] >> 8) & 0xFF);
|
||||
}
|
||||
}
|
||||
buffer[cnt++] = (cmd & 0xFF);
|
||||
buffer[cnt++] = ((cmd >> 8) & 0xFF);
|
||||
|
|
|
|||
|
|
@ -2205,15 +2205,13 @@ static int lgdt3306a_probe(struct i2c_client *client,
|
|||
struct dvb_frontend *fe;
|
||||
int ret;
|
||||
|
||||
config = kzalloc(sizeof(struct lgdt3306a_config), GFP_KERNEL);
|
||||
config = kmemdup(client->dev.platform_data,
|
||||
sizeof(struct lgdt3306a_config), GFP_KERNEL);
|
||||
if (config == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(config, client->dev.platform_data,
|
||||
sizeof(struct lgdt3306a_config));
|
||||
|
||||
config->i2c_addr = client->addr;
|
||||
fe = lgdt3306a_attach(config, client->adapter);
|
||||
if (fe == NULL) {
|
||||
|
|
|
|||
|
|
@ -781,7 +781,7 @@ static int set_input(struct dvb_frontend *fe, int input)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct dvb_frontend_ops mxl_ops = {
|
||||
static const struct dvb_frontend_ops mxl_ops = {
|
||||
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
|
||||
.info = {
|
||||
.name = "MaxLinear MxL5xx DVB-S/S2 tuner-demodulator",
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
|
|
|
|||
|
|
@ -968,7 +968,8 @@ static int get_ca_object_length(struct avc_response_frame *r)
|
|||
return r->operand[7];
|
||||
}
|
||||
|
||||
int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
|
||||
int avc_ca_app_info(struct firedtv *fdtv, unsigned char *app_info,
|
||||
unsigned int *len)
|
||||
{
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
|
|
@ -1009,7 +1010,8 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
|
||||
int avc_ca_info(struct firedtv *fdtv, unsigned char *app_info,
|
||||
unsigned int *len)
|
||||
{
|
||||
struct avc_command_frame *c = (void *)fdtv->avc_data;
|
||||
struct avc_response_frame *r = (void *)fdtv->avc_data;
|
||||
|
|
|
|||
|
|
@ -124,8 +124,10 @@ int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
|
|||
struct dvb_diseqc_master_cmd *diseqcmd);
|
||||
void avc_remote_ctrl_work(struct work_struct *work);
|
||||
int avc_register_remote_control(struct firedtv *fdtv);
|
||||
int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
|
||||
int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
|
||||
int avc_ca_app_info(struct firedtv *fdtv, unsigned char *app_info,
|
||||
unsigned int *len);
|
||||
int avc_ca_info(struct firedtv *fdtv, unsigned char *app_info,
|
||||
unsigned int *len);
|
||||
int avc_ca_reset(struct firedtv *fdtv);
|
||||
int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length);
|
||||
int avc_ca_get_time_date(struct firedtv *fdtv, int *interval);
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ config VIDEO_TDA1997X
|
|||
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
|
||||
depends on SND_SOC
|
||||
select SND_PCM
|
||||
select HDMI
|
||||
---help---
|
||||
V4L2 subdevice driver for the NXP TDA1997x HDMI receivers.
|
||||
|
||||
|
|
@ -595,6 +596,18 @@ config VIDEO_APTINA_PLL
|
|||
config VIDEO_SMIAPP_PLL
|
||||
tristate
|
||||
|
||||
config VIDEO_IMX214
|
||||
tristate "Sony IMX214 sensor support"
|
||||
depends on GPIOLIB && I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
depends on V4L2_FWNODE
|
||||
help
|
||||
This is a Video4Linux2 sensor driver for the Sony
|
||||
IMX214 camera.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called imx214.
|
||||
|
||||
config VIDEO_IMX258
|
||||
tristate "Sony IMX258 sensor support"
|
||||
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
|
||||
|
|
@ -610,6 +623,7 @@ config VIDEO_IMX274
|
|||
tristate "Sony IMX274 sensor support"
|
||||
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
select REGMAP_I2C
|
||||
---help---
|
||||
This is a V4L2 sensor driver for the Sony IMX274
|
||||
CMOS image sensor.
|
||||
|
|
@ -846,6 +860,7 @@ config VIDEO_MT9M032
|
|||
config VIDEO_MT9M111
|
||||
tristate "mt9m111, mt9m112 and mt9m131 support"
|
||||
depends on I2C && VIDEO_V4L2
|
||||
select V4L2_FWNODE
|
||||
help
|
||||
This driver supports MT9M111, MT9M112 and MT9M131 cameras from
|
||||
Micron/Aptina
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ obj-$(CONFIG_VIDEO_I2C) += video-i2c.o
|
|||
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
|
||||
obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
|
||||
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
|
||||
obj-$(CONFIG_VIDEO_IMX214) += imx214.o
|
||||
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
|
||||
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
|
||||
obj-$(CONFIG_VIDEO_IMX319) += imx319.o
|
||||
|
|
|
|||
|
|
@ -578,7 +578,7 @@ static const struct v4l2_dv_timings_cap ad9389b_timings_cap = {
|
|||
.type = V4L2_DV_BT_656_1120,
|
||||
/* keep this initialization for compatibility with GCC < 4.4.6 */
|
||||
.reserved = { 0 },
|
||||
V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
|
||||
V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
|
||||
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
|
||||
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
|
||||
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
|
||||
|
|
|
|||
|
|
@ -180,6 +180,9 @@
|
|||
|
||||
#define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00)
|
||||
|
||||
/* Initial number of frames to skip to avoid possible garbage */
|
||||
#define ADV7180_NUM_OF_SKIP_FRAMES 2
|
||||
|
||||
struct adv7180_state;
|
||||
|
||||
#define ADV7180_FLAG_RESET_POWERED BIT(0)
|
||||
|
|
@ -769,6 +772,13 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames)
|
||||
{
|
||||
*frames = ADV7180_NUM_OF_SKIP_FRAMES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
|
|
@ -849,10 +859,15 @@ static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
|
|||
.get_fmt = adv7180_get_pad_format,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = {
|
||||
.g_skip_frames = adv7180_get_skip_frames,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops adv7180_ops = {
|
||||
.core = &adv7180_core_ops,
|
||||
.video = &adv7180_video_ops,
|
||||
.pad = &adv7180_pad_ops,
|
||||
.sensor = &adv7180_sensor_ops,
|
||||
};
|
||||
|
||||
static irqreturn_t adv7180_irq(int irq, void *devid)
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ static const struct v4l2_dv_timings_cap adv7511_timings_cap = {
|
|||
.type = V4L2_DV_BT_656_1120,
|
||||
/* keep this initialization for compatibility with GCC < 4.4.6 */
|
||||
.reserved = { 0 },
|
||||
V4L2_INIT_BT_TIMINGS(0, ADV7511_MAX_WIDTH, 0, ADV7511_MAX_HEIGHT,
|
||||
V4L2_INIT_BT_TIMINGS(640, ADV7511_MAX_WIDTH, 350, ADV7511_MAX_HEIGHT,
|
||||
ADV7511_MIN_PIXELCLOCK, ADV7511_MAX_PIXELCLOCK,
|
||||
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
|
||||
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/videodev2.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <media/i2c/adv7604.h>
|
||||
#include <media/cec.h>
|
||||
|
|
@ -114,6 +115,11 @@ struct adv76xx_chip_info {
|
|||
unsigned int fmt_change_digital_mask;
|
||||
unsigned int cp_csc;
|
||||
|
||||
unsigned int cec_irq_status;
|
||||
unsigned int cec_rx_enable;
|
||||
unsigned int cec_rx_enable_mask;
|
||||
bool cec_irq_swap;
|
||||
|
||||
const struct adv76xx_format_info *formats;
|
||||
unsigned int nformats;
|
||||
|
||||
|
|
@ -766,7 +772,7 @@ static const struct v4l2_dv_timings_cap adv7604_timings_cap_analog = {
|
|||
.type = V4L2_DV_BT_656_1120,
|
||||
/* keep this initialization for compatibility with GCC < 4.4.6 */
|
||||
.reserved = { 0 },
|
||||
V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
|
||||
V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
|
||||
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
|
||||
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
|
||||
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
|
||||
|
|
@ -777,7 +783,7 @@ static const struct v4l2_dv_timings_cap adv76xx_timings_cap_digital = {
|
|||
.type = V4L2_DV_BT_656_1120,
|
||||
/* keep this initialization for compatibility with GCC < 4.4.6 */
|
||||
.reserved = { 0 },
|
||||
V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000,
|
||||
V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 225000000,
|
||||
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
|
||||
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
|
||||
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
|
||||
|
|
@ -2003,10 +2009,11 @@ static void adv76xx_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status)
|
|||
static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled)
|
||||
{
|
||||
struct adv76xx_state *state = to_state(sd);
|
||||
const struct adv76xx_chip_info *info = state->info;
|
||||
u8 cec_irq;
|
||||
|
||||
/* cec controller */
|
||||
cec_irq = io_read(sd, 0x4d) & 0x0f;
|
||||
cec_irq = io_read(sd, info->cec_irq_status) & 0x0f;
|
||||
if (!cec_irq)
|
||||
return;
|
||||
|
||||
|
|
@ -2024,15 +2031,21 @@ static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled)
|
|||
|
||||
for (i = 0; i < msg.len; i++)
|
||||
msg.msg[i] = cec_read(sd, i + 0x15);
|
||||
cec_write(sd, 0x26, 0x01); /* re-enable rx */
|
||||
cec_write(sd, info->cec_rx_enable,
|
||||
info->cec_rx_enable_mask); /* re-enable rx */
|
||||
cec_received_msg(state->cec_adap, &msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* note: the bit order is swapped between 0x4d and 0x4e */
|
||||
cec_irq = ((cec_irq & 0x08) >> 3) | ((cec_irq & 0x04) >> 1) |
|
||||
((cec_irq & 0x02) << 1) | ((cec_irq & 0x01) << 3);
|
||||
io_write(sd, 0x4e, cec_irq);
|
||||
if (info->cec_irq_swap) {
|
||||
/*
|
||||
* Note: the bit order is swapped between 0x4d and 0x4e
|
||||
* on adv7604
|
||||
*/
|
||||
cec_irq = ((cec_irq & 0x08) >> 3) | ((cec_irq & 0x04) >> 1) |
|
||||
((cec_irq & 0x02) << 1) | ((cec_irq & 0x01) << 3);
|
||||
}
|
||||
io_write(sd, info->cec_irq_status + 1, cec_irq);
|
||||
|
||||
if (handled)
|
||||
*handled = true;
|
||||
|
|
@ -2041,6 +2054,7 @@ static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled)
|
|||
static int adv76xx_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
{
|
||||
struct adv76xx_state *state = cec_get_drvdata(adap);
|
||||
const struct adv76xx_chip_info *info = state->info;
|
||||
struct v4l2_subdev *sd = &state->sd;
|
||||
|
||||
if (!state->cec_enabled_adap && enable) {
|
||||
|
|
@ -2052,11 +2066,11 @@ static int adv76xx_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
|||
/* tx: arbitration lost */
|
||||
/* tx: retry timeout */
|
||||
/* rx: ready */
|
||||
io_write_clr_set(sd, 0x50, 0x0f, 0x0f);
|
||||
cec_write(sd, 0x26, 0x01); /* enable rx */
|
||||
io_write_clr_set(sd, info->cec_irq_status + 3, 0x0f, 0x0f);
|
||||
cec_write(sd, info->cec_rx_enable, info->cec_rx_enable_mask);
|
||||
} else if (state->cec_enabled_adap && !enable) {
|
||||
/* disable cec interrupts */
|
||||
io_write_clr_set(sd, 0x50, 0x0f, 0x00);
|
||||
io_write_clr_set(sd, info->cec_irq_status + 3, 0x0f, 0x00);
|
||||
/* disable address mask 1-3 */
|
||||
cec_write_clr_set(sd, 0x27, 0x70, 0x00);
|
||||
/* power down cec section */
|
||||
|
|
@ -2221,6 +2235,16 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t adv76xx_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct adv76xx_state *state = dev_id;
|
||||
bool handled = false;
|
||||
|
||||
adv76xx_isr(&state->sd, 0, &handled);
|
||||
|
||||
return handled ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
|
||||
{
|
||||
struct adv76xx_state *state = to_state(sd);
|
||||
|
|
@ -2960,6 +2984,10 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = {
|
|||
.cable_det_mask = 0x1e,
|
||||
.fmt_change_digital_mask = 0xc1,
|
||||
.cp_csc = 0xfc,
|
||||
.cec_irq_status = 0x4d,
|
||||
.cec_rx_enable = 0x26,
|
||||
.cec_rx_enable_mask = 0x01,
|
||||
.cec_irq_swap = true,
|
||||
.formats = adv7604_formats,
|
||||
.nformats = ARRAY_SIZE(adv7604_formats),
|
||||
.set_termination = adv7604_set_termination,
|
||||
|
|
@ -3006,6 +3034,9 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = {
|
|||
.cable_det_mask = 0x01,
|
||||
.fmt_change_digital_mask = 0x03,
|
||||
.cp_csc = 0xf4,
|
||||
.cec_irq_status = 0x93,
|
||||
.cec_rx_enable = 0x2c,
|
||||
.cec_rx_enable_mask = 0x02,
|
||||
.formats = adv7611_formats,
|
||||
.nformats = ARRAY_SIZE(adv7611_formats),
|
||||
.set_termination = adv7611_set_termination,
|
||||
|
|
@ -3047,6 +3078,9 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = {
|
|||
.cable_det_mask = 0x01,
|
||||
.fmt_change_digital_mask = 0x03,
|
||||
.cp_csc = 0xf4,
|
||||
.cec_irq_status = 0x93,
|
||||
.cec_rx_enable = 0x2c,
|
||||
.cec_rx_enable_mask = 0x02,
|
||||
.formats = adv7612_formats,
|
||||
.nformats = ARRAY_SIZE(adv7612_formats),
|
||||
.set_termination = adv7611_set_termination,
|
||||
|
|
@ -3134,7 +3168,7 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
|
|||
state->pdata.insert_av_codes = 1;
|
||||
|
||||
/* Disable the interrupt for now as no DT-based board uses it. */
|
||||
state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED;
|
||||
state->pdata.int1_config = ADV76XX_INT1_CONFIG_ACTIVE_HIGH;
|
||||
|
||||
/* Hardcode the remaining platform data fields. */
|
||||
state->pdata.disable_pwrdnb = 0;
|
||||
|
|
@ -3517,6 +3551,16 @@ static int adv76xx_probe(struct i2c_client *client,
|
|||
if (err)
|
||||
goto err_entity;
|
||||
|
||||
if (client->irq) {
|
||||
err = devm_request_threaded_irq(&client->dev,
|
||||
client->irq,
|
||||
NULL, adv76xx_irq_handler,
|
||||
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
|
||||
client->name, state);
|
||||
if (err)
|
||||
goto err_entity;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_VIDEO_ADV7604_CEC)
|
||||
state->cec_adap = cec_allocate_adapter(&adv76xx_cec_adap_ops,
|
||||
state, dev_name(&client->dev),
|
||||
|
|
|
|||
|
|
@ -663,7 +663,7 @@ static const struct v4l2_dv_timings_cap adv7842_timings_cap_analog = {
|
|||
.type = V4L2_DV_BT_656_1120,
|
||||
/* keep this initialization for compatibility with GCC < 4.4.6 */
|
||||
.reserved = { 0 },
|
||||
V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 170000000,
|
||||
V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 170000000,
|
||||
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
|
||||
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
|
||||
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
|
||||
|
|
@ -674,7 +674,7 @@ static const struct v4l2_dv_timings_cap adv7842_timings_cap_digital = {
|
|||
.type = V4L2_DV_BT_656_1120,
|
||||
/* keep this initialization for compatibility with GCC < 4.4.6 */
|
||||
.reserved = { 0 },
|
||||
V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1200, 25000000, 225000000,
|
||||
V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 25000000, 225000000,
|
||||
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
|
||||
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
|
||||
V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING |
|
||||
|
|
|
|||
1118
drivers/media/i2c/imx214.c
Normal file
1118
drivers/media/i2c/imx214.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -62,11 +62,6 @@
|
|||
|
||||
/* Test Pattern Control */
|
||||
#define IMX258_REG_TEST_PATTERN 0x0600
|
||||
#define IMX258_TEST_PATTERN_DISABLE 0
|
||||
#define IMX258_TEST_PATTERN_SOLID_COLOR 1
|
||||
#define IMX258_TEST_PATTERN_COLOR_BARS 2
|
||||
#define IMX258_TEST_PATTERN_GREY_COLOR 3
|
||||
#define IMX258_TEST_PATTERN_PN9 4
|
||||
|
||||
/* Orientation */
|
||||
#define REG_MIRROR_FLIP_CONTROL 0x0101
|
||||
|
|
@ -504,18 +499,10 @@ static const struct imx258_reg mode_1048_780_regs[] = {
|
|||
|
||||
static const char * const imx258_test_pattern_menu[] = {
|
||||
"Disabled",
|
||||
"Color Bars",
|
||||
"Solid Color",
|
||||
"Grey Color Bars",
|
||||
"PN9"
|
||||
};
|
||||
|
||||
static const int imx258_test_pattern_val[] = {
|
||||
IMX258_TEST_PATTERN_DISABLE,
|
||||
IMX258_TEST_PATTERN_COLOR_BARS,
|
||||
IMX258_TEST_PATTERN_SOLID_COLOR,
|
||||
IMX258_TEST_PATTERN_GREY_COLOR,
|
||||
IMX258_TEST_PATTERN_PN9,
|
||||
"Solid Colour",
|
||||
"Eight Vertical Colour Bars",
|
||||
"Colour Bars With Fade to Grey",
|
||||
"Pseudorandom Sequence (PN9)",
|
||||
};
|
||||
|
||||
/* Configurations for supported link frequencies */
|
||||
|
|
@ -778,13 +765,10 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
|
|||
case V4L2_CID_TEST_PATTERN:
|
||||
ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN,
|
||||
IMX258_REG_VALUE_16BIT,
|
||||
imx258_test_pattern_val[ctrl->val]);
|
||||
|
||||
ctrl->val);
|
||||
ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
|
||||
IMX258_REG_VALUE_08BIT,
|
||||
ctrl->val == imx258_test_pattern_val
|
||||
[IMX258_TEST_PATTERN_DISABLE] ?
|
||||
REG_CONFIG_MIRROR_FLIP :
|
||||
!ctrl->val ? REG_CONFIG_MIRROR_FLIP :
|
||||
REG_CONFIG_FLIP_TEST_PATTERN);
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -619,16 +619,19 @@ static int imx274_write_table(struct stimx274 *priv, const struct reg_8 table[])
|
|||
|
||||
static inline int imx274_read_reg(struct stimx274 *priv, u16 addr, u8 *val)
|
||||
{
|
||||
unsigned int uint_val;
|
||||
int err;
|
||||
|
||||
err = regmap_read(priv->regmap, addr, (unsigned int *)val);
|
||||
err = regmap_read(priv->regmap, addr, &uint_val);
|
||||
if (err)
|
||||
dev_err(&priv->client->dev,
|
||||
"%s : i2c read failed, addr = %x\n", __func__, addr);
|
||||
else
|
||||
dev_dbg(&priv->client->dev,
|
||||
"%s : addr 0x%x, val=0x%x\n", __func__,
|
||||
addr, *val);
|
||||
addr, uint_val);
|
||||
|
||||
*val = uint_val;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -1901,7 +1904,7 @@ static int imx274_probe(struct i2c_client *client,
|
|||
imx274_reset(imx274, 1);
|
||||
|
||||
/* initialize controls */
|
||||
ret = v4l2_ctrl_handler_init(&imx274->ctrls.handler, 2);
|
||||
ret = v4l2_ctrl_handler_init(&imx274->ctrls.handler, 4);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev,
|
||||
"%s : ctrl handler init Failed\n", __func__);
|
||||
|
|
|
|||
|
|
@ -1648,10 +1648,10 @@ static const struct imx319_reg mode_1280x720_regs[] = {
|
|||
|
||||
static const char * const imx319_test_pattern_menu[] = {
|
||||
"Disabled",
|
||||
"100% color bars",
|
||||
"Solid color",
|
||||
"Fade to gray color bars",
|
||||
"PN9"
|
||||
"Solid Colour",
|
||||
"Eight Vertical Colour Bars",
|
||||
"Colour Bars With Fade to Grey",
|
||||
"Pseudorandom Sequence (PN9)",
|
||||
};
|
||||
|
||||
/* supported link frequencies */
|
||||
|
|
|
|||
|
|
@ -876,10 +876,10 @@ static const struct imx355_reg mode_820x616_regs[] = {
|
|||
|
||||
static const char * const imx355_test_pattern_menu[] = {
|
||||
"Disabled",
|
||||
"100% color bars",
|
||||
"Solid color",
|
||||
"Fade to gray color bars",
|
||||
"PN9"
|
||||
"Solid Colour",
|
||||
"Eight Vertical Colour Bars",
|
||||
"Colour Bars With Fade to Grey",
|
||||
"Pseudorandom Sequence (PN9)",
|
||||
};
|
||||
|
||||
/* supported link frequencies */
|
||||
|
|
|
|||
|
|
@ -15,12 +15,15 @@
|
|||
#include <linux/delay.h>
|
||||
#include <linux/v4l2-mediabus.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-clk.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
|
||||
/*
|
||||
* MT9M111, MT9M112 and MT9M131:
|
||||
|
|
@ -101,6 +104,7 @@
|
|||
#define MT9M111_REDUCER_XSIZE_A 0x1a7
|
||||
#define MT9M111_REDUCER_YZOOM_A 0x1a9
|
||||
#define MT9M111_REDUCER_YSIZE_A 0x1aa
|
||||
#define MT9M111_EFFECTS_MODE 0x1e2
|
||||
|
||||
#define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a
|
||||
#define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b
|
||||
|
|
@ -126,6 +130,9 @@
|
|||
#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1)
|
||||
#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B (1 << 0)
|
||||
#define MT9M111_TPG_SEL_MASK GENMASK(2, 0)
|
||||
#define MT9M111_EFFECTS_MODE_MASK GENMASK(2, 0)
|
||||
#define MT9M111_RM_PWR_MASK BIT(10)
|
||||
#define MT9M111_RM_SKIP2_MASK GENMASK(3, 2)
|
||||
|
||||
/*
|
||||
* Camera control register addresses (0x200..0x2ff not implemented)
|
||||
|
|
@ -204,6 +211,23 @@ static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
|
|||
{MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
|
||||
};
|
||||
|
||||
enum mt9m111_mode_id {
|
||||
MT9M111_MODE_SXGA_8FPS,
|
||||
MT9M111_MODE_SXGA_15FPS,
|
||||
MT9M111_MODE_QSXGA_30FPS,
|
||||
MT9M111_NUM_MODES,
|
||||
};
|
||||
|
||||
struct mt9m111_mode_info {
|
||||
unsigned int sensor_w;
|
||||
unsigned int sensor_h;
|
||||
unsigned int max_image_w;
|
||||
unsigned int max_image_h;
|
||||
unsigned int max_fps;
|
||||
unsigned int reg_val;
|
||||
unsigned int reg_mask;
|
||||
};
|
||||
|
||||
struct mt9m111 {
|
||||
struct v4l2_subdev subdev;
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
|
|
@ -213,15 +237,51 @@ struct mt9m111 {
|
|||
struct v4l2_clk *clk;
|
||||
unsigned int width; /* output */
|
||||
unsigned int height; /* sizes */
|
||||
struct v4l2_fract frame_interval;
|
||||
const struct mt9m111_mode_info *current_mode;
|
||||
struct mutex power_lock; /* lock to protect power_count */
|
||||
int power_count;
|
||||
const struct mt9m111_datafmt *fmt;
|
||||
int lastpage; /* PageMap cache value */
|
||||
bool is_streaming;
|
||||
/* user point of view - 0: falling 1: rising edge */
|
||||
unsigned int pclk_sample:1;
|
||||
#ifdef CONFIG_MEDIA_CONTROLLER
|
||||
struct media_pad pad;
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct mt9m111_mode_info mt9m111_mode_data[MT9M111_NUM_MODES] = {
|
||||
[MT9M111_MODE_SXGA_8FPS] = {
|
||||
.sensor_w = 1280,
|
||||
.sensor_h = 1024,
|
||||
.max_image_w = 1280,
|
||||
.max_image_h = 1024,
|
||||
.max_fps = 8,
|
||||
.reg_val = MT9M111_RM_LOW_POWER_RD,
|
||||
.reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
|
||||
},
|
||||
[MT9M111_MODE_SXGA_15FPS] = {
|
||||
.sensor_w = 1280,
|
||||
.sensor_h = 1024,
|
||||
.max_image_w = 1280,
|
||||
.max_image_h = 1024,
|
||||
.max_fps = 15,
|
||||
.reg_val = MT9M111_RM_FULL_POWER_RD,
|
||||
.reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
|
||||
},
|
||||
[MT9M111_MODE_QSXGA_30FPS] = {
|
||||
.sensor_w = 1280,
|
||||
.sensor_h = 1024,
|
||||
.max_image_w = 640,
|
||||
.max_image_h = 512,
|
||||
.max_fps = 30,
|
||||
.reg_val = MT9M111_RM_LOW_POWER_RD | MT9M111_RM_COL_SKIP_2X |
|
||||
MT9M111_RM_ROW_SKIP_2X,
|
||||
.reg_mask = MT9M111_RM_PWR_MASK | MT9M111_RM_SKIP2_MASK,
|
||||
},
|
||||
};
|
||||
|
||||
/* Find a data format by a pixel code */
|
||||
static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111,
|
||||
u32 code)
|
||||
|
|
@ -538,6 +598,10 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* receiver samples on falling edge, chip-hw default is rising */
|
||||
if (mt9m111->pclk_sample == 0)
|
||||
mask_outfmt2 |= MT9M111_OUTFMT_INV_PIX_CLOCK;
|
||||
|
||||
ret = mt9m111_reg_mask(client, context_a.output_fmt_ctrl2,
|
||||
data_outfmt2, mask_outfmt2);
|
||||
if (!ret)
|
||||
|
|
@ -559,6 +623,9 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd,
|
|||
bool bayer;
|
||||
int ret;
|
||||
|
||||
if (mt9m111->is_streaming)
|
||||
return -EBUSY;
|
||||
|
||||
if (format->pad)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
@ -611,6 +678,61 @@ static int mt9m111_set_fmt(struct v4l2_subdev *sd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const struct mt9m111_mode_info *
|
||||
mt9m111_find_mode(struct mt9m111 *mt9m111, unsigned int req_fps,
|
||||
unsigned int width, unsigned int height)
|
||||
{
|
||||
const struct mt9m111_mode_info *mode;
|
||||
struct v4l2_rect *sensor_rect = &mt9m111->rect;
|
||||
unsigned int gap, gap_best = (unsigned int) -1;
|
||||
int i, best_gap_idx = MT9M111_MODE_SXGA_15FPS;
|
||||
bool skip_30fps = false;
|
||||
|
||||
/*
|
||||
* The fps selection is based on the row, column skipping mechanism.
|
||||
* So ensure that the sensor window is set to default else the fps
|
||||
* aren't calculated correctly within the sensor hw.
|
||||
*/
|
||||
if (sensor_rect->width != MT9M111_MAX_WIDTH ||
|
||||
sensor_rect->height != MT9M111_MAX_HEIGHT) {
|
||||
dev_info(mt9m111->subdev.dev,
|
||||
"Framerate selection is not supported for cropped "
|
||||
"images\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 30fps only supported for images not exceeding 640x512 */
|
||||
if (width > MT9M111_MAX_WIDTH / 2 || height > MT9M111_MAX_HEIGHT / 2) {
|
||||
dev_dbg(mt9m111->subdev.dev,
|
||||
"Framerates > 15fps are supported only for images "
|
||||
"not exceeding 640x512\n");
|
||||
skip_30fps = true;
|
||||
}
|
||||
|
||||
/* find best matched fps */
|
||||
for (i = 0; i < MT9M111_NUM_MODES; i++) {
|
||||
unsigned int fps = mt9m111_mode_data[i].max_fps;
|
||||
|
||||
if (fps == 30 && skip_30fps)
|
||||
continue;
|
||||
|
||||
gap = abs(fps - req_fps);
|
||||
if (gap < gap_best) {
|
||||
best_gap_idx = i;
|
||||
gap_best = gap;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Use context a/b default timing values instead of calculate blanking
|
||||
* timing values.
|
||||
*/
|
||||
mode = &mt9m111_mode_data[best_gap_idx];
|
||||
mt9m111->ctx = (best_gap_idx == MT9M111_MODE_QSXGA_30FPS) ? &context_a :
|
||||
&context_b;
|
||||
return mode;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
static int mt9m111_g_register(struct v4l2_subdev *sd,
|
||||
struct v4l2_dbg_register *reg)
|
||||
|
|
@ -726,6 +848,29 @@ static int mt9m111_set_test_pattern(struct mt9m111 *mt9m111, int val)
|
|||
MT9M111_TPG_SEL_MASK);
|
||||
}
|
||||
|
||||
static int mt9m111_set_colorfx(struct mt9m111 *mt9m111, int val)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
|
||||
static const struct v4l2_control colorfx[] = {
|
||||
{ V4L2_COLORFX_NONE, 0 },
|
||||
{ V4L2_COLORFX_BW, 1 },
|
||||
{ V4L2_COLORFX_SEPIA, 2 },
|
||||
{ V4L2_COLORFX_NEGATIVE, 3 },
|
||||
{ V4L2_COLORFX_SOLARIZATION, 4 },
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(colorfx); i++) {
|
||||
if (colorfx[i].id == val) {
|
||||
return mt9m111_reg_mask(client, MT9M111_EFFECTS_MODE,
|
||||
colorfx[i].value,
|
||||
MT9M111_EFFECTS_MODE_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct mt9m111 *mt9m111 = container_of(ctrl->handler,
|
||||
|
|
@ -746,6 +891,8 @@ static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
return mt9m111_set_autowhitebalance(mt9m111, ctrl->val);
|
||||
case V4L2_CID_TEST_PATTERN:
|
||||
return mt9m111_set_test_pattern(mt9m111, ctrl->val);
|
||||
case V4L2_CID_COLORFX:
|
||||
return mt9m111_set_colorfx(mt9m111, ctrl->val);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
|
@ -771,11 +918,16 @@ static int mt9m111_suspend(struct mt9m111 *mt9m111)
|
|||
|
||||
static void mt9m111_restore_state(struct mt9m111 *mt9m111)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
|
||||
|
||||
mt9m111_set_context(mt9m111, mt9m111->ctx);
|
||||
mt9m111_set_pixfmt(mt9m111, mt9m111->fmt->code);
|
||||
mt9m111_setup_geometry(mt9m111, &mt9m111->rect,
|
||||
mt9m111->width, mt9m111->height, mt9m111->fmt->code);
|
||||
v4l2_ctrl_handler_setup(&mt9m111->hdl);
|
||||
mt9m111_reg_mask(client, mt9m111->ctx->read_mode,
|
||||
mt9m111->current_mode->reg_val,
|
||||
mt9m111->current_mode->reg_mask);
|
||||
}
|
||||
|
||||
static int mt9m111_resume(struct mt9m111 *mt9m111)
|
||||
|
|
@ -862,12 +1014,62 @@ static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
|
|||
|
||||
static const struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
|
||||
.s_power = mt9m111_s_power,
|
||||
.log_status = v4l2_ctrl_subdev_log_status,
|
||||
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
|
||||
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.g_register = mt9m111_g_register,
|
||||
.s_register = mt9m111_s_register,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int mt9m111_g_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_frame_interval *fi)
|
||||
{
|
||||
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
|
||||
|
||||
fi->interval = mt9m111->frame_interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m111_s_frame_interval(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_frame_interval *fi)
|
||||
{
|
||||
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
|
||||
const struct mt9m111_mode_info *mode;
|
||||
struct v4l2_fract *fract = &fi->interval;
|
||||
int fps;
|
||||
|
||||
if (mt9m111->is_streaming)
|
||||
return -EBUSY;
|
||||
|
||||
if (fi->pad != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (fract->numerator == 0) {
|
||||
fract->denominator = 30;
|
||||
fract->numerator = 1;
|
||||
}
|
||||
|
||||
fps = DIV_ROUND_CLOSEST(fract->denominator, fract->numerator);
|
||||
|
||||
/* Find best fitting mode. Do not update the mode if no one was found. */
|
||||
mode = mt9m111_find_mode(mt9m111, fps, mt9m111->width, mt9m111->height);
|
||||
if (!mode)
|
||||
return 0;
|
||||
|
||||
if (mode->max_fps != fps) {
|
||||
fract->denominator = mode->max_fps;
|
||||
fract->numerator = 1;
|
||||
}
|
||||
|
||||
mt9m111->current_mode = mode;
|
||||
mt9m111->frame_interval = fi->interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_mbus_code_enum *code)
|
||||
|
|
@ -879,12 +1081,26 @@ static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m111_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
|
||||
|
||||
mt9m111->is_streaming = !!enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_config *cfg)
|
||||
{
|
||||
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
|
||||
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
|
||||
|
||||
cfg->flags = V4L2_MBUS_MASTER |
|
||||
V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
|
||||
V4L2_MBUS_DATA_ACTIVE_HIGH;
|
||||
|
||||
cfg->flags |= mt9m111->pclk_sample ? V4L2_MBUS_PCLK_SAMPLE_RISING :
|
||||
V4L2_MBUS_PCLK_SAMPLE_FALLING;
|
||||
|
||||
cfg->type = V4L2_MBUS_PARALLEL;
|
||||
|
||||
return 0;
|
||||
|
|
@ -892,6 +1108,9 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
|
|||
|
||||
static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
|
||||
.g_mbus_config = mt9m111_g_mbus_config,
|
||||
.s_stream = mt9m111_s_stream,
|
||||
.g_frame_interval = mt9m111_g_frame_interval,
|
||||
.s_frame_interval = mt9m111_s_frame_interval,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
|
||||
|
|
@ -951,6 +1170,30 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int mt9m111_probe_fw(struct i2c_client *client, struct mt9m111 *mt9m111)
|
||||
{
|
||||
struct v4l2_fwnode_endpoint bus_cfg = {
|
||||
.bus_type = V4L2_MBUS_PARALLEL
|
||||
};
|
||||
struct fwnode_handle *np;
|
||||
int ret;
|
||||
|
||||
np = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
|
||||
if (!np)
|
||||
return -EINVAL;
|
||||
|
||||
ret = v4l2_fwnode_endpoint_parse(np, &bus_cfg);
|
||||
if (ret)
|
||||
goto out_put_fw;
|
||||
|
||||
mt9m111->pclk_sample = !!(bus_cfg.bus.parallel.flags &
|
||||
V4L2_MBUS_PCLK_SAMPLE_RISING);
|
||||
|
||||
out_put_fw:
|
||||
fwnode_handle_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mt9m111_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *did)
|
||||
{
|
||||
|
|
@ -968,6 +1211,10 @@ static int mt9m111_probe(struct i2c_client *client,
|
|||
if (!mt9m111)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = mt9m111_probe_fw(client, mt9m111);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
|
||||
if (IS_ERR(mt9m111->clk))
|
||||
return PTR_ERR(mt9m111->clk);
|
||||
|
|
@ -976,9 +1223,10 @@ static int mt9m111_probe(struct i2c_client *client,
|
|||
mt9m111->ctx = &context_b;
|
||||
|
||||
v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops);
|
||||
mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
|
||||
V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
|
||||
v4l2_ctrl_handler_init(&mt9m111->hdl, 5);
|
||||
v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
|
||||
v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
|
||||
V4L2_CID_VFLIP, 0, 1, 1, 0);
|
||||
v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
|
||||
|
|
@ -994,6 +1242,14 @@ static int mt9m111_probe(struct i2c_client *client,
|
|||
&mt9m111_ctrl_ops, V4L2_CID_TEST_PATTERN,
|
||||
ARRAY_SIZE(mt9m111_test_pattern_menu) - 1, 0, 0,
|
||||
mt9m111_test_pattern_menu);
|
||||
v4l2_ctrl_new_std_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
|
||||
V4L2_CID_COLORFX, V4L2_COLORFX_SOLARIZATION,
|
||||
~(BIT(V4L2_COLORFX_NONE) |
|
||||
BIT(V4L2_COLORFX_BW) |
|
||||
BIT(V4L2_COLORFX_SEPIA) |
|
||||
BIT(V4L2_COLORFX_NEGATIVE) |
|
||||
BIT(V4L2_COLORFX_SOLARIZATION)),
|
||||
V4L2_COLORFX_NONE);
|
||||
mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
|
||||
if (mt9m111->hdl.error) {
|
||||
ret = mt9m111->hdl.error;
|
||||
|
|
@ -1008,6 +1264,10 @@ static int mt9m111_probe(struct i2c_client *client,
|
|||
goto out_hdlfree;
|
||||
#endif
|
||||
|
||||
mt9m111->current_mode = &mt9m111_mode_data[MT9M111_MODE_SXGA_15FPS];
|
||||
mt9m111->frame_interval.numerator = 1;
|
||||
mt9m111->frame_interval.denominator = mt9m111->current_mode->max_fps;
|
||||
|
||||
/* Second stage probe - when a capture adapter is there */
|
||||
mt9m111->rect.left = MT9M111_MIN_DARK_COLS;
|
||||
mt9m111->rect.top = MT9M111_MIN_DARK_ROWS;
|
||||
|
|
|
|||
|
|
@ -1612,7 +1612,8 @@ static int ov13858_init_controls(struct ov13858 *ov13858)
|
|||
OV13858_NUM_OF_LINK_FREQS - 1,
|
||||
0,
|
||||
link_freq_menu_items);
|
||||
ov13858->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
if (ov13858->link_freq)
|
||||
ov13858->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
|
||||
pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
|
||||
pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]);
|
||||
|
|
@ -1635,7 +1636,8 @@ static int ov13858_init_controls(struct ov13858 *ov13858)
|
|||
ov13858->hblank = v4l2_ctrl_new_std(
|
||||
ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_HBLANK,
|
||||
hblank, hblank, 1, hblank);
|
||||
ov13858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
if (ov13858->hblank)
|
||||
ov13858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
|
||||
exposure_max = mode->vts_def - 8;
|
||||
ov13858->exposure = v4l2_ctrl_new_std(
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/videodev2.h>
|
||||
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-image-sizes.h>
|
||||
|
|
@ -705,6 +706,11 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const char * const ov2640_test_pattern_menu[] = {
|
||||
"Disabled",
|
||||
"Eight Vertical Colour Bars",
|
||||
};
|
||||
|
||||
/*
|
||||
* functions
|
||||
*/
|
||||
|
|
@ -740,6 +746,9 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
case V4L2_CID_HFLIP:
|
||||
val = ctrl->val ? REG04_HFLIP_IMG : 0x00;
|
||||
return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val);
|
||||
case V4L2_CID_TEST_PATTERN:
|
||||
val = ctrl->val ? COM7_COLOR_BAR_TEST : 0x00;
|
||||
return ov2640_mask_set(client, COM7, COM7_COLOR_BAR_TEST, val);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
|
|
@ -1088,6 +1097,9 @@ static const struct v4l2_ctrl_ops ov2640_ctrl_ops = {
|
|||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
|
||||
.log_status = v4l2_ctrl_subdev_log_status,
|
||||
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
|
||||
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.g_register = ov2640_g_register,
|
||||
.s_register = ov2640_s_register,
|
||||
|
|
@ -1182,14 +1194,19 @@ static int ov2640_probe(struct i2c_client *client,
|
|||
goto err_clk;
|
||||
|
||||
v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
|
||||
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
|
||||
V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
mutex_init(&priv->lock);
|
||||
v4l2_ctrl_handler_init(&priv->hdl, 2);
|
||||
v4l2_ctrl_handler_init(&priv->hdl, 3);
|
||||
priv->hdl.lock = &priv->lock;
|
||||
v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
|
||||
V4L2_CID_VFLIP, 0, 1, 1, 0);
|
||||
v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
|
||||
V4L2_CID_HFLIP, 0, 1, 1, 0);
|
||||
v4l2_ctrl_new_std_menu_items(&priv->hdl, &ov2640_ctrl_ops,
|
||||
V4L2_CID_TEST_PATTERN,
|
||||
ARRAY_SIZE(ov2640_test_pattern_menu) - 1, 0, 0,
|
||||
ov2640_test_pattern_menu);
|
||||
priv->subdev.ctrl_handler = &priv->hdl;
|
||||
if (priv->hdl.error) {
|
||||
ret = priv->hdl.error;
|
||||
|
|
|
|||
|
|
@ -568,10 +568,6 @@ static int ov2680_power_on(struct ov2680_dev *sensor)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ov2680_mode_restore(sensor);
|
||||
if (ret < 0)
|
||||
goto disable;
|
||||
|
||||
sensor->is_enabled = true;
|
||||
|
||||
/* Set clock lane into LP-11 state */
|
||||
|
|
@ -580,12 +576,6 @@ static int ov2680_power_on(struct ov2680_dev *sensor)
|
|||
ov2680_stream_disable(sensor);
|
||||
|
||||
return 0;
|
||||
|
||||
disable:
|
||||
dev_err(dev, "failed to enable sensor: %d\n", ret);
|
||||
ov2680_power_off(sensor);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ov2680_s_power(struct v4l2_subdev *sd, int on)
|
||||
|
|
@ -606,6 +596,8 @@ static int ov2680_s_power(struct v4l2_subdev *sd, int on)
|
|||
ret = v4l2_ctrl_handler_setup(&sensor->ctrls.handler);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ov2680_mode_restore(sensor);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <media/v4l2-async.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
|
|
@ -94,9 +95,6 @@
|
|||
#define OV5640_REG_SDE_CTRL5 0x5585
|
||||
#define OV5640_REG_AVG_READOUT 0x56a1
|
||||
|
||||
#define OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT 1
|
||||
#define OV5640_SCLK_ROOT_DIVIDER_DEFAULT 2
|
||||
|
||||
enum ov5640_mode_id {
|
||||
OV5640_MODE_QCIF_176_144 = 0,
|
||||
OV5640_MODE_QVGA_320_240,
|
||||
|
|
@ -113,6 +111,7 @@ enum ov5640_mode_id {
|
|||
enum ov5640_frame_rate {
|
||||
OV5640_15_FPS = 0,
|
||||
OV5640_30_FPS,
|
||||
OV5640_60_FPS,
|
||||
OV5640_NUM_FRAMERATES,
|
||||
};
|
||||
|
||||
|
|
@ -141,6 +140,7 @@ MODULE_PARM_DESC(virtual_channel,
|
|||
static const int ov5640_framerates[] = {
|
||||
[OV5640_15_FPS] = 15,
|
||||
[OV5640_30_FPS] = 30,
|
||||
[OV5640_60_FPS] = 60,
|
||||
};
|
||||
|
||||
/* regulator supplies */
|
||||
|
|
@ -261,8 +261,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
|
|||
static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
|
||||
{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
|
||||
{0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
|
||||
{0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
|
||||
{0x3037, 0x13, 0, 0}, {0x3630, 0x36, 0, 0},
|
||||
{0x3630, 0x36, 0, 0},
|
||||
{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
|
||||
{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
|
||||
{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
|
||||
|
|
@ -344,27 +343,8 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
|
|||
{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
|
||||
{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
|
||||
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
|
||||
{0x3810, 0x00, 0, 0},
|
||||
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
|
||||
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
|
||||
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
|
||||
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
|
||||
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
|
||||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
|
||||
{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
static const struct reg_value ov5640_setting_VGA_640_480[] = {
|
||||
{0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
|
|
@ -382,28 +362,8 @@ static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
|
|||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
|
||||
{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
|
||||
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
|
||||
{0x3810, 0x00, 0, 0},
|
||||
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
|
||||
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
|
||||
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
|
||||
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x0e, 0, 0},
|
||||
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
|
||||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
|
||||
{0x3035, 0x12, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
|
||||
{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
static const struct reg_value ov5640_setting_XGA_1024_768[] = {
|
||||
{0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
|
|
@ -421,8 +381,8 @@ static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
|
|||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
|
||||
{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
static const struct reg_value ov5640_setting_QVGA_320_240[] = {
|
||||
{0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
|
|
@ -440,8 +400,8 @@ static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
|
|||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
|
||||
{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
static const struct reg_value ov5640_setting_QCIF_176_144[] = {
|
||||
{0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
|
|
@ -459,46 +419,8 @@ static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
|
|||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
|
||||
{0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
|
||||
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
|
||||
{0x3810, 0x00, 0, 0},
|
||||
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
|
||||
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
|
||||
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
|
||||
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
|
||||
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
|
||||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
|
||||
{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
|
||||
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
|
||||
{0x3810, 0x00, 0, 0},
|
||||
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
|
||||
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
|
||||
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
|
||||
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
|
||||
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
|
||||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
|
||||
{0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
static const struct reg_value ov5640_setting_NTSC_720_480[] = {
|
||||
{0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
|
|
@ -516,27 +438,8 @@ static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
|
|||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
|
||||
{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
|
||||
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
|
||||
{0x3810, 0x00, 0, 0},
|
||||
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
|
||||
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
|
||||
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
|
||||
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
|
||||
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
|
||||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
|
||||
{0x3035, 0x12, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
static const struct reg_value ov5640_setting_PAL_720_576[] = {
|
||||
{0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
|
|
@ -554,48 +457,8 @@ static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
|
|||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
|
||||
{0x3035, 0x22, 0, 0}, {0x3036, 0x38, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
|
||||
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
|
||||
{0x3810, 0x00, 0, 0},
|
||||
{0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
|
||||
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
|
||||
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
|
||||
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
|
||||
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
|
||||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
|
||||
{0x3008, 0x42, 0, 0},
|
||||
{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
|
||||
{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
|
||||
{0x3810, 0x00, 0, 0},
|
||||
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
|
||||
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
|
||||
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
|
||||
{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
|
||||
{0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x72, 0, 0}, {0x3a0e, 0x01, 0, 0},
|
||||
{0x3a0d, 0x02, 0, 0}, {0x3a14, 0x02, 0, 0}, {0x3a15, 0xe4, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x02, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0},
|
||||
{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0}, {0x4005, 0x1a, 0, 0},
|
||||
{0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
|
||||
{0x3035, 0x41, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0},
|
||||
static const struct reg_value ov5640_setting_720P_1280_720[] = {
|
||||
{0x3c07, 0x07, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x31, 0, 0},
|
||||
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
|
|
@ -613,9 +476,9 @@ static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
|
|||
{0x3824, 0x04, 0, 0}, {0x5001, 0x83, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
|
||||
static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
|
||||
{0x3008, 0x42, 0, 0},
|
||||
{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
{0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x11, 0, 0},
|
||||
{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
|
|
@ -630,8 +493,8 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
|
|||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x11, 0, 0},
|
||||
{0x3036, 0x54, 0, 0}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
|
||||
{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
|
||||
{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
|
||||
|
|
@ -643,43 +506,10 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
|
|||
{0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
|
||||
{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
|
||||
{0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0},
|
||||
{0x3503, 0, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
|
||||
{0x3008, 0x42, 0, 0},
|
||||
{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x11, 0, 0},
|
||||
{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
|
||||
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
|
||||
{0x3810, 0x00, 0, 0},
|
||||
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
|
||||
{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
|
||||
{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
|
||||
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
|
||||
{0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
|
||||
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
|
||||
{0x4001, 0x02, 0, 0}, {0x4004, 0x06, 0, 0}, {0x4713, 0x03, 0, 0},
|
||||
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
|
||||
{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0}, {0x3035, 0x21, 0, 0},
|
||||
{0x3036, 0x54, 0, 1}, {0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
|
||||
{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
|
||||
{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0},
|
||||
{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
|
||||
{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
|
||||
{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
|
||||
{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
|
||||
{0x3a15, 0x60, 0, 0}, {0x4713, 0x02, 0, 0}, {0x4407, 0x04, 0, 0},
|
||||
{0x460b, 0x37, 0, 0}, {0x460c, 0x20, 0, 0}, {0x3824, 0x04, 0, 0},
|
||||
{0x4005, 0x1a, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3503, 0, 0, 0},
|
||||
};
|
||||
|
||||
static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
|
||||
{0x3035, 0x21, 0, 0}, {0x3036, 0x54, 0, 0}, {0x3c07, 0x08, 0, 0},
|
||||
static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
|
||||
{0x3c07, 0x08, 0, 0},
|
||||
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
|
||||
{0x3814, 0x11, 0, 0},
|
||||
{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
|
||||
|
|
@ -705,79 +535,43 @@ static const struct ov5640_mode_info ov5640_mode_init_data = {
|
|||
};
|
||||
|
||||
static const struct ov5640_mode_info
|
||||
ov5640_mode_data[OV5640_NUM_FRAMERATES][OV5640_NUM_MODES] = {
|
||||
{
|
||||
{OV5640_MODE_QCIF_176_144, SUBSAMPLING,
|
||||
176, 1896, 144, 984,
|
||||
ov5640_setting_15fps_QCIF_176_144,
|
||||
ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
|
||||
{OV5640_MODE_QVGA_320_240, SUBSAMPLING,
|
||||
320, 1896, 240, 984,
|
||||
ov5640_setting_15fps_QVGA_320_240,
|
||||
ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
|
||||
{OV5640_MODE_VGA_640_480, SUBSAMPLING,
|
||||
640, 1896, 480, 1080,
|
||||
ov5640_setting_15fps_VGA_640_480,
|
||||
ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
|
||||
{OV5640_MODE_NTSC_720_480, SUBSAMPLING,
|
||||
720, 1896, 480, 984,
|
||||
ov5640_setting_15fps_NTSC_720_480,
|
||||
ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
|
||||
{OV5640_MODE_PAL_720_576, SUBSAMPLING,
|
||||
720, 1896, 576, 984,
|
||||
ov5640_setting_15fps_PAL_720_576,
|
||||
ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
|
||||
{OV5640_MODE_XGA_1024_768, SUBSAMPLING,
|
||||
1024, 1896, 768, 1080,
|
||||
ov5640_setting_15fps_XGA_1024_768,
|
||||
ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
|
||||
{OV5640_MODE_720P_1280_720, SUBSAMPLING,
|
||||
1280, 1892, 720, 740,
|
||||
ov5640_setting_15fps_720P_1280_720,
|
||||
ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
|
||||
{OV5640_MODE_1080P_1920_1080, SCALING,
|
||||
1920, 2500, 1080, 1120,
|
||||
ov5640_setting_15fps_1080P_1920_1080,
|
||||
ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
|
||||
{OV5640_MODE_QSXGA_2592_1944, SCALING,
|
||||
2592, 2844, 1944, 1968,
|
||||
ov5640_setting_15fps_QSXGA_2592_1944,
|
||||
ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
|
||||
}, {
|
||||
{OV5640_MODE_QCIF_176_144, SUBSAMPLING,
|
||||
176, 1896, 144, 984,
|
||||
ov5640_setting_30fps_QCIF_176_144,
|
||||
ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
|
||||
{OV5640_MODE_QVGA_320_240, SUBSAMPLING,
|
||||
320, 1896, 240, 984,
|
||||
ov5640_setting_30fps_QVGA_320_240,
|
||||
ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
|
||||
{OV5640_MODE_VGA_640_480, SUBSAMPLING,
|
||||
640, 1896, 480, 1080,
|
||||
ov5640_setting_30fps_VGA_640_480,
|
||||
ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
|
||||
{OV5640_MODE_NTSC_720_480, SUBSAMPLING,
|
||||
720, 1896, 480, 984,
|
||||
ov5640_setting_30fps_NTSC_720_480,
|
||||
ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
|
||||
{OV5640_MODE_PAL_720_576, SUBSAMPLING,
|
||||
720, 1896, 576, 984,
|
||||
ov5640_setting_30fps_PAL_720_576,
|
||||
ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
|
||||
{OV5640_MODE_XGA_1024_768, SUBSAMPLING,
|
||||
1024, 1896, 768, 1080,
|
||||
ov5640_setting_30fps_XGA_1024_768,
|
||||
ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
|
||||
{OV5640_MODE_720P_1280_720, SUBSAMPLING,
|
||||
1280, 1892, 720, 740,
|
||||
ov5640_setting_30fps_720P_1280_720,
|
||||
ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
|
||||
{OV5640_MODE_1080P_1920_1080, SCALING,
|
||||
1920, 2500, 1080, 1120,
|
||||
ov5640_setting_30fps_1080P_1920_1080,
|
||||
ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)},
|
||||
{OV5640_MODE_QSXGA_2592_1944, -1, 0, 0, 0, 0, NULL, 0},
|
||||
},
|
||||
ov5640_mode_data[OV5640_NUM_MODES] = {
|
||||
{OV5640_MODE_QCIF_176_144, SUBSAMPLING,
|
||||
176, 1896, 144, 984,
|
||||
ov5640_setting_QCIF_176_144,
|
||||
ARRAY_SIZE(ov5640_setting_QCIF_176_144)},
|
||||
{OV5640_MODE_QVGA_320_240, SUBSAMPLING,
|
||||
320, 1896, 240, 984,
|
||||
ov5640_setting_QVGA_320_240,
|
||||
ARRAY_SIZE(ov5640_setting_QVGA_320_240)},
|
||||
{OV5640_MODE_VGA_640_480, SUBSAMPLING,
|
||||
640, 1896, 480, 1080,
|
||||
ov5640_setting_VGA_640_480,
|
||||
ARRAY_SIZE(ov5640_setting_VGA_640_480)},
|
||||
{OV5640_MODE_NTSC_720_480, SUBSAMPLING,
|
||||
720, 1896, 480, 984,
|
||||
ov5640_setting_NTSC_720_480,
|
||||
ARRAY_SIZE(ov5640_setting_NTSC_720_480)},
|
||||
{OV5640_MODE_PAL_720_576, SUBSAMPLING,
|
||||
720, 1896, 576, 984,
|
||||
ov5640_setting_PAL_720_576,
|
||||
ARRAY_SIZE(ov5640_setting_PAL_720_576)},
|
||||
{OV5640_MODE_XGA_1024_768, SUBSAMPLING,
|
||||
1024, 1896, 768, 1080,
|
||||
ov5640_setting_XGA_1024_768,
|
||||
ARRAY_SIZE(ov5640_setting_XGA_1024_768)},
|
||||
{OV5640_MODE_720P_1280_720, SUBSAMPLING,
|
||||
1280, 1892, 720, 740,
|
||||
ov5640_setting_720P_1280_720,
|
||||
ARRAY_SIZE(ov5640_setting_720P_1280_720)},
|
||||
{OV5640_MODE_1080P_1920_1080, SCALING,
|
||||
1920, 2500, 1080, 1120,
|
||||
ov5640_setting_1080P_1920_1080,
|
||||
ARRAY_SIZE(ov5640_setting_1080P_1920_1080)},
|
||||
{OV5640_MODE_QSXGA_2592_1944, SCALING,
|
||||
2592, 2844, 1944, 1968,
|
||||
ov5640_setting_QSXGA_2592_1944,
|
||||
ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944)},
|
||||
};
|
||||
|
||||
static int ov5640_init_slave_id(struct ov5640_dev *sensor)
|
||||
|
|
@ -909,6 +703,333 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
|
|||
return ov5640_write_reg(sensor, reg, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* After trying the various combinations, reading various
|
||||
* documentations spreaded around the net, and from the various
|
||||
* feedback, the clock tree is probably as follows:
|
||||
*
|
||||
* +--------------+
|
||||
* | Ext. Clock |
|
||||
* +-+------------+
|
||||
* | +----------+
|
||||
* +->| PLL1 | - reg 0x3036, for the multiplier
|
||||
* +-+--------+ - reg 0x3037, bits 0-3 for the pre-divider
|
||||
* | +--------------+
|
||||
* +->| System Clock | - reg 0x3035, bits 4-7
|
||||
* +-+------------+
|
||||
* | +--------------+
|
||||
* +->| MIPI Divider | - reg 0x3035, bits 0-3
|
||||
* | +-+------------+
|
||||
* | +----------------> MIPI SCLK
|
||||
* | + +-----+
|
||||
* | +->| / 2 |-------> MIPI BIT CLK
|
||||
* | +-----+
|
||||
* | +--------------+
|
||||
* +->| PLL Root Div | - reg 0x3037, bit 4
|
||||
* +-+------------+
|
||||
* | +---------+
|
||||
* +->| Bit Div | - reg 0x3035, bits 0-3
|
||||
* +-+-------+
|
||||
* | +-------------+
|
||||
* +->| SCLK Div | - reg 0x3108, bits 0-1
|
||||
* | +-+-----------+
|
||||
* | +---------------> SCLK
|
||||
* | +-------------+
|
||||
* +->| SCLK 2X Div | - reg 0x3108, bits 2-3
|
||||
* | +-+-----------+
|
||||
* | +---------------> SCLK 2X
|
||||
* | +-------------+
|
||||
* +->| PCLK Div | - reg 0x3108, bits 4-5
|
||||
* ++------------+
|
||||
* + +-----------+
|
||||
* +->| P_DIV | - reg 0x3035, bits 0-3
|
||||
* +-----+-----+
|
||||
* +------------> PCLK
|
||||
*
|
||||
* This is deviating from the datasheet at least for the register
|
||||
* 0x3108, since it's said here that the PCLK would be clocked from
|
||||
* the PLL.
|
||||
*
|
||||
* There seems to be also (unverified) constraints:
|
||||
* - the PLL pre-divider output rate should be in the 4-27MHz range
|
||||
* - the PLL multiplier output rate should be in the 500-1000MHz range
|
||||
* - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
|
||||
*
|
||||
* In the two latter cases, these constraints are met since our
|
||||
* factors are hardcoded. If we were to change that, we would need to
|
||||
* take this into account. The only varying parts are the PLL
|
||||
* multiplier and the system clock divider, which are shared between
|
||||
* all these clocks so won't cause any issue.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is supposed to be ranging from 1 to 8, but the value is always
|
||||
* set to 3 in the vendor kernels.
|
||||
*/
|
||||
#define OV5640_PLL_PREDIV 3
|
||||
|
||||
#define OV5640_PLL_MULT_MIN 4
|
||||
#define OV5640_PLL_MULT_MAX 252
|
||||
|
||||
/*
|
||||
* This is supposed to be ranging from 1 to 16, but the value is
|
||||
* always set to either 1 or 2 in the vendor kernels.
|
||||
*/
|
||||
#define OV5640_SYSDIV_MIN 1
|
||||
#define OV5640_SYSDIV_MAX 16
|
||||
|
||||
/*
|
||||
* Hardcode these values for scaler and non-scaler modes.
|
||||
* FIXME: to be re-calcualted for 1 data lanes setups
|
||||
*/
|
||||
#define OV5640_MIPI_DIV_PCLK 2
|
||||
#define OV5640_MIPI_DIV_SCLK 1
|
||||
|
||||
/*
|
||||
* This is supposed to be ranging from 1 to 2, but the value is always
|
||||
* set to 2 in the vendor kernels.
|
||||
*/
|
||||
#define OV5640_PLL_ROOT_DIV 2
|
||||
#define OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 BIT(4)
|
||||
|
||||
/*
|
||||
* We only supports 8-bit formats at the moment
|
||||
*/
|
||||
#define OV5640_BIT_DIV 2
|
||||
#define OV5640_PLL_CTRL0_MIPI_MODE_8BIT 0x08
|
||||
|
||||
/*
|
||||
* This is supposed to be ranging from 1 to 8, but the value is always
|
||||
* set to 2 in the vendor kernels.
|
||||
*/
|
||||
#define OV5640_SCLK_ROOT_DIV 2
|
||||
|
||||
/*
|
||||
* This is hardcoded so that the consistency is maintained between SCLK and
|
||||
* SCLK 2x.
|
||||
*/
|
||||
#define OV5640_SCLK2X_ROOT_DIV (OV5640_SCLK_ROOT_DIV / 2)
|
||||
|
||||
/*
|
||||
* This is supposed to be ranging from 1 to 8, but the value is always
|
||||
* set to 1 in the vendor kernels.
|
||||
*/
|
||||
#define OV5640_PCLK_ROOT_DIV 1
|
||||
#define OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS 0x00
|
||||
|
||||
static unsigned long ov5640_compute_sys_clk(struct ov5640_dev *sensor,
|
||||
u8 pll_prediv, u8 pll_mult,
|
||||
u8 sysdiv)
|
||||
{
|
||||
unsigned long sysclk = sensor->xclk_freq / pll_prediv * pll_mult;
|
||||
|
||||
/* PLL1 output cannot exceed 1GHz. */
|
||||
if (sysclk / 1000000 > 1000)
|
||||
return 0;
|
||||
|
||||
return sysclk / sysdiv;
|
||||
}
|
||||
|
||||
static unsigned long ov5640_calc_sys_clk(struct ov5640_dev *sensor,
|
||||
unsigned long rate,
|
||||
u8 *pll_prediv, u8 *pll_mult,
|
||||
u8 *sysdiv)
|
||||
{
|
||||
unsigned long best = ~0;
|
||||
u8 best_sysdiv = 1, best_mult = 1;
|
||||
u8 _sysdiv, _pll_mult;
|
||||
|
||||
for (_sysdiv = OV5640_SYSDIV_MIN;
|
||||
_sysdiv <= OV5640_SYSDIV_MAX;
|
||||
_sysdiv++) {
|
||||
for (_pll_mult = OV5640_PLL_MULT_MIN;
|
||||
_pll_mult <= OV5640_PLL_MULT_MAX;
|
||||
_pll_mult++) {
|
||||
unsigned long _rate;
|
||||
|
||||
/*
|
||||
* The PLL multiplier cannot be odd if above
|
||||
* 127.
|
||||
*/
|
||||
if (_pll_mult > 127 && (_pll_mult % 2))
|
||||
continue;
|
||||
|
||||
_rate = ov5640_compute_sys_clk(sensor,
|
||||
OV5640_PLL_PREDIV,
|
||||
_pll_mult, _sysdiv);
|
||||
|
||||
/*
|
||||
* We have reached the maximum allowed PLL1 output,
|
||||
* increase sysdiv.
|
||||
*/
|
||||
if (!rate)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Prefer rates above the expected clock rate than
|
||||
* below, even if that means being less precise.
|
||||
*/
|
||||
if (_rate < rate)
|
||||
continue;
|
||||
|
||||
if (abs(rate - _rate) < abs(rate - best)) {
|
||||
best = _rate;
|
||||
best_sysdiv = _sysdiv;
|
||||
best_mult = _pll_mult;
|
||||
}
|
||||
|
||||
if (_rate == rate)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
*sysdiv = best_sysdiv;
|
||||
*pll_prediv = OV5640_PLL_PREDIV;
|
||||
*pll_mult = best_mult;
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/*
|
||||
* ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
|
||||
* for the MIPI CSI-2 output.
|
||||
*
|
||||
* @rate: The requested bandwidth per lane in bytes per second.
|
||||
* 'Bandwidth Per Lane' is calculated as:
|
||||
* bpl = HTOT * VTOT * FPS * bpp / num_lanes;
|
||||
*
|
||||
* This function use the requested bandwidth to calculate:
|
||||
* - sample_rate = bpl / (bpp / num_lanes);
|
||||
* = bpl / (PLL_RDIV * BIT_DIV * PCLK_DIV * MIPI_DIV / num_lanes);
|
||||
*
|
||||
* - mipi_sclk = bpl / MIPI_DIV / 2; ( / 2 is for CSI-2 DDR)
|
||||
*
|
||||
* with these fixed parameters:
|
||||
* PLL_RDIV = 2;
|
||||
* BIT_DIVIDER = 2; (MIPI_BIT_MODE == 8 ? 2 : 2,5);
|
||||
* PCLK_DIV = 1;
|
||||
*
|
||||
* The MIPI clock generation differs for modes that use the scaler and modes
|
||||
* that do not. In case the scaler is in use, the MIPI_SCLK generates the MIPI
|
||||
* BIT CLk, and thus:
|
||||
*
|
||||
* - mipi_sclk = bpl / MIPI_DIV / 2;
|
||||
* MIPI_DIV = 1;
|
||||
*
|
||||
* For modes that do not go through the scaler, the MIPI BIT CLOCK is generated
|
||||
* from the pixel clock, and thus:
|
||||
*
|
||||
* - sample_rate = bpl / (bpp / num_lanes);
|
||||
* = bpl / (2 * 2 * 1 * MIPI_DIV / num_lanes);
|
||||
* = bpl / (4 * MIPI_DIV / num_lanes);
|
||||
* - MIPI_DIV = bpp / (4 * num_lanes);
|
||||
*
|
||||
* FIXME: this have been tested with 16bpp and 2 lanes setup only.
|
||||
* MIPI_DIV is fixed to value 2, but it -might- be changed according to the
|
||||
* above formula for setups with 1 lane or image formats with different bpp.
|
||||
*
|
||||
* FIXME: this deviates from the sensor manual documentation which is quite
|
||||
* thin on the MIPI clock tree generation part.
|
||||
*/
|
||||
static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor,
|
||||
unsigned long rate)
|
||||
{
|
||||
const struct ov5640_mode_info *mode = sensor->current_mode;
|
||||
u8 prediv, mult, sysdiv;
|
||||
u8 mipi_div;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* 1280x720 is reported to use 'SUBSAMPLING' only,
|
||||
* but according to the sensor manual it goes through the
|
||||
* scaler before subsampling.
|
||||
*/
|
||||
if (mode->dn_mode == SCALING ||
|
||||
(mode->id == OV5640_MODE_720P_1280_720))
|
||||
mipi_div = OV5640_MIPI_DIV_SCLK;
|
||||
else
|
||||
mipi_div = OV5640_MIPI_DIV_PCLK;
|
||||
|
||||
ov5640_calc_sys_clk(sensor, rate, &prediv, &mult, &sysdiv);
|
||||
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
|
||||
0x0f, OV5640_PLL_CTRL0_MIPI_MODE_8BIT);
|
||||
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
|
||||
0xff, sysdiv << 4 | mipi_div);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2, 0xff, mult);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
|
||||
0x1f, OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 | prediv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER,
|
||||
0x30, OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS);
|
||||
}
|
||||
|
||||
static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
|
||||
unsigned long rate,
|
||||
u8 *pll_prediv, u8 *pll_mult, u8 *sysdiv,
|
||||
u8 *pll_rdiv, u8 *bit_div, u8 *pclk_div)
|
||||
{
|
||||
unsigned long _rate = rate * OV5640_PLL_ROOT_DIV * OV5640_BIT_DIV *
|
||||
OV5640_PCLK_ROOT_DIV;
|
||||
|
||||
_rate = ov5640_calc_sys_clk(sensor, _rate, pll_prediv, pll_mult,
|
||||
sysdiv);
|
||||
*pll_rdiv = OV5640_PLL_ROOT_DIV;
|
||||
*bit_div = OV5640_BIT_DIV;
|
||||
*pclk_div = OV5640_PCLK_ROOT_DIV;
|
||||
|
||||
return _rate / *pll_rdiv / *bit_div / *pclk_div;
|
||||
}
|
||||
|
||||
static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate)
|
||||
{
|
||||
u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
|
||||
int ret;
|
||||
|
||||
ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
|
||||
&bit_div, &pclk_div);
|
||||
|
||||
if (bit_div == 2)
|
||||
bit_div = 8;
|
||||
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
|
||||
0x0f, bit_div);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* We need to set sysdiv according to the clock, and to clear
|
||||
* the MIPI divider.
|
||||
*/
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
|
||||
0xff, sysdiv << 4);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL2,
|
||||
0xff, mult);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
|
||||
0x1f, prediv | ((pll_rdiv - 1) << 4));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x30,
|
||||
(ilog2(pclk_div) << 4));
|
||||
}
|
||||
|
||||
/* download ov5640 settings to sensor through i2c */
|
||||
static int ov5640_set_timings(struct ov5640_dev *sensor,
|
||||
const struct ov5640_mode_info *mode)
|
||||
|
|
@ -1061,16 +1182,6 @@ static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
|
|||
*/
|
||||
|
||||
if (on) {
|
||||
/*
|
||||
* reset MIPI PCLK/SERCLK divider
|
||||
*
|
||||
* SC PLL CONTRL1 0
|
||||
* - [3..0]: MIPI PCLK/SERCLK divider
|
||||
*/
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0x0f, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* configure parallel port control lines polarity
|
||||
*
|
||||
|
|
@ -1444,8 +1555,8 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
|
|||
{
|
||||
const struct ov5640_mode_info *mode;
|
||||
|
||||
mode = v4l2_find_nearest_size(ov5640_mode_data[fr],
|
||||
ARRAY_SIZE(ov5640_mode_data[fr]),
|
||||
mode = v4l2_find_nearest_size(ov5640_mode_data,
|
||||
ARRAY_SIZE(ov5640_mode_data),
|
||||
hact, vact,
|
||||
width, height);
|
||||
|
||||
|
|
@ -1453,6 +1564,11 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
|
|||
(!nearest && (mode->hact != width || mode->vact != height)))
|
||||
return NULL;
|
||||
|
||||
/* Only 640x480 can operate at 60fps (for now) */
|
||||
if (fr == OV5640_60_FPS &&
|
||||
!(mode->hact == 640 && mode->vact == 480))
|
||||
return NULL;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
|
@ -1637,6 +1753,7 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
|
|||
enum ov5640_downsize_mode dn_mode, orig_dn_mode;
|
||||
bool auto_gain = sensor->ctrls.auto_gain->val == 1;
|
||||
bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
|
||||
unsigned long rate;
|
||||
int ret;
|
||||
|
||||
dn_mode = mode->dn_mode;
|
||||
|
|
@ -1655,6 +1772,23 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
|
|||
goto restore_auto_gain;
|
||||
}
|
||||
|
||||
/*
|
||||
* All the formats we support have 16 bits per pixel, seems to require
|
||||
* the same rate than YUV, so we can just use 16 bpp all the time.
|
||||
*/
|
||||
rate = mode->vtot * mode->htot * 16;
|
||||
rate *= ov5640_framerates[sensor->current_fr];
|
||||
if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
|
||||
rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes;
|
||||
ret = ov5640_set_mipi_pclk(sensor, rate);
|
||||
} else {
|
||||
rate = rate / sensor->ep.bus.parallel.bus_width;
|
||||
ret = ov5640_set_dvp_pclk(sensor, rate);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
if ((dn_mode == SUBSAMPLING && orig_dn_mode == SCALING) ||
|
||||
(dn_mode == SCALING && orig_dn_mode == SUBSAMPLING)) {
|
||||
/*
|
||||
|
|
@ -1724,8 +1858,8 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor)
|
|||
sensor->last_mode = &ov5640_mode_init_data;
|
||||
|
||||
ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
|
||||
(ilog2(OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT) << 2) |
|
||||
ilog2(OV5640_SCLK_ROOT_DIVIDER_DEFAULT));
|
||||
(ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
|
||||
ilog2(OV5640_SCLK_ROOT_DIV));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -1925,34 +2059,39 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
|
|||
u32 width, u32 height)
|
||||
{
|
||||
const struct ov5640_mode_info *mode;
|
||||
u32 minfps, maxfps, fps;
|
||||
int ret;
|
||||
enum ov5640_frame_rate rate = OV5640_30_FPS;
|
||||
int minfps, maxfps, best_fps, fps;
|
||||
int i;
|
||||
|
||||
minfps = ov5640_framerates[OV5640_15_FPS];
|
||||
maxfps = ov5640_framerates[OV5640_30_FPS];
|
||||
maxfps = ov5640_framerates[OV5640_60_FPS];
|
||||
|
||||
if (fi->numerator == 0) {
|
||||
fi->denominator = maxfps;
|
||||
fi->numerator = 1;
|
||||
return OV5640_30_FPS;
|
||||
rate = OV5640_60_FPS;
|
||||
goto find_mode;
|
||||
}
|
||||
|
||||
fps = DIV_ROUND_CLOSEST(fi->denominator, fi->numerator);
|
||||
fps = clamp_val(DIV_ROUND_CLOSEST(fi->denominator, fi->numerator),
|
||||
minfps, maxfps);
|
||||
|
||||
best_fps = minfps;
|
||||
for (i = 0; i < ARRAY_SIZE(ov5640_framerates); i++) {
|
||||
int curr_fps = ov5640_framerates[i];
|
||||
|
||||
if (abs(curr_fps - fps) < abs(best_fps - fps)) {
|
||||
best_fps = curr_fps;
|
||||
rate = i;
|
||||
}
|
||||
}
|
||||
|
||||
fi->numerator = 1;
|
||||
if (fps > maxfps)
|
||||
fi->denominator = maxfps;
|
||||
else if (fps < minfps)
|
||||
fi->denominator = minfps;
|
||||
else if (2 * fps >= 2 * minfps + (maxfps - minfps))
|
||||
fi->denominator = maxfps;
|
||||
else
|
||||
fi->denominator = minfps;
|
||||
fi->denominator = best_fps;
|
||||
|
||||
ret = (fi->denominator == minfps) ? OV5640_15_FPS : OV5640_30_FPS;
|
||||
|
||||
mode = ov5640_find_mode(sensor, ret, width, height, false);
|
||||
return mode ? ret : -EINVAL;
|
||||
find_mode:
|
||||
mode = ov5640_find_mode(sensor, rate, width, height, false);
|
||||
return mode ? rate : -EINVAL;
|
||||
}
|
||||
|
||||
static int ov5640_get_fmt(struct v4l2_subdev *sd,
|
||||
|
|
@ -2020,6 +2159,7 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
|
|||
struct ov5640_dev *sensor = to_ov5640_dev(sd);
|
||||
const struct ov5640_mode_info *new_mode;
|
||||
struct v4l2_mbus_framefmt *mbus_fmt = &format->format;
|
||||
struct v4l2_mbus_framefmt *fmt;
|
||||
int ret;
|
||||
|
||||
if (format->pad != 0)
|
||||
|
|
@ -2037,22 +2177,20 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
struct v4l2_mbus_framefmt *fmt =
|
||||
v4l2_subdev_get_try_format(sd, cfg, 0);
|
||||
if (format->which == V4L2_SUBDEV_FORMAT_TRY)
|
||||
fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
|
||||
else
|
||||
fmt = &sensor->fmt;
|
||||
|
||||
*fmt = *mbus_fmt;
|
||||
goto out;
|
||||
}
|
||||
*fmt = *mbus_fmt;
|
||||
|
||||
if (new_mode != sensor->current_mode) {
|
||||
sensor->current_mode = new_mode;
|
||||
sensor->pending_mode_change = true;
|
||||
}
|
||||
if (mbus_fmt->code != sensor->fmt.code) {
|
||||
sensor->fmt = *mbus_fmt;
|
||||
if (mbus_fmt->code != sensor->fmt.code)
|
||||
sensor->pending_fmt_change = true;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&sensor->lock);
|
||||
return ret;
|
||||
|
|
@ -2502,10 +2640,10 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
|
|||
return -EINVAL;
|
||||
|
||||
fse->min_width =
|
||||
ov5640_mode_data[0][fse->index].hact;
|
||||
ov5640_mode_data[fse->index].hact;
|
||||
fse->max_width = fse->min_width;
|
||||
fse->min_height =
|
||||
ov5640_mode_data[0][fse->index].vact;
|
||||
ov5640_mode_data[fse->index].vact;
|
||||
fse->max_height = fse->min_height;
|
||||
|
||||
return 0;
|
||||
|
|
@ -2570,8 +2708,11 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
|
|||
|
||||
frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
|
||||
mode->hact, mode->vact);
|
||||
if (frame_rate < 0)
|
||||
frame_rate = OV5640_15_FPS;
|
||||
if (frame_rate < 0) {
|
||||
/* Always return a valid frame interval value */
|
||||
fi->interval = sensor->frame_interval;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mode = ov5640_find_mode(sensor, frame_rate, mode->hact,
|
||||
mode->vact, true);
|
||||
|
|
@ -2641,6 +2782,9 @@ out:
|
|||
|
||||
static const struct v4l2_subdev_core_ops ov5640_core_ops = {
|
||||
.s_power = ov5640_s_power,
|
||||
.log_status = v4l2_ctrl_subdev_log_status,
|
||||
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
|
||||
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_video_ops ov5640_video_ops = {
|
||||
|
|
@ -2736,7 +2880,7 @@ static int ov5640_probe(struct i2c_client *client,
|
|||
sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
|
||||
sensor->current_fr = OV5640_30_FPS;
|
||||
sensor->current_mode =
|
||||
&ov5640_mode_data[OV5640_30_FPS][OV5640_MODE_VGA_640_480];
|
||||
&ov5640_mode_data[OV5640_MODE_VGA_640_480];
|
||||
sensor->last_mode = sensor->current_mode;
|
||||
|
||||
sensor->ae_target = 52;
|
||||
|
|
@ -2795,7 +2939,8 @@ static int ov5640_probe(struct i2c_client *client,
|
|||
|
||||
v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
|
||||
|
||||
sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
|
||||
V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
|
||||
sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
||||
ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
|
||||
|
|
|
|||
|
|
@ -886,7 +886,7 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct v4l2_ctrl_ops ov5645_ctrl_ops = {
|
||||
static const struct v4l2_ctrl_ops ov5645_ctrl_ops = {
|
||||
.s_ctrl = ov5645_s_ctrl,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-fwnode.h>
|
||||
#include <media/v4l2-mediabus.h>
|
||||
|
|
@ -1651,6 +1652,9 @@ static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
|||
static const struct v4l2_subdev_core_ops ov7670_core_ops = {
|
||||
.reset = ov7670_reset,
|
||||
.init = ov7670_init,
|
||||
.log_status = v4l2_ctrl_subdev_log_status,
|
||||
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
|
||||
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.g_register = ov7670_g_register,
|
||||
.s_register = ov7670_s_register,
|
||||
|
|
@ -1773,7 +1777,7 @@ static int ov7670_probe(struct i2c_client *client,
|
|||
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
sd->internal_ops = &ov7670_subdev_internal_ops;
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
#endif
|
||||
|
||||
info->clock_speed = 30; /* default: a guess */
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-image-sizes.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
|
||||
|
|
@ -1287,6 +1288,9 @@ static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
|
|||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
|
||||
.log_status = v4l2_ctrl_subdev_log_status,
|
||||
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
|
||||
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.g_register = ov772x_g_register,
|
||||
.s_register = ov772x_s_register,
|
||||
|
|
@ -1379,7 +1383,8 @@ static int ov772x_probe(struct i2c_client *client,
|
|||
mutex_init(&priv->lock);
|
||||
|
||||
v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
|
||||
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
|
||||
V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
v4l2_ctrl_handler_init(&priv->hdl, 3);
|
||||
/* Use our mutex for the controls */
|
||||
priv->hdl.lock = &priv->lock;
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ static int ov7740_set_power(struct ov7740 *ov7740, int on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_core_ops ov7740_subdev_core_ops = {
|
||||
static const struct v4l2_subdev_core_ops ov7740_subdev_core_ops = {
|
||||
.log_status = v4l2_ctrl_subdev_log_status,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
.g_register = ov7740_get_register,
|
||||
|
|
@ -648,7 +648,7 @@ static int ov7740_s_frame_interval(struct v4l2_subdev *sd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
|
||||
static const struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
|
||||
.s_stream = ov7740_set_stream,
|
||||
.s_frame_interval = ov7740_s_frame_interval,
|
||||
.g_frame_interval = ov7740_g_frame_interval,
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ static const struct v4l2_dv_timings_cap tc358743_timings_cap = {
|
|||
/* keep this initialization for compatibility with GCC < 4.4.6 */
|
||||
.reserved = { 0 },
|
||||
/* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */
|
||||
V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000,
|
||||
V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1200, 13000000, 165000000,
|
||||
V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT |
|
||||
V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT,
|
||||
V4L2_DV_BT_CAP_PROGRESSIVE |
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
*
|
||||
* loudness - set between 0 and 15 for varying degrees of loudness effect
|
||||
*
|
||||
* maxvol - set maximium volume to +20db (1), default is 0db(0)
|
||||
* maxvol - set maximum volume to +20db (1), default is 0db(0)
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
|
@ -53,7 +53,7 @@ MODULE_PARM_DESC(debug, "Set debugging level from 0 to 3. Default is off(0).");
|
|||
module_param(loudness, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(loudness, "Turn loudness on(1) else off(0). Default is off(0).");
|
||||
module_param(maxvol, int, S_IRUGO | S_IWUSR);
|
||||
MODULE_PARM_DESC(maxvol, "Set maximium volume to +20dB(0) else +0dB(1). Default is +20dB(0).");
|
||||
MODULE_PARM_DESC(maxvol, "Set maximum volume to +20dB(0) else +0dB(1). Default is +20dB(0).");
|
||||
|
||||
|
||||
/* Structure of address and subaddresses for the tda7432 */
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ static const struct v4l2_dv_timings_cap ths8200_timings_cap = {
|
|||
.type = V4L2_DV_BT_656_1120,
|
||||
/* keep this initialization for compatibility with GCC < 4.4.6 */
|
||||
.reserved = { 0 },
|
||||
V4L2_INIT_BT_TIMINGS(0, 1920, 0, 1080, 25000000, 148500000,
|
||||
V4L2_INIT_BT_TIMINGS(640, 1920, 350, 1080, 25000000, 148500000,
|
||||
V4L2_DV_BT_STD_CEA861, V4L2_DV_BT_CAP_PROGRESSIVE)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1790,7 +1790,7 @@ static int tvp5150_probe(struct i2c_client *c,
|
|||
tvp5150_isr, IRQF_TRIGGER_HIGH |
|
||||
IRQF_ONESHOT, "tvp5150", core);
|
||||
if (res)
|
||||
return res;
|
||||
goto err;
|
||||
}
|
||||
|
||||
res = v4l2_async_register_subdev(sd);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
|
@ -38,7 +40,7 @@ struct video_i2c_buffer {
|
|||
};
|
||||
|
||||
struct video_i2c_data {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
const struct video_i2c_chip *chip;
|
||||
struct mutex lock;
|
||||
spinlock_t slock;
|
||||
|
|
@ -51,6 +53,8 @@ struct video_i2c_data {
|
|||
|
||||
struct task_struct *kthread_vid_cap;
|
||||
struct list_head vid_cap_active;
|
||||
|
||||
struct v4l2_fract frame_interval;
|
||||
};
|
||||
|
||||
static const struct v4l2_fmtdesc amg88xx_format = {
|
||||
|
|
@ -62,13 +66,20 @@ static const struct v4l2_frmsize_discrete amg88xx_size = {
|
|||
.height = 8,
|
||||
};
|
||||
|
||||
static const struct regmap_config amg88xx_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0xff
|
||||
};
|
||||
|
||||
struct video_i2c_chip {
|
||||
/* video dimensions */
|
||||
const struct v4l2_fmtdesc *format;
|
||||
const struct v4l2_frmsize_discrete *size;
|
||||
|
||||
/* max frames per second */
|
||||
unsigned int max_fps;
|
||||
/* available frame intervals */
|
||||
const struct v4l2_fract *frame_intervals;
|
||||
unsigned int num_frame_intervals;
|
||||
|
||||
/* pixel buffer size */
|
||||
unsigned int buffer_size;
|
||||
|
|
@ -76,33 +87,111 @@ struct video_i2c_chip {
|
|||
/* pixel size in bits */
|
||||
unsigned int bpp;
|
||||
|
||||
const struct regmap_config *regmap_config;
|
||||
|
||||
/* setup function */
|
||||
int (*setup)(struct video_i2c_data *data);
|
||||
|
||||
/* xfer function */
|
||||
int (*xfer)(struct video_i2c_data *data, char *buf);
|
||||
|
||||
/* power control function */
|
||||
int (*set_power)(struct video_i2c_data *data, bool on);
|
||||
|
||||
/* hwmon init function */
|
||||
int (*hwmon_init)(struct video_i2c_data *data);
|
||||
};
|
||||
|
||||
/* 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
|
||||
|
||||
static int amg88xx_xfer(struct video_i2c_data *data, char *buf)
|
||||
{
|
||||
struct i2c_client *client = data->client;
|
||||
struct i2c_msg msg[2];
|
||||
u8 reg = 0x80;
|
||||
return regmap_bulk_read(data->regmap, AMG88XX_REG_T01L, buf,
|
||||
data->chip->buffer_size);
|
||||
}
|
||||
|
||||
static int amg88xx_setup(struct video_i2c_data *data)
|
||||
{
|
||||
unsigned int mask = AMG88XX_FPSC_1FPS;
|
||||
unsigned int val;
|
||||
|
||||
if (data->frame_interval.numerator == data->frame_interval.denominator)
|
||||
val = mask;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
return regmap_update_bits(data->regmap, AMG88XX_REG_FPSC, mask, val);
|
||||
}
|
||||
|
||||
static int amg88xx_set_power_on(struct video_i2c_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
msg[0].addr = client->addr;
|
||||
msg[0].flags = 0;
|
||||
msg[0].len = 1;
|
||||
msg[0].buf = (char *)®
|
||||
ret = regmap_write(data->regmap, AMG88XX_REG_PCTL, AMG88XX_PCTL_NORMAL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msg[1].addr = client->addr;
|
||||
msg[1].flags = I2C_M_RD;
|
||||
msg[1].len = data->chip->buffer_size;
|
||||
msg[1].buf = (char *)buf;
|
||||
msleep(50);
|
||||
|
||||
ret = i2c_transfer(client->adapter, msg, 2);
|
||||
ret = regmap_write(data->regmap, AMG88XX_REG_RST, AMG88XX_RST_INIT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return (ret == 2) ? 0 : -EIO;
|
||||
usleep_range(2000, 3000);
|
||||
|
||||
ret = regmap_write(data->regmap, AMG88XX_REG_RST, AMG88XX_RST_FLAG);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Wait two frames before reading thermistor and temperature registers
|
||||
*/
|
||||
msleep(200);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amg88xx_set_power_off(struct video_i2c_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(data->regmap, AMG88XX_REG_PCTL, AMG88XX_PCTL_SLEEP);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* Wait for a while to avoid resuming normal mode immediately after
|
||||
* entering sleep mode, otherwise the device occasionally goes wrong
|
||||
* (thermistor and temperature registers are not updated at all)
|
||||
*/
|
||||
msleep(100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int amg88xx_set_power(struct video_i2c_data *data, bool on)
|
||||
{
|
||||
if (on)
|
||||
return amg88xx_set_power_on(data);
|
||||
|
||||
return amg88xx_set_power_off(data);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_HWMON)
|
||||
|
|
@ -133,11 +222,22 @@ static int amg88xx_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct video_i2c_data *data = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = data->client;
|
||||
int tmp = i2c_smbus_read_word_data(client, 0x0e);
|
||||
__le16 buf;
|
||||
int tmp;
|
||||
|
||||
if (tmp < 0)
|
||||
tmp = pm_runtime_get_sync(regmap_get_device(data->regmap));
|
||||
if (tmp < 0) {
|
||||
pm_runtime_put_noidle(regmap_get_device(data->regmap));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
tmp = regmap_bulk_read(data->regmap, AMG88XX_REG_TTHL, &buf, 2);
|
||||
pm_runtime_mark_last_busy(regmap_get_device(data->regmap));
|
||||
pm_runtime_put_autosuspend(regmap_get_device(data->regmap));
|
||||
if (tmp)
|
||||
return tmp;
|
||||
|
||||
tmp = le16_to_cpu(buf);
|
||||
|
||||
/*
|
||||
* Check for sign bit, this isn't a two's complement value but an
|
||||
|
|
@ -164,8 +264,9 @@ static const struct hwmon_chip_info amg88xx_chip_info = {
|
|||
|
||||
static int amg88xx_hwmon_init(struct video_i2c_data *data)
|
||||
{
|
||||
void *hwmon = devm_hwmon_device_register_with_info(&data->client->dev,
|
||||
"amg88xx", data, &amg88xx_chip_info, NULL);
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
void *hwmon = devm_hwmon_device_register_with_info(dev, "amg88xx", data,
|
||||
&amg88xx_chip_info, NULL);
|
||||
|
||||
return PTR_ERR_OR_ZERO(hwmon);
|
||||
}
|
||||
|
|
@ -175,14 +276,23 @@ static int amg88xx_hwmon_init(struct video_i2c_data *data)
|
|||
|
||||
#define AMG88XX 0
|
||||
|
||||
static const struct v4l2_fract amg88xx_frame_intervals[] = {
|
||||
{ 1, 10 },
|
||||
{ 1, 1 },
|
||||
};
|
||||
|
||||
static const struct video_i2c_chip video_i2c_chip[] = {
|
||||
[AMG88XX] = {
|
||||
.size = &amg88xx_size,
|
||||
.format = &amg88xx_format,
|
||||
.max_fps = 10,
|
||||
.frame_intervals = amg88xx_frame_intervals,
|
||||
.num_frame_intervals = ARRAY_SIZE(amg88xx_frame_intervals),
|
||||
.buffer_size = 128,
|
||||
.bpp = 16,
|
||||
.regmap_config = &amg88xx_regmap_config,
|
||||
.setup = &amg88xx_setup,
|
||||
.xfer = &amg88xx_xfer,
|
||||
.set_power = amg88xx_set_power,
|
||||
.hwmon_init = amg88xx_hwmon_init,
|
||||
},
|
||||
};
|
||||
|
|
@ -246,7 +356,8 @@ static void buffer_queue(struct vb2_buffer *vb)
|
|||
static int video_i2c_thread_vid_cap(void *priv)
|
||||
{
|
||||
struct video_i2c_data *data = priv;
|
||||
unsigned int delay = msecs_to_jiffies(1000 / data->chip->max_fps);
|
||||
unsigned int delay = mult_frac(HZ, data->frame_interval.numerator,
|
||||
data->frame_interval.denominator);
|
||||
|
||||
set_freezable();
|
||||
|
||||
|
|
@ -308,19 +419,36 @@ static void video_i2c_del_list(struct vb2_queue *vq, enum vb2_buffer_state state
|
|||
static int start_streaming(struct vb2_queue *vq, unsigned int count)
|
||||
{
|
||||
struct video_i2c_data *data = vb2_get_drv_priv(vq);
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
int ret;
|
||||
|
||||
if (data->kthread_vid_cap)
|
||||
return 0;
|
||||
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_noidle(dev);
|
||||
goto error_del_list;
|
||||
}
|
||||
|
||||
ret = data->chip->setup(data);
|
||||
if (ret)
|
||||
goto error_rpm_put;
|
||||
|
||||
data->sequence = 0;
|
||||
data->kthread_vid_cap = kthread_run(video_i2c_thread_vid_cap, data,
|
||||
"%s-vid-cap", data->v4l2_dev.name);
|
||||
if (!IS_ERR(data->kthread_vid_cap))
|
||||
ret = PTR_ERR_OR_ZERO(data->kthread_vid_cap);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
error_rpm_put:
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
error_del_list:
|
||||
video_i2c_del_list(vq, VB2_BUF_STATE_QUEUED);
|
||||
|
||||
return PTR_ERR(data->kthread_vid_cap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void stop_streaming(struct vb2_queue *vq)
|
||||
|
|
@ -332,11 +460,13 @@ static void stop_streaming(struct vb2_queue *vq)
|
|||
|
||||
kthread_stop(data->kthread_vid_cap);
|
||||
data->kthread_vid_cap = NULL;
|
||||
pm_runtime_mark_last_busy(regmap_get_device(data->regmap));
|
||||
pm_runtime_put_autosuspend(regmap_get_device(data->regmap));
|
||||
|
||||
video_i2c_del_list(vq, VB2_BUF_STATE_ERROR);
|
||||
}
|
||||
|
||||
static struct vb2_ops video_i2c_video_qops = {
|
||||
static const struct vb2_ops video_i2c_video_qops = {
|
||||
.queue_setup = queue_setup,
|
||||
.buf_prepare = buffer_prepare,
|
||||
.buf_queue = buffer_queue,
|
||||
|
|
@ -350,7 +480,8 @@ static int video_i2c_querycap(struct file *file, void *priv,
|
|||
struct v4l2_capability *vcap)
|
||||
{
|
||||
struct video_i2c_data *data = video_drvdata(file);
|
||||
struct i2c_client *client = data->client;
|
||||
struct device *dev = regmap_get_device(data->regmap);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
strscpy(vcap->driver, data->v4l2_dev.name, sizeof(vcap->driver));
|
||||
strscpy(vcap->card, data->vdev.name, sizeof(vcap->card));
|
||||
|
|
@ -426,15 +557,14 @@ static int video_i2c_enum_frameintervals(struct file *file, void *priv,
|
|||
const struct video_i2c_data *data = video_drvdata(file);
|
||||
const struct v4l2_frmsize_discrete *size = data->chip->size;
|
||||
|
||||
if (fe->index > 0)
|
||||
if (fe->index >= data->chip->num_frame_intervals)
|
||||
return -EINVAL;
|
||||
|
||||
if (fe->width != size->width || fe->height != size->height)
|
||||
return -EINVAL;
|
||||
|
||||
fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
|
||||
fe->discrete.numerator = 1;
|
||||
fe->discrete.denominator = data->chip->max_fps;
|
||||
fe->discrete = data->chip->frame_intervals[fe->index];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -479,12 +609,27 @@ static int video_i2c_g_parm(struct file *filp, void *priv,
|
|||
|
||||
parm->parm.capture.readbuffers = 1;
|
||||
parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
|
||||
parm->parm.capture.timeperframe.numerator = 1;
|
||||
parm->parm.capture.timeperframe.denominator = data->chip->max_fps;
|
||||
parm->parm.capture.timeperframe = data->frame_interval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int video_i2c_s_parm(struct file *filp, void *priv,
|
||||
struct v4l2_streamparm *parm)
|
||||
{
|
||||
struct video_i2c_data *data = video_drvdata(filp);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data->chip->num_frame_intervals - 1; i++) {
|
||||
if (V4L2_FRACT_COMPARE(parm->parm.capture.timeperframe, <=,
|
||||
data->chip->frame_intervals[i]))
|
||||
break;
|
||||
}
|
||||
data->frame_interval = data->chip->frame_intervals[i];
|
||||
|
||||
return video_i2c_g_parm(filp, priv, parm);
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops video_i2c_ioctl_ops = {
|
||||
.vidioc_querycap = video_i2c_querycap,
|
||||
.vidioc_g_input = video_i2c_g_input,
|
||||
|
|
@ -496,7 +641,7 @@ static const struct v4l2_ioctl_ops video_i2c_ioctl_ops = {
|
|||
.vidioc_g_fmt_vid_cap = video_i2c_try_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = video_i2c_s_fmt_vid_cap,
|
||||
.vidioc_g_parm = video_i2c_g_parm,
|
||||
.vidioc_s_parm = video_i2c_g_parm,
|
||||
.vidioc_s_parm = video_i2c_s_parm,
|
||||
.vidioc_try_fmt_vid_cap = video_i2c_try_fmt_vid_cap,
|
||||
.vidioc_reqbufs = vb2_ioctl_reqbufs,
|
||||
.vidioc_create_bufs = vb2_ioctl_create_bufs,
|
||||
|
|
@ -510,7 +655,13 @@ static const struct v4l2_ioctl_ops video_i2c_ioctl_ops = {
|
|||
|
||||
static void video_i2c_release(struct video_device *vdev)
|
||||
{
|
||||
kfree(video_get_drvdata(vdev));
|
||||
struct video_i2c_data *data = video_get_drvdata(vdev);
|
||||
|
||||
v4l2_device_unregister(&data->v4l2_dev);
|
||||
mutex_destroy(&data->lock);
|
||||
mutex_destroy(&data->queue_lock);
|
||||
regmap_exit(data->regmap);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static int video_i2c_probe(struct i2c_client *client,
|
||||
|
|
@ -532,13 +683,18 @@ static int video_i2c_probe(struct i2c_client *client,
|
|||
else
|
||||
goto error_free_device;
|
||||
|
||||
data->client = client;
|
||||
data->regmap = regmap_init_i2c(client, data->chip->regmap_config);
|
||||
if (IS_ERR(data->regmap)) {
|
||||
ret = PTR_ERR(data->regmap);
|
||||
goto error_free_device;
|
||||
}
|
||||
|
||||
v4l2_dev = &data->v4l2_dev;
|
||||
strscpy(v4l2_dev->name, VIDEO_I2C_DRIVER, sizeof(v4l2_dev->name));
|
||||
|
||||
ret = v4l2_device_register(&client->dev, v4l2_dev);
|
||||
if (ret < 0)
|
||||
goto error_free_device;
|
||||
goto error_regmap_exit;
|
||||
|
||||
mutex_init(&data->lock);
|
||||
mutex_init(&data->queue_lock);
|
||||
|
|
@ -575,9 +731,23 @@ static int video_i2c_probe(struct i2c_client *client,
|
|||
spin_lock_init(&data->slock);
|
||||
INIT_LIST_HEAD(&data->vid_cap_active);
|
||||
|
||||
data->frame_interval = data->chip->frame_intervals[0];
|
||||
|
||||
video_set_drvdata(&data->vdev, data);
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
if (data->chip->set_power) {
|
||||
ret = data->chip->set_power(data, true);
|
||||
if (ret)
|
||||
goto error_unregister_device;
|
||||
}
|
||||
|
||||
pm_runtime_get_noresume(&client->dev);
|
||||
pm_runtime_set_active(&client->dev);
|
||||
pm_runtime_enable(&client->dev);
|
||||
pm_runtime_set_autosuspend_delay(&client->dev, 2000);
|
||||
pm_runtime_use_autosuspend(&client->dev);
|
||||
|
||||
if (data->chip->hwmon_init) {
|
||||
ret = data->chip->hwmon_init(data);
|
||||
if (ret < 0) {
|
||||
|
|
@ -588,15 +758,29 @@ static int video_i2c_probe(struct i2c_client *client,
|
|||
|
||||
ret = video_register_device(&data->vdev, VFL_TYPE_GRABBER, -1);
|
||||
if (ret < 0)
|
||||
goto error_unregister_device;
|
||||
goto error_pm_disable;
|
||||
|
||||
pm_runtime_mark_last_busy(&client->dev);
|
||||
pm_runtime_put_autosuspend(&client->dev);
|
||||
|
||||
return 0;
|
||||
|
||||
error_pm_disable:
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
if (data->chip->set_power)
|
||||
data->chip->set_power(data, false);
|
||||
|
||||
error_unregister_device:
|
||||
v4l2_device_unregister(v4l2_dev);
|
||||
mutex_destroy(&data->lock);
|
||||
mutex_destroy(&data->queue_lock);
|
||||
|
||||
error_regmap_exit:
|
||||
regmap_exit(data->regmap);
|
||||
|
||||
error_free_device:
|
||||
kfree(data);
|
||||
|
||||
|
|
@ -607,15 +791,48 @@ static int video_i2c_remove(struct i2c_client *client)
|
|||
{
|
||||
struct video_i2c_data *data = i2c_get_clientdata(client);
|
||||
|
||||
video_unregister_device(&data->vdev);
|
||||
v4l2_device_unregister(&data->v4l2_dev);
|
||||
pm_runtime_get_sync(&client->dev);
|
||||
pm_runtime_disable(&client->dev);
|
||||
pm_runtime_set_suspended(&client->dev);
|
||||
pm_runtime_put_noidle(&client->dev);
|
||||
|
||||
mutex_destroy(&data->lock);
|
||||
mutex_destroy(&data->queue_lock);
|
||||
if (data->chip->set_power)
|
||||
data->chip->set_power(data, false);
|
||||
|
||||
video_unregister_device(&data->vdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int video_i2c_pm_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct video_i2c_data *data = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
||||
if (!data->chip->set_power)
|
||||
return 0;
|
||||
|
||||
return data->chip->set_power(data, false);
|
||||
}
|
||||
|
||||
static int video_i2c_pm_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct video_i2c_data *data = i2c_get_clientdata(to_i2c_client(dev));
|
||||
|
||||
if (!data->chip->set_power)
|
||||
return 0;
|
||||
|
||||
return data->chip->set_power(data, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops video_i2c_pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(video_i2c_pm_runtime_suspend,
|
||||
video_i2c_pm_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static const struct i2c_device_id video_i2c_id_table[] = {
|
||||
{ "amg88xx", AMG88XX },
|
||||
{}
|
||||
|
|
@ -632,6 +849,7 @@ static struct i2c_driver video_i2c_driver = {
|
|||
.driver = {
|
||||
.name = VIDEO_I2C_DRIVER,
|
||||
.of_match_table = video_i2c_of_match,
|
||||
.pm = &video_i2c_pm_ops,
|
||||
},
|
||||
.probe = video_i2c_probe,
|
||||
.remove = video_i2c_remove,
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ int flexcop_dma_allocate(struct pci_dev *pdev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((tcpu = pci_alloc_consistent(pdev, size, &tdma)) != NULL) {
|
||||
tcpu = pci_alloc_consistent(pdev, size, &tdma);
|
||||
if (tcpu != NULL) {
|
||||
dma->pdev = pdev;
|
||||
dma->cpu_addr0 = tcpu;
|
||||
dma->dma_addr0 = tdma;
|
||||
|
|
@ -34,7 +35,7 @@ void flexcop_dma_free(struct flexcop_dma *dma)
|
|||
{
|
||||
pci_free_consistent(dma->pdev, dma->size*2,
|
||||
dma->cpu_addr0, dma->dma_addr0);
|
||||
memset(dma,0,sizeof(struct flexcop_dma));
|
||||
memset(dma, 0, sizeof(struct flexcop_dma));
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_free);
|
||||
|
||||
|
|
@ -42,23 +43,24 @@ int flexcop_dma_config(struct flexcop_device *fc,
|
|||
struct flexcop_dma *dma,
|
||||
flexcop_dma_index_t dma_idx)
|
||||
{
|
||||
flexcop_ibi_value v0x0,v0x4,v0xc;
|
||||
v0x0.raw = v0x4.raw = v0xc.raw = 0;
|
||||
flexcop_ibi_value v0x0, v0x4, v0xc;
|
||||
|
||||
v0x0.raw = v0x4.raw = v0xc.raw = 0;
|
||||
v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
|
||||
v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
|
||||
v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
|
||||
|
||||
if ((dma_idx & FC_DMA_1) == dma_idx) {
|
||||
fc->write_ibi_reg(fc,dma1_000,v0x0);
|
||||
fc->write_ibi_reg(fc,dma1_004,v0x4);
|
||||
fc->write_ibi_reg(fc,dma1_00c,v0xc);
|
||||
fc->write_ibi_reg(fc, dma1_000, v0x0);
|
||||
fc->write_ibi_reg(fc, dma1_004, v0x4);
|
||||
fc->write_ibi_reg(fc, dma1_00c, v0xc);
|
||||
} else if ((dma_idx & FC_DMA_2) == dma_idx) {
|
||||
fc->write_ibi_reg(fc,dma2_010,v0x0);
|
||||
fc->write_ibi_reg(fc,dma2_014,v0x4);
|
||||
fc->write_ibi_reg(fc,dma2_01c,v0xc);
|
||||
fc->write_ibi_reg(fc, dma2_010, v0x0);
|
||||
fc->write_ibi_reg(fc, dma2_014, v0x4);
|
||||
fc->write_ibi_reg(fc, dma2_01c, v0xc);
|
||||
} else {
|
||||
err("either DMA1 or DMA2 can be configured within one flexcop_dma_config call.");
|
||||
err("either DMA1 or DMA2 can be configured within one %s call.",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -72,8 +74,8 @@ int flexcop_dma_xfer_control(struct flexcop_device *fc,
|
|||
flexcop_dma_addr_index_t index,
|
||||
int onoff)
|
||||
{
|
||||
flexcop_ibi_value v0x0,v0xc;
|
||||
flexcop_ibi_register r0x0,r0xc;
|
||||
flexcop_ibi_value v0x0, v0xc;
|
||||
flexcop_ibi_register r0x0, r0xc;
|
||||
|
||||
if ((dma_idx & FC_DMA_1) == dma_idx) {
|
||||
r0x0 = dma1_000;
|
||||
|
|
@ -82,15 +84,16 @@ int flexcop_dma_xfer_control(struct flexcop_device *fc,
|
|||
r0x0 = dma2_010;
|
||||
r0xc = dma2_01c;
|
||||
} else {
|
||||
err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call.");
|
||||
err("transfer DMA1 or DMA2 can be started within one %s call.",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
v0x0 = fc->read_ibi_reg(fc,r0x0);
|
||||
v0xc = fc->read_ibi_reg(fc,r0xc);
|
||||
v0x0 = fc->read_ibi_reg(fc, r0x0);
|
||||
v0xc = fc->read_ibi_reg(fc, r0xc);
|
||||
|
||||
deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
|
||||
deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
|
||||
deb_rdump("reg: %03x: %x\n", r0x0, v0x0.raw);
|
||||
deb_rdump("reg: %03x: %x\n", r0xc, v0xc.raw);
|
||||
|
||||
if (index & FC_DMA_SUBADDR_0)
|
||||
v0x0.dma_0x0.dma_0start = onoff;
|
||||
|
|
@ -98,11 +101,11 @@ int flexcop_dma_xfer_control(struct flexcop_device *fc,
|
|||
if (index & FC_DMA_SUBADDR_1)
|
||||
v0xc.dma_0xc.dma_1start = onoff;
|
||||
|
||||
fc->write_ibi_reg(fc,r0x0,v0x0);
|
||||
fc->write_ibi_reg(fc,r0xc,v0xc);
|
||||
fc->write_ibi_reg(fc, r0x0, v0x0);
|
||||
fc->write_ibi_reg(fc, r0xc, v0xc);
|
||||
|
||||
deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
|
||||
deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
|
||||
deb_rdump("reg: %03x: %x\n", r0x0, v0x0.raw);
|
||||
deb_rdump("reg: %03x: %x\n", r0xc, v0xc.raw);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_xfer_control);
|
||||
|
|
@ -112,10 +115,11 @@ static int flexcop_dma_remap(struct flexcop_device *fc,
|
|||
int onoff)
|
||||
{
|
||||
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
|
||||
deb_info("%s\n",__func__);
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc, r);
|
||||
|
||||
deb_info("%s\n", __func__);
|
||||
v.dma_0xc.remap_enable = onoff;
|
||||
fc->write_ibi_reg(fc,r,v);
|
||||
fc->write_ibi_reg(fc, r, v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +127,7 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc,
|
|||
flexcop_dma_index_t no,
|
||||
int onoff)
|
||||
{
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc, ctrl_208);
|
||||
|
||||
if (no & FC_DMA_1)
|
||||
v.ctrl_208.DMA1_IRQ_Enable_sig = onoff;
|
||||
|
|
@ -131,7 +135,7 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc,
|
|||
if (no & FC_DMA_2)
|
||||
v.ctrl_208.DMA2_IRQ_Enable_sig = onoff;
|
||||
|
||||
fc->write_ibi_reg(fc,ctrl_208,v);
|
||||
fc->write_ibi_reg(fc, ctrl_208, v);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_control_size_irq);
|
||||
|
|
@ -140,7 +144,7 @@ int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
|
|||
flexcop_dma_index_t no,
|
||||
int onoff)
|
||||
{
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc, ctrl_208);
|
||||
|
||||
if (no & FC_DMA_1)
|
||||
v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
|
||||
|
|
@ -148,7 +152,7 @@ int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
|
|||
if (no & FC_DMA_2)
|
||||
v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
|
||||
|
||||
fc->write_ibi_reg(fc,ctrl_208,v);
|
||||
fc->write_ibi_reg(fc, ctrl_208, v);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
|
||||
|
|
@ -158,13 +162,13 @@ int flexcop_dma_config_timer(struct flexcop_device *fc,
|
|||
flexcop_dma_index_t dma_idx, u8 cycles)
|
||||
{
|
||||
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
|
||||
flexcop_ibi_value v = fc->read_ibi_reg(fc, r);
|
||||
|
||||
flexcop_dma_remap(fc,dma_idx,0);
|
||||
flexcop_dma_remap(fc, dma_idx, 0);
|
||||
|
||||
deb_info("%s\n",__func__);
|
||||
deb_info("%s\n", __func__);
|
||||
v.dma_0x4_write.dmatimer = cycles;
|
||||
fc->write_ibi_reg(fc,r,v);
|
||||
fc->write_ibi_reg(fc, r, v);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(flexcop_dma_config_timer);
|
||||
|
|
|
|||
|
|
@ -2792,19 +2792,17 @@ static int bttv_g_tuner(struct file *file, void *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bttv_cropcap(struct file *file, void *priv,
|
||||
struct v4l2_cropcap *cap)
|
||||
static int bttv_g_pixelaspect(struct file *file, void *priv,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct bttv_fh *fh = priv;
|
||||
struct bttv *btv = fh->btv;
|
||||
|
||||
if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
|
||||
cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
|
||||
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
/* defrect and bounds are set via g_selection */
|
||||
cap->pixelaspect = bttv_tvnorms[btv->tvnorm].cropcap.pixelaspect;
|
||||
|
||||
*f = bttv_tvnorms[btv->tvnorm].cropcap.pixelaspect;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3162,7 +3160,7 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
|
|||
.vidioc_g_fmt_vbi_cap = bttv_g_fmt_vbi_cap,
|
||||
.vidioc_try_fmt_vbi_cap = bttv_try_fmt_vbi_cap,
|
||||
.vidioc_s_fmt_vbi_cap = bttv_s_fmt_vbi_cap,
|
||||
.vidioc_cropcap = bttv_cropcap,
|
||||
.vidioc_g_pixelaspect = bttv_g_pixelaspect,
|
||||
.vidioc_reqbufs = bttv_reqbufs,
|
||||
.vidioc_querybuf = bttv_querybuf,
|
||||
.vidioc_qbuf = bttv_qbuf,
|
||||
|
|
|
|||
|
|
@ -1077,33 +1077,65 @@ static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cobalt_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cc)
|
||||
static int cobalt_g_pixelaspect(struct file *file, void *fh,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct cobalt_stream *s = video_drvdata(file);
|
||||
struct v4l2_dv_timings timings;
|
||||
int err = 0;
|
||||
|
||||
if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
if (s->input == 1)
|
||||
timings = cea1080p60;
|
||||
else
|
||||
err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings);
|
||||
if (!err) {
|
||||
cc->bounds.width = cc->defrect.width = timings.bt.width;
|
||||
cc->bounds.height = cc->defrect.height = timings.bt.height;
|
||||
cc->pixelaspect = v4l2_dv_timings_aspect_ratio(&timings);
|
||||
}
|
||||
if (!err)
|
||||
*f = v4l2_dv_timings_aspect_ratio(&timings);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cobalt_g_selection(struct file *file, void *fh,
|
||||
struct v4l2_selection *sel)
|
||||
{
|
||||
struct cobalt_stream *s = video_drvdata(file);
|
||||
struct v4l2_dv_timings timings;
|
||||
int err = 0;
|
||||
|
||||
if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
if (s->input == 1)
|
||||
timings = cea1080p60;
|
||||
else
|
||||
err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (sel->target) {
|
||||
case V4L2_SEL_TGT_CROP_BOUNDS:
|
||||
case V4L2_SEL_TGT_CROP_DEFAULT:
|
||||
sel->r.top = 0;
|
||||
sel->r.left = 0;
|
||||
sel->r.width = timings.bt.width;
|
||||
sel->r.height = timings.bt.height;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops cobalt_ioctl_ops = {
|
||||
.vidioc_querycap = cobalt_querycap,
|
||||
.vidioc_g_parm = cobalt_g_parm,
|
||||
.vidioc_log_status = cobalt_log_status,
|
||||
.vidioc_streamon = vb2_ioctl_streamon,
|
||||
.vidioc_streamoff = vb2_ioctl_streamoff,
|
||||
.vidioc_cropcap = cobalt_cropcap,
|
||||
.vidioc_g_pixelaspect = cobalt_g_pixelaspect,
|
||||
.vidioc_g_selection = cobalt_g_selection,
|
||||
.vidioc_enum_input = cobalt_enum_input,
|
||||
.vidioc_g_input = cobalt_g_input,
|
||||
.vidioc_s_input = cobalt_s_input,
|
||||
|
|
|
|||
|
|
@ -441,15 +441,16 @@ static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
|
|||
return cx18_get_input(cx, vin->index, vin);
|
||||
}
|
||||
|
||||
static int cx18_cropcap(struct file *file, void *fh,
|
||||
struct v4l2_cropcap *cropcap)
|
||||
static int cx18_g_pixelaspect(struct file *file, void *fh,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct cx18 *cx = fh2id(fh)->cx;
|
||||
|
||||
if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
cropcap->pixelaspect.numerator = cx->is_50hz ? 54 : 11;
|
||||
cropcap->pixelaspect.denominator = cx->is_50hz ? 59 : 10;
|
||||
|
||||
f->numerator = cx->is_50hz ? 54 : 11;
|
||||
f->denominator = cx->is_50hz ? 59 : 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1079,7 +1080,7 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
|
|||
.vidioc_g_audio = cx18_g_audio,
|
||||
.vidioc_enumaudio = cx18_enumaudio,
|
||||
.vidioc_enum_input = cx18_enum_input,
|
||||
.vidioc_cropcap = cx18_cropcap,
|
||||
.vidioc_g_pixelaspect = cx18_g_pixelaspect,
|
||||
.vidioc_g_selection = cx18_g_selection,
|
||||
.vidioc_g_input = cx18_g_input,
|
||||
.vidioc_s_input = cx18_s_input,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/moduleparam.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
@ -41,6 +42,18 @@ MODULE_AUTHOR("Steven Toth <[email protected]>");
|
|||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(CX23885_VERSION);
|
||||
|
||||
/*
|
||||
* Some platforms have been found to require periodic resetting of the DMA
|
||||
* engine. Ryzen and XEON platforms are known to be affected. The symptom
|
||||
* encountered is "mpeg risc op code error". Only Ryzen platforms employ
|
||||
* this workaround if the option equals 1. The workaround can be explicitly
|
||||
* disabled for all platforms by setting to 0, the workaround can be forced
|
||||
* on for any platform by setting to 2.
|
||||
*/
|
||||
static unsigned int dma_reset_workaround = 1;
|
||||
module_param(dma_reset_workaround, int, 0644);
|
||||
MODULE_PARM_DESC(dma_reset_workaround, "periodic RiSC dma engine reset; 0-force disable, 1-driver detect (default), 2-force enable");
|
||||
|
||||
static unsigned int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "enable debug messages");
|
||||
|
|
@ -603,8 +616,13 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port,
|
|||
|
||||
static void cx23885_clear_bridge_error(struct cx23885_dev *dev)
|
||||
{
|
||||
uint32_t reg1_val = cx_read(TC_REQ); /* read-only */
|
||||
uint32_t reg2_val = cx_read(TC_REQ_SET);
|
||||
uint32_t reg1_val, reg2_val;
|
||||
|
||||
if (!dev->need_dma_reset)
|
||||
return;
|
||||
|
||||
reg1_val = cx_read(TC_REQ); /* read-only */
|
||||
reg2_val = cx_read(TC_REQ_SET);
|
||||
|
||||
if (reg1_val && reg2_val) {
|
||||
cx_write(TC_REQ, reg1_val);
|
||||
|
|
@ -2058,6 +2076,37 @@ void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput)
|
|||
/* TODO: 23-19 */
|
||||
}
|
||||
|
||||
static struct {
|
||||
int vendor, dev;
|
||||
} const broken_dev_id[] = {
|
||||
/* According with
|
||||
* https://openbenchmarking.org/system/1703021-RI-AMDZEN08075/Ryzen%207%201800X/lspci,
|
||||
* 0x1451 is PCI ID for the IOMMU found on Ryzen
|
||||
*/
|
||||
{ PCI_VENDOR_ID_AMD, 0x1451 },
|
||||
};
|
||||
|
||||
static bool cx23885_does_need_dma_reset(void)
|
||||
{
|
||||
int i;
|
||||
struct pci_dev *pdev = NULL;
|
||||
|
||||
if (dma_reset_workaround == 0)
|
||||
return false;
|
||||
else if (dma_reset_workaround == 2)
|
||||
return true;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(broken_dev_id); i++) {
|
||||
pdev = pci_get_device(broken_dev_id[i].vendor,
|
||||
broken_dev_id[i].dev, NULL);
|
||||
if (pdev) {
|
||||
pci_dev_put(pdev);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int cx23885_initdev(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
|
|
@ -2069,6 +2118,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
|
|||
if (NULL == dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->need_dma_reset = cx23885_does_need_dma_reset();
|
||||
|
||||
err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev);
|
||||
if (err < 0)
|
||||
goto fail_free;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
#include "cx23885.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/io.h>
|
||||
|
|
|
|||
|
|
@ -668,26 +668,43 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_cropcap(struct file *file, void *priv,
|
||||
struct v4l2_cropcap *cc)
|
||||
static int vidioc_g_pixelaspect(struct file *file, void *priv,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
bool is_50hz = dev->tvnorm & V4L2_STD_625_50;
|
||||
|
||||
if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
cc->bounds.left = 0;
|
||||
cc->bounds.top = 0;
|
||||
cc->bounds.width = 720;
|
||||
cc->bounds.height = norm_maxh(dev->tvnorm);
|
||||
cc->defrect = cc->bounds;
|
||||
cc->pixelaspect.numerator = is_50hz ? 54 : 11;
|
||||
cc->pixelaspect.denominator = is_50hz ? 59 : 10;
|
||||
f->numerator = is_50hz ? 54 : 11;
|
||||
f->denominator = is_50hz ? 59 : 10;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_selection(struct file *file, void *fh,
|
||||
struct v4l2_selection *sel)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
|
||||
if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
switch (sel->target) {
|
||||
case V4L2_SEL_TGT_CROP_BOUNDS:
|
||||
case V4L2_SEL_TGT_CROP_DEFAULT:
|
||||
sel->r.top = 0;
|
||||
sel->r.left = 0;
|
||||
sel->r.width = 720;
|
||||
sel->r.height = norm_maxh(dev->tvnorm);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
|
||||
{
|
||||
struct cx23885_dev *dev = video_drvdata(file);
|
||||
|
|
@ -1122,7 +1139,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|||
.vidioc_dqbuf = vb2_ioctl_dqbuf,
|
||||
.vidioc_streamon = vb2_ioctl_streamon,
|
||||
.vidioc_streamoff = vb2_ioctl_streamoff,
|
||||
.vidioc_cropcap = vidioc_cropcap,
|
||||
.vidioc_g_pixelaspect = vidioc_g_pixelaspect,
|
||||
.vidioc_g_selection = vidioc_g_selection,
|
||||
.vidioc_s_std = vidioc_s_std,
|
||||
.vidioc_g_std = vidioc_g_std,
|
||||
.vidioc_enum_input = vidioc_enum_input,
|
||||
|
|
|
|||
|
|
@ -451,6 +451,8 @@ struct cx23885_dev {
|
|||
/* Analog raw audio */
|
||||
struct cx23885_audio_dev *audio_dev;
|
||||
|
||||
/* Does the system require periodic DMA resets? */
|
||||
unsigned int need_dma_reset:1;
|
||||
};
|
||||
|
||||
static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev)
|
||||
|
|
|
|||
|
|
@ -18,47 +18,43 @@
|
|||
#ifndef _DDBRIDGE_H_
|
||||
#define _DDBRIDGE_H_
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dvb/ca.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/swab.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/dvb/ca.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <media/dmxdev.h>
|
||||
#include <media/dvbdev.h>
|
||||
#include <media/dvb_demux.h>
|
||||
#include <media/dvb_frontend.h>
|
||||
#include <media/dvb_ringbuffer.h>
|
||||
#include <media/dvb_ca_en50221.h>
|
||||
#include <media/dvb_demux.h>
|
||||
#include <media/dvbdev.h>
|
||||
#include <media/dvb_frontend.h>
|
||||
#include <media/dvb_net.h>
|
||||
#include <media/dvb_ringbuffer.h>
|
||||
|
||||
#define DDBRIDGE_VERSION "0.9.33-integrated"
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@
|
|||
#define CIO2_PCI_ID 0x9d32
|
||||
#define CIO2_PCI_BAR 0
|
||||
#define CIO2_DMA_MASK DMA_BIT_MASK(39)
|
||||
#define CIO2_IMAGE_MAX_WIDTH 4224
|
||||
#define CIO2_IMAGE_MAX_LENGTH 3136
|
||||
|
||||
#define CIO2_IMAGE_MAX_WIDTH 4224
|
||||
#define CIO2_IMAGE_MAX_LENGTH 3136
|
||||
|
|
|
|||
|
|
@ -829,17 +829,18 @@ static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vou
|
|||
return ivtv_get_output(itv, vout->index, vout);
|
||||
}
|
||||
|
||||
static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
|
||||
static int ivtv_g_pixelaspect(struct file *file, void *fh,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct ivtv_open_id *id = fh2id(fh);
|
||||
struct ivtv *itv = id->itv;
|
||||
|
||||
if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
||||
cropcap->pixelaspect.numerator = itv->is_50hz ? 54 : 11;
|
||||
cropcap->pixelaspect.denominator = itv->is_50hz ? 59 : 10;
|
||||
} else if (cropcap->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
||||
cropcap->pixelaspect.numerator = itv->is_out_50hz ? 54 : 11;
|
||||
cropcap->pixelaspect.denominator = itv->is_out_50hz ? 59 : 10;
|
||||
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
||||
f->numerator = itv->is_50hz ? 54 : 11;
|
||||
f->denominator = itv->is_50hz ? 59 : 10;
|
||||
} else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
||||
f->numerator = itv->is_out_50hz ? 54 : 11;
|
||||
f->denominator = itv->is_out_50hz ? 59 : 10;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1923,7 +1924,7 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
|
|||
.vidioc_enum_input = ivtv_enum_input,
|
||||
.vidioc_enum_output = ivtv_enum_output,
|
||||
.vidioc_enumaudout = ivtv_enumaudout,
|
||||
.vidioc_cropcap = ivtv_cropcap,
|
||||
.vidioc_g_pixelaspect = ivtv_g_pixelaspect,
|
||||
.vidioc_s_selection = ivtv_s_selection,
|
||||
.vidioc_g_selection = ivtv_g_selection,
|
||||
.vidioc_g_input = ivtv_g_input,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
|
|||
|
|
@ -1419,8 +1419,8 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
|
|||
del_timer(&dev->vbi_q.timeout);
|
||||
del_timer(&dev->ts_q.timeout);
|
||||
|
||||
if (dev->remote)
|
||||
saa7134_ir_stop(dev);
|
||||
if (dev->remote && dev->remote->dev->users)
|
||||
saa7134_ir_close(dev->remote->dev);
|
||||
|
||||
pci_save_state(pci_dev);
|
||||
pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
|
||||
|
|
@ -1447,8 +1447,8 @@ static int saa7134_resume(struct pci_dev *pci_dev)
|
|||
saa7134_videoport_init(dev);
|
||||
if (card_has_mpeg(dev))
|
||||
saa7134_ts_init_hw(dev);
|
||||
if (dev->remote)
|
||||
saa7134_ir_start(dev);
|
||||
if (dev->remote && dev->remote->dev->users)
|
||||
saa7134_ir_open(dev->remote->dev);
|
||||
saa7134_hw_enable1(dev);
|
||||
|
||||
msleep(100);
|
||||
|
|
|
|||
|
|
@ -299,43 +299,6 @@ static int get_key_purpletv(struct IR_i2c *ir, enum rc_proto *protocol,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int get_key_hvr1110(struct IR_i2c *ir, enum rc_proto *protocol,
|
||||
u32 *scancode, u8 *toggle)
|
||||
{
|
||||
int rc;
|
||||
unsigned char buf[5];
|
||||
|
||||
/* poll IR chip */
|
||||
rc = i2c_master_recv(ir->c, buf, 5);
|
||||
if (rc != 5) {
|
||||
ir_dbg(ir, "read error\n");
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Check if some key were pressed */
|
||||
if (!(buf[0] & 0x80))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* buf[3] & 0x80 is always high.
|
||||
* buf[3] & 0x40 is a parity bit. A repeat event is marked
|
||||
* by preserving it into two separate readings
|
||||
* buf[4] bits 0 and 1, and buf[1] and buf[2] are always
|
||||
* zero.
|
||||
*
|
||||
* Note that the keymap which the hvr1110 uses is RC5.
|
||||
*
|
||||
* FIXME: start bits could maybe be used...?
|
||||
*/
|
||||
*protocol = RC_PROTO_RC5;
|
||||
*scancode = RC_SCANCODE_RC5(buf[3] & 0x1f, buf[4] >> 2);
|
||||
*toggle = !!(buf[3] & 0x40);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_proto *protocol,
|
||||
u32 *scancode, u8 *toggle)
|
||||
{
|
||||
|
|
@ -485,17 +448,10 @@ static void saa7134_input_timer(struct timer_list *t)
|
|||
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
|
||||
}
|
||||
|
||||
static int __saa7134_ir_start(void *priv)
|
||||
int saa7134_ir_open(struct rc_dev *rc)
|
||||
{
|
||||
struct saa7134_dev *dev = priv;
|
||||
struct saa7134_card_ir *ir;
|
||||
|
||||
if (!dev || !dev->remote)
|
||||
return -EINVAL;
|
||||
|
||||
ir = dev->remote;
|
||||
if (ir->running)
|
||||
return 0;
|
||||
struct saa7134_dev *dev = rc->priv;
|
||||
struct saa7134_card_ir *ir = dev->remote;
|
||||
|
||||
/* Moved here from saa7134_input_init1() because the latter
|
||||
* is not called on device resume */
|
||||
|
|
@ -544,55 +500,15 @@ static int __saa7134_ir_start(void *priv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void __saa7134_ir_stop(void *priv)
|
||||
void saa7134_ir_close(struct rc_dev *rc)
|
||||
{
|
||||
struct saa7134_dev *dev = priv;
|
||||
struct saa7134_card_ir *ir;
|
||||
|
||||
if (!dev || !dev->remote)
|
||||
return;
|
||||
|
||||
ir = dev->remote;
|
||||
if (!ir->running)
|
||||
return;
|
||||
struct saa7134_dev *dev = rc->priv;
|
||||
struct saa7134_card_ir *ir = dev->remote;
|
||||
|
||||
if (ir->polling)
|
||||
del_timer_sync(&ir->timer);
|
||||
|
||||
ir->running = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int saa7134_ir_start(struct saa7134_dev *dev)
|
||||
{
|
||||
if (dev->remote->users)
|
||||
return __saa7134_ir_start(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void saa7134_ir_stop(struct saa7134_dev *dev)
|
||||
{
|
||||
if (dev->remote->users)
|
||||
__saa7134_ir_stop(dev);
|
||||
}
|
||||
|
||||
static int saa7134_ir_open(struct rc_dev *rc)
|
||||
{
|
||||
struct saa7134_dev *dev = rc->priv;
|
||||
|
||||
dev->remote->users++;
|
||||
return __saa7134_ir_start(dev);
|
||||
}
|
||||
|
||||
static void saa7134_ir_close(struct rc_dev *rc)
|
||||
{
|
||||
struct saa7134_dev *dev = rc->priv;
|
||||
|
||||
dev->remote->users--;
|
||||
if (!dev->remote->users)
|
||||
__saa7134_ir_stop(dev);
|
||||
}
|
||||
|
||||
int saa7134_input_init1(struct saa7134_dev *dev)
|
||||
|
|
@ -661,7 +577,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
|
|||
mask_keycode = 0x0007C8;
|
||||
mask_keydown = 0x000010;
|
||||
polling = 50; // ms
|
||||
/* GPIO stuff moved to __saa7134_ir_start() */
|
||||
/* GPIO stuff moved to saa7134_ir_open() */
|
||||
break;
|
||||
case SAA7134_BOARD_AVERMEDIA_M135A:
|
||||
ir_codes = RC_MAP_AVERMEDIA_M135A;
|
||||
|
|
@ -683,14 +599,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
|
|||
mask_keycode = 0x02F200;
|
||||
mask_keydown = 0x000400;
|
||||
polling = 50; // ms
|
||||
/* GPIO stuff moved to __saa7134_ir_start() */
|
||||
/* GPIO stuff moved to saa7134_ir_open() */
|
||||
break;
|
||||
case SAA7134_BOARD_AVERMEDIA_A16D:
|
||||
ir_codes = RC_MAP_AVERMEDIA_A16D;
|
||||
mask_keycode = 0x02F200;
|
||||
mask_keydown = 0x000400;
|
||||
polling = 50; /* ms */
|
||||
/* GPIO stuff moved to __saa7134_ir_start() */
|
||||
/* GPIO stuff moved to saa7134_ir_open() */
|
||||
break;
|
||||
case SAA7134_BOARD_KWORLD_TERMINATOR:
|
||||
ir_codes = RC_MAP_PIXELVIEW;
|
||||
|
|
@ -742,7 +658,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
|
|||
mask_keycode = 0x0003CC;
|
||||
mask_keydown = 0x000010;
|
||||
polling = 5; /* ms */
|
||||
/* GPIO stuff moved to __saa7134_ir_start() */
|
||||
/* GPIO stuff moved to saa7134_ir_open() */
|
||||
break;
|
||||
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
|
||||
case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
|
||||
|
|
@ -880,8 +796,6 @@ int saa7134_input_init1(struct saa7134_dev *dev)
|
|||
ir->raw_decode = raw_decode;
|
||||
|
||||
/* init input device */
|
||||
snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)",
|
||||
saa7134_boards[dev->board].name);
|
||||
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
|
||||
pci_name(dev->pci));
|
||||
|
||||
|
|
@ -893,7 +807,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
|
|||
rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
|
||||
}
|
||||
|
||||
rc->device_name = ir->name;
|
||||
rc->device_name = saa7134_boards[dev->board].name;
|
||||
rc->input_phys = ir->phys;
|
||||
rc->input_id.bustype = BUS_PCI;
|
||||
rc->input_id.version = 1;
|
||||
|
|
@ -929,7 +843,6 @@ void saa7134_input_fini(struct saa7134_dev *dev)
|
|||
if (NULL == dev->remote)
|
||||
return;
|
||||
|
||||
saa7134_ir_stop(dev);
|
||||
rc_unregister_device(dev->remote->dev);
|
||||
kfree(dev->remote);
|
||||
dev->remote = NULL;
|
||||
|
|
@ -1031,9 +944,11 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
|
|||
(1 == rc) ? "yes" : "no");
|
||||
break;
|
||||
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
|
||||
dev->init_data.name = "HVR 1110";
|
||||
dev->init_data.get_key = get_key_hvr1110;
|
||||
dev->init_data.name = saa7134_boards[dev->board].name;
|
||||
dev->init_data.ir_codes = RC_MAP_HAUPPAUGE;
|
||||
dev->init_data.type = RC_PROTO_BIT_RC5 |
|
||||
RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_RC6_6A_32;
|
||||
dev->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
|
||||
info.addr = 0x71;
|
||||
break;
|
||||
case SAA7134_BOARD_BEHOLD_607FM_MK3:
|
||||
|
|
|
|||
|
|
@ -1650,23 +1650,22 @@ int saa7134_querystd(struct file *file, void *priv, v4l2_std_id *std)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(saa7134_querystd);
|
||||
|
||||
static int saa7134_cropcap(struct file *file, void *priv,
|
||||
struct v4l2_cropcap *cap)
|
||||
static int saa7134_g_pixelaspect(struct file *file, void *priv,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct saa7134_dev *dev = video_drvdata(file);
|
||||
|
||||
if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
|
||||
cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
|
||||
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
|
||||
type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
|
||||
return -EINVAL;
|
||||
cap->pixelaspect.numerator = 1;
|
||||
cap->pixelaspect.denominator = 1;
|
||||
|
||||
if (dev->tvnorm->id & V4L2_STD_525_60) {
|
||||
cap->pixelaspect.numerator = 11;
|
||||
cap->pixelaspect.denominator = 10;
|
||||
f->numerator = 11;
|
||||
f->denominator = 10;
|
||||
}
|
||||
if (dev->tvnorm->id & V4L2_STD_625_50) {
|
||||
cap->pixelaspect.numerator = 54;
|
||||
cap->pixelaspect.denominator = 59;
|
||||
f->numerator = 54;
|
||||
f->denominator = 59;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1987,7 +1986,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|||
.vidioc_g_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
|
||||
.vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
|
||||
.vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
|
||||
.vidioc_cropcap = saa7134_cropcap,
|
||||
.vidioc_g_pixelaspect = saa7134_g_pixelaspect,
|
||||
.vidioc_reqbufs = vb2_ioctl_reqbufs,
|
||||
.vidioc_querybuf = vb2_ioctl_querybuf,
|
||||
.vidioc_qbuf = vb2_ioctl_qbuf,
|
||||
|
|
|
|||
|
|
@ -123,9 +123,7 @@ struct saa7134_format {
|
|||
struct saa7134_card_ir {
|
||||
struct rc_dev *dev;
|
||||
|
||||
char name[32];
|
||||
char phys[32];
|
||||
unsigned users;
|
||||
|
||||
u32 polling;
|
||||
u32 last_gpio;
|
||||
|
|
@ -923,13 +921,13 @@ int saa7134_input_init1(struct saa7134_dev *dev);
|
|||
void saa7134_input_fini(struct saa7134_dev *dev);
|
||||
void saa7134_input_irq(struct saa7134_dev *dev);
|
||||
void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
|
||||
int saa7134_ir_start(struct saa7134_dev *dev);
|
||||
void saa7134_ir_stop(struct saa7134_dev *dev);
|
||||
int saa7134_ir_open(struct rc_dev *dev);
|
||||
void saa7134_ir_close(struct rc_dev *dev);
|
||||
#else
|
||||
#define saa7134_input_init1(dev) ((void)0)
|
||||
#define saa7134_input_fini(dev) ((void)0)
|
||||
#define saa7134_input_irq(dev) ((void)0)
|
||||
#define saa7134_probe_i2c_ir(dev) ((void)0)
|
||||
#define saa7134_ir_start(dev) ((void)0)
|
||||
#define saa7134_ir_stop(dev) ((void)0)
|
||||
#define saa7134_ir_open(dev) ((void)0)
|
||||
#define saa7134_ir_close(dev) ((void)0)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,6 +32,15 @@ source "drivers/media/platform/davinci/Kconfig"
|
|||
|
||||
source "drivers/media/platform/omap/Kconfig"
|
||||
|
||||
config VIDEO_ASPEED
|
||||
tristate "Aspeed AST2400 and AST2500 Video Engine driver"
|
||||
depends on VIDEO_V4L2
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
help
|
||||
Support for the Aspeed Video Engine (VE) embedded in the Aspeed
|
||||
AST2400 and AST2500 SOCs. The VE can capture and compress video data
|
||||
from digital or analog sources.
|
||||
|
||||
config VIDEO_SH_VOU
|
||||
tristate "SuperH VOU video output driver"
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
|
|
@ -138,6 +147,7 @@ source "drivers/media/platform/am437x/Kconfig"
|
|||
source "drivers/media/platform/xilinx/Kconfig"
|
||||
source "drivers/media/platform/rcar-vin/Kconfig"
|
||||
source "drivers/media/platform/atmel/Kconfig"
|
||||
source "drivers/media/platform/sunxi/sun6i-csi/Kconfig"
|
||||
|
||||
config VIDEO_TI_CAL
|
||||
tristate "TI CAL (Camera Adaptation Layer) driver"
|
||||
|
|
@ -625,6 +635,28 @@ config VIDEO_TEGRA_HDMI_CEC
|
|||
The CEC bus is present in the HDMI connector and enables communication
|
||||
between compatible devices.
|
||||
|
||||
config VIDEO_SECO_CEC
|
||||
tristate "SECO Boards HDMI CEC driver"
|
||||
depends on (X86 || IA64) || COMPILE_TEST
|
||||
depends on PCI && DMI
|
||||
select CEC_CORE
|
||||
select CEC_NOTIFIER
|
||||
help
|
||||
This is a driver for SECO Boards integrated CEC interface.
|
||||
Selecting it will enable support for this device.
|
||||
CEC bus is present in the HDMI connector and enables communication
|
||||
between compatible devices.
|
||||
|
||||
config VIDEO_SECO_RC
|
||||
bool "SECO Boards IR RC5 support"
|
||||
depends on VIDEO_SECO_CEC
|
||||
select RC_CORE
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
SECO Boards Consumer-IR in seco-cec driver.
|
||||
The embedded controller supports RC5 protocol only, default mapping
|
||||
is set to rc-hauppauge.
|
||||
|
||||
endif #CEC_PLATFORM_DRIVERS
|
||||
|
||||
menuconfig SDR_PLATFORM_DRIVERS
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# Makefile for the video capture/playback device drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_VIDEO_ASPEED) += aspeed-video.o
|
||||
obj-$(CONFIG_VIDEO_CADENCE) += cadence/
|
||||
obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
|
||||
obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
|
||||
|
|
@ -55,6 +56,8 @@ obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC) += tegra-cec/
|
|||
|
||||
obj-y += stm32/
|
||||
|
||||
obj-$(CONFIG_VIDEO_SECO_CEC) += seco-cec/
|
||||
|
||||
obj-y += davinci/
|
||||
|
||||
obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o
|
||||
|
|
@ -98,3 +101,5 @@ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/
|
|||
obj-y += meson/
|
||||
|
||||
obj-y += cros-ec-cec/
|
||||
|
||||
obj-$(CONFIG_VIDEO_SUN6I_CSI) += sunxi/sun6i-csi/
|
||||
|
|
|
|||
|
|
@ -2081,24 +2081,18 @@ static void vpfe_stop_streaming(struct vb2_queue *vq)
|
|||
spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags);
|
||||
}
|
||||
|
||||
static int vpfe_cropcap(struct file *file, void *priv,
|
||||
struct v4l2_cropcap *crop)
|
||||
static int vpfe_g_pixelaspect(struct file *file, void *priv,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct vpfe_device *vpfe = video_drvdata(file);
|
||||
|
||||
vpfe_dbg(2, vpfe, "vpfe_cropcap\n");
|
||||
vpfe_dbg(2, vpfe, "vpfe_g_pixelaspect\n");
|
||||
|
||||
if (vpfe->std_index >= ARRAY_SIZE(vpfe_standards))
|
||||
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
|
||||
vpfe->std_index >= ARRAY_SIZE(vpfe_standards))
|
||||
return -EINVAL;
|
||||
|
||||
memset(crop, 0, sizeof(struct v4l2_cropcap));
|
||||
|
||||
crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
crop->defrect.width = vpfe_standards[vpfe->std_index].width;
|
||||
crop->bounds.width = crop->defrect.width;
|
||||
crop->defrect.height = vpfe_standards[vpfe->std_index].height;
|
||||
crop->bounds.height = crop->defrect.height;
|
||||
crop->pixelaspect = vpfe_standards[vpfe->std_index].pixelaspect;
|
||||
*f = vpfe_standards[vpfe->std_index].pixelaspect;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2108,12 +2102,17 @@ vpfe_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
|
|||
{
|
||||
struct vpfe_device *vpfe = video_drvdata(file);
|
||||
|
||||
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
|
||||
vpfe->std_index >= ARRAY_SIZE(vpfe_standards))
|
||||
return -EINVAL;
|
||||
|
||||
switch (s->target) {
|
||||
case V4L2_SEL_TGT_CROP_BOUNDS:
|
||||
case V4L2_SEL_TGT_CROP_DEFAULT:
|
||||
s->r.left = s->r.top = 0;
|
||||
s->r.width = vpfe->crop.width;
|
||||
s->r.height = vpfe->crop.height;
|
||||
s->r.left = 0;
|
||||
s->r.top = 0;
|
||||
s->r.width = vpfe_standards[vpfe->std_index].width;
|
||||
s->r.height = vpfe_standards[vpfe->std_index].height;
|
||||
break;
|
||||
|
||||
case V4L2_SEL_TGT_CROP:
|
||||
|
|
@ -2282,7 +2281,7 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
|
|||
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
|
||||
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
||||
|
||||
.vidioc_cropcap = vpfe_cropcap,
|
||||
.vidioc_g_pixelaspect = vpfe_g_pixelaspect,
|
||||
.vidioc_g_selection = vpfe_g_selection,
|
||||
.vidioc_s_selection = vpfe_s_selection,
|
||||
|
||||
|
|
|
|||
1729
drivers/media/platform/aspeed-video.c
Normal file
1729
drivers/media/platform/aspeed-video.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -253,7 +253,6 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
|
|||
{
|
||||
struct vb2_v4l2_buffer *src_buf;
|
||||
struct coda_buffer_meta *meta;
|
||||
unsigned long flags;
|
||||
u32 start;
|
||||
|
||||
if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)
|
||||
|
|
@ -269,6 +268,23 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
|
|||
ctx->num_metas > 1)
|
||||
break;
|
||||
|
||||
if (ctx->num_internal_frames &&
|
||||
ctx->num_metas >= ctx->num_internal_frames) {
|
||||
meta = list_first_entry(&ctx->buffer_meta_list,
|
||||
struct coda_buffer_meta, list);
|
||||
|
||||
/*
|
||||
* If we managed to fill in at least a full reorder
|
||||
* window of buffers (num_internal_frames is a
|
||||
* conservative estimate for this) and the bitstream
|
||||
* prefetcher has at least 2 256 bytes periods beyond
|
||||
* the first buffer to fetch, we can safely stop queuing
|
||||
* in order to limit the decoder drain latency.
|
||||
*/
|
||||
if (coda_bitstream_can_fetch_past(ctx, meta->end))
|
||||
break;
|
||||
}
|
||||
|
||||
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
|
||||
|
||||
/* Drop frames that do not start/end with a SOI/EOI markers */
|
||||
|
|
@ -299,8 +315,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
|
|||
}
|
||||
|
||||
/* Buffer start position */
|
||||
start = ctx->bitstream_fifo.kfifo.in &
|
||||
ctx->bitstream_fifo.kfifo.mask;
|
||||
start = ctx->bitstream_fifo.kfifo.in;
|
||||
|
||||
if (coda_bitstream_try_queue(ctx, src_buf)) {
|
||||
/*
|
||||
|
|
@ -315,15 +330,12 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
|
|||
meta->timecode = src_buf->timecode;
|
||||
meta->timestamp = src_buf->vb2_buf.timestamp;
|
||||
meta->start = start;
|
||||
meta->end = ctx->bitstream_fifo.kfifo.in &
|
||||
ctx->bitstream_fifo.kfifo.mask;
|
||||
spin_lock_irqsave(&ctx->buffer_meta_lock,
|
||||
flags);
|
||||
meta->end = ctx->bitstream_fifo.kfifo.in;
|
||||
spin_lock(&ctx->buffer_meta_lock);
|
||||
list_add_tail(&meta->list,
|
||||
&ctx->buffer_meta_list);
|
||||
ctx->num_metas++;
|
||||
spin_unlock_irqrestore(&ctx->buffer_meta_lock,
|
||||
flags);
|
||||
spin_unlock(&ctx->buffer_meta_lock);
|
||||
|
||||
trace_coda_bit_queue(ctx, src_buf, meta);
|
||||
}
|
||||
|
|
@ -713,8 +725,7 @@ static void coda_setup_iram(struct coda_ctx *ctx)
|
|||
|
||||
out:
|
||||
if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"IRAM smaller than needed\n");
|
||||
coda_dbg(1, ctx, "IRAM smaller than needed\n");
|
||||
|
||||
if (dev->devtype->product == CODA_HX4 ||
|
||||
dev->devtype->product == CODA_7541) {
|
||||
|
|
@ -991,16 +1002,15 @@ static int coda_start_encoding(struct coda_ctx *ctx)
|
|||
else
|
||||
coda_write(dev, CODA_STD_H264,
|
||||
CODA_CMD_ENC_SEQ_COD_STD);
|
||||
if (ctx->params.h264_deblk_enabled) {
|
||||
value = ((ctx->params.h264_deblk_alpha &
|
||||
CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
|
||||
CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
|
||||
((ctx->params.h264_deblk_beta &
|
||||
CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
|
||||
CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
|
||||
} else {
|
||||
value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET;
|
||||
}
|
||||
value = ((ctx->params.h264_disable_deblocking_filter_idc &
|
||||
CODA_264PARAM_DISABLEDEBLK_MASK) <<
|
||||
CODA_264PARAM_DISABLEDEBLK_OFFSET) |
|
||||
((ctx->params.h264_slice_alpha_c0_offset_div2 &
|
||||
CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
|
||||
CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
|
||||
((ctx->params.h264_slice_beta_offset_div2 &
|
||||
CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
|
||||
CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
|
||||
coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
|
||||
break;
|
||||
case V4L2_PIX_FMT_JPEG:
|
||||
|
|
@ -1201,6 +1211,12 @@ static int coda_start_encoding(struct coda_ctx *ctx)
|
|||
goto out;
|
||||
}
|
||||
|
||||
coda_dbg(1, ctx, "start encoding %dx%d %4.4s->%4.4s @ %d/%d Hz\n",
|
||||
q_data_src->rect.width, q_data_src->rect.height,
|
||||
(char *)&ctx->codec->src_fourcc, (char *)&dst_fourcc,
|
||||
ctx->params.framerate & 0xffff,
|
||||
(ctx->params.framerate >> 16) + 1);
|
||||
|
||||
/* Save stream headers */
|
||||
buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
|
||||
switch (dst_fourcc) {
|
||||
|
|
@ -1462,8 +1478,7 @@ static void coda_finish_encode(struct coda_ctx *ctx)
|
|||
vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr);
|
||||
}
|
||||
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
|
||||
wr_ptr - start_ptr);
|
||||
coda_dbg(1, ctx, "frame size = %u\n", wr_ptr - start_ptr);
|
||||
|
||||
coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
|
||||
coda_read(dev, CODA_RET_ENC_PIC_FLAG);
|
||||
|
|
@ -1492,11 +1507,9 @@ static void coda_finish_encode(struct coda_ctx *ctx)
|
|||
if (ctx->gopcounter < 0)
|
||||
ctx->gopcounter = ctx->params.gop_size - 1;
|
||||
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
||||
"job finished: encoding frame (%d) (%s)\n",
|
||||
dst_buf->sequence,
|
||||
(dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ?
|
||||
"KEYFRAME" : "PFRAME");
|
||||
coda_dbg(1, ctx, "job finished: encoded %c frame (%d)\n",
|
||||
(dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : 'P',
|
||||
dst_buf->sequence);
|
||||
}
|
||||
|
||||
static void coda_seq_end_work(struct work_struct *work)
|
||||
|
|
@ -1510,9 +1523,7 @@ static void coda_seq_end_work(struct work_struct *work)
|
|||
if (ctx->initialized == 0)
|
||||
goto out;
|
||||
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
||||
"%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx,
|
||||
__func__);
|
||||
coda_dbg(1, ctx, "%s: sent command 'SEQ_END' to coda\n", __func__);
|
||||
if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"CODA_COMMAND_SEQ_END failed\n");
|
||||
|
|
@ -1655,8 +1666,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
|
|||
u32 val;
|
||||
int ret;
|
||||
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
||||
"Video Data Order Adapter: %s\n",
|
||||
coda_dbg(1, ctx, "Video Data Order Adapter: %s\n",
|
||||
ctx->use_vdoa ? "Enabled" : "Disabled");
|
||||
|
||||
/* Start decoding */
|
||||
|
|
@ -1736,7 +1746,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
|
|||
|
||||
if (coda_read(dev, CODA_RET_DEC_SEQ_SUCCESS) == 0) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"CODA_COMMAND_SEQ_INIT failed, error code = %d\n",
|
||||
"CODA_COMMAND_SEQ_INIT failed, error code = 0x%x\n",
|
||||
coda_read(dev, CODA_RET_DEC_SEQ_ERR_REASON));
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
|
@ -1760,8 +1770,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
|
|||
width = round_up(width, 16);
|
||||
height = round_up(height, 16);
|
||||
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
|
||||
__func__, ctx->idx, width, height);
|
||||
coda_dbg(1, ctx, "start decoding: %dx%d\n", width, height);
|
||||
|
||||
ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
|
||||
/*
|
||||
|
|
@ -1879,7 +1888,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
|
|||
struct coda_dev *dev = ctx->dev;
|
||||
struct coda_q_data *q_data_dst;
|
||||
struct coda_buffer_meta *meta;
|
||||
unsigned long flags;
|
||||
u32 rot_mode = 0;
|
||||
u32 reg_addr, reg_stride;
|
||||
|
||||
|
|
@ -1893,8 +1901,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
|
|||
|
||||
if (coda_get_bitstream_payload(ctx) < 512 &&
|
||||
(!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
||||
"bitstream payload: %d, skipping\n",
|
||||
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;
|
||||
|
|
@ -1973,15 +1980,14 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
|
|||
coda_write(dev, ctx->iram_info.axi_sram_use,
|
||||
CODA7_REG_BIT_AXI_SRAM_USE);
|
||||
|
||||
spin_lock_irqsave(&ctx->buffer_meta_lock, flags);
|
||||
spin_lock(&ctx->buffer_meta_lock);
|
||||
meta = list_first_entry_or_null(&ctx->buffer_meta_list,
|
||||
struct coda_buffer_meta, list);
|
||||
|
||||
if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) {
|
||||
|
||||
/* If this is the last buffer in the bitstream, add padding */
|
||||
if (meta->end == (ctx->bitstream_fifo.kfifo.in &
|
||||
ctx->bitstream_fifo.kfifo.mask)) {
|
||||
if (meta->end == ctx->bitstream_fifo.kfifo.in) {
|
||||
static unsigned char buf[512];
|
||||
unsigned int pad;
|
||||
|
||||
|
|
@ -1993,7 +1999,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
|
|||
kfifo_in(&ctx->bitstream_fifo, buf, pad);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags);
|
||||
spin_unlock(&ctx->buffer_meta_lock);
|
||||
|
||||
coda_kfifo_sync_to_device_full(ctx);
|
||||
|
||||
|
|
@ -2015,7 +2021,6 @@ static void coda_finish_decode(struct coda_ctx *ctx)
|
|||
struct vb2_v4l2_buffer *dst_buf;
|
||||
struct coda_buffer_meta *meta;
|
||||
unsigned long payload;
|
||||
unsigned long flags;
|
||||
int width, height;
|
||||
int decoded_idx;
|
||||
int display_idx;
|
||||
|
|
@ -2100,8 +2105,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
|
|||
val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
|
||||
if (val == 0) {
|
||||
/* not enough bitstream data */
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
||||
"prescan failed: %d\n", val);
|
||||
coda_dbg(1, ctx, "prescan failed: %d\n", val);
|
||||
ctx->hold = true;
|
||||
return;
|
||||
}
|
||||
|
|
@ -2147,13 +2151,13 @@ static void coda_finish_decode(struct coda_ctx *ctx)
|
|||
} else {
|
||||
val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
|
||||
val -= ctx->sequence_offset;
|
||||
spin_lock_irqsave(&ctx->buffer_meta_lock, flags);
|
||||
spin_lock(&ctx->buffer_meta_lock);
|
||||
if (!list_empty(&ctx->buffer_meta_list)) {
|
||||
meta = list_first_entry(&ctx->buffer_meta_list,
|
||||
struct coda_buffer_meta, list);
|
||||
list_del(&meta->list);
|
||||
ctx->num_metas--;
|
||||
spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags);
|
||||
spin_unlock(&ctx->buffer_meta_lock);
|
||||
/*
|
||||
* Clamp counters to 16 bits for comparison, as the HW
|
||||
* counter rolls over at this point for h.264. This
|
||||
|
|
@ -2170,7 +2174,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
|
|||
ctx->frame_metas[decoded_idx] = *meta;
|
||||
kfree(meta);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags);
|
||||
spin_unlock(&ctx->buffer_meta_lock);
|
||||
v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
|
||||
memset(&ctx->frame_metas[decoded_idx], 0,
|
||||
sizeof(struct coda_buffer_meta));
|
||||
|
|
@ -2243,18 +2247,28 @@ static void coda_finish_decode(struct coda_ctx *ctx)
|
|||
else
|
||||
coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE);
|
||||
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
||||
"job finished: decoding frame (%d) (%s)\n",
|
||||
dst_buf->sequence,
|
||||
(dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ?
|
||||
"KEYFRAME" : "PFRAME");
|
||||
coda_dbg(1, ctx, "job finished: decoded %c frame (%u/%u)\n",
|
||||
(dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' :
|
||||
((dst_buf->flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : 'B'),
|
||||
dst_buf->sequence, ctx->qsequence);
|
||||
} else {
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
||||
"job finished: no frame decoded\n");
|
||||
coda_dbg(1, ctx, "job finished: no frame decoded (%u/%u)\n",
|
||||
ctx->osequence, ctx->qsequence);
|
||||
}
|
||||
|
||||
/* The rotator will copy the current display frame next time */
|
||||
ctx->display_idx = display_idx;
|
||||
|
||||
/*
|
||||
* The current decode run might have brought the bitstream fill level
|
||||
* below the size where we can start the next decode run. As userspace
|
||||
* might have filled the output queue completely and might thus be
|
||||
* blocked, we can't rely on the next qbuf to trigger the bitstream
|
||||
* refill. Check if we have data to refill the bitstream now.
|
||||
*/
|
||||
mutex_lock(&ctx->bitstream_mutex);
|
||||
coda_fill_bitstream(ctx, NULL);
|
||||
mutex_unlock(&ctx->bitstream_mutex);
|
||||
}
|
||||
|
||||
static void coda_decode_timeout(struct coda_ctx *ctx)
|
||||
|
|
@ -2308,13 +2322,11 @@ irqreturn_t coda_irq_handler(int irq, void *data)
|
|||
trace_coda_bit_done(ctx);
|
||||
|
||||
if (ctx->aborting) {
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"task has been aborted\n");
|
||||
coda_dbg(1, ctx, "task has been aborted\n");
|
||||
}
|
||||
|
||||
if (coda_isbusy(ctx->dev)) {
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"coda is still busy!!!!\n");
|
||||
coda_dbg(1, ctx, "coda is still busy!!!!\n");
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/firmware.h>
|
||||
#include <linux/gcd.h>
|
||||
#include <linux/genalloc.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
|
|
@ -50,8 +51,8 @@
|
|||
|
||||
#define CODA_ISRAM_SIZE (2048 * 2)
|
||||
|
||||
#define MIN_W 176
|
||||
#define MIN_H 144
|
||||
#define MIN_W 48
|
||||
#define MIN_H 16
|
||||
|
||||
#define S_ALIGN 1 /* multiple of 2 */
|
||||
#define W_ALIGN 1 /* multiple of 2 */
|
||||
|
|
@ -703,7 +704,8 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f,
|
|||
return -EINVAL;
|
||||
|
||||
if (vb2_is_busy(vq)) {
|
||||
v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
|
||||
v4l2_err(&ctx->dev->v4l2_dev, "%s: %s queue busy: %d\n",
|
||||
__func__, v4l2_type_names[f->type], vq->num_buffers);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
|
@ -749,11 +751,10 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f,
|
|||
else
|
||||
ctx->use_vdoa = false;
|
||||
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"Setting format for type %d, wxh: %dx%d, fmt: %4.4s %c\n",
|
||||
f->type, q_data->width, q_data->height,
|
||||
(char *)&q_data->fourcc,
|
||||
(ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T');
|
||||
coda_dbg(1, ctx, "Setting %s format, wxh: %dx%d, fmt: %4.4s %c\n",
|
||||
v4l2_type_names[f->type], q_data->width, q_data->height,
|
||||
(char *)&q_data->fourcc,
|
||||
(ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) ? 'L' : 'T');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -938,32 +939,42 @@ static int coda_s_selection(struct file *file, void *fh,
|
|||
struct coda_ctx *ctx = fh_to_ctx(fh);
|
||||
struct coda_q_data *q_data;
|
||||
|
||||
if (ctx->inst_type == CODA_INST_ENCODER &&
|
||||
s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
|
||||
s->target == V4L2_SEL_TGT_CROP) {
|
||||
q_data = get_q_data(ctx, s->type);
|
||||
if (!q_data)
|
||||
return -EINVAL;
|
||||
switch (s->target) {
|
||||
case V4L2_SEL_TGT_CROP:
|
||||
if (ctx->inst_type == CODA_INST_ENCODER &&
|
||||
s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
||||
q_data = get_q_data(ctx, s->type);
|
||||
if (!q_data)
|
||||
return -EINVAL;
|
||||
|
||||
s->r.left = 0;
|
||||
s->r.top = 0;
|
||||
s->r.width = clamp(s->r.width, 2U, q_data->width);
|
||||
s->r.height = clamp(s->r.height, 2U, q_data->height);
|
||||
s->r.left = 0;
|
||||
s->r.top = 0;
|
||||
s->r.width = clamp(s->r.width, 2U, q_data->width);
|
||||
s->r.height = clamp(s->r.height, 2U, q_data->height);
|
||||
|
||||
if (s->flags & V4L2_SEL_FLAG_LE) {
|
||||
s->r.width = round_up(s->r.width, 2);
|
||||
s->r.height = round_up(s->r.height, 2);
|
||||
} else {
|
||||
s->r.width = round_down(s->r.width, 2);
|
||||
s->r.height = round_down(s->r.height, 2);
|
||||
if (s->flags & V4L2_SEL_FLAG_LE) {
|
||||
s->r.width = round_up(s->r.width, 2);
|
||||
s->r.height = round_up(s->r.height, 2);
|
||||
} else {
|
||||
s->r.width = round_down(s->r.width, 2);
|
||||
s->r.height = round_down(s->r.height, 2);
|
||||
}
|
||||
|
||||
q_data->rect = s->r;
|
||||
|
||||
coda_dbg(1, ctx, "Setting crop rectangle: %dx%d\n",
|
||||
s->r.width, s->r.height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
q_data->rect = s->r;
|
||||
|
||||
return 0;
|
||||
/* else fall through */
|
||||
case V4L2_SEL_TGT_NATIVE_SIZE:
|
||||
case V4L2_SEL_TGT_COMPOSE:
|
||||
return coda_g_selection(file, fh, s);
|
||||
default:
|
||||
/* v4l2-compliance expects this to fail for read-only targets */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return coda_g_selection(file, fh, s);
|
||||
}
|
||||
|
||||
static int coda_try_encoder_cmd(struct file *file, void *fh,
|
||||
|
|
@ -1044,6 +1055,38 @@ static int coda_decoder_cmd(struct file *file, void *fh,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int coda_enum_frameintervals(struct file *file, void *fh,
|
||||
struct v4l2_frmivalenum *f)
|
||||
{
|
||||
struct coda_ctx *ctx = fh_to_ctx(fh);
|
||||
int i;
|
||||
|
||||
if (f->index)
|
||||
return -EINVAL;
|
||||
|
||||
/* Disallow YUYV if the vdoa is not available */
|
||||
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 (i == CODA_MAX_FORMATS)
|
||||
return -EINVAL;
|
||||
|
||||
f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
|
||||
f->stepwise.min.numerator = 1;
|
||||
f->stepwise.min.denominator = 65535;
|
||||
f->stepwise.max.numerator = 65536;
|
||||
f->stepwise.max.denominator = 1;
|
||||
f->stepwise.step.numerator = 1;
|
||||
f->stepwise.step.denominator = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
|
||||
{
|
||||
struct coda_ctx *ctx = fh_to_ctx(fh);
|
||||
|
|
@ -1080,10 +1123,10 @@ static void coda_approximate_timeperframe(struct v4l2_fract *timeperframe)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Upper bound is 65536/1, map everything above to infinity */
|
||||
/* Upper bound is 65536/1 */
|
||||
if (s.denominator == 0 || s.numerator / s.denominator > 65536) {
|
||||
timeperframe->numerator = 1;
|
||||
timeperframe->denominator = 0;
|
||||
timeperframe->numerator = 65536;
|
||||
timeperframe->denominator = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1135,6 +1178,7 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
|
|||
if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
|
||||
return -EINVAL;
|
||||
|
||||
a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
|
||||
tpf = &a->parm.output.timeperframe;
|
||||
coda_approximate_timeperframe(tpf);
|
||||
ctx->params.framerate = coda_timeperframe_to_frate(tpf);
|
||||
|
|
@ -1189,6 +1233,8 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
|
|||
.vidioc_g_parm = coda_g_parm,
|
||||
.vidioc_s_parm = coda_s_parm,
|
||||
|
||||
.vidioc_enum_frameintervals = coda_enum_frameintervals,
|
||||
|
||||
.vidioc_subscribe_event = coda_subscribe_event,
|
||||
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
||||
};
|
||||
|
|
@ -1257,14 +1303,12 @@ static int coda_job_ready(void *m2m_priv)
|
|||
* the compressed frame can be in the bitstream.
|
||||
*/
|
||||
if (!src_bufs && ctx->inst_type != CODA_INST_DECODER) {
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"not ready: not enough video buffers.\n");
|
||||
coda_dbg(1, ctx, "not ready: not enough vid-out buffers.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"not ready: not enough video capture buffers.\n");
|
||||
coda_dbg(1, ctx, "not ready: not enough vid-cap buffers.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1272,49 +1316,48 @@ static int coda_job_ready(void *m2m_priv)
|
|||
bool stream_end = ctx->bit_stream_param &
|
||||
CODA_BIT_STREAM_END_FLAG;
|
||||
int num_metas = ctx->num_metas;
|
||||
struct coda_buffer_meta *meta;
|
||||
unsigned int count;
|
||||
|
||||
count = hweight32(ctx->frm_dis_flg);
|
||||
if (ctx->use_vdoa && count >= (ctx->num_internal_frames - 1)) {
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"%d: not ready: all internal buffers in use: %d/%d (0x%x)",
|
||||
ctx->idx, count, ctx->num_internal_frames,
|
||||
coda_dbg(1, ctx,
|
||||
"not ready: all internal buffers in use: %d/%d (0x%x)",
|
||||
count, ctx->num_internal_frames,
|
||||
ctx->frm_dis_flg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->hold && !src_bufs) {
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"%d: not ready: on hold for more buffers.\n",
|
||||
ctx->idx);
|
||||
coda_dbg(1, ctx,
|
||||
"not ready: on hold for more buffers.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!stream_end && (num_metas + src_bufs) < 2) {
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"%d: not ready: need 2 buffers available (%d, %d)\n",
|
||||
ctx->idx, num_metas, src_bufs);
|
||||
coda_dbg(1, ctx,
|
||||
"not ready: need 2 buffers available (queue:%d + bitstream:%d)\n",
|
||||
num_metas, src_bufs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (!src_bufs && !stream_end &&
|
||||
(coda_get_bitstream_payload(ctx) < 512)) {
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"%d: not ready: not enough bitstream data (%d).\n",
|
||||
ctx->idx, coda_get_bitstream_payload(ctx));
|
||||
meta = list_first_entry(&ctx->buffer_meta_list,
|
||||
struct coda_buffer_meta, list);
|
||||
if (!coda_bitstream_can_fetch_past(ctx, meta->end) &&
|
||||
!stream_end) {
|
||||
coda_dbg(1, ctx,
|
||||
"not ready: not enough bitstream data to read past %u (%u)\n",
|
||||
meta->end, ctx->bitstream_fifo.kfifo.in);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->aborting) {
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"not ready: aborting\n");
|
||||
coda_dbg(1, ctx, "not ready: aborting\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"job ready\n");
|
||||
coda_dbg(1, ctx, "job ready\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -1325,8 +1368,7 @@ static void coda_job_abort(void *priv)
|
|||
|
||||
ctx->aborting = 1;
|
||||
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"Aborting task\n");
|
||||
coda_dbg(1, ctx, "job abort\n");
|
||||
}
|
||||
|
||||
static const struct v4l2_m2m_ops coda_m2m_ops = {
|
||||
|
|
@ -1403,8 +1445,8 @@ static int coda_queue_setup(struct vb2_queue *vq,
|
|||
*nplanes = 1;
|
||||
sizes[0] = size;
|
||||
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"get %d buffer(s) of size %d each.\n", *nbuffers, size);
|
||||
coda_dbg(1, ctx, "get %d buffer(s) of size %d each.\n", *nbuffers,
|
||||
size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1469,8 +1511,7 @@ static void coda_update_h264_profile_ctrl(struct coda_ctx *ctx)
|
|||
|
||||
profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
|
||||
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Parsed H264 Profile: %s\n",
|
||||
profile_names[profile]);
|
||||
coda_dbg(1, ctx, "Parsed H264 Profile: %s\n", profile_names[profile]);
|
||||
}
|
||||
|
||||
static void coda_update_h264_level_ctrl(struct coda_ctx *ctx)
|
||||
|
|
@ -1489,8 +1530,7 @@ static void coda_update_h264_level_ctrl(struct coda_ctx *ctx)
|
|||
|
||||
level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
|
||||
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Parsed H264 Level: %s\n",
|
||||
level_names[level]);
|
||||
coda_dbg(1, ctx, "Parsed H264 Level: %s\n", level_names[level]);
|
||||
}
|
||||
|
||||
static void coda_buf_queue(struct vb2_buffer *vb)
|
||||
|
|
@ -1595,6 +1635,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
|
|||
if (count < 1)
|
||||
return -EINVAL;
|
||||
|
||||
coda_dbg(1, ctx, "start streaming %s\n", v4l2_type_names[q->type]);
|
||||
|
||||
INIT_LIST_HEAD(&list);
|
||||
|
||||
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
|
||||
|
|
@ -1687,14 +1729,13 @@ static void coda_stop_streaming(struct vb2_queue *q)
|
|||
struct coda_ctx *ctx = vb2_get_drv_priv(q);
|
||||
struct coda_dev *dev = ctx->dev;
|
||||
struct vb2_v4l2_buffer *buf;
|
||||
unsigned long flags;
|
||||
bool stop;
|
||||
|
||||
stop = ctx->streamon_out && ctx->streamon_cap;
|
||||
|
||||
coda_dbg(1, ctx, "stop streaming %s\n", v4l2_type_names[q->type]);
|
||||
|
||||
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
||||
"%s: output\n", __func__);
|
||||
ctx->streamon_out = 0;
|
||||
|
||||
coda_bit_stream_end_flag(ctx);
|
||||
|
|
@ -1704,8 +1745,6 @@ static void coda_stop_streaming(struct vb2_queue *q)
|
|||
while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
|
||||
v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
|
||||
} else {
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
|
||||
"%s: capture\n", __func__);
|
||||
ctx->streamon_cap = 0;
|
||||
|
||||
ctx->osequence = 0;
|
||||
|
|
@ -1722,7 +1761,7 @@ static void coda_stop_streaming(struct vb2_queue *q)
|
|||
queue_work(dev->workqueue, &ctx->seq_end_work);
|
||||
flush_work(&ctx->seq_end_work);
|
||||
}
|
||||
spin_lock_irqsave(&ctx->buffer_meta_lock, flags);
|
||||
spin_lock(&ctx->buffer_meta_lock);
|
||||
while (!list_empty(&ctx->buffer_meta_list)) {
|
||||
meta = list_first_entry(&ctx->buffer_meta_list,
|
||||
struct coda_buffer_meta, list);
|
||||
|
|
@ -1730,7 +1769,7 @@ static void coda_stop_streaming(struct vb2_queue *q)
|
|||
kfree(meta);
|
||||
}
|
||||
ctx->num_metas = 0;
|
||||
spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags);
|
||||
spin_unlock(&ctx->buffer_meta_lock);
|
||||
kfifo_init(&ctx->bitstream_fifo,
|
||||
ctx->bitstream.vaddr, ctx->bitstream.size);
|
||||
ctx->runcounter = 0;
|
||||
|
|
@ -1757,8 +1796,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
struct coda_ctx *ctx =
|
||||
container_of(ctrl->handler, struct coda_ctx, ctrls);
|
||||
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
|
||||
coda_dbg(1, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n",
|
||||
ctrl->id, ctrl->name, ctrl->val);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_HFLIP:
|
||||
|
|
@ -1792,14 +1831,13 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
ctx->params.h264_max_qp = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
|
||||
ctx->params.h264_deblk_alpha = ctrl->val;
|
||||
ctx->params.h264_slice_alpha_c0_offset_div2 = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
|
||||
ctx->params.h264_deblk_beta = ctrl->val;
|
||||
ctx->params.h264_slice_beta_offset_div2 = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
|
||||
ctx->params.h264_deblk_enabled = (ctrl->val ==
|
||||
V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
|
||||
ctx->params.h264_disable_deblocking_filter_idc = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
|
||||
/* TODO: switch between baseline and constrained baseline */
|
||||
|
|
@ -1849,9 +1887,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
ctx->params.vbv_size = min(ctrl->val * 8192, 0x7fffffff);
|
||||
break;
|
||||
default:
|
||||
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
|
||||
"Invalid control, id=%d, val=%d\n",
|
||||
ctrl->id, ctrl->val);
|
||||
coda_dbg(1, ctx, "Invalid control, id=%d, val=%d\n",
|
||||
ctrl->id, ctrl->val);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1881,13 +1918,13 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
|
|||
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
|
||||
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
|
||||
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, -6, 6, 1, 0);
|
||||
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
|
||||
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0);
|
||||
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
|
||||
V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
|
||||
V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
|
||||
V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
|
||||
0x0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
|
||||
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
|
||||
V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0,
|
||||
|
|
@ -2099,17 +2136,6 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
|
|||
return coda_queue_init(priv, dst_vq);
|
||||
}
|
||||
|
||||
static int coda_next_free_instance(struct coda_dev *dev)
|
||||
{
|
||||
int idx = ffz(dev->instance_mask);
|
||||
|
||||
if ((idx < 0) ||
|
||||
(dev->devtype->product == CODA_DX6 && idx > CODADX6_MAX_INSTANCES))
|
||||
return -EBUSY;
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* File operations
|
||||
*/
|
||||
|
|
@ -2118,7 +2144,8 @@ static int coda_open(struct file *file)
|
|||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
struct coda_dev *dev = video_get_drvdata(vdev);
|
||||
struct coda_ctx *ctx = NULL;
|
||||
struct coda_ctx *ctx;
|
||||
unsigned int max = ~0;
|
||||
char *name;
|
||||
int ret;
|
||||
int idx;
|
||||
|
|
@ -2127,12 +2154,13 @@ static int coda_open(struct file *file)
|
|||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
idx = coda_next_free_instance(dev);
|
||||
if (dev->devtype->product == CODA_DX6)
|
||||
max = CODADX6_MAX_INSTANCES - 1;
|
||||
idx = ida_alloc_max(&dev->ida, max, GFP_KERNEL);
|
||||
if (idx < 0) {
|
||||
ret = idx;
|
||||
goto err_coda_max;
|
||||
}
|
||||
set_bit(idx, &dev->instance_mask);
|
||||
|
||||
name = kasprintf(GFP_KERNEL, "context%d", idx);
|
||||
if (!name) {
|
||||
|
|
@ -2156,6 +2184,9 @@ static int coda_open(struct file *file)
|
|||
v4l2_fh_add(&ctx->fh);
|
||||
ctx->dev = dev;
|
||||
ctx->idx = idx;
|
||||
|
||||
coda_dbg(1, ctx, "open instance (%p)\n", ctx);
|
||||
|
||||
switch (dev->devtype->product) {
|
||||
case CODA_960:
|
||||
/*
|
||||
|
|
@ -2221,13 +2252,6 @@ static int coda_open(struct file *file)
|
|||
INIT_LIST_HEAD(&ctx->buffer_meta_list);
|
||||
spin_lock_init(&ctx->buffer_meta_lock);
|
||||
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
list_add(&ctx->list, &dev->instances);
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
|
||||
ctx->idx, ctx);
|
||||
|
||||
return 0;
|
||||
|
||||
err_ctrls_setup:
|
||||
|
|
@ -2241,8 +2265,8 @@ err_clk_per:
|
|||
err_pm_get:
|
||||
v4l2_fh_del(&ctx->fh);
|
||||
v4l2_fh_exit(&ctx->fh);
|
||||
clear_bit(ctx->idx, &dev->instance_mask);
|
||||
err_coda_name_init:
|
||||
ida_free(&dev->ida, ctx->idx);
|
||||
err_coda_max:
|
||||
kfree(ctx);
|
||||
return ret;
|
||||
|
|
@ -2253,8 +2277,7 @@ static int coda_release(struct file *file)
|
|||
struct coda_dev *dev = video_drvdata(file);
|
||||
struct coda_ctx *ctx = fh_to_ctx(file->private_data);
|
||||
|
||||
v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
|
||||
ctx);
|
||||
coda_dbg(1, ctx, "release instance (%p)\n", ctx);
|
||||
|
||||
if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit)
|
||||
coda_bit_stream_end_flag(ctx);
|
||||
|
|
@ -2271,10 +2294,6 @@ static int coda_release(struct file *file)
|
|||
flush_work(&ctx->seq_end_work);
|
||||
}
|
||||
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
list_del(&ctx->list);
|
||||
mutex_unlock(&dev->dev_mutex);
|
||||
|
||||
if (ctx->dev->devtype->product == CODA_DX6)
|
||||
coda_free_aux_buf(dev, &ctx->workbuf);
|
||||
|
||||
|
|
@ -2284,7 +2303,7 @@ static int coda_release(struct file *file)
|
|||
pm_runtime_put_sync(&dev->plat_dev->dev);
|
||||
v4l2_fh_del(&ctx->fh);
|
||||
v4l2_fh_exit(&ctx->fh);
|
||||
clear_bit(ctx->idx, &dev->instance_mask);
|
||||
ida_free(&dev->ida, ctx->idx);
|
||||
if (ctx->ops->release)
|
||||
ctx->ops->release(ctx);
|
||||
debugfs_remove_recursive(ctx->debugfs_entry);
|
||||
|
|
@ -2679,7 +2698,6 @@ static int coda_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
|
||||
spin_lock_init(&dev->irqlock);
|
||||
INIT_LIST_HEAD(&dev->instances);
|
||||
|
||||
dev->plat_dev = pdev;
|
||||
dev->clk_per = devm_clk_get(&pdev->dev, "per");
|
||||
|
|
@ -2745,6 +2763,7 @@ static int coda_probe(struct platform_device *pdev)
|
|||
|
||||
mutex_init(&dev->dev_mutex);
|
||||
mutex_init(&dev->coda_mutex);
|
||||
ida_init(&dev->ida);
|
||||
|
||||
dev->debugfs_root = debugfs_create_dir("coda", NULL);
|
||||
if (!dev->debugfs_root)
|
||||
|
|
@ -2832,6 +2851,7 @@ static int coda_remove(struct platform_device *pdev)
|
|||
coda_free_aux_buf(dev, &dev->tempbuf);
|
||||
coda_free_aux_buf(dev, &dev->workbuf);
|
||||
debugfs_remove_recursive(dev->debugfs_root);
|
||||
ida_destroy(&dev->ida);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#define __CODA_H__
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/irqreturn.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
|
@ -94,8 +95,7 @@ struct coda_dev {
|
|||
struct mutex coda_mutex;
|
||||
struct workqueue_struct *workqueue;
|
||||
struct v4l2_m2m_dev *m2m_dev;
|
||||
struct list_head instances;
|
||||
unsigned long instance_mask;
|
||||
struct ida ida;
|
||||
struct dentry *debugfs_root;
|
||||
};
|
||||
|
||||
|
|
@ -115,9 +115,9 @@ struct coda_params {
|
|||
u8 h264_inter_qp;
|
||||
u8 h264_min_qp;
|
||||
u8 h264_max_qp;
|
||||
u8 h264_deblk_enabled;
|
||||
u8 h264_deblk_alpha;
|
||||
u8 h264_deblk_beta;
|
||||
u8 h264_disable_deblocking_filter_idc;
|
||||
s8 h264_slice_alpha_c0_offset_div2;
|
||||
s8 h264_slice_beta_offset_div2;
|
||||
u8 h264_profile_idc;
|
||||
u8 h264_level_idc;
|
||||
u8 mpeg4_intra_qp;
|
||||
|
|
@ -144,8 +144,8 @@ struct coda_buffer_meta {
|
|||
u32 sequence;
|
||||
struct v4l2_timecode timecode;
|
||||
u64 timestamp;
|
||||
u32 start;
|
||||
u32 end;
|
||||
unsigned int start;
|
||||
unsigned int end;
|
||||
};
|
||||
|
||||
/* Per-queue, driver-specific private data */
|
||||
|
|
@ -192,7 +192,6 @@ struct coda_context_ops {
|
|||
struct coda_ctx {
|
||||
struct coda_dev *dev;
|
||||
struct mutex buffer_mutex;
|
||||
struct list_head list;
|
||||
struct work_struct pic_run_work;
|
||||
struct work_struct seq_end_work;
|
||||
struct completion completion;
|
||||
|
|
@ -253,6 +252,13 @@ struct coda_ctx {
|
|||
|
||||
extern int coda_debug;
|
||||
|
||||
#define coda_dbg(level, ctx, fmt, arg...) \
|
||||
do { \
|
||||
if (coda_debug >= (level)) \
|
||||
v4l2_dbg((level), coda_debug, &(ctx)->dev->v4l2_dev, \
|
||||
"%u: " fmt, (ctx)->idx, ##arg); \
|
||||
} while (0)
|
||||
|
||||
void coda_write(struct coda_dev *dev, u32 data, u32 reg);
|
||||
unsigned int coda_read(struct coda_dev *dev, u32 reg);
|
||||
void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data,
|
||||
|
|
@ -295,6 +301,18 @@ static inline unsigned int coda_get_bitstream_payload(struct coda_ctx *ctx)
|
|||
return kfifo_len(&ctx->bitstream_fifo);
|
||||
}
|
||||
|
||||
/*
|
||||
* The bitstream prefetcher needs to read at least 2 256 byte periods past
|
||||
* the desired bitstream position for all data to reach the decoder.
|
||||
*/
|
||||
static inline bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx,
|
||||
unsigned int pos)
|
||||
{
|
||||
return (int)(ctx->bitstream_fifo.kfifo.in - ALIGN(pos, 256)) > 512;
|
||||
}
|
||||
|
||||
bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, unsigned int pos);
|
||||
|
||||
void coda_bit_stream_end_flag(struct coda_ctx *ctx);
|
||||
|
||||
void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@
|
|||
#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET 8
|
||||
#define CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK 0x0f
|
||||
#define CODA_264PARAM_DISABLEDEBLK_OFFSET 6
|
||||
#define CODA_264PARAM_DISABLEDEBLK_MASK 0x01
|
||||
#define CODA_264PARAM_DISABLEDEBLK_MASK 0x03
|
||||
#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET 5
|
||||
#define CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK 0x01
|
||||
#define CODA_264PARAM_CHROMAQPOFFSET_OFFSET 0
|
||||
|
|
|
|||
|
|
@ -97,8 +97,8 @@ DECLARE_EVENT_CLASS(coda_buf_meta_class,
|
|||
TP_fast_assign(
|
||||
__entry->minor = ctx->fh.vdev->minor;
|
||||
__entry->index = buf->vb2_buf.index;
|
||||
__entry->start = meta->start;
|
||||
__entry->end = meta->end;
|
||||
__entry->start = meta->start & ctx->bitstream_fifo.kfifo.mask;
|
||||
__entry->end = meta->end & ctx->bitstream_fifo.kfifo.mask;
|
||||
__entry->ctx = ctx->idx;
|
||||
),
|
||||
|
||||
|
|
@ -127,8 +127,10 @@ DECLARE_EVENT_CLASS(coda_meta_class,
|
|||
|
||||
TP_fast_assign(
|
||||
__entry->minor = ctx->fh.vdev->minor;
|
||||
__entry->start = meta ? meta->start : 0;
|
||||
__entry->end = meta ? meta->end : 0;
|
||||
__entry->start = meta ? (meta->start &
|
||||
ctx->bitstream_fifo.kfifo.mask) : 0;
|
||||
__entry->end = meta ? (meta->end &
|
||||
ctx->bitstream_fifo.kfifo.mask) : 0;
|
||||
__entry->ctx = ctx->idx;
|
||||
),
|
||||
|
||||
|
|
|
|||
|
|
@ -92,28 +92,6 @@ static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* vpbe_g_cropcap - Get crop capabilities of the display
|
||||
* @vpbe_dev: vpbe device ptr
|
||||
* @cropcap: cropcap is a ptr to struct v4l2_cropcap
|
||||
*
|
||||
* Update the crop capabilities in crop cap for current
|
||||
* mode
|
||||
*/
|
||||
static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev,
|
||||
struct v4l2_cropcap *cropcap)
|
||||
{
|
||||
if (!cropcap)
|
||||
return -EINVAL;
|
||||
cropcap->bounds.left = 0;
|
||||
cropcap->bounds.top = 0;
|
||||
cropcap->bounds.width = vpbe_dev->current_timings.xres;
|
||||
cropcap->bounds.height = vpbe_dev->current_timings.yres;
|
||||
cropcap->defrect = cropcap->bounds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* vpbe_enum_outputs - enumerate outputs
|
||||
* @vpbe_dev: vpbe device ptr
|
||||
|
|
@ -740,7 +718,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
|
|||
if (ret) {
|
||||
v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default output %s",
|
||||
def_output);
|
||||
return ret;
|
||||
goto fail_kfree_amp;
|
||||
}
|
||||
|
||||
printk(KERN_NOTICE "Setting default mode to %s\n", def_mode);
|
||||
|
|
@ -748,12 +726,15 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
|
|||
if (ret) {
|
||||
v4l2_err(&vpbe_dev->v4l2_dev, "Failed to set default mode %s",
|
||||
def_mode);
|
||||
return ret;
|
||||
goto fail_kfree_amp;
|
||||
}
|
||||
vpbe_dev->initialized = 1;
|
||||
/* TBD handling of bootargs for default output and mode */
|
||||
return 0;
|
||||
|
||||
fail_kfree_amp:
|
||||
mutex_lock(&vpbe_dev->lock);
|
||||
kfree(vpbe_dev->amp);
|
||||
fail_kfree_encoders:
|
||||
kfree(vpbe_dev->encoders);
|
||||
fail_dev_unregister:
|
||||
|
|
@ -793,7 +774,6 @@ static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev)
|
|||
}
|
||||
|
||||
static const struct vpbe_device_ops vpbe_dev_ops = {
|
||||
.g_cropcap = vpbe_g_cropcap,
|
||||
.enum_outputs = vpbe_enum_outputs,
|
||||
.set_output = vpbe_set_output,
|
||||
.get_output = vpbe_get_output,
|
||||
|
|
|
|||
|
|
@ -759,18 +759,18 @@ static int vpbe_display_g_selection(struct file *file, void *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vpbe_display_cropcap(struct file *file, void *priv,
|
||||
struct v4l2_cropcap *cropcap)
|
||||
static int vpbe_display_g_pixelaspect(struct file *file, void *priv,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct vpbe_layer *layer = video_drvdata(file);
|
||||
struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
|
||||
|
||||
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n");
|
||||
|
||||
if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
|
||||
if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
|
||||
return -EINVAL;
|
||||
|
||||
cropcap->pixelaspect = vpbe_dev->current_timings.aspect;
|
||||
*f = vpbe_dev->current_timings.aspect;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1263,7 +1263,7 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
|
|||
.vidioc_streamoff = vb2_ioctl_streamoff,
|
||||
.vidioc_expbuf = vb2_ioctl_expbuf,
|
||||
|
||||
.vidioc_cropcap = vpbe_display_cropcap,
|
||||
.vidioc_g_pixelaspect = vpbe_display_g_pixelaspect,
|
||||
.vidioc_g_selection = vpbe_display_g_selection,
|
||||
.vidioc_s_selection = vpbe_display_s_selection,
|
||||
|
||||
|
|
|
|||
|
|
@ -1558,20 +1558,20 @@ static int vpfe_streamoff(struct file *file, void *priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int vpfe_cropcap(struct file *file, void *priv,
|
||||
struct v4l2_cropcap *crop)
|
||||
static int vpfe_g_pixelaspect(struct file *file, void *priv,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct vpfe_device *vpfe_dev = video_drvdata(file);
|
||||
|
||||
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_cropcap\n");
|
||||
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_pixelaspect\n");
|
||||
|
||||
if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
/* If std_index is invalid, then just return (== 1:1 aspect) */
|
||||
if (vpfe_dev->std_index >= ARRAY_SIZE(vpfe_standards))
|
||||
return 0;
|
||||
|
||||
crop->pixelaspect = vpfe_standards[vpfe_dev->std_index].pixelaspect;
|
||||
*f = vpfe_standards[vpfe_dev->std_index].pixelaspect;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1677,7 +1677,7 @@ static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
|
|||
.vidioc_dqbuf = vpfe_dqbuf,
|
||||
.vidioc_streamon = vpfe_streamon,
|
||||
.vidioc_streamoff = vpfe_streamoff,
|
||||
.vidioc_cropcap = vpfe_cropcap,
|
||||
.vidioc_g_pixelaspect = vpfe_g_pixelaspect,
|
||||
.vidioc_g_selection = vpfe_g_selection,
|
||||
.vidioc_s_selection = vpfe_s_selection,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -541,20 +541,7 @@ void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h)
|
|||
}
|
||||
}
|
||||
|
||||
int gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
|
||||
{
|
||||
struct gsc_frame *frame;
|
||||
|
||||
frame = ctx_get_frame(ctx, cr->type);
|
||||
if (IS_ERR(frame))
|
||||
return PTR_ERR(frame);
|
||||
|
||||
cr->c = frame->crop;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
|
||||
int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s)
|
||||
{
|
||||
struct gsc_frame *f;
|
||||
struct gsc_dev *gsc = ctx->gsc_dev;
|
||||
|
|
@ -562,25 +549,25 @@ int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
|
|||
u32 mod_x = 0, mod_y = 0, tmp_w, tmp_h;
|
||||
u32 min_w, min_h, max_w, max_h;
|
||||
|
||||
if (cr->c.top < 0 || cr->c.left < 0) {
|
||||
if (s->r.top < 0 || s->r.left < 0) {
|
||||
pr_err("doesn't support negative values for top & left\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pr_debug("user put w: %d, h: %d", cr->c.width, cr->c.height);
|
||||
pr_debug("user put w: %d, h: %d", s->r.width, s->r.height);
|
||||
|
||||
if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
f = &ctx->d_frame;
|
||||
else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
|
||||
else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
|
||||
f = &ctx->s_frame;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
max_w = f->f_width;
|
||||
max_h = f->f_height;
|
||||
tmp_w = cr->c.width;
|
||||
tmp_h = cr->c.height;
|
||||
tmp_w = s->r.width;
|
||||
tmp_h = s->r.height;
|
||||
|
||||
if (V4L2_TYPE_IS_OUTPUT(cr->type)) {
|
||||
if (V4L2_TYPE_IS_OUTPUT(s->type)) {
|
||||
if ((is_yuv422(f->fmt->color) && f->fmt->num_comp == 1) ||
|
||||
is_rgb(f->fmt->color))
|
||||
min_w = 32;
|
||||
|
|
@ -602,8 +589,8 @@ int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
|
|||
max_h = f->f_width;
|
||||
min_w = variant->pix_min->target_rot_en_w;
|
||||
min_h = variant->pix_min->target_rot_en_h;
|
||||
tmp_w = cr->c.height;
|
||||
tmp_h = cr->c.width;
|
||||
tmp_w = s->r.height;
|
||||
tmp_h = s->r.width;
|
||||
} else {
|
||||
min_w = variant->pix_min->target_rot_dis_w;
|
||||
min_h = variant->pix_min->target_rot_dis_h;
|
||||
|
|
@ -616,29 +603,29 @@ int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr)
|
|||
v4l_bound_align_image(&tmp_w, min_w, max_w, mod_x,
|
||||
&tmp_h, min_h, max_h, mod_y, 0);
|
||||
|
||||
if (!V4L2_TYPE_IS_OUTPUT(cr->type) &&
|
||||
(ctx->gsc_ctrls.rotate->val == 90 ||
|
||||
ctx->gsc_ctrls.rotate->val == 270))
|
||||
if (!V4L2_TYPE_IS_OUTPUT(s->type) &&
|
||||
(ctx->gsc_ctrls.rotate->val == 90 ||
|
||||
ctx->gsc_ctrls.rotate->val == 270))
|
||||
gsc_check_crop_change(tmp_h, tmp_w,
|
||||
&cr->c.width, &cr->c.height);
|
||||
&s->r.width, &s->r.height);
|
||||
else
|
||||
gsc_check_crop_change(tmp_w, tmp_h,
|
||||
&cr->c.width, &cr->c.height);
|
||||
&s->r.width, &s->r.height);
|
||||
|
||||
|
||||
/* adjust left/top if cropping rectangle is out of bounds */
|
||||
/* Need to add code to algin left value with 2's multiple */
|
||||
if (cr->c.left + tmp_w > max_w)
|
||||
cr->c.left = max_w - tmp_w;
|
||||
if (cr->c.top + tmp_h > max_h)
|
||||
cr->c.top = max_h - tmp_h;
|
||||
if (s->r.left + tmp_w > max_w)
|
||||
s->r.left = max_w - tmp_w;
|
||||
if (s->r.top + tmp_h > max_h)
|
||||
s->r.top = max_h - tmp_h;
|
||||
|
||||
if ((is_yuv420(f->fmt->color) || is_yuv422(f->fmt->color)) &&
|
||||
cr->c.left & 1)
|
||||
cr->c.left -= 1;
|
||||
s->r.left & 1)
|
||||
s->r.left -= 1;
|
||||
|
||||
pr_debug("Aligned l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
|
||||
cr->c.left, cr->c.top, cr->c.width, cr->c.height, max_w, max_h);
|
||||
s->r.left, s->r.top, s->r.width, s->r.height, max_w, max_h);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -392,8 +392,7 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
|
|||
void gsc_set_frame_size(struct gsc_frame *frame, int width, int height);
|
||||
int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f);
|
||||
void gsc_check_crop_change(u32 tmp_w, u32 tmp_h, u32 *w, u32 *h);
|
||||
int gsc_g_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr);
|
||||
int gsc_try_crop(struct gsc_ctx *ctx, struct v4l2_crop *cr);
|
||||
int gsc_try_selection(struct gsc_ctx *ctx, struct v4l2_selection *s);
|
||||
int gsc_cal_prescaler_ratio(struct gsc_variant *var, u32 src, u32 dst,
|
||||
u32 *ratio);
|
||||
void gsc_get_prescaler_shfactor(u32 hratio, u32 vratio, u32 *sh);
|
||||
|
|
|
|||
|
|
@ -494,30 +494,27 @@ static int gsc_m2m_s_selection(struct file *file, void *fh,
|
|||
{
|
||||
struct gsc_frame *frame;
|
||||
struct gsc_ctx *ctx = fh_to_ctx(fh);
|
||||
struct v4l2_crop cr;
|
||||
struct gsc_variant *variant = ctx->gsc_dev->variant;
|
||||
struct v4l2_selection sel = *s;
|
||||
int ret;
|
||||
|
||||
cr.type = s->type;
|
||||
cr.c = s->r;
|
||||
|
||||
if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
|
||||
(s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
|
||||
return -EINVAL;
|
||||
|
||||
ret = gsc_try_crop(ctx, &cr);
|
||||
ret = gsc_try_selection(ctx, &sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (s->flags & V4L2_SEL_FLAG_LE &&
|
||||
!is_rectangle_enclosed(&cr.c, &s->r))
|
||||
!is_rectangle_enclosed(&sel.r, &s->r))
|
||||
return -ERANGE;
|
||||
|
||||
if (s->flags & V4L2_SEL_FLAG_GE &&
|
||||
!is_rectangle_enclosed(&s->r, &cr.c))
|
||||
!is_rectangle_enclosed(&s->r, &sel.r))
|
||||
return -ERANGE;
|
||||
|
||||
s->r = cr.c;
|
||||
s->r = sel.r;
|
||||
|
||||
switch (s->target) {
|
||||
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
|
||||
|
|
@ -539,15 +536,15 @@ static int gsc_m2m_s_selection(struct file *file, void *fh,
|
|||
/* Check to see if scaling ratio is within supported range */
|
||||
if (gsc_ctx_state_is_set(GSC_DST_FMT | GSC_SRC_FMT, ctx)) {
|
||||
if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
||||
ret = gsc_check_scaler_ratio(variant, cr.c.width,
|
||||
cr.c.height, ctx->d_frame.crop.width,
|
||||
ret = gsc_check_scaler_ratio(variant, sel.r.width,
|
||||
sel.r.height, ctx->d_frame.crop.width,
|
||||
ctx->d_frame.crop.height,
|
||||
ctx->gsc_ctrls.rotate->val, ctx->out_path);
|
||||
} else {
|
||||
ret = gsc_check_scaler_ratio(variant,
|
||||
ctx->s_frame.crop.width,
|
||||
ctx->s_frame.crop.height, cr.c.width,
|
||||
cr.c.height, ctx->gsc_ctrls.rotate->val,
|
||||
ctx->s_frame.crop.height, sel.r.width,
|
||||
sel.r.height, ctx->gsc_ctrls.rotate->val,
|
||||
ctx->out_path);
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +554,7 @@ static int gsc_m2m_s_selection(struct file *file, void *fh,
|
|||
}
|
||||
}
|
||||
|
||||
frame->crop = cr.c;
|
||||
frame->crop = sel.r;
|
||||
|
||||
gsc_ctx_state_lock_set(GSC_PARAMS, ctx);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -596,12 +596,14 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
|
|||
{
|
||||
struct fimc_frame *frame;
|
||||
|
||||
if (V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE == type) {
|
||||
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ||
|
||||
type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
||||
if (fimc_ctx_state_is_set(FIMC_CTX_M2M, ctx))
|
||||
frame = &ctx->s_frame;
|
||||
else
|
||||
return ERR_PTR(-EINVAL);
|
||||
} else if (V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE == type) {
|
||||
} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
|
||||
type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
||||
frame = &ctx->d_frame;
|
||||
} else {
|
||||
v4l2_err(ctx->fimc_dev->v4l2_dev,
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ const char *fimc_is_param_strerr(unsigned int error)
|
|||
return "ERROR_SENSOR_INVALID_SIZE";
|
||||
case ERROR_SENSOR_INVALID_SETTING:
|
||||
return "ERROR_SENSOR_INVALID_SETTING";
|
||||
case ERROR_SENSOR_ACTURATOR_INIT_FAIL:
|
||||
return "ERROR_SENSOR_ACTURATOR_INIT_FAIL";
|
||||
case ERROR_SENSOR_ACTUATOR_INIT_FAIL:
|
||||
return "ERROR_SENSOR_ACTUATOR_INIT_FAIL";
|
||||
case ERROR_SENSOR_INVALID_AF_POS:
|
||||
return "ERROR_SENSOR_INVALID_AF_POS";
|
||||
case ERROR_SENSOR_UNSUPPORT_FUNC:
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ enum fimc_is_error {
|
|||
ERROR_SENSOR_INVALID_EXPOSURETIME,
|
||||
ERROR_SENSOR_INVALID_SIZE,
|
||||
ERROR_SENSOR_INVALID_SETTING,
|
||||
ERROR_SENSOR_ACTURATOR_INIT_FAIL,
|
||||
ERROR_SENSOR_ACTUATOR_INIT_FAIL,
|
||||
ERROR_SENSOR_INVALID_AF_POS,
|
||||
ERROR_SENSOR_UNSUPPORT_FUNC,
|
||||
ERROR_SENSOR_UNSUPPORT_PERI,
|
||||
|
|
|
|||
|
|
@ -383,60 +383,80 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fimc_m2m_cropcap(struct file *file, void *fh,
|
||||
struct v4l2_cropcap *cr)
|
||||
static int fimc_m2m_g_selection(struct file *file, void *fh,
|
||||
struct v4l2_selection *s)
|
||||
{
|
||||
struct fimc_ctx *ctx = fh_to_ctx(fh);
|
||||
struct fimc_frame *frame;
|
||||
|
||||
frame = ctx_get_frame(ctx, cr->type);
|
||||
frame = ctx_get_frame(ctx, s->type);
|
||||
if (IS_ERR(frame))
|
||||
return PTR_ERR(frame);
|
||||
|
||||
cr->bounds.left = 0;
|
||||
cr->bounds.top = 0;
|
||||
cr->bounds.width = frame->o_width;
|
||||
cr->bounds.height = frame->o_height;
|
||||
cr->defrect = cr->bounds;
|
||||
switch (s->target) {
|
||||
case V4L2_SEL_TGT_CROP:
|
||||
case V4L2_SEL_TGT_CROP_DEFAULT:
|
||||
case V4L2_SEL_TGT_CROP_BOUNDS:
|
||||
if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case V4L2_SEL_TGT_COMPOSE:
|
||||
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
|
||||
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
|
||||
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (s->target) {
|
||||
case V4L2_SEL_TGT_CROP:
|
||||
case V4L2_SEL_TGT_COMPOSE:
|
||||
s->r.left = frame->offs_h;
|
||||
s->r.top = frame->offs_v;
|
||||
s->r.width = frame->width;
|
||||
s->r.height = frame->height;
|
||||
break;
|
||||
case V4L2_SEL_TGT_CROP_DEFAULT:
|
||||
case V4L2_SEL_TGT_CROP_BOUNDS:
|
||||
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
|
||||
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
|
||||
s->r.left = 0;
|
||||
s->r.top = 0;
|
||||
s->r.width = frame->o_width;
|
||||
s->r.height = frame->o_height;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
|
||||
{
|
||||
struct fimc_ctx *ctx = fh_to_ctx(fh);
|
||||
struct fimc_frame *frame;
|
||||
|
||||
frame = ctx_get_frame(ctx, cr->type);
|
||||
if (IS_ERR(frame))
|
||||
return PTR_ERR(frame);
|
||||
|
||||
cr->c.left = frame->offs_h;
|
||||
cr->c.top = frame->offs_v;
|
||||
cr->c.width = frame->width;
|
||||
cr->c.height = frame->height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
|
||||
static int fimc_m2m_try_selection(struct fimc_ctx *ctx,
|
||||
struct v4l2_selection *s)
|
||||
{
|
||||
struct fimc_dev *fimc = ctx->fimc_dev;
|
||||
struct fimc_frame *f;
|
||||
u32 min_size, halign, depth = 0;
|
||||
int i;
|
||||
|
||||
if (cr->c.top < 0 || cr->c.left < 0) {
|
||||
if (s->r.top < 0 || s->r.left < 0) {
|
||||
v4l2_err(&fimc->m2m.vfd,
|
||||
"doesn't support negative values for top & left\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
|
||||
if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
||||
f = &ctx->d_frame;
|
||||
else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
|
||||
if (s->target != V4L2_SEL_TGT_COMPOSE)
|
||||
return -EINVAL;
|
||||
} else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
||||
f = &ctx->s_frame;
|
||||
else
|
||||
if (s->target != V4L2_SEL_TGT_CROP)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
min_size = (f == &ctx->s_frame) ?
|
||||
fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
|
||||
|
|
@ -450,61 +470,61 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
|
|||
for (i = 0; i < f->fmt->memplanes; i++)
|
||||
depth += f->fmt->depth[i];
|
||||
|
||||
v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
|
||||
v4l_bound_align_image(&s->r.width, min_size, f->o_width,
|
||||
ffs(min_size) - 1,
|
||||
&cr->c.height, min_size, f->o_height,
|
||||
&s->r.height, min_size, f->o_height,
|
||||
halign, 64/(ALIGN(depth, 8)));
|
||||
|
||||
/* adjust left/top if cropping rectangle is out of bounds */
|
||||
if (cr->c.left + cr->c.width > f->o_width)
|
||||
cr->c.left = f->o_width - cr->c.width;
|
||||
if (cr->c.top + cr->c.height > f->o_height)
|
||||
cr->c.top = f->o_height - cr->c.height;
|
||||
if (s->r.left + s->r.width > f->o_width)
|
||||
s->r.left = f->o_width - s->r.width;
|
||||
if (s->r.top + s->r.height > f->o_height)
|
||||
s->r.top = f->o_height - s->r.height;
|
||||
|
||||
cr->c.left = round_down(cr->c.left, min_size);
|
||||
cr->c.top = round_down(cr->c.top, fimc->variant->hor_offs_align);
|
||||
s->r.left = round_down(s->r.left, min_size);
|
||||
s->r.top = round_down(s->r.top, fimc->variant->hor_offs_align);
|
||||
|
||||
dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
|
||||
cr->c.left, cr->c.top, cr->c.width, cr->c.height,
|
||||
s->r.left, s->r.top, s->r.width, s->r.height,
|
||||
f->f_width, f->f_height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fimc_m2m_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
|
||||
static int fimc_m2m_s_selection(struct file *file, void *fh,
|
||||
struct v4l2_selection *s)
|
||||
{
|
||||
struct fimc_ctx *ctx = fh_to_ctx(fh);
|
||||
struct fimc_dev *fimc = ctx->fimc_dev;
|
||||
struct v4l2_crop cr = *crop;
|
||||
struct fimc_frame *f;
|
||||
int ret;
|
||||
|
||||
ret = fimc_m2m_try_crop(ctx, &cr);
|
||||
ret = fimc_m2m_try_selection(ctx, s);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
f = (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ?
|
||||
f = (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
|
||||
&ctx->s_frame : &ctx->d_frame;
|
||||
|
||||
/* Check to see if scaling ratio is within supported range */
|
||||
if (cr.type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
|
||||
ret = fimc_check_scaler_ratio(ctx, cr.c.width,
|
||||
cr.c.height, ctx->d_frame.width,
|
||||
if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
||||
ret = fimc_check_scaler_ratio(ctx, s->r.width,
|
||||
s->r.height, ctx->d_frame.width,
|
||||
ctx->d_frame.height, ctx->rotation);
|
||||
} else {
|
||||
ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width,
|
||||
ctx->s_frame.height, cr.c.width,
|
||||
cr.c.height, ctx->rotation);
|
||||
ctx->s_frame.height, s->r.width,
|
||||
s->r.height, ctx->rotation);
|
||||
}
|
||||
if (ret) {
|
||||
v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
f->offs_h = cr.c.left;
|
||||
f->offs_v = cr.c.top;
|
||||
f->width = cr.c.width;
|
||||
f->height = cr.c.height;
|
||||
f->offs_h = s->r.left;
|
||||
f->offs_v = s->r.top;
|
||||
f->width = s->r.width;
|
||||
f->height = s->r.height;
|
||||
|
||||
fimc_ctx_state_set(FIMC_PARAMS, ctx);
|
||||
|
||||
|
|
@ -528,9 +548,8 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
|
|||
.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
|
||||
.vidioc_streamon = v4l2_m2m_ioctl_streamon,
|
||||
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
|
||||
.vidioc_g_crop = fimc_m2m_g_crop,
|
||||
.vidioc_s_crop = fimc_m2m_s_crop,
|
||||
.vidioc_cropcap = fimc_m2m_cropcap
|
||||
.vidioc_g_selection = fimc_m2m_g_selection,
|
||||
.vidioc_s_selection = fimc_m2m_s_selection,
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -717,6 +736,7 @@ int fimc_register_m2m_device(struct fimc_dev *fimc,
|
|||
vfd->release = video_device_release_empty;
|
||||
vfd->lock = &fimc->lock;
|
||||
vfd->vfl_dir = VFL_DIR_M2M;
|
||||
set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags);
|
||||
|
||||
snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id);
|
||||
video_set_drvdata(vfd, fimc);
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
|
|||
*/
|
||||
np = of_get_parent(rem);
|
||||
|
||||
if (np && !of_node_cmp(np->name, "i2c-isp"))
|
||||
if (of_node_name_eq(np, "i2c-isp"))
|
||||
pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK;
|
||||
else
|
||||
pd->fimc_bus_type = pd->sensor_bus_type;
|
||||
|
|
@ -495,7 +495,7 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
|
|||
for_each_available_child_of_node(parent, node) {
|
||||
struct device_node *port;
|
||||
|
||||
if (of_node_cmp(node->name, "csis"))
|
||||
if (!of_node_name_eq(node, "csis"))
|
||||
continue;
|
||||
/* The csis node can have only port subnode. */
|
||||
port = of_get_next_child(node, NULL);
|
||||
|
|
@ -720,13 +720,13 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd,
|
|||
continue;
|
||||
|
||||
/* If driver of any entity isn't ready try all again later. */
|
||||
if (!strcmp(node->name, CSIS_OF_NODE_NAME))
|
||||
if (of_node_name_eq(node, CSIS_OF_NODE_NAME))
|
||||
plat_entity = IDX_CSIS;
|
||||
else if (!strcmp(node->name, FIMC_IS_OF_NODE_NAME))
|
||||
else if (of_node_name_eq(node, FIMC_IS_OF_NODE_NAME))
|
||||
plat_entity = IDX_IS_ISP;
|
||||
else if (!strcmp(node->name, FIMC_LITE_OF_NODE_NAME))
|
||||
else if (of_node_name_eq(node, FIMC_LITE_OF_NODE_NAME))
|
||||
plat_entity = IDX_FLITE;
|
||||
else if (!strcmp(node->name, FIMC_OF_NODE_NAME) &&
|
||||
else if (of_node_name_eq(node, FIMC_OF_NODE_NAME) &&
|
||||
!of_property_read_bool(node, "samsung,lcd-wb"))
|
||||
plat_entity = IDX_FIMC;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/sched.h>
|
||||
|
|
@ -1607,7 +1606,7 @@ static const struct v4l2_m2m_ops m2m_ops = {
|
|||
.job_abort = pxp_job_abort,
|
||||
};
|
||||
|
||||
static void pxp_soft_reset(struct pxp_dev *dev)
|
||||
static int pxp_soft_reset(struct pxp_dev *dev)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
|
@ -1620,10 +1619,12 @@ static void pxp_soft_reset(struct pxp_dev *dev)
|
|||
ret = readl_poll_timeout(dev->mmio + HW_PXP_CTRL, val,
|
||||
val & BM_PXP_CTRL_CLKGATE, 0, 100);
|
||||
if (ret < 0)
|
||||
pr_err("PXP reset timeout\n");
|
||||
return ret;
|
||||
|
||||
writel(BM_PXP_CTRL_SFTRST, dev->mmio + HW_PXP_CTRL_CLR);
|
||||
writel(BM_PXP_CTRL_CLKGATE, dev->mmio + HW_PXP_CTRL_CLR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxp_probe(struct platform_device *pdev)
|
||||
|
|
@ -1666,8 +1667,15 @@ static int pxp_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
clk_prepare_enable(dev->clk);
|
||||
pxp_soft_reset(dev);
|
||||
ret = clk_prepare_enable(dev->clk);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = pxp_soft_reset(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "PXP reset timeout: %d\n", ret);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
spin_lock_init(&dev->irqlock);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* sensor.
|
||||
*
|
||||
* The data sheet for this device can be found at:
|
||||
* http://www.marvell.com/products/pc_connectivity/88alp01/
|
||||
* http://wiki.laptop.org/images/5/5c/88ALP01_Datasheet_July_2007.pdf
|
||||
*
|
||||
* Copyright 2006-11 One Laptop Per Child Association, Inc.
|
||||
* Copyright 2006-11 Jonathan Corbet <corbet@lwn.net>
|
||||
|
|
|
|||
|
|
@ -1087,7 +1087,6 @@ static void mtk_venc_worker(struct work_struct *work)
|
|||
src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
|
||||
memset(&frm_buf, 0, sizeof(frm_buf));
|
||||
for (i = 0; i < src_buf->num_planes ; i++) {
|
||||
frm_buf.fb_addr[i].va = vb2_plane_vaddr(src_buf, i);
|
||||
frm_buf.fb_addr[i].dma_addr =
|
||||
vb2_dma_contig_plane_dma_addr(src_buf, i);
|
||||
frm_buf.fb_addr[i].size =
|
||||
|
|
@ -1098,14 +1097,11 @@ static void mtk_venc_worker(struct work_struct *work)
|
|||
bs_buf.size = (size_t)dst_buf->planes[0].length;
|
||||
|
||||
mtk_v4l2_debug(2,
|
||||
"Framebuf VA=%p PA=%llx Size=0x%zx;VA=%p PA=0x%llx Size=0x%zx;VA=%p PA=0x%llx Size=%zu",
|
||||
frm_buf.fb_addr[0].va,
|
||||
"Framebuf PA=%llx Size=0x%zx;PA=0x%llx Size=0x%zx;PA=0x%llx Size=%zu",
|
||||
(u64)frm_buf.fb_addr[0].dma_addr,
|
||||
frm_buf.fb_addr[0].size,
|
||||
frm_buf.fb_addr[1].va,
|
||||
(u64)frm_buf.fb_addr[1].dma_addr,
|
||||
frm_buf.fb_addr[1].size,
|
||||
frm_buf.fb_addr[2].va,
|
||||
(u64)frm_buf.fb_addr[2].dma_addr,
|
||||
frm_buf.fb_addr[2].size);
|
||||
|
||||
|
|
|
|||
|
|
@ -41,25 +41,27 @@ int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
|
|||
node = of_parse_phandle(dev->of_node, "mediatek,larb", 0);
|
||||
if (!node) {
|
||||
mtk_v4l2_err("no mediatek,larb found");
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
}
|
||||
pdev = of_find_device_by_node(node);
|
||||
of_node_put(node);
|
||||
if (!pdev) {
|
||||
mtk_v4l2_err("no mediatek,larb device found");
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
}
|
||||
pm->larbvenc = &pdev->dev;
|
||||
|
||||
node = of_parse_phandle(dev->of_node, "mediatek,larb", 1);
|
||||
if (!node) {
|
||||
mtk_v4l2_err("no mediatek,larb found");
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pdev = of_find_device_by_node(node);
|
||||
of_node_put(node);
|
||||
if (!pdev) {
|
||||
mtk_v4l2_err("no mediatek,larb device found");
|
||||
return -1;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pm->larbvenclt = &pdev->dev;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,11 @@ struct mtk_vcodec_mem {
|
|||
dma_addr_t dma_addr;
|
||||
};
|
||||
|
||||
struct mtk_vcodec_fb {
|
||||
size_t size;
|
||||
dma_addr_t dma_addr;
|
||||
};
|
||||
|
||||
struct mtk_vcodec_ctx;
|
||||
struct mtk_vcodec_dev;
|
||||
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ struct venc_enc_param {
|
|||
* @fb_addr: plane frame buffer addresses
|
||||
*/
|
||||
struct venc_frm_buf {
|
||||
struct mtk_vcodec_mem fb_addr[MTK_VCODEC_MAX_PLANES];
|
||||
struct mtk_vcodec_fb fb_addr[MTK_VCODEC_MAX_PLANES];
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@
|
|||
/* VFE halt timeout */
|
||||
#define VFE_HALT_TIMEOUT_MS 100
|
||||
/* Max number of frame drop updates per frame */
|
||||
#define VFE_FRAME_DROP_UPDATES 5
|
||||
/* Frame drop value. NOTE: VAL + UPDATES should not exceed 31 */
|
||||
#define VFE_FRAME_DROP_VAL 20
|
||||
#define VFE_FRAME_DROP_UPDATES 2
|
||||
/* Frame drop value. VAL + UPDATES - 1 should not exceed 31 */
|
||||
#define VFE_FRAME_DROP_VAL 30
|
||||
|
||||
#define VFE_NEXT_SOF_MS 500
|
||||
|
||||
|
|
@ -659,7 +659,9 @@ static int vfe_enable_output(struct vfe_line *line)
|
|||
struct vfe_device *vfe = to_vfe(line);
|
||||
struct vfe_output *output = &line->output;
|
||||
const struct vfe_hw_ops *ops = vfe->ops;
|
||||
struct media_entity *sensor;
|
||||
unsigned long flags;
|
||||
unsigned int frame_skip = 0;
|
||||
unsigned int i;
|
||||
u16 ub_size;
|
||||
|
||||
|
|
@ -667,6 +669,17 @@ static int vfe_enable_output(struct vfe_line *line)
|
|||
if (!ub_size)
|
||||
return -EINVAL;
|
||||
|
||||
sensor = camss_find_sensor(&line->subdev.entity);
|
||||
if (sensor) {
|
||||
struct v4l2_subdev *subdev =
|
||||
media_entity_to_v4l2_subdev(sensor);
|
||||
|
||||
v4l2_subdev_call(subdev, sensor, g_skip_frames, &frame_skip);
|
||||
/* Max frame skip is 29 frames */
|
||||
if (frame_skip > VFE_FRAME_DROP_VAL - 1)
|
||||
frame_skip = VFE_FRAME_DROP_VAL - 1;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&vfe->output_lock, flags);
|
||||
|
||||
ops->reg_update_clear(vfe, line->id);
|
||||
|
|
@ -695,10 +708,10 @@ static int vfe_enable_output(struct vfe_line *line)
|
|||
|
||||
switch (output->state) {
|
||||
case VFE_OUTPUT_SINGLE:
|
||||
vfe_output_frame_drop(vfe, output, 1);
|
||||
vfe_output_frame_drop(vfe, output, 1 << frame_skip);
|
||||
break;
|
||||
case VFE_OUTPUT_CONTINUOUS:
|
||||
vfe_output_frame_drop(vfe, output, 3);
|
||||
vfe_output_frame_drop(vfe, output, 3 << frame_skip);
|
||||
break;
|
||||
default:
|
||||
vfe_output_frame_drop(vfe, output, 0);
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ void camss_disable_clocks(int nclocks, struct camss_clock *clock)
|
|||
*
|
||||
* Return a pointer to sensor media entity or NULL if not found
|
||||
*/
|
||||
static struct media_entity *camss_find_sensor(struct media_entity *entity)
|
||||
struct media_entity *camss_find_sensor(struct media_entity *entity)
|
||||
{
|
||||
struct media_pad *pad;
|
||||
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ void camss_add_clock_margin(u64 *rate);
|
|||
int camss_enable_clocks(int nclocks, struct camss_clock *clock,
|
||||
struct device *dev);
|
||||
void camss_disable_clocks(int nclocks, struct camss_clock *clock);
|
||||
struct media_entity *camss_find_sensor(struct media_entity *entity);
|
||||
int camss_get_pixel_clock(struct media_entity *entity, u32 *pixel_clock);
|
||||
int camss_pm_domain_on(struct camss *camss, int id);
|
||||
void camss_pm_domain_off(struct camss *camss, int id);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ static void venus_sys_error_handler(struct work_struct *work)
|
|||
hfi_core_deinit(core, true);
|
||||
hfi_destroy(core);
|
||||
mutex_lock(&core->lock);
|
||||
venus_shutdown(core->dev);
|
||||
venus_shutdown(core);
|
||||
|
||||
pm_runtime_put_sync(core->dev);
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ static void venus_sys_error_handler(struct work_struct *work)
|
|||
|
||||
pm_runtime_get_sync(core->dev);
|
||||
|
||||
ret |= venus_boot(core->dev, core->res->fwname);
|
||||
ret |= venus_boot(core);
|
||||
|
||||
ret |= hfi_core_resume(core, true);
|
||||
|
||||
|
|
@ -264,6 +264,14 @@ static int venus_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!dev->dma_parms) {
|
||||
dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
|
||||
GFP_KERNEL);
|
||||
if (!dev->dma_parms)
|
||||
return -ENOMEM;
|
||||
}
|
||||
dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
|
||||
|
||||
INIT_LIST_HEAD(&core->instances);
|
||||
mutex_init(&core->lock);
|
||||
INIT_DELAYED_WORK(&core->work, venus_sys_error_handler);
|
||||
|
|
@ -284,7 +292,15 @@ static int venus_probe(struct platform_device *pdev)
|
|||
if (ret < 0)
|
||||
goto err_runtime_disable;
|
||||
|
||||
ret = venus_boot(dev, core->res->fwname);
|
||||
ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
|
||||
if (ret)
|
||||
goto err_runtime_disable;
|
||||
|
||||
ret = venus_firmware_init(core);
|
||||
if (ret)
|
||||
goto err_runtime_disable;
|
||||
|
||||
ret = venus_boot(core);
|
||||
if (ret)
|
||||
goto err_runtime_disable;
|
||||
|
||||
|
|
@ -308,10 +324,6 @@ static int venus_probe(struct platform_device *pdev)
|
|||
if (ret)
|
||||
goto err_core_deinit;
|
||||
|
||||
ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
|
||||
if (ret)
|
||||
goto err_dev_unregister;
|
||||
|
||||
ret = pm_runtime_put_sync(dev);
|
||||
if (ret)
|
||||
goto err_dev_unregister;
|
||||
|
|
@ -323,7 +335,7 @@ err_dev_unregister:
|
|||
err_core_deinit:
|
||||
hfi_core_deinit(core, false);
|
||||
err_venus_shutdown:
|
||||
venus_shutdown(dev);
|
||||
venus_shutdown(core);
|
||||
err_runtime_disable:
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
|
@ -344,9 +356,11 @@ static int venus_remove(struct platform_device *pdev)
|
|||
WARN_ON(ret);
|
||||
|
||||
hfi_destroy(core);
|
||||
venus_shutdown(dev);
|
||||
venus_shutdown(core);
|
||||
of_platform_depopulate(dev);
|
||||
|
||||
venus_firmware_deinit(core);
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ struct venus_caps {
|
|||
* @dev: convenience struct device pointer
|
||||
* @dev_dec: convenience struct device pointer for decoder device
|
||||
* @dev_enc: convenience struct device pointer for encoder device
|
||||
* @use_tz: a flag that suggests presence of trustzone
|
||||
* @lock: a lock for this strucure
|
||||
* @instances: a list_head of all instances
|
||||
* @insts_count: num of instances
|
||||
|
|
@ -129,6 +130,11 @@ struct venus_core {
|
|||
struct device *dev;
|
||||
struct device *dev_dec;
|
||||
struct device *dev_enc;
|
||||
unsigned int use_tz;
|
||||
struct video_firmware {
|
||||
struct device *dev;
|
||||
struct iommu_domain *iommu_domain;
|
||||
} fw;
|
||||
struct mutex lock;
|
||||
struct list_head instances;
|
||||
atomic_t insts_count;
|
||||
|
|
|
|||
|
|
@ -15,32 +15,66 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/qcom_scm.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/soc/qcom/mdt_loader.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "firmware.h"
|
||||
#include "hfi_venus_io.h"
|
||||
|
||||
#define VENUS_PAS_ID 9
|
||||
#define VENUS_FW_MEM_SIZE (6 * SZ_1M)
|
||||
#define VENUS_FW_START_ADDR 0x0
|
||||
|
||||
int venus_boot(struct device *dev, const char *fwname)
|
||||
static void venus_reset_cpu(struct venus_core *core)
|
||||
{
|
||||
void __iomem *base = core->base;
|
||||
|
||||
writel(0, base + WRAPPER_FW_START_ADDR);
|
||||
writel(VENUS_FW_MEM_SIZE, base + WRAPPER_FW_END_ADDR);
|
||||
writel(0, base + WRAPPER_CPA_START_ADDR);
|
||||
writel(VENUS_FW_MEM_SIZE, base + WRAPPER_CPA_END_ADDR);
|
||||
writel(VENUS_FW_MEM_SIZE, base + WRAPPER_NONPIX_START_ADDR);
|
||||
writel(VENUS_FW_MEM_SIZE, base + WRAPPER_NONPIX_END_ADDR);
|
||||
writel(0x0, base + WRAPPER_CPU_CGC_DIS);
|
||||
writel(0x0, base + WRAPPER_CPU_CLOCK_CONFIG);
|
||||
|
||||
/* Bring ARM9 out of reset */
|
||||
writel(0, base + WRAPPER_A9SS_SW_RESET);
|
||||
}
|
||||
|
||||
int venus_set_hw_state(struct venus_core *core, bool resume)
|
||||
{
|
||||
if (core->use_tz)
|
||||
return qcom_scm_set_remote_state(resume, 0);
|
||||
|
||||
if (resume)
|
||||
venus_reset_cpu(core);
|
||||
else
|
||||
writel(1, core->base + WRAPPER_A9SS_SW_RESET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int venus_load_fw(struct venus_core *core, const char *fwname,
|
||||
phys_addr_t *mem_phys, size_t *mem_size)
|
||||
{
|
||||
const struct firmware *mdt;
|
||||
struct device_node *node;
|
||||
phys_addr_t mem_phys;
|
||||
struct device *dev;
|
||||
struct resource r;
|
||||
ssize_t fw_size;
|
||||
size_t mem_size;
|
||||
void *mem_va;
|
||||
int ret;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) || !qcom_scm_is_available())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev = core->dev;
|
||||
node = of_parse_phandle(dev->of_node, "memory-region", 0);
|
||||
if (!node) {
|
||||
dev_err(dev, "no memory-region specified\n");
|
||||
|
|
@ -51,16 +85,16 @@ int venus_boot(struct device *dev, const char *fwname)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
mem_phys = r.start;
|
||||
mem_size = resource_size(&r);
|
||||
*mem_phys = r.start;
|
||||
*mem_size = resource_size(&r);
|
||||
|
||||
if (mem_size < VENUS_FW_MEM_SIZE)
|
||||
if (*mem_size < VENUS_FW_MEM_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
mem_va = memremap(r.start, mem_size, MEMREMAP_WC);
|
||||
mem_va = memremap(r.start, *mem_size, MEMREMAP_WC);
|
||||
if (!mem_va) {
|
||||
dev_err(dev, "unable to map memory region: %pa+%zx\n",
|
||||
&r.start, mem_size);
|
||||
&r.start, *mem_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -75,24 +109,181 @@ int venus_boot(struct device *dev, const char *fwname)
|
|||
goto err_unmap;
|
||||
}
|
||||
|
||||
ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys,
|
||||
mem_size, NULL);
|
||||
if (core->use_tz)
|
||||
ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID,
|
||||
mem_va, *mem_phys, *mem_size, NULL);
|
||||
else
|
||||
ret = qcom_mdt_load_no_init(dev, mdt, fwname, VENUS_PAS_ID,
|
||||
mem_va, *mem_phys, *mem_size, NULL);
|
||||
|
||||
release_firmware(mdt);
|
||||
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
|
||||
ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID);
|
||||
if (ret)
|
||||
goto err_unmap;
|
||||
|
||||
err_unmap:
|
||||
memunmap(mem_va);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int venus_shutdown(struct device *dev)
|
||||
static int venus_boot_no_tz(struct venus_core *core, phys_addr_t mem_phys,
|
||||
size_t mem_size)
|
||||
{
|
||||
return qcom_scm_pas_shutdown(VENUS_PAS_ID);
|
||||
struct iommu_domain *iommu;
|
||||
struct device *dev;
|
||||
int ret;
|
||||
|
||||
dev = core->fw.dev;
|
||||
if (!dev)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
iommu = core->fw.iommu_domain;
|
||||
|
||||
ret = iommu_map(iommu, VENUS_FW_START_ADDR, mem_phys, mem_size,
|
||||
IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV);
|
||||
if (ret) {
|
||||
dev_err(dev, "could not map video firmware region\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
venus_reset_cpu(core);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int venus_shutdown_no_tz(struct venus_core *core)
|
||||
{
|
||||
struct iommu_domain *iommu;
|
||||
size_t unmapped;
|
||||
u32 reg;
|
||||
struct device *dev = core->fw.dev;
|
||||
void __iomem *base = core->base;
|
||||
|
||||
/* Assert the reset to ARM9 */
|
||||
reg = readl_relaxed(base + WRAPPER_A9SS_SW_RESET);
|
||||
reg |= WRAPPER_A9SS_SW_RESET_BIT;
|
||||
writel_relaxed(reg, base + WRAPPER_A9SS_SW_RESET);
|
||||
|
||||
/* Make sure reset is asserted before the mapping is removed */
|
||||
mb();
|
||||
|
||||
iommu = core->fw.iommu_domain;
|
||||
|
||||
unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, VENUS_FW_MEM_SIZE);
|
||||
if (unmapped != VENUS_FW_MEM_SIZE)
|
||||
dev_err(dev, "failed to unmap firmware\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int venus_boot(struct venus_core *core)
|
||||
{
|
||||
struct device *dev = core->dev;
|
||||
phys_addr_t mem_phys;
|
||||
size_t mem_size;
|
||||
int ret;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ||
|
||||
(core->use_tz && !qcom_scm_is_available()))
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
ret = venus_load_fw(core, core->res->fwname, &mem_phys, &mem_size);
|
||||
if (ret) {
|
||||
dev_err(dev, "fail to load video firmware\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (core->use_tz)
|
||||
ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID);
|
||||
else
|
||||
ret = venus_boot_no_tz(core, mem_phys, mem_size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int venus_shutdown(struct venus_core *core)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (core->use_tz)
|
||||
ret = qcom_scm_pas_shutdown(VENUS_PAS_ID);
|
||||
else
|
||||
ret = venus_shutdown_no_tz(core);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int venus_firmware_init(struct venus_core *core)
|
||||
{
|
||||
struct platform_device_info info;
|
||||
struct iommu_domain *iommu_dom;
|
||||
struct platform_device *pdev;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
|
||||
np = of_get_child_by_name(core->dev->of_node, "video-firmware");
|
||||
if (!np) {
|
||||
core->use_tz = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.fwnode = &np->fwnode;
|
||||
info.parent = core->dev;
|
||||
info.name = np->name;
|
||||
info.dma_mask = DMA_BIT_MASK(32);
|
||||
|
||||
pdev = platform_device_register_full(&info);
|
||||
if (IS_ERR(pdev)) {
|
||||
of_node_put(np);
|
||||
return PTR_ERR(pdev);
|
||||
}
|
||||
|
||||
pdev->dev.of_node = np;
|
||||
|
||||
ret = of_dma_configure(&pdev->dev, np, true);
|
||||
if (ret) {
|
||||
dev_err(core->dev, "dma configure fail\n");
|
||||
goto err_unregister;
|
||||
}
|
||||
|
||||
core->fw.dev = &pdev->dev;
|
||||
|
||||
iommu_dom = iommu_domain_alloc(&platform_bus_type);
|
||||
if (!iommu_dom) {
|
||||
dev_err(core->fw.dev, "Failed to allocate iommu domain\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_unregister;
|
||||
}
|
||||
|
||||
ret = iommu_attach_device(iommu_dom, core->fw.dev);
|
||||
if (ret) {
|
||||
dev_err(core->fw.dev, "could not attach device\n");
|
||||
goto err_iommu_free;
|
||||
}
|
||||
|
||||
core->fw.iommu_domain = iommu_dom;
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
return 0;
|
||||
|
||||
err_iommu_free:
|
||||
iommu_domain_free(iommu_dom);
|
||||
err_unregister:
|
||||
platform_device_unregister(pdev);
|
||||
of_node_put(np);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void venus_firmware_deinit(struct venus_core *core)
|
||||
{
|
||||
struct iommu_domain *iommu;
|
||||
|
||||
if (!core->fw.dev)
|
||||
return;
|
||||
|
||||
iommu = core->fw.iommu_domain;
|
||||
|
||||
iommu_detach_device(iommu, core->fw.dev);
|
||||
iommu_domain_free(iommu);
|
||||
|
||||
platform_device_unregister(to_platform_device(core->fw.dev));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,20 @@
|
|||
|
||||
struct device;
|
||||
|
||||
int venus_boot(struct device *dev, const char *fwname);
|
||||
int venus_shutdown(struct device *dev);
|
||||
int venus_firmware_init(struct venus_core *core);
|
||||
void venus_firmware_deinit(struct venus_core *core);
|
||||
int venus_boot(struct venus_core *core);
|
||||
int venus_shutdown(struct venus_core *core);
|
||||
int venus_set_hw_state(struct venus_core *core, bool suspend);
|
||||
|
||||
static inline int venus_set_hw_state_suspend(struct venus_core *core)
|
||||
{
|
||||
return venus_set_hw_state(core, false);
|
||||
}
|
||||
|
||||
static inline int venus_set_hw_state_resume(struct venus_core *core)
|
||||
{
|
||||
return venus_set_hw_state(core, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1215,7 +1215,7 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
|
|||
}
|
||||
case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE:
|
||||
/* not implemented on Venus 4xx */
|
||||
break;
|
||||
return -ENOTSUPP;
|
||||
default:
|
||||
return pkt_session_set_property_3xx(pkt, cookie, ptype, pdata);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/qcom_scm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "core.h"
|
||||
|
|
@ -27,6 +26,7 @@
|
|||
#include "hfi_msgs.h"
|
||||
#include "hfi_venus.h"
|
||||
#include "hfi_venus_io.h"
|
||||
#include "firmware.h"
|
||||
|
||||
#define HFI_MASK_QHDR_TX_TYPE 0xff000000
|
||||
#define HFI_MASK_QHDR_RX_TYPE 0x00ff0000
|
||||
|
|
@ -55,11 +55,6 @@
|
|||
#define IFACEQ_VAR_LARGE_PKT_SIZE 512
|
||||
#define IFACEQ_VAR_HUGE_PKT_SIZE (1024 * 12)
|
||||
|
||||
enum tzbsp_video_state {
|
||||
TZBSP_VIDEO_STATE_SUSPEND = 0,
|
||||
TZBSP_VIDEO_STATE_RESUME
|
||||
};
|
||||
|
||||
struct hfi_queue_table_header {
|
||||
u32 version;
|
||||
u32 size;
|
||||
|
|
@ -575,7 +570,7 @@ static int venus_power_off(struct venus_hfi_device *hdev)
|
|||
if (!hdev->power_enabled)
|
||||
return 0;
|
||||
|
||||
ret = qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0);
|
||||
ret = venus_set_hw_state_suspend(hdev->core);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -595,7 +590,7 @@ static int venus_power_on(struct venus_hfi_device *hdev)
|
|||
if (hdev->power_enabled)
|
||||
return 0;
|
||||
|
||||
ret = qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_RESUME, 0);
|
||||
ret = venus_set_hw_state_resume(hdev->core);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
|
|
@ -608,7 +603,7 @@ static int venus_power_on(struct venus_hfi_device *hdev)
|
|||
return 0;
|
||||
|
||||
err_suspend:
|
||||
qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0);
|
||||
venus_set_hw_state_suspend(hdev->core);
|
||||
err:
|
||||
hdev->power_enabled = false;
|
||||
return ret;
|
||||
|
|
@ -1355,6 +1350,8 @@ static int venus_session_set_property(struct venus_inst *inst, u32 ptype,
|
|||
pkt = (struct hfi_session_set_property_pkt *)packet;
|
||||
|
||||
ret = pkt_session_set_property(pkt, inst, ptype, pdata);
|
||||
if (ret == -ENOTSUPP)
|
||||
return 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,14 @@
|
|||
#define WRAPPER_CPU_STATUS (WRAPPER_BASE + 0x2014)
|
||||
#define WRAPPER_CPU_STATUS_WFI BIT(0)
|
||||
#define WRAPPER_SW_RESET (WRAPPER_BASE + 0x3000)
|
||||
#define WRAPPER_CPA_START_ADDR (WRAPPER_BASE + 0x1020)
|
||||
#define WRAPPER_CPA_END_ADDR (WRAPPER_BASE + 0x1024)
|
||||
#define WRAPPER_FW_START_ADDR (WRAPPER_BASE + 0x1028)
|
||||
#define WRAPPER_FW_END_ADDR (WRAPPER_BASE + 0x102C)
|
||||
#define WRAPPER_NONPIX_START_ADDR (WRAPPER_BASE + 0x1030)
|
||||
#define WRAPPER_NONPIX_END_ADDR (WRAPPER_BASE + 0x1034)
|
||||
#define WRAPPER_A9SS_SW_RESET (WRAPPER_BASE + 0x3000)
|
||||
#define WRAPPER_A9SS_SW_RESET_BIT BIT(4)
|
||||
|
||||
/* Venus 4xx */
|
||||
#define WRAPPER_VCODEC0_MMCC_POWER_STATUS (WRAPPER_BASE + 0x90)
|
||||
|
|
|
|||
|
|
@ -885,10 +885,8 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type,
|
|||
vbuf->field = V4L2_FIELD_NONE;
|
||||
|
||||
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
|
||||
unsigned int opb_sz = venus_helper_get_opb_size(inst);
|
||||
|
||||
vb = &vbuf->vb2_buf;
|
||||
vb2_set_plane_payload(vb, 0, bytesused ? : opb_sz);
|
||||
vb2_set_plane_payload(vb, 0, bytesused);
|
||||
vb->planes[0].data_offset = data_offset;
|
||||
vb->timestamp = timestamp_us * NSEC_PER_USEC;
|
||||
vbuf->sequence = inst->sequence_cap++;
|
||||
|
|
|
|||
|
|
@ -651,6 +651,8 @@ static int venc_set_properties(struct venus_inst *inst)
|
|||
struct hfi_framerate frate;
|
||||
struct hfi_bitrate brate;
|
||||
struct hfi_idr_period idrp;
|
||||
struct hfi_quantization quant;
|
||||
struct hfi_quantization_range quant_range;
|
||||
u32 ptype, rate_control, bitrate, profile = 0, level = 0;
|
||||
int ret;
|
||||
|
||||
|
|
@ -770,6 +772,23 @@ static int venc_set_properties(struct venus_inst *inst)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP;
|
||||
quant.qp_i = ctr->h264_i_qp;
|
||||
quant.qp_p = ctr->h264_p_qp;
|
||||
quant.qp_b = ctr->h264_b_qp;
|
||||
quant.layer_id = 0;
|
||||
ret = hfi_session_set_property(inst, ptype, &quant);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE;
|
||||
quant_range.min_qp = ctr->h264_min_qp;
|
||||
quant_range.max_qp = ctr->h264_max_qp;
|
||||
quant_range.layer_id = 0;
|
||||
ret = hfi_session_set_property(inst, ptype, &quant_range);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264) {
|
||||
profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_PROFILE,
|
||||
ctr->profile.h264);
|
||||
|
|
@ -1074,7 +1093,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
|
|||
int ret;
|
||||
|
||||
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
|
||||
src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
|
||||
src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
|
||||
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
|
||||
src_vq->ops = &venc_vb2_ops;
|
||||
src_vq->mem_ops = &vb2_dma_sg_memops;
|
||||
|
|
@ -1090,7 +1109,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
|
|||
return ret;
|
||||
|
||||
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
|
||||
dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
|
||||
dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
|
||||
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
|
||||
dst_vq->ops = &venc_vb2_ops;
|
||||
dst_vq->mem_ops = &vb2_dma_sg_memops;
|
||||
|
|
|
|||
|
|
@ -79,7 +79,10 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
{
|
||||
struct venus_inst *inst = ctrl_to_inst(ctrl);
|
||||
struct venc_controls *ctr = &inst->controls.enc;
|
||||
struct hfi_enable en = { .enable = 1 };
|
||||
struct hfi_bitrate brate;
|
||||
u32 bframes;
|
||||
u32 ptype;
|
||||
int ret;
|
||||
|
||||
switch (ctrl->id) {
|
||||
|
|
@ -88,6 +91,19 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_BITRATE:
|
||||
ctr->bitrate = ctrl->val;
|
||||
mutex_lock(&inst->lock);
|
||||
if (inst->streamon_out && inst->streamon_cap) {
|
||||
ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
|
||||
brate.bitrate = ctr->bitrate;
|
||||
brate.layer_id = 0;
|
||||
|
||||
ret = hfi_session_set_property(inst, ptype, &brate);
|
||||
if (ret) {
|
||||
mutex_unlock(&inst->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&inst->lock);
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
|
||||
ctr->bitrate_peak = ctrl->val;
|
||||
|
|
@ -173,6 +189,19 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
|
|||
|
||||
ctr->num_b_frames = bframes;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
|
||||
mutex_lock(&inst->lock);
|
||||
if (inst->streamon_out && inst->streamon_cap) {
|
||||
ptype = HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
|
||||
ret = hfi_session_set_property(inst, ptype, &en);
|
||||
|
||||
if (ret) {
|
||||
mutex_unlock(&inst->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&inst->lock);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -188,7 +217,7 @@ int venc_ctrl_init(struct venus_inst *inst)
|
|||
{
|
||||
int ret;
|
||||
|
||||
ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 27);
|
||||
ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 28);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
@ -295,7 +324,7 @@ int venc_ctrl_init(struct venus_inst *inst)
|
|||
0, INTRA_REFRESH_MBS_MAX, 1, 0);
|
||||
|
||||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 12);
|
||||
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 30);
|
||||
|
||||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, 1, 128, 1, 1);
|
||||
|
|
@ -309,6 +338,9 @@ int venc_ctrl_init(struct venus_inst *inst)
|
|||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, 0, (1 << 16) - 1, 1, 0);
|
||||
|
||||
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
|
||||
V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 0, 0, 0, 0);
|
||||
|
||||
ret = inst->ctrl_handler.error;
|
||||
if (ret)
|
||||
goto err;
|
||||
|
|
|
|||
|
|
@ -1088,6 +1088,50 @@ static const struct rvin_info rcar_info_r8a77970 = {
|
|||
.routes = rcar_info_r8a77970_routes,
|
||||
};
|
||||
|
||||
static const struct rvin_group_route rcar_info_r8a77980_routes[] = {
|
||||
{ .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
|
||||
{ .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
|
||||
{ .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
|
||||
{ .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
|
||||
{ .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
|
||||
{ .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
|
||||
{ .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
|
||||
{ .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
|
||||
{ .csi = RVIN_CSI41, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
|
||||
{ .csi = RVIN_CSI41, .channel = 1, .vin = 4, .mask = BIT(2) },
|
||||
{ .csi = RVIN_CSI41, .channel = 0, .vin = 5, .mask = BIT(2) },
|
||||
{ .csi = RVIN_CSI41, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
|
||||
{ .csi = RVIN_CSI41, .channel = 0, .vin = 6, .mask = BIT(1) },
|
||||
{ .csi = RVIN_CSI41, .channel = 2, .vin = 6, .mask = BIT(3) },
|
||||
{ .csi = RVIN_CSI41, .channel = 1, .vin = 7, .mask = BIT(0) },
|
||||
{ .csi = RVIN_CSI41, .channel = 3, .vin = 7, .mask = BIT(3) },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
|
||||
static const struct rvin_info rcar_info_r8a77980 = {
|
||||
.model = RCAR_GEN3,
|
||||
.use_mc = true,
|
||||
.max_width = 4096,
|
||||
.max_height = 4096,
|
||||
.routes = rcar_info_r8a77980_routes,
|
||||
};
|
||||
|
||||
static const struct rvin_group_route rcar_info_r8a77990_routes[] = {
|
||||
{ .csi = RVIN_CSI40, .channel = 0, .vin = 4, .mask = BIT(0) | BIT(3) },
|
||||
{ .csi = RVIN_CSI40, .channel = 0, .vin = 5, .mask = BIT(2) },
|
||||
{ .csi = RVIN_CSI40, .channel = 1, .vin = 4, .mask = BIT(2) },
|
||||
{ .csi = RVIN_CSI40, .channel = 1, .vin = 5, .mask = BIT(1) | BIT(3) },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
|
||||
static const struct rvin_info rcar_info_r8a77990 = {
|
||||
.model = RCAR_GEN3,
|
||||
.use_mc = true,
|
||||
.max_width = 4096,
|
||||
.max_height = 4096,
|
||||
.routes = rcar_info_r8a77990_routes,
|
||||
};
|
||||
|
||||
static const struct rvin_group_route rcar_info_r8a77995_routes[] = {
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
|
|
@ -1145,6 +1189,14 @@ static const struct of_device_id rvin_of_id_table[] = {
|
|||
.compatible = "renesas,vin-r8a77970",
|
||||
.data = &rcar_info_r8a77970,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,vin-r8a77980",
|
||||
.data = &rcar_info_r8a77980,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,vin-r8a77990",
|
||||
.data = &rcar_info_r8a77990,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,vin-r8a77995",
|
||||
.data = &rcar_info_r8a77995,
|
||||
|
|
|
|||
|
|
@ -152,37 +152,37 @@ static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = {
|
|||
};
|
||||
|
||||
static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = {
|
||||
{ .mbps = 80, .reg = 0x00 },
|
||||
{ .mbps = 90, .reg = 0x20 },
|
||||
{ .mbps = 100, .reg = 0x40 },
|
||||
{ .mbps = 110, .reg = 0x02 },
|
||||
{ .mbps = 130, .reg = 0x22 },
|
||||
{ .mbps = 140, .reg = 0x42 },
|
||||
{ .mbps = 150, .reg = 0x04 },
|
||||
{ .mbps = 170, .reg = 0x24 },
|
||||
{ .mbps = 180, .reg = 0x44 },
|
||||
{ .mbps = 200, .reg = 0x06 },
|
||||
{ .mbps = 220, .reg = 0x26 },
|
||||
{ .mbps = 240, .reg = 0x46 },
|
||||
{ .mbps = 250, .reg = 0x08 },
|
||||
{ .mbps = 270, .reg = 0x28 },
|
||||
{ .mbps = 300, .reg = 0x0a },
|
||||
{ .mbps = 330, .reg = 0x2a },
|
||||
{ .mbps = 360, .reg = 0x4a },
|
||||
{ .mbps = 400, .reg = 0x0c },
|
||||
{ .mbps = 450, .reg = 0x2c },
|
||||
{ .mbps = 500, .reg = 0x0e },
|
||||
{ .mbps = 550, .reg = 0x2e },
|
||||
{ .mbps = 600, .reg = 0x10 },
|
||||
{ .mbps = 650, .reg = 0x30 },
|
||||
{ .mbps = 700, .reg = 0x12 },
|
||||
{ .mbps = 750, .reg = 0x32 },
|
||||
{ .mbps = 800, .reg = 0x52 },
|
||||
{ .mbps = 850, .reg = 0x72 },
|
||||
{ .mbps = 900, .reg = 0x14 },
|
||||
{ .mbps = 950, .reg = 0x34 },
|
||||
{ .mbps = 1000, .reg = 0x54 },
|
||||
{ .mbps = 1050, .reg = 0x74 },
|
||||
{ .mbps = 89, .reg = 0x00 },
|
||||
{ .mbps = 99, .reg = 0x20 },
|
||||
{ .mbps = 109, .reg = 0x40 },
|
||||
{ .mbps = 129, .reg = 0x02 },
|
||||
{ .mbps = 139, .reg = 0x22 },
|
||||
{ .mbps = 149, .reg = 0x42 },
|
||||
{ .mbps = 169, .reg = 0x04 },
|
||||
{ .mbps = 179, .reg = 0x24 },
|
||||
{ .mbps = 199, .reg = 0x44 },
|
||||
{ .mbps = 219, .reg = 0x06 },
|
||||
{ .mbps = 239, .reg = 0x26 },
|
||||
{ .mbps = 249, .reg = 0x46 },
|
||||
{ .mbps = 269, .reg = 0x08 },
|
||||
{ .mbps = 299, .reg = 0x28 },
|
||||
{ .mbps = 329, .reg = 0x0a },
|
||||
{ .mbps = 359, .reg = 0x2a },
|
||||
{ .mbps = 399, .reg = 0x4a },
|
||||
{ .mbps = 449, .reg = 0x0c },
|
||||
{ .mbps = 499, .reg = 0x2c },
|
||||
{ .mbps = 549, .reg = 0x0e },
|
||||
{ .mbps = 599, .reg = 0x2e },
|
||||
{ .mbps = 649, .reg = 0x10 },
|
||||
{ .mbps = 699, .reg = 0x30 },
|
||||
{ .mbps = 749, .reg = 0x12 },
|
||||
{ .mbps = 799, .reg = 0x32 },
|
||||
{ .mbps = 849, .reg = 0x52 },
|
||||
{ .mbps = 899, .reg = 0x72 },
|
||||
{ .mbps = 949, .reg = 0x14 },
|
||||
{ .mbps = 999, .reg = 0x34 },
|
||||
{ .mbps = 1049, .reg = 0x54 },
|
||||
{ .mbps = 1099, .reg = 0x74 },
|
||||
{ .mbps = 1125, .reg = 0x16 },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
|
@ -342,6 +342,7 @@ struct rcar_csi2_info {
|
|||
int (*confirm_start)(struct rcar_csi2 *priv);
|
||||
const struct rcsi2_mbps_reg *hsfreqrange;
|
||||
unsigned int csi0clkfreqrange;
|
||||
unsigned int num_channels;
|
||||
bool clear_ulps;
|
||||
};
|
||||
|
||||
|
|
@ -476,13 +477,14 @@ static int rcsi2_start(struct rcar_csi2 *priv)
|
|||
format = rcsi2_code_to_fmt(priv->mf.code);
|
||||
|
||||
/*
|
||||
* Enable all Virtual Channels.
|
||||
* Enable all supported CSI-2 channels with virtual channel and
|
||||
* data type matching.
|
||||
*
|
||||
* NOTE: It's not possible to get individual datatype for each
|
||||
* source virtual channel. Once this is possible in V4L2
|
||||
* it should be used here.
|
||||
*/
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = 0; i < priv->info->num_channels; i++) {
|
||||
u32 vcdt_part;
|
||||
|
||||
vcdt_part = VCDT_SEL_VC(i) | VCDT_VCDTN_EN | VCDT_SEL_DTN_ON |
|
||||
|
|
@ -511,7 +513,8 @@ static int rcsi2_start(struct rcar_csi2 *priv)
|
|||
rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 |
|
||||
FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN);
|
||||
rcsi2_write(priv, VCDT_REG, vcdt);
|
||||
rcsi2_write(priv, VCDT2_REG, vcdt2);
|
||||
if (vcdt2)
|
||||
rcsi2_write(priv, VCDT2_REG, vcdt2);
|
||||
/* Lanes are zero indexed. */
|
||||
rcsi2_write(priv, LSWAP_REG,
|
||||
LSWAP_L0SEL(priv->lane_swap[0] - 1) |
|
||||
|
|
@ -940,27 +943,45 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
|
|||
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
|
||||
.hsfreqrange = hsfreqrange_h3_v3h_m3n,
|
||||
.csi0clkfreqrange = 0x20,
|
||||
.num_channels = 4,
|
||||
.clear_ulps = true,
|
||||
};
|
||||
|
||||
static const struct rcar_csi2_info rcar_csi2_info_r8a7795es1 = {
|
||||
.hsfreqrange = hsfreqrange_m3w_h3es1,
|
||||
.num_channels = 4,
|
||||
};
|
||||
|
||||
static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
|
||||
.hsfreqrange = hsfreqrange_m3w_h3es1,
|
||||
.num_channels = 4,
|
||||
};
|
||||
|
||||
static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = {
|
||||
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
|
||||
.hsfreqrange = hsfreqrange_h3_v3h_m3n,
|
||||
.csi0clkfreqrange = 0x20,
|
||||
.num_channels = 4,
|
||||
.clear_ulps = true,
|
||||
};
|
||||
|
||||
static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = {
|
||||
.init_phtw = rcsi2_init_phtw_v3m_e3,
|
||||
.confirm_start = rcsi2_confirm_start_v3m_e3,
|
||||
.num_channels = 4,
|
||||
};
|
||||
|
||||
static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = {
|
||||
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
|
||||
.hsfreqrange = hsfreqrange_h3_v3h_m3n,
|
||||
.csi0clkfreqrange = 0x20,
|
||||
.clear_ulps = true,
|
||||
};
|
||||
|
||||
static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
|
||||
.init_phtw = rcsi2_init_phtw_v3m_e3,
|
||||
.confirm_start = rcsi2_confirm_start_v3m_e3,
|
||||
.num_channels = 2,
|
||||
};
|
||||
|
||||
static const struct of_device_id rcar_csi2_of_table[] = {
|
||||
|
|
@ -980,6 +1001,14 @@ static const struct of_device_id rcar_csi2_of_table[] = {
|
|||
.compatible = "renesas,r8a77970-csi2",
|
||||
.data = &rcar_csi2_info_r8a77970,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,r8a77980-csi2",
|
||||
.data = &rcar_csi2_info_r8a77980,
|
||||
},
|
||||
{
|
||||
.compatible = "renesas,r8a77990-csi2",
|
||||
.data = &rcar_csi2_info_r8a77990,
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
|
||||
|
|
|
|||
|
|
@ -404,16 +404,16 @@ static int rvin_s_selection(struct file *file, void *fh,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rvin_cropcap(struct file *file, void *priv,
|
||||
struct v4l2_cropcap *crop)
|
||||
static int rvin_g_pixelaspect(struct file *file, void *priv,
|
||||
int type, struct v4l2_fract *f)
|
||||
{
|
||||
struct rvin_dev *vin = video_drvdata(file);
|
||||
struct v4l2_subdev *sd = vin_to_source(vin);
|
||||
|
||||
if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
return v4l2_subdev_call(sd, video, g_pixelaspect, &crop->pixelaspect);
|
||||
return v4l2_subdev_call(sd, video, g_pixelaspect, f);
|
||||
}
|
||||
|
||||
static int rvin_enum_input(struct file *file, void *priv,
|
||||
|
|
@ -620,7 +620,7 @@ static const struct v4l2_ioctl_ops rvin_ioctl_ops = {
|
|||
.vidioc_g_selection = rvin_g_selection,
|
||||
.vidioc_s_selection = rvin_s_selection,
|
||||
|
||||
.vidioc_cropcap = rvin_cropcap,
|
||||
.vidioc_g_pixelaspect = rvin_g_pixelaspect,
|
||||
|
||||
.vidioc_enum_input = rvin_enum_input,
|
||||
.vidioc_g_input = rvin_g_input,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue