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:
Linus Torvalds 2018-12-25 13:00:14 -08:00
commit 5813540b58
780 changed files with 17553 additions and 3643 deletions

View file

@ -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)) {

View file

@ -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;

View file

@ -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

View file

@ -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); \

View file

@ -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;

View file

@ -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)

View file

@ -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]));

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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) {

View file

@ -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",

View file

@ -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>

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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 |

View file

@ -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)

View file

@ -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,

View file

@ -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),

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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:

View file

@ -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__);

View file

@ -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 */

View file

@ -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 */

View file

@ -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;

View file

@ -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(

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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,
};

View file

@ -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 */

View file

@ -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;

View file

@ -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,

View file

@ -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 |

View file

@ -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 */

View file

@ -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)
};

View file

@ -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);

View file

@ -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 *)&reg;
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,

View file

@ -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);

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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;

View file

@ -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>

View file

@ -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,

View file

@ -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)

View file

@ -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"

View file

@ -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

View file

@ -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,

View file

@ -19,7 +19,6 @@
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/slab.h>

View file

@ -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);

View file

@ -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:

View file

@ -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,

View file

@ -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

View file

@ -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

View file

@ -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/

View file

@ -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,

File diff suppressed because it is too large Load diff

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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,

View file

@ -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

View file

@ -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;
),

View file

@ -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,

View file

@ -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,

View file

@ -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,
};

View file

@ -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;
}

View file

@ -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);

View file

@ -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;

View file

@ -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,

View file

@ -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:

View file

@ -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,

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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>

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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];
};
/*

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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));
}

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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)

View file

@ -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++;

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -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