From 387caebee00671aa6895e7b51056dca1f38e35dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20=C4=8C=C3=A1ni?= Date: Thu, 17 Jun 2021 21:59:48 +0200 Subject: [PATCH 001/195] media: dvbsky: add support for MyGica T230C2_LITE and T230A MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Geniatech MyGica T230C2_LITE and T230A as many people are asking support for these devices on forums. Link: https://lore.kernel.org/linux-media/YMuptIYFLdwSmw//@kali Signed-off-by: Ján Čáni Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvbsky.c | 37 +++++++++++++++++++-------- include/media/dvb-usb-ids.h | 2 ++ 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index 689829f1b52a6..1221c924312ad 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -541,7 +541,9 @@ static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap) si2168_config.i2c_adapter = &i2c_adapter; si2168_config.fe = &adap->fe[0]; si2168_config.ts_mode = SI2168_TS_PARALLEL; - if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2) + if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2 || + le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2_LITE || + le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230A) si2168_config.ts_mode |= SI2168_TS_CLK_MANUAL; si2168_config.ts_clock_inv = 1; @@ -577,15 +579,24 @@ static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap) static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name) { - dvbsky_gpio_ctrl(d, 0x04, 1); - msleep(20); - dvbsky_gpio_ctrl(d, 0x83, 0); - dvbsky_gpio_ctrl(d, 0xc0, 1); - msleep(100); - dvbsky_gpio_ctrl(d, 0x83, 1); - dvbsky_gpio_ctrl(d, 0xc0, 0); - msleep(50); - + if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230A) { + dvbsky_gpio_ctrl(d, 0x87, 0); + msleep(20); + dvbsky_gpio_ctrl(d, 0x86, 1); + dvbsky_gpio_ctrl(d, 0x80, 0); + msleep(100); + dvbsky_gpio_ctrl(d, 0x80, 1); + msleep(50); + } else { + dvbsky_gpio_ctrl(d, 0x04, 1); + msleep(20); + dvbsky_gpio_ctrl(d, 0x83, 0); + dvbsky_gpio_ctrl(d, 0xc0, 1); + msleep(100); + dvbsky_gpio_ctrl(d, 0x83, 1); + dvbsky_gpio_ctrl(d, 0xc0, 0); + msleep(50); + } return WARM; } @@ -789,6 +800,12 @@ static const struct usb_device_id dvbsky_id_table[] = { { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2, &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2", RC_MAP_TOTAL_MEDIA_IN_HAND_02) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2_LITE, + &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2 Lite", + NULL) }, + { DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230A, + &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230A", + NULL) }, { } }; MODULE_DEVICE_TABLE(usb, dvbsky_id_table); diff --git a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h index d37cb74b769c3..b0a535d6893a1 100644 --- a/include/media/dvb-usb-ids.h +++ b/include/media/dvb-usb-ids.h @@ -394,6 +394,8 @@ #define USB_PID_MYGICA_T230C 0xc689 #define USB_PID_MYGICA_T230C2 0xc68a #define USB_PID_MYGICA_T230C_LITE 0xc699 +#define USB_PID_MYGICA_T230C2_LITE 0xc69a +#define USB_PID_MYGICA_T230A 0x689a #define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011 #define USB_PID_ELGATO_EYETV_DTT 0x0021 #define USB_PID_ELGATO_EYETV_DTT_2 0x003f From caa7302b3a346d9a9ec85568cff52d2cee5f32c4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 18 Jun 2021 16:21:36 +0200 Subject: [PATCH 002/195] media: include/uapi/linux/cec.h: typo: SATERDAY -> SATURDAY Fix typo in a define: CEC_OP_REC_SEQ_SATERDAY -> CEC_OP_REC_SEQ_SATURDAY This isn't used yet in actual applications to the best of my knowledge, and it certainly doesn't break the ABI since the value doesn't change. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/cec.h.rst.exceptions | 2 +- include/uapi/linux/cec.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/userspace-api/media/cec.h.rst.exceptions b/Documentation/userspace-api/media/cec.h.rst.exceptions index d83790ccac8e5..13de01d9555eb 100644 --- a/Documentation/userspace-api/media/cec.h.rst.exceptions +++ b/Documentation/userspace-api/media/cec.h.rst.exceptions @@ -140,7 +140,7 @@ ignore define CEC_OP_REC_SEQ_TUESDAY ignore define CEC_OP_REC_SEQ_WEDNESDAY ignore define CEC_OP_REC_SEQ_THURSDAY ignore define CEC_OP_REC_SEQ_FRIDAY -ignore define CEC_OP_REC_SEQ_SATERDAY +ignore define CEC_OP_REC_SEQ_SATURDAY ignore define CEC_OP_REC_SEQ_ONCE_ONLY ignore define CEC_MSG_CLEAR_DIGITAL_TIMER diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h index dc8879d179fdf..de936f5e446d8 100644 --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -642,7 +642,7 @@ struct cec_event { #define CEC_OP_REC_SEQ_WEDNESDAY 0x08 #define CEC_OP_REC_SEQ_THURSDAY 0x10 #define CEC_OP_REC_SEQ_FRIDAY 0x20 -#define CEC_OP_REC_SEQ_SATERDAY 0x40 +#define CEC_OP_REC_SEQ_SATURDAY 0x40 #define CEC_OP_REC_SEQ_ONCE_ONLY 0x00 #define CEC_MSG_CLEAR_DIGITAL_TIMER 0x99 From 2a621b0859d1caf4e03f47066dad78011d274617 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Sat, 19 Jun 2021 19:24:23 +0200 Subject: [PATCH 003/195] media: gspca: Drop default m Drop the "default m", as options should default to disabled. No other media driver is enabled by default. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index 0283e3b908e43..dca4e16ed1338 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -4,7 +4,6 @@ menuconfig USB_GSPCA depends on VIDEO_V4L2 depends on INPUT || INPUT=n select VIDEOBUF2_VMALLOC - default m help Say Y here if you want to enable selecting webcams based on the GSPCA framework. From 8db11aebdb8f93f46a8513c22c9bd52fa23263aa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 17 Jun 2021 13:28:57 +0200 Subject: [PATCH 004/195] media: dib8000: rewrite the init prbs logic The logic at dib8000_get_init_prbs() has a few issues: 1. the tables used there has an extra unused value at the beginning; 2. the dprintk() message doesn't write the right value when transmission mode is not 8K; 3. the array overflow validation is done by the callers. Rewrite the code to fix such issues. This should also shut up those smatch warnings: drivers/media/dvb-frontends/dib8000.c:2125 dib8000_get_init_prbs() error: buffer overflow 'lut_prbs_8k' 14 <= 14 drivers/media/dvb-frontends/dib8000.c:2129 dib8000_get_init_prbs() error: buffer overflow 'lut_prbs_2k' 14 <= 14 drivers/media/dvb-frontends/dib8000.c:2131 dib8000_get_init_prbs() error: buffer overflow 'lut_prbs_4k' 14 <= 14 drivers/media/dvb-frontends/dib8000.c:2134 dib8000_get_init_prbs() error: buffer overflow 'lut_prbs_8k' 14 <= 14 Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib8000.c | 58 +++++++++++++++++++-------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 082796534b0ae..bb02354a48b81 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -2107,32 +2107,55 @@ static void dib8000_load_ana_fe_coefs(struct dib8000_state *state, const s16 *an dib8000_write_word(state, 117 + mode, ana_fe[mode]); } -static const u16 lut_prbs_2k[14] = { - 0, 0x423, 0x009, 0x5C7, 0x7A6, 0x3D8, 0x527, 0x7FF, 0x79B, 0x3D6, 0x3A2, 0x53B, 0x2F4, 0x213 +static const u16 lut_prbs_2k[13] = { + 0x423, 0x009, 0x5C7, + 0x7A6, 0x3D8, 0x527, + 0x7FF, 0x79B, 0x3D6, + 0x3A2, 0x53B, 0x2F4, + 0x213 }; -static const u16 lut_prbs_4k[14] = { - 0, 0x208, 0x0C3, 0x7B9, 0x423, 0x5C7, 0x3D8, 0x7FF, 0x3D6, 0x53B, 0x213, 0x029, 0x0D0, 0x48E + +static const u16 lut_prbs_4k[13] = { + 0x208, 0x0C3, 0x7B9, + 0x423, 0x5C7, 0x3D8, + 0x7FF, 0x3D6, 0x53B, + 0x213, 0x029, 0x0D0, + 0x48E }; -static const u16 lut_prbs_8k[14] = { - 0, 0x740, 0x069, 0x7DD, 0x208, 0x7B9, 0x5C7, 0x7FF, 0x53B, 0x029, 0x48E, 0x4C4, 0x367, 0x684 + +static const u16 lut_prbs_8k[13] = { + 0x740, 0x069, 0x7DD, + 0x208, 0x7B9, 0x5C7, + 0x7FF, 0x53B, 0x029, + 0x48E, 0x4C4, 0x367, + 0x684 }; static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel) { int sub_channel_prbs_group = 0; + int prbs_group; - sub_channel_prbs_group = (subchannel / 3) + 1; - dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]); + sub_channel_prbs_group = subchannel / 3; + if (sub_channel_prbs_group >= ARRAY_SIZE(lut_prbs_2k)) + return 0; switch (state->fe[0]->dtv_property_cache.transmission_mode) { case TRANSMISSION_MODE_2K: - return lut_prbs_2k[sub_channel_prbs_group]; + prbs_group = lut_prbs_2k[sub_channel_prbs_group]; + break; case TRANSMISSION_MODE_4K: - return lut_prbs_4k[sub_channel_prbs_group]; + prbs_group = lut_prbs_4k[sub_channel_prbs_group]; + break; default: case TRANSMISSION_MODE_8K: - return lut_prbs_8k[sub_channel_prbs_group]; + prbs_group = lut_prbs_8k[sub_channel_prbs_group]; } + + dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", + sub_channel_prbs_group, subchannel, prbs_group); + + return prbs_group; } static void dib8000_set_13seg_channel(struct dib8000_state *state) @@ -2409,10 +2432,8 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq /* TSB or ISDBT ? apply it now */ if (c->isdbt_sb_mode) { dib8000_set_sb_channel(state); - if (c->isdbt_sb_subchannel < 14) - init_prbs = dib8000_get_init_prbs(state, c->isdbt_sb_subchannel); - else - init_prbs = 0; + init_prbs = dib8000_get_init_prbs(state, + c->isdbt_sb_subchannel); } else { dib8000_set_13seg_channel(state); init_prbs = 0xfff; @@ -3004,6 +3025,7 @@ static int dib8000_tune(struct dvb_frontend *fe) unsigned long *timeout = &state->timeout; unsigned long now = jiffies; + u16 init_prbs; #ifdef DIB8000_AGC_FREEZE u16 agc1, agc2; #endif @@ -3302,8 +3324,10 @@ static int dib8000_tune(struct dvb_frontend *fe) break; case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */ - if (state->subchannel <= 41) { - dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel)); + init_prbs = dib8000_get_init_prbs(state, state->subchannel); + + if (init_prbs) { + dib8000_set_subchannel_prbs(state, init_prbs); *tune_state = CT_DEMOD_STEP_9; } else { *tune_state = CT_DEMOD_STOP; From 54e80d9883bd5b76c80710bddc63d1bd3f374d50 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 21 Jun 2021 09:32:25 +0200 Subject: [PATCH 005/195] media: sti: don't copy past the size The logic at delta_ipc_open() tries to copy past the size of the name passed to it: drivers/media/platform/sti/delta/delta-ipc.c:178 delta_ipc_open() error: __memcpy() 'name' too small (17 vs 32) Basically,this function is called just one with: ret = delta_ipc_open(pctx, "JPEG_DECODER_HW0", ...); The string used there has just 17 bytes. Yet, the logic tries to copy the entire name size (32 bytes), which is plain wrong. Replace it by strscpy, which is good enough to copy the string, warranting that this will be NUL-terminated. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/delta/delta-ipc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/sti/delta/delta-ipc.c b/drivers/media/platform/sti/delta/delta-ipc.c index 186d88f02ecd2..21d3e08e259ad 100644 --- a/drivers/media/platform/sti/delta/delta-ipc.c +++ b/drivers/media/platform/sti/delta/delta-ipc.c @@ -175,8 +175,7 @@ int delta_ipc_open(struct delta_ctx *pctx, const char *name, msg.ipc_buf_size = ipc_buf_size; msg.ipc_buf_paddr = ctx->ipc_buf->paddr; - memcpy(msg.name, name, sizeof(msg.name)); - msg.name[sizeof(msg.name) - 1] = 0; + strscpy(msg.name, name, sizeof(msg.name)); msg.param_size = param->size; memcpy(ctx->ipc_buf->vaddr, param->data, msg.param_size); From 1a10d7fdb6d0e235e9d230916244cc2769d3f170 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 17 Jun 2021 14:33:29 +0200 Subject: [PATCH 006/195] media: uvc: don't do DMA on stack As warned by smatch: drivers/media/usb/uvc/uvc_v4l2.c:911 uvc_ioctl_g_input() error: doing dma on the stack (&i) drivers/media/usb/uvc/uvc_v4l2.c:943 uvc_ioctl_s_input() error: doing dma on the stack (&i) those two functions call uvc_query_ctrl passing a pointer to a data at the DMA stack. those are used to send URBs via usb_control_msg(). Using DMA stack is not supported and should not work anymore on modern Linux versions. So, use a kmalloc'ed buffer. Cc: stable@vger.kernel.org # Kernel 4.9 and upper Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_v4l2.c | 34 +++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 252136cc885ce..6acb8013de08b 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -899,8 +899,8 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) { struct uvc_fh *handle = fh; struct uvc_video_chain *chain = handle->chain; + u8 *buf; int ret; - u8 i; if (chain->selector == NULL || (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { @@ -908,22 +908,27 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input) return 0; } + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, chain->selector->id, chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL, - &i, 1); - if (ret < 0) - return ret; + buf, 1); + if (!ret) + *input = *buf - 1; - *input = i - 1; - return 0; + kfree(buf); + + return ret; } static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) { struct uvc_fh *handle = fh; struct uvc_video_chain *chain = handle->chain; + u8 *buf; int ret; - u32 i; ret = uvc_acquire_privileges(handle); if (ret < 0) @@ -939,10 +944,17 @@ static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input) if (input >= chain->selector->bNrInPins) return -EINVAL; - i = input + 1; - return uvc_query_ctrl(chain->dev, UVC_SET_CUR, chain->selector->id, - chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL, - &i, 1); + buf = kmalloc(1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + *buf = input + 1; + ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, chain->selector->id, + chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL, + buf, 1); + kfree(buf); + + return ret; } static int uvc_ioctl_queryctrl(struct file *file, void *fh, From ed638b1d6f69343f3e764fd3608780485e7c1731 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 21 Jun 2021 09:24:46 +0200 Subject: [PATCH 007/195] media: ivtv: prevent going past the hw arrays As warned by smatch: drivers/media/pci/ivtv/ivtv-i2c.c:245 ivtv_i2c_register() error: buffer overflow 'hw_devicenames' 21 <= 31 drivers/media/pci/ivtv/ivtv-i2c.c:266 ivtv_i2c_register() error: buffer overflow 'hw_addrs' 21 <= 31 drivers/media/pci/ivtv/ivtv-i2c.c:269 ivtv_i2c_register() error: buffer overflow 'hw_addrs' 21 <= 31 drivers/media/pci/ivtv/ivtv-i2c.c:275 ivtv_i2c_register() error: buffer overflow 'hw_addrs' 21 <= 31 drivers/media/pci/ivtv/ivtv-i2c.c:280 ivtv_i2c_register() error: buffer overflow 'hw_addrs' 21 <= 31 drivers/media/pci/ivtv/ivtv-i2c.c:290 ivtv_i2c_register() error: buffer overflow 'hw_addrs' 21 <= 31 The logic at ivtv_i2c_register() could let buffer overflows at hw_devicenames and hw_addrs arrays. This won't happen in practice due to a carefully-contructed logic, but it is not error-prune. Change the logic in a way that will make clearer that the I2C hardware flags will affect the size of those two arrays, and add an explicit check to avoid buffer overflows. While here, use the bit macro. Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-cards.h | 68 ++++++++++++++++++++--------- drivers/media/pci/ivtv/ivtv-i2c.c | 16 ++++--- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/drivers/media/pci/ivtv/ivtv-cards.h b/drivers/media/pci/ivtv/ivtv-cards.h index f3e2c5634962b..c252733df340b 100644 --- a/drivers/media/pci/ivtv/ivtv-cards.h +++ b/drivers/media/pci/ivtv/ivtv-cards.h @@ -78,27 +78,53 @@ #define IVTV_PCI_ID_SONY 0x104d /* hardware flags, no gaps allowed */ -#define IVTV_HW_CX25840 (1 << 0) -#define IVTV_HW_SAA7115 (1 << 1) -#define IVTV_HW_SAA7127 (1 << 2) -#define IVTV_HW_MSP34XX (1 << 3) -#define IVTV_HW_TUNER (1 << 4) -#define IVTV_HW_WM8775 (1 << 5) -#define IVTV_HW_CS53L32A (1 << 6) -#define IVTV_HW_TVEEPROM (1 << 7) -#define IVTV_HW_SAA7114 (1 << 8) -#define IVTV_HW_UPD64031A (1 << 9) -#define IVTV_HW_UPD6408X (1 << 10) -#define IVTV_HW_SAA717X (1 << 11) -#define IVTV_HW_WM8739 (1 << 12) -#define IVTV_HW_VP27SMPX (1 << 13) -#define IVTV_HW_M52790 (1 << 14) -#define IVTV_HW_GPIO (1 << 15) -#define IVTV_HW_I2C_IR_RX_AVER (1 << 16) -#define IVTV_HW_I2C_IR_RX_HAUP_EXT (1 << 17) /* External before internal */ -#define IVTV_HW_I2C_IR_RX_HAUP_INT (1 << 18) -#define IVTV_HW_Z8F0811_IR_HAUP (1 << 19) -#define IVTV_HW_I2C_IR_RX_ADAPTEC (1 << 20) +enum ivtv_hw_bits { + IVTV_HW_BIT_CX25840, + IVTV_HW_BIT_SAA7115, + IVTV_HW_BIT_SAA7127, + IVTV_HW_BIT_MSP34XX, + IVTV_HW_BIT_TUNER, + IVTV_HW_BIT_WM8775, + IVTV_HW_BIT_CS53L32A, + IVTV_HW_BIT_TVEEPROM, + IVTV_HW_BIT_SAA7114, + IVTV_HW_BIT_UPD64031A, + IVTV_HW_BIT_UPD6408X, + IVTV_HW_BIT_SAA717X, + IVTV_HW_BIT_WM8739, + IVTV_HW_BIT_VP27SMPX, + IVTV_HW_BIT_M52790, + IVTV_HW_BIT_GPIO, + IVTV_HW_BIT_I2C_IR_RX_AVER, + IVTV_HW_BIT_I2C_IR_RX_HAUP_EXT, /* External before internal */ + IVTV_HW_BIT_I2C_IR_RX_HAUP_INT, + IVTV_HW_BIT_Z8F0811_IR_HAUP, + IVTV_HW_BIT_I2C_IR_RX_ADAPTEC, + + IVTV_HW_MAX_BITS /* Should be the last one */ +}; + +#define IVTV_HW_CX25840 BIT(IVTV_HW_BIT_CX25840) +#define IVTV_HW_SAA7115 BIT(IVTV_HW_BIT_SAA7115) +#define IVTV_HW_SAA7127 BIT(IVTV_HW_BIT_SAA7127) +#define IVTV_HW_MSP34XX BIT(IVTV_HW_BIT_MSP34XX) +#define IVTV_HW_TUNER BIT(IVTV_HW_BIT_TUNER) +#define IVTV_HW_WM8775 BIT(IVTV_HW_BIT_WM8775) +#define IVTV_HW_CS53L32A BIT(IVTV_HW_BIT_CS53L32A) +#define IVTV_HW_TVEEPROM BIT(IVTV_HW_BIT_TVEEPROM) +#define IVTV_HW_SAA7114 BIT(IVTV_HW_BIT_SAA7114) +#define IVTV_HW_UPD64031A BIT(IVTV_HW_BIT_UPD64031A) +#define IVTV_HW_UPD6408X BIT(IVTV_HW_BIT_UPD6408X) +#define IVTV_HW_SAA717X BIT(IVTV_HW_BIT_SAA717X) +#define IVTV_HW_WM8739 BIT(IVTV_HW_BIT_WM8739) +#define IVTV_HW_VP27SMPX BIT(IVTV_HW_BIT_VP27SMPX) +#define IVTV_HW_M52790 BIT(IVTV_HW_BIT_M52790) +#define IVTV_HW_GPIO BIT(IVTV_HW_BIT_GPIO) +#define IVTV_HW_I2C_IR_RX_AVER BIT(IVTV_HW_BIT_I2C_IR_RX_AVER) +#define IVTV_HW_I2C_IR_RX_HAUP_EXT BIT(IVTV_HW_BIT_I2C_IR_RX_HAUP_EXT) +#define IVTV_HW_I2C_IR_RX_HAUP_INT BIT(IVTV_HW_BIT_I2C_IR_RX_HAUP_INT) +#define IVTV_HW_Z8F0811_IR_HAUP BIT(IVTV_HW_BIT_Z8F0811_IR_HAUP) +#define IVTV_HW_I2C_IR_RX_ADAPTEC BIT(IVTV_HW_BIT_I2C_IR_RX_ADAPTEC) #define IVTV_HW_SAA711X (IVTV_HW_SAA7115 | IVTV_HW_SAA7114) diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c index 982045c4eea81..c052c57c6dcef 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.c +++ b/drivers/media/pci/ivtv/ivtv-i2c.c @@ -85,7 +85,7 @@ #define IVTV_ADAPTEC_IR_ADDR 0x6b /* This array should match the IVTV_HW_ defines */ -static const u8 hw_addrs[] = { +static const u8 hw_addrs[IVTV_HW_MAX_BITS] = { IVTV_CX25840_I2C_ADDR, IVTV_SAA7115_I2C_ADDR, IVTV_SAA7127_I2C_ADDR, @@ -110,7 +110,7 @@ static const u8 hw_addrs[] = { }; /* This array should match the IVTV_HW_ defines */ -static const char * const hw_devicenames[] = { +static const char * const hw_devicenames[IVTV_HW_MAX_BITS] = { "cx25840", "saa7115", "saa7127_auto", /* saa7127 or saa7129 */ @@ -240,10 +240,16 @@ void ivtv_i2c_new_ir_legacy(struct ivtv *itv) int ivtv_i2c_register(struct ivtv *itv, unsigned idx) { - struct v4l2_subdev *sd; struct i2c_adapter *adap = &itv->i2c_adap; - const char *type = hw_devicenames[idx]; - u32 hw = 1 << idx; + struct v4l2_subdev *sd; + const char *type; + u32 hw; + + if (idx >= IVTV_HW_MAX_BITS) + return -ENODEV; + + type = hw_devicenames[idx]; + hw = 1 << idx; if (hw == IVTV_HW_TUNER) { /* special tuner handling */ From 229e5bdcd39ed3ca0a71dc8500ba4ea90d4415db Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 6 Jun 2021 10:23:13 +0200 Subject: [PATCH 008/195] media: hevc: Add segment address field If HEVC frame consists of multiple slices, segment address has to be known in order to properly decode it. Add segment address field to slice parameters. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 3 +++ include/media/hevc-ctrls.h | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 8c6e2a11ed95d..dc096a5562cdf 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -3000,6 +3000,9 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - * - __u8 - ``pic_struct`` - + * - __u32 + - ``slice_segment_addr`` + - * - __u8 - ``ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` - The list of L0 reference elements as indices in the DPB. diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index 53c0038c792bc..781371bff2adb 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -196,10 +196,11 @@ struct v4l2_ctrl_hevc_slice_params { __u8 pic_struct; /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */ + __u32 slice_segment_addr; __u8 ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; __u8 ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]; - __u8 padding[5]; + __u8 padding; /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */ struct v4l2_hevc_pred_weight_table pred_weight_table; From d92a4a27d983032267b231a32be98a11a9995e5c Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sun, 6 Jun 2021 10:23:14 +0200 Subject: [PATCH 009/195] media: cedrus: hevc: Add support for multiple slices Now that segment address is available, support for multi-slice frames can be easily added. Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/sunxi/cedrus/cedrus_h265.c | 26 ++++++++++++------- .../staging/media/sunxi/cedrus/cedrus_video.c | 1 + 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 6821e3d05d346..ef0311a16d019 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -247,6 +247,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, const struct v4l2_ctrl_hevc_slice_params *slice_params; const struct v4l2_ctrl_hevc_decode_params *decode_params; const struct v4l2_hevc_pred_weight_table *pred_weight_table; + unsigned int width_in_ctb_luma, ctb_size_luma; + unsigned int log2_max_luma_coding_block_size; dma_addr_t src_buf_addr; dma_addr_t src_buf_end_addr; u32 chroma_log2_weight_denom; @@ -260,15 +262,17 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, decode_params = run->h265.decode_params; pred_weight_table = &slice_params->pred_weight_table; + log2_max_luma_coding_block_size = + sps->log2_min_luma_coding_block_size_minus3 + 3 + + sps->log2_diff_max_min_luma_coding_block_size; + ctb_size_luma = 1UL << log2_max_luma_coding_block_size; + width_in_ctb_luma = + DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_luma); + /* MV column buffer size and allocation. */ if (!ctx->codec.h265.mv_col_buf_size) { unsigned int num_buffers = run->dst->vb2_buf.vb2_queue->num_buffers; - unsigned int log2_max_luma_coding_block_size = - sps->log2_min_luma_coding_block_size_minus3 + 3 + - sps->log2_diff_max_min_luma_coding_block_size; - unsigned int ctb_size_luma = - 1UL << log2_max_luma_coding_block_size; /* * Each CTB requires a MV col buffer with a specific unit size. @@ -322,15 +326,17 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, reg = VE_DEC_H265_BITS_END_ADDR_BASE(src_buf_end_addr); cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg); - /* Coding tree block address: start at the beginning. */ - reg = VE_DEC_H265_DEC_CTB_ADDR_X(0) | VE_DEC_H265_DEC_CTB_ADDR_Y(0); + /* Coding tree block address */ + reg = VE_DEC_H265_DEC_CTB_ADDR_X(slice_params->slice_segment_addr % width_in_ctb_luma); + reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(slice_params->slice_segment_addr / width_in_ctb_luma); cedrus_write(dev, VE_DEC_H265_DEC_CTB_ADDR, reg); cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0); cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0); /* Clear the number of correctly-decoded coding tree blocks. */ - cedrus_write(dev, VE_DEC_H265_DEC_CTB_NUM, 0); + if (ctx->fh.m2m_ctx->new_frame) + cedrus_write(dev, VE_DEC_H265_DEC_CTB_NUM, 0); /* Initialize bitstream access. */ cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC); @@ -482,8 +488,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx, V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT, slice_params->flags); - /* FIXME: For multi-slice support. */ - reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC; + if (ctx->fh.m2m_ctx->new_frame) + reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO0_FLAG_FIRST_SLICE_SEGMENT_IN_PIC; cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO0, reg); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 32c13ecb22d83..c589fe9dae701 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -340,6 +340,7 @@ static int cedrus_s_fmt_vid_out(struct file *file, void *priv, switch (ctx->src_fmt.pixelformat) { case V4L2_PIX_FMT_H264_SLICE: + case V4L2_PIX_FMT_HEVC_SLICE: vq->subsystem_flags |= VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; break; From e481ff3f19cd9d46da1a46ca7966403dc69e8632 Mon Sep 17 00:00:00 2001 From: Herman Date: Wed, 9 Jun 2021 05:00:31 +0200 Subject: [PATCH 010/195] media: drivers/media/pci/tw5864/Tw5864-reg.h: fix typo issues change 'syncrous' into 'synchronous' Signed-off-by: Herman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw5864/tw5864-reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/tw5864/tw5864-reg.h b/drivers/media/pci/tw5864/tw5864-reg.h index a26a439c4dc08..25d4a9a6cc6b1 100644 --- a/drivers/media/pci/tw5864/tw5864-reg.h +++ b/drivers/media/pci/tw5864/tw5864-reg.h @@ -663,7 +663,7 @@ #define TW5864_SYNC 0x8008 /* Define controls in register TW5864_SYNC */ /* - * 0 vlc stream to syncrous port + * 0 vlc stream to synchronous port * 1 vlc stream to ddr buffers */ #define TW5864_SYNC_CFG BIT(7) From 9a582884716aff660cf559b2df610c040c0e5087 Mon Sep 17 00:00:00 2001 From: Herman Date: Wed, 9 Jun 2021 11:53:22 +0200 Subject: [PATCH 011/195] media: drivers/media/usb/gspca: fix typo Fliker -> Flicker Change 'Fliker' into 'Flicker'. Signed-off-by: Herman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/vc032x.c | 6 +- drivers/media/usb/gspca/zc3xx.c | 134 +++++++++++++++---------------- 2 files changed, 70 insertions(+), 70 deletions(-) diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c index 4cb7c92ea1328..e7a534be061d0 100644 --- a/drivers/media/usb/gspca/vc032x.c +++ b/drivers/media/usb/gspca/vc032x.c @@ -1796,7 +1796,7 @@ static const u8 ov7660_60HZ[][4] = { {} }; -static const u8 ov7660_NoFliker[][4] = { +static const u8 ov7660_NoFlicker[][4] = { {0x00, 0x13, 0x87, 0xaa}, {} }; @@ -3319,8 +3319,8 @@ static void sethvflip(struct gspca_dev *gspca_dev, bool hflip, bool vflip) static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - static const u8 (*ov7660_freq_tb[3])[4] = - {ov7660_NoFliker, ov7660_50HZ, ov7660_60HZ}; + static const u8 (*ov7660_freq_tb[3])[4] = { + ov7660_NoFlicker, ov7660_50HZ, ov7660_60HZ}; if (sd->sensor != SENSOR_OV7660) return; diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c index aa285d5d6c0d9..5bcbf0d40147a 100644 --- a/drivers/media/usb/gspca/zc3xx.c +++ b/drivers/media/usb/gspca/zc3xx.c @@ -323,7 +323,7 @@ static const struct usb_action adcm2700_60HZ[] = { {0xaa, 0x28, 0x0002}, /* 00,28,02,aa */ {} }; -static const struct usb_action adcm2700_NoFliker[] = { +static const struct usb_action adcm2700_NoFlicker[] = { {0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */ {0xaa, 0xfe, 0x0002}, /* 00,fe,02,aa */ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0a,cc */ @@ -525,7 +525,7 @@ static const struct usb_action cs2102_60HZ[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action cs2102_NoFlikerScale[] = { +static const struct usb_action cs2102_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xaa, 0x23, 0x0001}, {0xaa, 0x24, 0x005f}, @@ -547,7 +547,7 @@ static const struct usb_action cs2102_NoFlikerScale[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action cs2102_NoFliker[] = { +static const struct usb_action cs2102_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xaa, 0x23, 0x0000}, {0xaa, 0x24, 0x00af}, @@ -1385,7 +1385,7 @@ static const struct usb_action gc0305_60HZ[] = { {} }; -static const struct usb_action gc0305_NoFliker[] = { +static const struct usb_action gc0305_NoFlicker[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ @@ -1710,7 +1710,7 @@ static const struct usb_action hdcs2020_60HZ[] = { {0xa0, 0x2c, ZC3XX_R01F_HSYNC_2}, /* 00,1f,2c,cc */ {} }; -static const struct usb_action hdcs2020_NoFliker[] = { +static const struct usb_action hdcs2020_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x13, 0x0010}, /* 00,13,10,aa */ {0xaa, 0x14, 0x0001}, /* 00,14,01,aa */ @@ -1925,7 +1925,7 @@ static const struct usb_action hv7131b_60HZScale[] = { /* 320x240 */ {0xa0, 0x40, ZC3XX_R020_HSYNC_3}, /* 00,20,40,cc */ {} }; -static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/ +static const struct usb_action hv7131b_NoFlicker[] = { /* 640x480*/ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ @@ -1950,7 +1950,7 @@ static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/ {0xa0, 0x03, ZC3XX_R020_HSYNC_3}, /* 00,20,03,cc */ {} }; -static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */ +static const struct usb_action hv7131b_NoFlickerScale[] = { /* 320x240 */ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x25, 0x0003}, /* 00,25,03,aa */ {0xaa, 0x26, 0x0000}, /* 00,26,00,aa */ @@ -2141,7 +2141,7 @@ static const struct usb_action hv7131r_60HZScale[] = { {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action hv7131r_NoFliker[] = { +static const struct usb_action hv7131r_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, @@ -2159,7 +2159,7 @@ static const struct usb_action hv7131r_NoFliker[] = { {0xa0, 0x08, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action hv7131r_NoFlikerScale[] = { +static const struct usb_action hv7131r_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, @@ -2662,7 +2662,7 @@ static const struct usb_action icm105a_60HZ[] = { {0xa0, 0xc0, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,c0,cc */ {} }; -static const struct usb_action icm105a_NoFlikerScale[] = { +static const struct usb_action icm105a_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ @@ -2693,7 +2693,7 @@ static const struct usb_action icm105a_NoFlikerScale[] = { {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ {} }; -static const struct usb_action icm105a_NoFliker[] = { +static const struct usb_action icm105a_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0x0d, 0x0003}, /* 00,0d,03,aa */ {0xaa, 0x0c, 0x0004}, /* 00,0c,04,aa */ @@ -3009,7 +3009,7 @@ static const struct usb_action mc501cb_60HZScale[] = { {} }; -static const struct usb_action mc501cb_NoFliker[] = { +static const struct usb_action mc501cb_NoFlicker[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */ @@ -3021,7 +3021,7 @@ static const struct usb_action mc501cb_NoFliker[] = { {} }; -static const struct usb_action mc501cb_NoFlikerScale[] = { +static const struct usb_action mc501cb_NoFlickerScale[] = { {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */ {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */ {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */ @@ -3211,7 +3211,7 @@ static const struct usb_action ov7620_60HZ[] = { {0xa1, 0x01, 0x0037}, */ {} }; -static const struct usb_action ov7620_NoFliker[] = { +static const struct usb_action ov7620_NoFlicker[] = { {0xdd, 0x00, 0x0100}, /* 00,01,00,dd */ {0xaa, 0x2b, 0x0000}, /* 00,2b,00,aa */ /* disable 1/120s & 1/100s exposures for banding filter */ @@ -3827,7 +3827,7 @@ static const struct usb_action pas106b_60HZ[] = { {0xa0, 0x04, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,04,cc */ {} }; -static const struct usb_action pas106b_NoFliker[] = { +static const struct usb_action pas106b_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ {0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,06,cc */ {0xa0, 0x50, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc */ @@ -4051,7 +4051,7 @@ static const struct usb_action pas202b_60HZScale[] = { {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ {} }; -static const struct usb_action pas202b_NoFliker[] = { +static const struct usb_action pas202b_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ @@ -4080,7 +4080,7 @@ static const struct usb_action pas202b_NoFliker[] = { {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ {} }; -static const struct usb_action pas202b_NoFlikerScale[] = { +static const struct usb_action pas202b_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ @@ -4309,7 +4309,7 @@ static const struct usb_action mt9v111_1_AE60HZScale[] = { {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, {} }; -static const struct usb_action mt9v111_1_AENoFliker[] = { +static const struct usb_action mt9v111_1_AENoFlicker[] = { {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xbb, 0x00, 0x0509}, @@ -4332,7 +4332,7 @@ static const struct usb_action mt9v111_1_AENoFliker[] = { {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, {} }; -static const struct usb_action mt9v111_1_AENoFlikerScale[] = { +static const struct usb_action mt9v111_1_AENoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xbb, 0x00, 0x0534}, @@ -4554,7 +4554,7 @@ static const struct usb_action mt9v111_3_AE60HZScale[] = { {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, {} }; -static const struct usb_action mt9v111_3_AENoFliker[] = { +static const struct usb_action mt9v111_3_AENoFlicker[] = { {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xaa, 0x05, 0x0034}, @@ -4577,7 +4577,7 @@ static const struct usb_action mt9v111_3_AENoFliker[] = { {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, {} }; -static const struct usb_action mt9v111_3_AENoFlikerScale[] = { +static const struct usb_action mt9v111_3_AENoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xaa, 0x05, 0x0034}, @@ -4787,7 +4787,7 @@ static const struct usb_action pb0330_60HZScale[] = { {0xa0, 0xd0, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action pb0330_NoFliker[] = { +static const struct usb_action pb0330_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xbb, 0x00, 0x0509}, {0xbb, 0x02, 0x0940}, @@ -4809,7 +4809,7 @@ static const struct usb_action pb0330_NoFliker[] = { {0xa0, 0xe0, ZC3XX_R020_HSYNC_3}, {} }; -static const struct usb_action pb0330_NoFlikerScale[] = { +static const struct usb_action pb0330_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, {0xbb, 0x00, 0x0535}, {0xbb, 0x01, 0x0980}, @@ -5031,7 +5031,7 @@ static const struct usb_action po2030_60HZ[] = { {} }; -static const struct usb_action po2030_NoFliker[] = { +static const struct usb_action po2030_NoFlicker[] = { {0xa0, 0x02, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,02,cc */ {0xaa, 0x8d, 0x000d}, /* 00,8d,0d,aa */ {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa */ @@ -5215,7 +5215,7 @@ static const struct usb_action tas5130c_60HZScale[] = { {0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN}, {} }; -static const struct usb_action tas5130c_NoFliker[] = { +static const struct usb_action tas5130c_NoFlicker[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ {0xaa, 0xa4, 0x0040}, /* 00,a4,40,aa */ @@ -5241,7 +5241,7 @@ static const struct usb_action tas5130c_NoFliker[] = { {} }; -static const struct usb_action tas5130c_NoFlikerScale[] = { +static const struct usb_action tas5130c_NoFlickerScale[] = { {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ {0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */ {0xaa, 0xa4, 0x0090}, /* 00,a4,90,aa */ @@ -5482,7 +5482,7 @@ static const struct usb_action gc0303_60HZScale[] = { {} }; -static const struct usb_action gc0303_NoFliker[] = { +static const struct usb_action gc0303_NoFlicker[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ @@ -5504,7 +5504,7 @@ static const struct usb_action gc0303_NoFliker[] = { {} }; -static const struct usb_action gc0303_NoFlikerScale[] = { +static const struct usb_action gc0303_NoFlickerScale[] = { {0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */ {0xaa, 0x82, 0x0000}, /* 00,82,00,aa */ {0xaa, 0x83, 0x0000}, /* 00,83,00,aa */ @@ -5806,7 +5806,7 @@ static void setquality(struct gspca_dev *gspca_dev) * Valid frequencies are: * 50Hz, for European and Asian lighting (default) * 60Hz, for American lighting - * 0 = No Fliker (for outdoore usage) + * 0 = No Flicker (for outdoor usage) */ static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) { @@ -5814,80 +5814,80 @@ static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) int i, mode; const struct usb_action *zc3_freq; static const struct usb_action *freq_tb[SENSOR_MAX][6] = { - [SENSOR_ADCM2700] = - {adcm2700_NoFliker, adcm2700_NoFliker, + [SENSOR_ADCM2700] = { + adcm2700_NoFlicker, adcm2700_NoFlicker, adcm2700_50HZ, adcm2700_50HZ, adcm2700_60HZ, adcm2700_60HZ}, - [SENSOR_CS2102] = - {cs2102_NoFliker, cs2102_NoFlikerScale, + [SENSOR_CS2102] = { + cs2102_NoFlicker, cs2102_NoFlickerScale, cs2102_50HZ, cs2102_50HZScale, cs2102_60HZ, cs2102_60HZScale}, - [SENSOR_CS2102K] = - {cs2102_NoFliker, cs2102_NoFlikerScale, + [SENSOR_CS2102K] = { + cs2102_NoFlicker, cs2102_NoFlickerScale, NULL, NULL, /* currently disabled */ NULL, NULL}, - [SENSOR_GC0303] = - {gc0303_NoFliker, gc0303_NoFlikerScale, + [SENSOR_GC0303] = { + gc0303_NoFlicker, gc0303_NoFlickerScale, gc0303_50HZ, gc0303_50HZScale, gc0303_60HZ, gc0303_60HZScale}, - [SENSOR_GC0305] = - {gc0305_NoFliker, gc0305_NoFliker, + [SENSOR_GC0305] = { + gc0305_NoFlicker, gc0305_NoFlicker, gc0305_50HZ, gc0305_50HZ, gc0305_60HZ, gc0305_60HZ}, - [SENSOR_HDCS2020] = - {hdcs2020_NoFliker, hdcs2020_NoFliker, + [SENSOR_HDCS2020] = { + hdcs2020_NoFlicker, hdcs2020_NoFlicker, hdcs2020_50HZ, hdcs2020_50HZ, hdcs2020_60HZ, hdcs2020_60HZ}, - [SENSOR_HV7131B] = - {hv7131b_NoFliker, hv7131b_NoFlikerScale, + [SENSOR_HV7131B] = { + hv7131b_NoFlicker, hv7131b_NoFlickerScale, hv7131b_50HZ, hv7131b_50HZScale, hv7131b_60HZ, hv7131b_60HZScale}, - [SENSOR_HV7131R] = - {hv7131r_NoFliker, hv7131r_NoFlikerScale, + [SENSOR_HV7131R] = { + hv7131r_NoFlicker, hv7131r_NoFlickerScale, hv7131r_50HZ, hv7131r_50HZScale, hv7131r_60HZ, hv7131r_60HZScale}, - [SENSOR_ICM105A] = - {icm105a_NoFliker, icm105a_NoFlikerScale, + [SENSOR_ICM105A] = { + icm105a_NoFlicker, icm105a_NoFlickerScale, icm105a_50HZ, icm105a_50HZScale, icm105a_60HZ, icm105a_60HZScale}, - [SENSOR_MC501CB] = - {mc501cb_NoFliker, mc501cb_NoFlikerScale, + [SENSOR_MC501CB] = { + mc501cb_NoFlicker, mc501cb_NoFlickerScale, mc501cb_50HZ, mc501cb_50HZScale, mc501cb_60HZ, mc501cb_60HZScale}, - [SENSOR_MT9V111_1] = - {mt9v111_1_AENoFliker, mt9v111_1_AENoFlikerScale, + [SENSOR_MT9V111_1] = { + mt9v111_1_AENoFlicker, mt9v111_1_AENoFlickerScale, mt9v111_1_AE50HZ, mt9v111_1_AE50HZScale, mt9v111_1_AE60HZ, mt9v111_1_AE60HZScale}, - [SENSOR_MT9V111_3] = - {mt9v111_3_AENoFliker, mt9v111_3_AENoFlikerScale, + [SENSOR_MT9V111_3] = { + mt9v111_3_AENoFlicker, mt9v111_3_AENoFlickerScale, mt9v111_3_AE50HZ, mt9v111_3_AE50HZScale, mt9v111_3_AE60HZ, mt9v111_3_AE60HZScale}, - [SENSOR_OV7620] = - {ov7620_NoFliker, ov7620_NoFliker, + [SENSOR_OV7620] = { + ov7620_NoFlicker, ov7620_NoFlicker, ov7620_50HZ, ov7620_50HZ, ov7620_60HZ, ov7620_60HZ}, - [SENSOR_OV7630C] = - {NULL, NULL, + [SENSOR_OV7630C] = { + NULL, NULL, NULL, NULL, NULL, NULL}, - [SENSOR_PAS106] = - {pas106b_NoFliker, pas106b_NoFliker, + [SENSOR_PAS106] = { + pas106b_NoFlicker, pas106b_NoFlicker, pas106b_50HZ, pas106b_50HZ, pas106b_60HZ, pas106b_60HZ}, - [SENSOR_PAS202B] = - {pas202b_NoFliker, pas202b_NoFlikerScale, + [SENSOR_PAS202B] = { + pas202b_NoFlicker, pas202b_NoFlickerScale, pas202b_50HZ, pas202b_50HZScale, pas202b_60HZ, pas202b_60HZScale}, - [SENSOR_PB0330] = - {pb0330_NoFliker, pb0330_NoFlikerScale, + [SENSOR_PB0330] = { + pb0330_NoFlicker, pb0330_NoFlickerScale, pb0330_50HZ, pb0330_50HZScale, pb0330_60HZ, pb0330_60HZScale}, - [SENSOR_PO2030] = - {po2030_NoFliker, po2030_NoFliker, + [SENSOR_PO2030] = { + po2030_NoFlicker, po2030_NoFlicker, po2030_50HZ, po2030_50HZ, po2030_60HZ, po2030_60HZ}, - [SENSOR_TAS5130C] = - {tas5130c_NoFliker, tas5130c_NoFlikerScale, + [SENSOR_TAS5130C] = { + tas5130c_NoFlicker, tas5130c_NoFlickerScale, tas5130c_50HZ, tas5130c_50HZScale, tas5130c_60HZ, tas5130c_60HZScale}, }; From b6ef5c123a4b73aae649ee2e7da73d751491b971 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 9 Jun 2021 14:14:08 +0200 Subject: [PATCH 012/195] media: atomisp: remove redundant initialization of variable ret The variable ret is being initialized with a value that is never read, it is being updated later on. The assignment is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 0828ca9ab6f22..5e3670c4fc29f 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -932,7 +932,7 @@ static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value) static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) { struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = -EINVAL; + int ret; u8 vcm_code; ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code); From 123aaf816b952e5b6ee754335596b01ba1f6c830 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 9 Jun 2021 15:00:28 +0200 Subject: [PATCH 013/195] media: atmel: atmel-sama5d2-isc: fix YUYV format SAMA5D2 does not have the YCYC field for the RLP (rounding, limiting, packaging) module. The YCYC field is supposed to work with interleaved YUV formats like YUYV. In SAMA5D2, we have to use YYCC field, which is used for both planar formats like YUV420 and interleaved formats like YUYV. Fix the according rlp callback to replace the generic YCYC field (which makes more sense from a logical point of view) with the required YYCC field. Fixes: debfa496871c ("media: atmel: atmel-isc-base: add support for more formats and additional pipeline modules") Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/atmel/atmel-sama5d2-isc.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c index 925aa80a139b2..b66f1d174e9d7 100644 --- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -255,6 +255,23 @@ static void isc_sama5d2_config_rlp(struct isc_device *isc) struct regmap *regmap = isc->regmap; u32 rlp_mode = isc->config.rlp_cfg_mode; + /* + * In sama5d2, the YUV planar modes and the YUYV modes are treated + * in the same way in RLP register. + * Normally, YYCC mode should be Luma(n) - Color B(n) - Color R (n) + * and YCYC should be Luma(n + 1) - Color B (n) - Luma (n) - Color R (n) + * but in sama5d2, the YCYC mode does not exist, and YYCC must be + * selected for both planar and interleaved modes, as in fact + * both modes are supported. + * + * Thus, if the YCYC mode is selected, replace it with the + * sama5d2-compliant mode which is YYCC . + */ + if ((rlp_mode & ISC_RLP_CFG_MODE_YCYC) == ISC_RLP_CFG_MODE_YCYC) { + rlp_mode &= ~ISC_RLP_CFG_MODE_MASK; + rlp_mode |= ISC_RLP_CFG_MODE_YYCC; + } + regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp, ISC_RLP_CFG_MODE_MASK, rlp_mode); } From 983eb35c991d286b083656c790c86c314b627871 Mon Sep 17 00:00:00 2001 From: Herman Date: Thu, 10 Jun 2021 10:38:15 +0200 Subject: [PATCH 014/195] media: drivers/media/platform/davinci/vpfe_capture.c : fix typo Proabably > Probably Change 'Proabably' into 'Probably'. Signed-off-by: Herman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index f9f7dd17c57c3..0a2226b321d7b 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -189,7 +189,7 @@ int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev) if (!ccdc_cfg) { /* * TODO. Will this ever happen? if so, we need to fix it. - * Proabably we need to add the request to a linked list and + * Probably we need to add the request to a linked list and * walk through it during vpfe probe */ printk(KERN_ERR "vpfe capture not initialized\n"); From 331ca86aff94323d252d843b73cd6dddf54715bd Mon Sep 17 00:00:00 2001 From: lijian Date: Fri, 11 Jun 2021 08:28:15 +0200 Subject: [PATCH 015/195] media: i2c: tvp5150: deleted the repeated word deleted the repeated word 'the' in the comments. Signed-off-by: lijian Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 30c63552556d0..4b16ffcaef98a 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -964,7 +964,7 @@ static int tvp5150_enable(struct v4l2_subdev *sd) /* * Enable the YCbCr and clock outputs. In discrete sync mode - * (non-BT.656) additionally enable the the sync outputs. + * (non-BT.656) additionally enable the sync outputs. */ switch (decoder->mbus_type) { case V4L2_MBUS_PARALLEL: From bc3db19f04f1ae62ab51dea6a5cdacb0b5ec1404 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 13 Jun 2021 17:03:31 +0200 Subject: [PATCH 016/195] media: saa7134: switch from 'pci_' to 'dma_' API The wrappers in include/linux/pci-dma-compat.h should go away. The patch has been generated with the coccinelle script below and has been hand modified to replace GFP_ with a correct flag. It has been compile tested. When memory is allocated in 'saa7134_pgtable_alloc()', GFP_KERNEL can be used because its 4 callers (one function calls it 2 times, so there is only 3 functions that call it): .hw_params in a struct snd_pcm_ops (saa7134-alsa.c) --> snd_card_saa7134_hw_params (saa7134-alsa.c) --> saa7134_pgtable_alloc ==> .hw_params function can use GFP_KERNEL saa7134_initdev (saa7134-core.c) --> saa7134_hwinit1 (saa7134-core.c) --> saa7134_ts_init1 (saa7134-ts.c) --> saa7134_pgtable_alloc ==> saa7134_initdev already uses GFP_KERNEL saa7134_initdev (saa7134-core.c) --> saa7134_hwinit1 (saa7134-core.c) --> saa7134_video_init1 (saa7134-video.c) --> saa7134_pgtable_alloc (called 2 times) ==> saa7134_initdev already uses GFP_KERNEL and no spin_lock is taken in the between. @@ @@ - PCI_DMA_BIDIRECTIONAL + DMA_BIDIRECTIONAL @@ @@ - PCI_DMA_TODEVICE + DMA_TO_DEVICE @@ @@ - PCI_DMA_FROMDEVICE + DMA_FROM_DEVICE @@ @@ - PCI_DMA_NONE + DMA_NONE @@ expression e1, e2, e3; @@ - pci_alloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3; @@ - pci_zalloc_consistent(e1, e2, e3) + dma_alloc_coherent(&e1->dev, e2, e3, GFP_) @@ expression e1, e2, e3, e4; @@ - pci_free_consistent(e1, e2, e3, e4) + dma_free_coherent(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_single(e1, e2, e3, e4) + dma_map_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_single(e1, e2, e3, e4) + dma_unmap_single(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4, e5; @@ - pci_map_page(e1, e2, e3, e4, e5) + dma_map_page(&e1->dev, e2, e3, e4, e5) @@ expression e1, e2, e3, e4; @@ - pci_unmap_page(e1, e2, e3, e4) + dma_unmap_page(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_map_sg(e1, e2, e3, e4) + dma_map_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_unmap_sg(e1, e2, e3, e4) + dma_unmap_sg(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_cpu(e1, e2, e3, e4) + dma_sync_single_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_single_for_device(e1, e2, e3, e4) + dma_sync_single_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_cpu(e1, e2, e3, e4) + dma_sync_sg_for_cpu(&e1->dev, e2, e3, e4) @@ expression e1, e2, e3, e4; @@ - pci_dma_sync_sg_for_device(e1, e2, e3, e4) + dma_sync_sg_for_device(&e1->dev, e2, e3, e4) @@ expression e1, e2; @@ - pci_dma_mapping_error(e1, e2) + dma_mapping_error(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_dma_mask(e1, e2) + dma_set_mask(&e1->dev, e2) @@ expression e1, e2; @@ - pci_set_consistent_dma_mask(e1, e2) + dma_set_coherent_mask(&e1->dev, e2) Signed-off-by: Christophe JAILLET Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 47158ab3956bf..96328b0af1641 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -223,7 +223,8 @@ int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt) __le32 *cpu; dma_addr_t dma_addr = 0; - cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr); + cpu = dma_alloc_coherent(&pci->dev, SAA7134_PGTABLE_SIZE, &dma_addr, + GFP_KERNEL); if (NULL == cpu) return -ENOMEM; pt->size = SAA7134_PGTABLE_SIZE; @@ -254,7 +255,7 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) { if (NULL == pt->cpu) return; - pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); + dma_free_coherent(&pci->dev, pt->size, pt->cpu, pt->dma); pt->cpu = NULL; } @@ -1092,7 +1093,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); - err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); + err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); if (err) { pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name); goto err_v4l2_unregister; From d229a910bf8c597340133e69d7fbbaede5a1692c Mon Sep 17 00:00:00 2001 From: Herman Date: Tue, 15 Jun 2021 04:06:36 +0200 Subject: [PATCH 017/195] media: drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c : fix typo 'in deed imporant' > 'indeed important' Change 'imporant' into 'important'. Signed-off-by: Herman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 49503c20d3200..28a06dc343fd5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1418,7 +1418,7 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) if (test_and_clear_bit(0, &dev->hw_lock) == 0) mfc_err("Failed to unlock hardware\n"); - /* This is in deed imporant, as no operation has been + /* This is indeed important, as no operation has been * scheduled, reduce the clock count as no one will * ever do this, because no interrupt related to this try_run * will ever come from hardware. */ From ea3e1c36e38810427485f06c2becc1f29e54521d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Wed, 16 Jun 2021 07:13:55 +0200 Subject: [PATCH 018/195] media: TDA1997x: enable EDID support Without this patch, the TDA19971 chip's EDID is inactive. EDID never worked with this driver, it was all tested with HDMI signal sources which don't need EDID support. Signed-off-by: Krzysztof Halasa Fixes: 9ac0038db9a7 ("media: i2c: Add TDA1997x HDMI receiver driver") Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda1997x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 91e6db847bb5a..3a191e257fad0 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -2233,6 +2233,7 @@ static int tda1997x_core_init(struct v4l2_subdev *sd) /* get initial HDMI status */ state->hdmi_status = io_read(sd, REG_HDMI_FLAGS); + io_write(sd, REG_EDID_ENABLE, EDID_ENABLE_A_EN | EDID_ENABLE_B_EN); return 0; } From 40c7f9c31d86bfa86306a7104ca361e78e76ba2c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 16 Jun 2021 09:22:20 +0200 Subject: [PATCH 019/195] media: vivid: increase max number of allowed The max number of allowed logical addresses was set to 1 in vivid, for no good reason. This prevented testing with multiple logical addresses for the same CEC device. Increase this number to CEC_MAX_LOG_ADDRS. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/test-drivers/vivid/vivid-cec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/test-drivers/vivid/vivid-cec.c b/drivers/media/test-drivers/vivid/vivid-cec.c index 4d2413e877303..55ea039fe5b2a 100644 --- a/drivers/media/test-drivers/vivid/vivid-cec.c +++ b/drivers/media/test-drivers/vivid/vivid-cec.c @@ -282,5 +282,5 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d", dev->inst, is_source ? "out" : "cap", idx); return cec_allocate_adapter(&vivid_cec_adap_ops, dev, - name, caps, 1); + name, caps, CEC_MAX_LOG_ADDRS); } From 46fdc302028e6d50138e951f9b3f1a781c2f07dd Mon Sep 17 00:00:00 2001 From: Herman Date: Wed, 16 Jun 2021 10:03:16 +0200 Subject: [PATCH 020/195] media: drivers/media/platform/marvell-ccic/mcam-core.c : fix typo 'gettig' > 'getting' Change 'gettig' into 'getting'. Signed-off-by: Herman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mcam-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 070a0f3fc3376..58f9463f3b8ce 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -692,7 +692,7 @@ static void mcam_dma_sg_done(struct mcam_camera *cam, int frame) * Scatter/gather mode requires stopping the controller between * frames so we can put in a new DMA descriptor array. If no new * buffer exists at frame completion, the controller is left stopped; - * this function is charged with gettig things going again. + * this function is charged with getting things going again. */ static void mcam_sg_restart(struct mcam_camera *cam) { From 3f3475a5c77e9eabab43537f713b90f1d19258b7 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Wed, 16 Jun 2021 10:36:45 +0200 Subject: [PATCH 021/195] media: saa7134: convert list_for_each to entry variant Convert list_for_each() to list_for_each_entry() where applicable. Signed-off-by: Yang Yingliang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-alsa.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index 7a1fb067b0e09..fb24d2ed3621b 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -1215,15 +1215,13 @@ static int alsa_device_exit(struct saa7134_dev *dev) static int saa7134_alsa_init(void) { struct saa7134_dev *dev = NULL; - struct list_head *list; saa7134_dmasound_init = alsa_device_init; saa7134_dmasound_exit = alsa_device_exit; pr_info("saa7134 ALSA driver for DMA sound loaded\n"); - list_for_each(list,&saa7134_devlist) { - dev = list_entry(list, struct saa7134_dev, devlist); + list_for_each_entry(dev, &saa7134_devlist, devlist) { if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) pr_info("%s/alsa: %s doesn't support digital audio\n", dev->name, saa7134_boards[dev->board].name); From afaff559ae98fec64e7e066749ab135577c17ddd Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 18 Jun 2021 11:50:20 +0200 Subject: [PATCH 022/195] media: saa7164: remove redundant continue statement The continue statement at the end of a for-loop has no effect, remove it. Addresses-Coverity: ("Continue has no effect") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7164/saa7164-cmd.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/pci/saa7164/saa7164-cmd.c b/drivers/media/pci/saa7164/saa7164-cmd.c index 716162055fb7b..a65d810ce212b 100644 --- a/drivers/media/pci/saa7164/saa7164-cmd.c +++ b/drivers/media/pci/saa7164/saa7164-cmd.c @@ -549,9 +549,6 @@ int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, /* See of other commands are on the bus */ if (saa7164_cmd_dequeue(dev) != SAA_OK) printk(KERN_ERR "dequeue(3) failed\n"); - - continue; - } /* (loop) */ /* Release the sequence number allocation */ From 4e11f02f6f9e10015ca07dd016359d2cde9cfbe7 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:11 +0200 Subject: [PATCH 023/195] media: ti-vpe: cal: add g/s_parm for legacy API v4l2-compliance complains about g/s_parm when using the non-MC API. Fix it by adding the functions and just call v4l2_s/g_parm_cap for the phy subdev. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-video.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index 15fb5360cf13c..57b3a592f8237 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -388,6 +388,20 @@ static int cal_enum_frameintervals(struct file *file, void *priv, return 0; } +static int cal_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct cal_ctx *ctx = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), ctx->phy->sensor, a); +} + +static int cal_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct cal_ctx *ctx = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), ctx->phy->sensor, a); +} + static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { .vidioc_querycap = cal_querycap, .vidioc_enum_fmt_vid_cap = cal_enum_fmt_vid_cap, @@ -411,6 +425,8 @@ static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { .vidioc_log_status = v4l2_ctrl_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_parm = cal_g_parm, + .vidioc_s_parm = cal_s_parm, }; /* ------------------------------------------------------------------ From 918d6d120a60c2640263396308eeb2b6afeb0cd6 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:12 +0200 Subject: [PATCH 024/195] media: ti-vpe: cal: fix error handling in cal_camerarx_create cal_camerarx_create() doesn't handle error returned from cal_camerarx_sd_init_cfg(). Fix this. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index 124a4e2bdefe0..e2e384a887ac2 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -845,7 +845,9 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, if (ret) goto error; - cal_camerarx_sd_init_cfg(sd, NULL); + ret = cal_camerarx_sd_init_cfg(sd, NULL); + if (ret) + goto error; ret = v4l2_device_register_subdev(&cal->v4l2_dev, sd); if (ret) From 97a2c65e2f21ac02807983b9602de2c82c25d0f7 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:13 +0200 Subject: [PATCH 025/195] media: ti-vpe: cal: remove unused cal_camerarx->dev field cal_camerarx->dev field is not used, remove it. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index db0e408eaa94a..e079c6a9f93f9 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -149,7 +149,6 @@ struct cal_data { struct cal_camerarx { void __iomem *base; struct resource *res; - struct device *dev; struct regmap_field *fields[F_MAX_FIELDS]; struct cal_dev *cal; From 27f86b9bff79e15ffdb047c2457b1b56417fe4fd Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:14 +0200 Subject: [PATCH 026/195] media: ti-vpe: cal: rename "sensor" to "source" CAL driver uses "sensor" name to refer to the subdev connected to CAL. As the subdev can also be a bridge, the naming is misleading and might cause the reader to think it refers to the actual sensor at the end of the pipeline. Rename "sensor" to "source". Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 34 ++++++++++---------- drivers/media/platform/ti-vpe/cal-video.c | 26 +++++++-------- drivers/media/platform/ti-vpe/cal.c | 20 ++++++------ drivers/media/platform/ti-vpe/cal.h | 6 ++-- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index e2e384a887ac2..92d39ef456252 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -50,15 +50,15 @@ static s64 cal_camerarx_get_external_rate(struct cal_camerarx *phy) struct v4l2_ctrl *ctrl; s64 rate; - ctrl = v4l2_ctrl_find(phy->sensor->ctrl_handler, V4L2_CID_PIXEL_RATE); + ctrl = v4l2_ctrl_find(phy->source->ctrl_handler, V4L2_CID_PIXEL_RATE); if (!ctrl) { phy_err(phy, "no pixel rate control in subdev: %s\n", - phy->sensor->name); + phy->source->name); return -EPIPE; } rate = v4l2_ctrl_g_ctrl_int64(ctrl); - phy_dbg(3, phy, "sensor Pixel Rate: %llu\n", rate); + phy_dbg(3, phy, "Source Pixel Rate: %llu\n", rate); return rate; } @@ -279,7 +279,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy) if (external_rate < 0) return external_rate; - ret = v4l2_subdev_call(phy->sensor, core, s_power, 1); + ret = v4l2_subdev_call(phy->source, core, s_power, 1); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { phy_err(phy, "power on failed in subdev\n"); return ret; @@ -311,7 +311,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy) * 2. CSI PHY and link initialization sequence. * * a. Deassert the CSI-2 PHY reset. Do not wait for reset completion - * at this point, as it requires the external sensor to send the + * at this point, as it requires the external source to send the * CSI-2 HS clock. */ cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), @@ -370,12 +370,12 @@ static int cal_camerarx_start(struct cal_camerarx *phy) cal_camerarx_power(phy, true); /* - * Start the sensor to enable the CSI-2 HS clock. We can now wait for + * Start the source to enable the CSI-2 HS clock. We can now wait for * CSI-2 PHY reset to complete. */ - ret = v4l2_subdev_call(phy->sensor, video, s_stream, 1); + ret = v4l2_subdev_call(phy->source, video, s_stream, 1); if (ret) { - v4l2_subdev_call(phy->sensor, core, s_power, 0); + v4l2_subdev_call(phy->source, core, s_power, 0); cal_camerarx_disable_irqs(phy); phy_err(phy, "stream on failed in subdev\n"); return ret; @@ -435,10 +435,10 @@ static void cal_camerarx_stop(struct cal_camerarx *phy) /* Disable the phy */ cal_camerarx_disable(phy); - if (v4l2_subdev_call(phy->sensor, video, s_stream, 0)) + if (v4l2_subdev_call(phy->source, video, s_stream, 0)) phy_err(phy, "stream off failed in subdev\n"); - ret = v4l2_subdev_call(phy->sensor, core, s_power, 0); + ret = v4l2_subdev_call(phy->source, core, s_power, 0); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) phy_err(phy, "power off failed in subdev\n"); } @@ -558,16 +558,16 @@ static int cal_camerarx_parse_dt(struct cal_camerarx *phy) endpoint->bus.mipi_csi2.flags); /* Retrieve the connected device and store it for later use. */ - phy->sensor_ep_node = of_graph_get_remote_endpoint(ep_node); - phy->sensor_node = of_graph_get_port_parent(phy->sensor_ep_node); - if (!phy->sensor_node) { + phy->source_ep_node = of_graph_get_remote_endpoint(ep_node); + phy->source_node = of_graph_get_port_parent(phy->source_ep_node); + if (!phy->source_node) { phy_dbg(3, phy, "Can't get remote parent\n"); - of_node_put(phy->sensor_ep_node); + of_node_put(phy->source_ep_node); ret = -EINVAL; goto done; } - phy_dbg(1, phy, "Found connected device %pOFn\n", phy->sensor_node); + phy_dbg(1, phy, "Found connected device %pOFn\n", phy->source_node); done: of_node_put(ep_node); @@ -868,7 +868,7 @@ void cal_camerarx_destroy(struct cal_camerarx *phy) v4l2_device_unregister_subdev(&phy->subdev); media_entity_cleanup(&phy->subdev.entity); - of_node_put(phy->sensor_ep_node); - of_node_put(phy->sensor_node); + of_node_put(phy->source_ep_node); + of_node_put(phy->source_node); kfree(phy); } diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index 57b3a592f8237..9d0b515f013e6 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -128,7 +128,7 @@ static int __subdev_get_format(struct cal_ctx *ctx, sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; sd_fmt.pad = 0; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, get_fmt, NULL, &sd_fmt); + ret = v4l2_subdev_call(ctx->phy->source, pad, get_fmt, NULL, &sd_fmt); if (ret) return ret; @@ -151,7 +151,7 @@ static int __subdev_set_format(struct cal_ctx *ctx, sd_fmt.pad = 0; *mbus_fmt = *fmt; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, set_fmt, NULL, &sd_fmt); + ret = v4l2_subdev_call(ctx->phy->source, pad, set_fmt, NULL, &sd_fmt); if (ret) return ret; @@ -216,7 +216,7 @@ static int cal_try_fmt_vid_cap(struct file *file, void *priv, fse.code = fmtinfo->code; fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; for (fse.index = 0; ; fse.index++) { - ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size, + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL, &fse); if (ret) break; @@ -321,7 +321,7 @@ static int cal_enum_framesizes(struct file *file, void *fh, fse.code = fmtinfo->code; fse.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_size, NULL, + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL, &fse); if (ret) return ret; @@ -378,7 +378,7 @@ static int cal_enum_frameintervals(struct file *file, void *priv, return -EINVAL; fie.code = fmtinfo->code; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_frame_interval, + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_interval, NULL, &fie); if (ret) return ret; @@ -392,14 +392,14 @@ static int cal_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct cal_ctx *ctx = video_drvdata(file); - return v4l2_g_parm_cap(video_devdata(file), ctx->phy->sensor, a); + return v4l2_g_parm_cap(video_devdata(file), ctx->phy->source, a); } static int cal_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct cal_ctx *ctx = video_drvdata(file); - return v4l2_s_parm_cap(video_devdata(file), ctx->phy->sensor, a); + return v4l2_s_parm_cap(video_devdata(file), ctx->phy->source, a); } static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { @@ -801,20 +801,20 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) memset(&mbus_code, 0, sizeof(mbus_code)); mbus_code.index = j; mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(ctx->phy->sensor, pad, enum_mbus_code, + ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code, NULL, &mbus_code); if (ret == -EINVAL) break; if (ret) { ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n", - ctx->phy->sensor->name, ret); + ctx->phy->source->name, ret); return ret; } ctx_dbg(2, ctx, "subdev %s: code: %04x idx: %u\n", - ctx->phy->sensor->name, mbus_code.code, j); + ctx->phy->source->name, mbus_code.code, j); for (k = 0; k < cal_num_formats; k++) { fmtinfo = &cal_formats[k]; @@ -832,7 +832,7 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) if (i == 0) { ctx_err(ctx, "No suitable format reported by subdev %s\n", - ctx->phy->sensor->name); + ctx->phy->source->name); return -EINVAL; } @@ -869,10 +869,10 @@ int cal_ctx_v4l2_register(struct cal_ctx *ctx) if (!cal_mc_api) { struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; - ret = v4l2_ctrl_add_handler(hdl, ctx->phy->sensor->ctrl_handler, + ret = v4l2_ctrl_add_handler(hdl, ctx->phy->source->ctrl_handler, NULL, true); if (ret < 0) { - ctx_err(ctx, "Failed to add sensor ctrl handler\n"); + ctx_err(ctx, "Failed to add source ctrl handler\n"); return ret; } } diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 76fe7a8b33f6b..9446933b9189c 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -635,20 +635,20 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier, int pad; int ret; - if (phy->sensor) { + if (phy->source) { phy_info(phy, "Rejecting subdev %s (Already set!!)", subdev->name); return 0; } - phy->sensor = subdev; - phy_dbg(1, phy, "Using sensor %s for capture\n", subdev->name); + phy->source = subdev; + phy_dbg(1, phy, "Using source %s for capture\n", subdev->name); pad = media_entity_get_fwnode_pad(&subdev->entity, - of_fwnode_handle(phy->sensor_ep_node), + of_fwnode_handle(phy->source_ep_node), MEDIA_PAD_FL_SOURCE); if (pad < 0) { - phy_err(phy, "Sensor %s has no connected source pad\n", + phy_err(phy, "Source %s has no connected source pad\n", subdev->name); return pad; } @@ -658,7 +658,7 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); if (ret) { - phy_err(phy, "Failed to create media link for sensor %s\n", + phy_err(phy, "Failed to create media link for source %s\n", subdev->name); return ret; } @@ -701,10 +701,10 @@ static int cal_async_notifier_register(struct cal_dev *cal) struct cal_v4l2_async_subdev *casd; struct fwnode_handle *fwnode; - if (!phy->sensor_node) + if (!phy->source_node) continue; - fwnode = of_fwnode_handle(phy->sensor_node); + fwnode = of_fwnode_handle(phy->source_node); casd = v4l2_async_notifier_add_fwnode_subdev(&cal->notifier, fwnode, struct cal_v4l2_async_subdev); @@ -1045,7 +1045,7 @@ static int cal_probe(struct platform_device *pdev) goto error_camerarx; } - if (cal->phy[i]->sensor_node) + if (cal->phy[i]->source_node) connected = true; } @@ -1057,7 +1057,7 @@ static int cal_probe(struct platform_device *pdev) /* Create contexts. */ for (i = 0; i < cal->data->num_csi2_phy; ++i) { - if (!cal->phy[i]->sensor_node) + if (!cal->phy[i]->source_node) continue; cal->ctx[i] = cal_ctx_create(cal, i); diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index e079c6a9f93f9..af46084580bd1 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -155,9 +155,9 @@ struct cal_camerarx { unsigned int instance; struct v4l2_fwnode_endpoint endpoint; - struct device_node *sensor_ep_node; - struct device_node *sensor_node; - struct v4l2_subdev *sensor; + struct device_node *source_ep_node; + struct device_node *source_node; + struct v4l2_subdev *source; struct media_pipeline pipe; struct v4l2_subdev subdev; From 93080e25a86d20ab875ffc278fa9c67f941f651e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:15 +0200 Subject: [PATCH 027/195] media: ti-vpe: cal: move global config from cal_ctx_wr_dma_config to runtime resume For some reason CAL_CTRL is written at the end of cal_ctx_wr_dma_config. CAL_CTRL is a global (for CAL) register, so it should be independent of contexts. Move the code to cal_runtime_resume(). Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 9446933b9189c..2f70725a567ba 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -403,17 +403,6 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index), val); ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->index, cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index))); - - val = cal_read(ctx->cal, CAL_CTRL); - cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, - CAL_CTRL_BURSTSIZE_MASK); - cal_set_field(&val, 0xF, CAL_CTRL_TAGCNT_MASK); - cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, - CAL_CTRL_POSTED_WRITES_MASK); - cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGL_MASK); - cal_set_field(&val, 0xFF, CAL_CTRL_MFLAGH_MASK); - cal_write(ctx->cal, CAL_CTRL, val); - ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", cal_read(ctx->cal, CAL_CTRL)); } void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr) @@ -1127,6 +1116,7 @@ static int cal_runtime_resume(struct device *dev) { struct cal_dev *cal = dev_get_drvdata(dev); unsigned int i; + u32 val; if (cal->data->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) { /* @@ -1143,6 +1133,17 @@ static int cal_runtime_resume(struct device *dev) */ cal_write(cal, CAL_HL_IRQENABLE_SET(0), CAL_HL_IRQ_OCPO_ERR_MASK); + val = cal_read(cal, CAL_CTRL); + cal_set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, + CAL_CTRL_BURSTSIZE_MASK); + cal_set_field(&val, 0xf, CAL_CTRL_TAGCNT_MASK); + cal_set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED, + CAL_CTRL_POSTED_WRITES_MASK); + cal_set_field(&val, 0xff, CAL_CTRL_MFLAGL_MASK); + cal_set_field(&val, 0xff, CAL_CTRL_MFLAGH_MASK); + cal_write(cal, CAL_CTRL, val); + cal_dbg(3, cal, "CAL_CTRL = 0x%08x\n", cal_read(cal, CAL_CTRL)); + return 0; } From bbdb9ae8d470715f85a690d7d2c7b54e7cff9cd6 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:16 +0200 Subject: [PATCH 028/195] media: ti-vpe: cal: use v4l2_get_link_freq CAL driver uses V4L2_CID_PIXEL_RATE to get the required pixel rate, and then changes that value to link rate before configuring the registers. Rewrite the code to use v4l2_get_link_freq(), which simplifies the code as we get the link rate directly, and it also adds support for V4L2_CID_LINK_FREQ. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 52 +++++++------------- 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index 92d39ef456252..3bc63a5e93177 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -45,22 +45,23 @@ static inline void camerarx_write(struct cal_camerarx *phy, u32 offset, u32 val) * ------------------------------------------------------------------ */ -static s64 cal_camerarx_get_external_rate(struct cal_camerarx *phy) +static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy) { - struct v4l2_ctrl *ctrl; - s64 rate; + struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2; + u32 num_lanes = mipi_csi2->num_data_lanes; + u32 bpp = phy->fmtinfo->bpp; + s64 freq; - ctrl = v4l2_ctrl_find(phy->source->ctrl_handler, V4L2_CID_PIXEL_RATE); - if (!ctrl) { - phy_err(phy, "no pixel rate control in subdev: %s\n", + freq = v4l2_get_link_freq(phy->source->ctrl_handler, bpp, 2 * num_lanes); + if (freq < 0) { + phy_err(phy, "failed to get link freq for subdev '%s'\n", phy->source->name); - return -EPIPE; + return freq; } - rate = v4l2_ctrl_g_ctrl_int64(ctrl); - phy_dbg(3, phy, "Source Pixel Rate: %llu\n", rate); + phy_dbg(3, phy, "Source Link Freq: %llu\n", freq); - return rate; + return freq; } static void cal_camerarx_lane_config(struct cal_camerarx *phy) @@ -116,34 +117,19 @@ void cal_camerarx_disable(struct cal_camerarx *phy) #define TCLK_MISS 1 #define TCLK_SETTLE 14 -static void cal_camerarx_config(struct cal_camerarx *phy, s64 external_rate) +static void cal_camerarx_config(struct cal_camerarx *phy, s64 link_freq) { unsigned int reg0, reg1; unsigned int ths_term, ths_settle; - unsigned int csi2_ddrclk_khz; - struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = - &phy->endpoint.bus.mipi_csi2; - u32 num_lanes = mipi_csi2->num_data_lanes; /* DPHY timing configuration */ - /* - * CSI-2 is DDR and we only count used lanes. - * - * csi2_ddrclk_khz = external_rate / 1000 - * / (2 * num_lanes) * phy->fmtinfo->bpp; - */ - csi2_ddrclk_khz = div_s64(external_rate * phy->fmtinfo->bpp, - 2 * num_lanes * 1000); - - phy_dbg(1, phy, "csi2_ddrclk_khz: %d\n", csi2_ddrclk_khz); - /* THS_TERM: Programmed value = floor(20 ns/DDRClk period) */ - ths_term = 20 * csi2_ddrclk_khz / 1000000; + ths_term = div_s64(20 * link_freq, 1000 * 1000 * 1000); phy_dbg(1, phy, "ths_term: %d (0x%02x)\n", ths_term, ths_term); /* THS_SETTLE: Programmed value = floor(105 ns/DDRClk period) + 4 */ - ths_settle = (105 * csi2_ddrclk_khz / 1000000) + 4; + ths_settle = div_s64(105 * link_freq, 1000 * 1000 * 1000) + 4; phy_dbg(1, phy, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle); reg0 = camerarx_read(phy, CAL_CSI2_PHY_REG0); @@ -270,14 +256,14 @@ static void cal_camerarx_ppi_disable(struct cal_camerarx *phy) static int cal_camerarx_start(struct cal_camerarx *phy) { - s64 external_rate; + s64 link_freq; u32 sscounter; u32 val; int ret; - external_rate = cal_camerarx_get_external_rate(phy); - if (external_rate < 0) - return external_rate; + link_freq = cal_camerarx_get_ext_link_freq(phy); + if (link_freq < 0) + return link_freq; ret = v4l2_subdev_call(phy->source, core, s_power, 1); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { @@ -325,7 +311,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy) camerarx_read(phy, CAL_CSI2_PHY_REG0); /* Program the PHY timing parameters. */ - cal_camerarx_config(phy, external_rate); + cal_camerarx_config(phy, link_freq); /* * b. Assert the FORCERXMODE signal. From 2e63c4c57aff0e2972eaed126b8b64bfd9ed4604 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:17 +0200 Subject: [PATCH 029/195] media: ti-vpe: cal: add cal_ctx_prepare/unprepare In the following patches we need to do context configuration which might fail. Add new functions, cal_ctx_prepare and cal_ctx_unprepare, to handle such configuration. [hverkuil: fix spurious newline checkpatch warning] Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-video.c | 9 +++++++++ drivers/media/platform/ti-vpe/cal.c | 9 +++++++++ drivers/media/platform/ti-vpe/cal.h | 2 ++ 3 files changed, 20 insertions(+) diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index 9d0b515f013e6..f17524579102b 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -708,6 +708,12 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) goto error_pipeline; } + ret = cal_ctx_prepare(ctx); + if (ret) { + ctx_err(ctx, "Failed to prepare context: %d\n", ret); + goto error_pipeline; + } + spin_lock_irq(&ctx->dma.lock); buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list); ctx->dma.pending = buf; @@ -735,6 +741,7 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) error_stop: cal_ctx_stop(ctx); pm_runtime_put_sync(ctx->cal->dev); + cal_ctx_unprepare(ctx); error_pipeline: media_pipeline_stop(&ctx->vdev.entity); @@ -754,6 +761,8 @@ static void cal_stop_streaming(struct vb2_queue *vq) pm_runtime_put_sync(ctx->cal->dev); + cal_ctx_unprepare(ctx); + cal_release_buffers(ctx, VB2_BUF_STATE_ERROR); media_pipeline_stop(&ctx->vdev.entity); diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 2f70725a567ba..fb3d14162ffa2 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -430,6 +430,15 @@ static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) return stopped; } +int cal_ctx_prepare(struct cal_ctx *ctx) +{ + return 0; +} + +void cal_ctx_unprepare(struct cal_ctx *ctx) +{ +} + void cal_ctx_start(struct cal_ctx *ctx) { ctx->sequence = 0; diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index af46084580bd1..09ad20faa9e19 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -296,6 +296,8 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, unsigned int instance); void cal_camerarx_destroy(struct cal_camerarx *phy); +int cal_ctx_prepare(struct cal_ctx *ctx); +void cal_ctx_unprepare(struct cal_ctx *ctx); void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr); void cal_ctx_start(struct cal_ctx *ctx); void cal_ctx_stop(struct cal_ctx *ctx); From 05b12b557234995aa77083d3c6c373832816c01f Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:18 +0200 Subject: [PATCH 030/195] media: ti-vpe: cal: change index and cport to u8 cal_ctx's index and cport fields are numbers less than 8. In the following patches we will get a bunch of new fields, all of which are similar small numbers, so lets change the type to u8. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index 09ad20faa9e19..251bb0ba7b3bc 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -217,8 +217,8 @@ struct cal_ctx { unsigned int sequence; struct vb2_queue vb_vidq; - unsigned int index; - unsigned int cport; + u8 index; + u8 cport; }; extern unsigned int cal_debug; From 6266ddefec0f89507b6099d1ad0a695f2ffea6b6 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:19 +0200 Subject: [PATCH 031/195] media: ti-vpe: cal: Add CSI2 context CAL has 8 CSI2 contexts per PHY, which are used to tag the incoming data. The current driver only uses the first context, but we need to support all of them to implement multi-stream support. Add a csi2_ctx field to cal_ctx, which indicates which of the 8 CSI2 contexts is used for the particular cal_ctx. Also clean up the context register macros to take the CSI2 context number as a parameter. Note that before this patch the CSI2 context used for both PHYs was always 0. This patch always uses cal_ctx index number as the CSI2 context. There is no functional difference, but this approach will work also in the future when we use more than 1 CSI2 context per PHY. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 10 ++++++---- drivers/media/platform/ti-vpe/cal.h | 1 + drivers/media/platform/ti-vpe/cal_regs.h | 18 ++---------------- 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index fb3d14162ffa2..a96019cf8b285 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -294,7 +294,7 @@ static void cal_ctx_csi2_config(struct cal_ctx *ctx) { u32 val; - val = cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index)); + val = cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx)); cal_set_field(&val, ctx->cport, CAL_CSI2_CTX_CPORT_MASK); /* * DT type: MIPI CSI-2 Specs @@ -310,9 +310,10 @@ static void cal_ctx_csi2_config(struct cal_ctx *ctx) cal_set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK); cal_set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE, CAL_CSI2_CTX_PACK_MODE_MASK); - cal_write(ctx->cal, CAL_CSI2_CTX0(ctx->index), val); - ctx_dbg(3, ctx, "CAL_CSI2_CTX0(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index))); + cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), val); + ctx_dbg(3, ctx, "CAL_CSI2_CTX(%u, %u) = 0x%08x\n", + ctx->phy->instance, ctx->csi2_ctx, + cal_read(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx))); } static void cal_ctx_pix_proc_config(struct cal_ctx *ctx) @@ -853,6 +854,7 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) ctx->cal = cal; ctx->phy = cal->phy[inst]; ctx->index = inst; + ctx->csi2_ctx = inst; ctx->cport = inst; ret = cal_ctx_v4l2_init(ctx); diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index 251bb0ba7b3bc..bcc3378b6b41d 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -219,6 +219,7 @@ struct cal_ctx { struct vb2_queue vb_vidq; u8 index; u8 cport; + u8 csi2_ctx; }; extern unsigned int cal_debug; diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h index f752096dcf7f7..bf937919a1e96 100644 --- a/drivers/media/platform/ti-vpe/cal_regs.h +++ b/drivers/media/platform/ti-vpe/cal_regs.h @@ -72,22 +72,8 @@ #define CAL_CSI2_TIMING(m) (0x314U + (m) * 0x80U) #define CAL_CSI2_VC_IRQENABLE(m) (0x318U + (m) * 0x80U) #define CAL_CSI2_VC_IRQSTATUS(m) (0x328U + (m) * 0x80U) -#define CAL_CSI2_CTX0(m) (0x330U + (m) * 0x80U) -#define CAL_CSI2_CTX1(m) (0x334U + (m) * 0x80U) -#define CAL_CSI2_CTX2(m) (0x338U + (m) * 0x80U) -#define CAL_CSI2_CTX3(m) (0x33cU + (m) * 0x80U) -#define CAL_CSI2_CTX4(m) (0x340U + (m) * 0x80U) -#define CAL_CSI2_CTX5(m) (0x344U + (m) * 0x80U) -#define CAL_CSI2_CTX6(m) (0x348U + (m) * 0x80U) -#define CAL_CSI2_CTX7(m) (0x34cU + (m) * 0x80U) -#define CAL_CSI2_STATUS0(m) (0x350U + (m) * 0x80U) -#define CAL_CSI2_STATUS1(m) (0x354U + (m) * 0x80U) -#define CAL_CSI2_STATUS2(m) (0x358U + (m) * 0x80U) -#define CAL_CSI2_STATUS3(m) (0x35cU + (m) * 0x80U) -#define CAL_CSI2_STATUS4(m) (0x360U + (m) * 0x80U) -#define CAL_CSI2_STATUS5(m) (0x364U + (m) * 0x80U) -#define CAL_CSI2_STATUS6(m) (0x368U + (m) * 0x80U) -#define CAL_CSI2_STATUS7(m) (0x36cU + (m) * 0x80U) +#define CAL_CSI2_CTX(phy, csi2_ctx) (0x330U + (phy) * 0x80U + (csi2_ctx) * 4) +#define CAL_CSI2_STATUS(phy, csi2_ctx) (0x350U + (phy) * 0x80U + (csi2_ctx) * 4) /* CAL CSI2 PHY register offsets */ #define CAL_CSI2_PHY_REG0 0x000 From 0de6f41a06b8b69f2230a0488fde1703e55f0f39 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:20 +0200 Subject: [PATCH 032/195] media: ti-vpe: cal: Add pixel processing context CAL has 4 pixel processing contexts (PIX PROC) of which the driver currently uses pix proc 0 for PHY0, and pix proc 1 for PHY1 (as the driver supports only a single source per PHY). Add a pix_proc field to cal_ctx to allow us to use different pix proc contexts in the future Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 9 +++++---- drivers/media/platform/ti-vpe/cal.h | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index a96019cf8b285..1b38b8ad6cf94 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -355,16 +355,16 @@ static void cal_ctx_pix_proc_config(struct cal_ctx *ctx) break; } - val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->index)); + val = cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc)); cal_set_field(&val, extract, CAL_PIX_PROC_EXTRACT_MASK); cal_set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK); cal_set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK); cal_set_field(&val, pack, CAL_PIX_PROC_PACK_MASK); cal_set_field(&val, ctx->cport, CAL_PIX_PROC_CPORT_MASK); cal_set_field(&val, 1, CAL_PIX_PROC_EN_MASK); - cal_write(ctx->cal, CAL_PIX_PROC(ctx->index), val); - ctx_dbg(3, ctx, "CAL_PIX_PROC(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_PIX_PROC(ctx->index))); + cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), val); + ctx_dbg(3, ctx, "CAL_PIX_PROC(%u) = 0x%08x\n", ctx->pix_proc, + cal_read(ctx->cal, CAL_PIX_PROC(ctx->pix_proc))); } static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) @@ -856,6 +856,7 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) ctx->index = inst; ctx->csi2_ctx = inst; ctx->cport = inst; + ctx->pix_proc = inst; ret = cal_ctx_v4l2_init(ctx); if (ret) diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index bcc3378b6b41d..9475dc80559b6 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -220,6 +220,7 @@ struct cal_ctx { u8 index; u8 cport; u8 csi2_ctx; + u8 pix_proc; }; extern unsigned int cal_debug; From 42a1364ce738ffd02957f1b1e6e863e62398412e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:21 +0200 Subject: [PATCH 033/195] media: ti-vpe: cal: rename cal_ctx->index to dma_ctx Rename cal_ctx->index to dma_ctx to clarify that the field refers to the DMA context number. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-video.c | 4 +-- drivers/media/platform/ti-vpe/cal.c | 38 +++++++++++------------ drivers/media/platform/ti-vpe/cal.h | 8 ++--- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index f17524579102b..cdbfdca8570fa 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -899,7 +899,7 @@ int cal_ctx_v4l2_register(struct cal_ctx *ctx) MEDIA_LNK_FL_ENABLED); if (ret) { ctx_err(ctx, "Failed to create media link for context %u\n", - ctx->index); + ctx->dma_ctx); video_unregister_device(vfd); return ret; } @@ -951,7 +951,7 @@ int cal_ctx_v4l2_init(struct cal_ctx *ctx) | (cal_mc_api ? V4L2_CAP_IO_MC : 0); vfd->v4l2_dev = &ctx->cal->v4l2_dev; vfd->queue = q; - snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->index); + snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->dma_ctx); vfd->release = video_device_release_empty; vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_video_ops; vfd->lock = &ctx->mutex; diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 1b38b8ad6cf94..21584ff7062f7 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -372,7 +372,7 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) unsigned int stride = ctx->v_fmt.fmt.pix.bytesperline; u32 val; - val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index)); + val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); cal_set_field(&val, ctx->cport, CAL_WR_DMA_CTRL_CPORT_MASK); cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_WR_DMA_CTRL_YSIZE_MASK); @@ -383,16 +383,16 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) cal_set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR, CAL_WR_DMA_CTRL_PATTERN_MASK); cal_set_field(&val, 1, CAL_WR_DMA_CTRL_STALL_RD_MASK); - cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val); - ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index))); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); + ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx))); - cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->index), + cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx), stride / 16, CAL_WR_DMA_OFST_MASK); - ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->index))); + ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->dma_ctx))); - val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index)); + val = cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx)); /* 64 bit word means no skipping */ cal_set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK); /* @@ -401,23 +401,23 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) * written per line. */ cal_set_field(&val, stride / 8, CAL_WR_DMA_XSIZE_MASK); - cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index), val); - ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->index, - cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index))); + cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx), val); + ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->dma_ctx, + cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->dma_ctx))); } void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr) { - cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->index), addr); + cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->dma_ctx), addr); } static void cal_ctx_wr_dma_disable(struct cal_ctx *ctx) { - u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index)); + u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_DIS, CAL_WR_DMA_CTRL_MODE_MASK); - cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); } static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) @@ -452,9 +452,9 @@ void cal_ctx_start(struct cal_ctx *ctx) /* Enable IRQ_WDMA_END and IRQ_WDMA_START. */ cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(1), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_MASK(ctx->dma_ctx)); cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(2), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_MASK(ctx->dma_ctx)); } void cal_ctx_stop(struct cal_ctx *ctx) @@ -478,9 +478,9 @@ void cal_ctx_stop(struct cal_ctx *ctx) /* Disable IRQ_WDMA_END and IRQ_WDMA_START. */ cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(1), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_MASK(ctx->dma_ctx)); cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(2), - CAL_HL_IRQ_MASK(ctx->index)); + CAL_HL_IRQ_MASK(ctx->dma_ctx)); ctx->dma.state = CAL_DMA_STOPPED; } @@ -853,7 +853,7 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) ctx->cal = cal; ctx->phy = cal->phy[inst]; - ctx->index = inst; + ctx->dma_ctx = inst; ctx->csi2_ctx = inst; ctx->cport = inst; ctx->pix_proc = inst; diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index 9475dc80559b6..e4db2a905f687 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -217,7 +217,7 @@ struct cal_ctx { unsigned int sequence; struct vb2_queue vb_vidq; - u8 index; + u8 dma_ctx; u8 cport; u8 csi2_ctx; u8 pix_proc; @@ -238,11 +238,11 @@ extern bool cal_mc_api; dev_err((cal)->dev, fmt, ##arg) #define ctx_dbg(level, ctx, fmt, arg...) \ - cal_dbg(level, (ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg) + cal_dbg(level, (ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) #define ctx_info(ctx, fmt, arg...) \ - cal_info((ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg) + cal_info((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) #define ctx_err(ctx, fmt, arg...) \ - cal_err((ctx)->cal, "ctx%u: " fmt, (ctx)->index, ##arg) + cal_err((ctx)->cal, "ctx%u: " fmt, (ctx)->dma_ctx, ##arg) #define phy_dbg(level, phy, fmt, arg...) \ cal_dbg(level, (phy)->cal, "phy%u: " fmt, (phy)->instance, ##arg) From 2eef9ee3c60010edd78ec961b4f7971e328e3e5e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:22 +0200 Subject: [PATCH 034/195] media: ti-vpe: cal: rename CAL_HL_IRQ_MASK CAL_HL_IRQ_MASK macro is used for both WDMA start and end status bits. For clarity, rename CAL_HL_IRQ_MASK macro to CAL_HL_IRQ_WDMA_END_MASK and CAL_HL_IRQ_WDMA_START_MASK. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 12 ++++++------ drivers/media/platform/ti-vpe/cal_regs.h | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 21584ff7062f7..673952b3e3826 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -452,9 +452,9 @@ void cal_ctx_start(struct cal_ctx *ctx) /* Enable IRQ_WDMA_END and IRQ_WDMA_START. */ cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(1), - CAL_HL_IRQ_MASK(ctx->dma_ctx)); + CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(2), - CAL_HL_IRQ_MASK(ctx->dma_ctx)); + CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); } void cal_ctx_stop(struct cal_ctx *ctx) @@ -478,9 +478,9 @@ void cal_ctx_stop(struct cal_ctx *ctx) /* Disable IRQ_WDMA_END and IRQ_WDMA_START. */ cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(1), - CAL_HL_IRQ_MASK(ctx->dma_ctx)); + CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(2), - CAL_HL_IRQ_MASK(ctx->dma_ctx)); + CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); ctx->dma.state = CAL_DMA_STOPPED; } @@ -588,7 +588,7 @@ static irqreturn_t cal_irq(int irq_cal, void *data) cal_write(cal, CAL_HL_IRQSTATUS(1), status); for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (status & CAL_HL_IRQ_MASK(i)) + if (status & CAL_HL_IRQ_WDMA_END_MASK(i)) cal_irq_wdma_end(cal->ctx[i]); } } @@ -602,7 +602,7 @@ static irqreturn_t cal_irq(int irq_cal, void *data) cal_write(cal, CAL_HL_IRQSTATUS(2), status); for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (status & CAL_HL_IRQ_MASK(i)) + if (status & CAL_HL_IRQ_WDMA_START_MASK(i)) cal_irq_wdma_start(cal->ctx[i]); } } diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h index bf937919a1e96..94cb4f329cf31 100644 --- a/drivers/media/platform/ti-vpe/cal_regs.h +++ b/drivers/media/platform/ti-vpe/cal_regs.h @@ -125,7 +125,8 @@ #define CAL_HL_IRQ_EOI_LINE_NUMBER_READ0 0 #define CAL_HL_IRQ_EOI_LINE_NUMBER_EOI0 0 -#define CAL_HL_IRQ_MASK(m) BIT(m) +#define CAL_HL_IRQ_WDMA_END_MASK(m) BIT(m) +#define CAL_HL_IRQ_WDMA_START_MASK(m) BIT(m) #define CAL_HL_IRQ_OCPO_ERR_MASK BIT(6) From aece634d978c7bc570ec5399184cd7df4f5498e6 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:23 +0200 Subject: [PATCH 035/195] media: ti-vpe: cal: clean up CAL_CSI2_VC_IRQ_* macros The macros related to CAL_CSI2_VC_IRQ can be handled better by having the VC number as a macro parameter. Note that the macros are not used anywhere yet, so no other changes are needed. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal_regs.h | 30 +++++------------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h index 94cb4f329cf31..7eeceeeb303ec 100644 --- a/drivers/media/platform/ti-vpe/cal_regs.h +++ b/drivers/media/platform/ti-vpe/cal_regs.h @@ -406,30 +406,12 @@ #define CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK BIT(14) #define CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK BIT(15) -#define CAL_CSI2_VC_IRQ_FS_IRQ_0_MASK BIT(0) -#define CAL_CSI2_VC_IRQ_FE_IRQ_0_MASK BIT(1) -#define CAL_CSI2_VC_IRQ_LS_IRQ_0_MASK BIT(2) -#define CAL_CSI2_VC_IRQ_LE_IRQ_0_MASK BIT(3) -#define CAL_CSI2_VC_IRQ_CS_IRQ_0_MASK BIT(4) -#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_0_MASK BIT(5) -#define CAL_CSI2_VC_IRQ_FS_IRQ_1_MASK BIT(8) -#define CAL_CSI2_VC_IRQ_FE_IRQ_1_MASK BIT(9) -#define CAL_CSI2_VC_IRQ_LS_IRQ_1_MASK BIT(10) -#define CAL_CSI2_VC_IRQ_LE_IRQ_1_MASK BIT(11) -#define CAL_CSI2_VC_IRQ_CS_IRQ_1_MASK BIT(12) -#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_1_MASK BIT(13) -#define CAL_CSI2_VC_IRQ_FS_IRQ_2_MASK BIT(16) -#define CAL_CSI2_VC_IRQ_FE_IRQ_2_MASK BIT(17) -#define CAL_CSI2_VC_IRQ_LS_IRQ_2_MASK BIT(18) -#define CAL_CSI2_VC_IRQ_LE_IRQ_2_MASK BIT(19) -#define CAL_CSI2_VC_IRQ_CS_IRQ_2_MASK BIT(20) -#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_2_MASK BIT(21) -#define CAL_CSI2_VC_IRQ_FS_IRQ_3_MASK BIT(24) -#define CAL_CSI2_VC_IRQ_FE_IRQ_3_MASK BIT(25) -#define CAL_CSI2_VC_IRQ_LS_IRQ_3_MASK BIT(26) -#define CAL_CSI2_VC_IRQ_LE_IRQ_3_MASK BIT(27) -#define CAL_CSI2_VC_IRQ_CS_IRQ_3_MASK BIT(28) -#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_3_MASK BIT(29) +#define CAL_CSI2_VC_IRQ_FS_IRQ_MASK(n) BIT(0 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_FE_IRQ_MASK(n) BIT(1 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_LS_IRQ_MASK(n) BIT(2 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_LE_IRQ_MASK(n) BIT(3 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_CS_IRQ_MASK(n) BIT(4 + ((n) * 8)) +#define CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(n) BIT(5 + ((n) * 8)) #define CAL_CSI2_CTX_DT_MASK GENMASK(5, 0) #define CAL_CSI2_CTX_VC_MASK GENMASK(7, 6) From 3b1fe1abbba2869239e0f55f9616624b7d99ab52 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:24 +0200 Subject: [PATCH 036/195] media: ti-vpe: cal: catch VC errors CAL driver currently ignores VC related errors. To help catch error conditions, enable all the VC error interrupts and handle them in the interrupt handler by printing an error. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 25 ++++++++++++++++---- drivers/media/platform/ti-vpe/cal.c | 10 ++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index 3bc63a5e93177..b36e55b63718e 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -226,24 +226,41 @@ static void cal_camerarx_enable_irqs(struct cal_camerarx *phy) CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK | CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK | CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK; - - /* Enable CIO error IRQs. */ + const u32 vc_err_mask = + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(0) | + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(1) | + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(2) | + CAL_CSI2_VC_IRQ_CS_IRQ_MASK(3) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(0) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(1) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(2) | + CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(3); + + /* Enable CIO & VC error IRQs. */ cal_write(phy->cal, CAL_HL_IRQENABLE_SET(0), - CAL_HL_IRQ_CIO_MASK(phy->instance)); + CAL_HL_IRQ_CIO_MASK(phy->instance) | + CAL_HL_IRQ_VC_MASK(phy->instance)); cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), cio_err_mask); + cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), + vc_err_mask); } static void cal_camerarx_disable_irqs(struct cal_camerarx *phy) { /* Disable CIO error irqs */ cal_write(phy->cal, CAL_HL_IRQENABLE_CLR(0), - CAL_HL_IRQ_CIO_MASK(phy->instance)); + CAL_HL_IRQ_CIO_MASK(phy->instance) | + CAL_HL_IRQ_VC_MASK(phy->instance)); cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), 0); + cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), 0); } static void cal_camerarx_ppi_enable(struct cal_camerarx *phy) { + cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), + 1, CAL_CSI2_PPI_CTRL_ECC_EN_MASK); + cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance), 1, CAL_CSI2_PPI_CTRL_IF_EN_MASK); } diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 673952b3e3826..df48a8912a943 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -576,6 +576,16 @@ static irqreturn_t cal_irq(int irq_cal, void *data) cal_write(cal, CAL_CSI2_COMPLEXIO_IRQSTATUS(i), cio_stat); } + + if (status & CAL_HL_IRQ_VC_MASK(i)) { + u32 vc_stat = cal_read(cal, CAL_CSI2_VC_IRQSTATUS(i)); + + dev_err_ratelimited(cal->dev, + "CIO%u VC error: %#08x\n", + i, vc_stat); + + cal_write(cal, CAL_CSI2_VC_IRQSTATUS(i), vc_stat); + } } } From af981fc2e6ca2a8a59ed967e50c8b5875e36fa68 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:25 +0200 Subject: [PATCH 037/195] media: ti-vpe: cal: remove wait when stopping camerarx Asserting ComplexIO reset seems to affect the HW (ie. asserting reset will break an active capture), but the RESET_DONE bit never changes to "reset is ongoing" state. Thus we always get a timeout. Drop the wait, as it seems to achieve nothing. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index b36e55b63718e..a8cca30f3f51e 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -407,7 +407,6 @@ static int cal_camerarx_start(struct cal_camerarx *phy) static void cal_camerarx_stop(struct cal_camerarx *phy) { - unsigned int i; int ret; cal_camerarx_ppi_disable(phy); @@ -421,19 +420,9 @@ static void cal_camerarx_stop(struct cal_camerarx *phy) CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL, CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK); - /* Wait for power down completion */ - for (i = 0; i < 10; i++) { - if (cal_read_field(phy->cal, - CAL_CSI2_COMPLEXIO_CFG(phy->instance), - CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) == - CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING) - break; - usleep_range(1000, 1100); - } - phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset (%d) %s\n", + phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset\n", phy->instance, - cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)), i, - (i >= 10) ? "(timeout)" : ""); + cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance))); /* Disable the phy */ cal_camerarx_disable(phy); From 38f7435f13049fb9f721fbed30d2ca3c3ddfbd6a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:26 +0200 Subject: [PATCH 038/195] media: ti-vpe: cal: disable csi2 ctx and pix proc at ctx_stop Disable CSI2 context and pix proc in cal_ctx_stop() to ensure they are not used if the same context is used later on a different PHY or without pix proc. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index df48a8912a943..531cfe3ab6c7b 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -483,6 +483,12 @@ void cal_ctx_stop(struct cal_ctx *ctx) CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); ctx->dma.state = CAL_DMA_STOPPED; + + /* Disable CSI2 context */ + cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), 0); + + /* Disable pix proc */ + cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), 0); } /* ------------------------------------------------------------------ From 4cb3a0f3896d9ad1d19efb25fd00a58ae6667a95 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:27 +0200 Subject: [PATCH 039/195] media: ti-vpe: cal: allocate pix proc dynamically CAL has 4 pixel processing units but the units are not needed e.g. for metadata. As we could be capturing 4 pixel streams and 4 metadata streams, i.e. using 8 DMA contexts, we cannot assign a pixel processing unit to every DMA context. Instead we need to reserve a pixel processing unit only when needed. Add functions to reserve and release a pix proc unit, and use them in cal_ctx_prepare/unprepare. Note that for the time being we still always reserve a pix proc unit. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 43 ++++++++++++++++++++++++++++- drivers/media/platform/ti-vpe/cal.h | 2 ++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 531cfe3ab6c7b..92240dfa7b784 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -290,6 +290,37 @@ void cal_quickdump_regs(struct cal_dev *cal) * ------------------------------------------------------------------ */ +#define CAL_MAX_PIX_PROC 4 + +static int cal_reserve_pix_proc(struct cal_dev *cal) +{ + unsigned long ret; + + spin_lock(&cal->v4l2_dev.lock); + + ret = find_first_zero_bit(&cal->reserved_pix_proc_mask, CAL_MAX_PIX_PROC); + + if (ret == CAL_MAX_PIX_PROC) { + spin_unlock(&cal->v4l2_dev.lock); + return -ENOSPC; + } + + cal->reserved_pix_proc_mask |= BIT(ret); + + spin_unlock(&cal->v4l2_dev.lock); + + return ret; +} + +static void cal_release_pix_proc(struct cal_dev *cal, unsigned int pix_proc_num) +{ + spin_lock(&cal->v4l2_dev.lock); + + cal->reserved_pix_proc_mask &= ~BIT(pix_proc_num); + + spin_unlock(&cal->v4l2_dev.lock); +} + static void cal_ctx_csi2_config(struct cal_ctx *ctx) { u32 val; @@ -433,11 +464,22 @@ static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx) int cal_ctx_prepare(struct cal_ctx *ctx) { + int ret; + + ret = cal_reserve_pix_proc(ctx->cal); + if (ret < 0) { + ctx_err(ctx, "Failed to reserve pix proc: %d\n", ret); + return ret; + } + + ctx->pix_proc = ret; + return 0; } void cal_ctx_unprepare(struct cal_ctx *ctx) { + cal_release_pix_proc(ctx->cal, ctx->pix_proc); } void cal_ctx_start(struct cal_ctx *ctx) @@ -872,7 +914,6 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) ctx->dma_ctx = inst; ctx->csi2_ctx = inst; ctx->cport = inst; - ctx->pix_proc = inst; ret = cal_ctx_v4l2_init(ctx); if (ret) diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index e4db2a905f687..5d8b3193be7da 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -188,6 +188,8 @@ struct cal_dev { struct media_device mdev; struct v4l2_device v4l2_dev; struct v4l2_async_notifier notifier; + + unsigned long reserved_pix_proc_mask; }; /* From 8927a9f642fd999df0f4e489ee5e52430358b725 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:28 +0200 Subject: [PATCH 040/195] media: ti-vpe: cal: add 'use_pix_proc' field We already have functions to reserve and release a pix proc unit, but we always reserve such and the code expects the pix proc unit to be used. Add a new field, 'use_pix_proc', to indicate if the pix prox unit has been reserved and should be used. Use the flag to skip programming pix proc unit when not needed. Note that we still always set the use_pix_proc flag to true. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 10 +++++++--- drivers/media/platform/ti-vpe/cal.h | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 92240dfa7b784..fdfa5ada64ebc 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -473,13 +473,15 @@ int cal_ctx_prepare(struct cal_ctx *ctx) } ctx->pix_proc = ret; + ctx->use_pix_proc = true; return 0; } void cal_ctx_unprepare(struct cal_ctx *ctx) { - cal_release_pix_proc(ctx->cal, ctx->pix_proc); + if (ctx->use_pix_proc) + cal_release_pix_proc(ctx->cal, ctx->pix_proc); } void cal_ctx_start(struct cal_ctx *ctx) @@ -489,7 +491,8 @@ void cal_ctx_start(struct cal_ctx *ctx) /* Configure the CSI-2, pixel processing and write DMA contexts. */ cal_ctx_csi2_config(ctx); - cal_ctx_pix_proc_config(ctx); + if (ctx->use_pix_proc) + cal_ctx_pix_proc_config(ctx); cal_ctx_wr_dma_config(ctx); /* Enable IRQ_WDMA_END and IRQ_WDMA_START. */ @@ -530,7 +533,8 @@ void cal_ctx_stop(struct cal_ctx *ctx) cal_write(ctx->cal, CAL_CSI2_CTX(ctx->phy->instance, ctx->csi2_ctx), 0); /* Disable pix proc */ - cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), 0); + if (ctx->use_pix_proc) + cal_write(ctx->cal, CAL_PIX_PROC(ctx->pix_proc), 0); } /* ------------------------------------------------------------------ diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index 5d8b3193be7da..d7cc399f47dae 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -223,6 +223,8 @@ struct cal_ctx { u8 cport; u8 csi2_ctx; u8 pix_proc; + + bool use_pix_proc; }; extern unsigned int cal_debug; From 1a7adfda349e9211b816928eecd5246e44f2f74d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:29 +0200 Subject: [PATCH 041/195] media: ti-vpe: cal: add cal_ctx_wr_dma_enable and fix a race I have not noticed any errors due to this, but the DMA configuration looks racy. Setting the DMA mode bitfield in CAL_WR_DMA_CTRL supposedly enables the DMA. However, the driver currently a) continues configuring the DMA after setting the mode, and b) enables the DMA interrupts only after setting the mode. This probably doesn't cause any issues as there should be no data coming in to the DMA yet, but it's still better to fix this. Add a new function, cal_ctx_wr_dma_enable(), to set the DMA mode field, and call that function only after the DMA config and the irq enabling has been done. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index fdfa5ada64ebc..cd8ec04134639 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -409,8 +409,6 @@ static void cal_ctx_wr_dma_config(struct cal_ctx *ctx) CAL_WR_DMA_CTRL_YSIZE_MASK); cal_set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT, CAL_WR_DMA_CTRL_DTAG_MASK); - cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, - CAL_WR_DMA_CTRL_MODE_MASK); cal_set_field(&val, CAL_WR_DMA_CTRL_PATTERN_LINEAR, CAL_WR_DMA_CTRL_PATTERN_MASK); cal_set_field(&val, 1, CAL_WR_DMA_CTRL_STALL_RD_MASK); @@ -442,6 +440,15 @@ void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr) cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->dma_ctx), addr); } +static void cal_ctx_wr_dma_enable(struct cal_ctx *ctx) +{ + u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); + + cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST, + CAL_WR_DMA_CTRL_MODE_MASK); + cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx), val); +} + static void cal_ctx_wr_dma_disable(struct cal_ctx *ctx) { u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->dma_ctx)); @@ -500,6 +507,8 @@ void cal_ctx_start(struct cal_ctx *ctx) CAL_HL_IRQ_WDMA_END_MASK(ctx->dma_ctx)); cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(2), CAL_HL_IRQ_WDMA_START_MASK(ctx->dma_ctx)); + + cal_ctx_wr_dma_enable(ctx); } void cal_ctx_stop(struct cal_ctx *ctx) From 7d167e68d8c790ed8afafd772c3fe77e8aeb55bd Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:30 +0200 Subject: [PATCH 042/195] media: ti-vpe: cal: add vc and datatype fields to cal_ctx In preparation for supporting multiple virtual channels and datatypes, add vc and datatype fields to cal_ctx, initialize them to the currently used values, and use those fields when writing to the register. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 6 ++++-- drivers/media/platform/ti-vpe/cal.h | 2 ++ drivers/media/platform/ti-vpe/cal_regs.h | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index cd8ec04134639..2d05fb3993d8a 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -335,8 +335,8 @@ static void cal_ctx_csi2_config(struct cal_ctx *ctx) * 0x2A: RAW8 1 pixel = 1 byte * 0x1E: YUV422 2 pixels = 4 bytes */ - cal_set_field(&val, 0x1, CAL_CSI2_CTX_DT_MASK); - cal_set_field(&val, 0, CAL_CSI2_CTX_VC_MASK); + cal_set_field(&val, ctx->datatype, CAL_CSI2_CTX_DT_MASK); + cal_set_field(&val, ctx->vc, CAL_CSI2_CTX_VC_MASK); cal_set_field(&val, ctx->v_fmt.fmt.pix.height, CAL_CSI2_CTX_LINES_MASK); cal_set_field(&val, CAL_CSI2_CTX_ATT_PIX, CAL_CSI2_CTX_ATT_MASK); cal_set_field(&val, CAL_CSI2_CTX_PACK_MODE_LINE, @@ -927,6 +927,8 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) ctx->dma_ctx = inst; ctx->csi2_ctx = inst; ctx->cport = inst; + ctx->vc = 0; + ctx->datatype = CAL_CSI2_CTX_DT_ANY; ret = cal_ctx_v4l2_init(ctx); if (ret) diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index d7cc399f47dae..def0c9a3657d3 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -223,6 +223,8 @@ struct cal_ctx { u8 cport; u8 csi2_ctx; u8 pix_proc; + u8 vc; + u8 datatype; bool use_pix_proc; }; diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h index 7eeceeeb303ec..40e4f972fcb74 100644 --- a/drivers/media/platform/ti-vpe/cal_regs.h +++ b/drivers/media/platform/ti-vpe/cal_regs.h @@ -414,6 +414,8 @@ #define CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(n) BIT(5 + ((n) * 8)) #define CAL_CSI2_CTX_DT_MASK GENMASK(5, 0) +#define CAL_CSI2_CTX_DT_DISABLED 0 +#define CAL_CSI2_CTX_DT_ANY 1 #define CAL_CSI2_CTX_VC_MASK GENMASK(7, 6) #define CAL_CSI2_CTX_CPORT_MASK GENMASK(12, 8) #define CAL_CSI2_CTX_ATT_MASK BIT(13) From a6c9aad96508d31732cba7f0855a7f21ddf65eae Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:31 +0200 Subject: [PATCH 043/195] media: ti-vpe: cal: handle cal_ctx_v4l2_register error cal_async_notifier_complete() doesn't handle errors returned from cal_ctx_v4l2_register(). Add the error handling. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 2d05fb3993d8a..3a836813eda85 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -740,15 +740,33 @@ static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier) { struct cal_dev *cal = container_of(notifier, struct cal_dev, notifier); unsigned int i; - int ret = 0; + int ret; for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (cal->ctx[i]) - cal_ctx_v4l2_register(cal->ctx[i]); + if (!cal->ctx[i]) + continue; + + ret = cal_ctx_v4l2_register(cal->ctx[i]); + if (ret) + goto err_ctx_unreg; } - if (cal_mc_api) - ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev); + if (!cal_mc_api) + return 0; + + ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev); + if (ret) + goto err_ctx_unreg; + + return 0; + +err_ctx_unreg: + for (; i > 0; --i) { + if (!cal->ctx[i - 1]) + continue; + + cal_ctx_v4l2_unregister(cal->ctx[i - 1]); + } return ret; } From 37fa1d2a5c0502b97172e297eae06917b98d1f70 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:32 +0200 Subject: [PATCH 044/195] media: ti-vpe: cal: set field always to V4L2_FIELD_NONE cal_camerarx_sd_set_fmt() accepts any value for the format field, but there should be no reason to have any other value accepted than V4L2_FIELD_NONE. So set the field always to V4L2_FIELD_NONE. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index a8cca30f3f51e..f2ea2bdb9ea33 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -705,10 +705,7 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, if (!fmtinfo) fmtinfo = &cal_formats[0]; - /* - * Clamp the size, update the code. The field and colorspace are - * accepted as-is. - */ + /* Clamp the size, update the code. The colorspace is accepted as-is. */ bpp = ALIGN(fmtinfo->bpp, 8); format->format.width = clamp_t(unsigned int, format->format.width, @@ -718,6 +715,7 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, CAL_MIN_HEIGHT_LINES, CAL_MAX_HEIGHT_LINES); format->format.code = fmtinfo->code; + format->format.field = V4L2_FIELD_NONE; /* Store the format and propagate it to the source pad. */ fmt = cal_camerarx_get_pad_format(phy, sd_state, From d3409a65735e617c425dcbcb7ba312d894547152 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:33 +0200 Subject: [PATCH 045/195] media: ti-vpe: cal: fix typo in a comment Fix a typo in a comment in cal_camerarx_sd_set_fmt(). Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index f2ea2bdb9ea33..7940e47964af6 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -698,7 +698,7 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, return cal_camerarx_sd_get_fmt(sd, sd_state, format); /* - * Default to the first format is the requested media bus code isn't + * Default to the first format if the requested media bus code isn't * supported. */ fmtinfo = cal_format_by_code(format->format.code); From 7f9f8123212d090a89a0e3db794a684bbf3a6b1d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:34 +0200 Subject: [PATCH 046/195] media: ti-vpe: cal: add mbus_code support to cal_mc_enum_fmt_vid_cap Commit e5b6b07a1b45 ("media: v4l2: Extend VIDIOC_ENUM_FMT to support MC-centric devices") added support to enumerate formats based on mbus-code. Add this feature to cal driver. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-video.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index cdbfdca8570fa..1099ef4ae9681 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -437,13 +437,28 @@ static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { static int cal_mc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { + unsigned int i; + unsigned int idx; + if (f->index >= cal_num_formats) return -EINVAL; - f->pixelformat = cal_formats[f->index].fourcc; - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + idx = 0; - return 0; + for (i = 0; i < cal_num_formats; ++i) { + if (f->mbus_code && cal_formats[i].code != f->mbus_code) + continue; + + if (idx == f->index) { + f->pixelformat = cal_formats[i].fourcc; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; + } + + idx++; + } + + return -EINVAL; } static void cal_mc_try_fmt(struct cal_ctx *ctx, struct v4l2_format *f, From e6a800d63a1239887dfe1b19d10b69ab7ff85f9a Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:35 +0200 Subject: [PATCH 047/195] media: ti-vpe: cal: rename non-MC funcs to cal_legacy_* To make it more obvious if the function in question is dealing with media-controller API or the legacy API, rename legacy API functions to cal_legacy_*. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-video.c | 58 +++++++++++------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index 1099ef4ae9681..fb50b1acd24c7 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -102,8 +102,8 @@ static const struct cal_format_info *find_format_by_code(struct cal_ctx *ctx, return NULL; } -static int cal_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int cal_legacy_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct cal_ctx *ctx = video_drvdata(file); const struct cal_format_info *fmtinfo; @@ -189,8 +189,8 @@ static void cal_calc_format_size(struct cal_ctx *ctx, f->fmt.pix.bytesperline, f->fmt.pix.sizeimage); } -static int cal_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct cal_ctx *ctx = video_drvdata(file); const struct cal_format_info *fmtinfo; @@ -249,8 +249,8 @@ static int cal_try_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int cal_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) { struct cal_ctx *ctx = video_drvdata(file); struct vb2_queue *q = &ctx->vb_vidq; @@ -266,7 +266,7 @@ static int cal_s_fmt_vid_cap(struct file *file, void *priv, return -EBUSY; } - ret = cal_try_fmt_vid_cap(file, priv, f); + ret = cal_legacy_try_fmt_vid_cap(file, priv, f); if (ret < 0) return ret; @@ -300,8 +300,8 @@ static int cal_s_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int cal_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) +static int cal_legacy_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) { struct cal_ctx *ctx = video_drvdata(file); const struct cal_format_info *fmtinfo; @@ -337,8 +337,8 @@ static int cal_enum_framesizes(struct file *file, void *fh, return 0; } -static int cal_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) +static int cal_legacy_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) { if (inp->index > 0) return -EINVAL; @@ -348,20 +348,20 @@ static int cal_enum_input(struct file *file, void *priv, return 0; } -static int cal_g_input(struct file *file, void *priv, unsigned int *i) +static int cal_legacy_g_input(struct file *file, void *priv, unsigned int *i) { *i = 0; return 0; } -static int cal_s_input(struct file *file, void *priv, unsigned int i) +static int cal_legacy_s_input(struct file *file, void *priv, unsigned int i) { return i > 0 ? -EINVAL : 0; } /* timeperframe is arbitrary and continuous */ -static int cal_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fival) +static int cal_legacy_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *fival) { struct cal_ctx *ctx = video_drvdata(file); const struct cal_format_info *fmtinfo; @@ -388,27 +388,27 @@ static int cal_enum_frameintervals(struct file *file, void *priv, return 0; } -static int cal_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +static int cal_legacy_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct cal_ctx *ctx = video_drvdata(file); return v4l2_g_parm_cap(video_devdata(file), ctx->phy->source, a); } -static int cal_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +static int cal_legacy_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct cal_ctx *ctx = video_drvdata(file); return v4l2_s_parm_cap(video_devdata(file), ctx->phy->source, a); } -static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { +static const struct v4l2_ioctl_ops cal_ioctl_legacy_ops = { .vidioc_querycap = cal_querycap, - .vidioc_enum_fmt_vid_cap = cal_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = cal_legacy_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = cal_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = cal_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = cal_s_fmt_vid_cap, - .vidioc_enum_framesizes = cal_enum_framesizes, + .vidioc_try_fmt_vid_cap = cal_legacy_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cal_legacy_s_fmt_vid_cap, + .vidioc_enum_framesizes = cal_legacy_enum_framesizes, .vidioc_reqbufs = vb2_ioctl_reqbufs, .vidioc_create_bufs = vb2_ioctl_create_bufs, .vidioc_prepare_buf = vb2_ioctl_prepare_buf, @@ -416,17 +416,17 @@ static const struct v4l2_ioctl_ops cal_ioctl_video_ops = { .vidioc_qbuf = vb2_ioctl_qbuf, .vidioc_dqbuf = vb2_ioctl_dqbuf, .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_enum_input = cal_enum_input, - .vidioc_g_input = cal_g_input, - .vidioc_s_input = cal_s_input, - .vidioc_enum_frameintervals = cal_enum_frameintervals, + .vidioc_enum_input = cal_legacy_enum_input, + .vidioc_g_input = cal_legacy_g_input, + .vidioc_s_input = cal_legacy_s_input, + .vidioc_enum_frameintervals = cal_legacy_enum_frameintervals, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_log_status = v4l2_ctrl_log_status, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - .vidioc_g_parm = cal_g_parm, - .vidioc_s_parm = cal_s_parm, + .vidioc_g_parm = cal_legacy_g_parm, + .vidioc_s_parm = cal_legacy_s_parm, }; /* ------------------------------------------------------------------ @@ -968,7 +968,7 @@ int cal_ctx_v4l2_init(struct cal_ctx *ctx) vfd->queue = q; snprintf(vfd->name, sizeof(vfd->name), "CAL output %u", ctx->dma_ctx); vfd->release = video_device_release_empty; - vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_video_ops; + vfd->ioctl_ops = cal_mc_api ? &cal_ioctl_mc_ops : &cal_ioctl_legacy_ops; vfd->lock = &ctx->mutex; video_set_drvdata(vfd, ctx); From 8bfd1af2fdd193017c1bdbae7c3f5aab027e5282 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:36 +0200 Subject: [PATCH 048/195] media: ti-vpe: cal: init ctx->v_fmt correctly in MC mode CAL driver enumerates mbus codes in the connected subdev to create a list of supported formats reported to userspace, and initializes ctx->v_fmt and ctx->fmtinfo to one of those formats. This works fine for legacy mode, but is not correct for MC mode, and the list is not even used in MC mode. Fix this by adding a new function, cal_ctx_v4l2_init_mc_format, which only initializes ctx->v_fmt and ctx->fmtinfo to a default value. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-video.c | 43 ++++++++++++++++++++--- drivers/media/platform/ti-vpe/cal.h | 2 +- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index fb50b1acd24c7..b53191425cc46 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -881,24 +881,59 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx) return 0; } +static int cal_ctx_v4l2_init_mc_format(struct cal_ctx *ctx) +{ + const struct cal_format_info *fmtinfo; + struct v4l2_pix_format *pix_fmt = &ctx->v_fmt.fmt.pix; + + fmtinfo = cal_format_by_code(MEDIA_BUS_FMT_UYVY8_2X8); + if (!fmtinfo) + return -EINVAL; + + pix_fmt->width = 640; + pix_fmt->height = 480; + pix_fmt->field = V4L2_FIELD_NONE; + pix_fmt->colorspace = V4L2_COLORSPACE_SRGB; + pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; + pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; + pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; + pix_fmt->pixelformat = fmtinfo->fourcc; + + ctx->v_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + /* Save current format */ + cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt); + ctx->fmtinfo = fmtinfo; + + return 0; +} + int cal_ctx_v4l2_register(struct cal_ctx *ctx) { struct video_device *vfd = &ctx->vdev; int ret; - ret = cal_ctx_v4l2_init_formats(ctx); - if (ret) - return ret; - if (!cal_mc_api) { struct v4l2_ctrl_handler *hdl = &ctx->ctrl_handler; + ret = cal_ctx_v4l2_init_formats(ctx); + if (ret) { + ctx_err(ctx, "Failed to init formats: %d\n", ret); + return ret; + } + ret = v4l2_ctrl_add_handler(hdl, ctx->phy->source->ctrl_handler, NULL, true); if (ret < 0) { ctx_err(ctx, "Failed to add source ctrl handler\n"); return ret; } + } else { + ret = cal_ctx_v4l2_init_mc_format(ctx); + if (ret) { + ctx_err(ctx, "Failed to init format: %d\n", ret); + return ret; + } } ret = video_register_device(vfd, VFL_TYPE_VIDEO, cal_video_nr); diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index def0c9a3657d3..ee42c9c48fa1e 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -213,7 +213,7 @@ struct cal_ctx { /* Used to store current pixel format */ struct v4l2_format v_fmt; - /* Current subdev enumerated format */ + /* Current subdev enumerated format (legacy) */ const struct cal_format_info **active_fmt; unsigned int num_active_fmt; From 2e7e09a902c6e4121a91a2f9d597228474cabe4c Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:37 +0200 Subject: [PATCH 049/195] media: ti-vpe: cal: remove cal_camerarx->fmtinfo struct cal_camerarx has fmtinfo field which is used to point to the current active input format. The only place where the field is used is cal_camerarx_get_ext_link_freq(). With multiple streams the whole concept of single input format is not valid anymore, so lets remove the field by looking up the format in cal_camerarx_get_ext_link_freq(), making it easier to handle the multistream-case in the following patches. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 12 ++++++++---- drivers/media/platform/ti-vpe/cal.h | 1 - 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index 7940e47964af6..82392499e6634 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -49,9 +49,16 @@ static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy) { struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2; u32 num_lanes = mipi_csi2->num_data_lanes; - u32 bpp = phy->fmtinfo->bpp; + const struct cal_format_info *fmtinfo; + u32 bpp; s64 freq; + fmtinfo = cal_format_by_code(phy->formats[CAL_CAMERARX_PAD_SINK].code); + if (!fmtinfo) + return -EINVAL; + + bpp = fmtinfo->bpp; + freq = v4l2_get_link_freq(phy->source->ctrl_handler, bpp, 2 * num_lanes); if (freq < 0) { phy_err(phy, "failed to get link freq for subdev '%s'\n", @@ -728,9 +735,6 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, format->which); *fmt = format->format; - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - phy->fmtinfo = fmtinfo; - return 0; } diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index ee42c9c48fa1e..7d9a2d697fc4f 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -163,7 +163,6 @@ struct cal_camerarx { struct v4l2_subdev subdev; struct media_pad pads[2]; struct v4l2_mbus_framefmt formats[2]; - const struct cal_format_info *fmtinfo; }; struct cal_dev { From 75e7e58bfac11714159049c7f8c01f57cf7f39f2 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:38 +0200 Subject: [PATCH 050/195] media: ti-vpe: cal: support 8 DMA contexts The current driver only ever needs 2 DMA contexts (one per PHY), but we need to use more of the 8 contexts to add support for multiple streams. Change the code so that we allocate DMA contexts as needed, which at this time is 1 per PHY, but could be up to 8. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 31 ++++++++++------------------- drivers/media/platform/ti-vpe/cal.h | 5 +++-- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 3a836813eda85..ec8ffc8d5721d 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -658,7 +658,7 @@ static irqreturn_t cal_irq(int irq_cal, void *data) /* Clear Interrupt status */ cal_write(cal, CAL_HL_IRQSTATUS(1), status); - for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { + for (i = 0; i < cal->num_contexts; ++i) { if (status & CAL_HL_IRQ_WDMA_END_MASK(i)) cal_irq_wdma_end(cal->ctx[i]); } @@ -672,7 +672,7 @@ static irqreturn_t cal_irq(int irq_cal, void *data) /* Clear Interrupt status */ cal_write(cal, CAL_HL_IRQSTATUS(2), status); - for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { + for (i = 0; i < cal->num_contexts; ++i) { if (status & CAL_HL_IRQ_WDMA_START_MASK(i)) cal_irq_wdma_start(cal->ctx[i]); } @@ -742,10 +742,7 @@ static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier) unsigned int i; int ret; - for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) { - if (!cal->ctx[i]) - continue; - + for (i = 0; i < cal->num_contexts; ++i) { ret = cal_ctx_v4l2_register(cal->ctx[i]); if (ret) goto err_ctx_unreg; @@ -865,10 +862,8 @@ static void cal_media_unregister(struct cal_dev *cal) unsigned int i; /* Unregister all the V4L2 video devices. */ - for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { - if (cal->ctx[i]) - cal_ctx_v4l2_unregister(cal->ctx[i]); - } + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_v4l2_unregister(cal->ctx[i]); cal_async_notifier_unregister(cal); media_device_unregister(&cal->mdev); @@ -915,10 +910,8 @@ static void cal_media_cleanup(struct cal_dev *cal) { unsigned int i; - for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { - if (cal->ctx[i]) - cal_ctx_v4l2_cleanup(cal->ctx[i]); - } + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_v4l2_cleanup(cal->ctx[i]); v4l2_device_unregister(&cal->v4l2_dev); media_device_cleanup(&cal->mdev); @@ -1067,7 +1060,6 @@ static int cal_init_camerarx_regmap(struct cal_dev *cal) static int cal_probe(struct platform_device *pdev) { struct cal_dev *cal; - struct cal_ctx *ctx; bool connected = false; unsigned int i; int ret; @@ -1157,6 +1149,8 @@ static int cal_probe(struct platform_device *pdev) ret = -ENODEV; goto error_context; } + + cal->num_contexts++; } /* Register the media device. */ @@ -1167,11 +1161,8 @@ static int cal_probe(struct platform_device *pdev) return 0; error_context: - for (i = 0; i < ARRAY_SIZE(cal->ctx); i++) { - ctx = cal->ctx[i]; - if (ctx) - cal_ctx_v4l2_cleanup(ctx); - } + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_v4l2_cleanup(cal->ctx[i]); error_camerarx: for (i = 0; i < cal->data->num_csi2_phy; i++) diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index 7d9a2d697fc4f..400f95485d7c8 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -29,7 +29,7 @@ #include #define CAL_MODULE_NAME "cal" -#define CAL_NUM_CONTEXT 2 +#define CAL_MAX_NUM_CONTEXT 8 #define CAL_NUM_CSI2_PORTS 2 /* @@ -182,7 +182,8 @@ struct cal_dev { /* Camera Core Module handle */ struct cal_camerarx *phy[CAL_NUM_CSI2_PORTS]; - struct cal_ctx *ctx[CAL_NUM_CONTEXT]; + u32 num_contexts; + struct cal_ctx *ctx[CAL_MAX_NUM_CONTEXT]; struct media_device mdev; struct v4l2_device v4l2_dev; From b65836f40a748f14f402135a28fa75c6cca3e3fb Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:39 +0200 Subject: [PATCH 051/195] media: ti-vpe: cal: cleanup phy iteration in cal_remove Most of the driver has moved from ARRAY_SIZE(cal->phy) to cal->data->num_csi2_phy, but we have one place left in cal_remove. Also, checking for cal->phy[i] != NULL is not needed as we always have all the phys instantiated. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index ec8ffc8d5721d..9bba07647610d 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1188,10 +1188,8 @@ static int cal_remove(struct platform_device *pdev) cal_media_unregister(cal); - for (i = 0; i < ARRAY_SIZE(cal->phy); i++) { - if (cal->phy[i]) - cal_camerarx_disable(cal->phy[i]); - } + for (i = 0; i < cal->data->num_csi2_phy; i++) + cal_camerarx_disable(cal->phy[i]); cal_media_cleanup(cal); From 9e67f24e4d90858bfec2dbac84d5380db3926bd5 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:40 +0200 Subject: [PATCH 052/195] media: ti-vpe: cal: fix ctx uninitialization Somewhere along the way the context uninitialization has gone a bit odd: * We have cal_ctx_create() but no matching destroy call, but we still need to call cal_ctx_v4l2_cleanup() for each context. * We have cal_media_cleanup() which calls cal_ctx_v4l2_cleanup() for all contexts, but cal_media_init() is not where the contexts are created. * The order of uninit steps in cal_remove() is different than the error handling path in cal_probe(). * cal_probe()'s error handling calls cal_ctx_v4l2_cleanup() for each context, but also calls cal_media_clean(), doing the same context cleanup twice. So fix these, by introducing cal_ctx_destroy(), and using that in appropriate places instead of calling cal_ctx_v4l2_cleanup() in cal_media_clean(). Also use normal kzalloc (and kfree) instead of devm version as we anyway do manual cleanup for each context. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 9bba07647610d..cce627c5519c3 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -908,11 +908,6 @@ static int cal_media_init(struct cal_dev *cal) */ static void cal_media_cleanup(struct cal_dev *cal) { - unsigned int i; - - for (i = 0; i < cal->num_contexts; i++) - cal_ctx_v4l2_cleanup(cal->ctx[i]); - v4l2_device_unregister(&cal->v4l2_dev); media_device_cleanup(&cal->mdev); @@ -929,7 +924,7 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) struct cal_ctx *ctx; int ret; - ctx = devm_kzalloc(cal->dev, sizeof(*ctx), GFP_KERNEL); + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return NULL; @@ -948,6 +943,13 @@ static struct cal_ctx *cal_ctx_create(struct cal_dev *cal, int inst) return ctx; } +static void cal_ctx_destroy(struct cal_ctx *ctx) +{ + cal_ctx_v4l2_cleanup(ctx); + + kfree(ctx); +} + static const struct of_device_id cal_of_match[] = { { .compatible = "ti,dra72-cal", @@ -1162,7 +1164,7 @@ static int cal_probe(struct platform_device *pdev) error_context: for (i = 0; i < cal->num_contexts; i++) - cal_ctx_v4l2_cleanup(cal->ctx[i]); + cal_ctx_destroy(cal->ctx[i]); error_camerarx: for (i = 0; i < cal->data->num_csi2_phy; i++) @@ -1191,11 +1193,14 @@ static int cal_remove(struct platform_device *pdev) for (i = 0; i < cal->data->num_csi2_phy; i++) cal_camerarx_disable(cal->phy[i]); - cal_media_cleanup(cal); + for (i = 0; i < cal->num_contexts; i++) + cal_ctx_destroy(cal->ctx[i]); for (i = 0; i < cal->data->num_csi2_phy; i++) cal_camerarx_destroy(cal->phy[i]); + cal_media_cleanup(cal); + if (ret >= 0) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); From 892c37f8a3d673b945e951a8754695c119a2b1b0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:41 +0200 Subject: [PATCH 053/195] media: ti-vpe: cal: fix queuing of the initial buffer When starting streaming the driver currently programs the buffer address to the CAL base-address register and assigns the buffer pointer to ctx->dma.pending. This is not correct, as the buffer is not "pending", but active, and causes the first buffer to be needlessly written twice. Fix this by assigning the buffer pointer to ctx->dma.active. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index b53191425cc46..6364ccb450738 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -731,7 +731,7 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count) spin_lock_irq(&ctx->dma.lock); buf = list_first_entry(&ctx->dma.queue, struct cal_buffer, list); - ctx->dma.pending = buf; + ctx->dma.active = buf; list_del(&buf->list); spin_unlock_irq(&ctx->dma.lock); From 6cb0eee34c24b0052da554ff2ef9def8a10bbf96 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:42 +0200 Subject: [PATCH 054/195] media: ti-vpe: cal: add camerarx locking We don't have any locking in camerarx for the subdev ops. We have managed fine so far without locking, but in the future multiple video capture devices can use the same camerarx, and locking is a must. Add a mutex to protect the camerarx subdev ops. Some of the functions were slightly restructured to make lock handling cleaner. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 81 ++++++++++++++------ drivers/media/platform/ti-vpe/cal.h | 6 ++ 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index 82392499e6634..f799047c70f75 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -601,12 +601,18 @@ cal_camerarx_get_pad_format(struct cal_camerarx *phy, static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable) { struct cal_camerarx *phy = to_cal_camerarx(sd); + int ret = 0; + + mutex_lock(&phy->mutex); if (enable) - return cal_camerarx_start(phy); + ret = cal_camerarx_start(phy); + else + cal_camerarx_stop(phy); - cal_camerarx_stop(phy); - return 0; + mutex_unlock(&phy->mutex); + + return ret; } static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, @@ -614,27 +620,36 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_mbus_code_enum *code) { struct cal_camerarx *phy = to_cal_camerarx(sd); + int ret = 0; + + mutex_lock(&phy->mutex); /* No transcoding, source and sink codes must match. */ if (code->pad == CAL_CAMERARX_PAD_SOURCE) { struct v4l2_mbus_framefmt *fmt; - if (code->index > 0) - return -EINVAL; + if (code->index > 0) { + ret = -EINVAL; + goto out; + } fmt = cal_camerarx_get_pad_format(phy, sd_state, CAL_CAMERARX_PAD_SINK, code->which); code->code = fmt->code; - return 0; - } + } else { + if (code->index >= cal_num_formats) { + ret = -EINVAL; + goto out; + } - if (code->index >= cal_num_formats) - return -EINVAL; + code->code = cal_formats[code->index].code; + } - code->code = cal_formats[code->index].code; +out: + mutex_unlock(&phy->mutex); - return 0; + return ret; } static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, @@ -643,10 +658,13 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, { struct cal_camerarx *phy = to_cal_camerarx(sd); const struct cal_format_info *fmtinfo; + int ret = 0; if (fse->index > 0) return -EINVAL; + mutex_lock(&phy->mutex); + /* No transcoding, source and sink formats must match. */ if (fse->pad == CAL_CAMERARX_PAD_SOURCE) { struct v4l2_mbus_framefmt *fmt; @@ -654,27 +672,32 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, fmt = cal_camerarx_get_pad_format(phy, sd_state, CAL_CAMERARX_PAD_SINK, fse->which); - if (fse->code != fmt->code) - return -EINVAL; + if (fse->code != fmt->code) { + ret = -EINVAL; + goto out; + } fse->min_width = fmt->width; fse->max_width = fmt->width; fse->min_height = fmt->height; fse->max_height = fmt->height; + } else { + fmtinfo = cal_format_by_code(fse->code); + if (!fmtinfo) { + ret = -EINVAL; + goto out; + } - return 0; + fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); + fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); + fse->min_height = CAL_MIN_HEIGHT_LINES; + fse->max_height = CAL_MAX_HEIGHT_LINES; } - fmtinfo = cal_format_by_code(fse->code); - if (!fmtinfo) - return -EINVAL; - - fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); - fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8); - fse->min_height = CAL_MIN_HEIGHT_LINES; - fse->max_height = CAL_MAX_HEIGHT_LINES; +out: + mutex_unlock(&phy->mutex); - return 0; + return ret; } static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd, @@ -684,10 +707,14 @@ static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd, struct cal_camerarx *phy = to_cal_camerarx(sd); struct v4l2_mbus_framefmt *fmt; + mutex_lock(&phy->mutex); + fmt = cal_camerarx_get_pad_format(phy, sd_state, format->pad, format->which); format->format = *fmt; + mutex_unlock(&phy->mutex); + return 0; } @@ -725,6 +752,9 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, format->format.field = V4L2_FIELD_NONE; /* Store the format and propagate it to the source pad. */ + + mutex_lock(&phy->mutex); + fmt = cal_camerarx_get_pad_format(phy, sd_state, CAL_CAMERARX_PAD_SINK, format->which); @@ -735,6 +765,8 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, format->which); *fmt = format->format; + mutex_unlock(&phy->mutex); + return 0; } @@ -801,6 +833,8 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, phy->cal = cal; phy->instance = instance; + mutex_init(&phy->mutex); + phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, (instance == 0) ? "cal_rx_core0" : @@ -864,5 +898,6 @@ void cal_camerarx_destroy(struct cal_camerarx *phy) media_entity_cleanup(&phy->subdev.entity); of_node_put(phy->source_ep_node); of_node_put(phy->source_node); + mutex_destroy(&phy->mutex); kfree(phy); } diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index 400f95485d7c8..cf0b8f5d43786 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -163,6 +163,12 @@ struct cal_camerarx { struct v4l2_subdev subdev; struct media_pad pads[2]; struct v4l2_mbus_framefmt formats[2]; + + /* + * Lock for camerarx ops. Protects: + * - formats + */ + struct mutex mutex; }; struct cal_dev { From 9eaca40c0d13a21848b5a35dc8c37dc3690a4ff1 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:43 +0200 Subject: [PATCH 055/195] media: ti-vpe: cal: add camerarx enable/disable refcounting The following patches add multistream support and we will have multiple video devices using the same camerarx instances. Thus we need enable/disable refcounting for the camerarx. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 10 ++++++++++ drivers/media/platform/ti-vpe/cal.h | 3 +++ 2 files changed, 13 insertions(+) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index f799047c70f75..79ebad1392895 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -285,6 +285,11 @@ static int cal_camerarx_start(struct cal_camerarx *phy) u32 val; int ret; + if (phy->enable_count > 0) { + phy->enable_count++; + return 0; + } + link_freq = cal_camerarx_get_ext_link_freq(phy); if (link_freq < 0) return link_freq; @@ -409,6 +414,8 @@ static int cal_camerarx_start(struct cal_camerarx *phy) /* Finally, enable the PHY Protocol Interface (PPI). */ cal_camerarx_ppi_enable(phy); + phy->enable_count++; + return 0; } @@ -416,6 +423,9 @@ static void cal_camerarx_stop(struct cal_camerarx *phy) { int ret; + if (--phy->enable_count > 0) + return; + cal_camerarx_ppi_disable(phy); cal_camerarx_disable_irqs(phy); diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index cf0b8f5d43786..006374be3f9f5 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -167,8 +167,11 @@ struct cal_camerarx { /* * Lock for camerarx ops. Protects: * - formats + * - enable_count */ struct mutex mutex; + + unsigned int enable_count; }; struct cal_dev { From 71e3a18114ebdb48482d731d04bff7a222036381 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:44 +0200 Subject: [PATCH 056/195] media: ti-vpe: cal: allow more than 1 source pads CAL RX has a single sink and a single source pad. To support multiple streams, we will have multiple source pads (up to 8, one for each CAL context). Change the driver to allow creating more source pads and change the code accordingly to handle multiple source pads. We still keep CAL_CAMERARX_NUM_SOURCE_PADS as 1, and the behavior is unchanged. Also rename CAL_CAMERARX_PAD_SOURCE to CAL_CAMERARX_PAD_FIRST_SOURCE to highlight that it's the first source. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal-camerarx.c | 12 ++++++----- drivers/media/platform/ti-vpe/cal-video.c | 9 +++++++-- drivers/media/platform/ti-vpe/cal.h | 21 +++++++++++++++++--- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index 79ebad1392895..4bf7a8c2e711f 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -635,7 +635,7 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd, mutex_lock(&phy->mutex); /* No transcoding, source and sink codes must match. */ - if (code->pad == CAL_CAMERARX_PAD_SOURCE) { + if (cal_rx_pad_is_source(code->pad)) { struct v4l2_mbus_framefmt *fmt; if (code->index > 0) { @@ -676,7 +676,7 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd, mutex_lock(&phy->mutex); /* No transcoding, source and sink formats must match. */ - if (fse->pad == CAL_CAMERARX_PAD_SOURCE) { + if (cal_rx_pad_is_source(fse->pad)) { struct v4l2_mbus_framefmt *fmt; fmt = cal_camerarx_get_pad_format(phy, sd_state, @@ -738,7 +738,7 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, unsigned int bpp; /* No transcoding, source and sink formats must match. */ - if (format->pad == CAL_CAMERARX_PAD_SOURCE) + if (cal_rx_pad_is_source(format->pad)) return cal_camerarx_sd_get_fmt(sd, sd_state, format); /* @@ -771,7 +771,7 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd, *fmt = format->format; fmt = cal_camerarx_get_pad_format(phy, sd_state, - CAL_CAMERARX_PAD_SOURCE, + CAL_CAMERARX_PAD_FIRST_SOURCE, format->which); *fmt = format->format; @@ -834,6 +834,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, struct platform_device *pdev = to_platform_device(cal->dev); struct cal_camerarx *phy; struct v4l2_subdev *sd; + unsigned int i; int ret; phy = kzalloc(sizeof(*phy), GFP_KERNEL); @@ -876,7 +877,8 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal, sd->dev = cal->dev; phy->pads[CAL_CAMERARX_PAD_SINK].flags = MEDIA_PAD_FL_SINK; - phy->pads[CAL_CAMERARX_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; + for (i = CAL_CAMERARX_PAD_FIRST_SOURCE; i < CAL_CAMERARX_NUM_PADS; ++i) + phy->pads[i].flags = MEDIA_PAD_FL_SOURCE; sd->entity.ops = &cal_camerarx_media_ops; ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(phy->pads), phy->pads); diff --git a/drivers/media/platform/ti-vpe/cal-video.c b/drivers/media/platform/ti-vpe/cal-video.c index 6364ccb450738..7799da1cc261b 100644 --- a/drivers/media/platform/ti-vpe/cal-video.c +++ b/drivers/media/platform/ti-vpe/cal-video.c @@ -687,8 +687,13 @@ static void cal_release_buffers(struct cal_ctx *ctx, static int cal_video_check_format(struct cal_ctx *ctx) { const struct v4l2_mbus_framefmt *format; + struct media_pad *remote_pad; - format = &ctx->phy->formats[CAL_CAMERARX_PAD_SOURCE]; + remote_pad = media_entity_remote_pad(&ctx->pad); + if (!remote_pad) + return -ENODEV; + + format = &ctx->phy->formats[remote_pad->index]; if (ctx->fmtinfo->code != format->code || ctx->v_fmt.fmt.pix.height != format->height || @@ -943,7 +948,7 @@ int cal_ctx_v4l2_register(struct cal_ctx *ctx) } ret = media_create_pad_link(&ctx->phy->subdev.entity, - CAL_CAMERARX_PAD_SOURCE, + CAL_CAMERARX_PAD_FIRST_SOURCE, &vfd->entity, 0, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index 006374be3f9f5..d3e89d2ee10fb 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -44,7 +44,22 @@ #define CAL_MAX_HEIGHT_LINES 16383 #define CAL_CAMERARX_PAD_SINK 0 -#define CAL_CAMERARX_PAD_SOURCE 1 +#define CAL_CAMERARX_PAD_FIRST_SOURCE 1 +#define CAL_CAMERARX_NUM_SOURCE_PADS 1 +#define CAL_CAMERARX_NUM_PADS (1 + CAL_CAMERARX_NUM_SOURCE_PADS) + +static inline bool cal_rx_pad_is_sink(u32 pad) +{ + /* Camera RX has 1 sink pad, and N source pads */ + return pad == 0; +} + +static inline bool cal_rx_pad_is_source(u32 pad) +{ + /* Camera RX has 1 sink pad, and N source pads */ + return pad >= CAL_CAMERARX_PAD_FIRST_SOURCE && + pad <= CAL_CAMERARX_NUM_SOURCE_PADS; +} struct device; struct device_node; @@ -161,8 +176,8 @@ struct cal_camerarx { struct media_pipeline pipe; struct v4l2_subdev subdev; - struct media_pad pads[2]; - struct v4l2_mbus_framefmt formats[2]; + struct media_pad pads[CAL_CAMERARX_NUM_PADS]; + struct v4l2_mbus_framefmt formats[CAL_CAMERARX_NUM_PADS]; /* * Lock for camerarx ops. Protects: From f4a87d54c5895a822b4b8ef518dd4f115e30a604 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 14 Jun 2021 13:23:45 +0200 Subject: [PATCH 057/195] media: ti-vpe: cal: add embedded data support Add support for capturing embedded data from the sensor. The only difference with capturing pixel data and embedded data is that we need to ensure the PIX PROC is disabled for embedded data so that CAL doesn't repack the data. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 17 ++++++++++------- drivers/media/platform/ti-vpe/cal.h | 1 + 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index cce627c5519c3..05bdc6d126d82 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -473,14 +473,17 @@ int cal_ctx_prepare(struct cal_ctx *ctx) { int ret; - ret = cal_reserve_pix_proc(ctx->cal); - if (ret < 0) { - ctx_err(ctx, "Failed to reserve pix proc: %d\n", ret); - return ret; - } + ctx->use_pix_proc = !ctx->fmtinfo->meta; - ctx->pix_proc = ret; - ctx->use_pix_proc = true; + if (ctx->use_pix_proc) { + ret = cal_reserve_pix_proc(ctx->cal); + if (ret < 0) { + ctx_err(ctx, "Failed to reserve pix proc: %d\n", ret); + return ret; + } + + ctx->pix_proc = ret; + } return 0; } diff --git a/drivers/media/platform/ti-vpe/cal.h b/drivers/media/platform/ti-vpe/cal.h index d3e89d2ee10fb..527e22d022f30 100644 --- a/drivers/media/platform/ti-vpe/cal.h +++ b/drivers/media/platform/ti-vpe/cal.h @@ -88,6 +88,7 @@ struct cal_format_info { u32 code; /* Bits per pixel */ u8 bpp; + bool meta; }; /* buffer for one video frame */ From e5dd86446fe3ed91b696bb4eced78631f7c7a7d4 Mon Sep 17 00:00:00 2001 From: lijian Date: Thu, 10 Jun 2021 05:15:04 +0200 Subject: [PATCH 058/195] media: rc: streamzap: Removed unnecessary 'return' Removed unnecessary 'return'. Signed-off-by: lijian Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/streamzap.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 9f3cd9fb6b6e1..9cd765e31c490 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -265,8 +265,6 @@ static void streamzap_callback(struct urb *urb) ir_raw_event_handle(sz->rdev); usb_submit_urb(urb, GFP_ATOMIC); - - return; } static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) From adb08a09230b8e7337dc162815288a189e9ee30f Mon Sep 17 00:00:00 2001 From: lijian Date: Thu, 10 Jun 2021 05:24:13 +0200 Subject: [PATCH 059/195] media: rc: redrat3: Fix a typo Change 'an' to 'on'. Signed-off-by: lijian Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 2cf3377ec63a7..ac85464864b9d 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -6,7 +6,7 @@ * based heavily on the work of Stephen Cox, with additional * help from RedRat Ltd. * - * This driver began life based an an old version of the first-generation + * This driver began life based on an old version of the first-generation * lirc_mceusb driver from the lirc 0.7.2 distribution. It was then * significantly rewritten by Stephen Cox with the aid of RedRat Ltd's * Chris Dodge. From 86541f0480b574cf299563156ac22ebf266ea5ec Mon Sep 17 00:00:00 2001 From: lijian Date: Thu, 10 Jun 2021 11:27:25 +0200 Subject: [PATCH 060/195] media: rc: rc-main.c: deleted the repeated word deleted the repeated word 'the' in the comments. Signed-off-by: lijian Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 8e88dc8ea6c5e..b90438a71c800 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1940,7 +1940,7 @@ int rc_register_device(struct rc_dev *dev) kfree(path); /* - * once the the input device is registered in rc_setup_rx_device, + * once the input device is registered in rc_setup_rx_device, * userspace can open the input device and rc_open() will be called * as a result. This results in driver code being allowed to submit * keycodes with rc_keydown, so lirc must be registered first. From dcb0145821017e929a733e2271c85c6f82b9c9f8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 10 Jun 2021 21:54:31 +0200 Subject: [PATCH 061/195] media: cxd2880-spi: Fix an error handling path If an error occurs after a successful 'regulator_enable()' call, 'regulator_disable()' must be called. Fix the error handling path of the probe accordingly. Fixes: cb496cd472af ("media: cxd2880-spi: Add optional vcc regulator") Signed-off-by: Christophe JAILLET Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/spi/cxd2880-spi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/spi/cxd2880-spi.c b/drivers/media/spi/cxd2880-spi.c index e5094fff04c5a..b91a1e845b972 100644 --- a/drivers/media/spi/cxd2880-spi.c +++ b/drivers/media/spi/cxd2880-spi.c @@ -524,13 +524,13 @@ cxd2880_spi_probe(struct spi_device *spi) if (IS_ERR(dvb_spi->vcc_supply)) { if (PTR_ERR(dvb_spi->vcc_supply) == -EPROBE_DEFER) { ret = -EPROBE_DEFER; - goto fail_adapter; + goto fail_regulator; } dvb_spi->vcc_supply = NULL; } else { ret = regulator_enable(dvb_spi->vcc_supply); if (ret) - goto fail_adapter; + goto fail_regulator; } dvb_spi->spi = spi; @@ -618,6 +618,9 @@ cxd2880_spi_probe(struct spi_device *spi) fail_attach: dvb_unregister_adapter(&dvb_spi->adapter); fail_adapter: + if (!dvb_spi->vcc_supply) + regulator_disable(dvb_spi->vcc_supply); +fail_regulator: kfree(dvb_spi); return ret; } From 4acb04dc90aa285c3d3ea3009b03c3b6b8858f94 Mon Sep 17 00:00:00 2001 From: lijian Date: Fri, 18 Jun 2021 09:17:57 +0200 Subject: [PATCH 062/195] media: dvb-frontends: cx24117: Delete 'break' after 'goto' break is not useful after a goto, so delete 'break' after 'goto'. Signed-off-by: lijian Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/cx24117.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index 9fccc906d85a4..ac6e47d81b9eb 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c @@ -1172,7 +1172,6 @@ struct dvb_frontend *cx24117_attach(const struct cx24117_config *config, "%s: Error attaching frontend %d\n", KBUILD_MODNAME, demod); goto error1; - break; case 1: /* new priv instance */ priv->i2c = i2c; From 73415d70192a9092102b4842f6ec6e0bb7109084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 12 Jun 2021 11:13:50 +0200 Subject: [PATCH 063/195] media: usb: dvb-usb-v2: af9035: report if i2c client isn't bound MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a sub device doesn't immediately bind after it was added, emit an error indication to the kernel log to help debugging. This happens for example if the needed driver isn't available at all. Signed-off-by: Uwe Kleine-König Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index b1f69c11c8395..5eef37b00a520 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -210,6 +210,7 @@ static int af9035_add_i2c_dev(struct dvb_usb_device *d, const char *type, /* register I2C device */ client = i2c_new_client_device(adapter, &board_info); if (!i2c_client_has_driver(client)) { + dev_err(&intf->dev, "failed to bind i2c device to %s driver\n", type); ret = -ENODEV; goto err; } From 379e205dab9d7f9761984728e7d6f5f8305cc424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 12 Jun 2021 11:13:51 +0200 Subject: [PATCH 064/195] media: usb: dvb-usb-v2: af9035: let subdrv autoselect enable si2168 and si2157 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Logilink VG0022A DVB-T2 stick has these three devices. So to enable support for this stick in the presence of MEDIA_SUBDRV_AUTOSELECT, let DVB_USB_AF9035 select the two other drivers. Signed-off-by: Uwe Kleine-König Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 5c75303fba9d0..60ca8b9d070b7 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -34,6 +34,8 @@ config DVB_USB_AF9035 tristate "Afatech AF9035 DVB-T USB2.0 support" depends on DVB_USB_V2 select DVB_AF9033 + select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TUA9001 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_FC0011 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT From 6b7f554be8c92319d7e6df92fd247ebb9beb4a45 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 3 Jul 2021 15:37:17 +0200 Subject: [PATCH 065/195] media: rc-loopback: return number of emitters rather than error The LIRC_SET_TRANSMITTER_MASK ioctl should return the number of emitters if an invalid list was set. Cc: stable@vger.kernel.org Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-loopback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 1ba3f96ffa7dc..40ab66c850f23 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -42,7 +42,7 @@ static int loop_set_tx_mask(struct rc_dev *dev, u32 mask) if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) { dprintk("invalid tx mask: %u\n", mask); - return -EINVAL; + return 2; } dprintk("setting tx mask: %u\n", mask); From d9d0103940e981ba424b832a7143b547d9364b5b Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 3 Jul 2021 15:36:15 +0200 Subject: [PATCH 066/195] media: rc-loopback: use dev_dbg() rather than handrolled debug Make use of dynamic debug. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-loopback.c | 36 +++++++++++++--------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 40ab66c850f23..5adfbb6989ee3 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -16,12 +16,9 @@ #include #define DRIVER_NAME "rc-loopback" -#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x) #define RXMASK_REGULAR 0x1 #define RXMASK_LEARNING 0x2 -static bool debug; - struct loopback_dev { struct rc_dev *dev; u32 txmask; @@ -41,11 +38,11 @@ static int loop_set_tx_mask(struct rc_dev *dev, u32 mask) struct loopback_dev *lodev = dev->priv; if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) { - dprintk("invalid tx mask: %u\n", mask); + dev_dbg(&dev->dev, "invalid tx mask: %u\n", mask); return 2; } - dprintk("setting tx mask: %u\n", mask); + dev_dbg(&dev->dev, "setting tx mask: %u\n", mask); lodev->txmask = mask; return 0; } @@ -54,7 +51,7 @@ static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier) { struct loopback_dev *lodev = dev->priv; - dprintk("setting tx carrier: %u\n", carrier); + dev_dbg(&dev->dev, "setting tx carrier: %u\n", carrier); lodev->txcarrier = carrier; return 0; } @@ -64,11 +61,11 @@ static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle) struct loopback_dev *lodev = dev->priv; if (duty_cycle < 1 || duty_cycle > 99) { - dprintk("invalid duty cycle: %u\n", duty_cycle); + dev_dbg(&dev->dev, "invalid duty cycle: %u\n", duty_cycle); return -EINVAL; } - dprintk("setting duty cycle: %u\n", duty_cycle); + dev_dbg(&dev->dev, "setting duty cycle: %u\n", duty_cycle); lodev->txduty = duty_cycle; return 0; } @@ -78,11 +75,11 @@ static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max) struct loopback_dev *lodev = dev->priv; if (min < 1 || min > max) { - dprintk("invalid rx carrier range %u to %u\n", min, max); + dev_dbg(&dev->dev, "invalid rx carrier range %u to %u\n", min, max); return -EINVAL; } - dprintk("setting rx carrier range %u to %u\n", min, max); + dev_dbg(&dev->dev, "setting rx carrier range %u to %u\n", min, max); lodev->rxcarriermin = min; lodev->rxcarriermax = max; return 0; @@ -97,7 +94,7 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) if (lodev->txcarrier < lodev->rxcarriermin || lodev->txcarrier > lodev->rxcarriermax) { - dprintk("ignoring tx, carrier out of range\n"); + dev_dbg(&dev->dev, "ignoring tx, carrier out of range\n"); goto out; } @@ -107,7 +104,7 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) rxmask = RXMASK_REGULAR; if (!(rxmask & lodev->txmask)) { - dprintk("ignoring tx, rx mask mismatch\n"); + dev_dbg(&dev->dev, "ignoring tx, rx mask mismatch\n"); goto out; } @@ -134,7 +131,7 @@ static void loop_set_idle(struct rc_dev *dev, bool enable) struct loopback_dev *lodev = dev->priv; if (lodev->idle != enable) { - dprintk("%sing idle mode\n", enable ? "enter" : "exit"); + dev_dbg(&dev->dev, "%sing idle mode\n", enable ? "enter" : "exit"); lodev->idle = enable; } } @@ -144,7 +141,7 @@ static int loop_set_learning_mode(struct rc_dev *dev, int enable) struct loopback_dev *lodev = dev->priv; if (lodev->learning != enable) { - dprintk("%sing learning mode\n", enable ? "enter" : "exit"); + dev_dbg(&dev->dev, "%sing learning mode\n", enable ? "enter" : "exit"); lodev->learning = !!enable; } @@ -156,7 +153,7 @@ static int loop_set_carrier_report(struct rc_dev *dev, int enable) struct loopback_dev *lodev = dev->priv; if (lodev->carrierreport != enable) { - dprintk("%sabling carrier reports\n", enable ? "en" : "dis"); + dev_dbg(&dev->dev, "%sabling carrier reports\n", enable ? "en" : "dis"); lodev->carrierreport = !!enable; } @@ -204,10 +201,8 @@ static int __init loop_init(void) int ret; rc = rc_allocate_device(RC_DRIVER_IR_RAW); - if (!rc) { - printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n"); + if (!rc) return -ENOMEM; - } rc->device_name = "rc-core loopback device"; rc->input_phys = "rc-core/virtual"; @@ -245,7 +240,7 @@ static int __init loop_init(void) ret = rc_register_device(rc); if (ret < 0) { - printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n"); + dev_err(&rc->dev, "rc_dev registration failed\n"); rc_free_device(rc); return ret; } @@ -262,9 +257,6 @@ static void __exit loop_exit(void) module_init(loop_init); module_exit(loop_exit); -module_param(debug, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable debug messages"); - MODULE_DESCRIPTION("Loopback device for rc-core debugging"); MODULE_AUTHOR("David Härdeman "); MODULE_LICENSE("GPL"); From 7300d0c2391a08d03b69100c454146b578322fa3 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 3 Jul 2021 15:51:10 +0200 Subject: [PATCH 067/195] media: rc-loopback: send carrier reports When carrier reports are enabled, send them over loopback. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-loopback.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 5adfbb6989ee3..67782dd7ee4d5 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -111,8 +111,16 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) for (i = 0; i < count; i++) { rawir.pulse = i % 2 ? false : true; rawir.duration = txbuf[i]; - if (rawir.duration) - ir_raw_event_store_with_filter(dev, &rawir); + + ir_raw_event_store_with_filter(dev, &rawir); + } + + if (lodev->carrierreport) { + rawir.pulse = false; + rawir.carrier_report = true; + rawir.carrier = lodev->txcarrier; + + ir_raw_event_store(dev, &rawir); } /* Fake a silence long enough to cause us to go idle */ From 50634548d3c360c19013f665964e6c5b8300ff05 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 5 Jul 2021 19:56:01 +0200 Subject: [PATCH 068/195] media: rc-loopback: max_timeout of UINT_MAX does not work Any timeout larger than LIRC_VALUE_MASK cannot work for the lirc uapi. LIRC_VALUE_MASK is about 16 seconds which is more than enough. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-loopback.c | 4 ++-- include/media/rc-core.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 67782dd7ee4d5..40fca1226b098 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -222,9 +222,9 @@ static int __init loop_init(void) rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; rc->allowed_wakeup_protocols = RC_PROTO_BIT_ALL_IR_ENCODER; rc->encode_wakeup = true; - rc->timeout = MS_TO_US(100); /* 100 ms */ + rc->timeout = IR_DEFAULT_TIMEOUT; rc->min_timeout = 1; - rc->max_timeout = UINT_MAX; + rc->max_timeout = IR_MAX_TIMEOUT; rc->rx_resolution = 1; rc->tx_resolution = 1; rc->s_tx_mask = loop_set_tx_mask; diff --git a/include/media/rc-core.h b/include/media/rc-core.h index a1019c4ab5e89..64b43d76f7f0d 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -313,6 +313,7 @@ struct ir_raw_event { #define MS_TO_US(msec) ((msec) * 1000) #define IR_MAX_DURATION MS_TO_US(500) #define IR_DEFAULT_TIMEOUT MS_TO_US(125) +#define IR_MAX_TIMEOUT LIRC_VALUE_MASK void ir_raw_event_handle(struct rc_dev *dev); int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev); From 8b777edff097ca9bb564529913f3a934d59112f4 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 3 Jul 2021 11:04:40 +0200 Subject: [PATCH 069/195] media: rc: rename s_learning_mode() to s_wideband_receiver() The s_learning_mode() function is called in response to the ioctl LIRC_SET_WIDEBAND_RECEIVER, so rename it to s_wideband_receiver(). Learning mode is when both the wideband receiver is turned on and carrier reports are enabled. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ene_ir.c | 2 +- drivers/media/rc/lirc_dev.c | 6 +++--- drivers/media/rc/mceusb.c | 2 +- drivers/media/rc/rc-loopback.c | 30 +++++++++++++++--------------- include/media/rc-core.h | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index 6049e5c95394f..e09270916fbca 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1052,7 +1052,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) rdev->device_name = "ENE eHome Infrared Remote Receiver"; if (dev->hw_learning_and_tx_capable) { - rdev->s_learning_mode = ene_set_learning_mode; + rdev->s_wideband_receiver = ene_set_learning_mode; init_completion(&dev->tx_complete); rdev->tx_ir = ene_transmit; rdev->s_tx_mask = ene_set_tx_mask; diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 116daf90c858c..7f591ff5269d2 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -412,7 +412,7 @@ static long lirc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) val |= LIRC_CAN_SET_REC_CARRIER | LIRC_CAN_SET_REC_CARRIER_RANGE; - if (dev->s_learning_mode) + if (dev->s_wideband_receiver) val |= LIRC_CAN_USE_WIDEBAND_RECEIVER; if (dev->s_carrier_report) @@ -519,10 +519,10 @@ static long lirc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; case LIRC_SET_WIDEBAND_RECEIVER: - if (!dev->s_learning_mode) + if (!dev->s_wideband_receiver) ret = -ENOTTY; else - ret = dev->s_learning_mode(dev, !!val); + ret = dev->s_wideband_receiver(dev, !!val); break; case LIRC_SET_MEASURE_CARRIER_MODE: diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 5642595a057ec..e03dd1f0144f0 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1630,7 +1630,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->tx_ir = mceusb_tx_ir; } if (ir->flags.rx2 > 0) { - rc->s_learning_mode = mceusb_set_rx_wideband; + rc->s_wideband_receiver = mceusb_set_rx_wideband; rc->s_carrier_report = mceusb_set_rx_carrier_report; } rc->driver_name = DRIVER_NAME; diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index 40fca1226b098..6441879fcba1a 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -15,9 +15,9 @@ #include #include -#define DRIVER_NAME "rc-loopback" -#define RXMASK_REGULAR 0x1 -#define RXMASK_LEARNING 0x2 +#define DRIVER_NAME "rc-loopback" +#define RXMASK_NARROWBAND 0x1 +#define RXMASK_WIDEBAND 0x2 struct loopback_dev { struct rc_dev *dev; @@ -25,7 +25,7 @@ struct loopback_dev { u32 txcarrier; u32 txduty; bool idle; - bool learning; + bool wideband; bool carrierreport; u32 rxcarriermin; u32 rxcarriermax; @@ -37,7 +37,7 @@ static int loop_set_tx_mask(struct rc_dev *dev, u32 mask) { struct loopback_dev *lodev = dev->priv; - if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) { + if ((mask & (RXMASK_NARROWBAND | RXMASK_WIDEBAND)) != mask) { dev_dbg(&dev->dev, "invalid tx mask: %u\n", mask); return 2; } @@ -98,10 +98,10 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) goto out; } - if (lodev->learning) - rxmask = RXMASK_LEARNING; + if (lodev->wideband) + rxmask = RXMASK_WIDEBAND; else - rxmask = RXMASK_REGULAR; + rxmask = RXMASK_NARROWBAND; if (!(rxmask & lodev->txmask)) { dev_dbg(&dev->dev, "ignoring tx, rx mask mismatch\n"); @@ -144,13 +144,13 @@ static void loop_set_idle(struct rc_dev *dev, bool enable) } } -static int loop_set_learning_mode(struct rc_dev *dev, int enable) +static int loop_set_wideband_receiver(struct rc_dev *dev, int enable) { struct loopback_dev *lodev = dev->priv; - if (lodev->learning != enable) { - dev_dbg(&dev->dev, "%sing learning mode\n", enable ? "enter" : "exit"); - lodev->learning = !!enable; + if (lodev->wideband != enable) { + dev_dbg(&dev->dev, "using %sband receiver\n", enable ? "wide" : "narrow"); + lodev->wideband = !!enable; } return 0; @@ -233,17 +233,17 @@ static int __init loop_init(void) rc->s_rx_carrier_range = loop_set_rx_carrier_range; rc->tx_ir = loop_tx_ir; rc->s_idle = loop_set_idle; - rc->s_learning_mode = loop_set_learning_mode; + rc->s_wideband_receiver = loop_set_wideband_receiver; rc->s_carrier_report = loop_set_carrier_report; rc->s_wakeup_filter = loop_set_wakeup_filter; - loopdev.txmask = RXMASK_REGULAR; + loopdev.txmask = RXMASK_NARROWBAND; loopdev.txcarrier = 36000; loopdev.txduty = 50; loopdev.rxcarriermin = 1; loopdev.rxcarriermax = ~0; loopdev.idle = true; - loopdev.learning = false; + loopdev.wideband = false; loopdev.carrierreport = false; ret = rc_register_device(rc); diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 64b43d76f7f0d..8c5b7978e1d98 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -151,7 +151,7 @@ struct lirc_fh { * @tx_ir: transmit IR * @s_idle: enable/disable hardware idle mode, upon which, * device doesn't interrupt host until it sees IR pulses - * @s_learning_mode: enable wide band receiver used for learning + * @s_wideband_receiver: enable wide band receiver used for learning * @s_carrier_report: enable carrier reports * @s_filter: set the scancode filter * @s_wakeup_filter: set the wakeup scancode filter. If the mask is zero @@ -218,7 +218,7 @@ struct rc_dev { int (*s_rx_carrier_range)(struct rc_dev *dev, u32 min, u32 max); int (*tx_ir)(struct rc_dev *dev, unsigned *txbuf, unsigned n); void (*s_idle)(struct rc_dev *dev, bool enable); - int (*s_learning_mode)(struct rc_dev *dev, int enable); + int (*s_wideband_receiver)(struct rc_dev *dev, int enable); int (*s_carrier_report) (struct rc_dev *dev, int enable); int (*s_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter); From c5453769f77ce19a5b03f1f49946fd3f8a374009 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Fri, 25 Jun 2021 07:33:27 +0200 Subject: [PATCH 070/195] media: dvb-usb: fix uninit-value in dvb_usb_adapter_dvb_init If dibusb_read_eeprom_byte fails, the mac address is not initialized. And nova_t_read_mac_address does not handle this failure, which leads to the uninit-value in dvb_usb_adapter_dvb_init. Fix this by handling the failure of dibusb_read_eeprom_byte. Reported-by: syzbot+e27b4fd589762b0b9329@syzkaller.appspotmail.com Fixes: 786baecfe78f ("[media] dvb-usb: move it to drivers/media/usb/dvb-usb") Signed-off-by: Dongliang Mu Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/nova-t-usb2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb/nova-t-usb2.c b/drivers/media/usb/dvb-usb/nova-t-usb2.c index e7b290552b663..9c0eb0d40822e 100644 --- a/drivers/media/usb/dvb-usb/nova-t-usb2.c +++ b/drivers/media/usb/dvb-usb/nova-t-usb2.c @@ -130,7 +130,7 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state) static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) { - int i; + int i, ret; u8 b; mac[0] = 0x00; @@ -139,7 +139,9 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6]) /* this is a complete guess, but works for my box */ for (i = 136; i < 139; i++) { - dibusb_read_eeprom_byte(d,i, &b); + ret = dibusb_read_eeprom_byte(d, i, &b); + if (ret) + return ret; mac[5 - (i - 136)] = b; } From 797c061ad715a9a1480eb73f44b6939fbe3209ed Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Fri, 25 Jun 2021 07:59:04 +0200 Subject: [PATCH 071/195] media: dvb-usb: fix uninit-value in vp702x_read_mac_addr If vp702x_usb_in_op fails, the mac address is not initialized. And vp702x_read_mac_addr does not handle this failure, which leads to the uninit-value in dvb_usb_adapter_dvb_init. Fix this by handling the failure of vp702x_usb_in_op. Fixes: 786baecfe78f ("[media] dvb-usb: move it to drivers/media/usb/dvb-usb") Signed-off-by: Dongliang Mu Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/vp702x.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c index bf54747e2e01a..a1d9e4801a2ba 100644 --- a/drivers/media/usb/dvb-usb/vp702x.c +++ b/drivers/media/usb/dvb-usb/vp702x.c @@ -291,16 +291,22 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state) static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6]) { u8 i, *buf; + int ret; struct vp702x_device_state *st = d->priv; mutex_lock(&st->buf_mutex); buf = st->buf; - for (i = 6; i < 12; i++) - vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1); + for (i = 6; i < 12; i++) { + ret = vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, + &buf[i - 6], 1); + if (ret < 0) + goto err; + } memcpy(mac, buf, 6); +err: mutex_unlock(&st->buf_mutex); - return 0; + return ret; } static int vp702x_frontend_attach(struct dvb_usb_adapter *adap) From 131ae388b88e3daf4cb0721ed4b4cb8bfc201465 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Mon, 21 Jun 2021 07:07:28 +0200 Subject: [PATCH 072/195] media: dvb-usb: Fix error handling in dvb_usb_i2c_init In dvb_usb_i2c_init, if i2c_add_adapter fails, it only prints an error message, and then continues to set DVB_USB_STATE_I2C. This affects the logic of dvb_usb_i2c_exit, which leads to that, the deletion of i2c_adap even if the i2c_add_adapter fails. Fix this by returning at the failure of i2c_add_adapter and then move dvb_usb_i2c_exit out of the error handling code of dvb_usb_i2c_init. Fixes: 13a79f14ab28 ("media: dvb-usb: Fix memory leak at error in dvb_usb_device_init()") Signed-off-by: Dongliang Mu Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dvb-usb-i2c.c | 9 +++++++-- drivers/media/usb/dvb-usb/dvb-usb-init.c | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c index 2e07106f46803..bc4b2abdde1a4 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-i2c.c @@ -17,7 +17,8 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) if (d->props.i2c_algo == NULL) { err("no i2c algorithm specified"); - return -EINVAL; + ret = -EINVAL; + goto err; } strscpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); @@ -27,11 +28,15 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) i2c_set_adapdata(&d->i2c_adap, d); - if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0) + ret = i2c_add_adapter(&d->i2c_adap); + if (ret < 0) { err("could not add i2c adapter"); + goto err; + } d->state |= DVB_USB_STATE_I2C; +err: return ret; } diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c index 28e1fd64dd3c2..61439c8f33cab 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c @@ -194,8 +194,8 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) err_adapter_init: dvb_usb_adapter_exit(d); -err_i2c_init: dvb_usb_i2c_exit(d); +err_i2c_init: if (d->priv && d->props.priv_destroy) d->props.priv_destroy(d); err_priv_init: From 6ad61a7847da09b6261824accb539d05bcdfef65 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 19 Jul 2021 22:52:33 +0200 Subject: [PATCH 073/195] media: hantro: vp8: Move noisy WARN_ON to vpu_debug When the VP8 decoders can't find a reference frame, the driver falls back to the current output frame. This will probably produce some undesirable results, leading to frame corruption, but shouldn't cause noisy warnings. Signed-off-by: Ezequiel Garcia Acked-by: Nicolas Dufresne Tested-by: Alex Bee Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_g1_vp8_dec.c | 13 ++++++++++--- .../staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index 96622a7f8279e..2afd5996d75f8 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -376,12 +376,17 @@ static void cfg_ref(struct hantro_ctx *ctx, vb2_dst = hantro_get_dst_buf(ctx); ref = hantro_get_ref(ctx, hdr->last_frame_ts); - if (!ref) + if (!ref) { + vpu_debug(0, "failed to find last frame ts=%llu\n", + hdr->last_frame_ts); ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + } vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(0)); ref = hantro_get_ref(ctx, hdr->golden_frame_ts); - WARN_ON(!ref && hdr->golden_frame_ts); + if (!ref && hdr->golden_frame_ts) + vpu_debug(0, "failed to find golden frame ts=%llu\n", + hdr->golden_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); if (hdr->flags & V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN) @@ -389,7 +394,9 @@ static void cfg_ref(struct hantro_ctx *ctx, vdpu_write_relaxed(vpu, ref, G1_REG_ADDR_REF(4)); ref = hantro_get_ref(ctx, hdr->alt_frame_ts); - WARN_ON(!ref && hdr->alt_frame_ts); + if (!ref && hdr->alt_frame_ts) + vpu_debug(0, "failed to find alt frame ts=%llu\n", + hdr->alt_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); if (hdr->flags & V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT) diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c index 951b55f58a612..704607511b57f 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c @@ -453,12 +453,17 @@ static void cfg_ref(struct hantro_ctx *ctx, vb2_dst = hantro_get_dst_buf(ctx); ref = hantro_get_ref(ctx, hdr->last_frame_ts); - if (!ref) + if (!ref) { + vpu_debug(0, "failed to find last frame ts=%llu\n", + hdr->last_frame_ts); ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); + } vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF0); ref = hantro_get_ref(ctx, hdr->golden_frame_ts); - WARN_ON(!ref && hdr->golden_frame_ts); + if (!ref && hdr->golden_frame_ts) + vpu_debug(0, "failed to find golden frame ts=%llu\n", + hdr->golden_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); if (hdr->flags & V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN) @@ -466,7 +471,9 @@ static void cfg_ref(struct hantro_ctx *ctx, vdpu_write_relaxed(vpu, ref, VDPU_REG_VP8_ADDR_REF2_5(2)); ref = hantro_get_ref(ctx, hdr->alt_frame_ts); - WARN_ON(!ref && hdr->alt_frame_ts); + if (!ref && hdr->alt_frame_ts) + vpu_debug(0, "failed to find alt frame ts=%llu\n", + hdr->alt_frame_ts); if (!ref) ref = vb2_dma_contig_plane_dma_addr(&vb2_dst->vb2_buf, 0); if (hdr->flags & V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT) From 96f33a5b325e630b31cde9a9393708f569a5f6ac Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 19 Jul 2021 22:52:34 +0200 Subject: [PATCH 074/195] media: hantro: Make struct hantro_variant.init() optional The hantro_variant.init() function is there for platforms to perform hardware-specific initialization, such as clock rate bumping. Not all platforms require it, so make it optional. Signed-off-by: Ezequiel Garcia Tested-by: Alex Bee Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro.h | 4 ++-- drivers/staging/media/hantro/hantro_drv.c | 10 ++++++---- drivers/staging/media/hantro/sama5d4_vdec_hw.c | 6 ------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index a70c386de6f19..c2e2dca38628a 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -61,8 +61,8 @@ struct hantro_irq { * @num_postproc_fmts: Number of post-processor formats. * @codec: Supported codecs * @codec_ops: Codec ops. - * @init: Initialize hardware. - * @runtime_resume: reenable hardware after power gating + * @init: Initialize hardware, optional. + * @runtime_resume: reenable hardware after power gating, optional. * @irqs: array of irq names and interrupt handlers * @num_irqs: number of irqs in the array * @clk_names: array of clock names diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 31d8449ca1d2d..9b5415176bfe2 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -942,10 +942,12 @@ static int hantro_probe(struct platform_device *pdev) } } - ret = vpu->variant->init(vpu); - if (ret) { - dev_err(&pdev->dev, "Failed to init VPU hardware\n"); - return ret; + if (vpu->variant->init) { + ret = vpu->variant->init(vpu); + if (ret) { + dev_err(&pdev->dev, "Failed to init VPU hardware\n"); + return ret; + } } pm_runtime_set_autosuspend_delay(vpu->dev, 100); diff --git a/drivers/staging/media/hantro/sama5d4_vdec_hw.c b/drivers/staging/media/hantro/sama5d4_vdec_hw.c index 58ae72c2b723e..9c3b8cd0b2394 100644 --- a/drivers/staging/media/hantro/sama5d4_vdec_hw.c +++ b/drivers/staging/media/hantro/sama5d4_vdec_hw.c @@ -64,11 +64,6 @@ static const struct hantro_fmt sama5d4_vdec_fmts[] = { }, }; -static int sama5d4_hw_init(struct hantro_dev *vpu) -{ - return 0; -} - /* * Supported codec ops. */ @@ -109,7 +104,6 @@ const struct hantro_variant sama5d4_vdec_variant = { .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | HANTRO_H264_DECODER, .codec_ops = sama5d4_vdec_codec_ops, - .init = sama5d4_hw_init, .irqs = sama5d4_irqs, .num_irqs = ARRAY_SIZE(sama5d4_irqs), .clk_names = sama5d4_clk_names, From b1e60562a62e0a8babbffcaff404ba36a19240ca Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 19 Jul 2021 22:52:35 +0200 Subject: [PATCH 075/195] media: hantro: Avoid redundant hantro_get_{dst,src}_buf() calls Getting the next src/dst buffer is relatively expensive so avoid doing it multiple times. Signed-off-by: Ezequiel Garcia Tested-by: Alex Bee Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/hantro/hantro_g1_h264_dec.c | 17 ++++++++--------- .../staging/media/hantro/hantro_g1_vp8_dec.c | 18 +++++++++--------- .../media/hantro/rockchip_vpu2_hw_vp8_dec.c | 19 +++++++++---------- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c index 5c792b7bcb79e..2aa37baad0c3f 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -19,13 +19,12 @@ #include "hantro_hw.h" #include "hantro_v4l2.h" -static void set_params(struct hantro_ctx *ctx) +static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) { const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; - struct vb2_v4l2_buffer *src_buf = hantro_get_src_buf(ctx); struct hantro_dev *vpu = ctx->dev; u32 reg; @@ -226,22 +225,20 @@ static void set_ref(struct hantro_ctx *ctx) } } -static void set_buffers(struct hantro_ctx *ctx) +static void set_buffers(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) { const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; - struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct vb2_v4l2_buffer *dst_buf; struct hantro_dev *vpu = ctx->dev; dma_addr_t src_dma, dst_dma; size_t offset = 0; - src_buf = hantro_get_src_buf(ctx); - dst_buf = hantro_get_dst_buf(ctx); - /* Source (stream) buffer. */ src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); vdpu_write_relaxed(vpu, src_dma, G1_REG_ADDR_STR); /* Destination (decoded frame) buffer. */ + dst_buf = hantro_get_dst_buf(ctx); dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); /* Adjust dma addr to start at second line for bottom field */ if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) @@ -276,6 +273,7 @@ static void set_buffers(struct hantro_ctx *ctx) int hantro_g1_h264_dec_run(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *src_buf; int ret; /* Prepare the H264 decoder context. */ @@ -284,9 +282,10 @@ int hantro_g1_h264_dec_run(struct hantro_ctx *ctx) return ret; /* Configure hardware registers. */ - set_params(ctx); + src_buf = hantro_get_src_buf(ctx); + set_params(ctx, src_buf); set_ref(ctx); - set_buffers(ctx); + set_buffers(ctx, src_buf); hantro_end_prepare_run(ctx); diff --git a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c index 2afd5996d75f8..6180b23e7d949 100644 --- a/drivers/staging/media/hantro/hantro_g1_vp8_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_vp8_dec.c @@ -367,13 +367,12 @@ static void cfg_tap(struct hantro_ctx *ctx, } static void cfg_ref(struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp8_frame *hdr) + const struct v4l2_ctrl_vp8_frame *hdr, + struct vb2_v4l2_buffer *vb2_dst) { struct hantro_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *vb2_dst; dma_addr_t ref; - vb2_dst = hantro_get_dst_buf(ctx); ref = hantro_get_ref(ctx, hdr->last_frame_ts); if (!ref) { @@ -405,16 +404,14 @@ static void cfg_ref(struct hantro_ctx *ctx, } static void cfg_buffers(struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp8_frame *hdr) + const struct v4l2_ctrl_vp8_frame *hdr, + struct vb2_v4l2_buffer *vb2_dst) { const struct v4l2_vp8_segment *seg = &hdr->segment; struct hantro_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *vb2_dst; dma_addr_t dst_dma; u32 reg; - vb2_dst = hantro_get_dst_buf(ctx); - /* Set probability table buffer address */ vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma, G1_REG_ADDR_QTABLE); @@ -436,6 +433,7 @@ int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) { const struct v4l2_ctrl_vp8_frame *hdr; struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; size_t height = ctx->dst_fmt.height; size_t width = ctx->dst_fmt.width; u32 mb_width, mb_height; @@ -499,8 +497,10 @@ int hantro_g1_vp8_dec_run(struct hantro_ctx *ctx) cfg_qp(ctx, hdr); cfg_parts(ctx, hdr); cfg_tap(ctx, hdr); - cfg_ref(ctx, hdr); - cfg_buffers(ctx, hdr); + + vb2_dst = hantro_get_dst_buf(ctx); + cfg_ref(ctx, hdr, vb2_dst); + cfg_buffers(ctx, hdr, vb2_dst); hantro_end_prepare_run(ctx); diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c index 704607511b57f..d079075448c96 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_vp8_dec.c @@ -444,14 +444,12 @@ static void cfg_tap(struct hantro_ctx *ctx, } static void cfg_ref(struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp8_frame *hdr) + const struct v4l2_ctrl_vp8_frame *hdr, + struct vb2_v4l2_buffer *vb2_dst) { struct hantro_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *vb2_dst; dma_addr_t ref; - vb2_dst = hantro_get_dst_buf(ctx); - ref = hantro_get_ref(ctx, hdr->last_frame_ts); if (!ref) { vpu_debug(0, "failed to find last frame ts=%llu\n", @@ -482,16 +480,14 @@ static void cfg_ref(struct hantro_ctx *ctx, } static void cfg_buffers(struct hantro_ctx *ctx, - const struct v4l2_ctrl_vp8_frame *hdr) + const struct v4l2_ctrl_vp8_frame *hdr, + struct vb2_v4l2_buffer *vb2_dst) { const struct v4l2_vp8_segment *seg = &hdr->segment; struct hantro_dev *vpu = ctx->dev; - struct vb2_v4l2_buffer *vb2_dst; dma_addr_t dst_dma; u32 reg; - vb2_dst = hantro_get_dst_buf(ctx); - /* Set probability table buffer address */ vdpu_write_relaxed(vpu, ctx->vp8_dec.prob_tbl.dma, VDPU_REG_ADDR_QTABLE); @@ -514,6 +510,7 @@ int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx) { const struct v4l2_ctrl_vp8_frame *hdr; struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *vb2_dst; size_t height = ctx->dst_fmt.height; size_t width = ctx->dst_fmt.width; u32 mb_width, mb_height; @@ -590,8 +587,10 @@ int rockchip_vpu2_vp8_dec_run(struct hantro_ctx *ctx) cfg_qp(ctx, hdr); cfg_parts(ctx, hdr); cfg_tap(ctx, hdr); - cfg_ref(ctx, hdr); - cfg_buffers(ctx, hdr); + + vb2_dst = hantro_get_dst_buf(ctx); + cfg_ref(ctx, hdr, vb2_dst); + cfg_buffers(ctx, hdr, vb2_dst); hantro_end_prepare_run(ctx); From a9096c585386a381c1bd7aaed0c478165adcb524 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 19 Jul 2021 22:52:36 +0200 Subject: [PATCH 076/195] media: hantro: h264: Move DPB valid and long-term bitmaps In order to reuse these bitmaps, move this process to struct hantro_h264_dec_hw_ctx. This will be used by the Rockchip VDPU2 H.264 driver. This idea was originally proposed by Jonas Karlman in "[RFC 08/12] media: hantro: Fix H264 decoding of field encoded content" which was posted a while ago. Link: https://lore.kernel.org/linux-media/HE1PR06MB4011EA39133818A85768B91FACBF0@HE1PR06MB4011.eurprd06.prod.outlook.com/ Signed-off-by: Ezequiel Garcia Tested-by: Alex Bee Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/hantro/hantro_g1_h264_dec.c | 17 ++--------------- drivers/staging/media/hantro/hantro_h264.c | 13 +++++++++++++ drivers/staging/media/hantro/hantro_hw.h | 4 ++++ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c index 2aa37baad0c3f..6faacfc44c7c1 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -129,25 +129,12 @@ static void set_ref(struct hantro_ctx *ctx) struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; const u8 *b0_reflist, *b1_reflist, *p_reflist; struct hantro_dev *vpu = ctx->dev; - u32 dpb_longterm = 0; - u32 dpb_valid = 0; int reg_num; u32 reg; int i; - /* - * Set up bit maps of valid and long term DPBs. - * NOTE: The bits are reversed, i.e. MSb is DPB 0. - */ - for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); - - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); - } - vdpu_write_relaxed(vpu, dpb_valid << 16, G1_REG_VALID_REF); - vdpu_write_relaxed(vpu, dpb_longterm << 16, G1_REG_LT_REF); + vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_valid, G1_REG_VALID_REF); + vdpu_write_relaxed(vpu, ctx->h264_dec.dpb_longterm, G1_REG_LT_REF); /* * Set up reference frame picture numbers. diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c index ed6eaf11d96f2..6d72136760e7e 100644 --- a/drivers/staging/media/hantro/hantro_h264.c +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -229,12 +229,25 @@ static void prepare_table(struct hantro_ctx *ctx) const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + u32 dpb_longterm = 0; + u32 dpb_valid = 0; int i; for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { tbl->poc[i * 2] = dpb[i].top_field_order_cnt; tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; + + /* + * Set up bit maps of valid and long term DPBs. + * NOTE: The bits are reversed, i.e. MSb is DPB 0. + */ + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); } + ctx->h264_dec.dpb_valid = dpb_valid << 16; + ctx->h264_dec.dpb_longterm = dpb_longterm << 16; tbl->poc[32] = dec_param->top_field_order_cnt; tbl->poc[33] = dec_param->bottom_field_order_cnt; diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 5dcf65805396b..ce678fedaad60 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -89,12 +89,16 @@ struct hantro_h264_dec_reflists { * @dpb: DPB * @reflists: P/B0/B1 reflists * @ctrls: V4L2 controls attached to a run + * @dpb_longterm: DPB long-term + * @dpb_valid: DPB valid */ struct hantro_h264_dec_hw_ctx { struct hantro_aux_buf priv; struct v4l2_h264_dpb_entry dpb[HANTRO_H264_DPB_SIZE]; struct hantro_h264_dec_reflists reflists; struct hantro_h264_dec_ctrls ctrls; + u32 dpb_longterm; + u32 dpb_valid; }; /** From 678ddaf3ff8b259a88a7a0d3bf3b8c0eed90059a Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 19 Jul 2021 22:52:37 +0200 Subject: [PATCH 077/195] media: hantro: h264: Move reference picture number to a helper Add a hantro_h264_get_ref_nbr() helper function to get the reference picture numbers. This will be used by the Rockchip VDPU2 H.264 driver. This idea was originally proposed by Jonas Karlman in "[RFC 09/12] media: hantro: Refactor G1 H264 code" posted a while ago. Link: https://lore.kernel.org/linux-media/HE1PR06MB401165F2BA0AD8A634FDFAF2ACBF0@HE1PR06MB4011.eurprd06.prod.outlook.com/ Signed-off-by: Ezequiel Garcia Tested-by: Alex Bee Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_g1_h264_dec.c | 14 ++------------ drivers/staging/media/hantro/hantro_h264.c | 11 +++++++++++ drivers/staging/media/hantro/hantro_hw.h | 2 ++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_g1_h264_dec.c b/drivers/staging/media/hantro/hantro_g1_h264_dec.c index 6faacfc44c7c1..236ce24ca00c8 100644 --- a/drivers/staging/media/hantro/hantro_g1_h264_dec.c +++ b/drivers/staging/media/hantro/hantro_g1_h264_dec.c @@ -126,7 +126,6 @@ static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) static void set_ref(struct hantro_ctx *ctx) { - struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; const u8 *b0_reflist, *b1_reflist, *p_reflist; struct hantro_dev *vpu = ctx->dev; int reg_num; @@ -143,17 +142,8 @@ static void set_ref(struct hantro_ctx *ctx) * subsequential reference pictures. */ for (i = 0; i < HANTRO_H264_DPB_SIZE; i += 2) { - reg = 0; - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].pic_num); - else - reg |= G1_REG_REF_PIC_REFER0_NBR(dpb[i].frame_num); - - if (dpb[i + 1].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].pic_num); - else - reg |= G1_REG_REF_PIC_REFER1_NBR(dpb[i + 1].frame_num); - + reg = G1_REG_REF_PIC_REFER0_NBR(hantro_h264_get_ref_nbr(ctx, i)) | + G1_REG_REF_PIC_REFER1_NBR(hantro_h264_get_ref_nbr(ctx, i + 1)); vdpu_write_relaxed(vpu, reg, G1_REG_REF_PIC(i / 2)); } diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c index 6d72136760e7e..0b4d2491be3b8 100644 --- a/drivers/staging/media/hantro/hantro_h264.c +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -348,6 +348,17 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, return dma_addr; } +u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, unsigned int dpb_idx) +{ + const struct v4l2_h264_dpb_entry *dpb = &ctx->h264_dec.dpb[dpb_idx]; + + if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + return 0; + if (dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + return dpb->pic_num; + return dpb->frame_num; +} + int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx) { struct hantro_h264_dec_hw_ctx *h264_ctx = &ctx->h264_dec; diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index ce678fedaad60..7a8048afe3572 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -238,6 +238,8 @@ void hantro_jpeg_enc_done(struct hantro_ctx *ctx); dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, unsigned int dpb_idx); +u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, + unsigned int dpb_idx); int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); int hantro_g1_h264_dec_run(struct hantro_ctx *ctx); int hantro_h264_dec_init(struct hantro_ctx *ctx); From c07665f99386da2f211508586e0dcfe211fe1249 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Mon, 19 Jul 2021 22:52:38 +0200 Subject: [PATCH 078/195] media: hantro: Add H.264 support for Rockchip VDPU2 Rockchip VDPU2 core is present on RK3328, RK3326/PX30, RK3399 and others. It's similar to Hantro G1, but it's not compatible with it. Signed-off-by: Jonas Karlman Signed-off-by: Ezequiel Garcia Tested-by: Alex Bee Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/Makefile | 1 + drivers/staging/media/hantro/hantro_hw.h | 1 + .../media/hantro/rockchip_vpu2_hw_h264_dec.c | 491 ++++++++++++++++++ 3 files changed, 493 insertions(+) create mode 100644 drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile index 287370188d2ae..90036831fec4c 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/staging/media/hantro/Makefile @@ -13,6 +13,7 @@ hantro-vpu-y += \ hantro_g2_hevc_dec.o \ hantro_g1_vp8_dec.o \ rockchip_vpu2_hw_jpeg_enc.o \ + rockchip_vpu2_hw_h264_dec.o \ rockchip_vpu2_hw_mpeg2_dec.o \ rockchip_vpu2_hw_vp8_dec.o \ hantro_jpeg.o \ diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 7a8048afe3572..9296624654a6e 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -241,6 +241,7 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, unsigned int dpb_idx); int hantro_h264_dec_prepare_run(struct hantro_ctx *ctx); +int rockchip_vpu2_h264_dec_run(struct hantro_ctx *ctx); int hantro_g1_h264_dec_run(struct hantro_ctx *ctx); int hantro_h264_dec_init(struct hantro_ctx *ctx); void hantro_h264_dec_exit(struct hantro_ctx *ctx); diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c new file mode 100644 index 0000000000000..64a6330475ebe --- /dev/null +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_h264_dec.c @@ -0,0 +1,491 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Hantro VPU codec driver + * + * Copyright (c) 2014 Rockchip Electronics Co., Ltd. + * Hertz Wong + * Herman Chen + * + * Copyright (C) 2014 Google, Inc. + * Tomasz Figa + */ + +#include +#include + +#include + +#include "hantro_hw.h" +#include "hantro_v4l2.h" + +#define VDPU_SWREG(nr) ((nr) * 4) + +#define VDPU_REG_DEC_OUT_BASE VDPU_SWREG(63) +#define VDPU_REG_RLC_VLC_BASE VDPU_SWREG(64) +#define VDPU_REG_QTABLE_BASE VDPU_SWREG(61) +#define VDPU_REG_DIR_MV_BASE VDPU_SWREG(62) +#define VDPU_REG_REFER_BASE(i) (VDPU_SWREG(84 + (i))) +#define VDPU_REG_DEC_E(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_DEC_ADV_PRE_DIS(v) ((v) ? BIT(11) : 0) +#define VDPU_REG_DEC_SCMD_DIS(v) ((v) ? BIT(10) : 0) +#define VDPU_REG_FILTERING_DIS(v) ((v) ? BIT(8) : 0) +#define VDPU_REG_PIC_FIXED_QUANT(v) ((v) ? BIT(7) : 0) +#define VDPU_REG_DEC_LATENCY(v) (((v) << 1) & GENMASK(6, 1)) + +#define VDPU_REG_INIT_QP(v) (((v) << 25) & GENMASK(30, 25)) +#define VDPU_REG_STREAM_LEN(v) (((v) << 0) & GENMASK(23, 0)) + +#define VDPU_REG_APF_THRESHOLD(v) (((v) << 17) & GENMASK(30, 17)) +#define VDPU_REG_STARTMB_X(v) (((v) << 8) & GENMASK(16, 8)) +#define VDPU_REG_STARTMB_Y(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_DEC_MODE(v) (((v) << 0) & GENMASK(3, 0)) + +#define VDPU_REG_DEC_STRENDIAN_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_DEC_STRSWAP32_E(v) ((v) ? BIT(4) : 0) +#define VDPU_REG_DEC_OUTSWAP32_E(v) ((v) ? BIT(3) : 0) +#define VDPU_REG_DEC_INSWAP32_E(v) ((v) ? BIT(2) : 0) +#define VDPU_REG_DEC_OUT_ENDIAN(v) ((v) ? BIT(1) : 0) +#define VDPU_REG_DEC_IN_ENDIAN(v) ((v) ? BIT(0) : 0) + +#define VDPU_REG_DEC_DATA_DISC_E(v) ((v) ? BIT(22) : 0) +#define VDPU_REG_DEC_MAX_BURST(v) (((v) << 16) & GENMASK(20, 16)) +#define VDPU_REG_DEC_AXI_WR_ID(v) (((v) << 8) & GENMASK(15, 8)) +#define VDPU_REG_DEC_AXI_RD_ID(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_START_CODE_E(v) ((v) ? BIT(22) : 0) +#define VDPU_REG_CH_8PIX_ILEAV_E(v) ((v) ? BIT(21) : 0) +#define VDPU_REG_RLC_MODE_E(v) ((v) ? BIT(20) : 0) +#define VDPU_REG_PIC_INTERLACE_E(v) ((v) ? BIT(17) : 0) +#define VDPU_REG_PIC_FIELDMODE_E(v) ((v) ? BIT(16) : 0) +#define VDPU_REG_PIC_TOPFIELD_E(v) ((v) ? BIT(13) : 0) +#define VDPU_REG_WRITE_MVS_E(v) ((v) ? BIT(10) : 0) +#define VDPU_REG_SEQ_MBAFF_E(v) ((v) ? BIT(7) : 0) +#define VDPU_REG_PICORD_COUNT_E(v) ((v) ? BIT(6) : 0) +#define VDPU_REG_DEC_TIMEOUT_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_DEC_CLK_GATE_E(v) ((v) ? BIT(4) : 0) + +#define VDPU_REG_PRED_BC_TAP_0_0(v) (((v) << 22) & GENMASK(31, 22)) +#define VDPU_REG_PRED_BC_TAP_0_1(v) (((v) << 12) & GENMASK(21, 12)) +#define VDPU_REG_PRED_BC_TAP_0_2(v) (((v) << 2) & GENMASK(11, 2)) + +#define VDPU_REG_REFBU_E(v) ((v) ? BIT(31) : 0) + +#define VDPU_REG_PINIT_RLIST_F9(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_PINIT_RLIST_F8(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_PINIT_RLIST_F7(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_PINIT_RLIST_F6(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_PINIT_RLIST_F5(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_PINIT_RLIST_F4(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_PINIT_RLIST_F15(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_PINIT_RLIST_F14(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_PINIT_RLIST_F13(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_PINIT_RLIST_F12(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_PINIT_RLIST_F11(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_PINIT_RLIST_F10(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_REFER1_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER0_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER3_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER2_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER5_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER4_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER7_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER6_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER9_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER8_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER11_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER10_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER13_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER12_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFER15_NBR(v) (((v) << 16) & GENMASK(31, 16)) +#define VDPU_REG_REFER14_NBR(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_BINIT_RLIST_F5(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_BINIT_RLIST_F4(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_BINIT_RLIST_F3(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_F2(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_F1(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_F0(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_F11(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_BINIT_RLIST_F10(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_BINIT_RLIST_F9(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_F8(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_F7(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_F6(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_F15(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_F14(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_F13(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_F12(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_B5(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_BINIT_RLIST_B4(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_BINIT_RLIST_B3(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_B2(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_B1(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_B0(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_B11(v) (((v) << 25) & GENMASK(29, 25)) +#define VDPU_REG_BINIT_RLIST_B10(v) (((v) << 20) & GENMASK(24, 20)) +#define VDPU_REG_BINIT_RLIST_B9(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_B8(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_B7(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_B6(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_BINIT_RLIST_B15(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_BINIT_RLIST_B14(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_BINIT_RLIST_B13(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_BINIT_RLIST_B12(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_PINIT_RLIST_F3(v) (((v) << 15) & GENMASK(19, 15)) +#define VDPU_REG_PINIT_RLIST_F2(v) (((v) << 10) & GENMASK(14, 10)) +#define VDPU_REG_PINIT_RLIST_F1(v) (((v) << 5) & GENMASK(9, 5)) +#define VDPU_REG_PINIT_RLIST_F0(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_REFER_LTERM_E(v) (((v) << 0) & GENMASK(31, 0)) + +#define VDPU_REG_REFER_VALID_E(v) (((v) << 0) & GENMASK(31, 0)) + +#define VDPU_REG_STRM_START_BIT(v) (((v) << 0) & GENMASK(5, 0)) + +#define VDPU_REG_CH_QP_OFFSET2(v) (((v) << 22) & GENMASK(26, 22)) +#define VDPU_REG_CH_QP_OFFSET(v) (((v) << 17) & GENMASK(21, 17)) +#define VDPU_REG_PIC_MB_HEIGHT_P(v) (((v) << 9) & GENMASK(16, 9)) +#define VDPU_REG_PIC_MB_WIDTH(v) (((v) << 0) & GENMASK(8, 0)) + +#define VDPU_REG_WEIGHT_BIPR_IDC(v) (((v) << 16) & GENMASK(17, 16)) +#define VDPU_REG_REF_FRAMES(v) (((v) << 0) & GENMASK(4, 0)) + +#define VDPU_REG_FILT_CTRL_PRES(v) ((v) ? BIT(31) : 0) +#define VDPU_REG_RDPIC_CNT_PRES(v) ((v) ? BIT(30) : 0) +#define VDPU_REG_FRAMENUM_LEN(v) (((v) << 16) & GENMASK(20, 16)) +#define VDPU_REG_FRAMENUM(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_REFPIC_MK_LEN(v) (((v) << 16) & GENMASK(26, 16)) +#define VDPU_REG_IDR_PIC_ID(v) (((v) << 0) & GENMASK(15, 0)) + +#define VDPU_REG_PPS_ID(v) (((v) << 24) & GENMASK(31, 24)) +#define VDPU_REG_REFIDX1_ACTIVE(v) (((v) << 19) & GENMASK(23, 19)) +#define VDPU_REG_REFIDX0_ACTIVE(v) (((v) << 14) & GENMASK(18, 14)) +#define VDPU_REG_POC_LENGTH(v) (((v) << 0) & GENMASK(7, 0)) + +#define VDPU_REG_IDR_PIC_E(v) ((v) ? BIT(8) : 0) +#define VDPU_REG_DIR_8X8_INFER_E(v) ((v) ? BIT(7) : 0) +#define VDPU_REG_BLACKWHITE_E(v) ((v) ? BIT(6) : 0) +#define VDPU_REG_CABAC_E(v) ((v) ? BIT(5) : 0) +#define VDPU_REG_WEIGHT_PRED_E(v) ((v) ? BIT(4) : 0) +#define VDPU_REG_CONST_INTRA_E(v) ((v) ? BIT(3) : 0) +#define VDPU_REG_8X8TRANS_FLAG_E(v) ((v) ? BIT(2) : 0) +#define VDPU_REG_TYPE1_QUANT_E(v) ((v) ? BIT(1) : 0) +#define VDPU_REG_FIELDPIC_FLAG_E(v) ((v) ? BIT(0) : 0) + +static void set_params(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; + const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; + const struct v4l2_ctrl_h264_pps *pps = ctrls->pps; + struct hantro_dev *vpu = ctx->dev; + u32 reg; + + reg = VDPU_REG_DEC_ADV_PRE_DIS(0) | + VDPU_REG_DEC_SCMD_DIS(0) | + VDPU_REG_FILTERING_DIS(0) | + VDPU_REG_PIC_FIXED_QUANT(0) | + VDPU_REG_DEC_LATENCY(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(50)); + + reg = VDPU_REG_INIT_QP(pps->pic_init_qp_minus26 + 26) | + VDPU_REG_STREAM_LEN(vb2_get_plane_payload(&src_buf->vb2_buf, 0)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(51)); + + reg = VDPU_REG_APF_THRESHOLD(8) | + VDPU_REG_STARTMB_X(0) | + VDPU_REG_STARTMB_Y(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(52)); + + reg = VDPU_REG_DEC_MODE(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(53)); + + reg = VDPU_REG_DEC_STRENDIAN_E(1) | + VDPU_REG_DEC_STRSWAP32_E(1) | + VDPU_REG_DEC_OUTSWAP32_E(1) | + VDPU_REG_DEC_INSWAP32_E(1) | + VDPU_REG_DEC_OUT_ENDIAN(1) | + VDPU_REG_DEC_IN_ENDIAN(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(54)); + + reg = VDPU_REG_DEC_DATA_DISC_E(0) | + VDPU_REG_DEC_MAX_BURST(16) | + VDPU_REG_DEC_AXI_WR_ID(0) | + VDPU_REG_DEC_AXI_RD_ID(0xff); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(56)); + + reg = VDPU_REG_START_CODE_E(1) | + VDPU_REG_CH_8PIX_ILEAV_E(0) | + VDPU_REG_RLC_MODE_E(0) | + VDPU_REG_PIC_INTERLACE_E(!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY) && + (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD || + dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) | + VDPU_REG_PIC_FIELDMODE_E(dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) | + VDPU_REG_PIC_TOPFIELD_E(!(dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)) | + VDPU_REG_WRITE_MVS_E((sps->profile_idc > 66) && dec_param->nal_ref_idc) | + VDPU_REG_SEQ_MBAFF_E(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD) | + VDPU_REG_PICORD_COUNT_E(sps->profile_idc > 66) | + VDPU_REG_DEC_TIMEOUT_E(1) | + VDPU_REG_DEC_CLK_GATE_E(1); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(57)); + + reg = VDPU_REG_PRED_BC_TAP_0_0(1) | + VDPU_REG_PRED_BC_TAP_0_1((u32)-5) | + VDPU_REG_PRED_BC_TAP_0_2(20); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(59)); + + reg = VDPU_REG_REFBU_E(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(65)); + + reg = VDPU_REG_STRM_START_BIT(0); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(109)); + + reg = VDPU_REG_CH_QP_OFFSET2(pps->second_chroma_qp_index_offset) | + VDPU_REG_CH_QP_OFFSET(pps->chroma_qp_index_offset) | + VDPU_REG_PIC_MB_HEIGHT_P(MB_HEIGHT(ctx->src_fmt.height)) | + VDPU_REG_PIC_MB_WIDTH(MB_WIDTH(ctx->src_fmt.width)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(110)); + + reg = VDPU_REG_WEIGHT_BIPR_IDC(pps->weighted_bipred_idc) | + VDPU_REG_REF_FRAMES(sps->max_num_ref_frames); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(111)); + + reg = VDPU_REG_FILT_CTRL_PRES(pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) | + VDPU_REG_RDPIC_CNT_PRES(pps->flags & V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT) | + VDPU_REG_FRAMENUM_LEN(sps->log2_max_frame_num_minus4 + 4) | + VDPU_REG_FRAMENUM(dec_param->frame_num); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(112)); + + reg = VDPU_REG_REFPIC_MK_LEN(dec_param->dec_ref_pic_marking_bit_size) | + VDPU_REG_IDR_PIC_ID(dec_param->idr_pic_id); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(113)); + + reg = VDPU_REG_PPS_ID(pps->pic_parameter_set_id) | + VDPU_REG_REFIDX1_ACTIVE(pps->num_ref_idx_l1_default_active_minus1 + 1) | + VDPU_REG_REFIDX0_ACTIVE(pps->num_ref_idx_l0_default_active_minus1 + 1) | + VDPU_REG_POC_LENGTH(dec_param->pic_order_cnt_bit_size); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(114)); + + reg = VDPU_REG_IDR_PIC_E(dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC) | + VDPU_REG_DIR_8X8_INFER_E(sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) | + VDPU_REG_BLACKWHITE_E(sps->profile_idc >= 100 && sps->chroma_format_idc == 0) | + VDPU_REG_CABAC_E(pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) | + VDPU_REG_WEIGHT_PRED_E(pps->flags & V4L2_H264_PPS_FLAG_WEIGHTED_PRED) | + VDPU_REG_CONST_INTRA_E(pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) | + VDPU_REG_8X8TRANS_FLAG_E(pps->flags & V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE) | + VDPU_REG_TYPE1_QUANT_E(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT) | + VDPU_REG_FIELDPIC_FLAG_E(!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(115)); +} + +static void set_ref(struct hantro_ctx *ctx) +{ + const u8 *b0_reflist, *b1_reflist, *p_reflist; + struct hantro_dev *vpu = ctx->dev; + u32 reg; + int i; + + b0_reflist = ctx->h264_dec.reflists.b0; + b1_reflist = ctx->h264_dec.reflists.b1; + p_reflist = ctx->h264_dec.reflists.p; + + reg = VDPU_REG_PINIT_RLIST_F9(p_reflist[9]) | + VDPU_REG_PINIT_RLIST_F8(p_reflist[8]) | + VDPU_REG_PINIT_RLIST_F7(p_reflist[7]) | + VDPU_REG_PINIT_RLIST_F6(p_reflist[6]) | + VDPU_REG_PINIT_RLIST_F5(p_reflist[5]) | + VDPU_REG_PINIT_RLIST_F4(p_reflist[4]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(74)); + + reg = VDPU_REG_PINIT_RLIST_F15(p_reflist[15]) | + VDPU_REG_PINIT_RLIST_F14(p_reflist[14]) | + VDPU_REG_PINIT_RLIST_F13(p_reflist[13]) | + VDPU_REG_PINIT_RLIST_F12(p_reflist[12]) | + VDPU_REG_PINIT_RLIST_F11(p_reflist[11]) | + VDPU_REG_PINIT_RLIST_F10(p_reflist[10]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(75)); + + reg = VDPU_REG_REFER1_NBR(hantro_h264_get_ref_nbr(ctx, 1)) | + VDPU_REG_REFER0_NBR(hantro_h264_get_ref_nbr(ctx, 0)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(76)); + + reg = VDPU_REG_REFER3_NBR(hantro_h264_get_ref_nbr(ctx, 3)) | + VDPU_REG_REFER2_NBR(hantro_h264_get_ref_nbr(ctx, 2)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(77)); + + reg = VDPU_REG_REFER5_NBR(hantro_h264_get_ref_nbr(ctx, 5)) | + VDPU_REG_REFER4_NBR(hantro_h264_get_ref_nbr(ctx, 4)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(78)); + + reg = VDPU_REG_REFER7_NBR(hantro_h264_get_ref_nbr(ctx, 7)) | + VDPU_REG_REFER6_NBR(hantro_h264_get_ref_nbr(ctx, 6)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(79)); + + reg = VDPU_REG_REFER9_NBR(hantro_h264_get_ref_nbr(ctx, 9)) | + VDPU_REG_REFER8_NBR(hantro_h264_get_ref_nbr(ctx, 8)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(80)); + + reg = VDPU_REG_REFER11_NBR(hantro_h264_get_ref_nbr(ctx, 11)) | + VDPU_REG_REFER10_NBR(hantro_h264_get_ref_nbr(ctx, 10)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(81)); + + reg = VDPU_REG_REFER13_NBR(hantro_h264_get_ref_nbr(ctx, 13)) | + VDPU_REG_REFER12_NBR(hantro_h264_get_ref_nbr(ctx, 12)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(82)); + + reg = VDPU_REG_REFER15_NBR(hantro_h264_get_ref_nbr(ctx, 15)) | + VDPU_REG_REFER14_NBR(hantro_h264_get_ref_nbr(ctx, 14)); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(83)); + + reg = VDPU_REG_BINIT_RLIST_F5(b0_reflist[5]) | + VDPU_REG_BINIT_RLIST_F4(b0_reflist[4]) | + VDPU_REG_BINIT_RLIST_F3(b0_reflist[3]) | + VDPU_REG_BINIT_RLIST_F2(b0_reflist[2]) | + VDPU_REG_BINIT_RLIST_F1(b0_reflist[1]) | + VDPU_REG_BINIT_RLIST_F0(b0_reflist[0]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(100)); + + reg = VDPU_REG_BINIT_RLIST_F11(b0_reflist[11]) | + VDPU_REG_BINIT_RLIST_F10(b0_reflist[10]) | + VDPU_REG_BINIT_RLIST_F9(b0_reflist[9]) | + VDPU_REG_BINIT_RLIST_F8(b0_reflist[8]) | + VDPU_REG_BINIT_RLIST_F7(b0_reflist[7]) | + VDPU_REG_BINIT_RLIST_F6(b0_reflist[6]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(101)); + + reg = VDPU_REG_BINIT_RLIST_F15(b0_reflist[15]) | + VDPU_REG_BINIT_RLIST_F14(b0_reflist[14]) | + VDPU_REG_BINIT_RLIST_F13(b0_reflist[13]) | + VDPU_REG_BINIT_RLIST_F12(b0_reflist[12]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(102)); + + reg = VDPU_REG_BINIT_RLIST_B5(b1_reflist[5]) | + VDPU_REG_BINIT_RLIST_B4(b1_reflist[4]) | + VDPU_REG_BINIT_RLIST_B3(b1_reflist[3]) | + VDPU_REG_BINIT_RLIST_B2(b1_reflist[2]) | + VDPU_REG_BINIT_RLIST_B1(b1_reflist[1]) | + VDPU_REG_BINIT_RLIST_B0(b1_reflist[0]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(103)); + + reg = VDPU_REG_BINIT_RLIST_B11(b1_reflist[11]) | + VDPU_REG_BINIT_RLIST_B10(b1_reflist[10]) | + VDPU_REG_BINIT_RLIST_B9(b1_reflist[9]) | + VDPU_REG_BINIT_RLIST_B8(b1_reflist[8]) | + VDPU_REG_BINIT_RLIST_B7(b1_reflist[7]) | + VDPU_REG_BINIT_RLIST_B6(b1_reflist[6]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(104)); + + reg = VDPU_REG_BINIT_RLIST_B15(b1_reflist[15]) | + VDPU_REG_BINIT_RLIST_B14(b1_reflist[14]) | + VDPU_REG_BINIT_RLIST_B13(b1_reflist[13]) | + VDPU_REG_BINIT_RLIST_B12(b1_reflist[12]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(105)); + + reg = VDPU_REG_PINIT_RLIST_F3(p_reflist[3]) | + VDPU_REG_PINIT_RLIST_F2(p_reflist[2]) | + VDPU_REG_PINIT_RLIST_F1(p_reflist[1]) | + VDPU_REG_PINIT_RLIST_F0(p_reflist[0]); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(106)); + + reg = VDPU_REG_REFER_LTERM_E(ctx->h264_dec.dpb_longterm); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(107)); + + reg = VDPU_REG_REFER_VALID_E(ctx->h264_dec.dpb_valid); + vdpu_write_relaxed(vpu, reg, VDPU_SWREG(108)); + + /* Set up addresses of DPB buffers. */ + for (i = 0; i < HANTRO_H264_DPB_SIZE; i++) { + dma_addr_t dma_addr = hantro_h264_get_ref_buf(ctx, i); + + vdpu_write_relaxed(vpu, dma_addr, VDPU_REG_REFER_BASE(i)); + } +} + +static void set_buffers(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) +{ + const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; + struct vb2_v4l2_buffer *dst_buf; + struct hantro_dev *vpu = ctx->dev; + dma_addr_t src_dma, dst_dma; + size_t offset = 0; + + /* Source (stream) buffer. */ + src_dma = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); + vdpu_write_relaxed(vpu, src_dma, VDPU_REG_RLC_VLC_BASE); + + /* Destination (decoded frame) buffer. */ + dst_buf = hantro_get_dst_buf(ctx); + dst_dma = hantro_get_dec_buf_addr(ctx, &dst_buf->vb2_buf); + /* Adjust dma addr to start at second line for bottom field */ + if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + offset = ALIGN(ctx->src_fmt.width, MB_DIM); + vdpu_write_relaxed(vpu, dst_dma + offset, VDPU_REG_DEC_OUT_BASE); + + /* Higher profiles require DMV buffer appended to reference frames. */ + if (ctrls->sps->profile_idc > 66 && ctrls->decode->nal_ref_idc) { + unsigned int bytes_per_mb = 384; + + /* DMV buffer for monochrome start directly after Y-plane */ + if (ctrls->sps->profile_idc >= 100 && + ctrls->sps->chroma_format_idc == 0) + bytes_per_mb = 256; + offset = bytes_per_mb * MB_WIDTH(ctx->src_fmt.width) * + MB_HEIGHT(ctx->src_fmt.height); + + /* + * DMV buffer is split in two for field encoded frames, + * adjust offset for bottom field + */ + if (ctrls->decode->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + offset += 32 * MB_WIDTH(ctx->src_fmt.width) * + MB_HEIGHT(ctx->src_fmt.height); + vdpu_write_relaxed(vpu, dst_dma + offset, VDPU_REG_DIR_MV_BASE); + } + + /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ + vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, VDPU_REG_QTABLE_BASE); +} + +int rockchip_vpu2_h264_dec_run(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + struct vb2_v4l2_buffer *src_buf; + u32 reg; + int ret; + + /* Prepare the H264 decoder context. */ + ret = hantro_h264_dec_prepare_run(ctx); + if (ret) + return ret; + + src_buf = hantro_get_src_buf(ctx); + set_params(ctx, src_buf); + set_ref(ctx); + set_buffers(ctx, src_buf); + + hantro_end_prepare_run(ctx); + + /* Start decoding! */ + reg = vdpu_read(vpu, VDPU_SWREG(57)) | VDPU_REG_DEC_E(1); + vdpu_write(vpu, reg, VDPU_SWREG(57)); + + return 0; +} From 1f82f2df523cbc6dc972d1b4b977aebc5333cb0f Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 19 Jul 2021 22:52:39 +0200 Subject: [PATCH 079/195] media: hantro: Enable H.264 on Rockchip VDPU2 Given H.264 support for VDPU2 was just added, let's enable it. For now, this is only enabled on platform that don't have an RKVDEC core, such as RK3328. Signed-off-by: Ezequiel Garcia Tested-by: Alex Bee Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/hantro/rockchip_vpu_hw.c | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c index 3ccc16413f42f..e4e3b5e7689bc 100644 --- a/drivers/staging/media/hantro/rockchip_vpu_hw.c +++ b/drivers/staging/media/hantro/rockchip_vpu_hw.c @@ -162,6 +162,19 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = { .fourcc = V4L2_PIX_FMT_NV12, .codec_mode = HANTRO_MODE_NONE, }, + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .codec_mode = HANTRO_MODE_H264_DEC, + .max_depth = 2, + .frmsize = { + .min_width = 48, + .max_width = 1920, + .step_width = MB_DIM, + .min_height = 48, + .max_height = 1088, + .step_height = MB_DIM, + }, + }, { .fourcc = V4L2_PIX_FMT_MPEG2_SLICE, .codec_mode = HANTRO_MODE_MPEG2_DEC, @@ -388,6 +401,12 @@ static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { .init = hantro_jpeg_enc_init, .exit = hantro_jpeg_enc_exit, }, + [HANTRO_MODE_H264_DEC] = { + .run = rockchip_vpu2_h264_dec_run, + .reset = rockchip_vpu2_dec_reset, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, [HANTRO_MODE_MPEG2_DEC] = { .run = rockchip_vpu2_mpeg2_dec_run, .reset = rockchip_vpu2_dec_reset, @@ -433,6 +452,8 @@ static const char * const rockchip_vpu_clk_names[] = { "aclk", "hclk" }; +/* VDPU1/VEPU1 */ + const struct hantro_variant rk3036_vpu_variant = { .dec_offset = 0x400, .dec_fmts = rk3066_vpu_dec_fmts, @@ -495,11 +516,14 @@ const struct hantro_variant rk3288_vpu_variant = { .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) }; +/* VDPU2/VEPU2 */ + const struct hantro_variant rk3328_vpu_variant = { .dec_offset = 0x400, .dec_fmts = rk3399_vpu_dec_fmts, .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), - .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER, + .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | + HANTRO_H264_DECODER, .codec_ops = rk3399_vpu_codec_ops, .irqs = rockchip_vdpu2_irqs, .num_irqs = ARRAY_SIZE(rockchip_vdpu2_irqs), From fb7cb344b969386979d15f3e1c08d511ffe88ef3 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Mon, 19 Jul 2021 22:52:40 +0200 Subject: [PATCH 080/195] media: hantro: Add support for the Rockchip PX30 The PX30 SoC includes both the VDPU2 and VEPU2 blocks which are similar to the RK3399 (Hantro G1/H1 with shuffled registers). Signed-off-by: Paul Kocialkowski Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 1 + drivers/staging/media/hantro/hantro_hw.h | 1 + drivers/staging/media/hantro/rockchip_vpu_hw.c | 17 +++++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 9b5415176bfe2..8a2edd67f2c6f 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -582,6 +582,7 @@ static const struct v4l2_file_operations hantro_fops = { static const struct of_device_id of_hantro_match[] = { #ifdef CONFIG_VIDEO_HANTRO_ROCKCHIP + { .compatible = "rockchip,px30-vpu", .data = &px30_vpu_variant, }, { .compatible = "rockchip,rk3036-vpu", .data = &rk3036_vpu_variant, }, { .compatible = "rockchip,rk3066-vpu", .data = &rk3066_vpu_variant, }, { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, }, diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 9296624654a6e..df7b5e3a57b9b 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -209,6 +209,7 @@ enum hantro_enc_fmt { extern const struct hantro_variant imx8mq_vpu_g2_variant; extern const struct hantro_variant imx8mq_vpu_variant; +extern const struct hantro_variant px30_vpu_variant; extern const struct hantro_variant rk3036_vpu_variant; extern const struct hantro_variant rk3066_vpu_variant; extern const struct hantro_variant rk3288_vpu_variant; diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c index e4e3b5e7689bc..d4f52957cc534 100644 --- a/drivers/staging/media/hantro/rockchip_vpu_hw.c +++ b/drivers/staging/media/hantro/rockchip_vpu_hw.c @@ -548,3 +548,20 @@ const struct hantro_variant rk3399_vpu_variant = { .clk_names = rockchip_vpu_clk_names, .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) }; + +const struct hantro_variant px30_vpu_variant = { + .enc_offset = 0x0, + .enc_fmts = rockchip_vpu_enc_fmts, + .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts), + .dec_offset = 0x400, + .dec_fmts = rk3399_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts), + .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER | + HANTRO_VP8_DECODER | HANTRO_H264_DECODER, + .codec_ops = rk3399_vpu_codec_ops, + .irqs = rockchip_vpu2_irqs, + .num_irqs = ARRAY_SIZE(rockchip_vpu2_irqs), + .init = rk3036_vpu_hw_init, + .clk_names = rockchip_vpu_clk_names, + .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) +}; From 9d05c1e00e1045d3651ede7f01a3eb2327be0fe5 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Mon, 19 Jul 2021 22:52:41 +0200 Subject: [PATCH 081/195] media: dt-bindings: media: rockchip-vpu: Add PX30 compatible The Rockchip PX30 SoC has a Hantro VPU that features a decoder (VDPU2) and an encoder (VEPU2). Suggested-by: Alex Bee Signed-off-by: Paul Kocialkowski Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/rockchip-vpu.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml index b88172a59de7a..bacb60a349895 100644 --- a/Documentation/devicetree/bindings/media/rockchip-vpu.yaml +++ b/Documentation/devicetree/bindings/media/rockchip-vpu.yaml @@ -22,6 +22,7 @@ properties: - rockchip,rk3288-vpu - rockchip,rk3328-vpu - rockchip,rk3399-vpu + - rockchip,px30-vpu - items: - const: rockchip,rk3188-vpu - const: rockchip,rk3066-vpu From 724fae95889684377c85f85a0ddd7e9846d00752 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 31 May 2021 13:22:35 +0200 Subject: [PATCH 082/195] media: dt-bindings: adv7180: Introduce the 'reset-gpios' property Introduce the 'reset-gpios' property to describe the GPIO that connects to the ADV7180 reset pin. Signed-off-by: Fabio Estevam Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/adv7180.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml index 3ce4af143a3a3..7b233212d0e6e 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml @@ -35,6 +35,9 @@ properties: powerdown-gpios: maxItems: 1 + reset-gpios: + maxItems: 1 + port: $ref: /schemas/graph.yaml#/$defs/port-base unevaluatedProperties: false From abb7c7c2f025e5f5f80359809e5c73549614306b Mon Sep 17 00:00:00 2001 From: Frieder Schrempf Date: Mon, 31 May 2021 13:22:36 +0200 Subject: [PATCH 083/195] media: adv7180: Add optional reset GPIO There is a reset input that can be controlled by GPIO. Let's add it to let the driver control it if required. [hverkuil: fix a small checkpatch alignment warning] Signed-off-by: Frieder Schrempf Signed-off-by: Fabio Estevam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index fa5bc55bc9445..83690d42a0c30 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -205,6 +205,7 @@ struct adv7180_state { struct mutex mutex; /* mutual excl. when accessing chip */ int irq; struct gpio_desc *pwdn_gpio; + struct gpio_desc *rst_gpio; v4l2_std_id curr_norm; bool powered; bool streaming; @@ -484,6 +485,19 @@ static void adv7180_set_power_pin(struct adv7180_state *state, bool on) } } +static void adv7180_set_reset_pin(struct adv7180_state *state, bool on) +{ + if (!state->rst_gpio) + return; + + if (on) { + gpiod_set_value_cansleep(state->rst_gpio, 1); + } else { + gpiod_set_value_cansleep(state->rst_gpio, 0); + usleep_range(5000, 10000); + } +} + static int adv7180_set_power(struct adv7180_state *state, bool on) { u8 val; @@ -1263,6 +1277,7 @@ static int init_device(struct adv7180_state *state) mutex_lock(&state->mutex); adv7180_set_power_pin(state, true); + adv7180_set_reset_pin(state, false); adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES); usleep_range(5000, 10000); @@ -1338,6 +1353,14 @@ static int adv7180_probe(struct i2c_client *client, return ret; } + state->rst_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(state->rst_gpio)) { + ret = PTR_ERR(state->rst_gpio); + v4l_err(client, "request for reset pin failed: %d\n", ret); + return ret; + } + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { state->csi_client = i2c_new_dummy_device(client->adapter, ADV7180_DEFAULT_CSI_I2C_ADDR); @@ -1428,6 +1451,7 @@ static int adv7180_remove(struct i2c_client *client) i2c_unregister_device(state->vpp_client); i2c_unregister_device(state->csi_client); + adv7180_set_reset_pin(state, true); adv7180_set_power_pin(state, false); mutex_destroy(&state->mutex); From f7b96a9f350c95495ebdba55780b4a63aa677a64 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 31 May 2021 13:22:37 +0200 Subject: [PATCH 084/195] media: i2c: adv7180: Print the chip ID on probe Improve the probe message by printing the chip ID version. Signed-off-by: Fabio Estevam Reviewed-by: Frieder Schrempf Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 83690d42a0c30..81dd9eba19ba4 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1415,11 +1415,19 @@ static int adv7180_probe(struct i2c_client *client, if (ret) goto err_free_irq; - v4l_info(client, "chip found @ 0x%02x (%s)\n", - client->addr, client->adapter->name); + mutex_lock(&state->mutex); + ret = adv7180_read(state, ADV7180_REG_IDENT); + mutex_unlock(&state->mutex); + if (ret < 0) + goto err_v4l2_async_unregister; + + v4l_info(client, "chip id 0x%x found @ 0x%02x (%s)\n", + ret, client->addr, client->adapter->name); return 0; +err_v4l2_async_unregister: + v4l2_async_unregister_subdev(sd); err_free_irq: if (state->irq > 0) free_irq(client->irq, state); From 28d1e47694aff751cfb1d86a2f9701f0a22e5f1e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 4 Jun 2021 23:22:16 +0200 Subject: [PATCH 085/195] media: dt-bindings: adv7180: Introduce 'adv,force-bt656-4' property Captured NTSC video would be out of sync when using the adv7280 with the BT.656-4 protocol. Certain registers (0x04, 0x31, 0xE6) need to be configured properly to ensure BT.656-4 compatibility. Introduce the 'adv,force-bt656-4' property to allow the ADV7280 behavior to be consistent with the ADV7180, where BT.656-4 timing is used by default. Signed-off-by: Fabio Estevam Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/adv7180.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml index 7b233212d0e6e..c8d887eee3bbe 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7180.yaml +++ b/Documentation/devicetree/bindings/media/i2c/adv7180.yaml @@ -38,6 +38,11 @@ properties: reset-gpios: maxItems: 1 + adv,force-bt656-4: + description: + Indicates that the output is a BT.656-4 compatible stream. + type: boolean + port: $ref: /schemas/graph.yaml#/$defs/port-base unevaluatedProperties: false From ed771d75af3cf7e8747ab6a5c207cd920fe0adaa Mon Sep 17 00:00:00 2001 From: Matthew Michilot Date: Fri, 4 Jun 2021 23:22:17 +0200 Subject: [PATCH 086/195] media: i2c: adv7180: fix adv7280 BT.656-4 compatibility Captured video would be out of sync when using the adv7280 with the BT.656-4 protocol. Certain registers (0x04, 0x31, 0xE6) had to be configured properly to ensure BT.656-4 compatibility. An error in the adv7280 reference manual suggested that EAV/SAV mode was enabled by default, however upon inspecting register 0x31, it was determined to be disabled by default. [fabio: Introduce "adv,force-bt656-4" to not affect the existing users] [hverkuil: fix a small checkpatch alignment warning] Signed-off-by: Matthew Michilot Reviewed-by: Tim Harvey Signed-off-by: Fabio Estevam Tested-by: Tim Harvey Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 81dd9eba19ba4..d9a99fcfacb17 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -94,6 +94,7 @@ #define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017 #define ADV7180_REG_CTRL_2 0x001d #define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031 +#define ADV7180_VSYNC_FIELD_CTL_1_NEWAV 0x12 #define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d #define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e #define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f @@ -217,6 +218,7 @@ struct adv7180_state { struct i2c_client *vpp_client; const struct adv7180_chip_info *chip_info; enum v4l2_field field; + bool force_bt656_4; }; #define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \ struct adv7180_state, \ @@ -977,10 +979,26 @@ static int adv7182_init(struct adv7180_state *state) adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57); adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0); } else { - if (state->chip_info->flags & ADV7180_FLAG_V2) - adv7180_write(state, - ADV7180_REG_EXTENDED_OUTPUT_CONTROL, - 0x17); + if (state->chip_info->flags & ADV7180_FLAG_V2) { + if (state->force_bt656_4) { + /* ITU-R BT.656-4 compatible */ + adv7180_write(state, + ADV7180_REG_EXTENDED_OUTPUT_CONTROL, + ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS); + /* Manually set NEWAVMODE */ + adv7180_write(state, + ADV7180_REG_VSYNC_FIELD_CTL_1, + ADV7180_VSYNC_FIELD_CTL_1_NEWAV); + /* Manually set V bit end position in NTSC mode */ + adv7180_write(state, + ADV7180_REG_NTSC_V_BIT_END, + ADV7180_NTSC_V_BIT_END_MANUAL_NVEND); + } else { + adv7180_write(state, + ADV7180_REG_EXTENDED_OUTPUT_CONTROL, + 0x17); + } + } else adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, @@ -1329,6 +1347,7 @@ static int init_device(struct adv7180_state *state) static int adv7180_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct device_node *np = client->dev.of_node; struct adv7180_state *state; struct v4l2_subdev *sd; int ret; @@ -1361,6 +1380,9 @@ static int adv7180_probe(struct i2c_client *client, return ret; } + if (of_property_read_bool(np, "adv,force-bt656-4")) + state->force_bt656_4 = true; + if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { state->csi_client = i2c_new_dummy_device(client->adapter, ADV7180_DEFAULT_CSI_I2C_ADDR); From 47d94dad8e64b2fc1d8f66ce7acf714f9462c60f Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Sun, 20 Jun 2021 21:45:02 +0200 Subject: [PATCH 087/195] media: go7007: fix memory leak in go7007_usb_probe In commit 137641287eb4 ("go7007: add sanity checking for endpoints") endpoint sanity check was introduced, but if check fails it simply returns with leaked pointers. Cutted log from my local syzbot instance: BUG: memory leak unreferenced object 0xffff8880209f0000 (size 8192): comm "kworker/0:4", pid 4916, jiffies 4295263583 (age 29.310s) hex dump (first 32 bytes): 30 b0 27 22 80 88 ff ff 75 73 62 2d 64 75 6d 6d 0.'"....usb-dumm 79 5f 68 63 64 2e 33 2d 31 00 00 00 00 00 00 00 y_hcd.3-1....... backtrace: [] kmalloc include/linux/slab.h:556 [inline] [] kzalloc include/linux/slab.h:686 [inline] [] go7007_alloc+0x46/0xb40 drivers/media/usb/go7007/go7007-driver.c:696 [] go7007_usb_probe+0x13e/0x2200 drivers/media/usb/go7007/go7007-usb.c:1114 [] usb_probe_interface+0x314/0x7f0 drivers/usb/core/driver.c:396 [] really_probe+0x291/0xf60 drivers/base/dd.c:576 BUG: memory leak unreferenced object 0xffff88801e2f2800 (size 512): comm "kworker/0:4", pid 4916, jiffies 4295263583 (age 29.310s) hex dump (first 32 bytes): 00 87 40 8a ff ff ff ff 00 00 00 00 00 00 00 00 ..@............. 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [] kmalloc include/linux/slab.h:556 [inline] [] kzalloc include/linux/slab.h:686 [inline] [] go7007_usb_probe+0x184/0x2200 drivers/media/usb/go7007/go7007-usb.c:1118 [] usb_probe_interface+0x314/0x7f0 drivers/usb/core/driver.c:396 [] really_probe+0x291/0xf60 drivers/base/dd.c:576 Fixes: 137641287eb4 ("go7007: add sanity checking for endpoints") Signed-off-by: Pavel Skripkin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/go7007/go7007-usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index dbf0455d5d50d..eeb85981e02b6 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -1134,7 +1134,7 @@ static int go7007_usb_probe(struct usb_interface *intf, ep = usb->usbdev->ep_in[4]; if (!ep) - return -ENODEV; + goto allocfail; /* Allocate the URB and buffer for receiving incoming interrupts */ usb->intr_urb = usb_alloc_urb(0, GFP_KERNEL); From 6f5885a7750545973bf1a942d2f0f129aef0aa06 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Sun, 20 Jun 2021 21:45:42 +0200 Subject: [PATCH 088/195] media: go7007: remove redundant initialization In go7007_alloc() kzalloc() is used for struct go7007 allocation. It means that there is no need in zeroing any members, because kzalloc will take care of it. Removing these reduntant initialization steps increases execution speed a lot: Before: + 86.802 us | go7007_alloc(); After: + 29.595 us | go7007_alloc(); Fixes: 866b8695d67e8 ("Staging: add the go7007 video driver") Signed-off-by: Pavel Skripkin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/go7007/go7007-driver.c | 26 ------------------------ 1 file changed, 26 deletions(-) diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c index f1767be9d8685..6650eab913d81 100644 --- a/drivers/media/usb/go7007/go7007-driver.c +++ b/drivers/media/usb/go7007/go7007-driver.c @@ -691,49 +691,23 @@ struct go7007 *go7007_alloc(const struct go7007_board_info *board, struct device *dev) { struct go7007 *go; - int i; go = kzalloc(sizeof(struct go7007), GFP_KERNEL); if (go == NULL) return NULL; go->dev = dev; go->board_info = board; - go->board_id = 0; go->tuner_type = -1; - go->channel_number = 0; - go->name[0] = 0; mutex_init(&go->hw_lock); init_waitqueue_head(&go->frame_waitq); spin_lock_init(&go->spinlock); go->status = STATUS_INIT; - memset(&go->i2c_adapter, 0, sizeof(go->i2c_adapter)); - go->i2c_adapter_online = 0; - go->interrupt_available = 0; init_waitqueue_head(&go->interrupt_waitq); - go->input = 0; go7007_update_board(go); - go->encoder_h_halve = 0; - go->encoder_v_halve = 0; - go->encoder_subsample = 0; go->format = V4L2_PIX_FMT_MJPEG; go->bitrate = 1500000; go->fps_scale = 1; - go->pali = 0; go->aspect_ratio = GO7007_RATIO_1_1; - go->gop_size = 0; - go->ipb = 0; - go->closed_gop = 0; - go->repeat_seqhead = 0; - go->seq_header_enable = 0; - go->gop_header_enable = 0; - go->dvd_mode = 0; - go->interlace_coding = 0; - for (i = 0; i < 4; ++i) - go->modet[i].enable = 0; - for (i = 0; i < 1624; ++i) - go->modet_map[i] = 0; - go->audio_deliver = NULL; - go->audio_enabled = 0; return go; } From ba7a93e507f88306d7a19a1dcb53b857b790cfb8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 22 Jun 2021 16:31:53 +0200 Subject: [PATCH 089/195] media: v4l2-subdev: fix some NULL vs IS_ERR() checks The v4l2_subdev_alloc_state() function returns error pointers, it doesn't return NULL. Fixes: 0d346d2a6f54 ("media: v4l2-subdev: add subdev-wide state struct") Signed-off-by: Dan Carpenter Reviewed-by: Laurent Pinchart Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 4 ++-- drivers/media/platform/vsp1/vsp1_entity.c | 4 ++-- drivers/staging/media/tegra-video/vi.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index cca15a10c0b34..0d141155f0e3e 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -253,8 +253,8 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which, int ret; sd_state = v4l2_subdev_alloc_state(sd); - if (sd_state == NULL) - return -ENOMEM; + if (IS_ERR(sd_state)) + return PTR_ERR(sd_state); if (!rvin_format_from_pixel(vin, pix->pixelformat)) pix->pixelformat = RVIN_DEFAULT_FORMAT; diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 6f51e5c755432..823c15facd1b4 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -676,9 +676,9 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, * rectangles. */ entity->config = v4l2_subdev_alloc_state(&entity->subdev); - if (entity->config == NULL) { + if (IS_ERR(entity->config)) { media_entity_cleanup(&entity->subdev.entity); - return -ENOMEM; + return PTR_ERR(entity->config); } return 0; diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c index 89709cd06d4d3..d321790b07d95 100644 --- a/drivers/staging/media/tegra-video/vi.c +++ b/drivers/staging/media/tegra-video/vi.c @@ -508,8 +508,8 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan, return -ENODEV; sd_state = v4l2_subdev_alloc_state(subdev); - if (!sd_state) - return -ENOMEM; + if (IS_ERR(sd_state)) + return PTR_ERR(sd_state); /* * Retrieve the format information and if requested format isn't * supported, keep the current format. From 07e59d91e70107803630c1bbed0837f0cf32eed7 Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Fri, 25 Jun 2021 10:23:08 +0200 Subject: [PATCH 090/195] media: rkisp1: remove field 'vaddr' from 'rkisp1_buffer' The virtual address can be accessed using vb2_plane_vaddr therefore there is no need to save it in an extra field in 'rkisp1_buffer'. Remove it. Signed-off-by: Dafna Hirschfeld Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rkisp1/rkisp1-common.h | 6 +----- drivers/media/platform/rockchip/rkisp1/rkisp1-params.c | 3 +-- drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c | 6 ++---- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index 038c303a8aed0..bb73f4e17b665 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -156,15 +156,11 @@ struct rkisp1_vdev_node { * @vb: vb2 buffer * @queue: entry of the buffer in the queue * @buff_addr: dma addresses of each plane, used only by the capture devices: selfpath, mainpath - * @vaddr: virtual address for buffers used by params and stats devices */ struct rkisp1_buffer { struct vb2_v4l2_buffer vb; struct list_head queue; - union { - u32 buff_addr[VIDEO_MAX_PLANES]; - void *vaddr; - }; + u32 buff_addr[VIDEO_MAX_PLANES]; }; /* diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c index 529c6e21815f3..8fa5b0abf1f9c 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c @@ -1143,7 +1143,7 @@ static void rkisp1_params_apply_params_cfg(struct rkisp1_params *params, cur_buf = list_first_entry(¶ms->params, struct rkisp1_buffer, queue); - new_params = (struct rkisp1_params_cfg *)(cur_buf->vaddr); + new_params = (struct rkisp1_params_cfg *)vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0); rkisp1_isp_isr_other_config(params, new_params); rkisp1_isp_isr_meas_config(params, new_params); @@ -1382,7 +1382,6 @@ static void rkisp1_params_vb2_buf_queue(struct vb2_buffer *vb) struct vb2_queue *vq = vb->vb2_queue; struct rkisp1_params *params = vq->drv_priv; - params_buf->vaddr = vb2_plane_vaddr(vb, 0); spin_lock_irq(¶ms->config_lock); list_add_tail(¶ms_buf->queue, ¶ms->params); spin_unlock_irq(¶ms->config_lock); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c index c1d07a2e8839f..e88bdd612d719 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c @@ -112,7 +112,6 @@ static void rkisp1_stats_vb2_buf_queue(struct vb2_buffer *vb) struct vb2_queue *vq = vb->vb2_queue; struct rkisp1_stats *stats_dev = vq->drv_priv; - stats_buf->vaddr = vb2_plane_vaddr(vb, 0); spin_lock_irq(&stats_dev->lock); list_add_tail(&stats_buf->queue, &stats_dev->stat); @@ -305,9 +304,8 @@ rkisp1_stats_send_measurement(struct rkisp1_stats *stats, u32 isp_ris) if (!cur_buf) return; - cur_stat_buf = - (struct rkisp1_stat_buffer *)(cur_buf->vaddr); - + cur_stat_buf = (struct rkisp1_stat_buffer *) + vb2_plane_vaddr(&cur_buf->vb.vb2_buf, 0); if (isp_ris & RKISP1_CIF_ISP_AWB_DONE) rkisp1_stats_get_awb_meas(stats, cur_stat_buf); From f003d635a8aede9d0e44fb1255ff63a1b2d7eb6e Mon Sep 17 00:00:00 2001 From: Dafna Hirschfeld Date: Fri, 25 Jun 2021 10:23:09 +0200 Subject: [PATCH 091/195] media: rkisp1: cap: initialize dma buf address in 'buf_init' cb Initializing the dma addresses of the capture buffers can move to the 'buf_init' callback, since it is enough to do it once for each buffer and not every time it is queued. Signed-off-by: Dafna Hirschfeld Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../media/platform/rockchip/rkisp1/rkisp1-capture.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index 60cd2200e7aea..41988eb0ec0a5 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -750,7 +750,7 @@ static int rkisp1_vb2_queue_setup(struct vb2_queue *queue, return 0; } -static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb) +static int rkisp1_vb2_buf_init(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct rkisp1_buffer *ispbuf = @@ -780,6 +780,15 @@ static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb) if (cap->pix.info->comp_planes == 3 && cap->pix.cfg->uv_swap) swap(ispbuf->buff_addr[RKISP1_PLANE_CR], ispbuf->buff_addr[RKISP1_PLANE_CB]); + return 0; +} + +static void rkisp1_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rkisp1_buffer *ispbuf = + container_of(vbuf, struct rkisp1_buffer, vb); + struct rkisp1_capture *cap = vb->vb2_queue->drv_priv; spin_lock_irq(&cap->buf.lock); list_add_tail(&ispbuf->queue, &cap->buf.queue); @@ -1039,6 +1048,7 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) static const struct vb2_ops rkisp1_vb2_ops = { .queue_setup = rkisp1_vb2_queue_setup, + .buf_init = rkisp1_vb2_buf_init, .buf_queue = rkisp1_vb2_buf_queue, .buf_prepare = rkisp1_vb2_buf_prepare, .wait_prepare = vb2_ops_wait_prepare, From 7910c23d704794461aba7a72b07aae582496b781 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 28 Jun 2021 10:23:49 +0200 Subject: [PATCH 092/195] media: media/cec-core.rst: update adap_enable doc The description of adap_enable was out-of-date. Improve it so that it corresponds to what really happens. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/cec-core.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/driver-api/media/cec-core.rst b/Documentation/driver-api/media/cec-core.rst index 56345eae9a262..c6194ee81c41b 100644 --- a/Documentation/driver-api/media/cec-core.rst +++ b/Documentation/driver-api/media/cec-core.rst @@ -130,9 +130,12 @@ To enable/disable the hardware:: int (*adap_enable)(struct cec_adapter *adap, bool enable); This callback enables or disables the CEC hardware. Enabling the CEC hardware -means powering it up in a state where no logical addresses are claimed. This -op assumes that the physical address (adap->phys_addr) is valid when enable is -true and will not change while the CEC adapter remains enabled. The initial +means powering it up in a state where no logical addresses are claimed. The +physical address will always be valid if CEC_CAP_NEEDS_HPD is set. If that +capability is not set, then the physical address can change while the CEC +hardware is enabled. CEC drivers should not set CEC_CAP_NEEDS_HPD unless +the hardware design requires that as this will make it impossible to wake +up displays that pull the HPD low when in standby mode. The initial state of the CEC adapter after calling cec_allocate_adapter() is disabled. Note that adap_enable must return 0 if enable is false. From 514e97674400462cc09c459a1ddfb9bf39017223 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Wed, 7 Jul 2021 19:54:30 +0200 Subject: [PATCH 093/195] media: stkwebcam: fix memory leak in stk_camera_probe My local syzbot instance hit memory leak in usb_set_configuration(). The problem was in unputted usb interface. In case of errors after usb_get_intf() the reference should be putted to correclty free memory allocated for this interface. Fixes: ec16dae5453e ("V4L/DVB (7019): V4L: add support for Syntek DC1125 webcams") Cc: stable@vger.kernel.org Signed-off-by: Pavel Skripkin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-webcam.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index a45d464427c4c..0e231e576dc3d 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -1346,7 +1346,7 @@ static int stk_camera_probe(struct usb_interface *interface, if (!dev->isoc_ep) { pr_err("Could not find isoc-in endpoint\n"); err = -ENODEV; - goto error; + goto error_put; } dev->vsettings.palette = V4L2_PIX_FMT_RGB565; dev->vsettings.mode = MODE_VGA; @@ -1359,10 +1359,12 @@ static int stk_camera_probe(struct usb_interface *interface, err = stk_register_video_device(dev); if (err) - goto error; + goto error_put; return 0; +error_put: + usb_put_intf(interface); error: v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&dev->v4l2_dev); From 055d2db28ec2fa3ab5c527c5604f1b32b89fa13a Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Sat, 10 Jul 2021 14:04:32 +0200 Subject: [PATCH 094/195] media: platform: stm32: unprepare clocks at handling errors in probe stm32_cec_probe() did not unprepare clocks on error handling paths. The patch fixes that. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Evgeny Novikov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/platform/stm32/stm32-cec.c | 26 ++++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c index ea4b1ebfca991..0ffd89712536b 100644 --- a/drivers/media/cec/platform/stm32/stm32-cec.c +++ b/drivers/media/cec/platform/stm32/stm32-cec.c @@ -305,14 +305,16 @@ static int stm32_cec_probe(struct platform_device *pdev) cec->clk_hdmi_cec = devm_clk_get(&pdev->dev, "hdmi-cec"); if (IS_ERR(cec->clk_hdmi_cec) && - PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER) - return -EPROBE_DEFER; + PTR_ERR(cec->clk_hdmi_cec) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_unprepare_cec_clk; + } if (!IS_ERR(cec->clk_hdmi_cec)) { ret = clk_prepare(cec->clk_hdmi_cec); if (ret) { dev_err(&pdev->dev, "Can't prepare hdmi-cec clock\n"); - return ret; + goto err_unprepare_cec_clk; } } @@ -324,19 +326,27 @@ static int stm32_cec_probe(struct platform_device *pdev) CEC_NAME, caps, CEC_MAX_LOG_ADDRS); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) - return ret; + goto err_unprepare_hdmi_cec_clk; ret = cec_register_adapter(cec->adap, &pdev->dev); - if (ret) { - cec_delete_adapter(cec->adap); - return ret; - } + if (ret) + goto err_delete_adapter; cec_hw_init(cec); platform_set_drvdata(pdev, cec); return 0; + +err_delete_adapter: + cec_delete_adapter(cec->adap); + +err_unprepare_hdmi_cec_clk: + clk_unprepare(cec->clk_hdmi_cec); + +err_unprepare_cec_clk: + clk_unprepare(cec->clk_cec); + return ret; } static int stm32_cec_remove(struct platform_device *pdev) From e58430e1d4fd01b74475d2fbe2e25b5817b729a9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 13 Jul 2021 11:24:10 +0200 Subject: [PATCH 095/195] media: rockchip/rga: fix error handling in probe There are a few bugs in this code. 1) No checks for whether dma_alloc_attrs() or __get_free_pages() failed. 2) If video_register_device() fails it doesn't clean up the dma attrs or the free pages. 3) The video_device_release() function frees "vfd" which leads to a use after free on the next line. The call to video_unregister_device() is not required so I have just removed that. Fixes: f7e7b48e6d79 ("[media] rockchip/rga: v4l2 m2m support") Reported-by: Dongliang Mu Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rga/rga.c | 27 ++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index bf3fd71ec3aff..6759091b15e09 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -863,12 +863,12 @@ static int rga_probe(struct platform_device *pdev) if (IS_ERR(rga->m2m_dev)) { v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n"); ret = PTR_ERR(rga->m2m_dev); - goto unreg_video_dev; + goto rel_vdev; } ret = pm_runtime_resume_and_get(rga->dev); if (ret < 0) - goto unreg_video_dev; + goto rel_vdev; rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF; rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F; @@ -882,11 +882,23 @@ static int rga_probe(struct platform_device *pdev) rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE, &rga->cmdbuf_phy, GFP_KERNEL, DMA_ATTR_WRITE_COMBINE); + if (!rga->cmdbuf_virt) { + ret = -ENOMEM; + goto rel_vdev; + } rga->src_mmu_pages = (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + if (!rga->src_mmu_pages) { + ret = -ENOMEM; + goto free_dma; + } rga->dst_mmu_pages = (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + if (rga->dst_mmu_pages) { + ret = -ENOMEM; + goto free_src_pages; + } def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; def_frame.size = def_frame.stride * def_frame.height; @@ -894,7 +906,7 @@ static int rga_probe(struct platform_device *pdev) ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); if (ret) { v4l2_err(&rga->v4l2_dev, "Failed to register video device\n"); - goto rel_vdev; + goto free_dst_pages; } v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n", @@ -902,10 +914,15 @@ static int rga_probe(struct platform_device *pdev) return 0; +free_dst_pages: + free_pages((unsigned long)rga->dst_mmu_pages, 3); +free_src_pages: + free_pages((unsigned long)rga->src_mmu_pages, 3); +free_dma: + dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, rga->cmdbuf_virt, + rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE); rel_vdev: video_device_release(vfd); -unreg_video_dev: - video_unregister_device(rga->vfd); unreg_v4l2_dev: v4l2_device_unregister(&rga->v4l2_dev); err_put_clk: From fa0b5658597f1362c08c662a3a3c5139829e13a8 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 16 Jul 2021 21:17:33 +0200 Subject: [PATCH 096/195] media: ti-vpe: cal: fix indexing of cal->ctx[] in cal_probe() cal->ctx[i] is allocated with this loop for (i = 0; i < cal->data->num_csi2_phy; ++i) { and accessed in the error handler and else where with this loop for (i = 0; i < cal->num_contexts; i++) Because the first loop contains a continue statement before cal->num_contexts is incremented, using i as the indexer will leave gaps in the cal->ctx[]. So use cal->num_contexts as the indexer. Fixes: 75e7e58bfac1 ("media: ti-vpe: cal: support 8 DMA contexts") Signed-off-by: Tom Rix Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 05bdc6d126d82..8e469d518a742 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1148,9 +1148,9 @@ static int cal_probe(struct platform_device *pdev) if (!cal->phy[i]->source_node) continue; - cal->ctx[i] = cal_ctx_create(cal, i); - if (!cal->ctx[i]) { - cal_err(cal, "Failed to create context %u\n", i); + cal->ctx[cal->num_contexts] = cal_ctx_create(cal, i); + if (!cal->ctx[cal->num_contexts]) { + cal_err(cal, "Failed to create context %u\n", cal->num_contexts); ret = -ENODEV; goto error_context; } From 44693d74f5653f82cd7ca0fe730eed0f6b83306a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 19 Jul 2021 16:57:08 +0200 Subject: [PATCH 097/195] media: coda: fix frame_mem_ctrl for YUV420 and YVU420 formats The frame memory control register value is currently determined before userspace selects the final capture format and never corrected. Update ctx->frame_mem_ctrl in __coda_start_decoding() to fix decoding into YUV420 or YVU420 capture buffers. Reported-by: Andrej Picej Fixes: 497e6b8559a6 ("media: coda: add sequence initialization work") Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 2f42808c43a4b..c484c008ab027 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2053,17 +2053,25 @@ static int __coda_start_decoding(struct coda_ctx *ctx) u32 src_fourcc, dst_fourcc; int ret; + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + src_fourcc = q_data_src->fourcc; + dst_fourcc = q_data_dst->fourcc; + if (!ctx->initialized) { ret = __coda_decoder_seq_init(ctx); if (ret < 0) return ret; + } else { + ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | + CODA9_FRAME_TILED2LINEAR); + if (dst_fourcc == V4L2_PIX_FMT_NV12 || dst_fourcc == V4L2_PIX_FMT_YUYV) + ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ctx->frame_mem_ctrl |= (0x3 << 9) | + ((ctx->use_vdoa) ? 0 : CODA9_FRAME_TILED2LINEAR); } - q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - src_fourcc = q_data_src->fourcc; - dst_fourcc = q_data_dst->fourcc; - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); From e6f238735f63921175c5d8df2d7b21f8002eaa6a Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Thu, 18 Mar 2021 21:22:16 +0100 Subject: [PATCH 098/195] media: atomisp: Fix typo "accesible" Trivial fix. Link: https://lore.kernel.org/linux-media/20210318202223.164873-2-ribalda@chromium.org Signed-off-by: Ricardo Ribalda Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h | 2 +- drivers/staging/media/atomisp/pci/isp_acquisition_defs.h | 2 +- drivers/staging/media/atomisp/pci/isp_capture_defs.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h b/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h index c801ddd711924..b2076a96987c4 100644 --- a/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h +++ b/drivers/staging/media/atomisp/pci/input_system_ctrl_defs.h @@ -27,7 +27,7 @@ // Number of registers #define ISYS_CTRL_NOF_REGS 23 -// Register id's of MMIO slave accesible registers +// Register id's of MMIO slave accessible registers #define ISYS_CTRL_CAPT_START_ADDR_A_REG_ID 0 #define ISYS_CTRL_CAPT_START_ADDR_B_REG_ID 1 #define ISYS_CTRL_CAPT_START_ADDR_C_REG_ID 2 diff --git a/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h b/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h index 8e4bddc3790d1..7e8f6f2178aa8 100644 --- a/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h +++ b/drivers/staging/media/atomisp/pci/isp_acquisition_defs.h @@ -35,7 +35,7 @@ #define NOF_ACQ_REGS 12 -// Register id's of MMIO slave accesible registers +// Register id's of MMIO slave accessible registers #define ACQ_START_ADDR_REG_ID 0 #define ACQ_MEM_REGION_SIZE_REG_ID 1 #define ACQ_NUM_MEM_REGIONS_REG_ID 2 diff --git a/drivers/staging/media/atomisp/pci/isp_capture_defs.h b/drivers/staging/media/atomisp/pci/isp_capture_defs.h index 14cbb6390d3e4..b9e5ed932702f 100644 --- a/drivers/staging/media/atomisp/pci/isp_capture_defs.h +++ b/drivers/staging/media/atomisp/pci/isp_capture_defs.h @@ -33,7 +33,7 @@ // Number of registers #define CAPT_NOF_REGS 16 -// Register id's of MMIO slave accesible registers +// Register id's of MMIO slave accessible registers #define CAPT_START_MODE_REG_ID 0 #define CAPT_START_ADDR_REG_ID 1 #define CAPT_MEM_REGION_SIZE_REG_ID 2 From fe8e320d8bf7596123d160d7fce6a1ea6e0761ca Mon Sep 17 00:00:00 2001 From: Bhaskar Chowdhury Date: Wed, 24 Mar 2021 14:56:42 +0100 Subject: [PATCH 099/195] media: atomisp-ov2680: A trivial typo fix s/miror/mirror/ Link: https://lore.kernel.org/linux-media/20210324135642.30054-1-unixbhaskar@gmail.com Signed-off-by: Bhaskar Chowdhury Acked-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/ov2680.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 4d43b45915e56..874115f35fcad 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -627,7 +627,7 @@ static struct ov2680_reg const ov2680_1296x976_30fps[] = { {0x5706, 0x0c}, {0x5707, 0x78}, {0x3820, 0xc0}, - {0x3821, 0x00}, //miror/flip + {0x3821, 0x00}, //mirror/flip // {0x5090, 0x0c}, {} }; From 672fe1cf145ab9978c62eb827d6a16aa6b63994b Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Thu, 8 Apr 2021 10:18:43 +0200 Subject: [PATCH 100/195] media: atomisp: Fix runtime PM imbalance in atomisp_pci_probe When hmm_pool_register() fails, a pairing PM usage counter increment is needed to keep the counter balanced. It's the same for the following error paths. Link: https://lore.kernel.org/linux-media/20210408081850.24278-1-dinghao.liu@zju.edu.cn Signed-off-by: Dinghao Liu Acked-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_v4l2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 948769ca6539d..af0d83eaa68c2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -1815,6 +1815,7 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i hmm_cleanup(); hmm_pool_unregister(HMM_POOL_TYPE_RESERVED); hmm_pool_fail: + pm_runtime_get_noresume(&pdev->dev); destroy_workqueue(isp->wdt_work_queue); wdt_work_queue_fail: atomisp_acc_cleanup(isp); From 24d4fbdc9a8553c3f433e6f390fa9959aaba3e32 Mon Sep 17 00:00:00 2001 From: Dmitrii Wolf Date: Sun, 11 Apr 2021 15:48:41 +0200 Subject: [PATCH 101/195] media: atomisp: pci: fixed a curly bracket coding style issue. Fixed a coding style issue. Link: https://lore.kernel.org/linux-media/20210411134840.7184-1-dev.dragon@bk.ru Signed-off-by: Dmitrii Wolf Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_csi2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp_csi2.c index 56456e59bf893..11b6b12164738 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_csi2.c @@ -28,7 +28,8 @@ static struct v4l2_mbus_framefmt *__csi2_get_format(struct struct v4l2_subdev_state *sd_state, enum v4l2_subdev_format_whence - which, unsigned int pad) { + which, unsigned int pad) +{ if (which == V4L2_SUBDEV_FORMAT_TRY) return v4l2_subdev_get_try_format(&csi2->subdev, sd_state, pad); From 9763267eda9d424f69e17d322df388af6f3756d0 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Sat, 8 May 2021 15:17:12 +0200 Subject: [PATCH 102/195] media: atomisp: remove useless breaks Breaks are not useful after a return, they can simply be removed. Link: https://lore.kernel.org/linux-media/4b4a6ad1bc8fc1fd6aafc3e6cd7a4969890340c1.1620479607.git.paskripkin@gmail.com Signed-off-by: Pavel Skripkin Signed-off-by: Mauro Carvalho Chehab --- .../pci/hive_isp_css_common/host/input_system.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index 0f5a231672a8e..fd82997b11cc9 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -904,16 +904,12 @@ static input_system_err_t input_system_configure_channel( break; case INPUT_SYSTEM_SOURCE_TPG: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; case INPUT_SYSTEM_SOURCE_PRBS: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; case INPUT_SYSTEM_SOURCE_FIFO: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } if (error != INPUT_SYSTEM_ERR_NO_ERROR) return error; @@ -995,7 +991,6 @@ static input_system_err_t input_buffer_configuration(void) default: config.csi_buffer_flags[port] |= INPUT_SYSTEM_CFG_FLAG_CONFLICT; return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } // Check acquisition buffer specified but set it later since it has to be unique. @@ -1032,7 +1027,6 @@ static input_system_err_t input_buffer_configuration(void) default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } } else { config.csi_buffer_flags[port] = INPUT_SYSTEM_CFG_FLAG_BLOCKED; @@ -1319,7 +1313,6 @@ static input_system_err_t configuration_to_registers(void) default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } // end of switch (source_type) @@ -1696,16 +1689,12 @@ static input_system_err_t input_system_configure_channel_sensor( break; case INPUT_SYSTEM_FIFO_CAPTURE_WITH_COUNTING: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; case INPUT_SYSTEM_XMEM_CAPTURE: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; case INPUT_SYSTEM_XMEM_ACQUIRE: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; - break; } return INPUT_SYSTEM_ERR_NO_ERROR; } From 728a5c64ae5fef9524528153b290b7d4a4e56043 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Sat, 8 May 2021 15:17:20 +0200 Subject: [PATCH 103/195] media: atomisp: remove dublicate code Removed dublicate returns and breaks inside switch statements and useless return after switch. Link: https://lore.kernel.org/linux-media/3944cd10bb5a64157781b1e0ef044c62c05f07c7.1620479607.git.paskripkin@gmail.com Signed-off-by: Pavel Skripkin Signed-off-by: Mauro Carvalho Chehab --- .../pci/hive_isp_css_common/host/input_system.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index fd82997b11cc9..76414b6b43c9f 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -903,11 +903,8 @@ static input_system_err_t input_system_configure_channel( error = input_system_configure_channel_sensor(channel); break; case INPUT_SYSTEM_SOURCE_TPG: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; case INPUT_SYSTEM_SOURCE_PRBS: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; case INPUT_SYSTEM_SOURCE_FIFO: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; } @@ -1301,13 +1298,7 @@ static input_system_err_t configuration_to_registers(void) break; case INPUT_SYSTEM_SOURCE_TPG: - - break; - case INPUT_SYSTEM_SOURCE_PRBS: - - break; - case INPUT_SYSTEM_SOURCE_FIFO: break; @@ -1688,15 +1679,11 @@ static input_system_err_t input_system_configure_channel_sensor( break; case INPUT_SYSTEM_FIFO_CAPTURE_WITH_COUNTING: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; case INPUT_SYSTEM_XMEM_CAPTURE: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; case INPUT_SYSTEM_XMEM_ACQUIRE: - return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; default: return INPUT_SYSTEM_ERR_PARAMETER_NOT_SUPPORTED; } - return INPUT_SYSTEM_ERR_NO_ERROR; } // Test flags and set structure. From 264f590899146baa19e0ab5689e55fadbc292333 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Sat, 8 May 2021 15:17:27 +0200 Subject: [PATCH 104/195] media: atomisp: remove useless returns Returns are not useful at the end of void functions, they can simply be removed. Link: https://lore.kernel.org/linux-media/23a6984ddfb15ba38f6983381bb6fdaef3edd7d8.1620479607.git.paskripkin@gmail.com Signed-off-by: Pavel Skripkin Signed-off-by: Mauro Carvalho Chehab --- .../hive_isp_css_common/host/input_system.c | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c index 76414b6b43c9f..8e085dda0c18d 100644 --- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/input_system.c @@ -174,8 +174,6 @@ void input_system_get_state( ctrl_unit_get_state(ID, sub_id, &state->ctrl_unit_state[sub_id - CTRL_UNIT0_ID]); } - - return; } void receiver_get_state( @@ -246,8 +244,6 @@ void receiver_get_state( _HRT_CSS_RECEIVER_BE_IRQ_STATUS_REG_IDX); state->be_irq_clear = receiver_reg_load(ID, _HRT_CSS_RECEIVER_BE_IRQ_CLEAR_REG_IDX); - - return; } bool is_mipi_format_yuv420( @@ -310,8 +306,6 @@ void receiver_set_compression( reg = ((field_id < 6) ? (val << (field_id * 5)) : (val << (( field_id - 6) * 5))); receiver_reg_store(ID, addr, reg); - - return; } void receiver_port_enable( @@ -330,7 +324,6 @@ void receiver_port_enable( receiver_port_reg_store(ID, port_ID, _HRT_CSS_RECEIVER_DEVICE_READY_REG_IDX, reg); - return; } bool is_receiver_port_enabled( @@ -349,7 +342,6 @@ void receiver_irq_enable( { receiver_port_reg_store(ID, port_ID, _HRT_CSS_RECEIVER_IRQ_ENABLE_REG_IDX, irq_info); - return; } rx_irq_info_t receiver_get_irq_info( @@ -367,7 +359,6 @@ void receiver_irq_clear( { receiver_port_reg_store(ID, port_ID, _HRT_CSS_RECEIVER_IRQ_STATUS_REG_IDX, irq_info); - return; } static inline void capture_unit_get_state( @@ -428,8 +419,6 @@ static inline void capture_unit_get_state( state->FSM_State_Info = input_system_sub_system_reg_load(ID, sub_id, CAPT_FSM_STATE_INFO_REG_ID); - - return; } static inline void acquisition_unit_get_state( @@ -478,8 +467,6 @@ static inline void acquisition_unit_get_state( state->Int_Cntr_Info = input_system_sub_system_reg_load(ID, sub_id, ACQ_INT_CNTR_INFO_REG_ID); - - return; } static inline void ctrl_unit_get_state( @@ -561,8 +548,6 @@ static inline void ctrl_unit_get_state( state->capt_reserve_one_mem_region = input_system_sub_system_reg_load(ID, sub_id, ISYS_CTRL_CAPT_RESERVE_ONE_MEM_REGION_REG_ID); - - return; } static inline void mipi_port_get_state( @@ -597,8 +582,6 @@ static inline void mipi_port_get_state( state->lane_sync_count[i] = (uint8_t)((state->sync_count) >> (i * 8)); state->lane_rx_count[i] = (uint8_t)((state->rx_count) >> (i * 8)); } - - return; } static inline void rx_channel_get_state( @@ -652,8 +635,6 @@ static inline void rx_channel_get_state( state->comp[i] = (mipi_compressor_t)(val & 0x07); state->pred[i] = (mipi_predictor_t)((val & 0x18) >> 3); } - - return; } // MW: "2400" in the name is not good, but this is to avoid a naming conflict @@ -672,8 +653,6 @@ static void receiver_rst( } // AM: Additional actions for stopping receiver? - - return; } //Single function to reset all the devices mapped via GP_DEVICE. @@ -722,8 +701,6 @@ static void gp_device_rst(const gp_device_ID_t ID) // gp_device_reg_store(ID, _REG_GP_SYNCGEN_FRAME_CNT_ADDR, ZERO); gp_device_reg_store(ID, _REG_GP_SOFT_RESET_ADDR, ZERO); // AM: Maybe this soft reset is not safe. - - return; } static void input_selector_cfg_for_sensor(const gp_device_ID_t ID) @@ -740,8 +717,6 @@ static void input_selector_cfg_for_sensor(const gp_device_ID_t ID) gp_device_reg_store(ID, _REG_GP_ISEL_SBAND_SEL_ADDR, ZERO); gp_device_reg_store(ID, _REG_GP_ISEL_SYNC_SEL_ADDR, ZERO); gp_device_reg_store(ID, _REG_GP_SOFT_RESET_ADDR, ZERO); - - return; } static void input_switch_rst(const gp_device_ID_t ID) @@ -760,8 +735,6 @@ static void input_switch_rst(const gp_device_ID_t ID) gp_device_reg_store(ID, _REG_GP_IFMT_input_switch_fsync_lut, ZERO); - - return; } static void input_switch_cfg( @@ -786,8 +759,6 @@ static void input_switch_cfg( gp_device_reg_store(ID, _REG_GP_IFMT_input_switch_fsync_lut, cfg->vsync_data_reg); - - return; } static void input_system_network_rst(const input_system_ID_t ID) @@ -843,8 +814,6 @@ static void input_system_network_rst(const input_system_ID_t ID) ISYS_CTRL_INIT_REG_ID, 1U); //AM: Is there any named constant? } - - return; } // Function that resets current configuration. @@ -1072,8 +1041,6 @@ static void capture_unit_configure( sub_id, CAPT_NUM_MEM_REGIONS_REG_ID, cfg->nof_mem_regs); - - return; } static void acquisition_unit_configure( @@ -1097,8 +1064,6 @@ static void acquisition_unit_configure( sub_id, ACQ_MEM_REGION_SIZE_REG_ID, cfg->mem_reg_size); - - return; } static void ctrl_unit_configure( @@ -1165,7 +1130,6 @@ static void ctrl_unit_configure( sub_id, ISYS_CTRL_CAPT_RESERVE_ONE_MEM_REGION_REG_ID, 0); - return; } static void input_system_network_configure( @@ -1223,8 +1187,6 @@ static void input_system_network_configure( sub_id, &cfg->ctrl_unit_cfg[sub_id - CTRL_UNIT0_ID]); } - - return; } static input_system_err_t configuration_to_registers(void) From c275e5d349b0d2b1143607d28b9c7c14a8a0a9b4 Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Fri, 25 Jun 2021 07:38:56 +0200 Subject: [PATCH 105/195] media: atomisp: fix the uninitialized use and rename "retvalue" Inside function mt9m114_detect(), variable "retvalue" could be uninitialized if mt9m114_read_reg() returns error, however, it is used in the later if statement, which is potentially unsafe. The local variable "retvalue" is renamed to "model" to avoid confusion. Link: https://lore.kernel.org/linux-media/20210625053858.3862-1-yzhai003@ucr.edu Fixes: ad85094 (media / atomisp: fix the uninitialized use of model ID) Signed-off-by: Yizhuo Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 11196180a2066..34bf92de2f29b 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -1545,16 +1545,19 @@ static struct v4l2_ctrl_config mt9m114_controls[] = { static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - u32 retvalue; + u32 model; + int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "%s: i2c error", __func__); return -ENODEV; } - mt9m114_read_reg(client, MISENSOR_16BIT, (u32)MT9M114_PID, &retvalue); - dev->real_model_id = retvalue; + ret = mt9m114_read_reg(client, MISENSOR_16BIT, MT9M114_PID, &model); + if (ret) + return ret; + dev->real_model_id = model; - if (retvalue != MT9M114_MOD_ID) { + if (model != MT9M114_MOD_ID) { dev_err(&client->dev, "%s: failed: client->addr = %x\n", __func__, client->addr); return -ENODEV; From 9d971b81359837ed05f466afa7c8df5d5f94786f Mon Sep 17 00:00:00 2001 From: Baokun Li Date: Thu, 17 Jun 2021 16:09:26 +0200 Subject: [PATCH 106/195] media: atomisp: use list_splice_init in atomisp_compat_css20.c Using list_splice_init() instead of entire while-loops in atomisp_compat_css20.c. Link: https://lore.kernel.org/linux-media/20210617140926.887680-1-libaokun1@huawei.com Reported-by: Hulk Robot Signed-off-by: Baokun Li Reviewed-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp_compat_css20.c | 38 +++---------------- 1 file changed, 5 insertions(+), 33 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index f60198bb8a1a9..99a632f33d2d6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -2102,9 +2102,6 @@ void atomisp_css_stop(struct atomisp_sub_device *asd, enum ia_css_pipe_id pipe_id, bool in_reset) { struct atomisp_device *isp = asd->isp; - struct atomisp_s3a_buf *s3a_buf; - struct atomisp_dis_buf *dis_buf; - struct atomisp_metadata_buf *md_buf; unsigned long irqflags; unsigned int i; @@ -2144,42 +2141,17 @@ void atomisp_css_stop(struct atomisp_sub_device *asd, } /* move stats buffers to free queue list */ - while (!list_empty(&asd->s3a_stats_in_css)) { - s3a_buf = list_entry(asd->s3a_stats_in_css.next, - struct atomisp_s3a_buf, list); - list_del(&s3a_buf->list); - list_add_tail(&s3a_buf->list, &asd->s3a_stats); - } - while (!list_empty(&asd->s3a_stats_ready)) { - s3a_buf = list_entry(asd->s3a_stats_ready.next, - struct atomisp_s3a_buf, list); - list_del(&s3a_buf->list); - list_add_tail(&s3a_buf->list, &asd->s3a_stats); - } + list_splice_init(&asd->s3a_stats_in_css, &asd->s3a_stats); + list_splice_init(&asd->s3a_stats_ready, &asd->s3a_stats); spin_lock_irqsave(&asd->dis_stats_lock, irqflags); - while (!list_empty(&asd->dis_stats_in_css)) { - dis_buf = list_entry(asd->dis_stats_in_css.next, - struct atomisp_dis_buf, list); - list_del(&dis_buf->list); - list_add_tail(&dis_buf->list, &asd->dis_stats); - } + list_splice_init(&asd->dis_stats_in_css, &asd->dis_stats); asd->params.dis_proj_data_valid = false; spin_unlock_irqrestore(&asd->dis_stats_lock, irqflags); for (i = 0; i < ATOMISP_METADATA_TYPE_NUM; i++) { - while (!list_empty(&asd->metadata_in_css[i])) { - md_buf = list_entry(asd->metadata_in_css[i].next, - struct atomisp_metadata_buf, list); - list_del(&md_buf->list); - list_add_tail(&md_buf->list, &asd->metadata[i]); - } - while (!list_empty(&asd->metadata_ready[i])) { - md_buf = list_entry(asd->metadata_ready[i].next, - struct atomisp_metadata_buf, list); - list_del(&md_buf->list); - list_add_tail(&md_buf->list, &asd->metadata[i]); - } + list_splice_init(&asd->metadata_in_css[i], &asd->metadata[i]); + list_splice_init(&asd->metadata_ready[i], &asd->metadata[i]); } atomisp_flush_params_queue(&asd->video_out_capture); From 7f52dbb8f7e9de24412bf1a1b935000f9c1ea884 Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Sun, 9 May 2021 01:56:19 +0200 Subject: [PATCH 107/195] media: atomisp: Resolve goto style issue in sh_css.c Change the goto label to lower case. Remove a space in the goto label. Link: https://lore.kernel.org/linux-media/20210508235622.300394-2-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index d26b1301eeb7e..53c1001b807bc 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -5170,7 +5170,7 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, if (binary) { err = ia_css_binary_3a_grid_info(binary, info, pipe); if (err) - goto ERR; + goto err; } else { memset(&info->s3a_grid, 0, sizeof(info->s3a_grid)); } @@ -5195,7 +5195,7 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, info->vamem_type = IA_CSS_VAMEM_TYPE_2; -ERR : +err: IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } From f6e2a76d443c5f778dc4b22ea1560be97ee8931c Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Sun, 9 May 2021 01:56:20 +0200 Subject: [PATCH 108/195] media: atomisp: Remove unnecessary parens in sh_css.c Remove unnecessary parenthesis. Link: https://lore.kernel.org/linux-media/20210508235622.300394-3-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 53c1001b807bc..51fe939a89589 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -10162,7 +10162,7 @@ ia_css_stop_sp(void) timeout--; udelay(1); } - if ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED)) + if (ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED) IA_CSS_WARNING("SP has not terminated (SW)"); if (timeout == 0) { From 00ba215607e2f6015932b45c9b8e5b022424012c Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Sun, 9 May 2021 01:56:21 +0200 Subject: [PATCH 109/195] media: atomisp: Use kcalloc instead of kzalloc with multiply in sh_css.c Use kcalloc instead of kzalloc with multiplication. Link: https://lore.kernel.org/linux-media/20210508235622.300394-4-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 51fe939a89589..b8dd817616e89 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -5328,14 +5328,15 @@ static int load_video_binaries(struct ia_css_pipe *pipe) if (err) return err; mycs->num_yuv_scaler = cas_scaler_descr.num_stage; - mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * - sizeof(struct ia_css_binary), GFP_KERNEL); + mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, + sizeof(struct ia_css_binary), + GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; return err; } - mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage - * sizeof(bool), GFP_KERNEL); + mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, + sizeof(bool), GFP_KERNEL); if (!mycs->is_output_stage) { err = -ENOMEM; return err; @@ -5938,14 +5939,15 @@ static int load_primary_binaries( return err; } mycs->num_yuv_scaler = cas_scaler_descr.num_stage; - mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * - sizeof(struct ia_css_binary), GFP_KERNEL); + mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, + sizeof(struct ia_css_binary), + GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } - mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * + mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, sizeof(bool), GFP_KERNEL); if (!mycs->is_output_stage) { err = -ENOMEM; @@ -6989,14 +6991,14 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) goto ERR; mycs->num_output = cas_scaler_descr.num_output_stage; mycs->num_yuv_scaler = cas_scaler_descr.num_stage; - mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * + mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, sizeof(struct ia_css_binary), GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; goto ERR; } - mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * + mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, sizeof(bool), GFP_KERNEL); if (!mycs->is_output_stage) { err = -ENOMEM; @@ -7097,7 +7099,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) mycs->num_vf_pp = 1; } - mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp * + mycs->vf_pp_binary = kcalloc(mycs->num_vf_pp, sizeof(struct ia_css_binary), GFP_KERNEL); if (!mycs->vf_pp_binary) { From 6b6d22831331434b6a1b5b557bc235ca9df420e0 Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Sun, 9 May 2021 01:56:22 +0200 Subject: [PATCH 110/195] media: atomisp: Fix line continuation style issue in sh_css.c Fix logical continuation style issue and adjacent line splits. Link: https://lore.kernel.org/linux-media/20210508235622.300394-5-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index b8dd817616e89..5dac4a506b002 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -3224,24 +3224,22 @@ init_vf_frameinfo_defaults(struct ia_css_pipe *pipe, #ifdef ISP2401 static unsigned int -get_crop_lines_for_bayer_order( - const struct ia_css_stream_config *config) +get_crop_lines_for_bayer_order(const struct ia_css_stream_config *config) { assert(config); - if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) - || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) + if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) || + (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) return 1; return 0; } static unsigned int -get_crop_columns_for_bayer_order( - const struct ia_css_stream_config *config) +get_crop_columns_for_bayer_order(const struct ia_css_stream_config *config) { assert(config); - if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) - || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) + if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) || + (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) return 1; return 0; From 2c08a018f0d5f3902d4e1cbf99e3858477ac0515 Mon Sep 17 00:00:00 2001 From: Nguyen Dinh Phi Date: Thu, 13 May 2021 05:46:50 +0200 Subject: [PATCH 111/195] media: atomisp: Use sysfs_emit() instead of sprintf() where appropriate sysfs_emit() is preferred over raw sprintf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in sanity checks. Link: https://lore.kernel.org/linux-media/20210513034650.252993-1-phind.uet@gmail.com Signed-off-by: Nguyen Dinh Phi Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_drvfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c index f670faf978e6e..dcb571f515a71 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c +++ b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c @@ -96,7 +96,7 @@ static inline int iunit_dump_dbgopt(struct atomisp_device *isp, static ssize_t iunit_dbglvl_show(struct device_driver *drv, char *buf) { iunit_debug.dbglvl = dbg_level; - return sprintf(buf, "dtrace level:%u\n", iunit_debug.dbglvl); + return sysfs_emit(buf, "dtrace level:%u\n", iunit_debug.dbglvl); } static ssize_t iunit_dbglvl_store(struct device_driver *drv, const char *buf, @@ -115,7 +115,7 @@ static ssize_t iunit_dbglvl_store(struct device_driver *drv, const char *buf, static ssize_t iunit_dbgfun_show(struct device_driver *drv, char *buf) { iunit_debug.dbgfun = atomisp_get_css_dbgfunc(); - return sprintf(buf, "dbgfun opt:%u\n", iunit_debug.dbgfun); + return sysfs_emit(buf, "dbgfun opt:%u\n", iunit_debug.dbgfun); } static ssize_t iunit_dbgfun_store(struct device_driver *drv, const char *buf, @@ -139,7 +139,7 @@ static ssize_t iunit_dbgfun_store(struct device_driver *drv, const char *buf, static ssize_t iunit_dbgopt_show(struct device_driver *drv, char *buf) { - return sprintf(buf, "option:0x%x\n", iunit_debug.dbgopt); + return sysfs_emit(buf, "option:0x%x\n", iunit_debug.dbgopt); } static ssize_t iunit_dbgopt_store(struct device_driver *drv, const char *buf, From 95d2117cfe77eb3f9af4981a54f0fd8b17fec1cc Mon Sep 17 00:00:00 2001 From: Jiabing Wan Date: Tue, 18 May 2021 13:29:35 +0200 Subject: [PATCH 112/195] media: atomisp: Align block comments Fixing the following checkpatch warning: WARNING: Block comments should align the * on each line Link: https://lore.kernel.org/linux-media/20210518112938.88240-1-wanjiabing@vivo.com Signed-off-by: Jiabing Wan Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h index be3534e46c15d..9b22f2da45d56 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h @@ -17,8 +17,8 @@ #define __IA_CSS_ANR_TYPES_H /* @file -* CSS-API header file for Advanced Noise Reduction kernel v1 -*/ + * CSS-API header file for Advanced Noise Reduction kernel v1 + */ /* Application specific DMA settings */ #define ANR_BPP 10 From f89aa0d174b3e7f2988a976125c3a67a07b71040 Mon Sep 17 00:00:00 2001 From: Aniket Bhattacharyea Date: Mon, 24 May 2021 19:36:09 +0200 Subject: [PATCH 113/195] media: atomisp: Fix whitespace at the beginning of line This patch fixes whitespace at the beginning of line by wrapping after the type name and aligning the arguments with the open parenthesis. Identified by checkpatch: WARNING: please, no spaces at the start of a line. Link: https://lore.kernel.org/linux-media/20210524173609.672153-1-aniketmail669@gmail.com Signed-off-by: Aniket Bhattacharyea Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 135994d44802c..d8c9e31314b2e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -1040,10 +1040,10 @@ static struct camera_sensor_platform_data acpi_gmin_plat = { .get_vcm_ctrl = gmin_get_vcm_ctrl, }; -struct camera_sensor_platform_data *gmin_camera_platform_data( - struct v4l2_subdev *subdev, - enum atomisp_input_format csi_format, - enum atomisp_bayer_order csi_bayer) +struct camera_sensor_platform_data * +gmin_camera_platform_data(struct v4l2_subdev *subdev, + enum atomisp_input_format csi_format, + enum atomisp_bayer_order csi_bayer) { u8 pmic_i2c_addr = gmin_detect_pmic(subdev); struct gmin_subdev *gs; From 544ee7306d9e3a7ff675e87f151723ff30efd9a1 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 21 May 2021 21:48:05 +0200 Subject: [PATCH 114/195] media: atomisp: improve error handling in gc2235_detect() Static analysis reports this representative problem atomisp-gc2235.c:867:20: warning: The right operand of '|' is a garbage value id = ((high << 8) | low); ^ ~~~ When gc2235_read_reg() fails, its return val is never written. For gc2235_detect(), high and low are or-ed and compared with GC2235_ID, 0x2235. Initialize both to 0 and skip checking the read returns, it's errors are not passed up, only -ENODEV is. Link: https://lore.kernel.org/linux-media/20210521194805.2078135-1-trix@redhat.com Signed-off-by: Tom Rix Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 9363c1a52ae9b..4d769590f2d32 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -849,21 +849,14 @@ static int gc2235_get_fmt(struct v4l2_subdev *sd, static int gc2235_detect(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; + u16 high = 0, low = 0; u16 id; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_L, &low); + gc2235_read_reg(client, GC2235_8BIT, GC2235_SENSOR_ID_H, &high); + gc2235_read_reg(client, GC2235_8BIT, GC2235_SENSOR_ID_L, &low); id = ((high << 8) | low); if (id != GC2235_ID) { From d741db71cf1dfca2c12651197be6e910d40ff12f Mon Sep 17 00:00:00 2001 From: Shaokun Zhang Date: Tue, 25 May 2021 08:02:39 +0200 Subject: [PATCH 115/195] media: atomisp: remove the repeated declaration Function 'ia_css_mmu_invalidate_cache' is declared twice, remove the repeated declaration. Link: https://lore.kernel.org/linux-media/1621922559-1859-1-git-send-email-zhangshaokun@hisilicon.com Signed-off-by: Shaokun Zhang Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_compat.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat.h b/drivers/staging/media/atomisp/pci/atomisp_compat.h index a60551450c452..c16eaf3d126f7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat.h +++ b/drivers/staging/media/atomisp/pci/atomisp_compat.h @@ -83,8 +83,6 @@ int atomisp_q_dis_buffer_to_css(struct atomisp_sub_device *asd, void ia_css_mmu_invalidate_cache(void); -void ia_css_mmu_invalidate_cache(void); - int atomisp_css_start(struct atomisp_sub_device *asd, enum ia_css_pipe_id pipe_id, bool in_reset); From 8e38adf99d2fc216b0f9a059a2054f673cbfe1a7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 May 2021 14:43:19 +0200 Subject: [PATCH 116/195] media: atomisp: Remove unused declarations There is a few static declarations that are not used anywhere, remove them. Link: https://lore.kernel.org/linux-media/20210526124322.48915-3-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/pci/isp2400_input_system_local.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 072a92199e052..27f3c8a45730a 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -362,23 +362,6 @@ static const hrt_address MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { 0x00000200UL }; -static const mipi_lane_cfg_t MIPI_PORT_MAXLANES[N_MIPI_PORT_ID] = { - MIPI_4LANE_CFG, - MIPI_1LANE_CFG, - MIPI_2LANE_CFG -}; - -static const bool MIPI_PORT_ACTIVE[N_RX_MODE][N_MIPI_PORT_ID] = { - {true, true, false}, - {true, true, false}, - {true, true, false}, - {true, true, false}, - {true, true, true}, - {true, true, true}, - {true, true, true}, - {true, true, true} -}; - static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, From 86d92c3ad7179df2ee082e31138f00ca26db7572 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 May 2021 14:43:20 +0200 Subject: [PATCH 117/195] media: atomisp: Annotate a couple of definitions with __maybe_unused There are definitions in the header that are not used by all modules inside the driver. Annotate them with __maybe_unused to avoid compiler warnings. Link: https://lore.kernel.org/linux-media/20210526124322.48915-4-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/isp2400_input_system_local.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 27f3c8a45730a..21f11bdfc85f3 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -356,7 +356,7 @@ struct rx_cfg_s { }; /* NOTE: The base has already an offset of 0x0100 */ -static const hrt_address MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { +static const hrt_address __maybe_unused MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { 0x00000000UL, 0x00000100UL, 0x00000200UL @@ -373,7 +373,7 @@ static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG} }; -static const hrt_address SUB_SYSTEM_OFFSET[N_SUB_SYSTEM_ID] = { +static const hrt_address __maybe_unused SUB_SYSTEM_OFFSET[N_SUB_SYSTEM_ID] = { 0x00001000UL, 0x00002000UL, 0x00003000UL, From a5d46d9afbdf9d1755d421052dcdeaf2f3725f52 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 May 2021 14:43:22 +0200 Subject: [PATCH 118/195] media: atomisp: Remove unused port_enabled variable Remove unused port_enabled variable in ia_css_isys_rx_configure(). Link: https://lore.kernel.org/linux-media/20210526124322.48915-6-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index 4a18da6bf0c15..60b98c10a3bc5 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -479,7 +479,6 @@ unsigned int ia_css_csi2_calculate_input_system_alignment( void ia_css_isys_rx_configure(const rx_cfg_t *config, const enum ia_css_input_mode input_mode) { - bool port_enabled[N_MIPI_PORT_ID]; bool any_port_enabled = false; enum mipi_port_id port; @@ -516,8 +515,6 @@ void ia_css_isys_rx_configure(const rx_cfg_t *config, _HRT_CSS_RECEIVER_2400_RX_COUNT_REG_IDX, config->rxcount); - port_enabled[port] = true; - if (input_mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { /* MW: A bit of a hack, straight wiring of the capture * units,assuming they are linearly enumerated. */ From 179b1fce5d80f7d1b075bf9cb00cb78cb16ea09c Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Thu, 27 May 2021 21:39:22 +0200 Subject: [PATCH 119/195] media: atomisp: pci: Remove checks before kfree/kvfree Removed checks for pointers != NULL before freeing memory. If kvfree() and kfree() are given NULL pointers no operations are performed, so there is no need for the above-mentioned checks. Coccinelle detected the second of the two unnecessary checks. Link: https://lore.kernel.org/linux-media/20210527193922.25225-1-fmdefrancesco@gmail.com Signed-off-by: Fabio M. De Francesco Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css_firmware.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/sh_css_firmware.c index f4ce8ace9d509..5301cc014c7e6 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/sh_css_firmware.c @@ -363,10 +363,8 @@ void sh_css_unload_firmware(void) unsigned int i = 0; for (i = 0; i < sh_css_num_binaries; i++) { - if (fw_minibuffer[i].name) - kfree((void *)fw_minibuffer[i].name); - if (fw_minibuffer[i].buffer) - kvfree(fw_minibuffer[i].buffer); + kfree((void *)fw_minibuffer[i].name); + kvfree(fw_minibuffer[i].buffer); } kfree(fw_minibuffer); fw_minibuffer = NULL; From 655ace3c74fbafe0c2d331109412c62cc56006a1 Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Sat, 5 Jun 2021 04:08:55 +0200 Subject: [PATCH 120/195] media: atomisp: pci: Remove unnecessary (void *) cast Removed an unnecessary (void *) cast for an argument passed to kfree(). Link: https://lore.kernel.org/linux-media/20210605020855.1065-3-fmdefrancesco@gmail.com Suggested-by: Dan Carpenter Signed-off-by: Fabio M. De Francesco Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css_firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/sh_css_firmware.c index 5301cc014c7e6..e1a16a50e5884 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/sh_css_firmware.c @@ -363,7 +363,7 @@ void sh_css_unload_firmware(void) unsigned int i = 0; for (i = 0; i < sh_css_num_binaries; i++) { - kfree((void *)fw_minibuffer[i].name); + kfree(fw_minibuffer[i].name); kvfree(fw_minibuffer[i].buffer); } kfree(fw_minibuffer); From d14e272958bdfdc40dcafb827d24ba6fdafa9d52 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 17 Jun 2021 09:23:29 +0200 Subject: [PATCH 121/195] media: atomisp: pci: fix error return code in atomisp_pci_probe() If init_atomisp_wdts() fails, atomisp_pci_probe() need return error code. Link: https://lore.kernel.org/linux-media/20210617072329.1233662-1-yangyingliang@huawei.com Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_v4l2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index af0d83eaa68c2..1e324f1f656e5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -1763,7 +1763,8 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i if (err < 0) goto register_entities_fail; /* init atomisp wdts */ - if (init_atomisp_wdts(isp) != 0) + err = init_atomisp_wdts(isp); + if (err != 0) goto wdt_work_queue_fail; /* save the iunit context only once after all the values are init'ed. */ From 1d74a91dc5c8400302e5c6269093135994e30939 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 11 Jul 2021 16:51:01 +0200 Subject: [PATCH 122/195] media: atomisp: Perform a single memset() for union There is no need to memset() both dvs_grid_info and dvs_stat_grid_info separately: they are part of the same union. Instead, just zero the union itself. This additionally avoids a false positive (due to a gcc optimization bug[1]) when building with the coming FORTIFY_SOURCE improvements: In function 'fortify_memset_chk', inlined from 'sh_css_pipe_get_grid_info' at drivers/staging/media/atomisp/pci/sh_css.c:5186:3, inlined from 'ia_css_stream_create' at drivers/staging/media/atomisp/pci/sh_css.c:9442:10: ./include/linux/fortify-string.h:199:4: warning: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Wattribute-warning] 199 | __write_overflow_field(); | ^~~~~~~~~~~~~~~~~~~~~~~~ [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101419 Link: https://lore.kernel.org/linux-media/20210711145101.1434065-1-keescook@chromium.org Signed-off-by: Kees Cook Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 5dac4a506b002..c4b35cbab3737 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -5179,10 +5179,7 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, ia_css_binary_dvs_grid_info(binary, info, pipe); ia_css_binary_dvs_stat_grid_info(binary, info, pipe); } else { - memset(&info->dvs_grid.dvs_grid_info, 0, - sizeof(info->dvs_grid.dvs_grid_info)); - memset(&info->dvs_grid.dvs_stat_grid_info, 0, - sizeof(info->dvs_grid.dvs_stat_grid_info)); + memset(&info->dvs_grid, 0, sizeof(info->dvs_grid)); } if (binary) { From 70d4ac6fb085dc621122cbf78169bcbd1162d0a6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Jul 2021 17:25:22 +0200 Subject: [PATCH 123/195] media: atomisp: Move MIPI_PORT_LANES to the only user Move MIPI_PORT_LANES to the only user of it, i.e. pci/runtime/isys/src/rx.c. Link: https://lore.kernel.org/linux-media/20210713152523.19902-4-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/isp2400_input_system_local.h | 11 ----------- .../staging/media/atomisp/pci/runtime/isys/src/rx.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 21f11bdfc85f3..2614b89b8e34b 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -362,17 +362,6 @@ static const hrt_address __maybe_unused MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { 0x00000200UL }; -static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { - {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_2LANE_CFG}, - {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, - {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, - {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG} -}; - static const hrt_address __maybe_unused SUB_SYSTEM_OFFSET[N_SUB_SYSTEM_ID] = { 0x00001000UL, 0x00002000UL, diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index 60b98c10a3bc5..af153c3fb86d3 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -476,6 +476,17 @@ unsigned int ia_css_csi2_calculate_input_system_alignment( #endif #if !defined(ISP2401) +static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { + {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_2LANE_CFG}, + {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, + {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG} +}; + void ia_css_isys_rx_configure(const rx_cfg_t *config, const enum ia_css_input_mode input_mode) { From 278cc35d750c3186ac30d249c9681ff7e6d80398 Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Mon, 19 Jul 2021 07:52:16 +0200 Subject: [PATCH 124/195] media: atomisp: i2c: Remove a superfluous else clause in atomisp-mt9m114.c Remove a superfluous clause in mt9m114_s_power() Link: https://lore.kernel.org/linux-media/20210719055216.28508-1-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 34bf92de2f29b..49f4090856d30 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -570,14 +570,13 @@ static int power_down(struct v4l2_subdev *sd) static int mt9m114_s_power(struct v4l2_subdev *sd, int power) { - if (power == 0) { + if (power == 0) return power_down(sd); - } else { - if (power_up(sd)) - return -EINVAL; - return mt9m114_init_common(sd); - } + if (power_up(sd)) + return -EINVAL; + + return mt9m114_init_common(sd); } /* From c27479d762de4eda72ba9e0aa150d439970f2077 Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Fri, 30 Apr 2021 17:40:12 +0200 Subject: [PATCH 125/195] media: atomisp: pci: reposition braces as per coding style Misplaced braces makes it difficult to follow the code easily. This also goes against the code style guidelines. This resolved following checkpatch complaints: ERROR: open brace '{' following function definitions go on the next line ERROR: that open brace { should be on the previous line Link: https://lore.kernel.org/linux-media/YIwk3KbVGRPJwKa4@dU2104 [mchehab: dropped a hunk with a merge conflict] Cc: linux-media@vger.kernel.org, devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, drv@mailo.com # X-LSpam-Score: -7.3 (-------) Signed-off-by: Deepak R Varma Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/sh_css_mipi.c | 69 +++---- .../staging/media/atomisp/pci/sh_css_params.c | 171 ++++++++---------- drivers/staging/media/atomisp/pci/sh_css_sp.c | 108 +++++------ .../media/atomisp/pci/sh_css_version.c | 3 +- 4 files changed, 155 insertions(+), 196 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_mipi.c b/drivers/staging/media/atomisp/pci/sh_css_mipi.c index 3f34cc81be87f..75489f7d75eec 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mipi.c +++ b/drivers/staging/media/atomisp/pci/sh_css_mipi.c @@ -91,7 +91,8 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, const enum atomisp_input_format format, const bool hasSOLandEOL, const unsigned int embedded_data_size_words, - unsigned int *size_mem_words) { + unsigned int *size_mem_words) +{ int err = 0; unsigned int bits_per_pixel = 0; @@ -118,8 +119,7 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, IA_CSS_ENTER("padded_width=%d, height=%d, format=%d, hasSOLandEOL=%d, embedded_data_size_words=%d\n", width_padded, height, format, hasSOLandEOL, embedded_data_size_words); - switch (format) - { + switch (format) { case ATOMISP_INPUT_FORMAT_RAW_6: /* 4p, 3B, 24bits */ bits_per_pixel = 6; break; @@ -178,12 +178,10 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, /* Even lines for YUV420 formats are double in bits_per_pixel. */ if (format == ATOMISP_INPUT_FORMAT_YUV420_8 || format == ATOMISP_INPUT_FORMAT_YUV420_10 - || format == ATOMISP_INPUT_FORMAT_YUV420_16) - { + || format == ATOMISP_INPUT_FORMAT_YUV420_16) { even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */ - } else - { + } else { even_line_bytes = odd_line_bytes; } @@ -236,7 +234,8 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, #if !defined(ISP2401) int ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port, - const unsigned int size_mem_words) { + const unsigned int size_mem_words) +{ u32 idx; int err = -EBUSY; @@ -246,11 +245,9 @@ ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port, for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT && my_css.mipi_sizes_for_check[port][idx] != 0; - idx++) /* do nothing */ - { + idx++) { /* do nothing */ } - if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT) - { + if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT) { my_css.mipi_sizes_for_check[port][idx] = size_mem_words; err = 0; } @@ -271,7 +268,8 @@ mipi_init(void) int calculate_mipi_buff_size( struct ia_css_stream_config *stream_cfg, - unsigned int *size_mem_words) { + unsigned int *size_mem_words) +{ #if !defined(ISP2401) int err = -EINVAL; (void)stream_cfg; @@ -346,12 +344,10 @@ calculate_mipi_buff_size( /* Even lines for YUV420 formats are double in bits_per_pixel. */ if (format == ATOMISP_INPUT_FORMAT_YUV420_8 - || format == ATOMISP_INPUT_FORMAT_YUV420_10) - { + || format == ATOMISP_INPUT_FORMAT_YUV420_10) { even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */ - } else - { + } else { even_line_bytes = odd_line_bytes; } @@ -393,7 +389,8 @@ static bool buffers_needed(struct ia_css_pipe *pipe) int allocate_mipi_frames(struct ia_css_pipe *pipe, - struct ia_css_stream_info *info) { + struct ia_css_stream_info *info) +{ int err = -EINVAL; unsigned int port; @@ -402,8 +399,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, assert(pipe); assert(pipe->stream); - if ((!pipe) || (!pipe->stream)) - { + if ((!pipe) || (!pipe->stream)) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) exit: pipe or stream is null.\n", pipe); @@ -411,8 +407,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, } #ifdef ISP2401 - if (pipe->stream->config.online) - { + if (pipe->stream->config.online) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) exit: no buffers needed for 2401 pipe mode.\n", pipe); @@ -449,8 +444,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, #endif #if !defined(ISP2401) - if (ref_count_mipi_allocation[port] != 0) - { + if (ref_count_mipi_allocation[port] != 0) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) exit: already allocated for this port (port=%d).\n", pipe, port); @@ -462,8 +456,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, * TODO AM: Once that is changed (removed) this code should be removed as well. * In that case only 2400 related code should remain. */ - if (ref_count_mipi_allocation[port] != 0) - { + if (ref_count_mipi_allocation[port] != 0) { ref_count_mipi_allocation[port]++; ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) leave: nothing to do, already allocated for this port (port=%d).\n", @@ -481,8 +474,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, { /* limit the scope of i,j */ unsigned int i, j; - for (i = 0; i < my_css.num_mipi_frames[port]; i++) - { + for (i = 0; i < my_css.num_mipi_frames[port]; i++) { /* free previous frame */ if (my_css.mipi_frames[port][i]) { ia_css_frame_free(my_css.mipi_frames[port][i]); @@ -535,7 +527,8 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, } int -free_mipi_frames(struct ia_css_pipe *pipe) { +free_mipi_frames(struct ia_css_pipe *pipe) +{ int err = -EINVAL; unsigned int port; @@ -543,8 +536,7 @@ free_mipi_frames(struct ia_css_pipe *pipe) { "free_mipi_frames(%p) enter:\n", pipe); /* assert(pipe != NULL); TEMP: TODO: Should be assert only. */ - if (pipe) - { + if (pipe) { assert(pipe->stream); if ((!pipe) || (!pipe->stream)) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, @@ -620,8 +612,7 @@ free_mipi_frames(struct ia_css_pipe *pipe) { } #endif } - } else /* pipe ==NULL */ - { + } else { /* pipe ==NULL */ /* AM TEMP: free-ing all mipi buffers just like a legacy code. */ for (port = CSI_PORT0_ID; port < N_CSI_PORTS; port++) { unsigned int i; @@ -645,7 +636,8 @@ free_mipi_frames(struct ia_css_pipe *pipe) { } int -send_mipi_frames(struct ia_css_pipe *pipe) { +send_mipi_frames(struct ia_css_pipe *pipe) +{ int err = -EINVAL; unsigned int i; #ifndef ISP2401 @@ -658,8 +650,7 @@ send_mipi_frames(struct ia_css_pipe *pipe) { assert(pipe); assert(pipe->stream); - if (!pipe || !pipe->stream) - { + if (!pipe || !pipe->stream) { IA_CSS_ERROR("pipe or stream is null"); return -EINVAL; } @@ -686,8 +677,7 @@ send_mipi_frames(struct ia_css_pipe *pipe) { } /* Hand-over the SP-internal mipi buffers */ - for (i = 0; i < my_css.num_mipi_frames[port]; i++) - { + for (i = 0; i < my_css.num_mipi_frames[port]; i++) { /* Need to include the ofset for port. */ sh_css_update_host2sp_mipi_frame(port * NUM_MIPI_FRAMES_PER_STREAM + i, my_css.mipi_frames[port][i]); @@ -700,8 +690,7 @@ send_mipi_frames(struct ia_css_pipe *pipe) { * Send an event to inform the SP * that all MIPI frames are passed. **********************************/ - if (!sh_css_sp_is_running()) - { + if (!sh_css_sp_is_running()) { /* SP is not running. The queues are not valid */ IA_CSS_ERROR("sp is not running"); return err; diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 644e145759874..dbd3bfe3d343c 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -813,15 +813,15 @@ convert_allocate_fpntbl(struct ia_css_isp_parameters *params) } static int -store_fpntbl(struct ia_css_isp_parameters *params, ia_css_ptr ptr) { +store_fpntbl(struct ia_css_isp_parameters *params, ia_css_ptr ptr) +{ struct ia_css_host_data *isp_data; assert(params); assert(ptr != mmgr_NULL); isp_data = convert_allocate_fpntbl(params); - if (!isp_data) - { + if (!isp_data) { IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; } @@ -894,7 +894,8 @@ ia_css_process_kernel(struct ia_css_stream *stream, static int sh_css_select_dp_10bpp_config(const struct ia_css_pipe *pipe, - bool *is_dp_10bpp) { + bool *is_dp_10bpp) +{ int err = 0; /* Currently we check if 10bpp DPC configuration is required based * on the use case,i.e. if BDS and DPC is both enabled. The more cleaner @@ -903,12 +904,10 @@ sh_css_select_dp_10bpp_config(const struct ia_css_pipe *pipe, * implementation. (This is because the configuration is set before a * binary is selected, and the binary info is not available) */ - if ((!pipe) || (!is_dp_10bpp)) - { + if ((!pipe) || (!is_dp_10bpp)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); err = -EINVAL; - } else - { + } else { *is_dp_10bpp = false; /* check if DPC is enabled from the host */ @@ -936,7 +935,8 @@ sh_css_select_dp_10bpp_config(const struct ia_css_pipe *pipe, int sh_css_set_black_frame(struct ia_css_stream *stream, - const struct ia_css_frame *raw_black_frame) { + const struct ia_css_frame *raw_black_frame) +{ struct ia_css_isp_parameters *params; /* this function desperately needs to be moved to the ISP or SP such * that it can use the DMA. @@ -957,13 +957,11 @@ sh_css_set_black_frame(struct ia_css_stream *stream, IA_CSS_ENTER_PRIVATE("black_frame=%p", raw_black_frame); if (params->fpn_config.data && - (params->fpn_config.width != width || params->fpn_config.height != height)) - { + (params->fpn_config.width != width || params->fpn_config.height != height)) { kvfree(params->fpn_config.data); params->fpn_config.data = NULL; } - if (!params->fpn_config.data) - { + if (!params->fpn_config.data) { params->fpn_config.data = kvmalloc(height * width * sizeof(short), GFP_KERNEL); if (!params->fpn_config.data) { @@ -977,8 +975,7 @@ sh_css_set_black_frame(struct ia_css_stream *stream, } /* store raw to fpntbl */ - for (y = 0; y < height; y++) - { + for (y = 0; y < height; y++) { for (x = 0; x < width; x += (ISP_VEC_NELEMS * 2)) { int ofs = y * width + x; @@ -1181,7 +1178,8 @@ sh_css_enable_pipeline(const struct ia_css_binary *binary) static int ia_css_process_zoom_and_motion( struct ia_css_isp_parameters *params, - const struct ia_css_pipeline_stage *first_stage) { + const struct ia_css_pipeline_stage *first_stage) +{ /* first_stage can be NULL */ const struct ia_css_pipeline_stage *stage; int err = 0; @@ -1195,8 +1193,7 @@ ia_css_process_zoom_and_motion( IA_CSS_ENTER_PRIVATE(""); /* Go through all stages to udate uds and cropping */ - for (stage = first_stage; stage; stage = stage->next) - { + for (stage = first_stage; stage; stage = stage->next) { struct ia_css_binary *binary; /* note: the var below is made static as it is quite large; if it is not static it ends up on the stack which could @@ -1581,7 +1578,8 @@ ia_css_isp_3a_statistics_map_allocate( int ia_css_get_3a_statistics(struct ia_css_3a_statistics *host_stats, - const struct ia_css_isp_3a_statistics *isp_stats) { + const struct ia_css_isp_3a_statistics *isp_stats) +{ struct ia_css_isp_3a_statistics_map *map; int ret = 0; @@ -1591,13 +1589,11 @@ ia_css_get_3a_statistics(struct ia_css_3a_statistics *host_stats, assert(isp_stats); map = ia_css_isp_3a_statistics_map_allocate(isp_stats, NULL); - if (map) - { + if (map) { hmm_load(isp_stats->data_ptr, map->data_ptr, isp_stats->size); ia_css_translate_3a_statistics(host_stats, map); ia_css_isp_3a_statistics_map_free(map); - } else - { + } else { IA_CSS_ERROR("out of memory"); ret = -ENOMEM; } @@ -1894,7 +1890,8 @@ sh_css_pipe_isp_config_get(struct ia_css_pipe *pipe) int ia_css_stream_set_isp_config( struct ia_css_stream *stream, - const struct ia_css_isp_config *config) { + const struct ia_css_isp_config *config) +{ return ia_css_stream_set_isp_config_on_pipe(stream, config, NULL); } @@ -1902,7 +1899,8 @@ int ia_css_stream_set_isp_config_on_pipe( struct ia_css_stream *stream, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe) { + struct ia_css_pipe *pipe) +{ int err = 0; if ((!stream) || (!config)) @@ -1923,7 +1921,8 @@ ia_css_stream_set_isp_config_on_pipe( int ia_css_pipe_set_isp_config(struct ia_css_pipe *pipe, - struct ia_css_isp_config *config) { + struct ia_css_isp_config *config) +{ struct ia_css_pipe *pipe_in = pipe; int err = 0; @@ -1948,7 +1947,8 @@ static int sh_css_set_global_isp_config_on_pipe( struct ia_css_pipe *curr_pipe, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe) { + struct ia_css_pipe *pipe) +{ int err = 0; int err1 = 0; int err2 = 0; @@ -1977,7 +1977,8 @@ static int sh_css_set_per_frame_isp_config_on_pipe( struct ia_css_stream *stream, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe) { + struct ia_css_pipe *pipe) +{ unsigned int i; bool per_frame_config_created = false; int err = 0; @@ -1991,8 +1992,7 @@ sh_css_set_per_frame_isp_config_on_pipe( IA_CSS_ENTER_PRIVATE("stream=%p, config=%p, pipe=%p", stream, config, pipe); - if (!pipe) - { + if (!pipe) { err = -EINVAL; goto exit; } @@ -2000,8 +2000,7 @@ sh_css_set_per_frame_isp_config_on_pipe( /* create per-frame ISP params object with default values * from stream->isp_params_configs if one doesn't already exist */ - if (!stream->per_frame_isp_params_configs) - { + if (!stream->per_frame_isp_params_configs) { err = sh_css_create_isp_params(stream, &stream->per_frame_isp_params_configs); if (err) @@ -2012,15 +2011,13 @@ sh_css_set_per_frame_isp_config_on_pipe( params = stream->per_frame_isp_params_configs; /* update new ISP params object with the new config */ - if (!sh_css_init_isp_params_from_global(stream, params, false, pipe)) - { + if (!sh_css_init_isp_params_from_global(stream, params, false, pipe)) { err1 = -EINVAL; } err2 = sh_css_init_isp_params_from_config(stream->pipes[0], params, config, pipe); - if (per_frame_config_created) - { + if (per_frame_config_created) { ddr_ptrs = ¶ms->ddr_ptrs; ddr_ptrs_size = ¶ms->ddr_ptrs_size; /* create per pipe reference to general ddr_ptrs */ @@ -2051,7 +2048,8 @@ static int sh_css_init_isp_params_from_config(struct ia_css_pipe *pipe, struct ia_css_isp_parameters *params, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe_in) { + struct ia_css_pipe *pipe_in) +{ int err = 0; bool is_dp_10bpp = true; @@ -2096,8 +2094,7 @@ sh_css_init_isp_params_from_config(struct ia_css_pipe *pipe, } if (0 == - sh_css_select_dp_10bpp_config(pipe, &is_dp_10bpp)) - { + sh_css_select_dp_10bpp_config(pipe, &is_dp_10bpp)) { /* return an error when both DPC and BDS is enabled by the * user. */ /* we do not exit from this point immediately to allow internal @@ -2105,8 +2102,7 @@ sh_css_init_isp_params_from_config(struct ia_css_pipe *pipe, if (is_dp_10bpp) { err = -EINVAL; } - } else - { + } else { err = -EINVAL; goto exit; } @@ -2359,7 +2355,8 @@ static unsigned int g_param_buffer_dequeue_count; static unsigned int g_param_buffer_enqueue_count; int -ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { +ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) +{ int err = 0; unsigned int i; struct sh_css_ddr_address_map *ddr_ptrs; @@ -2369,8 +2366,7 @@ ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { assert(stream); IA_CSS_ENTER_PRIVATE("void"); - if (!stream) - { + if (!stream) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -2385,8 +2381,7 @@ ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { goto ERR; params = stream->isp_params_configs; - if (!sh_css_init_isp_params_from_global(stream, params, true, NULL)) - { + if (!sh_css_init_isp_params_from_global(stream, params, true, NULL)) { /* we do not return the error immediately to enable internal * firmware feature testing */ err = -EINVAL; @@ -2396,8 +2391,7 @@ ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { ddr_ptrs_size = ¶ms->ddr_ptrs_size; /* create per pipe reference to general ddr_ptrs */ - for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) - { + for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { ref_sh_css_ddr_address_map(ddr_ptrs, ¶ms->pipe_ddr_ptrs[i]); params->pipe_ddr_ptrs_size[i] = *ddr_ptrs_size; } @@ -2431,7 +2425,8 @@ ia_css_set_sdis2_config( static int sh_css_create_isp_params(struct ia_css_stream *stream, - struct ia_css_isp_parameters **isp_params_out) { + struct ia_css_isp_parameters **isp_params_out) +{ bool succ = true; unsigned int i; struct sh_css_ddr_address_map *ddr_ptrs; @@ -2441,23 +2436,20 @@ sh_css_create_isp_params(struct ia_css_stream *stream, struct ia_css_isp_parameters *params = kvmalloc(sizeof(struct ia_css_isp_parameters), GFP_KERNEL); - if (!params) - { + if (!params) { *isp_params_out = NULL; err = -ENOMEM; IA_CSS_ERROR("%s:%d error: cannot allocate memory", __FILE__, __LINE__); IA_CSS_LEAVE_ERR_PRIVATE(err); return err; - } else - { + } else { memset(params, 0, sizeof(struct ia_css_isp_parameters)); } ddr_ptrs = ¶ms->ddr_ptrs; ddr_ptrs_size = ¶ms->ddr_ptrs_size; - for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) - { + for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { memset(¶ms->pipe_ddr_ptrs[i], 0, sizeof(params->pipe_ddr_ptrs[i])); memset(¶ms->pipe_ddr_ptrs_size[i], 0, @@ -2714,7 +2706,8 @@ sh_css_init_isp_params_from_global(struct ia_css_stream *stream, } int -sh_css_params_init(void) { +sh_css_params_init(void) +{ int i, p; IA_CSS_ENTER_PRIVATE("void"); @@ -2723,8 +2716,7 @@ sh_css_params_init(void) { g_param_buffer_dequeue_count = 0; g_param_buffer_enqueue_count = 0; - for (p = 0; p < IA_CSS_PIPE_ID_NUM; p++) - { + for (p = 0; p < IA_CSS_PIPE_ID_NUM; p++) { for (i = 0; i < SH_CSS_MAX_STAGES; i++) { xmem_sp_stage_ptrs[p][i] = ia_css_refcount_increment(-1, @@ -2762,8 +2754,7 @@ sh_css_params_init(void) { ATOMISP_MAP_FLAG_CLEARED)); if ((sp_ddr_ptrs == mmgr_NULL) || - (xmem_sp_group_ptrs == mmgr_NULL)) - { + (xmem_sp_group_ptrs == mmgr_NULL)) { ia_css_uninit(); IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; @@ -3094,14 +3085,14 @@ store_morph_plane( unsigned int width, unsigned int height, ia_css_ptr dest, - unsigned int aligned_width) { + unsigned int aligned_width) +{ struct ia_css_host_data *isp_data; assert(dest != mmgr_NULL); isp_data = convert_allocate_morph_plane(data, width, height, aligned_width); - if (!isp_data) - { + if (!isp_data) { IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; } @@ -3221,7 +3212,8 @@ int sh_css_param_update_isp_params(struct ia_css_pipe *curr_pipe, struct ia_css_isp_parameters *params, bool commit, - struct ia_css_pipe *pipe_in) { + struct ia_css_pipe *pipe_in) +{ int err = 0; ia_css_ptr cpy; int i; @@ -3238,15 +3230,13 @@ sh_css_param_update_isp_params(struct ia_css_pipe *curr_pipe, raw_bit_depth = ia_css_stream_input_format_bits_per_pixel(curr_pipe->stream); /* now make the map available to the sp */ - if (!commit) - { + if (!commit) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } /* enqueue a copies of the mem_map to the designated pipelines */ - for (i = 0; i < curr_pipe->stream->num_pipes; i++) - { + for (i = 0; i < curr_pipe->stream->num_pipes; i++) { struct ia_css_pipe *pipe; struct sh_css_ddr_address_map *cur_map; struct sh_css_ddr_address_map_size *cur_map_size; @@ -3430,7 +3420,8 @@ sh_css_params_write_to_ddr_internal( struct ia_css_isp_parameters *params, const struct ia_css_pipeline_stage *stage, struct sh_css_ddr_address_map *ddr_map, - struct sh_css_ddr_address_map_size *ddr_map_size) { + struct sh_css_ddr_address_map_size *ddr_map_size) +{ int err; const struct ia_css_binary *binary; @@ -3452,8 +3443,7 @@ sh_css_params_write_to_ddr_internal( stage_num = stage->stage_num; - if (binary->info->sp.enable.fpnr) - { + if (binary->info->sp.enable.fpnr) { buff_realloced = reallocate_buffer(&ddr_map->fpn_tbl, &ddr_map_size->fpn_tbl, (size_t)(FPNTBL_BYTES(binary)), @@ -3474,8 +3464,7 @@ sh_css_params_write_to_ddr_internal( } } - if (binary->info->sp.enable.sc) - { + if (binary->info->sp.enable.sc) { u32 enable_conv; size_t bytes; @@ -3577,8 +3566,7 @@ sh_css_params_write_to_ddr_internal( * DPC kernel. The code below sets the pipe specific configuration to * individual binaries. */ if (IS_ISP2401 && - params->pipe_dpc_config_changed[pipe_id] && binary->info->sp.enable.dpc) - { + params->pipe_dpc_config_changed[pipe_id] && binary->info->sp.enable.dpc) { unsigned int size = stage->binary->info->mem_offsets.offsets.param->dmem.dp.size; @@ -3596,8 +3584,7 @@ sh_css_params_write_to_ddr_internal( } } - if (params->config_changed[IA_CSS_MACC_ID] && binary->info->sp.enable.macc) - { + if (params->config_changed[IA_CSS_MACC_ID] && binary->info->sp.enable.macc) { unsigned int i, j, idx; unsigned int idx_map[] = { 0, 1, 3, 2, 6, 7, 5, 4, 12, 13, 15, 14, 10, 11, 9, 8 @@ -3646,8 +3633,7 @@ sh_css_params_write_to_ddr_internal( sizeof(converted_macc_table.data)); } - if (binary->info->sp.enable.dvs_6axis) - { + if (binary->info->sp.enable.dvs_6axis) { /* because UV is packed into the Y plane, calc total * YYU size = /2 gives size of UV-only, * total YYU size = UV-only * 3. @@ -3705,8 +3691,7 @@ sh_css_params_write_to_ddr_internal( } } - if (binary->info->sp.enable.ca_gdc) - { + if (binary->info->sp.enable.ca_gdc) { unsigned int i; ia_css_ptr *virt_addr_tetra_x[ @@ -3811,8 +3796,7 @@ sh_css_params_write_to_ddr_internal( } /* After special cases like SC, FPN since they may change parameters */ - for (mem = 0; mem < N_IA_CSS_MEMORIES; mem++) - { + for (mem = 0; mem < N_IA_CSS_MEMORIES; mem++) { const struct ia_css_isp_data *isp_data = ia_css_isp_param_get_isp_mem_init(&binary->info->sp.mem_initializers, IA_CSS_PARAM_CLASS_PARAM, mem); @@ -4025,7 +4009,8 @@ static int write_ia_css_isp_parameter_set_info_to_ddr( static int free_ia_css_isp_parameter_set_info( - ia_css_ptr ptr) { + ia_css_ptr ptr) +{ int err = 0; struct ia_css_isp_parameter_set_info isp_params_info; unsigned int i; @@ -4034,8 +4019,7 @@ free_ia_css_isp_parameter_set_info( IA_CSS_ENTER_PRIVATE("ptr = %u", ptr); /* sanity check - ptr must be valid */ - if (!ia_css_refcount_is_valid(ptr)) - { + if (!ia_css_refcount_is_valid(ptr)) { IA_CSS_ERROR("%s: IA_CSS_REFCOUNT_PARAM_SET_POOL(0x%x) invalid arg", __func__, ptr); err = -EINVAL; @@ -4046,8 +4030,7 @@ free_ia_css_isp_parameter_set_info( hmm_load(ptr, &isp_params_info.mem_map, sizeof(struct sh_css_ddr_address_map)); /* copy map using size info */ for (i = 0; i < (sizeof(struct sh_css_ddr_address_map_size) / - sizeof(size_t)); i++) - { + sizeof(size_t)); i++) { if (addrs[i] == mmgr_NULL) continue; @@ -4254,7 +4237,8 @@ sh_css_update_uds_and_crop_info_based_on_zoom_region( struct sh_css_uds_info *uds, /* out */ struct sh_css_crop_pos *sp_out_crop_pos, /* out */ struct ia_css_resolution pipe_in_res, - bool enable_zoom) { + bool enable_zoom) +{ unsigned int x0 = 0, y0 = 0, x1 = 0, y1 = 0; int err = 0; /* Note: @@ -4285,19 +4269,16 @@ sh_css_update_uds_and_crop_info_based_on_zoom_region( if ((x0 > x1) || (y0 > y1) || (x1 > pipe_in_res.width) || (y1 > pipe_in_res.height)) return -EINVAL; - if (!enable_zoom) - { + if (!enable_zoom) { uds->curr_dx = HRT_GDC_N; uds->curr_dy = HRT_GDC_N; } - if (info->enable.dvs_envelope) - { + if (info->enable.dvs_envelope) { /* Zoom region is only supported by the UDS module on ISP * 2 and higher. It is not supported in video mode on ISP 1 */ return -EINVAL; - } else - { + } else { if (enable_zoom) { /* A. Calculate dx/dy based on crop region using in_frame_info * Scale the crop region if in_frame_info to the stage is not same as diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.c b/drivers/staging/media/atomisp/pci/sh_css_sp.c index 02f5a73b40963..a73e8ca1e225f 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.c +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.c @@ -535,12 +535,12 @@ sh_css_copy_frame_to_spframe(struct ia_css_frame_sp *sp_frame_out, } static int -set_input_frame_buffer(const struct ia_css_frame *frame) { +set_input_frame_buffer(const struct ia_css_frame *frame) +{ if (!frame) return -EINVAL; - switch (frame->info.format) - { + switch (frame->info.format) { case IA_CSS_FRAME_FORMAT_QPLANE6: case IA_CSS_FRAME_FORMAT_YUV420_16: case IA_CSS_FRAME_FORMAT_RAW_PACKED: @@ -566,12 +566,12 @@ set_input_frame_buffer(const struct ia_css_frame *frame) { static int set_output_frame_buffer(const struct ia_css_frame *frame, - unsigned int idx) { + unsigned int idx) +{ if (!frame) return -EINVAL; - switch (frame->info.format) - { + switch (frame->info.format) { case IA_CSS_FRAME_FORMAT_YUV420: case IA_CSS_FRAME_FORMAT_YUV422: case IA_CSS_FRAME_FORMAT_YUV444: @@ -607,12 +607,12 @@ set_output_frame_buffer(const struct ia_css_frame *frame, } static int -set_view_finder_buffer(const struct ia_css_frame *frame) { +set_view_finder_buffer(const struct ia_css_frame *frame) +{ if (!frame) return -EINVAL; - switch (frame->info.format) - { + switch (frame->info.format) { /* the dual output pin */ case IA_CSS_FRAME_FORMAT_NV12: case IA_CSS_FRAME_FORMAT_NV12_16: @@ -732,7 +732,8 @@ sh_css_sp_set_disable_continuous_viewfinder(bool flag) } static int -sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) { +sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) +{ int err = 0; int i; @@ -742,8 +743,7 @@ sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) { err = set_input_frame_buffer(args->in_frame); if (!err && args->out_vf_frame) err = set_view_finder_buffer(args->out_vf_frame); - for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) - { + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { if (!err && args->out_frame[i]) err = set_output_frame_buffer(args->out_frame[i], i); } @@ -786,7 +786,8 @@ sh_css_stage_write_binary_info(struct ia_css_binary_info *info) } static int -copy_isp_mem_if_to_ddr(struct ia_css_binary *binary) { +copy_isp_mem_if_to_ddr(struct ia_css_binary *binary) +{ int err; err = ia_css_isp_param_copy_isp_mem_if_to_ddr( @@ -817,7 +818,8 @@ configure_isp_from_args( const struct ia_css_binary *binary, const struct sh_css_binary_args *args, bool two_ppc, - bool deinterleaved) { + bool deinterleaved) +{ ia_css_fpn_configure(binary, &binary->in_frame_info); ia_css_crop_configure(binary, &args->delay_frames[0]->info); ia_css_qplane_configure(pipeline, binary, &binary->in_frame_info); @@ -896,7 +898,8 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, bool xnr, const struct ia_css_isp_param_css_segments *isp_mem_if, unsigned int if_config_index, - bool two_ppc) { + bool two_ppc) +{ const struct ia_css_binary_xinfo *xinfo; const struct ia_css_binary_info *info; int err = 0; @@ -928,8 +931,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); - if (!info) - { + if (!info) { sh_css_sp_group.pipe[thread_id].sp_stage_addr[stage] = mmgr_NULL; return 0; } @@ -961,8 +963,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.in.info, &binary->in_frame_info); - for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) - { + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.out[i].info, &binary->out_frame_info[i]); } @@ -996,16 +997,14 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, err = sh_css_sp_write_frame_pointers(args); /* TODO: move it to a better place */ - if (binary->info->sp.enable.s3a) - { + if (binary->info->sp.enable.s3a) { ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_3A_STATISTICS, thread_id, &queue_id); sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.s3a_buf, queue_id, mmgr_EXCEPTION, IA_CSS_BUFFER_TYPE_3A_STATISTICS); } - if (binary->info->sp.enable.dis) - { + if (binary->info->sp.enable.dis) { ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_DIS_STATISTICS, thread_id, &queue_id); sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.dvs_buf, queue_id, @@ -1046,8 +1045,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, * the original out res. for video pipe, it has two output pins --- out and * vf_out, so it can keep these two resolutions already. */ if (binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW && - (binary->vf_downscale_log2 > 0)) - { + (binary->vf_downscale_log2 > 0)) { /* TODO: Remove this after preview output decimation is fixed * by configuring out&vf info fiels properly */ sh_css_sp_stage.frames.out[0].info.padded_width @@ -1069,7 +1067,8 @@ sp_init_stage(struct ia_css_pipeline_stage *stage, unsigned int pipe_num, bool xnr, unsigned int if_config_index, - bool two_ppc) { + bool two_ppc) +{ struct ia_css_binary *binary; const struct ia_css_fw_info *firmware; const struct sh_css_binary_args *args; @@ -1105,14 +1104,12 @@ sp_init_stage(struct ia_css_pipeline_stage *stage, args = &stage->args; stage_num = stage->stage_num; - if (binary) - { + if (binary) { info = binary->info; binary_name = (const char *)(info->blob->name); blob_info = &info->blob->header.blob; ia_css_init_memory_interface(mem_if, &binary->mem_params, &binary->css_params); - } else if (firmware) - { + } else if (firmware) { const struct ia_css_frame_info *out_infos[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL}; if (args->out_frame[0]) @@ -1133,8 +1130,7 @@ sp_init_stage(struct ia_css_pipeline_stage *stage, binary_name = IA_CSS_EXT_ISP_PROG_NAME(firmware); blob_info = &firmware->blob; mem_if = (struct ia_css_isp_param_css_segments *)&firmware->mem_initializers; - } else - { + } else { /* SP stage */ assert(stage->sp_func != IA_CSS_PIPELINE_NO_FUNC); /* binary and blob_info are now NULL. @@ -1205,7 +1201,8 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, *internal_frame_origin_bqs_on_sctbl, /* Origin of internal frame positioned on shading table at shading correction in ISP. */ const struct ia_css_isp_parameters *params - ) { + ) +{ /* Get first stage */ struct ia_css_pipeline_stage *stage = NULL; struct ia_css_binary *first_binary = NULL; @@ -1223,17 +1220,14 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, first_binary = me->stages->binary; if (input_mode == IA_CSS_INPUT_MODE_SENSOR || - input_mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) - { + input_mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { assert(port_id < N_MIPI_PORT_ID); if (port_id >= N_MIPI_PORT_ID) /* should not happen but KW does not know */ return; /* we should be able to return an error */ if_config_index = (uint8_t)(port_id - MIPI_PORT0_ID); - } else if (input_mode == IA_CSS_INPUT_MODE_MEMORY) - { + } else if (input_mode == IA_CSS_INPUT_MODE_MEMORY) { if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED; - } else - { + } else { if_config_index = 0x0; } @@ -1241,15 +1235,13 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, memset(&sh_css_sp_group.pipe[thread_id], 0, sizeof(struct sh_css_sp_pipeline)); /* Count stages */ - for (stage = me->stages, num = 0; stage; stage = stage->next, num++) - { + for (stage = me->stages, num = 0; stage; stage = stage->next, num++) { stage->stage_num = num; ia_css_debug_pipe_graph_dump_stage(stage, id); } me->num_stages = num; - if (first_binary) - { + if (first_binary) { /* Init pipeline data */ sh_css_sp_init_group(two_ppc, first_binary->input_format, offline, if_config_index); @@ -1277,8 +1269,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, /* TODO: next indicates from which queues parameters need to be sampled, needs checking/improvement */ - if (ia_css_pipeline_uses_params(me)) - { + if (ia_css_pipeline_uses_params(me)) { sh_css_sp_group.pipe[thread_id].pipe_config = SH_CSS_PIPE_CONFIG_SAMPLE_PARAMS << thread_id; } @@ -1292,15 +1283,13 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, pipe = find_pipe_by_num(pipe_num); assert(pipe); - if (!pipe) - { + if (!pipe) { return; } sh_css_sp_group.pipe[thread_id].scaler_pp_lut = sh_css_pipe_get_pp_gdc_lut(pipe); #if defined(SH_CSS_ENABLE_METADATA) - if (md_info && md_info->size > 0) - { + if (md_info && md_info->size > 0) { sh_css_sp_group.pipe[thread_id].metadata.width = md_info->resolution.width; sh_css_sp_group.pipe[thread_id].metadata.height = md_info->resolution.height; sh_css_sp_group.pipe[thread_id].metadata.stride = md_info->stride; @@ -1316,8 +1305,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS) sh_css_sp_group.pipe[thread_id].output_frame_queue_id = (uint32_t)SH_CSS_INVALID_QUEUE_ID; - if (pipe_id != IA_CSS_PIPE_ID_COPY) - { + if (pipe_id != IA_CSS_PIPE_ID_COPY) { ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, (enum sh_css_queue_id *)( &sh_css_sp_group.pipe[thread_id].output_frame_queue_id)); @@ -1329,14 +1317,12 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, * the parameters are passed to the isp for the shading table centering. */ if (internal_frame_origin_bqs_on_sctbl && - params && params->shading_settings.enable_shading_table_conversion == 0) - { + params && params->shading_settings.enable_shading_table_conversion == 0) { sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_x_bqs_on_sctbl = (uint32_t)internal_frame_origin_bqs_on_sctbl->x; sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_y_bqs_on_sctbl = (uint32_t)internal_frame_origin_bqs_on_sctbl->y; - } else - { + } else { sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_x_bqs_on_sctbl = 0; sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_y_bqs_on_sctbl = @@ -1347,8 +1333,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, IA_CSS_LOG("pipe_id %d port_config %08x", pipe_id, sh_css_sp_group.pipe[thread_id].inout_port_config); - for (stage = me->stages, num = 0; stage; stage = stage->next, num++) - { + for (stage = me->stages, num = 0; stage; stage = stage->next, num++) { sh_css_sp_group.pipe[thread_id].num_stages++; if (is_sp_stage(stage)) { sp_init_sp_stage(stage, pipe_num, two_ppc, @@ -1400,7 +1385,8 @@ bool sh_css_write_host2sp_command(enum host2sp_commands host2sp_command) } enum host2sp_commands -sh_css_read_host2sp_command(void) { +sh_css_read_host2sp_command(void) +{ unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; unsigned int offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_command) / sizeof(int); @@ -1586,7 +1572,8 @@ sh_css_event_init_irq_mask(void) int ia_css_pipe_set_irq_mask(struct ia_css_pipe *pipe, unsigned int or_mask, - unsigned int and_mask) { + unsigned int and_mask) +{ unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; unsigned int offset; struct sh_css_event_irq_mask event_irq_mask; @@ -1625,7 +1612,8 @@ ia_css_pipe_set_irq_mask(struct ia_css_pipe *pipe, int ia_css_event_get_irq_mask(const struct ia_css_pipe *pipe, unsigned int *or_mask, - unsigned int *and_mask) { + unsigned int *and_mask) +{ unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; unsigned int offset; struct sh_css_event_irq_mask event_irq_mask; diff --git a/drivers/staging/media/atomisp/pci/sh_css_version.c b/drivers/staging/media/atomisp/pci/sh_css_version.c index fa6de61e49952..f5ff8ca66b508 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_version.c +++ b/drivers/staging/media/atomisp/pci/sh_css_version.c @@ -21,7 +21,8 @@ #include "sh_css_firmware.h" int -ia_css_get_version(char *version, int max_size) { +ia_css_get_version(char *version, int max_size) +{ char *css_version; if (!IS_ISP2401) From 0c980e3f5276ba2eb95c42919c5f1694e38ef86a Mon Sep 17 00:00:00 2001 From: Yizhuo Date: Fri, 25 Jun 2021 07:38:56 +0200 Subject: [PATCH 126/195] media: atomisp: fix the uninitialized use and rename "retvalue" Inside function mt9m114_detect(), variable "retvalue" could be uninitialized if mt9m114_read_reg() returns error, however, it is used in the later if statement, which is potentially unsafe. The local variable "retvalue" is renamed to "model" to avoid confusion. Link: https://lore.kernel.org/linux-media/20210625053858.3862-1-yzhai003@ucr.edu Fixes: ad85094b293e ("Revert "media: staging: atomisp: Remove driver"") Signed-off-by: Yizhuo Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 11196180a2066..34bf92de2f29b 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -1545,16 +1545,19 @@ static struct v4l2_ctrl_config mt9m114_controls[] = { static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - u32 retvalue; + u32 model; + int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "%s: i2c error", __func__); return -ENODEV; } - mt9m114_read_reg(client, MISENSOR_16BIT, (u32)MT9M114_PID, &retvalue); - dev->real_model_id = retvalue; + ret = mt9m114_read_reg(client, MISENSOR_16BIT, MT9M114_PID, &model); + if (ret) + return ret; + dev->real_model_id = model; - if (retvalue != MT9M114_MOD_ID) { + if (model != MT9M114_MOD_ID) { dev_err(&client->dev, "%s: failed: client->addr = %x\n", __func__, client->addr); return -ENODEV; From 9e77871a59c86d71e9821dcc5f57a4461bfff1ee Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Sun, 9 May 2021 01:56:19 +0200 Subject: [PATCH 127/195] media: atomisp: Resolve goto style issue in sh_css.c Change the goto label to lower case. Remove a space in the goto label. Link: https://lore.kernel.org/linux-media/20210508235622.300394-2-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index d26b1301eeb7e..53c1001b807bc 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -5170,7 +5170,7 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, if (binary) { err = ia_css_binary_3a_grid_info(binary, info, pipe); if (err) - goto ERR; + goto err; } else { memset(&info->s3a_grid, 0, sizeof(info->s3a_grid)); } @@ -5195,7 +5195,7 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, info->vamem_type = IA_CSS_VAMEM_TYPE_2; -ERR : +err: IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } From a93cf5a5058495877e226fc2f3b9560deae5ff2d Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Sun, 9 May 2021 01:56:20 +0200 Subject: [PATCH 128/195] media: atomisp: Remove unnecessary parens in sh_css.c Remove unnecessary parenthesis. Link: https://lore.kernel.org/linux-media/20210508235622.300394-3-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 53c1001b807bc..51fe939a89589 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -10162,7 +10162,7 @@ ia_css_stop_sp(void) timeout--; udelay(1); } - if ((ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED)) + if (ia_css_spctrl_get_state(SP0_ID) != IA_CSS_SP_SW_TERMINATED) IA_CSS_WARNING("SP has not terminated (SW)"); if (timeout == 0) { From d2f3009e86fdad199d3c376baddfb2c987d7df1c Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Sun, 9 May 2021 01:56:21 +0200 Subject: [PATCH 129/195] media: atomisp: Use kcalloc instead of kzalloc with multiply in sh_css.c Use kcalloc instead of kzalloc with multiplication. Link: https://lore.kernel.org/linux-media/20210508235622.300394-4-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 51fe939a89589..b8dd817616e89 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -5328,14 +5328,15 @@ static int load_video_binaries(struct ia_css_pipe *pipe) if (err) return err; mycs->num_yuv_scaler = cas_scaler_descr.num_stage; - mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * - sizeof(struct ia_css_binary), GFP_KERNEL); + mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, + sizeof(struct ia_css_binary), + GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; return err; } - mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage - * sizeof(bool), GFP_KERNEL); + mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, + sizeof(bool), GFP_KERNEL); if (!mycs->is_output_stage) { err = -ENOMEM; return err; @@ -5938,14 +5939,15 @@ static int load_primary_binaries( return err; } mycs->num_yuv_scaler = cas_scaler_descr.num_stage; - mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * - sizeof(struct ia_css_binary), GFP_KERNEL); + mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, + sizeof(struct ia_css_binary), + GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } - mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * + mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, sizeof(bool), GFP_KERNEL); if (!mycs->is_output_stage) { err = -ENOMEM; @@ -6989,14 +6991,14 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) goto ERR; mycs->num_output = cas_scaler_descr.num_output_stage; mycs->num_yuv_scaler = cas_scaler_descr.num_stage; - mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * + mycs->yuv_scaler_binary = kcalloc(cas_scaler_descr.num_stage, sizeof(struct ia_css_binary), GFP_KERNEL); if (!mycs->yuv_scaler_binary) { err = -ENOMEM; goto ERR; } - mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * + mycs->is_output_stage = kcalloc(cas_scaler_descr.num_stage, sizeof(bool), GFP_KERNEL); if (!mycs->is_output_stage) { err = -ENOMEM; @@ -7097,7 +7099,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) mycs->num_vf_pp = 1; } - mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp * + mycs->vf_pp_binary = kcalloc(mycs->num_vf_pp, sizeof(struct ia_css_binary), GFP_KERNEL); if (!mycs->vf_pp_binary) { From 66b22424ad271d762948da0fda55b21d08327029 Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Sun, 9 May 2021 01:56:22 +0200 Subject: [PATCH 130/195] media: atomisp: Fix line continuation style issue in sh_css.c Fix logical continuation style issue and adjacent line splits. Link: https://lore.kernel.org/linux-media/20210508235622.300394-5-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index b8dd817616e89..5dac4a506b002 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -3224,24 +3224,22 @@ init_vf_frameinfo_defaults(struct ia_css_pipe *pipe, #ifdef ISP2401 static unsigned int -get_crop_lines_for_bayer_order( - const struct ia_css_stream_config *config) +get_crop_lines_for_bayer_order(const struct ia_css_stream_config *config) { assert(config); - if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) - || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) + if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_BGGR) || + (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) return 1; return 0; } static unsigned int -get_crop_columns_for_bayer_order( - const struct ia_css_stream_config *config) +get_crop_columns_for_bayer_order(const struct ia_css_stream_config *config) { assert(config); - if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) - || (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) + if ((config->input_config.bayer_order == IA_CSS_BAYER_ORDER_RGGB) || + (config->input_config.bayer_order == IA_CSS_BAYER_ORDER_GBRG)) return 1; return 0; From e53656ab8c806b26f85238af341d93e6792d1ee6 Mon Sep 17 00:00:00 2001 From: Nguyen Dinh Phi Date: Thu, 13 May 2021 05:46:50 +0200 Subject: [PATCH 131/195] media: atomisp: Use sysfs_emit() instead of sprintf() where appropriate sysfs_emit() is preferred over raw sprintf() for sysfs attributes since it knows about the sysfs buffer specifics and has some built-in sanity checks. Link: https://lore.kernel.org/linux-media/20210513034650.252993-1-phind.uet@gmail.com Signed-off-by: Nguyen Dinh Phi Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_drvfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c index f670faf978e6e..dcb571f515a71 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_drvfs.c +++ b/drivers/staging/media/atomisp/pci/atomisp_drvfs.c @@ -96,7 +96,7 @@ static inline int iunit_dump_dbgopt(struct atomisp_device *isp, static ssize_t iunit_dbglvl_show(struct device_driver *drv, char *buf) { iunit_debug.dbglvl = dbg_level; - return sprintf(buf, "dtrace level:%u\n", iunit_debug.dbglvl); + return sysfs_emit(buf, "dtrace level:%u\n", iunit_debug.dbglvl); } static ssize_t iunit_dbglvl_store(struct device_driver *drv, const char *buf, @@ -115,7 +115,7 @@ static ssize_t iunit_dbglvl_store(struct device_driver *drv, const char *buf, static ssize_t iunit_dbgfun_show(struct device_driver *drv, char *buf) { iunit_debug.dbgfun = atomisp_get_css_dbgfunc(); - return sprintf(buf, "dbgfun opt:%u\n", iunit_debug.dbgfun); + return sysfs_emit(buf, "dbgfun opt:%u\n", iunit_debug.dbgfun); } static ssize_t iunit_dbgfun_store(struct device_driver *drv, const char *buf, @@ -139,7 +139,7 @@ static ssize_t iunit_dbgfun_store(struct device_driver *drv, const char *buf, static ssize_t iunit_dbgopt_show(struct device_driver *drv, char *buf) { - return sprintf(buf, "option:0x%x\n", iunit_debug.dbgopt); + return sysfs_emit(buf, "option:0x%x\n", iunit_debug.dbgopt); } static ssize_t iunit_dbgopt_store(struct device_driver *drv, const char *buf, From b09ea938621416abf5b05f73d37d2e6b8ed2a997 Mon Sep 17 00:00:00 2001 From: Jiabing Wan Date: Tue, 18 May 2021 13:29:35 +0200 Subject: [PATCH 132/195] media: atomisp: Align block comments Fixing the following checkpatch warning: WARNING: Block comments should align the * on each line Link: https://lore.kernel.org/linux-media/20210518112938.88240-1-wanjiabing@vivo.com Signed-off-by: Jiabing Wan Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h index be3534e46c15d..9b22f2da45d56 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h +++ b/drivers/staging/media/atomisp/pci/isp/kernels/anr/anr_1.0/ia_css_anr_types.h @@ -17,8 +17,8 @@ #define __IA_CSS_ANR_TYPES_H /* @file -* CSS-API header file for Advanced Noise Reduction kernel v1 -*/ + * CSS-API header file for Advanced Noise Reduction kernel v1 + */ /* Application specific DMA settings */ #define ANR_BPP 10 From 6bdad3bb7eb1d91e10998eb21b6f9159064b53af Mon Sep 17 00:00:00 2001 From: Aniket Bhattacharyea Date: Mon, 24 May 2021 19:36:09 +0200 Subject: [PATCH 133/195] media: atomisp: Fix whitespace at the beginning of line This patch fixes whitespace at the beginning of line by wrapping after the type name and aligning the arguments with the open parenthesis. Identified by checkpatch: WARNING: please, no spaces at the start of a line. Link: https://lore.kernel.org/linux-media/20210524173609.672153-1-aniketmail669@gmail.com Signed-off-by: Aniket Bhattacharyea Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 135994d44802c..d8c9e31314b2e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -1040,10 +1040,10 @@ static struct camera_sensor_platform_data acpi_gmin_plat = { .get_vcm_ctrl = gmin_get_vcm_ctrl, }; -struct camera_sensor_platform_data *gmin_camera_platform_data( - struct v4l2_subdev *subdev, - enum atomisp_input_format csi_format, - enum atomisp_bayer_order csi_bayer) +struct camera_sensor_platform_data * +gmin_camera_platform_data(struct v4l2_subdev *subdev, + enum atomisp_input_format csi_format, + enum atomisp_bayer_order csi_bayer) { u8 pmic_i2c_addr = gmin_detect_pmic(subdev); struct gmin_subdev *gs; From 280355522d61d106e52cf0536dcf2807a15aec37 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 21 May 2021 21:48:05 +0200 Subject: [PATCH 134/195] media: atomisp: improve error handling in gc2235_detect() Static analysis reports this representative problem atomisp-gc2235.c:867:20: warning: The right operand of '|' is a garbage value id = ((high << 8) | low); ^ ~~~ When gc2235_read_reg() fails, its return val is never written. For gc2235_detect(), high and low are or-ed and compared with GC2235_ID, 0x2235. Initialize both to 0 and skip checking the read returns, it's errors are not passed up, only -ENODEV is. Link: https://lore.kernel.org/linux-media/20210521194805.2078135-1-trix@redhat.com Signed-off-by: Tom Rix Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 9363c1a52ae9b..4d769590f2d32 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -849,21 +849,14 @@ static int gc2235_get_fmt(struct v4l2_subdev *sd, static int gc2235_detect(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; + u16 high = 0, low = 0; u16 id; if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) return -ENODEV; - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_L, &low); + gc2235_read_reg(client, GC2235_8BIT, GC2235_SENSOR_ID_H, &high); + gc2235_read_reg(client, GC2235_8BIT, GC2235_SENSOR_ID_L, &low); id = ((high << 8) | low); if (id != GC2235_ID) { From 0ae19e8c0866f170cb43170735b95f061e245b5a Mon Sep 17 00:00:00 2001 From: Shaokun Zhang Date: Tue, 25 May 2021 08:02:39 +0200 Subject: [PATCH 135/195] media: atomisp: remove the repeated declaration Function 'ia_css_mmu_invalidate_cache' is declared twice, remove the repeated declaration. Link: https://lore.kernel.org/linux-media/1621922559-1859-1-git-send-email-zhangshaokun@hisilicon.com Signed-off-by: Shaokun Zhang Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_compat.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat.h b/drivers/staging/media/atomisp/pci/atomisp_compat.h index a60551450c452..c16eaf3d126f7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat.h +++ b/drivers/staging/media/atomisp/pci/atomisp_compat.h @@ -83,8 +83,6 @@ int atomisp_q_dis_buffer_to_css(struct atomisp_sub_device *asd, void ia_css_mmu_invalidate_cache(void); -void ia_css_mmu_invalidate_cache(void); - int atomisp_css_start(struct atomisp_sub_device *asd, enum ia_css_pipe_id pipe_id, bool in_reset); From 85001df54b5f0dda164655e038aebee8b037c031 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 May 2021 14:43:19 +0200 Subject: [PATCH 136/195] media: atomisp: Remove unused declarations There is a few static declarations that are not used anywhere, remove them. Link: https://lore.kernel.org/linux-media/20210526124322.48915-3-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/pci/isp2400_input_system_local.h | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 072a92199e052..27f3c8a45730a 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -362,23 +362,6 @@ static const hrt_address MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { 0x00000200UL }; -static const mipi_lane_cfg_t MIPI_PORT_MAXLANES[N_MIPI_PORT_ID] = { - MIPI_4LANE_CFG, - MIPI_1LANE_CFG, - MIPI_2LANE_CFG -}; - -static const bool MIPI_PORT_ACTIVE[N_RX_MODE][N_MIPI_PORT_ID] = { - {true, true, false}, - {true, true, false}, - {true, true, false}, - {true, true, false}, - {true, true, true}, - {true, true, true}, - {true, true, true}, - {true, true, true} -}; - static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, From dbe93bc9706356799c8aac9fe3d6a132a5a6ec4c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 May 2021 14:43:20 +0200 Subject: [PATCH 137/195] media: atomisp: Annotate a couple of definitions with __maybe_unused There are definitions in the header that are not used by all modules inside the driver. Annotate them with __maybe_unused to avoid compiler warnings. Link: https://lore.kernel.org/linux-media/20210526124322.48915-4-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/isp2400_input_system_local.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 27f3c8a45730a..21f11bdfc85f3 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -356,7 +356,7 @@ struct rx_cfg_s { }; /* NOTE: The base has already an offset of 0x0100 */ -static const hrt_address MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { +static const hrt_address __maybe_unused MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { 0x00000000UL, 0x00000100UL, 0x00000200UL @@ -373,7 +373,7 @@ static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG} }; -static const hrt_address SUB_SYSTEM_OFFSET[N_SUB_SYSTEM_ID] = { +static const hrt_address __maybe_unused SUB_SYSTEM_OFFSET[N_SUB_SYSTEM_ID] = { 0x00001000UL, 0x00002000UL, 0x00003000UL, From 693064eafa9e4b7ab81b97d7349b6c7edb292011 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 May 2021 14:43:22 +0200 Subject: [PATCH 138/195] media: atomisp: Remove unused port_enabled variable Remove unused port_enabled variable in ia_css_isys_rx_configure(). Link: https://lore.kernel.org/linux-media/20210526124322.48915-6-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index 4a18da6bf0c15..60b98c10a3bc5 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -479,7 +479,6 @@ unsigned int ia_css_csi2_calculate_input_system_alignment( void ia_css_isys_rx_configure(const rx_cfg_t *config, const enum ia_css_input_mode input_mode) { - bool port_enabled[N_MIPI_PORT_ID]; bool any_port_enabled = false; enum mipi_port_id port; @@ -516,8 +515,6 @@ void ia_css_isys_rx_configure(const rx_cfg_t *config, _HRT_CSS_RECEIVER_2400_RX_COUNT_REG_IDX, config->rxcount); - port_enabled[port] = true; - if (input_mode != IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { /* MW: A bit of a hack, straight wiring of the capture * units,assuming they are linearly enumerated. */ From 1c6edb2831d941d5c14f7d2ac3f3f82655a560b4 Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Thu, 27 May 2021 21:39:22 +0200 Subject: [PATCH 139/195] media: atomisp: pci: Remove checks before kfree/kvfree Removed checks for pointers != NULL before freeing memory. If kvfree() and kfree() are given NULL pointers no operations are performed, so there is no need for the above-mentioned checks. Coccinelle detected the second of the two unnecessary checks. Link: https://lore.kernel.org/linux-media/20210527193922.25225-1-fmdefrancesco@gmail.com Signed-off-by: Fabio M. De Francesco Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css_firmware.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/sh_css_firmware.c index f4ce8ace9d509..5301cc014c7e6 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/sh_css_firmware.c @@ -363,10 +363,8 @@ void sh_css_unload_firmware(void) unsigned int i = 0; for (i = 0; i < sh_css_num_binaries; i++) { - if (fw_minibuffer[i].name) - kfree((void *)fw_minibuffer[i].name); - if (fw_minibuffer[i].buffer) - kvfree(fw_minibuffer[i].buffer); + kfree((void *)fw_minibuffer[i].name); + kvfree(fw_minibuffer[i].buffer); } kfree(fw_minibuffer); fw_minibuffer = NULL; From 454a6232e294e20fc339d05fcae18074df40757b Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Sat, 5 Jun 2021 04:08:55 +0200 Subject: [PATCH 140/195] media: atomisp: pci: Remove unnecessary (void *) cast Removed an unnecessary (void *) cast for an argument passed to kfree(). Link: https://lore.kernel.org/linux-media/20210605020855.1065-3-fmdefrancesco@gmail.com Suggested-by: Dan Carpenter Signed-off-by: Fabio M. De Francesco Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css_firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/sh_css_firmware.c index 5301cc014c7e6..e1a16a50e5884 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/sh_css_firmware.c @@ -363,7 +363,7 @@ void sh_css_unload_firmware(void) unsigned int i = 0; for (i = 0; i < sh_css_num_binaries; i++) { - kfree((void *)fw_minibuffer[i].name); + kfree(fw_minibuffer[i].name); kvfree(fw_minibuffer[i].buffer); } kfree(fw_minibuffer); From d27f346aa98fa8ba4fc6aa056240969ab34f9450 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 17 Jun 2021 09:23:29 +0200 Subject: [PATCH 141/195] media: atomisp: pci: fix error return code in atomisp_pci_probe() If init_atomisp_wdts() fails, atomisp_pci_probe() need return error code. Link: https://lore.kernel.org/linux-media/20210617072329.1233662-1-yangyingliang@huawei.com Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_v4l2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index af0d83eaa68c2..1e324f1f656e5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -1763,7 +1763,8 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i if (err < 0) goto register_entities_fail; /* init atomisp wdts */ - if (init_atomisp_wdts(isp) != 0) + err = init_atomisp_wdts(isp); + if (err != 0) goto wdt_work_queue_fail; /* save the iunit context only once after all the values are init'ed. */ From 69aa1deeab47a47f1e7876fabb76e1e11496c418 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Sun, 11 Jul 2021 16:51:01 +0200 Subject: [PATCH 142/195] media: atomisp: Perform a single memset() for union There is no need to memset() both dvs_grid_info and dvs_stat_grid_info separately: they are part of the same union. Instead, just zero the union itself. This additionally avoids a false positive (due to a gcc optimization bug[1]) when building with the coming FORTIFY_SOURCE improvements: In function 'fortify_memset_chk', inlined from 'sh_css_pipe_get_grid_info' at drivers/staging/media/atomisp/pci/sh_css.c:5186:3, inlined from 'ia_css_stream_create' at drivers/staging/media/atomisp/pci/sh_css.c:9442:10: ./include/linux/fortify-string.h:199:4: warning: call to '__write_overflow_field' declared with attribute warning: detected write beyond size of field (1st parameter); maybe use struct_group()? [-Wattribute-warning] 199 | __write_overflow_field(); | ^~~~~~~~~~~~~~~~~~~~~~~~ [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101419 Link: https://lore.kernel.org/linux-media/20210711145101.1434065-1-keescook@chromium.org Signed-off-by: Kees Cook Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c index 5dac4a506b002..c4b35cbab3737 100644 --- a/drivers/staging/media/atomisp/pci/sh_css.c +++ b/drivers/staging/media/atomisp/pci/sh_css.c @@ -5179,10 +5179,7 @@ sh_css_pipe_get_grid_info(struct ia_css_pipe *pipe, ia_css_binary_dvs_grid_info(binary, info, pipe); ia_css_binary_dvs_stat_grid_info(binary, info, pipe); } else { - memset(&info->dvs_grid.dvs_grid_info, 0, - sizeof(info->dvs_grid.dvs_grid_info)); - memset(&info->dvs_grid.dvs_stat_grid_info, 0, - sizeof(info->dvs_grid.dvs_stat_grid_info)); + memset(&info->dvs_grid, 0, sizeof(info->dvs_grid)); } if (binary) { From a5e5ceae597ba1df8a2a5720f80bf690c96805b0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 13 Jul 2021 17:25:22 +0200 Subject: [PATCH 143/195] media: atomisp: Move MIPI_PORT_LANES to the only user Move MIPI_PORT_LANES to the only user of it, i.e. pci/runtime/isys/src/rx.c. Link: https://lore.kernel.org/linux-media/20210713152523.19902-4-andriy.shevchenko@linux.intel.com Signed-off-by: Andy Shevchenko Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/isp2400_input_system_local.h | 11 ----------- .../staging/media/atomisp/pci/runtime/isys/src/rx.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h index 21f11bdfc85f3..2614b89b8e34b 100644 --- a/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h +++ b/drivers/staging/media/atomisp/pci/isp2400_input_system_local.h @@ -362,17 +362,6 @@ static const hrt_address __maybe_unused MIPI_PORT_OFFSET[N_MIPI_PORT_ID] = { 0x00000200UL }; -static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { - {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, - {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_2LANE_CFG}, - {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, - {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, - {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG} -}; - static const hrt_address __maybe_unused SUB_SYSTEM_OFFSET[N_SUB_SYSTEM_ID] = { 0x00001000UL, 0x00002000UL, diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index 60b98c10a3bc5..af153c3fb86d3 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -476,6 +476,17 @@ unsigned int ia_css_csi2_calculate_input_system_alignment( #endif #if !defined(ISP2401) +static const mipi_lane_cfg_t MIPI_PORT_LANES[N_RX_MODE][N_MIPI_PORT_ID] = { + {MIPI_4LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_0LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_2LANE_CFG}, + {MIPI_3LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, + {MIPI_2LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG}, + {MIPI_1LANE_CFG, MIPI_1LANE_CFG, MIPI_1LANE_CFG} +}; + void ia_css_isys_rx_configure(const rx_cfg_t *config, const enum ia_css_input_mode input_mode) { From f83f86e72622f46796fe5aed7fee980c543e4010 Mon Sep 17 00:00:00 2001 From: Martiros Shakhzadyan Date: Mon, 19 Jul 2021 07:52:16 +0200 Subject: [PATCH 144/195] media: atomisp: i2c: Remove a superfluous else clause in atomisp-mt9m114.c Remove a superfluous clause in mt9m114_s_power() Link: https://lore.kernel.org/linux-media/20210719055216.28508-1-vrzh@vrzh.net Signed-off-by: Martiros Shakhzadyan Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 34bf92de2f29b..49f4090856d30 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -570,14 +570,13 @@ static int power_down(struct v4l2_subdev *sd) static int mt9m114_s_power(struct v4l2_subdev *sd, int power) { - if (power == 0) { + if (power == 0) return power_down(sd); - } else { - if (power_up(sd)) - return -EINVAL; - return mt9m114_init_common(sd); - } + if (power_up(sd)) + return -EINVAL; + + return mt9m114_init_common(sd); } /* From c3cdc019a6bf03c4bf06fe8252db96eb6e4a3b5f Mon Sep 17 00:00:00 2001 From: Deepak R Varma Date: Fri, 30 Apr 2021 17:40:12 +0200 Subject: [PATCH 145/195] media: atomisp: pci: reposition braces as per coding style Misplaced braces makes it difficult to follow the code easily. This also goes against the code style guidelines. This resolved following checkpatch complaints: ERROR: open brace '{' following function definitions go on the next line ERROR: that open brace { should be on the previous line Link: https://lore.kernel.org/linux-media/YIwk3KbVGRPJwKa4@dU2104 [mchehab: dropped a hunk with a merge conflict] Cc: linux-media@vger.kernel.org, devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, drv@mailo.com # X-LSpam-Score: -7.3 (-------) Signed-off-by: Deepak R Varma Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/sh_css_mipi.c | 69 +++---- .../staging/media/atomisp/pci/sh_css_params.c | 171 ++++++++---------- drivers/staging/media/atomisp/pci/sh_css_sp.c | 108 +++++------ .../media/atomisp/pci/sh_css_version.c | 3 +- 4 files changed, 155 insertions(+), 196 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_mipi.c b/drivers/staging/media/atomisp/pci/sh_css_mipi.c index 3f34cc81be87f..75489f7d75eec 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_mipi.c +++ b/drivers/staging/media/atomisp/pci/sh_css_mipi.c @@ -91,7 +91,8 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, const enum atomisp_input_format format, const bool hasSOLandEOL, const unsigned int embedded_data_size_words, - unsigned int *size_mem_words) { + unsigned int *size_mem_words) +{ int err = 0; unsigned int bits_per_pixel = 0; @@ -118,8 +119,7 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, IA_CSS_ENTER("padded_width=%d, height=%d, format=%d, hasSOLandEOL=%d, embedded_data_size_words=%d\n", width_padded, height, format, hasSOLandEOL, embedded_data_size_words); - switch (format) - { + switch (format) { case ATOMISP_INPUT_FORMAT_RAW_6: /* 4p, 3B, 24bits */ bits_per_pixel = 6; break; @@ -178,12 +178,10 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, /* Even lines for YUV420 formats are double in bits_per_pixel. */ if (format == ATOMISP_INPUT_FORMAT_YUV420_8 || format == ATOMISP_INPUT_FORMAT_YUV420_10 - || format == ATOMISP_INPUT_FORMAT_YUV420_16) - { + || format == ATOMISP_INPUT_FORMAT_YUV420_16) { even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */ - } else - { + } else { even_line_bytes = odd_line_bytes; } @@ -236,7 +234,8 @@ ia_css_mipi_frame_calculate_size(const unsigned int width, #if !defined(ISP2401) int ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port, - const unsigned int size_mem_words) { + const unsigned int size_mem_words) +{ u32 idx; int err = -EBUSY; @@ -246,11 +245,9 @@ ia_css_mipi_frame_enable_check_on_size(const enum mipi_port_id port, for (idx = 0; idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT && my_css.mipi_sizes_for_check[port][idx] != 0; - idx++) /* do nothing */ - { + idx++) { /* do nothing */ } - if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT) - { + if (idx < IA_CSS_MIPI_SIZE_CHECK_MAX_NOF_ENTRIES_PER_PORT) { my_css.mipi_sizes_for_check[port][idx] = size_mem_words; err = 0; } @@ -271,7 +268,8 @@ mipi_init(void) int calculate_mipi_buff_size( struct ia_css_stream_config *stream_cfg, - unsigned int *size_mem_words) { + unsigned int *size_mem_words) +{ #if !defined(ISP2401) int err = -EINVAL; (void)stream_cfg; @@ -346,12 +344,10 @@ calculate_mipi_buff_size( /* Even lines for YUV420 formats are double in bits_per_pixel. */ if (format == ATOMISP_INPUT_FORMAT_YUV420_8 - || format == ATOMISP_INPUT_FORMAT_YUV420_10) - { + || format == ATOMISP_INPUT_FORMAT_YUV420_10) { even_line_bytes = (width_padded * 2 * bits_per_pixel + 7) >> 3; /* ceil ( bits per line / 8) */ - } else - { + } else { even_line_bytes = odd_line_bytes; } @@ -393,7 +389,8 @@ static bool buffers_needed(struct ia_css_pipe *pipe) int allocate_mipi_frames(struct ia_css_pipe *pipe, - struct ia_css_stream_info *info) { + struct ia_css_stream_info *info) +{ int err = -EINVAL; unsigned int port; @@ -402,8 +399,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, assert(pipe); assert(pipe->stream); - if ((!pipe) || (!pipe->stream)) - { + if ((!pipe) || (!pipe->stream)) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) exit: pipe or stream is null.\n", pipe); @@ -411,8 +407,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, } #ifdef ISP2401 - if (pipe->stream->config.online) - { + if (pipe->stream->config.online) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) exit: no buffers needed for 2401 pipe mode.\n", pipe); @@ -449,8 +444,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, #endif #if !defined(ISP2401) - if (ref_count_mipi_allocation[port] != 0) - { + if (ref_count_mipi_allocation[port] != 0) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) exit: already allocated for this port (port=%d).\n", pipe, port); @@ -462,8 +456,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, * TODO AM: Once that is changed (removed) this code should be removed as well. * In that case only 2400 related code should remain. */ - if (ref_count_mipi_allocation[port] != 0) - { + if (ref_count_mipi_allocation[port] != 0) { ref_count_mipi_allocation[port]++; ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, "allocate_mipi_frames(%p) leave: nothing to do, already allocated for this port (port=%d).\n", @@ -481,8 +474,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, { /* limit the scope of i,j */ unsigned int i, j; - for (i = 0; i < my_css.num_mipi_frames[port]; i++) - { + for (i = 0; i < my_css.num_mipi_frames[port]; i++) { /* free previous frame */ if (my_css.mipi_frames[port][i]) { ia_css_frame_free(my_css.mipi_frames[port][i]); @@ -535,7 +527,8 @@ allocate_mipi_frames(struct ia_css_pipe *pipe, } int -free_mipi_frames(struct ia_css_pipe *pipe) { +free_mipi_frames(struct ia_css_pipe *pipe) +{ int err = -EINVAL; unsigned int port; @@ -543,8 +536,7 @@ free_mipi_frames(struct ia_css_pipe *pipe) { "free_mipi_frames(%p) enter:\n", pipe); /* assert(pipe != NULL); TEMP: TODO: Should be assert only. */ - if (pipe) - { + if (pipe) { assert(pipe->stream); if ((!pipe) || (!pipe->stream)) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE_PRIVATE, @@ -620,8 +612,7 @@ free_mipi_frames(struct ia_css_pipe *pipe) { } #endif } - } else /* pipe ==NULL */ - { + } else { /* pipe ==NULL */ /* AM TEMP: free-ing all mipi buffers just like a legacy code. */ for (port = CSI_PORT0_ID; port < N_CSI_PORTS; port++) { unsigned int i; @@ -645,7 +636,8 @@ free_mipi_frames(struct ia_css_pipe *pipe) { } int -send_mipi_frames(struct ia_css_pipe *pipe) { +send_mipi_frames(struct ia_css_pipe *pipe) +{ int err = -EINVAL; unsigned int i; #ifndef ISP2401 @@ -658,8 +650,7 @@ send_mipi_frames(struct ia_css_pipe *pipe) { assert(pipe); assert(pipe->stream); - if (!pipe || !pipe->stream) - { + if (!pipe || !pipe->stream) { IA_CSS_ERROR("pipe or stream is null"); return -EINVAL; } @@ -686,8 +677,7 @@ send_mipi_frames(struct ia_css_pipe *pipe) { } /* Hand-over the SP-internal mipi buffers */ - for (i = 0; i < my_css.num_mipi_frames[port]; i++) - { + for (i = 0; i < my_css.num_mipi_frames[port]; i++) { /* Need to include the ofset for port. */ sh_css_update_host2sp_mipi_frame(port * NUM_MIPI_FRAMES_PER_STREAM + i, my_css.mipi_frames[port][i]); @@ -700,8 +690,7 @@ send_mipi_frames(struct ia_css_pipe *pipe) { * Send an event to inform the SP * that all MIPI frames are passed. **********************************/ - if (!sh_css_sp_is_running()) - { + if (!sh_css_sp_is_running()) { /* SP is not running. The queues are not valid */ IA_CSS_ERROR("sp is not running"); return err; diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 644e145759874..dbd3bfe3d343c 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -813,15 +813,15 @@ convert_allocate_fpntbl(struct ia_css_isp_parameters *params) } static int -store_fpntbl(struct ia_css_isp_parameters *params, ia_css_ptr ptr) { +store_fpntbl(struct ia_css_isp_parameters *params, ia_css_ptr ptr) +{ struct ia_css_host_data *isp_data; assert(params); assert(ptr != mmgr_NULL); isp_data = convert_allocate_fpntbl(params); - if (!isp_data) - { + if (!isp_data) { IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; } @@ -894,7 +894,8 @@ ia_css_process_kernel(struct ia_css_stream *stream, static int sh_css_select_dp_10bpp_config(const struct ia_css_pipe *pipe, - bool *is_dp_10bpp) { + bool *is_dp_10bpp) +{ int err = 0; /* Currently we check if 10bpp DPC configuration is required based * on the use case,i.e. if BDS and DPC is both enabled. The more cleaner @@ -903,12 +904,10 @@ sh_css_select_dp_10bpp_config(const struct ia_css_pipe *pipe, * implementation. (This is because the configuration is set before a * binary is selected, and the binary info is not available) */ - if ((!pipe) || (!is_dp_10bpp)) - { + if ((!pipe) || (!is_dp_10bpp)) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); err = -EINVAL; - } else - { + } else { *is_dp_10bpp = false; /* check if DPC is enabled from the host */ @@ -936,7 +935,8 @@ sh_css_select_dp_10bpp_config(const struct ia_css_pipe *pipe, int sh_css_set_black_frame(struct ia_css_stream *stream, - const struct ia_css_frame *raw_black_frame) { + const struct ia_css_frame *raw_black_frame) +{ struct ia_css_isp_parameters *params; /* this function desperately needs to be moved to the ISP or SP such * that it can use the DMA. @@ -957,13 +957,11 @@ sh_css_set_black_frame(struct ia_css_stream *stream, IA_CSS_ENTER_PRIVATE("black_frame=%p", raw_black_frame); if (params->fpn_config.data && - (params->fpn_config.width != width || params->fpn_config.height != height)) - { + (params->fpn_config.width != width || params->fpn_config.height != height)) { kvfree(params->fpn_config.data); params->fpn_config.data = NULL; } - if (!params->fpn_config.data) - { + if (!params->fpn_config.data) { params->fpn_config.data = kvmalloc(height * width * sizeof(short), GFP_KERNEL); if (!params->fpn_config.data) { @@ -977,8 +975,7 @@ sh_css_set_black_frame(struct ia_css_stream *stream, } /* store raw to fpntbl */ - for (y = 0; y < height; y++) - { + for (y = 0; y < height; y++) { for (x = 0; x < width; x += (ISP_VEC_NELEMS * 2)) { int ofs = y * width + x; @@ -1181,7 +1178,8 @@ sh_css_enable_pipeline(const struct ia_css_binary *binary) static int ia_css_process_zoom_and_motion( struct ia_css_isp_parameters *params, - const struct ia_css_pipeline_stage *first_stage) { + const struct ia_css_pipeline_stage *first_stage) +{ /* first_stage can be NULL */ const struct ia_css_pipeline_stage *stage; int err = 0; @@ -1195,8 +1193,7 @@ ia_css_process_zoom_and_motion( IA_CSS_ENTER_PRIVATE(""); /* Go through all stages to udate uds and cropping */ - for (stage = first_stage; stage; stage = stage->next) - { + for (stage = first_stage; stage; stage = stage->next) { struct ia_css_binary *binary; /* note: the var below is made static as it is quite large; if it is not static it ends up on the stack which could @@ -1581,7 +1578,8 @@ ia_css_isp_3a_statistics_map_allocate( int ia_css_get_3a_statistics(struct ia_css_3a_statistics *host_stats, - const struct ia_css_isp_3a_statistics *isp_stats) { + const struct ia_css_isp_3a_statistics *isp_stats) +{ struct ia_css_isp_3a_statistics_map *map; int ret = 0; @@ -1591,13 +1589,11 @@ ia_css_get_3a_statistics(struct ia_css_3a_statistics *host_stats, assert(isp_stats); map = ia_css_isp_3a_statistics_map_allocate(isp_stats, NULL); - if (map) - { + if (map) { hmm_load(isp_stats->data_ptr, map->data_ptr, isp_stats->size); ia_css_translate_3a_statistics(host_stats, map); ia_css_isp_3a_statistics_map_free(map); - } else - { + } else { IA_CSS_ERROR("out of memory"); ret = -ENOMEM; } @@ -1894,7 +1890,8 @@ sh_css_pipe_isp_config_get(struct ia_css_pipe *pipe) int ia_css_stream_set_isp_config( struct ia_css_stream *stream, - const struct ia_css_isp_config *config) { + const struct ia_css_isp_config *config) +{ return ia_css_stream_set_isp_config_on_pipe(stream, config, NULL); } @@ -1902,7 +1899,8 @@ int ia_css_stream_set_isp_config_on_pipe( struct ia_css_stream *stream, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe) { + struct ia_css_pipe *pipe) +{ int err = 0; if ((!stream) || (!config)) @@ -1923,7 +1921,8 @@ ia_css_stream_set_isp_config_on_pipe( int ia_css_pipe_set_isp_config(struct ia_css_pipe *pipe, - struct ia_css_isp_config *config) { + struct ia_css_isp_config *config) +{ struct ia_css_pipe *pipe_in = pipe; int err = 0; @@ -1948,7 +1947,8 @@ static int sh_css_set_global_isp_config_on_pipe( struct ia_css_pipe *curr_pipe, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe) { + struct ia_css_pipe *pipe) +{ int err = 0; int err1 = 0; int err2 = 0; @@ -1977,7 +1977,8 @@ static int sh_css_set_per_frame_isp_config_on_pipe( struct ia_css_stream *stream, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe) { + struct ia_css_pipe *pipe) +{ unsigned int i; bool per_frame_config_created = false; int err = 0; @@ -1991,8 +1992,7 @@ sh_css_set_per_frame_isp_config_on_pipe( IA_CSS_ENTER_PRIVATE("stream=%p, config=%p, pipe=%p", stream, config, pipe); - if (!pipe) - { + if (!pipe) { err = -EINVAL; goto exit; } @@ -2000,8 +2000,7 @@ sh_css_set_per_frame_isp_config_on_pipe( /* create per-frame ISP params object with default values * from stream->isp_params_configs if one doesn't already exist */ - if (!stream->per_frame_isp_params_configs) - { + if (!stream->per_frame_isp_params_configs) { err = sh_css_create_isp_params(stream, &stream->per_frame_isp_params_configs); if (err) @@ -2012,15 +2011,13 @@ sh_css_set_per_frame_isp_config_on_pipe( params = stream->per_frame_isp_params_configs; /* update new ISP params object with the new config */ - if (!sh_css_init_isp_params_from_global(stream, params, false, pipe)) - { + if (!sh_css_init_isp_params_from_global(stream, params, false, pipe)) { err1 = -EINVAL; } err2 = sh_css_init_isp_params_from_config(stream->pipes[0], params, config, pipe); - if (per_frame_config_created) - { + if (per_frame_config_created) { ddr_ptrs = ¶ms->ddr_ptrs; ddr_ptrs_size = ¶ms->ddr_ptrs_size; /* create per pipe reference to general ddr_ptrs */ @@ -2051,7 +2048,8 @@ static int sh_css_init_isp_params_from_config(struct ia_css_pipe *pipe, struct ia_css_isp_parameters *params, const struct ia_css_isp_config *config, - struct ia_css_pipe *pipe_in) { + struct ia_css_pipe *pipe_in) +{ int err = 0; bool is_dp_10bpp = true; @@ -2096,8 +2094,7 @@ sh_css_init_isp_params_from_config(struct ia_css_pipe *pipe, } if (0 == - sh_css_select_dp_10bpp_config(pipe, &is_dp_10bpp)) - { + sh_css_select_dp_10bpp_config(pipe, &is_dp_10bpp)) { /* return an error when both DPC and BDS is enabled by the * user. */ /* we do not exit from this point immediately to allow internal @@ -2105,8 +2102,7 @@ sh_css_init_isp_params_from_config(struct ia_css_pipe *pipe, if (is_dp_10bpp) { err = -EINVAL; } - } else - { + } else { err = -EINVAL; goto exit; } @@ -2359,7 +2355,8 @@ static unsigned int g_param_buffer_dequeue_count; static unsigned int g_param_buffer_enqueue_count; int -ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { +ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) +{ int err = 0; unsigned int i; struct sh_css_ddr_address_map *ddr_ptrs; @@ -2369,8 +2366,7 @@ ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { assert(stream); IA_CSS_ENTER_PRIVATE("void"); - if (!stream) - { + if (!stream) { IA_CSS_LEAVE_ERR_PRIVATE(-EINVAL); return -EINVAL; } @@ -2385,8 +2381,7 @@ ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { goto ERR; params = stream->isp_params_configs; - if (!sh_css_init_isp_params_from_global(stream, params, true, NULL)) - { + if (!sh_css_init_isp_params_from_global(stream, params, true, NULL)) { /* we do not return the error immediately to enable internal * firmware feature testing */ err = -EINVAL; @@ -2396,8 +2391,7 @@ ia_css_stream_isp_parameters_init(struct ia_css_stream *stream) { ddr_ptrs_size = ¶ms->ddr_ptrs_size; /* create per pipe reference to general ddr_ptrs */ - for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) - { + for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { ref_sh_css_ddr_address_map(ddr_ptrs, ¶ms->pipe_ddr_ptrs[i]); params->pipe_ddr_ptrs_size[i] = *ddr_ptrs_size; } @@ -2431,7 +2425,8 @@ ia_css_set_sdis2_config( static int sh_css_create_isp_params(struct ia_css_stream *stream, - struct ia_css_isp_parameters **isp_params_out) { + struct ia_css_isp_parameters **isp_params_out) +{ bool succ = true; unsigned int i; struct sh_css_ddr_address_map *ddr_ptrs; @@ -2441,23 +2436,20 @@ sh_css_create_isp_params(struct ia_css_stream *stream, struct ia_css_isp_parameters *params = kvmalloc(sizeof(struct ia_css_isp_parameters), GFP_KERNEL); - if (!params) - { + if (!params) { *isp_params_out = NULL; err = -ENOMEM; IA_CSS_ERROR("%s:%d error: cannot allocate memory", __FILE__, __LINE__); IA_CSS_LEAVE_ERR_PRIVATE(err); return err; - } else - { + } else { memset(params, 0, sizeof(struct ia_css_isp_parameters)); } ddr_ptrs = ¶ms->ddr_ptrs; ddr_ptrs_size = ¶ms->ddr_ptrs_size; - for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) - { + for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) { memset(¶ms->pipe_ddr_ptrs[i], 0, sizeof(params->pipe_ddr_ptrs[i])); memset(¶ms->pipe_ddr_ptrs_size[i], 0, @@ -2714,7 +2706,8 @@ sh_css_init_isp_params_from_global(struct ia_css_stream *stream, } int -sh_css_params_init(void) { +sh_css_params_init(void) +{ int i, p; IA_CSS_ENTER_PRIVATE("void"); @@ -2723,8 +2716,7 @@ sh_css_params_init(void) { g_param_buffer_dequeue_count = 0; g_param_buffer_enqueue_count = 0; - for (p = 0; p < IA_CSS_PIPE_ID_NUM; p++) - { + for (p = 0; p < IA_CSS_PIPE_ID_NUM; p++) { for (i = 0; i < SH_CSS_MAX_STAGES; i++) { xmem_sp_stage_ptrs[p][i] = ia_css_refcount_increment(-1, @@ -2762,8 +2754,7 @@ sh_css_params_init(void) { ATOMISP_MAP_FLAG_CLEARED)); if ((sp_ddr_ptrs == mmgr_NULL) || - (xmem_sp_group_ptrs == mmgr_NULL)) - { + (xmem_sp_group_ptrs == mmgr_NULL)) { ia_css_uninit(); IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; @@ -3094,14 +3085,14 @@ store_morph_plane( unsigned int width, unsigned int height, ia_css_ptr dest, - unsigned int aligned_width) { + unsigned int aligned_width) +{ struct ia_css_host_data *isp_data; assert(dest != mmgr_NULL); isp_data = convert_allocate_morph_plane(data, width, height, aligned_width); - if (!isp_data) - { + if (!isp_data) { IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM); return -ENOMEM; } @@ -3221,7 +3212,8 @@ int sh_css_param_update_isp_params(struct ia_css_pipe *curr_pipe, struct ia_css_isp_parameters *params, bool commit, - struct ia_css_pipe *pipe_in) { + struct ia_css_pipe *pipe_in) +{ int err = 0; ia_css_ptr cpy; int i; @@ -3238,15 +3230,13 @@ sh_css_param_update_isp_params(struct ia_css_pipe *curr_pipe, raw_bit_depth = ia_css_stream_input_format_bits_per_pixel(curr_pipe->stream); /* now make the map available to the sp */ - if (!commit) - { + if (!commit) { IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } /* enqueue a copies of the mem_map to the designated pipelines */ - for (i = 0; i < curr_pipe->stream->num_pipes; i++) - { + for (i = 0; i < curr_pipe->stream->num_pipes; i++) { struct ia_css_pipe *pipe; struct sh_css_ddr_address_map *cur_map; struct sh_css_ddr_address_map_size *cur_map_size; @@ -3430,7 +3420,8 @@ sh_css_params_write_to_ddr_internal( struct ia_css_isp_parameters *params, const struct ia_css_pipeline_stage *stage, struct sh_css_ddr_address_map *ddr_map, - struct sh_css_ddr_address_map_size *ddr_map_size) { + struct sh_css_ddr_address_map_size *ddr_map_size) +{ int err; const struct ia_css_binary *binary; @@ -3452,8 +3443,7 @@ sh_css_params_write_to_ddr_internal( stage_num = stage->stage_num; - if (binary->info->sp.enable.fpnr) - { + if (binary->info->sp.enable.fpnr) { buff_realloced = reallocate_buffer(&ddr_map->fpn_tbl, &ddr_map_size->fpn_tbl, (size_t)(FPNTBL_BYTES(binary)), @@ -3474,8 +3464,7 @@ sh_css_params_write_to_ddr_internal( } } - if (binary->info->sp.enable.sc) - { + if (binary->info->sp.enable.sc) { u32 enable_conv; size_t bytes; @@ -3577,8 +3566,7 @@ sh_css_params_write_to_ddr_internal( * DPC kernel. The code below sets the pipe specific configuration to * individual binaries. */ if (IS_ISP2401 && - params->pipe_dpc_config_changed[pipe_id] && binary->info->sp.enable.dpc) - { + params->pipe_dpc_config_changed[pipe_id] && binary->info->sp.enable.dpc) { unsigned int size = stage->binary->info->mem_offsets.offsets.param->dmem.dp.size; @@ -3596,8 +3584,7 @@ sh_css_params_write_to_ddr_internal( } } - if (params->config_changed[IA_CSS_MACC_ID] && binary->info->sp.enable.macc) - { + if (params->config_changed[IA_CSS_MACC_ID] && binary->info->sp.enable.macc) { unsigned int i, j, idx; unsigned int idx_map[] = { 0, 1, 3, 2, 6, 7, 5, 4, 12, 13, 15, 14, 10, 11, 9, 8 @@ -3646,8 +3633,7 @@ sh_css_params_write_to_ddr_internal( sizeof(converted_macc_table.data)); } - if (binary->info->sp.enable.dvs_6axis) - { + if (binary->info->sp.enable.dvs_6axis) { /* because UV is packed into the Y plane, calc total * YYU size = /2 gives size of UV-only, * total YYU size = UV-only * 3. @@ -3705,8 +3691,7 @@ sh_css_params_write_to_ddr_internal( } } - if (binary->info->sp.enable.ca_gdc) - { + if (binary->info->sp.enable.ca_gdc) { unsigned int i; ia_css_ptr *virt_addr_tetra_x[ @@ -3811,8 +3796,7 @@ sh_css_params_write_to_ddr_internal( } /* After special cases like SC, FPN since they may change parameters */ - for (mem = 0; mem < N_IA_CSS_MEMORIES; mem++) - { + for (mem = 0; mem < N_IA_CSS_MEMORIES; mem++) { const struct ia_css_isp_data *isp_data = ia_css_isp_param_get_isp_mem_init(&binary->info->sp.mem_initializers, IA_CSS_PARAM_CLASS_PARAM, mem); @@ -4025,7 +4009,8 @@ static int write_ia_css_isp_parameter_set_info_to_ddr( static int free_ia_css_isp_parameter_set_info( - ia_css_ptr ptr) { + ia_css_ptr ptr) +{ int err = 0; struct ia_css_isp_parameter_set_info isp_params_info; unsigned int i; @@ -4034,8 +4019,7 @@ free_ia_css_isp_parameter_set_info( IA_CSS_ENTER_PRIVATE("ptr = %u", ptr); /* sanity check - ptr must be valid */ - if (!ia_css_refcount_is_valid(ptr)) - { + if (!ia_css_refcount_is_valid(ptr)) { IA_CSS_ERROR("%s: IA_CSS_REFCOUNT_PARAM_SET_POOL(0x%x) invalid arg", __func__, ptr); err = -EINVAL; @@ -4046,8 +4030,7 @@ free_ia_css_isp_parameter_set_info( hmm_load(ptr, &isp_params_info.mem_map, sizeof(struct sh_css_ddr_address_map)); /* copy map using size info */ for (i = 0; i < (sizeof(struct sh_css_ddr_address_map_size) / - sizeof(size_t)); i++) - { + sizeof(size_t)); i++) { if (addrs[i] == mmgr_NULL) continue; @@ -4254,7 +4237,8 @@ sh_css_update_uds_and_crop_info_based_on_zoom_region( struct sh_css_uds_info *uds, /* out */ struct sh_css_crop_pos *sp_out_crop_pos, /* out */ struct ia_css_resolution pipe_in_res, - bool enable_zoom) { + bool enable_zoom) +{ unsigned int x0 = 0, y0 = 0, x1 = 0, y1 = 0; int err = 0; /* Note: @@ -4285,19 +4269,16 @@ sh_css_update_uds_and_crop_info_based_on_zoom_region( if ((x0 > x1) || (y0 > y1) || (x1 > pipe_in_res.width) || (y1 > pipe_in_res.height)) return -EINVAL; - if (!enable_zoom) - { + if (!enable_zoom) { uds->curr_dx = HRT_GDC_N; uds->curr_dy = HRT_GDC_N; } - if (info->enable.dvs_envelope) - { + if (info->enable.dvs_envelope) { /* Zoom region is only supported by the UDS module on ISP * 2 and higher. It is not supported in video mode on ISP 1 */ return -EINVAL; - } else - { + } else { if (enable_zoom) { /* A. Calculate dx/dy based on crop region using in_frame_info * Scale the crop region if in_frame_info to the stage is not same as diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.c b/drivers/staging/media/atomisp/pci/sh_css_sp.c index 02f5a73b40963..a73e8ca1e225f 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_sp.c +++ b/drivers/staging/media/atomisp/pci/sh_css_sp.c @@ -535,12 +535,12 @@ sh_css_copy_frame_to_spframe(struct ia_css_frame_sp *sp_frame_out, } static int -set_input_frame_buffer(const struct ia_css_frame *frame) { +set_input_frame_buffer(const struct ia_css_frame *frame) +{ if (!frame) return -EINVAL; - switch (frame->info.format) - { + switch (frame->info.format) { case IA_CSS_FRAME_FORMAT_QPLANE6: case IA_CSS_FRAME_FORMAT_YUV420_16: case IA_CSS_FRAME_FORMAT_RAW_PACKED: @@ -566,12 +566,12 @@ set_input_frame_buffer(const struct ia_css_frame *frame) { static int set_output_frame_buffer(const struct ia_css_frame *frame, - unsigned int idx) { + unsigned int idx) +{ if (!frame) return -EINVAL; - switch (frame->info.format) - { + switch (frame->info.format) { case IA_CSS_FRAME_FORMAT_YUV420: case IA_CSS_FRAME_FORMAT_YUV422: case IA_CSS_FRAME_FORMAT_YUV444: @@ -607,12 +607,12 @@ set_output_frame_buffer(const struct ia_css_frame *frame, } static int -set_view_finder_buffer(const struct ia_css_frame *frame) { +set_view_finder_buffer(const struct ia_css_frame *frame) +{ if (!frame) return -EINVAL; - switch (frame->info.format) - { + switch (frame->info.format) { /* the dual output pin */ case IA_CSS_FRAME_FORMAT_NV12: case IA_CSS_FRAME_FORMAT_NV12_16: @@ -732,7 +732,8 @@ sh_css_sp_set_disable_continuous_viewfinder(bool flag) } static int -sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) { +sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) +{ int err = 0; int i; @@ -742,8 +743,7 @@ sh_css_sp_write_frame_pointers(const struct sh_css_binary_args *args) { err = set_input_frame_buffer(args->in_frame); if (!err && args->out_vf_frame) err = set_view_finder_buffer(args->out_vf_frame); - for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) - { + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { if (!err && args->out_frame[i]) err = set_output_frame_buffer(args->out_frame[i], i); } @@ -786,7 +786,8 @@ sh_css_stage_write_binary_info(struct ia_css_binary_info *info) } static int -copy_isp_mem_if_to_ddr(struct ia_css_binary *binary) { +copy_isp_mem_if_to_ddr(struct ia_css_binary *binary) +{ int err; err = ia_css_isp_param_copy_isp_mem_if_to_ddr( @@ -817,7 +818,8 @@ configure_isp_from_args( const struct ia_css_binary *binary, const struct sh_css_binary_args *args, bool two_ppc, - bool deinterleaved) { + bool deinterleaved) +{ ia_css_fpn_configure(binary, &binary->in_frame_info); ia_css_crop_configure(binary, &args->delay_frames[0]->info); ia_css_qplane_configure(pipeline, binary, &binary->in_frame_info); @@ -896,7 +898,8 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, bool xnr, const struct ia_css_isp_param_css_segments *isp_mem_if, unsigned int if_config_index, - bool two_ppc) { + bool two_ppc) +{ const struct ia_css_binary_xinfo *xinfo; const struct ia_css_binary_info *info; int err = 0; @@ -928,8 +931,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, ia_css_pipeline_get_sp_thread_id(pipe_num, &thread_id); - if (!info) - { + if (!info) { sh_css_sp_group.pipe[thread_id].sp_stage_addr[stage] = mmgr_NULL; return 0; } @@ -961,8 +963,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.in.info, &binary->in_frame_info); - for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) - { + for (i = 0; i < IA_CSS_BINARY_MAX_OUTPUT_PORTS; i++) { ia_css_frame_info_to_frame_sp_info(&sh_css_sp_stage.frames.out[i].info, &binary->out_frame_info[i]); } @@ -996,16 +997,14 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, err = sh_css_sp_write_frame_pointers(args); /* TODO: move it to a better place */ - if (binary->info->sp.enable.s3a) - { + if (binary->info->sp.enable.s3a) { ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_3A_STATISTICS, thread_id, &queue_id); sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.s3a_buf, queue_id, mmgr_EXCEPTION, IA_CSS_BUFFER_TYPE_3A_STATISTICS); } - if (binary->info->sp.enable.dis) - { + if (binary->info->sp.enable.dis) { ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_DIS_STATISTICS, thread_id, &queue_id); sh_css_copy_buffer_attr_to_spbuffer(&sh_css_sp_stage.frames.dvs_buf, queue_id, @@ -1046,8 +1045,7 @@ sh_css_sp_init_stage(struct ia_css_binary *binary, * the original out res. for video pipe, it has two output pins --- out and * vf_out, so it can keep these two resolutions already. */ if (binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW && - (binary->vf_downscale_log2 > 0)) - { + (binary->vf_downscale_log2 > 0)) { /* TODO: Remove this after preview output decimation is fixed * by configuring out&vf info fiels properly */ sh_css_sp_stage.frames.out[0].info.padded_width @@ -1069,7 +1067,8 @@ sp_init_stage(struct ia_css_pipeline_stage *stage, unsigned int pipe_num, bool xnr, unsigned int if_config_index, - bool two_ppc) { + bool two_ppc) +{ struct ia_css_binary *binary; const struct ia_css_fw_info *firmware; const struct sh_css_binary_args *args; @@ -1105,14 +1104,12 @@ sp_init_stage(struct ia_css_pipeline_stage *stage, args = &stage->args; stage_num = stage->stage_num; - if (binary) - { + if (binary) { info = binary->info; binary_name = (const char *)(info->blob->name); blob_info = &info->blob->header.blob; ia_css_init_memory_interface(mem_if, &binary->mem_params, &binary->css_params); - } else if (firmware) - { + } else if (firmware) { const struct ia_css_frame_info *out_infos[IA_CSS_BINARY_MAX_OUTPUT_PORTS] = {NULL}; if (args->out_frame[0]) @@ -1133,8 +1130,7 @@ sp_init_stage(struct ia_css_pipeline_stage *stage, binary_name = IA_CSS_EXT_ISP_PROG_NAME(firmware); blob_info = &firmware->blob; mem_if = (struct ia_css_isp_param_css_segments *)&firmware->mem_initializers; - } else - { + } else { /* SP stage */ assert(stage->sp_func != IA_CSS_PIPELINE_NO_FUNC); /* binary and blob_info are now NULL. @@ -1205,7 +1201,8 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, *internal_frame_origin_bqs_on_sctbl, /* Origin of internal frame positioned on shading table at shading correction in ISP. */ const struct ia_css_isp_parameters *params - ) { + ) +{ /* Get first stage */ struct ia_css_pipeline_stage *stage = NULL; struct ia_css_binary *first_binary = NULL; @@ -1223,17 +1220,14 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, first_binary = me->stages->binary; if (input_mode == IA_CSS_INPUT_MODE_SENSOR || - input_mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) - { + input_mode == IA_CSS_INPUT_MODE_BUFFERED_SENSOR) { assert(port_id < N_MIPI_PORT_ID); if (port_id >= N_MIPI_PORT_ID) /* should not happen but KW does not know */ return; /* we should be able to return an error */ if_config_index = (uint8_t)(port_id - MIPI_PORT0_ID); - } else if (input_mode == IA_CSS_INPUT_MODE_MEMORY) - { + } else if (input_mode == IA_CSS_INPUT_MODE_MEMORY) { if_config_index = SH_CSS_IF_CONFIG_NOT_NEEDED; - } else - { + } else { if_config_index = 0x0; } @@ -1241,15 +1235,13 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, memset(&sh_css_sp_group.pipe[thread_id], 0, sizeof(struct sh_css_sp_pipeline)); /* Count stages */ - for (stage = me->stages, num = 0; stage; stage = stage->next, num++) - { + for (stage = me->stages, num = 0; stage; stage = stage->next, num++) { stage->stage_num = num; ia_css_debug_pipe_graph_dump_stage(stage, id); } me->num_stages = num; - if (first_binary) - { + if (first_binary) { /* Init pipeline data */ sh_css_sp_init_group(two_ppc, first_binary->input_format, offline, if_config_index); @@ -1277,8 +1269,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, /* TODO: next indicates from which queues parameters need to be sampled, needs checking/improvement */ - if (ia_css_pipeline_uses_params(me)) - { + if (ia_css_pipeline_uses_params(me)) { sh_css_sp_group.pipe[thread_id].pipe_config = SH_CSS_PIPE_CONFIG_SAMPLE_PARAMS << thread_id; } @@ -1292,15 +1283,13 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, pipe = find_pipe_by_num(pipe_num); assert(pipe); - if (!pipe) - { + if (!pipe) { return; } sh_css_sp_group.pipe[thread_id].scaler_pp_lut = sh_css_pipe_get_pp_gdc_lut(pipe); #if defined(SH_CSS_ENABLE_METADATA) - if (md_info && md_info->size > 0) - { + if (md_info && md_info->size > 0) { sh_css_sp_group.pipe[thread_id].metadata.width = md_info->resolution.width; sh_css_sp_group.pipe[thread_id].metadata.height = md_info->resolution.height; sh_css_sp_group.pipe[thread_id].metadata.stride = md_info->stride; @@ -1316,8 +1305,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS) sh_css_sp_group.pipe[thread_id].output_frame_queue_id = (uint32_t)SH_CSS_INVALID_QUEUE_ID; - if (pipe_id != IA_CSS_PIPE_ID_COPY) - { + if (pipe_id != IA_CSS_PIPE_ID_COPY) { ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, (enum sh_css_queue_id *)( &sh_css_sp_group.pipe[thread_id].output_frame_queue_id)); @@ -1329,14 +1317,12 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, * the parameters are passed to the isp for the shading table centering. */ if (internal_frame_origin_bqs_on_sctbl && - params && params->shading_settings.enable_shading_table_conversion == 0) - { + params && params->shading_settings.enable_shading_table_conversion == 0) { sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_x_bqs_on_sctbl = (uint32_t)internal_frame_origin_bqs_on_sctbl->x; sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_y_bqs_on_sctbl = (uint32_t)internal_frame_origin_bqs_on_sctbl->y; - } else - { + } else { sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_x_bqs_on_sctbl = 0; sh_css_sp_group.pipe[thread_id].shading.internal_frame_origin_y_bqs_on_sctbl = @@ -1347,8 +1333,7 @@ sh_css_sp_init_pipeline(struct ia_css_pipeline *me, IA_CSS_LOG("pipe_id %d port_config %08x", pipe_id, sh_css_sp_group.pipe[thread_id].inout_port_config); - for (stage = me->stages, num = 0; stage; stage = stage->next, num++) - { + for (stage = me->stages, num = 0; stage; stage = stage->next, num++) { sh_css_sp_group.pipe[thread_id].num_stages++; if (is_sp_stage(stage)) { sp_init_sp_stage(stage, pipe_num, two_ppc, @@ -1400,7 +1385,8 @@ bool sh_css_write_host2sp_command(enum host2sp_commands host2sp_command) } enum host2sp_commands -sh_css_read_host2sp_command(void) { +sh_css_read_host2sp_command(void) +{ unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; unsigned int offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_command) / sizeof(int); @@ -1586,7 +1572,8 @@ sh_css_event_init_irq_mask(void) int ia_css_pipe_set_irq_mask(struct ia_css_pipe *pipe, unsigned int or_mask, - unsigned int and_mask) { + unsigned int and_mask) +{ unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; unsigned int offset; struct sh_css_event_irq_mask event_irq_mask; @@ -1625,7 +1612,8 @@ ia_css_pipe_set_irq_mask(struct ia_css_pipe *pipe, int ia_css_event_get_irq_mask(const struct ia_css_pipe *pipe, unsigned int *or_mask, - unsigned int *and_mask) { + unsigned int *and_mask) +{ unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com; unsigned int offset; struct sh_css_event_irq_mask event_irq_mask; diff --git a/drivers/staging/media/atomisp/pci/sh_css_version.c b/drivers/staging/media/atomisp/pci/sh_css_version.c index fa6de61e49952..f5ff8ca66b508 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_version.c +++ b/drivers/staging/media/atomisp/pci/sh_css_version.c @@ -21,7 +21,8 @@ #include "sh_css_firmware.h" int -ia_css_get_version(char *version, int max_size) { +ia_css_get_version(char *version, int max_size) +{ char *css_version; if (!IS_ISP2401) From e9f504f7b585c822b4c7d42bbbf18bbdd0241df4 Mon Sep 17 00:00:00 2001 From: Viktor Prutyanov Date: Mon, 19 Jul 2021 19:05:05 +0200 Subject: [PATCH 146/195] media: rc: meson-ir-tx: document device tree bindings This patch adds binding documentation for the IR transmitter available in Amlogic Meson SoCs. Signed-off-by: Viktor Prutyanov Acked-by: Martin Blumenstingl Reviewed-by: Rob Herring Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/amlogic,meson-ir-tx.yaml | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/amlogic,meson-ir-tx.yaml diff --git a/Documentation/devicetree/bindings/media/amlogic,meson-ir-tx.yaml b/Documentation/devicetree/bindings/media/amlogic,meson-ir-tx.yaml new file mode 100644 index 0000000000000..4432fea326507 --- /dev/null +++ b/Documentation/devicetree/bindings/media/amlogic,meson-ir-tx.yaml @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) + +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/media/amlogic,meson-ir-tx.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Amlogic Meson IR transmitter + +maintainers: + - Viktor Prutyanov + +description: | + Some Amlogic SoCs such as A311D and T950D4 have IR transmitter + (also called blaster) controller onboard. It is capable of + sending IR signals with arbitrary carrier frequency and duty cycle. + +properties: + compatible: + oneOf: + - const: amlogic,meson-ir-tx + - items: + - const: amlogic,meson-g12a-ir-tx + - const: amlogic,meson-ir-tx + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 2 + + clock-names: + items: + - const: sysclk + - const: xtal + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + + ir@ff80014c { + compatible = "amlogic,meson-g12a-ir-tx", "amlogic,meson-ir-tx"; + reg = <0xff80014c 0x10>; + interrupts = <0 198 IRQ_TYPE_EDGE_RISING>; + clocks = <&clkc CLKID_CLK81>, <&xtal>; + clock-names = "sysclk", "xtal"; + }; From 49be1c78d575eedf862a05aebfd5ab5c24193f61 Mon Sep 17 00:00:00 2001 From: Viktor Prutyanov Date: Mon, 19 Jul 2021 19:05:06 +0200 Subject: [PATCH 147/195] media: rc: introduce Meson IR TX driver This patch adds the driver for Amlogic Meson IR transmitter. Some Amlogic SoCs such as A311D and T950D4 have IR transmitter (also called blaster) controller onboard. It is capable of sending IR signals with arbitrary carrier frequency and duty cycle. The driver supports 2 modulation clock sources: - xtal3 clock (xtal divided by 3) - 1us clock Signed-off-by: Viktor Prutyanov Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 10 + drivers/media/rc/Makefile | 1 + drivers/media/rc/meson-ir-tx.c | 407 +++++++++++++++++++++++++++++++++ 3 files changed, 418 insertions(+) create mode 100644 drivers/media/rc/meson-ir-tx.c diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index d0a8326b75c22..fd5a7a0587143 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -246,6 +246,16 @@ config IR_MESON To compile this driver as a module, choose M here: the module will be called meson-ir. +config IR_MESON_TX + tristate "Amlogic Meson IR TX" + depends on ARCH_MESON || COMPILE_TEST + help + Say Y if you want to use the IR transmitter available on + Amlogic Meson SoCs. + + To compile this driver as a module, choose M here: the + module will be called meson-ir-tx. + config IR_MTK tristate "Mediatek IR remote receiver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 692e9b6b203f8..0db51fad27d64 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o obj-$(CONFIG_IR_MCEUSB) += mceusb.o obj-$(CONFIG_IR_FINTEK) += fintek-cir.o obj-$(CONFIG_IR_MESON) += meson-ir.o +obj-$(CONFIG_IR_MESON_TX) += meson-ir-tx.o obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o obj-$(CONFIG_IR_ENE) += ene_ir.o obj-$(CONFIG_IR_REDRAT3) += redrat3.o diff --git a/drivers/media/rc/meson-ir-tx.c b/drivers/media/rc/meson-ir-tx.c new file mode 100644 index 0000000000000..3055f8e1b6ffa --- /dev/null +++ b/drivers/media/rc/meson-ir-tx.c @@ -0,0 +1,407 @@ +// SPDX-License-Identifier: GPL-2.0-only +/** + * meson-ir-tx.c - Amlogic Meson IR TX driver + * + * Copyright (c) 2021, SberDevices. All Rights Reserved. + * + * Author: Viktor Prutyanov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NAME "Meson IR TX" +#define DRIVER_NAME "meson-ir-tx" + +#define MIRTX_DEFAULT_CARRIER 38000 +#define MIRTX_DEFAULT_DUTY_CYCLE 50 +#define MIRTX_FIFO_THD 32 + +#define IRB_MOD_1US_CLK_RATE 1000000 + +#define IRB_FIFO_LEN 128 + +#define IRB_ADDR0 0x0 +#define IRB_ADDR1 0x4 +#define IRB_ADDR2 0x8 +#define IRB_ADDR3 0xc + +#define IRB_MAX_DELAY (1 << 10) +#define IRB_DELAY_MASK (IRB_MAX_DELAY - 1) + +/* IRCTRL_IR_BLASTER_ADDR0 */ +#define IRB_MOD_CLK(x) ((x) << 12) +#define IRB_MOD_SYS_CLK 0 +#define IRB_MOD_XTAL3_CLK 1 +#define IRB_MOD_1US_CLK 2 +#define IRB_MOD_10US_CLK 3 +#define IRB_INIT_HIGH BIT(2) +#define IRB_ENABLE BIT(0) + +/* IRCTRL_IR_BLASTER_ADDR2 */ +#define IRB_MOD_COUNT(lo, hi) ((((lo) - 1) << 16) | ((hi) - 1)) + +/* IRCTRL_IR_BLASTER_ADDR2 */ +#define IRB_WRITE_FIFO BIT(16) +#define IRB_MOD_ENABLE BIT(12) +#define IRB_TB_1US (0x0 << 10) +#define IRB_TB_10US (0x1 << 10) +#define IRB_TB_100US (0x2 << 10) +#define IRB_TB_MOD_CLK (0x3 << 10) + +/* IRCTRL_IR_BLASTER_ADDR3 */ +#define IRB_FIFO_THD_PENDING BIT(16) +#define IRB_FIFO_IRQ_ENABLE BIT(8) + +struct meson_irtx { + struct device *dev; + void __iomem *reg_base; + u32 *buf; + unsigned int buf_len; + unsigned int buf_head; + unsigned int carrier; + unsigned int duty_cycle; + /* Locks buf */ + spinlock_t lock; + struct completion completion; + unsigned long clk_rate; +}; + +static void meson_irtx_set_mod(struct meson_irtx *ir) +{ + unsigned int cnt = DIV_ROUND_CLOSEST(ir->clk_rate, ir->carrier); + unsigned int pulse_cnt = DIV_ROUND_CLOSEST(cnt * ir->duty_cycle, 100); + unsigned int space_cnt = cnt - pulse_cnt; + + dev_dbg(ir->dev, "F_mod = %uHz, T_mod = %luns, duty_cycle = %u%%\n", + ir->carrier, NSEC_PER_SEC / ir->clk_rate * cnt, + 100 * pulse_cnt / cnt); + + writel(IRB_MOD_COUNT(pulse_cnt, space_cnt), + ir->reg_base + IRB_ADDR1); +} + +static void meson_irtx_setup(struct meson_irtx *ir, unsigned int clk_nr) +{ + /* + * Disable the TX, set modulator clock tick and set initialize + * output to be high. Set up carrier frequency and duty cycle. Then + * unset initialize output. Enable FIFO interrupt, set FIFO interrupt + * threshold. Finally, enable the transmitter back. + */ + writel(~IRB_ENABLE & (IRB_MOD_CLK(clk_nr) | IRB_INIT_HIGH), + ir->reg_base + IRB_ADDR0); + meson_irtx_set_mod(ir); + writel(readl(ir->reg_base + IRB_ADDR0) & ~IRB_INIT_HIGH, + ir->reg_base + IRB_ADDR0); + writel(IRB_FIFO_IRQ_ENABLE | MIRTX_FIFO_THD, + ir->reg_base + IRB_ADDR3); + writel(readl(ir->reg_base + IRB_ADDR0) | IRB_ENABLE, + ir->reg_base + IRB_ADDR0); +} + +static u32 meson_irtx_prepare_pulse(struct meson_irtx *ir, unsigned int time) +{ + unsigned int delay; + unsigned int tb = IRB_TB_MOD_CLK; + unsigned int tb_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, ir->carrier); + + delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK; + + return ((IRB_WRITE_FIFO | IRB_MOD_ENABLE) | tb | delay); +} + +static u32 meson_irtx_prepare_space(struct meson_irtx *ir, unsigned int time) +{ + unsigned int delay; + unsigned int tb = IRB_TB_100US; + unsigned int tb_us = 100; + + if (time <= IRB_MAX_DELAY) { + tb = IRB_TB_1US; + tb_us = 1; + } else if (time <= 10 * IRB_MAX_DELAY) { + tb = IRB_TB_10US; + tb_us = 10; + } else if (time <= 100 * IRB_MAX_DELAY) { + tb = IRB_TB_100US; + tb_us = 100; + } + + delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK; + + return ((IRB_WRITE_FIFO & ~IRB_MOD_ENABLE) | tb | delay); +} + +static void meson_irtx_send_buffer(struct meson_irtx *ir) +{ + unsigned int nr = 0; + unsigned int max_fifo_level = IRB_FIFO_LEN - MIRTX_FIFO_THD; + + while (ir->buf_head < ir->buf_len && nr < max_fifo_level) { + writel(ir->buf[ir->buf_head], ir->reg_base + IRB_ADDR2); + + ir->buf_head++; + nr++; + } +} + +static bool meson_irtx_check_buf(struct meson_irtx *ir, + unsigned int *buf, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) { + unsigned int max_tb_us; + /* + * Max space timebase is 100 us. + * Pulse timebase equals to carrier period. + */ + if (i % 2 == 0) + max_tb_us = USEC_PER_SEC / ir->carrier; + else + max_tb_us = 100; + + if (buf[i] >= max_tb_us * IRB_MAX_DELAY) + return false; + } + + return true; +} + +static void meson_irtx_fill_buf(struct meson_irtx *ir, u32 *dst_buf, + unsigned int *src_buf, unsigned int len) +{ + unsigned int i; + + for (i = 0; i < len; i++) { + if (i % 2 == 0) + dst_buf[i] = meson_irtx_prepare_pulse(ir, src_buf[i]); + else + dst_buf[i] = meson_irtx_prepare_space(ir, src_buf[i]); + } +} + +static irqreturn_t meson_irtx_irqhandler(int irq, void *data) +{ + unsigned long flags; + struct meson_irtx *ir = data; + + writel(readl(ir->reg_base + IRB_ADDR3) & ~IRB_FIFO_THD_PENDING, + ir->reg_base + IRB_ADDR3); + + if (completion_done(&ir->completion)) + return IRQ_HANDLED; + + spin_lock_irqsave(&ir->lock, flags); + if (ir->buf_head < ir->buf_len) + meson_irtx_send_buffer(ir); + else + complete(&ir->completion); + spin_unlock_irqrestore(&ir->lock, flags); + + return IRQ_HANDLED; +} + +static int meson_irtx_set_carrier(struct rc_dev *rc, u32 carrier) +{ + struct meson_irtx *ir = rc->priv; + + if (carrier == 0) + return -EINVAL; + + ir->carrier = carrier; + meson_irtx_set_mod(ir); + + return 0; +} + +static int meson_irtx_set_duty_cycle(struct rc_dev *rc, u32 duty_cycle) +{ + struct meson_irtx *ir = rc->priv; + + ir->duty_cycle = duty_cycle; + meson_irtx_set_mod(ir); + + return 0; +} + +static void meson_irtx_update_buf(struct meson_irtx *ir, u32 *buf, + unsigned int len, unsigned int head) +{ + ir->buf = buf; + ir->buf_len = len; + ir->buf_head = head; +} + +static int meson_irtx_transmit(struct rc_dev *rc, unsigned int *buf, + unsigned int len) +{ + unsigned long flags; + struct meson_irtx *ir = rc->priv; + u32 *tx_buf; + int ret = len; + + if (!meson_irtx_check_buf(ir, buf, len)) + return -EINVAL; + + tx_buf = kmalloc_array(len, sizeof(u32), GFP_KERNEL); + if (!tx_buf) + return -ENOMEM; + + meson_irtx_fill_buf(ir, tx_buf, buf, len); + dev_dbg(ir->dev, "TX buffer filled, length = %u\n", len); + + spin_lock_irqsave(&ir->lock, flags); + meson_irtx_update_buf(ir, tx_buf, len, 0); + reinit_completion(&ir->completion); + meson_irtx_send_buffer(ir); + spin_unlock_irqrestore(&ir->lock, flags); + + if (!wait_for_completion_timeout(&ir->completion, + usecs_to_jiffies(IR_MAX_DURATION))) + ret = -ETIMEDOUT; + + spin_lock_irqsave(&ir->lock, flags); + kfree(ir->buf); + meson_irtx_update_buf(ir, NULL, 0, 0); + spin_unlock_irqrestore(&ir->lock, flags); + + return ret; +} + +static int meson_irtx_mod_clock_probe(struct meson_irtx *ir, + unsigned int *clk_nr) +{ + struct device_node *np = ir->dev->of_node; + struct clk *clock; + + if (!np) + return -ENODEV; + + clock = devm_clk_get(ir->dev, "xtal"); + if (IS_ERR(clock) || clk_prepare_enable(clock)) + return -ENODEV; + + *clk_nr = IRB_MOD_XTAL3_CLK; + ir->clk_rate = clk_get_rate(clock) / 3; + + if (ir->clk_rate < IRB_MOD_1US_CLK_RATE) { + *clk_nr = IRB_MOD_1US_CLK; + ir->clk_rate = IRB_MOD_1US_CLK_RATE; + } + + dev_info(ir->dev, "F_clk = %luHz\n", ir->clk_rate); + + return 0; +} + +static int __init meson_irtx_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct meson_irtx *ir; + struct rc_dev *rc; + int irq; + unsigned int clk_nr; + int ret; + + ir = devm_kzalloc(dev, sizeof(*ir), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + ir->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(ir->reg_base)) + return PTR_ERR(ir->reg_base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "no irq resource found\n"); + return -ENODEV; + } + + ir->dev = dev; + ir->carrier = MIRTX_DEFAULT_CARRIER; + ir->duty_cycle = MIRTX_DEFAULT_DUTY_CYCLE; + init_completion(&ir->completion); + spin_lock_init(&ir->lock); + + ret = meson_irtx_mod_clock_probe(ir, &clk_nr); + if (ret) { + dev_err(dev, "modulator clock setup failed\n"); + return ret; + } + meson_irtx_setup(ir, clk_nr); + + ret = devm_request_irq(dev, irq, + meson_irtx_irqhandler, + IRQF_TRIGGER_RISING, + DRIVER_NAME, ir); + if (ret) { + dev_err(dev, "irq request failed\n"); + return ret; + } + + rc = rc_allocate_device(RC_DRIVER_IR_RAW_TX); + if (!rc) + return -ENOMEM; + + rc->driver_name = DRIVER_NAME; + rc->device_name = DEVICE_NAME; + rc->priv = ir; + + rc->tx_ir = meson_irtx_transmit; + rc->s_tx_carrier = meson_irtx_set_carrier; + rc->s_tx_duty_cycle = meson_irtx_set_duty_cycle; + + ret = rc_register_device(rc); + if (ret < 0) { + dev_err(dev, "rc_dev registration failed\n"); + rc_free_device(rc); + return ret; + } + + platform_set_drvdata(pdev, rc); + + return 0; +} + +static int meson_irtx_remove(struct platform_device *pdev) +{ + struct rc_dev *rc = platform_get_drvdata(pdev); + + rc_unregister_device(rc); + + return 0; +} + +static const struct of_device_id meson_irtx_dt_match[] = { + { + .compatible = "amlogic,meson-g12a-ir-tx", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, meson_irtx_dt_match); + +static struct platform_driver meson_irtx_pd = { + .remove = meson_irtx_remove, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = meson_irtx_dt_match, + }, +}; + +module_platform_driver_probe(meson_irtx_pd, meson_irtx_probe); + +MODULE_DESCRIPTION("Meson IR TX driver"); +MODULE_AUTHOR("Viktor Prutyanov "); +MODULE_LICENSE("GPL"); From 6fa54bc713c262e1cfbc5613377ef52280d7311f Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Wed, 7 Jul 2021 11:34:09 +0200 Subject: [PATCH 148/195] media: em28xx-input: fix refcount bug in em28xx_usb_disconnect If em28xx_ir_init fails, it would decrease the refcount of dev. However, in the em28xx_ir_fini, when ir is NULL, it goes to ref_put and decrease the refcount of dev. This will lead to a refcount bug. Fix this bug by removing the kref_put in the error handling code of em28xx_ir_init. refcount_t: underflow; use-after-free. WARNING: CPU: 0 PID: 7 at lib/refcount.c:28 refcount_warn_saturate+0x18e/0x1a0 lib/refcount.c:28 Modules linked in: CPU: 0 PID: 7 Comm: kworker/0:1 Not tainted 5.13.0 #3 Workqueue: usb_hub_wq hub_event RIP: 0010:refcount_warn_saturate+0x18e/0x1a0 lib/refcount.c:28 Call Trace: kref_put.constprop.0+0x60/0x85 include/linux/kref.h:69 em28xx_usb_disconnect.cold+0xd7/0xdc drivers/media/usb/em28xx/em28xx-cards.c:4150 usb_unbind_interface+0xbf/0x3a0 drivers/usb/core/driver.c:458 __device_release_driver drivers/base/dd.c:1201 [inline] device_release_driver_internal+0x22a/0x230 drivers/base/dd.c:1232 bus_remove_device+0x108/0x160 drivers/base/bus.c:529 device_del+0x1fe/0x510 drivers/base/core.c:3540 usb_disable_device+0xd1/0x1d0 drivers/usb/core/message.c:1419 usb_disconnect+0x109/0x330 drivers/usb/core/hub.c:2221 hub_port_connect drivers/usb/core/hub.c:5151 [inline] hub_port_connect_change drivers/usb/core/hub.c:5440 [inline] port_event drivers/usb/core/hub.c:5586 [inline] hub_event+0xf81/0x1d40 drivers/usb/core/hub.c:5668 process_one_work+0x2c9/0x610 kernel/workqueue.c:2276 process_scheduled_works kernel/workqueue.c:2338 [inline] worker_thread+0x333/0x5b0 kernel/workqueue.c:2424 kthread+0x188/0x1d0 kernel/kthread.c:319 ret_from_fork+0x1f/0x30 arch/x86/entry/entry_64.S:295 Reported-by: Dongliang Mu Fixes: ac5688637144 ("media: em28xx: Fix possible memory leak of em28xx struct") Signed-off-by: Dongliang Mu Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-input.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 59529cbf9cd0b..0b6d77c3bec86 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -842,7 +842,6 @@ static int em28xx_ir_init(struct em28xx *dev) kfree(ir); ref_put: em28xx_shutdown_buttons(dev); - kref_put(&dev->ref, em28xx_free_device); return err; } From c3609c45b7c207e176bbea3dfc2241c5cc2cf746 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 9 Jun 2021 13:54:56 +0200 Subject: [PATCH 149/195] media: v4l2-subdev: Fix documentation of the subdev_notifier member Fix the name of the function that registers the subdev_notifier member of the v4l2_subdev structure. [Sakari Ailus: Drop _sensor from the function name.] Signed-off-by: Paul Kocialkowski Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 95f8bfd632735..5364e3a6ac9bf 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -871,7 +871,7 @@ struct v4l2_subdev_platform_data { * @asd: Pointer to respective &struct v4l2_async_subdev. * @notifier: Pointer to the managing notifier. * @subdev_notifier: A sub-device notifier implicitly registered for the sub- - * device using v4l2_device_register_sensor_subdev(). + * device using v4l2_async_register_subdev_sensor(). * @pdata: common part of subdevice platform data * * Each instance of a subdev driver should create this struct, either From 932741d451a57819af4e316f9818ff363ac1f02a Mon Sep 17 00:00:00 2001 From: Martina Krasteva Date: Thu, 27 May 2021 16:21:40 +0200 Subject: [PATCH 150/195] media: dt-bindings: media: Add bindings for imx335 - Add dt-bindings documentation for Sony imx335 sensor driver - Add MAINTAINERS entry for Sony imx335 binding documentation Signed-off-by: Martina Krasteva Acked-by: Daniele Alessandrelli Acked-by: Paul J. Murphy Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/sony,imx335.yaml | 91 +++++++++++++++++++ MAINTAINERS | 8 ++ 2 files changed, 99 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml new file mode 100644 index 0000000000000..881f79532501f --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2021 Intel Corporation +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx335.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX335 Sensor + +maintainers: + - Paul J. Murphy + - Daniele Alessandrelli + +description: + IMX335 sensor is a Sony CMOS active pixel digital image sensor with an active + array size of 2592H x 1944V. It is programmable through I2C interface. The + I2C client address is fixed to 0x1a as per sensor data sheet. Image data is + sent through MIPI CSI-2. + +properties: + compatible: + const: sony,imx335 + reg: + description: I2C address + maxItems: 1 + + assigned-clocks: true + assigned-clock-parents: true + assigned-clock-rates: true + + clocks: + description: Clock frequency from 6 to 27 MHz, 37.125MHz, 74.25MHz + maxItems: 1 + + reset-gpios: + description: Reference to the GPIO connected to the XCLR pin, if any. + maxItems: 1 + + port: + additionalProperties: false + $ref: /schemas/graph.yaml#/properties/port + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: true + link-frequencies: true + + required: + - data-lanes + - link-frequencies + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@1a { + compatible = "sony,imx335"; + reg = <0x1a>; + clocks = <&imx335_clk>; + + assigned-clocks = <&imx335_clk>; + assigned-clock-parents = <&imx335_clk_parent>; + assigned-clock-rates = <24000000>; + + port { + imx335: endpoint { + remote-endpoint = <&cam>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <594000000>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index a61f4f3b78a91..33ead04951770 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17276,6 +17276,14 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx334.yaml F: drivers/media/i2c/imx334.c +SONY IMX335 SENSOR DRIVER +M: Paul J. Murphy +M: Daniele Alessandrelli +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml + SONY IMX355 SENSOR DRIVER M: Tianshu Qiu L: linux-media@vger.kernel.org From 45d19b5fb9aeab4d0c8aa20ad8f67205b3bea752 Mon Sep 17 00:00:00 2001 From: Martina Krasteva Date: Thu, 27 May 2021 16:21:41 +0200 Subject: [PATCH 151/195] media: i2c: Add imx335 camera sensor driver Add a v4l2 sub-device driver for the Sony imx335 image sensor. ThE camera sensor uses the i2c bus for control and the csi-2 bus for data. The following features are supported: - manual exposure and analog gain control support - vblank/hblank/pixel rate/link freq control support - supported resolution: - 2592x1940 @ 30fps - supported bayer order output: - SRGGB12 [Sakari Ailus: Rebase on commit c802a4174beeb25cb539c806c9d0d3c0f61dfa53.] Signed-off-by: Martina Krasteva Acked-by: Daniele Alessandrelli Acked-by: Paul J. Murphy Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + drivers/media/i2c/Kconfig | 14 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/imx335.c | 1129 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1145 insertions(+) create mode 100644 drivers/media/i2c/imx335.c diff --git a/MAINTAINERS b/MAINTAINERS index 33ead04951770..9c0e728771fca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17283,6 +17283,7 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx335.yaml +F: drivers/media/i2c/imx335.c SONY IMX355 SENSOR DRIVER M: Tianshu Qiu diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 588f8eb959844..8af7bd91ef241 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -842,6 +842,20 @@ config VIDEO_IMX334 To compile this driver as a module, choose M here: the module will be called imx334. +config VIDEO_IMX335 + tristate "Sony IMX335 sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_V4L2 + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Sony + IMX335 camera. + + To compile this driver as a module, choose M here: the + module will be called imx335. + config VIDEO_IMX355 tristate "Sony IMX355 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 1168fa6b84ed8..804d28fef3e45 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -124,6 +124,7 @@ obj-$(CONFIG_VIDEO_IMX274) += imx274.o obj-$(CONFIG_VIDEO_IMX290) += imx290.o obj-$(CONFIG_VIDEO_IMX319) += imx319.o obj-$(CONFIG_VIDEO_IMX334) += imx334.o +obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o obj-$(CONFIG_VIDEO_MAX9286) += max9286.o obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c new file mode 100644 index 0000000000000..410d6b86feb52 --- /dev/null +++ b/drivers/media/i2c/imx335.c @@ -0,0 +1,1129 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Sony imx335 Camera Sensor Driver + * + * Copyright (C) 2021 Intel Corporation + */ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Streaming Mode */ +#define IMX335_REG_MODE_SELECT 0x3000 +#define IMX335_MODE_STANDBY 0x01 +#define IMX335_MODE_STREAMING 0x00 + +/* Lines per frame */ +#define IMX335_REG_LPFR 0x3030 + +/* Chip ID */ +#define IMX335_REG_ID 0x3912 +#define IMX335_ID 0x00 + +/* Exposure control */ +#define IMX335_REG_SHUTTER 0x3058 +#define IMX335_EXPOSURE_MIN 1 +#define IMX335_EXPOSURE_OFFSET 9 +#define IMX335_EXPOSURE_STEP 1 +#define IMX335_EXPOSURE_DEFAULT 0x0648 + +/* Analog gain control */ +#define IMX335_REG_AGAIN 0x30e8 +#define IMX335_AGAIN_MIN 0 +#define IMX335_AGAIN_MAX 240 +#define IMX335_AGAIN_STEP 1 +#define IMX335_AGAIN_DEFAULT 0 + +/* Group hold register */ +#define IMX335_REG_HOLD 0x3001 + +/* Input clock rate */ +#define IMX335_INCLK_RATE 24000000 + +/* CSI2 HW configuration */ +#define IMX335_LINK_FREQ 594000000 +#define IMX335_NUM_DATA_LANES 4 + +#define IMX335_REG_MIN 0x00 +#define IMX335_REG_MAX 0xfffff + +/** + * struct imx335_reg - imx335 sensor register + * @address: Register address + * @val: Register value + */ +struct imx335_reg { + u16 address; + u8 val; +}; + +/** + * struct imx335_reg_list - imx335 sensor register list + * @num_of_regs: Number of registers in the list + * @regs: Pointer to register list + */ +struct imx335_reg_list { + u32 num_of_regs; + const struct imx335_reg *regs; +}; + +/** + * struct imx335_mode - imx335 sensor mode structure + * @width: Frame width + * @height: Frame height + * @code: Format code + * @hblank: Horizontal blanking in lines + * @vblank: Vertical blanking in lines + * @vblank_min: Minimum vertical blanking in lines + * @vblank_max: Maximum vertical blanking in lines + * @pclk: Sensor pixel clock + * @link_freq_idx: Link frequency index + * @reg_list: Register list for sensor mode + */ +struct imx335_mode { + u32 width; + u32 height; + u32 code; + u32 hblank; + u32 vblank; + u32 vblank_min; + u32 vblank_max; + u64 pclk; + u32 link_freq_idx; + struct imx335_reg_list reg_list; +}; + +/** + * struct imx335 - imx335 sensor device structure + * @dev: Pointer to generic device + * @client: Pointer to i2c client + * @sd: V4L2 sub-device + * @pad: Media pad. Only one pad supported + * @reset_gpio: Sensor reset gpio + * @inclk: Sensor input clock + * @ctrl_handler: V4L2 control handler + * @link_freq_ctrl: Pointer to link frequency control + * @pclk_ctrl: Pointer to pixel clock control + * @hblank_ctrl: Pointer to horizontal blanking control + * @vblank_ctrl: Pointer to vertical blanking control + * @exp_ctrl: Pointer to exposure control + * @again_ctrl: Pointer to analog gain control + * @vblank: Vertical blanking in lines + * @cur_mode: Pointer to current selected sensor mode + * @mutex: Mutex for serializing sensor controls + * @streaming: Flag indicating streaming state + */ +struct imx335 { + struct device *dev; + struct i2c_client *client; + struct v4l2_subdev sd; + struct media_pad pad; + struct gpio_desc *reset_gpio; + struct clk *inclk; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *link_freq_ctrl; + struct v4l2_ctrl *pclk_ctrl; + struct v4l2_ctrl *hblank_ctrl; + struct v4l2_ctrl *vblank_ctrl; + struct { + struct v4l2_ctrl *exp_ctrl; + struct v4l2_ctrl *again_ctrl; + }; + u32 vblank; + const struct imx335_mode *cur_mode; + struct mutex mutex; + bool streaming; +}; + +static const s64 link_freq[] = { + IMX335_LINK_FREQ, +}; + +/* Sensor mode registers */ +static const struct imx335_reg mode_2592x1940_regs[] = { + {0x3000, 0x01}, + {0x3002, 0x00}, + {0x300c, 0x3b}, + {0x300d, 0x2a}, + {0x3018, 0x04}, + {0x302c, 0x3c}, + {0x302e, 0x20}, + {0x3056, 0x94}, + {0x3074, 0xc8}, + {0x3076, 0x28}, + {0x304c, 0x00}, + {0x314c, 0xc6}, + {0x315a, 0x02}, + {0x3168, 0xa0}, + {0x316a, 0x7e}, + {0x31a1, 0x00}, + {0x3288, 0x21}, + {0x328a, 0x02}, + {0x3414, 0x05}, + {0x3416, 0x18}, + {0x3648, 0x01}, + {0x364a, 0x04}, + {0x364c, 0x04}, + {0x3678, 0x01}, + {0x367c, 0x31}, + {0x367e, 0x31}, + {0x3706, 0x10}, + {0x3708, 0x03}, + {0x3714, 0x02}, + {0x3715, 0x02}, + {0x3716, 0x01}, + {0x3717, 0x03}, + {0x371c, 0x3d}, + {0x371d, 0x3f}, + {0x372c, 0x00}, + {0x372d, 0x00}, + {0x372e, 0x46}, + {0x372f, 0x00}, + {0x3730, 0x89}, + {0x3731, 0x00}, + {0x3732, 0x08}, + {0x3733, 0x01}, + {0x3734, 0xfe}, + {0x3735, 0x05}, + {0x3740, 0x02}, + {0x375d, 0x00}, + {0x375e, 0x00}, + {0x375f, 0x11}, + {0x3760, 0x01}, + {0x3768, 0x1b}, + {0x3769, 0x1b}, + {0x376a, 0x1b}, + {0x376b, 0x1b}, + {0x376c, 0x1a}, + {0x376d, 0x17}, + {0x376e, 0x0f}, + {0x3776, 0x00}, + {0x3777, 0x00}, + {0x3778, 0x46}, + {0x3779, 0x00}, + {0x377a, 0x89}, + {0x377b, 0x00}, + {0x377c, 0x08}, + {0x377d, 0x01}, + {0x377e, 0x23}, + {0x377f, 0x02}, + {0x3780, 0xd9}, + {0x3781, 0x03}, + {0x3782, 0xf5}, + {0x3783, 0x06}, + {0x3784, 0xa5}, + {0x3788, 0x0f}, + {0x378a, 0xd9}, + {0x378b, 0x03}, + {0x378c, 0xeb}, + {0x378d, 0x05}, + {0x378e, 0x87}, + {0x378f, 0x06}, + {0x3790, 0xf5}, + {0x3792, 0x43}, + {0x3794, 0x7a}, + {0x3796, 0xa1}, + {0x37b0, 0x36}, + {0x3a00, 0x01}, +}; + +/* Supported sensor mode configurations */ +static const struct imx335_mode supported_mode = { + .width = 2592, + .height = 1940, + .hblank = 342, + .vblank = 2560, + .vblank_min = 2560, + .vblank_max = 133060, + .pclk = 396000000, + .link_freq_idx = 0, + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_2592x1940_regs), + .regs = mode_2592x1940_regs, + }, +}; + +/** + * to_imx335() - imx335 V4L2 sub-device to imx335 device. + * @subdev: pointer to imx335 V4L2 sub-device + * + * Return: pointer to imx335 device + */ +static inline struct imx335 *to_imx335(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct imx335, sd); +} + +/** + * imx335_read_reg() - Read registers. + * @imx335: pointer to imx335 device + * @reg: register address + * @len: length of bytes to read. Max supported bytes is 4 + * @val: pointer to register value to be filled. + * + * Big endian register addresses with little endian values. + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_read_reg(struct imx335 *imx335, u16 reg, u32 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx335->sd); + struct i2c_msg msgs[2] = {0}; + u8 addr_buf[2] = {0}; + u8 data_buf[4] = {0}; + int ret; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = data_buf; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_le32(data_buf); + + return 0; +} + +/** + * imx335_write_reg() - Write register + * @imx335: pointer to imx335 device + * @reg: register address + * @len: length of bytes. Max supported bytes is 4 + * @val: register value + * + * Big endian register addresses with little endian values. + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_write_reg(struct imx335 *imx335, u16 reg, u32 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx335->sd); + u8 buf[6] = {0}; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_le32(val, buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/** + * imx335_write_regs() - Write a list of registers + * @imx335: pointer to imx335 device + * @regs: list of registers to be written + * @len: length of registers array + * + * Return: 0 if successful. error code otherwise. + */ +static int imx335_write_regs(struct imx335 *imx335, + const struct imx335_reg *regs, u32 len) +{ + unsigned int i; + int ret; + + for (i = 0; i < len; i++) { + ret = imx335_write_reg(imx335, regs[i].address, 1, regs[i].val); + if (ret) + return ret; + } + + return 0; +} + +/** + * imx335_update_controls() - Update control ranges based on streaming mode + * @imx335: pointer to imx335 device + * @mode: pointer to imx335_mode sensor mode + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_update_controls(struct imx335 *imx335, + const struct imx335_mode *mode) +{ + int ret; + + ret = __v4l2_ctrl_s_ctrl(imx335->link_freq_ctrl, mode->link_freq_idx); + if (ret) + return ret; + + ret = __v4l2_ctrl_s_ctrl(imx335->hblank_ctrl, mode->hblank); + if (ret) + return ret; + + return __v4l2_ctrl_modify_range(imx335->vblank_ctrl, mode->vblank_min, + mode->vblank_max, 1, mode->vblank); +} + +/** + * imx335_update_exp_gain() - Set updated exposure and gain + * @imx335: pointer to imx335 device + * @exposure: updated exposure value + * @gain: updated analog gain value + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_update_exp_gain(struct imx335 *imx335, u32 exposure, u32 gain) +{ + u32 lpfr, shutter; + int ret; + + lpfr = imx335->vblank + imx335->cur_mode->height; + shutter = lpfr - exposure; + + dev_dbg(imx335->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u", + exposure, gain, shutter, lpfr); + + ret = imx335_write_reg(imx335, IMX335_REG_HOLD, 1, 1); + if (ret) + return ret; + + ret = imx335_write_reg(imx335, IMX335_REG_LPFR, 3, lpfr); + if (ret) + goto error_release_group_hold; + + ret = imx335_write_reg(imx335, IMX335_REG_SHUTTER, 3, shutter); + if (ret) + goto error_release_group_hold; + + ret = imx335_write_reg(imx335, IMX335_REG_AGAIN, 2, gain); + +error_release_group_hold: + imx335_write_reg(imx335, IMX335_REG_HOLD, 1, 0); + + return ret; +} + +/** + * imx335_set_ctrl() - Set subdevice control + * @ctrl: pointer to v4l2_ctrl structure + * + * Supported controls: + * - V4L2_CID_VBLANK + * - cluster controls: + * - V4L2_CID_ANALOGUE_GAIN + * - V4L2_CID_EXPOSURE + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx335 *imx335 = + container_of(ctrl->handler, struct imx335, ctrl_handler); + u32 analog_gain; + u32 exposure; + int ret; + + switch (ctrl->id) { + case V4L2_CID_VBLANK: + imx335->vblank = imx335->vblank_ctrl->val; + + dev_dbg(imx335->dev, "Received vblank %u, new lpfr %u", + imx335->vblank, + imx335->vblank + imx335->cur_mode->height); + + ret = __v4l2_ctrl_modify_range(imx335->exp_ctrl, + IMX335_EXPOSURE_MIN, + imx335->vblank + + imx335->cur_mode->height - + IMX335_EXPOSURE_OFFSET, + 1, IMX335_EXPOSURE_DEFAULT); + break; + case V4L2_CID_EXPOSURE: + /* Set controls only if sensor is in power on state */ + if (!pm_runtime_get_if_in_use(imx335->dev)) + return 0; + + exposure = ctrl->val; + analog_gain = imx335->again_ctrl->val; + + dev_dbg(imx335->dev, "Received exp %u, analog gain %u", + exposure, analog_gain); + + ret = imx335_update_exp_gain(imx335, exposure, analog_gain); + + pm_runtime_put(imx335->dev); + + break; + default: + dev_err(imx335->dev, "Invalid control %d", ctrl->id); + ret = -EINVAL; + } + + return ret; +} + +/* V4l2 subdevice control ops*/ +static const struct v4l2_ctrl_ops imx335_ctrl_ops = { + .s_ctrl = imx335_set_ctrl, +}; + +/** + * imx335_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @code: V4L2 sub-device code enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = supported_mode.code; + + return 0; +} + +/** + * imx335_enum_frame_size() - Enumerate V4L2 sub-device frame sizes + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fsize: V4L2 sub-device size enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fsize) +{ + if (fsize->index > 0) + return -EINVAL; + + if (fsize->code != supported_mode.code) + return -EINVAL; + + fsize->min_width = supported_mode.width; + fsize->max_width = fsize->min_width; + fsize->min_height = supported_mode.height; + fsize->max_height = fsize->min_height; + + return 0; +} + +/** + * imx335_fill_pad_format() - Fill subdevice pad format + * from selected sensor mode + * @imx335: pointer to imx335 device + * @mode: pointer to imx335_mode sensor mode + * @fmt: V4L2 sub-device format need to be filled + */ +static void imx335_fill_pad_format(struct imx335 *imx335, + const struct imx335_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = mode->code; + fmt->format.field = V4L2_FIELD_NONE; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->format.quantization = V4L2_QUANTIZATION_DEFAULT; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; +} + +/** + * imx335_get_pad_format() - Get subdevice pad format + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx335 *imx335 = to_imx335(sd); + + mutex_lock(&imx335->mutex); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + fmt->format = *framefmt; + } else { + imx335_fill_pad_format(imx335, imx335->cur_mode, fmt); + } + + mutex_unlock(&imx335->mutex); + + return 0; +} + +/** + * imx335_set_pad_format() - Set subdevice pad format + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx335 *imx335 = to_imx335(sd); + const struct imx335_mode *mode; + int ret = 0; + + mutex_lock(&imx335->mutex); + + mode = &supported_mode; + imx335_fill_pad_format(imx335, mode, fmt); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + *framefmt = fmt->format; + } else { + ret = imx335_update_controls(imx335, mode); + if (!ret) + imx335->cur_mode = mode; + } + + mutex_unlock(&imx335->mutex); + + return ret; +} + +/** + * imx335_init_pad_cfg() - Initialize sub-device pad configuration + * @sd: pointer to imx335 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_init_pad_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct imx335 *imx335 = to_imx335(sd); + struct v4l2_subdev_format fmt = { 0 }; + + fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + imx335_fill_pad_format(imx335, &supported_mode, &fmt); + + return imx335_set_pad_format(sd, sd_state, &fmt); +} + +/** + * imx335_start_streaming() - Start sensor stream + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_start_streaming(struct imx335 *imx335) +{ + const struct imx335_reg_list *reg_list; + int ret; + + /* Write sensor mode registers */ + reg_list = &imx335->cur_mode->reg_list; + ret = imx335_write_regs(imx335, reg_list->regs, + reg_list->num_of_regs); + if (ret) { + dev_err(imx335->dev, "fail to write initial registers"); + return ret; + } + + /* Setup handler will write actual exposure and gain */ + ret = __v4l2_ctrl_handler_setup(imx335->sd.ctrl_handler); + if (ret) { + dev_err(imx335->dev, "fail to setup handler"); + return ret; + } + + /* Start streaming */ + ret = imx335_write_reg(imx335, IMX335_REG_MODE_SELECT, + 1, IMX335_MODE_STREAMING); + if (ret) { + dev_err(imx335->dev, "fail to start streaming"); + return ret; + } + + /* Initial regulator stabilization period */ + usleep_range(18000, 20000); + + return 0; +} + +/** + * imx335_stop_streaming() - Stop sensor stream + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_stop_streaming(struct imx335 *imx335) +{ + return imx335_write_reg(imx335, IMX335_REG_MODE_SELECT, + 1, IMX335_MODE_STANDBY); +} + +/** + * imx335_set_stream() - Enable sensor streaming + * @sd: pointer to imx335 subdevice + * @enable: set to enable sensor streaming + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx335 *imx335 = to_imx335(sd); + int ret; + + mutex_lock(&imx335->mutex); + + if (imx335->streaming == enable) { + mutex_unlock(&imx335->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(imx335->dev); + if (ret) + goto error_unlock; + + ret = imx335_start_streaming(imx335); + if (ret) + goto error_power_off; + } else { + imx335_stop_streaming(imx335); + pm_runtime_put(imx335->dev); + } + + imx335->streaming = enable; + + mutex_unlock(&imx335->mutex); + + return 0; + +error_power_off: + pm_runtime_put(imx335->dev); +error_unlock: + mutex_unlock(&imx335->mutex); + + return ret; +} + +/** + * imx335_detect() - Detect imx335 sensor + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, -EIO if sensor id does not match + */ +static int imx335_detect(struct imx335 *imx335) +{ + int ret; + u32 val; + + ret = imx335_read_reg(imx335, IMX335_REG_ID, 2, &val); + if (ret) + return ret; + + if (val != IMX335_ID) { + dev_err(imx335->dev, "chip id mismatch: %x!=%x", + IMX335_ID, val); + return -ENXIO; + } + + return 0; +} + +/** + * imx335_parse_hw_config() - Parse HW configuration and check if supported + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_parse_hw_config(struct imx335 *imx335) +{ + struct fwnode_handle *fwnode = dev_fwnode(imx335->dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *ep; + unsigned long rate; + unsigned int i; + int ret; + + if (!fwnode) + return -ENXIO; + + /* Request optional reset pin */ + imx335->reset_gpio = devm_gpiod_get_optional(imx335->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(imx335->reset_gpio)) { + dev_err(imx335->dev, "failed to get reset gpio %ld", + PTR_ERR(imx335->reset_gpio)); + return PTR_ERR(imx335->reset_gpio); + } + + /* Get sensor input clock */ + imx335->inclk = devm_clk_get(imx335->dev, NULL); + if (IS_ERR(imx335->inclk)) { + dev_err(imx335->dev, "could not get inclk"); + return PTR_ERR(imx335->inclk); + } + + rate = clk_get_rate(imx335->inclk); + if (rate != IMX335_INCLK_RATE) { + dev_err(imx335->dev, "inclk frequency mismatch"); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX335_NUM_DATA_LANES) { + dev_err(imx335->dev, + "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto done_endpoint_free; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(imx335->dev, "no link frequencies defined"); + ret = -EINVAL; + goto done_endpoint_free; + } + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) + if (bus_cfg.link_frequencies[i] == IMX335_LINK_FREQ) + goto done_endpoint_free; + + ret = -EINVAL; + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +/* V4l2 subdevice ops */ +static const struct v4l2_subdev_video_ops imx335_video_ops = { + .s_stream = imx335_set_stream, +}; + +static const struct v4l2_subdev_pad_ops imx335_pad_ops = { + .init_cfg = imx335_init_pad_cfg, + .enum_mbus_code = imx335_enum_mbus_code, + .enum_frame_size = imx335_enum_frame_size, + .get_fmt = imx335_get_pad_format, + .set_fmt = imx335_set_pad_format, +}; + +static const struct v4l2_subdev_ops imx335_subdev_ops = { + .video = &imx335_video_ops, + .pad = &imx335_pad_ops, +}; + +/** + * imx335_power_on() - Sensor power on sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx335 *imx335 = to_imx335(sd); + int ret; + + gpiod_set_value_cansleep(imx335->reset_gpio, 1); + + ret = clk_prepare_enable(imx335->inclk); + if (ret) { + dev_err(imx335->dev, "fail to enable inclk"); + goto error_reset; + } + + usleep_range(20, 22); + + return 0; + +error_reset: + gpiod_set_value_cansleep(imx335->reset_gpio, 0); + + return ret; +} + +/** + * imx335_power_off() - Sensor power off sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx335 *imx335 = to_imx335(sd); + + gpiod_set_value_cansleep(imx335->reset_gpio, 0); + + clk_disable_unprepare(imx335->inclk); + + return 0; +} + +/** + * imx335_init_controls() - Initialize sensor subdevice controls + * @imx335: pointer to imx335 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_init_controls(struct imx335 *imx335) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &imx335->ctrl_handler; + const struct imx335_mode *mode = imx335->cur_mode; + u32 lpfr; + int ret; + + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); + if (ret) + return ret; + + /* Serialize controls with sensor device */ + ctrl_hdlr->lock = &imx335->mutex; + + /* Initialize exposure and gain */ + lpfr = mode->vblank + mode->height; + imx335->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX335_EXPOSURE_MIN, + lpfr - IMX335_EXPOSURE_OFFSET, + IMX335_EXPOSURE_STEP, + IMX335_EXPOSURE_DEFAULT); + + imx335->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, + IMX335_AGAIN_MIN, + IMX335_AGAIN_MAX, + IMX335_AGAIN_STEP, + IMX335_AGAIN_DEFAULT); + + v4l2_ctrl_cluster(2, &imx335->exp_ctrl); + + imx335->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_VBLANK, + mode->vblank_min, + mode->vblank_max, + 1, mode->vblank); + + /* Read only controls */ + imx335->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_PIXEL_RATE, + mode->pclk, mode->pclk, + 1, mode->pclk); + + imx335->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq) - + 1, + mode->link_freq_idx, + link_freq); + if (imx335->link_freq_ctrl) + imx335->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + imx335->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx335_ctrl_ops, + V4L2_CID_HBLANK, + IMX335_REG_MIN, + IMX335_REG_MAX, + 1, mode->hblank); + if (imx335->hblank_ctrl) + imx335->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + if (ctrl_hdlr->error) { + dev_err(imx335->dev, "control init failed: %d", + ctrl_hdlr->error); + v4l2_ctrl_handler_free(ctrl_hdlr); + return ctrl_hdlr->error; + } + + imx335->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +/** + * imx335_probe() - I2C client device binding + * @client: pointer to i2c client device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_probe(struct i2c_client *client) +{ + struct imx335 *imx335; + int ret; + + imx335 = devm_kzalloc(&client->dev, sizeof(*imx335), GFP_KERNEL); + if (!imx335) + return -ENOMEM; + + imx335->dev = &client->dev; + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&imx335->sd, client, &imx335_subdev_ops); + + ret = imx335_parse_hw_config(imx335); + if (ret) { + dev_err(imx335->dev, "HW configuration is not supported"); + return ret; + } + + mutex_init(&imx335->mutex); + + ret = imx335_power_on(imx335->dev); + if (ret) { + dev_err(imx335->dev, "failed to power-on the sensor"); + goto error_mutex_destroy; + } + + /* Check module identity */ + ret = imx335_detect(imx335); + if (ret) { + dev_err(imx335->dev, "failed to find sensor: %d", ret); + goto error_power_off; + } + + /* Set default mode to max resolution */ + imx335->cur_mode = &supported_mode; + imx335->vblank = imx335->cur_mode->vblank; + + ret = imx335_init_controls(imx335); + if (ret) { + dev_err(imx335->dev, "failed to init controls: %d", ret); + goto error_power_off; + } + + /* Initialize subdev */ + imx335->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx335->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + imx335->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx335->sd.entity, 1, &imx335->pad); + if (ret) { + dev_err(imx335->dev, "failed to init entity pads: %d", ret); + goto error_handler_free; + } + + ret = v4l2_async_register_subdev_sensor(&imx335->sd); + if (ret < 0) { + dev_err(imx335->dev, + "failed to register async subdev: %d", ret); + goto error_media_entity; + } + + pm_runtime_set_active(imx335->dev); + pm_runtime_enable(imx335->dev); + pm_runtime_idle(imx335->dev); + + return 0; + +error_media_entity: + media_entity_cleanup(&imx335->sd.entity); +error_handler_free: + v4l2_ctrl_handler_free(imx335->sd.ctrl_handler); +error_power_off: + imx335_power_off(imx335->dev); +error_mutex_destroy: + mutex_destroy(&imx335->mutex); + + return ret; +} + +/** + * imx335_remove() - I2C client device unbinding + * @client: pointer to I2C client device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx335_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx335 *imx335 = to_imx335(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + imx335_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + + mutex_destroy(&imx335->mutex); + + return 0; +} + +static const struct dev_pm_ops imx335_pm_ops = { + SET_RUNTIME_PM_OPS(imx335_power_off, imx335_power_on, NULL) +}; + +static const struct of_device_id imx335_of_match[] = { + { .compatible = "sony,imx335" }, + { } +}; + +MODULE_DEVICE_TABLE(of, imx335_of_match); + +static struct i2c_driver imx335_driver = { + .probe_new = imx335_probe, + .remove = imx335_remove, + .driver = { + .name = "imx335", + .pm = &imx335_pm_ops, + .of_match_table = imx335_of_match, + }, +}; + +module_i2c_driver(imx335_driver); + +MODULE_DESCRIPTION("Sony imx335 sensor driver"); +MODULE_LICENSE("GPL"); From 333b3125d1300e9a06e537295b9eb6042d131492 Mon Sep 17 00:00:00 2001 From: Martina Krasteva Date: Thu, 27 May 2021 16:21:42 +0200 Subject: [PATCH 152/195] media: dt-bindings: media: Add bindings for imx412 - Add dt-bindings documentation for Sony imx412 sensor driver - Add MAINTAINERS entry for Sony imx412 binding documentation Signed-off-by: Martina Krasteva Acked-by: Daniele Alessandrelli Acked-by: Paul J. Murphy Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/sony,imx412.yaml | 91 +++++++++++++++++++ MAINTAINERS | 8 ++ 2 files changed, 99 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml new file mode 100644 index 0000000000000..1edeabf39e6a7 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2021 Intel Corporation +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/sony,imx412.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Sony IMX412 Sensor + +maintainers: + - Paul J. Murphy + - Daniele Alessandrelli + +description: + IMX412 sensor is a Sony CMOS active pixel digital image sensor with an active + array size of 4072H x 3176V. It is programmable through I2C interface. The + I2C client address is fixed to 0x1a as per sensor data sheet. Image data is + sent through MIPI CSI-2. + +properties: + compatible: + const: sony,imx412 + reg: + description: I2C address + maxItems: 1 + + assigned-clocks: true + assigned-clock-parents: true + assigned-clock-rates: true + + clocks: + description: Clock frequency 6MHz, 12MHz, 18MHz, 24MHz or 27MHz + maxItems: 1 + + reset-gpios: + description: Reference to the GPIO connected to the XCLR pin, if any. + maxItems: 1 + + port: + additionalProperties: false + $ref: /schemas/graph.yaml#/properties/port + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: true + link-frequencies: true + + required: + - data-lanes + - link-frequencies + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@1a { + compatible = "sony,imx412"; + reg = <0x1a>; + clocks = <&imx412_clk>; + + assigned-clocks = <&imx412_clk>; + assigned-clock-parents = <&imx412_clk_parent>; + assigned-clock-rates = <24000000>; + + port { + imx412: endpoint { + remote-endpoint = <&cam>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <600000000>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 9c0e728771fca..358ef920fea84 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17292,6 +17292,14 @@ S: Maintained T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/imx355.c +SONY IMX412 SENSOR DRIVER +M: Paul J. Murphy +M: Daniele Alessandrelli +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml + SONY MEMORYSTICK SUBSYSTEM M: Maxim Levitsky M: Alex Dubov From 9214e86c0cc1ea6c811f14c293fed9ce1baefbae Mon Sep 17 00:00:00 2001 From: Martina Krasteva Date: Thu, 27 May 2021 16:21:43 +0200 Subject: [PATCH 153/195] media: i2c: Add imx412 camera sensor driver Add a v4l2 sub-device driver for the Sony imx412 image sensor. This is a camera sensor using the i2c bus for control and the csi-2 bus for data. The following features are supported: - manual exposure and analog gain control support - vblank/hblank/pixel rate/link freq control support - supported resolution: - 4056x3040 @ 30fps - supported bayer order output: - SRGGB10 [Sakari Ailus: Rebase on commit c802a4174beeb25cb539c806c9d0d3c0f61dfa53.] Signed-off-by: Martina Krasteva Acked-by: Daniele Alessandrelli Acked-by: Paul J. Murphy Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + drivers/media/i2c/Kconfig | 14 + drivers/media/i2c/Makefile | 2 +- drivers/media/i2c/imx412.c | 1272 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1288 insertions(+), 1 deletion(-) create mode 100644 drivers/media/i2c/imx412.c diff --git a/MAINTAINERS b/MAINTAINERS index 358ef920fea84..955d74fe8b9e4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17299,6 +17299,7 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/sony,imx412.yaml +F: drivers/media/i2c/imx412.c SONY MEMORYSTICK SUBSYSTEM M: Maxim Levitsky diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 8af7bd91ef241..bdae664beb871 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -868,6 +868,20 @@ config VIDEO_IMX355 To compile this driver as a module, choose M here: the module will be called imx355. +config VIDEO_IMX412 + tristate "Sony IMX412 sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_V4L2 + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Sony + IMX412 camera. + + To compile this driver as a module, choose M here: the + module will be called imx412. + config VIDEO_OV02A10 tristate "OmniVision OV02A10 sensor support" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 804d28fef3e45..303995beb6731 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -126,10 +126,10 @@ obj-$(CONFIG_VIDEO_IMX319) += imx319.o obj-$(CONFIG_VIDEO_IMX334) += imx334.o obj-$(CONFIG_VIDEO_IMX335) += imx335.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o +obj-$(CONFIG_VIDEO_IMX412) += imx412.o obj-$(CONFIG_VIDEO_MAX9286) += max9286.o obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o - obj-$(CONFIG_SDR_MAX2175) += max2175.o diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c new file mode 100644 index 0000000000000..be3f6ea555597 --- /dev/null +++ b/drivers/media/i2c/imx412.c @@ -0,0 +1,1272 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Sony imx412 Camera Sensor Driver + * + * Copyright (C) 2021 Intel Corporation + */ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Streaming Mode */ +#define IMX412_REG_MODE_SELECT 0x0100 +#define IMX412_MODE_STANDBY 0x00 +#define IMX412_MODE_STREAMING 0x01 + +/* Lines per frame */ +#define IMX412_REG_LPFR 0x0340 + +/* Chip ID */ +#define IMX412_REG_ID 0x0016 +#define IMX412_ID 0x577 + +/* Exposure control */ +#define IMX412_REG_EXPOSURE_CIT 0x0202 +#define IMX412_EXPOSURE_MIN 8 +#define IMX412_EXPOSURE_OFFSET 22 +#define IMX412_EXPOSURE_STEP 1 +#define IMX412_EXPOSURE_DEFAULT 0x0648 + +/* Analog gain control */ +#define IMX412_REG_AGAIN 0x0204 +#define IMX412_AGAIN_MIN 0 +#define IMX412_AGAIN_MAX 978 +#define IMX412_AGAIN_STEP 1 +#define IMX412_AGAIN_DEFAULT 0 + +/* Group hold register */ +#define IMX412_REG_HOLD 0x0104 + +/* Input clock rate */ +#define IMX412_INCLK_RATE 24000000 + +/* CSI2 HW configuration */ +#define IMX412_LINK_FREQ 600000000 +#define IMX412_NUM_DATA_LANES 4 + +#define IMX412_REG_MIN 0x00 +#define IMX412_REG_MAX 0xffff + +/** + * struct imx412_reg - imx412 sensor register + * @address: Register address + * @val: Register value + */ +struct imx412_reg { + u16 address; + u8 val; +}; + +/** + * struct imx412_reg_list - imx412 sensor register list + * @num_of_regs: Number of registers in the list + * @regs: Pointer to register list + */ +struct imx412_reg_list { + u32 num_of_regs; + const struct imx412_reg *regs; +}; + +/** + * struct imx412_mode - imx412 sensor mode structure + * @width: Frame width + * @height: Frame height + * @code: Format code + * @hblank: Horizontal blanking in lines + * @vblank: Vertical blanking in lines + * @vblank_min: Minimum vertical blanking in lines + * @vblank_max: Maximum vertical blanking in lines + * @pclk: Sensor pixel clock + * @link_freq_idx: Link frequency index + * @reg_list: Register list for sensor mode + */ +struct imx412_mode { + u32 width; + u32 height; + u32 code; + u32 hblank; + u32 vblank; + u32 vblank_min; + u32 vblank_max; + u64 pclk; + u32 link_freq_idx; + struct imx412_reg_list reg_list; +}; + +/** + * struct imx412 - imx412 sensor device structure + * @dev: Pointer to generic device + * @client: Pointer to i2c client + * @sd: V4L2 sub-device + * @pad: Media pad. Only one pad supported + * @reset_gpio: Sensor reset gpio + * @inclk: Sensor input clock + * @ctrl_handler: V4L2 control handler + * @link_freq_ctrl: Pointer to link frequency control + * @pclk_ctrl: Pointer to pixel clock control + * @hblank_ctrl: Pointer to horizontal blanking control + * @vblank_ctrl: Pointer to vertical blanking control + * @exp_ctrl: Pointer to exposure control + * @again_ctrl: Pointer to analog gain control + * @vblank: Vertical blanking in lines + * @cur_mode: Pointer to current selected sensor mode + * @mutex: Mutex for serializing sensor controls + * @streaming: Flag indicating streaming state + */ +struct imx412 { + struct device *dev; + struct i2c_client *client; + struct v4l2_subdev sd; + struct media_pad pad; + struct gpio_desc *reset_gpio; + struct clk *inclk; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *link_freq_ctrl; + struct v4l2_ctrl *pclk_ctrl; + struct v4l2_ctrl *hblank_ctrl; + struct v4l2_ctrl *vblank_ctrl; + struct { + struct v4l2_ctrl *exp_ctrl; + struct v4l2_ctrl *again_ctrl; + }; + u32 vblank; + const struct imx412_mode *cur_mode; + struct mutex mutex; + bool streaming; +}; + +static const s64 link_freq[] = { + IMX412_LINK_FREQ, +}; + +/* Sensor mode registers */ +static const struct imx412_reg mode_4056x3040_regs[] = { + {0x0136, 0x18}, + {0x0137, 0x00}, + {0x3c7e, 0x08}, + {0x3c7f, 0x02}, + {0x38a8, 0x1f}, + {0x38a9, 0xff}, + {0x38aa, 0x1f}, + {0x38ab, 0xff}, + {0x55d4, 0x00}, + {0x55d5, 0x00}, + {0x55d6, 0x07}, + {0x55d7, 0xff}, + {0x55e8, 0x07}, + {0x55e9, 0xff}, + {0x55ea, 0x00}, + {0x55eb, 0x00}, + {0x575c, 0x07}, + {0x575d, 0xff}, + {0x575e, 0x00}, + {0x575f, 0x00}, + {0x5764, 0x00}, + {0x5765, 0x00}, + {0x5766, 0x07}, + {0x5767, 0xff}, + {0x5974, 0x04}, + {0x5975, 0x01}, + {0x5f10, 0x09}, + {0x5f11, 0x92}, + {0x5f12, 0x32}, + {0x5f13, 0x72}, + {0x5f14, 0x16}, + {0x5f15, 0xba}, + {0x5f17, 0x13}, + {0x5f18, 0x24}, + {0x5f19, 0x60}, + {0x5f1a, 0xe3}, + {0x5f1b, 0xad}, + {0x5f1c, 0x74}, + {0x5f2d, 0x25}, + {0x5f5c, 0xd0}, + {0x6a22, 0x00}, + {0x6a23, 0x1d}, + {0x7ba8, 0x00}, + {0x7ba9, 0x00}, + {0x886b, 0x00}, + {0x9002, 0x0a}, + {0x9004, 0x1a}, + {0x9214, 0x93}, + {0x9215, 0x69}, + {0x9216, 0x93}, + {0x9217, 0x6b}, + {0x9218, 0x93}, + {0x9219, 0x6d}, + {0x921a, 0x57}, + {0x921b, 0x58}, + {0x921c, 0x57}, + {0x921d, 0x59}, + {0x921e, 0x57}, + {0x921f, 0x5a}, + {0x9220, 0x57}, + {0x9221, 0x5b}, + {0x9222, 0x93}, + {0x9223, 0x02}, + {0x9224, 0x93}, + {0x9225, 0x03}, + {0x9226, 0x93}, + {0x9227, 0x04}, + {0x9228, 0x93}, + {0x9229, 0x05}, + {0x922a, 0x98}, + {0x922b, 0x21}, + {0x922c, 0xb2}, + {0x922d, 0xdb}, + {0x922e, 0xb2}, + {0x922f, 0xdc}, + {0x9230, 0xb2}, + {0x9231, 0xdd}, + {0x9232, 0xe2}, + {0x9233, 0xe1}, + {0x9234, 0xb2}, + {0x9235, 0xe2}, + {0x9236, 0xb2}, + {0x9237, 0xe3}, + {0x9238, 0xb7}, + {0x9239, 0xb9}, + {0x923a, 0xb7}, + {0x923b, 0xbb}, + {0x923c, 0xb7}, + {0x923d, 0xbc}, + {0x923e, 0xb7}, + {0x923f, 0xc5}, + {0x9240, 0xb7}, + {0x9241, 0xc7}, + {0x9242, 0xb7}, + {0x9243, 0xc9}, + {0x9244, 0x98}, + {0x9245, 0x56}, + {0x9246, 0x98}, + {0x9247, 0x55}, + {0x9380, 0x00}, + {0x9381, 0x62}, + {0x9382, 0x00}, + {0x9383, 0x56}, + {0x9384, 0x00}, + {0x9385, 0x52}, + {0x9388, 0x00}, + {0x9389, 0x55}, + {0x938a, 0x00}, + {0x938b, 0x55}, + {0x938c, 0x00}, + {0x938d, 0x41}, + {0x5078, 0x01}, + {0x0112, 0x0a}, + {0x0113, 0x0a}, + {0x0114, 0x03}, + {0x0342, 0x11}, + {0x0343, 0xa0}, + {0x0340, 0x0d}, + {0x0341, 0xda}, + {0x3210, 0x00}, + {0x0344, 0x00}, + {0x0345, 0x00}, + {0x0346, 0x00}, + {0x0347, 0x00}, + {0x0348, 0x0f}, + {0x0349, 0xd7}, + {0x034a, 0x0b}, + {0x034b, 0xdf}, + {0x00e3, 0x00}, + {0x00e4, 0x00}, + {0x00e5, 0x01}, + {0x00fc, 0x0a}, + {0x00fd, 0x0a}, + {0x00fe, 0x0a}, + {0x00ff, 0x0a}, + {0xe013, 0x00}, + {0x0220, 0x00}, + {0x0221, 0x11}, + {0x0381, 0x01}, + {0x0383, 0x01}, + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0900, 0x00}, + {0x0901, 0x11}, + {0x0902, 0x00}, + {0x3140, 0x02}, + {0x3241, 0x11}, + {0x3250, 0x03}, + {0x3e10, 0x00}, + {0x3e11, 0x00}, + {0x3f0d, 0x00}, + {0x3f42, 0x00}, + {0x3f43, 0x00}, + {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x10}, + {0x0408, 0x00}, + {0x0409, 0x00}, + {0x040a, 0x00}, + {0x040b, 0x00}, + {0x040c, 0x0f}, + {0x040d, 0xd8}, + {0x040e, 0x0b}, + {0x040f, 0xe0}, + {0x034c, 0x0f}, + {0x034d, 0xd8}, + {0x034e, 0x0b}, + {0x034f, 0xe0}, + {0x0301, 0x05}, + {0x0303, 0x02}, + {0x0305, 0x04}, + {0x0306, 0x00}, + {0x0307, 0xc8}, + {0x0309, 0x0a}, + {0x030b, 0x01}, + {0x030d, 0x02}, + {0x030e, 0x01}, + {0x030f, 0x5e}, + {0x0310, 0x00}, + {0x0820, 0x12}, + {0x0821, 0xc0}, + {0x0822, 0x00}, + {0x0823, 0x00}, + {0x3e20, 0x01}, + {0x3e37, 0x00}, + {0x3f50, 0x00}, + {0x3f56, 0x00}, + {0x3f57, 0xe2}, + {0x3c0a, 0x5a}, + {0x3c0b, 0x55}, + {0x3c0c, 0x28}, + {0x3c0d, 0x07}, + {0x3c0e, 0xff}, + {0x3c0f, 0x00}, + {0x3c10, 0x00}, + {0x3c11, 0x02}, + {0x3c12, 0x00}, + {0x3c13, 0x03}, + {0x3c14, 0x00}, + {0x3c15, 0x00}, + {0x3c16, 0x0c}, + {0x3c17, 0x0c}, + {0x3c18, 0x0c}, + {0x3c19, 0x0a}, + {0x3c1a, 0x0a}, + {0x3c1b, 0x0a}, + {0x3c1c, 0x00}, + {0x3c1d, 0x00}, + {0x3c1e, 0x00}, + {0x3c1f, 0x00}, + {0x3c20, 0x00}, + {0x3c21, 0x00}, + {0x3c22, 0x3f}, + {0x3c23, 0x0a}, + {0x3e35, 0x01}, + {0x3f4a, 0x03}, + {0x3f4b, 0xbf}, + {0x3f26, 0x00}, + {0x0202, 0x0d}, + {0x0203, 0xc4}, + {0x0204, 0x00}, + {0x0205, 0x00}, + {0x020e, 0x01}, + {0x020f, 0x00}, + {0x0210, 0x01}, + {0x0211, 0x00}, + {0x0212, 0x01}, + {0x0213, 0x00}, + {0x0214, 0x01}, + {0x0215, 0x00}, + {0xbcf1, 0x00}, +}; + +/* Supported sensor mode configurations */ +static const struct imx412_mode supported_mode = { + .width = 4056, + .height = 3040, + .hblank = 456, + .vblank = 506, + .vblank_min = 506, + .vblank_max = 32420, + .pclk = 480000000, + .link_freq_idx = 0, + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_4056x3040_regs), + .regs = mode_4056x3040_regs, + }, +}; + +/** + * to_imx412() - imx412 V4L2 sub-device to imx412 device. + * @subdev: pointer to imx412 V4L2 sub-device + * + * Return: pointer to imx412 device + */ +static inline struct imx412 *to_imx412(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct imx412, sd); +} + +/** + * imx412_read_reg() - Read registers. + * @imx412: pointer to imx412 device + * @reg: register address + * @len: length of bytes to read. Max supported bytes is 4 + * @val: pointer to register value to be filled. + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_read_reg(struct imx412 *imx412, u16 reg, u32 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd); + struct i2c_msg msgs[2] = {0}; + u8 addr_buf[2] = {0}; + u8 data_buf[4] = {0}; + int ret; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +/** + * imx412_write_reg() - Write register + * @imx412: pointer to imx412 device + * @reg: register address + * @len: length of bytes. Max supported bytes is 4 + * @val: register value + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_write_reg(struct imx412 *imx412, u16 reg, u32 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&imx412->sd); + u8 buf[6] = {0}; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/** + * imx412_write_regs() - Write a list of registers + * @imx412: pointer to imx412 device + * @regs: list of registers to be written + * @len: length of registers array + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_write_regs(struct imx412 *imx412, + const struct imx412_reg *regs, u32 len) +{ + unsigned int i; + int ret; + + for (i = 0; i < len; i++) { + ret = imx412_write_reg(imx412, regs[i].address, 1, regs[i].val); + if (ret) + return ret; + } + + return 0; +} + +/** + * imx412_update_controls() - Update control ranges based on streaming mode + * @imx412: pointer to imx412 device + * @mode: pointer to imx412_mode sensor mode + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_update_controls(struct imx412 *imx412, + const struct imx412_mode *mode) +{ + int ret; + + ret = __v4l2_ctrl_s_ctrl(imx412->link_freq_ctrl, mode->link_freq_idx); + if (ret) + return ret; + + ret = __v4l2_ctrl_s_ctrl(imx412->hblank_ctrl, mode->hblank); + if (ret) + return ret; + + return __v4l2_ctrl_modify_range(imx412->vblank_ctrl, mode->vblank_min, + mode->vblank_max, 1, mode->vblank); +} + +/** + * imx412_update_exp_gain() - Set updated exposure and gain + * @imx412: pointer to imx412 device + * @exposure: updated exposure value + * @gain: updated analog gain value + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) +{ + u32 lpfr, shutter; + int ret; + + lpfr = imx412->vblank + imx412->cur_mode->height; + shutter = lpfr - exposure; + + dev_dbg(imx412->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u", + exposure, gain, shutter, lpfr); + + ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1); + if (ret) + return ret; + + ret = imx412_write_reg(imx412, IMX412_REG_LPFR, 2, lpfr); + if (ret) + goto error_release_group_hold; + + ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, shutter); + if (ret) + goto error_release_group_hold; + + ret = imx412_write_reg(imx412, IMX412_REG_AGAIN, 2, gain); + +error_release_group_hold: + imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 0); + + return ret; +} + +/** + * imx412_set_ctrl() - Set subdevice control + * @ctrl: pointer to v4l2_ctrl structure + * + * Supported controls: + * - V4L2_CID_VBLANK + * - cluster controls: + * - V4L2_CID_ANALOGUE_GAIN + * - V4L2_CID_EXPOSURE + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx412 *imx412 = + container_of(ctrl->handler, struct imx412, ctrl_handler); + u32 analog_gain; + u32 exposure; + int ret; + + switch (ctrl->id) { + case V4L2_CID_VBLANK: + imx412->vblank = imx412->vblank_ctrl->val; + + dev_dbg(imx412->dev, "Received vblank %u, new lpfr %u", + imx412->vblank, + imx412->vblank + imx412->cur_mode->height); + + ret = __v4l2_ctrl_modify_range(imx412->exp_ctrl, + IMX412_EXPOSURE_MIN, + imx412->vblank + + imx412->cur_mode->height - + IMX412_EXPOSURE_OFFSET, + 1, IMX412_EXPOSURE_DEFAULT); + break; + case V4L2_CID_EXPOSURE: + /* Set controls only if sensor is in power on state */ + if (!pm_runtime_get_if_in_use(imx412->dev)) + return 0; + + exposure = ctrl->val; + analog_gain = imx412->again_ctrl->val; + + dev_dbg(imx412->dev, "Received exp %u, analog gain %u", + exposure, analog_gain); + + ret = imx412_update_exp_gain(imx412, exposure, analog_gain); + + pm_runtime_put(imx412->dev); + + break; + default: + dev_err(imx412->dev, "Invalid control %d", ctrl->id); + ret = -EINVAL; + } + + return ret; +} + +/* V4l2 subdevice control ops*/ +static const struct v4l2_ctrl_ops imx412_ctrl_ops = { + .s_ctrl = imx412_set_ctrl, +}; + +/** + * imx412_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @code: V4L2 sub-device code enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = supported_mode.code; + + return 0; +} + +/** + * imx412_enum_frame_size() - Enumerate V4L2 sub-device frame sizes + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fsize: V4L2 sub-device size enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fsize) +{ + if (fsize->index > 0) + return -EINVAL; + + if (fsize->code != supported_mode.code) + return -EINVAL; + + fsize->min_width = supported_mode.width; + fsize->max_width = fsize->min_width; + fsize->min_height = supported_mode.height; + fsize->max_height = fsize->min_height; + + return 0; +} + +/** + * imx412_fill_pad_format() - Fill subdevice pad format + * from selected sensor mode + * @imx412: pointer to imx412 device + * @mode: pointer to imx412_mode sensor mode + * @fmt: V4L2 sub-device format need to be filled + */ +static void imx412_fill_pad_format(struct imx412 *imx412, + const struct imx412_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = mode->code; + fmt->format.field = V4L2_FIELD_NONE; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->format.quantization = V4L2_QUANTIZATION_DEFAULT; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; +} + +/** + * imx412_get_pad_format() - Get subdevice pad format + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx412 *imx412 = to_imx412(sd); + + mutex_lock(&imx412->mutex); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + fmt->format = *framefmt; + } else { + imx412_fill_pad_format(imx412, imx412->cur_mode, fmt); + } + + mutex_unlock(&imx412->mutex); + + return 0; +} + +/** + * imx412_set_pad_format() - Set subdevice pad format + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct imx412 *imx412 = to_imx412(sd); + const struct imx412_mode *mode; + int ret = 0; + + mutex_lock(&imx412->mutex); + + mode = &supported_mode; + imx412_fill_pad_format(imx412, mode, fmt); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + *framefmt = fmt->format; + } else { + ret = imx412_update_controls(imx412, mode); + if (!ret) + imx412->cur_mode = mode; + } + + mutex_unlock(&imx412->mutex); + + return ret; +} + +/** + * imx412_init_pad_cfg() - Initialize sub-device pad configuration + * @sd: pointer to imx412 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_init_pad_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct imx412 *imx412 = to_imx412(sd); + struct v4l2_subdev_format fmt = { 0 }; + + fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + imx412_fill_pad_format(imx412, &supported_mode, &fmt); + + return imx412_set_pad_format(sd, sd_state, &fmt); +} + +/** + * imx412_start_streaming() - Start sensor stream + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_start_streaming(struct imx412 *imx412) +{ + const struct imx412_reg_list *reg_list; + int ret; + + /* Write sensor mode registers */ + reg_list = &imx412->cur_mode->reg_list; + ret = imx412_write_regs(imx412, reg_list->regs, + reg_list->num_of_regs); + if (ret) { + dev_err(imx412->dev, "fail to write initial registers"); + return ret; + } + + /* Setup handler will write actual exposure and gain */ + ret = __v4l2_ctrl_handler_setup(imx412->sd.ctrl_handler); + if (ret) { + dev_err(imx412->dev, "fail to setup handler"); + return ret; + } + + /* Delay is required before streaming*/ + usleep_range(7400, 8000); + + /* Start streaming */ + ret = imx412_write_reg(imx412, IMX412_REG_MODE_SELECT, + 1, IMX412_MODE_STREAMING); + if (ret) { + dev_err(imx412->dev, "fail to start streaming"); + return ret; + } + + return 0; +} + +/** + * imx412_stop_streaming() - Stop sensor stream + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_stop_streaming(struct imx412 *imx412) +{ + return imx412_write_reg(imx412, IMX412_REG_MODE_SELECT, + 1, IMX412_MODE_STANDBY); +} + +/** + * imx412_set_stream() - Enable sensor streaming + * @sd: pointer to imx412 subdevice + * @enable: set to enable sensor streaming + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx412 *imx412 = to_imx412(sd); + int ret; + + mutex_lock(&imx412->mutex); + + if (imx412->streaming == enable) { + mutex_unlock(&imx412->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(imx412->dev); + if (ret) + goto error_unlock; + + ret = imx412_start_streaming(imx412); + if (ret) + goto error_power_off; + } else { + imx412_stop_streaming(imx412); + pm_runtime_put(imx412->dev); + } + + imx412->streaming = enable; + + mutex_unlock(&imx412->mutex); + + return 0; + +error_power_off: + pm_runtime_put(imx412->dev); +error_unlock: + mutex_unlock(&imx412->mutex); + + return ret; +} + +/** + * imx412_detect() - Detect imx412 sensor + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, -EIO if sensor id does not match + */ +static int imx412_detect(struct imx412 *imx412) +{ + int ret; + u32 val; + + ret = imx412_read_reg(imx412, IMX412_REG_ID, 2, &val); + if (ret) + return ret; + + if (val != IMX412_ID) { + dev_err(imx412->dev, "chip id mismatch: %x!=%x", + IMX412_ID, val); + return -ENXIO; + } + + return 0; +} + +/** + * imx412_parse_hw_config() - Parse HW configuration and check if supported + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_parse_hw_config(struct imx412 *imx412) +{ + struct fwnode_handle *fwnode = dev_fwnode(imx412->dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *ep; + unsigned long rate; + unsigned int i; + int ret; + + if (!fwnode) + return -ENXIO; + + /* Request optional reset pin */ + imx412->reset_gpio = devm_gpiod_get_optional(imx412->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(imx412->reset_gpio)) { + dev_err(imx412->dev, "failed to get reset gpio %ld", + PTR_ERR(imx412->reset_gpio)); + return PTR_ERR(imx412->reset_gpio); + } + + /* Get sensor input clock */ + imx412->inclk = devm_clk_get(imx412->dev, NULL); + if (IS_ERR(imx412->inclk)) { + dev_err(imx412->dev, "could not get inclk"); + return PTR_ERR(imx412->inclk); + } + + rate = clk_get_rate(imx412->inclk); + if (rate != IMX412_INCLK_RATE) { + dev_err(imx412->dev, "inclk frequency mismatch"); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != IMX412_NUM_DATA_LANES) { + dev_err(imx412->dev, + "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto done_endpoint_free; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(imx412->dev, "no link frequencies defined"); + ret = -EINVAL; + goto done_endpoint_free; + } + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) + if (bus_cfg.link_frequencies[i] == IMX412_LINK_FREQ) + goto done_endpoint_free; + + ret = -EINVAL; + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +/* V4l2 subdevice ops */ +static const struct v4l2_subdev_video_ops imx412_video_ops = { + .s_stream = imx412_set_stream, +}; + +static const struct v4l2_subdev_pad_ops imx412_pad_ops = { + .init_cfg = imx412_init_pad_cfg, + .enum_mbus_code = imx412_enum_mbus_code, + .enum_frame_size = imx412_enum_frame_size, + .get_fmt = imx412_get_pad_format, + .set_fmt = imx412_set_pad_format, +}; + +static const struct v4l2_subdev_ops imx412_subdev_ops = { + .video = &imx412_video_ops, + .pad = &imx412_pad_ops, +}; + +/** + * imx412_power_on() - Sensor power on sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx412 *imx412 = to_imx412(sd); + int ret; + + gpiod_set_value_cansleep(imx412->reset_gpio, 1); + + ret = clk_prepare_enable(imx412->inclk); + if (ret) { + dev_err(imx412->dev, "fail to enable inclk"); + goto error_reset; + } + + usleep_range(1000, 1200); + + return 0; + +error_reset: + gpiod_set_value_cansleep(imx412->reset_gpio, 0); + + return ret; +} + +/** + * imx412_power_off() - Sensor power off sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct imx412 *imx412 = to_imx412(sd); + + gpiod_set_value_cansleep(imx412->reset_gpio, 0); + + clk_disable_unprepare(imx412->inclk); + + return 0; +} + +/** + * imx412_init_controls() - Initialize sensor subdevice controls + * @imx412: pointer to imx412 device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_init_controls(struct imx412 *imx412) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &imx412->ctrl_handler; + const struct imx412_mode *mode = imx412->cur_mode; + u32 lpfr; + int ret; + + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); + if (ret) + return ret; + + /* Serialize controls with sensor device */ + ctrl_hdlr->lock = &imx412->mutex; + + /* Initialize exposure and gain */ + lpfr = mode->vblank + mode->height; + imx412->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_EXPOSURE, + IMX412_EXPOSURE_MIN, + lpfr - IMX412_EXPOSURE_OFFSET, + IMX412_EXPOSURE_STEP, + IMX412_EXPOSURE_DEFAULT); + + imx412->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, + IMX412_AGAIN_MIN, + IMX412_AGAIN_MAX, + IMX412_AGAIN_STEP, + IMX412_AGAIN_DEFAULT); + + v4l2_ctrl_cluster(2, &imx412->exp_ctrl); + + imx412->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_VBLANK, + mode->vblank_min, + mode->vblank_max, + 1, mode->vblank); + + /* Read only controls */ + imx412->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_PIXEL_RATE, + mode->pclk, mode->pclk, + 1, mode->pclk); + + imx412->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq) - + 1, + mode->link_freq_idx, + link_freq); + if (imx412->link_freq_ctrl) + imx412->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + imx412->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &imx412_ctrl_ops, + V4L2_CID_HBLANK, + IMX412_REG_MIN, + IMX412_REG_MAX, + 1, mode->hblank); + if (imx412->hblank_ctrl) + imx412->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + if (ctrl_hdlr->error) { + dev_err(imx412->dev, "control init failed: %d", + ctrl_hdlr->error); + v4l2_ctrl_handler_free(ctrl_hdlr); + return ctrl_hdlr->error; + } + + imx412->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +/** + * imx412_probe() - I2C client device binding + * @client: pointer to i2c client device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_probe(struct i2c_client *client) +{ + struct imx412 *imx412; + int ret; + + imx412 = devm_kzalloc(&client->dev, sizeof(*imx412), GFP_KERNEL); + if (!imx412) + return -ENOMEM; + + imx412->dev = &client->dev; + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&imx412->sd, client, &imx412_subdev_ops); + + ret = imx412_parse_hw_config(imx412); + if (ret) { + dev_err(imx412->dev, "HW configuration is not supported"); + return ret; + } + + mutex_init(&imx412->mutex); + + ret = imx412_power_on(imx412->dev); + if (ret) { + dev_err(imx412->dev, "failed to power-on the sensor"); + goto error_mutex_destroy; + } + + /* Check module identity */ + ret = imx412_detect(imx412); + if (ret) { + dev_err(imx412->dev, "failed to find sensor: %d", ret); + goto error_power_off; + } + + /* Set default mode to max resolution */ + imx412->cur_mode = &supported_mode; + imx412->vblank = imx412->cur_mode->vblank; + + ret = imx412_init_controls(imx412); + if (ret) { + dev_err(imx412->dev, "failed to init controls: %d", ret); + goto error_power_off; + } + + /* Initialize subdev */ + imx412->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx412->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + imx412->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx412->sd.entity, 1, &imx412->pad); + if (ret) { + dev_err(imx412->dev, "failed to init entity pads: %d", ret); + goto error_handler_free; + } + + ret = v4l2_async_register_subdev_sensor(&imx412->sd); + if (ret < 0) { + dev_err(imx412->dev, + "failed to register async subdev: %d", ret); + goto error_media_entity; + } + + pm_runtime_set_active(imx412->dev); + pm_runtime_enable(imx412->dev); + pm_runtime_idle(imx412->dev); + + return 0; + +error_media_entity: + media_entity_cleanup(&imx412->sd.entity); +error_handler_free: + v4l2_ctrl_handler_free(imx412->sd.ctrl_handler); +error_power_off: + imx412_power_off(imx412->dev); +error_mutex_destroy: + mutex_destroy(&imx412->mutex); + + return ret; +} + +/** + * imx412_remove() - I2C client device unbinding + * @client: pointer to I2C client device + * + * Return: 0 if successful, error code otherwise. + */ +static int imx412_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx412 *imx412 = to_imx412(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + imx412_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + + mutex_destroy(&imx412->mutex); + + return 0; +} + +static const struct dev_pm_ops imx412_pm_ops = { + SET_RUNTIME_PM_OPS(imx412_power_off, imx412_power_on, NULL) +}; + +static const struct of_device_id imx412_of_match[] = { + { .compatible = "sony,imx412" }, + { } +}; + +MODULE_DEVICE_TABLE(of, imx412_of_match); + +static struct i2c_driver imx412_driver = { + .probe_new = imx412_probe, + .remove = imx412_remove, + .driver = { + .name = "imx412", + .pm = &imx412_pm_ops, + .of_match_table = imx412_of_match, + }, +}; + +module_i2c_driver(imx412_driver); + +MODULE_DESCRIPTION("Sony imx412 sensor driver"); +MODULE_LICENSE("GPL"); From 4874ea39874731e589dc5b329f5c03965c2a6474 Mon Sep 17 00:00:00 2001 From: Martina Krasteva Date: Thu, 27 May 2021 16:21:44 +0200 Subject: [PATCH 154/195] media: dt-bindings: media: Add bindings for ov9282 - Add dt-bindings documentation for OmniVision ov9282 sensor driver - Add MAINTAINERS entry for OmniVision ov9282 binding documentation Signed-off-by: Martina Krasteva Acked-by: Daniele Alessandrelli Acked-by: Paul J. Murphy Reviewed-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/ovti,ov9282.yaml | 91 +++++++++++++++++++ MAINTAINERS | 8 ++ 2 files changed, 99 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml new file mode 100644 index 0000000000000..ad42992c6da39 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2021 Intel Corporation +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ov9282.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OV9282 Sensor + +maintainers: + - Paul J. Murphy + - Daniele Alessandrelli + +description: + OV9282 sensor is an OmniVision black & white CMOS active pixel digital image + sensor with an active array size of 1296H x 816V. It is programmable through + I2C interface. The I2C client address is fixed to 0x60/0x70 as per sensor data + sheet. Image data is sent through MIPI CSI-2. + +properties: + compatible: + const: ovti,ov9282 + reg: + description: I2C address + maxItems: 1 + + assigned-clocks: true + assigned-clock-parents: true + assigned-clock-rates: true + + clocks: + description: Clock frequency from 6 to 27MHz + maxItems: 1 + + reset-gpios: + description: Reference to the GPIO connected to the XCLR pin, if any. + maxItems: 1 + + port: + additionalProperties: false + $ref: /schemas/graph.yaml#/properties/port + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: true + link-frequencies: true + + required: + - data-lanes + - link-frequencies + + required: + - endpoint + +required: + - compatible + - reg + - clocks + - port + +additionalProperties: false + +examples: + - | + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + camera@60 { + compatible = "ovti,ov9282"; + reg = <0x60>; + clocks = <&ov9282_clk>; + + assigned-clocks = <&ov9282_clk>; + assigned-clock-parents = <&ov9282_clk_parent>; + assigned-clock-rates = <24000000>; + + port { + ov9282: endpoint { + remote-endpoint = <&cam>; + data-lanes = <1 2>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 955d74fe8b9e4..fe9ffeeae9f47 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13772,6 +13772,14 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/ov8856.yaml F: drivers/media/i2c/ov8856.c +OMNIVISION OV9282 SENSOR DRIVER +M: Paul J. Murphy +M: Daniele Alessandrelli +L: linux-media@vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml + OMNIVISION OV9640 SENSOR DRIVER M: Petr Cvek L: linux-media@vger.kernel.org From 14ea315bbeb75aa996b577822999df4edbcfb3d0 Mon Sep 17 00:00:00 2001 From: Martina Krasteva Date: Thu, 27 May 2021 16:21:45 +0200 Subject: [PATCH 155/195] media: i2c: Add ov9282 camera sensor driver Add a v4l2 sub-device driver for the OmniVisison ov9282 black&white image sensor. The camera sensor uses the i2c bus for control and the csi-2 bus for data. The following features are supported: - manual exposure and analog gain control support - vblank/hblank/pixel rate/link freq control support - supported resolution: - 1280x720 @ 30fps [Sakari Ailus: Rebase on commit c802a4174beeb25cb539c806c9d0d3c0f61dfa53.] Signed-off-by: Martina Krasteva Acked-by: Daniele Alessandrelli Acked-by: Paul J. Murphy Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 1 + drivers/media/i2c/Kconfig | 14 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ov9282.c | 1137 ++++++++++++++++++++++++++++++++++++ 4 files changed, 1153 insertions(+) create mode 100644 drivers/media/i2c/ov9282.c diff --git a/MAINTAINERS b/MAINTAINERS index fe9ffeeae9f47..a958368c09d16 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13779,6 +13779,7 @@ L: linux-media@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/i2c/ovti,ov9282.yaml +F: drivers/media/i2c/ov9282.c OMNIVISION OV9640 SENSOR DRIVER M: Petr Cvek diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index bdae664beb871..08feb3e8c1bf6 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -1131,6 +1131,20 @@ config VIDEO_OV8865 To compile this driver as a module, choose M here: the module will be called ov8865. +config VIDEO_OV9282 + tristate "OmniVision OV9282 sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_V4L2 + select VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the OmniVision + OV9282 camera sensor. + + To compile this driver as a module, choose M here: the + module will be called ov9282. + config VIDEO_OV9640 tristate "OmniVision OV9640 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 303995beb6731..83268f20aa3ae 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -84,6 +84,7 @@ obj-$(CONFIG_VIDEO_OV772X) += ov772x.o obj-$(CONFIG_VIDEO_OV7740) += ov7740.o obj-$(CONFIG_VIDEO_OV8856) += ov8856.o obj-$(CONFIG_VIDEO_OV8865) += ov8865.o +obj-$(CONFIG_VIDEO_OV9282) += ov9282.o obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV9734) += ov9734.o diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c new file mode 100644 index 0000000000000..2e0b315801e56 --- /dev/null +++ b/drivers/media/i2c/ov9282.c @@ -0,0 +1,1137 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * OmniVision ov9282 Camera Sensor Driver + * + * Copyright (C) 2021 Intel Corporation + */ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Streaming Mode */ +#define OV9282_REG_MODE_SELECT 0x0100 +#define OV9282_MODE_STANDBY 0x00 +#define OV9282_MODE_STREAMING 0x01 + +/* Lines per frame */ +#define OV9282_REG_LPFR 0x380e + +/* Chip ID */ +#define OV9282_REG_ID 0x300a +#define OV9282_ID 0x9281 + +/* Exposure control */ +#define OV9282_REG_EXPOSURE 0x3500 +#define OV9282_EXPOSURE_MIN 1 +#define OV9282_EXPOSURE_OFFSET 12 +#define OV9282_EXPOSURE_STEP 1 +#define OV9282_EXPOSURE_DEFAULT 0x0282 + +/* Analog gain control */ +#define OV9282_REG_AGAIN 0x3509 +#define OV9282_AGAIN_MIN 0x10 +#define OV9282_AGAIN_MAX 0xff +#define OV9282_AGAIN_STEP 1 +#define OV9282_AGAIN_DEFAULT 0x10 + +/* Group hold register */ +#define OV9282_REG_HOLD 0x3308 + +/* Input clock rate */ +#define OV9282_INCLK_RATE 24000000 + +/* CSI2 HW configuration */ +#define OV9282_LINK_FREQ 400000000 +#define OV9282_NUM_DATA_LANES 2 + +#define OV9282_REG_MIN 0x00 +#define OV9282_REG_MAX 0xfffff + +/** + * struct ov9282_reg - ov9282 sensor register + * @address: Register address + * @val: Register value + */ +struct ov9282_reg { + u16 address; + u8 val; +}; + +/** + * struct ov9282_reg_list - ov9282 sensor register list + * @num_of_regs: Number of registers in the list + * @regs: Pointer to register list + */ +struct ov9282_reg_list { + u32 num_of_regs; + const struct ov9282_reg *regs; +}; + +/** + * struct ov9282_mode - ov9282 sensor mode structure + * @width: Frame width + * @height: Frame height + * @code: Format code + * @hblank: Horizontal blanking in lines + * @vblank: Vertical blanking in lines + * @vblank_min: Minimum vertical blanking in lines + * @vblank_max: Maximum vertical blanking in lines + * @pclk: Sensor pixel clock + * @link_freq_idx: Link frequency index + * @reg_list: Register list for sensor mode + */ +struct ov9282_mode { + u32 width; + u32 height; + u32 code; + u32 hblank; + u32 vblank; + u32 vblank_min; + u32 vblank_max; + u64 pclk; + u32 link_freq_idx; + struct ov9282_reg_list reg_list; +}; + +/** + * struct ov9282 - ov9282 sensor device structure + * @dev: Pointer to generic device + * @client: Pointer to i2c client + * @sd: V4L2 sub-device + * @pad: Media pad. Only one pad supported + * @reset_gpio: Sensor reset gpio + * @inclk: Sensor input clock + * @ctrl_handler: V4L2 control handler + * @link_freq_ctrl: Pointer to link frequency control + * @pclk_ctrl: Pointer to pixel clock control + * @hblank_ctrl: Pointer to horizontal blanking control + * @vblank_ctrl: Pointer to vertical blanking control + * @exp_ctrl: Pointer to exposure control + * @again_ctrl: Pointer to analog gain control + * @vblank: Vertical blanking in lines + * @cur_mode: Pointer to current selected sensor mode + * @mutex: Mutex for serializing sensor controls + * @streaming: Flag indicating streaming state + */ +struct ov9282 { + struct device *dev; + struct i2c_client *client; + struct v4l2_subdev sd; + struct media_pad pad; + struct gpio_desc *reset_gpio; + struct clk *inclk; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *link_freq_ctrl; + struct v4l2_ctrl *pclk_ctrl; + struct v4l2_ctrl *hblank_ctrl; + struct v4l2_ctrl *vblank_ctrl; + struct { + struct v4l2_ctrl *exp_ctrl; + struct v4l2_ctrl *again_ctrl; + }; + u32 vblank; + const struct ov9282_mode *cur_mode; + struct mutex mutex; + bool streaming; +}; + +static const s64 link_freq[] = { + OV9282_LINK_FREQ, +}; + +/* Sensor mode registers */ +static const struct ov9282_reg mode_1280x720_regs[] = { + {0x0302, 0x32}, + {0x030d, 0x50}, + {0x030e, 0x02}, + {0x3001, 0x00}, + {0x3004, 0x00}, + {0x3005, 0x00}, + {0x3006, 0x04}, + {0x3011, 0x0a}, + {0x3013, 0x18}, + {0x301c, 0xf0}, + {0x3022, 0x01}, + {0x3030, 0x10}, + {0x3039, 0x32}, + {0x303a, 0x00}, + {0x3500, 0x00}, + {0x3501, 0x5f}, + {0x3502, 0x1e}, + {0x3503, 0x08}, + {0x3505, 0x8c}, + {0x3507, 0x03}, + {0x3508, 0x00}, + {0x3509, 0x10}, + {0x3610, 0x80}, + {0x3611, 0xa0}, + {0x3620, 0x6e}, + {0x3632, 0x56}, + {0x3633, 0x78}, + {0x3666, 0x00}, + {0x366f, 0x5a}, + {0x3680, 0x84}, + {0x3712, 0x80}, + {0x372d, 0x22}, + {0x3731, 0x80}, + {0x3732, 0x30}, + {0x3778, 0x00}, + {0x377d, 0x22}, + {0x3788, 0x02}, + {0x3789, 0xa4}, + {0x378a, 0x00}, + {0x378b, 0x4a}, + {0x3799, 0x20}, + {0x3800, 0x00}, + {0x3801, 0x00}, + {0x3802, 0x00}, + {0x3803, 0x00}, + {0x3804, 0x05}, + {0x3805, 0x0f}, + {0x3806, 0x02}, + {0x3807, 0xdf}, + {0x3808, 0x05}, + {0x3809, 0x00}, + {0x380a, 0x02}, + {0x380b, 0xd0}, + {0x380c, 0x05}, + {0x380d, 0xfa}, + {0x380e, 0x06}, + {0x380f, 0xce}, + {0x3810, 0x00}, + {0x3811, 0x08}, + {0x3812, 0x00}, + {0x3813, 0x08}, + {0x3814, 0x11}, + {0x3815, 0x11}, + {0x3820, 0x3c}, + {0x3821, 0x84}, + {0x3881, 0x42}, + {0x38a8, 0x02}, + {0x38a9, 0x80}, + {0x38b1, 0x00}, + {0x38c4, 0x00}, + {0x38c5, 0xc0}, + {0x38c6, 0x04}, + {0x38c7, 0x80}, + {0x3920, 0xff}, + {0x4003, 0x40}, + {0x4008, 0x02}, + {0x4009, 0x05}, + {0x400c, 0x00}, + {0x400d, 0x03}, + {0x4010, 0x40}, + {0x4043, 0x40}, + {0x4307, 0x30}, + {0x4317, 0x00}, + {0x4501, 0x00}, + {0x4507, 0x00}, + {0x4509, 0x80}, + {0x450a, 0x08}, + {0x4601, 0x04}, + {0x470f, 0x00}, + {0x4f07, 0x00}, + {0x4800, 0x20}, + {0x5000, 0x9f}, + {0x5001, 0x00}, + {0x5e00, 0x00}, + {0x5d00, 0x07}, + {0x5d01, 0x00}, + {0x0101, 0x01}, + {0x1000, 0x03}, + {0x5a08, 0x84}, +}; + +/* Supported sensor mode configurations */ +static const struct ov9282_mode supported_mode = { + .width = 1280, + .height = 720, + .hblank = 250, + .vblank = 1022, + .vblank_min = 151, + .vblank_max = 51540, + .pclk = 160000000, + .link_freq_idx = 0, + .code = MEDIA_BUS_FMT_Y10_1X10, + .reg_list = { + .num_of_regs = ARRAY_SIZE(mode_1280x720_regs), + .regs = mode_1280x720_regs, + }, +}; + +/** + * to_ov9282() - ov9282 V4L2 sub-device to ov9282 device. + * @subdev: pointer to ov9282 V4L2 sub-device + * + * Return: pointer to ov9282 device + */ +static inline struct ov9282 *to_ov9282(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct ov9282, sd); +} + +/** + * ov9282_read_reg() - Read registers. + * @ov9282: pointer to ov9282 device + * @reg: register address + * @len: length of bytes to read. Max supported bytes is 4 + * @val: pointer to register value to be filled. + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_read_reg(struct ov9282 *ov9282, u16 reg, u32 len, u32 *val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9282->sd); + struct i2c_msg msgs[2] = {0}; + u8 addr_buf[2] = {0}; + u8 data_buf[4] = {0}; + int ret; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, addr_buf); + + /* Write register address */ + msgs[0].addr = client->addr; + msgs[0].flags = 0; + msgs[0].len = ARRAY_SIZE(addr_buf); + msgs[0].buf = addr_buf; + + /* Read data from register */ + msgs[1].addr = client->addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = &data_buf[4 - len]; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *val = get_unaligned_be32(data_buf); + + return 0; +} + +/** + * ov9282_write_reg() - Write register + * @ov9282: pointer to ov9282 device + * @reg: register address + * @len: length of bytes. Max supported bytes is 4 + * @val: register value + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_write_reg(struct ov9282 *ov9282, u16 reg, u32 len, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov9282->sd); + u8 buf[6] = {0}; + + if (WARN_ON(len > 4)) + return -EINVAL; + + put_unaligned_be16(reg, buf); + put_unaligned_be32(val << (8 * (4 - len)), buf + 2); + if (i2c_master_send(client, buf, len + 2) != len + 2) + return -EIO; + + return 0; +} + +/** + * ov9282_write_regs() - Write a list of registers + * @ov9282: pointer to ov9282 device + * @regs: list of registers to be written + * @len: length of registers array + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_write_regs(struct ov9282 *ov9282, + const struct ov9282_reg *regs, u32 len) +{ + unsigned int i; + int ret; + + for (i = 0; i < len; i++) { + ret = ov9282_write_reg(ov9282, regs[i].address, 1, regs[i].val); + if (ret) + return ret; + } + + return 0; +} + +/** + * ov9282_update_controls() - Update control ranges based on streaming mode + * @ov9282: pointer to ov9282 device + * @mode: pointer to ov9282_mode sensor mode + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_update_controls(struct ov9282 *ov9282, + const struct ov9282_mode *mode) +{ + int ret; + + ret = __v4l2_ctrl_s_ctrl(ov9282->link_freq_ctrl, mode->link_freq_idx); + if (ret) + return ret; + + ret = __v4l2_ctrl_s_ctrl(ov9282->hblank_ctrl, mode->hblank); + if (ret) + return ret; + + return __v4l2_ctrl_modify_range(ov9282->vblank_ctrl, mode->vblank_min, + mode->vblank_max, 1, mode->vblank); +} + +/** + * ov9282_update_exp_gain() - Set updated exposure and gain + * @ov9282: pointer to ov9282 device + * @exposure: updated exposure value + * @gain: updated analog gain value + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_update_exp_gain(struct ov9282 *ov9282, u32 exposure, u32 gain) +{ + u32 lpfr; + int ret; + + lpfr = ov9282->vblank + ov9282->cur_mode->height; + + dev_dbg(ov9282->dev, "Set exp %u, analog gain %u, lpfr %u", + exposure, gain, lpfr); + + ret = ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 1); + if (ret) + return ret; + + ret = ov9282_write_reg(ov9282, OV9282_REG_LPFR, 2, lpfr); + if (ret) + goto error_release_group_hold; + + ret = ov9282_write_reg(ov9282, OV9282_REG_EXPOSURE, 3, exposure << 4); + if (ret) + goto error_release_group_hold; + + ret = ov9282_write_reg(ov9282, OV9282_REG_AGAIN, 1, gain); + +error_release_group_hold: + ov9282_write_reg(ov9282, OV9282_REG_HOLD, 1, 0); + + return ret; +} + +/** + * ov9282_set_ctrl() - Set subdevice control + * @ctrl: pointer to v4l2_ctrl structure + * + * Supported controls: + * - V4L2_CID_VBLANK + * - cluster controls: + * - V4L2_CID_ANALOGUE_GAIN + * - V4L2_CID_EXPOSURE + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov9282 *ov9282 = + container_of(ctrl->handler, struct ov9282, ctrl_handler); + u32 analog_gain; + u32 exposure; + int ret; + + switch (ctrl->id) { + case V4L2_CID_VBLANK: + ov9282->vblank = ov9282->vblank_ctrl->val; + + dev_dbg(ov9282->dev, "Received vblank %u, new lpfr %u", + ov9282->vblank, + ov9282->vblank + ov9282->cur_mode->height); + + ret = __v4l2_ctrl_modify_range(ov9282->exp_ctrl, + OV9282_EXPOSURE_MIN, + ov9282->vblank + + ov9282->cur_mode->height - + OV9282_EXPOSURE_OFFSET, + 1, OV9282_EXPOSURE_DEFAULT); + break; + case V4L2_CID_EXPOSURE: + /* Set controls only if sensor is in power on state */ + if (!pm_runtime_get_if_in_use(ov9282->dev)) + return 0; + + exposure = ctrl->val; + analog_gain = ov9282->again_ctrl->val; + + dev_dbg(ov9282->dev, "Received exp %u, analog gain %u", + exposure, analog_gain); + + ret = ov9282_update_exp_gain(ov9282, exposure, analog_gain); + + pm_runtime_put(ov9282->dev); + + break; + default: + dev_err(ov9282->dev, "Invalid control %d", ctrl->id); + ret = -EINVAL; + } + + return ret; +} + +/* V4l2 subdevice control ops*/ +static const struct v4l2_ctrl_ops ov9282_ctrl_ops = { + .s_ctrl = ov9282_set_ctrl, +}; + +/** + * ov9282_enum_mbus_code() - Enumerate V4L2 sub-device mbus codes + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @code: V4L2 sub-device code enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = supported_mode.code; + + return 0; +} + +/** + * ov9282_enum_frame_size() - Enumerate V4L2 sub-device frame sizes + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fsize: V4L2 sub-device size enumeration need to be filled + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fsize) +{ + if (fsize->index > 0) + return -EINVAL; + + if (fsize->code != supported_mode.code) + return -EINVAL; + + fsize->min_width = supported_mode.width; + fsize->max_width = fsize->min_width; + fsize->min_height = supported_mode.height; + fsize->max_height = fsize->min_height; + + return 0; +} + +/** + * ov9282_fill_pad_format() - Fill subdevice pad format + * from selected sensor mode + * @ov9282: pointer to ov9282 device + * @mode: pointer to ov9282_mode sensor mode + * @fmt: V4L2 sub-device format need to be filled + */ +static void ov9282_fill_pad_format(struct ov9282 *ov9282, + const struct ov9282_mode *mode, + struct v4l2_subdev_format *fmt) +{ + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.code = mode->code; + fmt->format.field = V4L2_FIELD_NONE; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->format.quantization = V4L2_QUANTIZATION_DEFAULT; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; +} + +/** + * ov9282_get_pad_format() - Get subdevice pad format + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct ov9282 *ov9282 = to_ov9282(sd); + + mutex_lock(&ov9282->mutex); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + fmt->format = *framefmt; + } else { + ov9282_fill_pad_format(ov9282, ov9282->cur_mode, fmt); + } + + mutex_unlock(&ov9282->mutex); + + return 0; +} + +/** + * ov9282_set_pad_format() - Set subdevice pad format + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * @fmt: V4L2 sub-device format need to be set + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct ov9282 *ov9282 = to_ov9282(sd); + const struct ov9282_mode *mode; + int ret = 0; + + mutex_lock(&ov9282->mutex); + + mode = &supported_mode; + ov9282_fill_pad_format(ov9282, mode, fmt); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *framefmt; + + framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + *framefmt = fmt->format; + } else { + ret = ov9282_update_controls(ov9282, mode); + if (!ret) + ov9282->cur_mode = mode; + } + + mutex_unlock(&ov9282->mutex); + + return ret; +} + +/** + * ov9282_init_pad_cfg() - Initialize sub-device pad configuration + * @sd: pointer to ov9282 V4L2 sub-device structure + * @sd_state: V4L2 sub-device configuration + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_init_pad_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct ov9282 *ov9282 = to_ov9282(sd); + struct v4l2_subdev_format fmt = { 0 }; + + fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + ov9282_fill_pad_format(ov9282, &supported_mode, &fmt); + + return ov9282_set_pad_format(sd, sd_state, &fmt); +} + +/** + * ov9282_start_streaming() - Start sensor stream + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_start_streaming(struct ov9282 *ov9282) +{ + const struct ov9282_reg_list *reg_list; + int ret; + + /* Write sensor mode registers */ + reg_list = &ov9282->cur_mode->reg_list; + ret = ov9282_write_regs(ov9282, reg_list->regs, reg_list->num_of_regs); + if (ret) { + dev_err(ov9282->dev, "fail to write initial registers"); + return ret; + } + + /* Setup handler will write actual exposure and gain */ + ret = __v4l2_ctrl_handler_setup(ov9282->sd.ctrl_handler); + if (ret) { + dev_err(ov9282->dev, "fail to setup handler"); + return ret; + } + + /* Start streaming */ + ret = ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT, + 1, OV9282_MODE_STREAMING); + if (ret) { + dev_err(ov9282->dev, "fail to start streaming"); + return ret; + } + + return 0; +} + +/** + * ov9282_stop_streaming() - Stop sensor stream + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_stop_streaming(struct ov9282 *ov9282) +{ + return ov9282_write_reg(ov9282, OV9282_REG_MODE_SELECT, + 1, OV9282_MODE_STANDBY); +} + +/** + * ov9282_set_stream() - Enable sensor streaming + * @sd: pointer to ov9282 subdevice + * @enable: set to enable sensor streaming + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov9282 *ov9282 = to_ov9282(sd); + int ret; + + mutex_lock(&ov9282->mutex); + + if (ov9282->streaming == enable) { + mutex_unlock(&ov9282->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(ov9282->dev); + if (ret) + goto error_unlock; + + ret = ov9282_start_streaming(ov9282); + if (ret) + goto error_power_off; + } else { + ov9282_stop_streaming(ov9282); + pm_runtime_put(ov9282->dev); + } + + ov9282->streaming = enable; + + mutex_unlock(&ov9282->mutex); + + return 0; + +error_power_off: + pm_runtime_put(ov9282->dev); +error_unlock: + mutex_unlock(&ov9282->mutex); + + return ret; +} + +/** + * ov9282_detect() - Detect ov9282 sensor + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, -EIO if sensor id does not match + */ +static int ov9282_detect(struct ov9282 *ov9282) +{ + int ret; + u32 val; + + ret = ov9282_read_reg(ov9282, OV9282_REG_ID, 2, &val); + if (ret) + return ret; + + if (val != OV9282_ID) { + dev_err(ov9282->dev, "chip id mismatch: %x!=%x", + OV9282_ID, val); + return -ENXIO; + } + + return 0; +} + +/** + * ov9282_parse_hw_config() - Parse HW configuration and check if supported + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_parse_hw_config(struct ov9282 *ov9282) +{ + struct fwnode_handle *fwnode = dev_fwnode(ov9282->dev); + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY + }; + struct fwnode_handle *ep; + unsigned long rate; + unsigned int i; + int ret; + + if (!fwnode) + return -ENXIO; + + /* Request optional reset pin */ + ov9282->reset_gpio = devm_gpiod_get_optional(ov9282->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ov9282->reset_gpio)) { + dev_err(ov9282->dev, "failed to get reset gpio %ld", + PTR_ERR(ov9282->reset_gpio)); + return PTR_ERR(ov9282->reset_gpio); + } + + /* Get sensor input clock */ + ov9282->inclk = devm_clk_get(ov9282->dev, NULL); + if (IS_ERR(ov9282->inclk)) { + dev_err(ov9282->dev, "could not get inclk"); + return PTR_ERR(ov9282->inclk); + } + + rate = clk_get_rate(ov9282->inclk); + if (rate != OV9282_INCLK_RATE) { + dev_err(ov9282->dev, "inclk frequency mismatch"); + return -EINVAL; + } + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -ENXIO; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV9282_NUM_DATA_LANES) { + dev_err(ov9282->dev, + "number of CSI2 data lanes %d is not supported", + bus_cfg.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto done_endpoint_free; + } + + if (!bus_cfg.nr_of_link_frequencies) { + dev_err(ov9282->dev, "no link frequencies defined"); + ret = -EINVAL; + goto done_endpoint_free; + } + + for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) + if (bus_cfg.link_frequencies[i] == OV9282_LINK_FREQ) + goto done_endpoint_free; + + ret = -EINVAL; + +done_endpoint_free: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +/* V4l2 subdevice ops */ +static const struct v4l2_subdev_video_ops ov9282_video_ops = { + .s_stream = ov9282_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ov9282_pad_ops = { + .init_cfg = ov9282_init_pad_cfg, + .enum_mbus_code = ov9282_enum_mbus_code, + .enum_frame_size = ov9282_enum_frame_size, + .get_fmt = ov9282_get_pad_format, + .set_fmt = ov9282_set_pad_format, +}; + +static const struct v4l2_subdev_ops ov9282_subdev_ops = { + .video = &ov9282_video_ops, + .pad = &ov9282_pad_ops, +}; + +/** + * ov9282_power_on() - Sensor power on sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov9282 *ov9282 = to_ov9282(sd); + int ret; + + usleep_range(400, 600); + + gpiod_set_value_cansleep(ov9282->reset_gpio, 1); + + ret = clk_prepare_enable(ov9282->inclk); + if (ret) { + dev_err(ov9282->dev, "fail to enable inclk"); + goto error_reset; + } + + usleep_range(400, 600); + + return 0; + +error_reset: + gpiod_set_value_cansleep(ov9282->reset_gpio, 0); + + return ret; +} + +/** + * ov9282_power_off() - Sensor power off sequence + * @dev: pointer to i2c device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov9282 *ov9282 = to_ov9282(sd); + + gpiod_set_value_cansleep(ov9282->reset_gpio, 0); + + clk_disable_unprepare(ov9282->inclk); + + return 0; +} + +/** + * ov9282_init_controls() - Initialize sensor subdevice controls + * @ov9282: pointer to ov9282 device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_init_controls(struct ov9282 *ov9282) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &ov9282->ctrl_handler; + const struct ov9282_mode *mode = ov9282->cur_mode; + u32 lpfr; + int ret; + + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 6); + if (ret) + return ret; + + /* Serialize controls with sensor device */ + ctrl_hdlr->lock = &ov9282->mutex; + + /* Initialize exposure and gain */ + lpfr = mode->vblank + mode->height; + ov9282->exp_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_EXPOSURE, + OV9282_EXPOSURE_MIN, + lpfr - OV9282_EXPOSURE_OFFSET, + OV9282_EXPOSURE_STEP, + OV9282_EXPOSURE_DEFAULT); + + ov9282->again_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, + OV9282_AGAIN_MIN, + OV9282_AGAIN_MAX, + OV9282_AGAIN_STEP, + OV9282_AGAIN_DEFAULT); + + v4l2_ctrl_cluster(2, &ov9282->exp_ctrl); + + ov9282->vblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_VBLANK, + mode->vblank_min, + mode->vblank_max, + 1, mode->vblank); + + /* Read only controls */ + ov9282->pclk_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_PIXEL_RATE, + mode->pclk, mode->pclk, + 1, mode->pclk); + + ov9282->link_freq_ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(link_freq) - + 1, + mode->link_freq_idx, + link_freq); + if (ov9282->link_freq_ctrl) + ov9282->link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ov9282->hblank_ctrl = v4l2_ctrl_new_std(ctrl_hdlr, + &ov9282_ctrl_ops, + V4L2_CID_HBLANK, + OV9282_REG_MIN, + OV9282_REG_MAX, + 1, mode->hblank); + if (ov9282->hblank_ctrl) + ov9282->hblank_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + if (ctrl_hdlr->error) { + dev_err(ov9282->dev, "control init failed: %d", + ctrl_hdlr->error); + v4l2_ctrl_handler_free(ctrl_hdlr); + return ctrl_hdlr->error; + } + + ov9282->sd.ctrl_handler = ctrl_hdlr; + + return 0; +} + +/** + * ov9282_probe() - I2C client device binding + * @client: pointer to i2c client device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_probe(struct i2c_client *client) +{ + struct ov9282 *ov9282; + int ret; + + ov9282 = devm_kzalloc(&client->dev, sizeof(*ov9282), GFP_KERNEL); + if (!ov9282) + return -ENOMEM; + + ov9282->dev = &client->dev; + + /* Initialize subdev */ + v4l2_i2c_subdev_init(&ov9282->sd, client, &ov9282_subdev_ops); + + ret = ov9282_parse_hw_config(ov9282); + if (ret) { + dev_err(ov9282->dev, "HW configuration is not supported"); + return ret; + } + + mutex_init(&ov9282->mutex); + + ret = ov9282_power_on(ov9282->dev); + if (ret) { + dev_err(ov9282->dev, "failed to power-on the sensor"); + goto error_mutex_destroy; + } + + /* Check module identity */ + ret = ov9282_detect(ov9282); + if (ret) { + dev_err(ov9282->dev, "failed to find sensor: %d", ret); + goto error_power_off; + } + + /* Set default mode to max resolution */ + ov9282->cur_mode = &supported_mode; + ov9282->vblank = ov9282->cur_mode->vblank; + + ret = ov9282_init_controls(ov9282); + if (ret) { + dev_err(ov9282->dev, "failed to init controls: %d", ret); + goto error_power_off; + } + + /* Initialize subdev */ + ov9282->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov9282->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* Initialize source pad */ + ov9282->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&ov9282->sd.entity, 1, &ov9282->pad); + if (ret) { + dev_err(ov9282->dev, "failed to init entity pads: %d", ret); + goto error_handler_free; + } + + ret = v4l2_async_register_subdev_sensor(&ov9282->sd); + if (ret < 0) { + dev_err(ov9282->dev, + "failed to register async subdev: %d", ret); + goto error_media_entity; + } + + pm_runtime_set_active(ov9282->dev); + pm_runtime_enable(ov9282->dev); + pm_runtime_idle(ov9282->dev); + + return 0; + +error_media_entity: + media_entity_cleanup(&ov9282->sd.entity); +error_handler_free: + v4l2_ctrl_handler_free(ov9282->sd.ctrl_handler); +error_power_off: + ov9282_power_off(ov9282->dev); +error_mutex_destroy: + mutex_destroy(&ov9282->mutex); + + return ret; +} + +/** + * ov9282_remove() - I2C client device unbinding + * @client: pointer to I2C client device + * + * Return: 0 if successful, error code otherwise. + */ +static int ov9282_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov9282 *ov9282 = to_ov9282(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + ov9282_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + + mutex_destroy(&ov9282->mutex); + + return 0; +} + +static const struct dev_pm_ops ov9282_pm_ops = { + SET_RUNTIME_PM_OPS(ov9282_power_off, ov9282_power_on, NULL) +}; + +static const struct of_device_id ov9282_of_match[] = { + { .compatible = "ovti,ov9282" }, + { } +}; + +MODULE_DEVICE_TABLE(of, ov9282_of_match); + +static struct i2c_driver ov9282_driver = { + .probe_new = ov9282_probe, + .remove = ov9282_remove, + .driver = { + .name = "ov9282", + .pm = &ov9282_pm_ops, + .of_match_table = ov9282_of_match, + }, +}; + +module_i2c_driver(ov9282_driver); + +MODULE_DESCRIPTION("OmniVision ov9282 sensor driver"); +MODULE_LICENSE("GPL"); From 1536fbdbcb7f6bf0442c5158fbda9c73cf706f74 Mon Sep 17 00:00:00 2001 From: Xavier Roumegue Date: Fri, 18 Jun 2021 09:59:33 +0200 Subject: [PATCH 156/195] media: ov5640: Complement yuv mbus formats with their 1X16 versions According to media bus pixel codes definition, data formats on serial busses should be described with one bus sample per pixel. Documentation/userspace-api/media/v4l/subdev-formats.rst states: "The media bus pixel codes document parallel formats. Should the pixel data be transported over a serial bus, the media bus pixel code that describes a parallel format that transfers a sample on a single clock cycle is used. For instance, both MEDIA_BUS_FMT_BGR888_1X24 and MEDIA_BUS_FMT_BGR888_3X8 are used on parallel busses for transferring an 8 bits per sample BGR data, whereas on serial busses the data in this format is only referred to using MEDIA_BUS_FMT_BGR888_1X24. This is because there is effectively only a single way to transport that format on the serial busses." Some MIPI CSI receivers strictly obey this definition and declare support for only *1X_* formats. Hence, complement the supported media bus formats with their 1X16 versions (currently applicable to yuyv, uyvy) to enhance interoperability with CSI receivers. Signed-off-by: Xavier Roumegue Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index f6e1e51e0375f..ddbd71394db33 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -135,7 +135,9 @@ struct ov5640_pixfmt { static const struct ov5640_pixfmt ov5640_formats[] = { { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, }, { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, }, { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, }, @@ -2338,11 +2340,13 @@ static int ov5640_set_framefmt(struct ov5640_dev *sensor, u8 fmt, mux; switch (format->code) { + case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_UYVY8_2X8: /* YUV422, UYVY */ fmt = 0x3f; mux = OV5640_FMT_MUX_YUV422; break; + case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_YUYV8_2X8: /* YUV422, YUYV */ fmt = 0x30; From 7b537f290a9a9039d10d8f6da45e21018cc18cb2 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Thu, 3 Jun 2021 09:12:49 +0200 Subject: [PATCH 157/195] media: mc-device.c: use DEVICE_ATTR_RO() helper macro Use DEVICE_ATTR_RO() helper macro instead of DEVICE_ATTR(), which is simpler and more readable. Due to the name of the read function of the sysfs attribute is normalized, there is a natural association. Signed-off-by: Zhen Lei Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/mc/mc-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index 9e56d2ad6b94b..cf5e459b1d962 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -556,7 +556,7 @@ static const struct media_file_operations media_device_fops = { * sysfs */ -static ssize_t show_model(struct device *cd, +static ssize_t model_show(struct device *cd, struct device_attribute *attr, char *buf) { struct media_devnode *devnode = to_media_devnode(cd); @@ -565,7 +565,7 @@ static ssize_t show_model(struct device *cd, return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); } -static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); +static DEVICE_ATTR_RO(model); /* ----------------------------------------------------------------------------- * Registration/unregistration From 5fca4169f5bd8dce5f49123196fb97db52d25a99 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Thu, 3 Jun 2021 09:15:29 +0200 Subject: [PATCH 158/195] media: i2c: et8ek8: use DEVICE_ATTR_RO() helper macro Use DEVICE_ATTR_RO() helper macro instead of DEVICE_ATTR(), which is simpler and more readable. Due to the name of the read function of the sysfs attribute is normalized, there is a natural association. Signed-off-by: Zhen Lei Acked-by: Pavel Machek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/et8ek8/et8ek8_driver.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index c7b91c0c03b5a..873d614339bbb 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -1237,8 +1237,7 @@ static int et8ek8_dev_init(struct v4l2_subdev *subdev) * sysfs attributes */ static ssize_t -et8ek8_priv_mem_read(struct device *dev, struct device_attribute *attr, - char *buf) +priv_mem_show(struct device *dev, struct device_attribute *attr, char *buf) { struct v4l2_subdev *subdev = dev_get_drvdata(dev); struct et8ek8_sensor *sensor = to_et8ek8_sensor(subdev); @@ -1251,7 +1250,7 @@ et8ek8_priv_mem_read(struct device *dev, struct device_attribute *attr, return ET8EK8_PRIV_MEM_SIZE; } -static DEVICE_ATTR(priv_mem, 0444, et8ek8_priv_mem_read, NULL); +static DEVICE_ATTR_RO(priv_mem); /* -------------------------------------------------------------------------- * V4L2 subdev core operations From 9256de06942c703e22d61ad73458b52263857157 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Thu, 3 Jun 2021 09:17:50 +0200 Subject: [PATCH 159/195] media: i2c: use DEVICE_ATTR_RO() helper macro Use DEVICE_ATTR_RO() helper macro instead of DEVICE_ATTR(), which is simpler and more readable. Due to the name of the read function of the sysfs attribute is normalized, there is a natural association. Signed-off-by: Zhen Lei Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index a9403a227c6b3..121cbe406fe4b 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -2673,8 +2673,7 @@ static int ccs_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines) */ static ssize_t -ccs_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, - char *buf) +nvm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); struct i2c_client *client = v4l2_get_subdevdata(subdev); @@ -2704,11 +2703,10 @@ ccs_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, */ return rval; } -static DEVICE_ATTR(nvm, S_IRUGO, ccs_sysfs_nvm_read, NULL); +static DEVICE_ATTR_RO(nvm); static ssize_t -ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr, - char *buf) +ident_show(struct device *dev, struct device_attribute *attr, char *buf) { struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); struct ccs_sensor *sensor = to_ccs_sensor(subdev); @@ -2723,8 +2721,7 @@ ccs_sysfs_ident_read(struct device *dev, struct device_attribute *attr, minfo->smia_manufacturer_id, minfo->model_id, minfo->revision_number) + 1; } - -static DEVICE_ATTR(ident, S_IRUGO, ccs_sysfs_ident_read, NULL); +static DEVICE_ATTR_RO(ident); /* ----------------------------------------------------------------------------- * V4L2 subdev core operations From e006558fa4737d6d123ec2c1a0f1a8a42f2199b3 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Thu, 3 Jun 2021 09:06:13 +0200 Subject: [PATCH 160/195] media: exynos4-is: use DEVICE_ATTR_RW() helper macro Use DEVICE_ATTR_RW() helper macro instead of DEVICE_ATTR(), which is simpler and more readable. Due to the names of the read and write functions of the sysfs attribute is normalized, there is a natural association. Signed-off-by: Zhen Lei Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 3b8a24bb724c8..fa648721eaab9 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -1238,8 +1238,8 @@ static const struct media_device_ops fimc_md_ops = { .link_notify = fimc_md_link_notify, }; -static ssize_t fimc_md_sysfs_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t subdev_conf_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct fimc_md *fmd = dev_get_drvdata(dev); @@ -1249,9 +1249,9 @@ static ssize_t fimc_md_sysfs_show(struct device *dev, return strscpy(buf, "V4L2 video node only API (vid-dev)\n", PAGE_SIZE); } -static ssize_t fimc_md_sysfs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t subdev_conf_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct fimc_md *fmd = dev_get_drvdata(dev); bool subdev_api; @@ -1278,8 +1278,7 @@ static ssize_t fimc_md_sysfs_store(struct device *dev, * sub-dev - for media controller API, subdevs must be configured in user * space before starting streaming. */ -static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO, - fimc_md_sysfs_show, fimc_md_sysfs_store); +static DEVICE_ATTR_RW(subdev_conf_mode); static int cam_clk_prepare(struct clk_hw *hw) { From 0368e7d2cd84a90d0518753fac33795e13df553f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 7 Apr 2021 16:37:33 +0200 Subject: [PATCH 161/195] media: omap3isp: Fix missing unlock in isp_subdev_notifier_complete() Add the missing unlock before return from function isp_subdev_notifier_complete() in the init error handling case. Fixes: ba689d933361 ("media: omap3isp: Acquire graph mutex for graph traversal") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 53025c8c75312..20f59c59ff8a2 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2037,8 +2037,10 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) mutex_lock(&isp->media_dev.graph_mutex); ret = media_entity_enum_init(&isp->crashed, &isp->media_dev); - if (ret) + if (ret) { + mutex_unlock(&isp->media_dev.graph_mutex); return ret; + } list_for_each_entry(sd, &v4l2_dev->subdevs, list) { if (sd->notifier != &isp->notifier) From b9a543364299e09ba236c69acb021ebbf7cebf1a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 1 Feb 2021 10:16:03 +0100 Subject: [PATCH 162/195] media: Documentation: media: Improve camera sensor documentation Modernise the documentation to make it more precise and update the use of pixel rate control and various other changes. In particular: - Use non-proportional font for file names, properties as well as controls. - The unit of the HBLANK control is pixels, not lines. - The unit of PIXEL_RATE control is pixels per second, not Hz. - Merge common requirements for CSI-2 and parallel busses. - Include all DT properties needed for assigned clocks. - Fix referencing the link rate control. - SMIA driver's new name is CCS driver. - The PIXEL_RATE control denotes pixel rate on the pixel array on camera sensors. Do not suggest it is used to tell the maximum pixel rate on the bus anymore. - Improve ReST syntax (plain struct and function names). - Remove the suggestion to use s_power() in receiver drivers. - Make MIPI website URL use HTTPS, add Wikipedia links to BT.601 and BT.656. Fixes: e4cf8c58af75 ("media: Documentation: media: Document how to write camera sensor drivers") Signed-off-by: Sakari Ailus Reviewed-by: Jacopo Mondi Reviewed-by: Andrey Konovalov Signed-off-by: Mauro Carvalho Chehab --- .../driver-api/media/camera-sensor.rst | 45 +++---- Documentation/driver-api/media/csi2.rst | 94 -------------- Documentation/driver-api/media/index.rst | 2 +- Documentation/driver-api/media/tx-rx.rst | 117 ++++++++++++++++++ .../media/v4l/ext-ctrls-image-process.rst | 2 + 5 files changed, 137 insertions(+), 123 deletions(-) delete mode 100644 Documentation/driver-api/media/csi2.rst create mode 100644 Documentation/driver-api/media/tx-rx.rst diff --git a/Documentation/driver-api/media/camera-sensor.rst b/Documentation/driver-api/media/camera-sensor.rst index 7160336aa4753..c7d4891bd24e7 100644 --- a/Documentation/driver-api/media/camera-sensor.rst +++ b/Documentation/driver-api/media/camera-sensor.rst @@ -3,10 +3,10 @@ Writing camera sensor drivers ============================= -CSI-2 ------ +CSI-2 and parallel (BT.601 and BT.656) busses +--------------------------------------------- -Please see what is written on :ref:`MIPI_CSI_2`. +Please see :ref:`transmitter-receiver`. Handling clocks --------------- @@ -26,15 +26,16 @@ user. ACPI ~~~~ -Read the "clock-frequency" _DSD property to denote the frequency. The driver can -rely on this frequency being used. +Read the ``clock-frequency`` _DSD property to denote the frequency. The driver +can rely on this frequency being used. Devicetree ~~~~~~~~~~ -The currently preferred way to achieve this is using "assigned-clock-rates" -property. See Documentation/devicetree/bindings/clock/clock-bindings.txt for -more information. The driver then gets the frequency using clk_get_rate(). +The currently preferred way to achieve this is using ``assigned-clocks``, +``assigned-clock-parents`` and ``assigned-clock-rates`` properties. See +``Documentation/devicetree/bindings/clock/clock-bindings.txt`` for more +information. The driver then gets the frequency using ``clk_get_rate()``. This approach has the drawback that there's no guarantee that the frequency hasn't been modified directly or indirectly by another driver, or supported by @@ -55,7 +56,7 @@ processing pipeline as one or more sub-devices with different cropping and scaling configurations. The output size of the device is the result of a series of cropping and scaling operations from the device's pixel array's size. -An example of such a driver is the smiapp driver (see drivers/media/i2c/smiapp). +An example of such a driver is the CCS driver (see ``drivers/media/i2c/ccs``). Register list based drivers ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -67,7 +68,7 @@ level are independent. How a driver picks such configuration is based on the format set on a source pad at the end of the device's internal pipeline. Most sensor drivers are implemented this way, see e.g. -drivers/media/i2c/imx319.c for an example. +``drivers/media/i2c/imx319.c`` for an example. Frame interval configuration ---------------------------- @@ -94,9 +95,10 @@ large variety of devices beyond camera sensors. Devices that have no analogue crop, use the full source image size, i.e. pixel array size. Horizontal and vertical blanking are specified by ``V4L2_CID_HBLANK`` and -``V4L2_CID_VBLANK``, respectively. The unit of these controls are lines. The -pixel rate is specified by ``V4L2_CID_PIXEL_RATE`` in the same sub-device. The -unit of that control is Hz. +``V4L2_CID_VBLANK``, respectively. The unit of the ``V4L2_CID_HBLANK`` control +is pixels and the unit of the ``V4L2_CID_VBLANK`` is lines. The pixel rate in +the sensor's **pixel array** is specified by ``V4L2_CID_PIXEL_RATE`` in the same +sub-device. The unit of that control is pixels per second. Register list based drivers need to implement read-only sub-device nodes for the purpose. Devices that are not register list based need these to configure the @@ -125,14 +127,14 @@ general, the device must be powered on at least when its registers are being accessed and when it is streaming. Existing camera sensor drivers may rely on the old -:c:type:`v4l2_subdev_core_ops`->s_power() callback for bridge or ISP drivers to +struct v4l2_subdev_core_ops->s_power() callback for bridge or ISP drivers to manage their power state. This is however **deprecated**. If you feel you need to begin calling an s_power from an ISP or a bridge driver, instead please add runtime PM support to the sensor driver you are using. Likewise, new drivers should not use s_power. Please see examples in e.g. ``drivers/media/i2c/ov8856.c`` and -``drivers/media/i2c/smiapp/smiapp-core.c``. The two drivers work in both ACPI +``drivers/media/i2c/ccs/ccs-core.c``. The two drivers work in both ACPI and DT based systems. Control framework @@ -149,16 +151,3 @@ used to obtain device's power state after the power state transition: The function returns a non-zero value if it succeeded getting the power count or runtime PM was disabled, in either of which cases the driver may proceed to access the device. - -Controls --------- - -For camera sensors that are connected to a bus where transmitter and receiver -require common configuration set by drivers, such as CSI-2 or parallel (BT.601 -or BT.656) bus, the ``V4L2_CID_LINK_FREQ`` control is mandatory on transmitter -drivers. Receiver drivers can use the ``V4L2_CID_LINK_FREQ`` to query the -frequency used on the bus. - -The transmitter drivers should also implement ``V4L2_CID_PIXEL_RATE`` control in -order to tell the maximum pixel rate to the receiver. This is required on raw -camera sensors. diff --git a/Documentation/driver-api/media/csi2.rst b/Documentation/driver-api/media/csi2.rst deleted file mode 100644 index 11c52b0be8b87..0000000000000 --- a/Documentation/driver-api/media/csi2.rst +++ /dev/null @@ -1,94 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -.. _MIPI_CSI_2: - -MIPI CSI-2 -========== - -CSI-2 is a data bus intended for transferring images from cameras to -the host SoC. It is defined by the `MIPI alliance`_. - -.. _`MIPI alliance`: http://www.mipi.org/ - -Media bus formats ------------------ - -See :ref:`v4l2-mbus-pixelcode` for details on which media bus formats should -be used for CSI-2 interfaces. - -Transmitter drivers -------------------- - -CSI-2 transmitter, such as a sensor or a TV tuner, drivers need to -provide the CSI-2 receiver with information on the CSI-2 bus -configuration. These include the V4L2_CID_LINK_FREQ and -V4L2_CID_PIXEL_RATE controls and -(:c:type:`v4l2_subdev_video_ops`->s_stream() callback). These -interface elements must be present on the sub-device represents the -CSI-2 transmitter. - -The V4L2_CID_LINK_FREQ control is used to tell the receiver driver the -frequency (and not the symbol rate) of the link. The V4L2_CID_PIXEL_RATE -control may be used by the receiver to obtain the pixel rate the transmitter -uses. The :c:type:`v4l2_subdev_video_ops`->s_stream() callback provides an -ability to start and stop the stream. - -The value of the V4L2_CID_PIXEL_RATE is calculated as follows:: - - pixel_rate = link_freq * 2 * nr_of_lanes * 16 / k / bits_per_sample - -where - -.. list-table:: variables in pixel rate calculation - :header-rows: 1 - - * - variable or constant - - description - * - link_freq - - The value of the V4L2_CID_LINK_FREQ integer64 menu item. - * - nr_of_lanes - - Number of data lanes used on the CSI-2 link. This can - be obtained from the OF endpoint configuration. - * - 2 - - Two bits are transferred per clock cycle per lane. - * - bits_per_sample - - Number of bits per sample. - * - k - - 16 for D-PHY and 7 for C-PHY - -The transmitter drivers must, if possible, configure the CSI-2 -transmitter to *LP-11 mode* whenever the transmitter is powered on but -not active, and maintain *LP-11 mode* until stream on. Only at stream -on should the transmitter activate the clock on the clock lane and -transition to *HS mode*. - -Some transmitters do this automatically but some have to be explicitly -programmed to do so, and some are unable to do so altogether due to -hardware constraints. - -Stopping the transmitter -^^^^^^^^^^^^^^^^^^^^^^^^ - -A transmitter stops sending the stream of images as a result of -calling the ``.s_stream()`` callback. Some transmitters may stop the -stream at a frame boundary whereas others stop immediately, -effectively leaving the current frame unfinished. The receiver driver -should not make assumptions either way, but function properly in both -cases. - -Receiver drivers ----------------- - -Before the receiver driver may enable the CSI-2 transmitter by using -the :c:type:`v4l2_subdev_video_ops`->s_stream(), it must have powered -the transmitter up by using the -:c:type:`v4l2_subdev_core_ops`->s_power() callback. This may take -place either indirectly by using :c:func:`v4l2_pipeline_pm_get` or -directly. - -Formats -------- - -The media bus pixel codes document parallel formats. Should the pixel data be -transported over a serial bus, the media bus pixel code that describes a -parallel format that transfers a sample on a single clock cycle is used. diff --git a/Documentation/driver-api/media/index.rst b/Documentation/driver-api/media/index.rst index 813d7db59da71..08e206567408c 100644 --- a/Documentation/driver-api/media/index.rst +++ b/Documentation/driver-api/media/index.rst @@ -37,7 +37,7 @@ Documentation/userspace-api/media/index.rst rc-core mc-core cec-core - csi2 + tx-rx camera-sensor drivers/index diff --git a/Documentation/driver-api/media/tx-rx.rst b/Documentation/driver-api/media/tx-rx.rst new file mode 100644 index 0000000000000..4c8584e7b6f21 --- /dev/null +++ b/Documentation/driver-api/media/tx-rx.rst @@ -0,0 +1,117 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. _transmitter-receiver: + +Pixel data transmitter and receiver drivers +=========================================== + +V4L2 supports various devices that transmit and receiver pixel data. Examples of +these devices include a camera sensor, a TV tuner and a parallel or a CSI-2 +receiver in an SoC. + +Bus types +--------- + +The following busses are the most common. This section discusses these two only. + +MIPI CSI-2 +^^^^^^^^^^ + +CSI-2 is a data bus intended for transferring images from cameras to +the host SoC. It is defined by the `MIPI alliance`_. + +.. _`MIPI alliance`: https://www.mipi.org/ + +Parallel +^^^^^^^^ + +`BT.601`_ and `BT.656`_ are the most common parallel busses. + +.. _`BT.601`: https://en.wikipedia.org/wiki/Rec._601 +.. _`BT.656`: https://en.wikipedia.org/wiki/ITU-R_BT.656 + +Transmitter drivers +------------------- + +Transmitter drivers generally need to provide the receiver drivers with the +configuration of the transmitter. What is required depends on the type of the +bus. These are common for both busses. + +Media bus pixel code +^^^^^^^^^^^^^^^^^^^^ + +See :ref:`v4l2-mbus-pixelcode`. + +Link frequency +^^^^^^^^^^^^^^ + +The :ref:`V4L2_CID_LINK_FREQ ` control is used to tell the +receiver the frequency of the bus (i.e. it is not the same as the symbol rate). + +``.s_stream()`` callback +^^^^^^^^^^^^^^^^^^^^^^^^ + +The struct struct v4l2_subdev_video_ops->s_stream() callback is used by the +receiver driver to control the transmitter driver's streaming state. + + +CSI-2 transmitter drivers +------------------------- + +Pixel rate +^^^^^^^^^^ + +The pixel rate on the bus is calculated as follows:: + + pixel_rate = link_freq * 2 * nr_of_lanes * 16 / k / bits_per_sample + +where + +.. list-table:: variables in pixel rate calculation + :header-rows: 1 + + * - variable or constant + - description + * - link_freq + - The value of the ``V4L2_CID_LINK_FREQ`` integer64 menu item. + * - nr_of_lanes + - Number of data lanes used on the CSI-2 link. This can + be obtained from the OF endpoint configuration. + * - 2 + - Data is transferred on both rising and falling edge of the signal. + * - bits_per_sample + - Number of bits per sample. + * - k + - 16 for D-PHY and 7 for C-PHY + +.. note:: + + The pixel rate calculated this way is **not** the same thing as the + pixel rate on the camera sensor's pixel array which is indicated by the + :ref:`V4L2_CID_PIXEL_RATE ` control. + +LP-11 and LP-111 modes +^^^^^^^^^^^^^^^^^^^^^^ + +The transmitter drivers must, if possible, configure the CSI-2 transmitter to +*LP-11 or LP-111 mode* whenever the transmitter is powered on but not active, +and maintain *LP-11 or LP-111 mode* until stream on. Only at stream on should +the transmitter activate the clock on the clock lane and transition to *HS +mode*. + +Some transmitters do this automatically but some have to be explicitly +programmed to do so, and some are unable to do so altogether due to +hardware constraints. + +The receiver thus need to be configured to expect LP-11 or LP-111 mode from the +transmitter before the transmitter driver's ``.s_stream()`` op is called. + +Stopping the transmitter +^^^^^^^^^^^^^^^^^^^^^^^^ + +A transmitter stops sending the stream of images as a result of +calling the ``.s_stream()`` callback. Some transmitters may stop the +stream at a frame boundary whereas others stop immediately, +effectively leaving the current frame unfinished. The receiver driver +should not make assumptions either way, but function properly in both +cases. diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst index 87698c15c0276..37dad2f4df8cf 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst @@ -20,6 +20,8 @@ Image Process Control IDs ``V4L2_CID_IMAGE_PROC_CLASS (class)`` The IMAGE_PROC class descriptor. +.. _v4l2-cid-link-freq: + ``V4L2_CID_LINK_FREQ (integer menu)`` Data bus frequency. Together with the media bus pixel code, bus type (clock cycles per sample), the data bus frequency defines the pixel From 6f8f9fdec8e4615a2cf539bbcad400d4b3a39070 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 8 Feb 2021 11:33:14 +0100 Subject: [PATCH 163/195] media: Documentation: media: Fix v4l2-async kerneldoc syntax Fix kerneldoc syntax in v4l2-async. The references were not produced correctly. Signed-off-by: Sakari Ailus Reviewed-by: Jacopo Mondi Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/tx-rx.rst | 8 ++--- .../media/v4l/ext-ctrls-image-process.rst | 2 ++ include/media/v4l2-async.h | 30 +++++++++---------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/Documentation/driver-api/media/tx-rx.rst b/Documentation/driver-api/media/tx-rx.rst index 4c8584e7b6f21..12d492d25df29 100644 --- a/Documentation/driver-api/media/tx-rx.rst +++ b/Documentation/driver-api/media/tx-rx.rst @@ -5,7 +5,7 @@ Pixel data transmitter and receiver drivers =========================================== -V4L2 supports various devices that transmit and receiver pixel data. Examples of +V4L2 supports various devices that transmit and receive pixel data. Examples of these devices include a camera sensor, a TV tuner and a parallel or a CSI-2 receiver in an SoC. @@ -95,9 +95,9 @@ LP-11 and LP-111 modes The transmitter drivers must, if possible, configure the CSI-2 transmitter to *LP-11 or LP-111 mode* whenever the transmitter is powered on but not active, -and maintain *LP-11 or LP-111 mode* until stream on. Only at stream on should -the transmitter activate the clock on the clock lane and transition to *HS -mode*. +and maintain *LP-11 or LP-111 mode* until stream on. Only at stream on time +should the transmitter activate the clock on the clock lane and transition to +*HS mode*. Some transmitters do this automatically but some have to be explicitly programmed to do so, and some are unable to do so altogether due to diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst index 37dad2f4df8cf..ed65fb594cc8e 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst @@ -37,6 +37,8 @@ Image Process Control IDs by selecting the desired horizontal and vertical blanking. The unit of this control is Hz. +.. _v4l2-cid-pixel-rate: + ``V4L2_CID_PIXEL_RATE (64-bit integer)`` Pixel rate in the source pads of the subdev. This control is read-only and its unit is pixels / second. diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index 5b275a845c20b..fa4901162663b 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -129,11 +129,11 @@ void v4l2_async_debug_init(struct dentry *debugfs_dir); * * This function initializes the notifier @asd_list. It must be called * before adding a subdevice to a notifier, using one of: - * @v4l2_async_notifier_add_fwnode_remote_subdev, - * @v4l2_async_notifier_add_fwnode_subdev, - * @v4l2_async_notifier_add_i2c_subdev, - * @__v4l2_async_notifier_add_subdev or - * @v4l2_async_notifier_parse_fwnode_endpoints. + * v4l2_async_notifier_add_fwnode_remote_subdev(), + * v4l2_async_notifier_add_fwnode_subdev(), + * v4l2_async_notifier_add_i2c_subdev(), + * __v4l2_async_notifier_add_subdev() or + * v4l2_async_notifier_parse_fwnode_endpoints(). */ void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier); @@ -145,9 +145,9 @@ void v4l2_async_notifier_init(struct v4l2_async_notifier *notifier); * @asd: pointer to &struct v4l2_async_subdev * * \warning: Drivers should avoid using this function and instead use one of: - * @v4l2_async_notifier_add_fwnode_subdev, - * @v4l2_async_notifier_add_fwnode_remote_subdev or - * @v4l2_async_notifier_add_i2c_subdev. + * v4l2_async_notifier_add_fwnode_subdev(), + * v4l2_async_notifier_add_fwnode_remote_subdev() or + * v4l2_async_notifier_add_i2c_subdev(). * * Call this function before registering a notifier to link the provided @asd to * the notifiers master @asd_list. The @asd must be allocated with k*alloc() as @@ -200,7 +200,7 @@ __v4l2_async_notifier_add_fwnode_remote_subdev(struct v4l2_async_notifier *notif * function also gets a reference of the fwnode which is released later at * notifier cleanup time. * - * This is just like @v4l2_async_notifier_add_fwnode_subdev, but with the + * This is just like v4l2_async_notifier_add_fwnode_subdev(), but with the * exception that the fwnode refers to a local endpoint, not the remote one. */ #define v4l2_async_notifier_add_fwnode_remote_subdev(notifier, ep, type) \ @@ -265,13 +265,13 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier); * sub-devices allocated for the purposes of the notifier but not the notifier * itself. The user is responsible for calling this function to clean up the * notifier after calling - * @v4l2_async_notifier_add_fwnode_remote_subdev, - * @v4l2_async_notifier_add_fwnode_subdev, - * @v4l2_async_notifier_add_i2c_subdev, - * @__v4l2_async_notifier_add_subdev or - * @v4l2_async_notifier_parse_fwnode_endpoints. + * v4l2_async_notifier_add_fwnode_remote_subdev(), + * v4l2_async_notifier_add_fwnode_subdev(), + * v4l2_async_notifier_add_i2c_subdev(), + * __v4l2_async_notifier_add_subdev() or + * v4l2_async_notifier_parse_fwnode_endpoints(). * - * There is no harm from calling v4l2_async_notifier_cleanup in other + * There is no harm from calling v4l2_async_notifier_cleanup() in other * cases as long as its memory has been zeroed after it has been * allocated. */ From 8925b53083980057de99599ba8dd2a72b03406a6 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 22 Jun 2021 12:52:03 +0200 Subject: [PATCH 164/195] media: Documentation: v4l: Fix V4L2_CID_PIXEL_RATE documentation The V4L2_CID_PIXEL_RATE is nowadays used to tell pixel sampling rate in the sub-device's pixel array, not the pixel rate over a link (for which it also becomes unfit with the addition of multiplexed streams later on). Fix this. Signed-off-by: Sakari Ailus Reviewed-by: Jacopo Mondi Reviewed-by: Andrey Konovalov Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-image-process.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst index ed65fb594cc8e..2b5a13dc843ff 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst @@ -40,7 +40,7 @@ Image Process Control IDs .. _v4l2-cid-pixel-rate: ``V4L2_CID_PIXEL_RATE (64-bit integer)`` - Pixel rate in the source pads of the subdev. This control is + Pixel sampling rate in the device's pixel array. This control is read-only and its unit is pixels / second. ``V4L2_CID_TEST_PATTERN (menu)`` From e5a466d4bcf962daa8fea589b09a5675bda275a1 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 22 Jun 2021 13:17:20 +0200 Subject: [PATCH 165/195] media: Documentation: v4l: Improve frame rate configuration documentation Improve the documentation of the frame rate configuration so that it can be understood by a regular human being. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/v4l/ext-ctrls-image-process.rst | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst index 2b5a13dc843ff..b1c2ab2854af1 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst @@ -23,19 +23,7 @@ Image Process Control IDs .. _v4l2-cid-link-freq: ``V4L2_CID_LINK_FREQ (integer menu)`` - Data bus frequency. Together with the media bus pixel code, bus type - (clock cycles per sample), the data bus frequency defines the pixel - rate (``V4L2_CID_PIXEL_RATE``) in the pixel array (or possibly - elsewhere, if the device is not an image sensor). The frame rate can - be calculated from the pixel clock, image width and height and - horizontal and vertical blanking. While the pixel rate control may - be defined elsewhere than in the subdev containing the pixel array, - the frame rate cannot be obtained from that information. This is - because only on the pixel array it can be assumed that the vertical - and horizontal blanking information is exact: no other blanking is - allowed in the pixel array. The selection of frame rate is performed - by selecting the desired horizontal and vertical blanking. The unit - of this control is Hz. + The frequency of the data bus (e.g. parallel or CSI-2). .. _v4l2-cid-pixel-rate: @@ -43,6 +31,15 @@ Image Process Control IDs Pixel sampling rate in the device's pixel array. This control is read-only and its unit is pixels / second. + Some devices use horizontal and vertical balanking to configure the frame + rate. The frame rate can be calculated from the pixel rate, analogue crop + rectangle as well as horizontal and vertical blanking. The pixel rate + control may be present in a different sub-device than the blanking controls + and the analogue crop rectangle configuration. + + The configuration of the frame rate is performed by selecting the desired + horizontal and vertical blanking. The unit of this control is Hz. + ``V4L2_CID_TEST_PATTERN (menu)`` Some capture/display/sensor devices have the capability to generate test pattern images. These hardware specific test patterns can be From 013c35b22e6216b0bde04a1fc3a1a4b599a4e13f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 23 Jun 2021 14:38:31 +0200 Subject: [PATCH 166/195] media: Documentation: v4l: Rework LP-11 documentation, add callbacks Rework LP-11 and LP-111 mode documentation to make it more understandable and useful. This involves adding pre_streamon and post_streamon callbacks that make it possible to explicitly transition the transmitter to either mode. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/media/tx-rx.rst | 40 +++++++++++++++++------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/Documentation/driver-api/media/tx-rx.rst b/Documentation/driver-api/media/tx-rx.rst index 12d492d25df29..e1e9258dd8624 100644 --- a/Documentation/driver-api/media/tx-rx.rst +++ b/Documentation/driver-api/media/tx-rx.rst @@ -93,18 +93,34 @@ where LP-11 and LP-111 modes ^^^^^^^^^^^^^^^^^^^^^^ -The transmitter drivers must, if possible, configure the CSI-2 transmitter to -*LP-11 or LP-111 mode* whenever the transmitter is powered on but not active, -and maintain *LP-11 or LP-111 mode* until stream on. Only at stream on time -should the transmitter activate the clock on the clock lane and transition to -*HS mode*. - -Some transmitters do this automatically but some have to be explicitly -programmed to do so, and some are unable to do so altogether due to -hardware constraints. - -The receiver thus need to be configured to expect LP-11 or LP-111 mode from the -transmitter before the transmitter driver's ``.s_stream()`` op is called. +As part of transitioning to high speed mode, a CSI-2 transmitter typically +briefly sets the bus to LP-11 or LP-111 state, depending on the PHY. This period +may be as short as 100 µs, during which the receiver observes this state and +proceeds its own part of high speed mode transition. + +Most receivers are capable of autonomously handling this once the software has +configured them to do so, but there are receivers which require software +involvement in observing LP-11 or LP-111 state. 100 µs is a brief period to hit +in software, especially when there is no interrupt telling something is +happening. + +One way to address this is to configure the transmitter side explicitly to LP-11 +or LP-111 mode, which requires support from the transmitter hardware. This is +not universally available. Many devices return to this state once streaming is +stopped while the state after power-on is LP-00 or LP-000. + +The ``.pre_streamon()`` callback may be used to prepare a transmitter for +transitioning to streaming state, but not yet start streaming. Similarly, the +``.post_streamoff()`` callback is used to undo what was done by the +``.pre_streamon()`` callback. The caller of ``.pre_streamon()`` is thus required +to call ``.post_streamoff()`` for each successful call of ``.pre_streamon()``. + +In the context of CSI-2, the ``.pre_streamon()`` callback is used to transition +the transmitter to the LP-11 or LP-111 mode. This also requires powering on the +device, so this should be only done when it is needed. + +Receiver drivers that do not need explicit LP-11 or LP-111 mode setup are waived +from calling the two callbacks. Stopping the transmitter ^^^^^^^^^^^^^^^^^^^^^^^^ From 253171a0da67304f0ee7358b37df7b715c65dd77 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 23 Jun 2021 14:44:28 +0200 Subject: [PATCH 167/195] media: v4l: subdev: Add pre_streamon and post_streamoff callbacks Add pre_streamon and post_streamoff callbacks that can be used to set a CSI-2 transmitter to LP-11 or LP-111 mode. This can be used by receiver drivers to reliably initialise the receiver when its initialisation requires software involvement. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-subdev.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 5364e3a6ac9bf..95ec18c2f49ce 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -354,6 +354,16 @@ struct v4l2_mbus_frame_desc { unsigned short num_entries; }; +/** + * enum v4l2_subdev_pre_streamon_flags - Flags for pre_streamon subdev core op + * + * @V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP: Set the transmitter to either LP-11 + * or LP-111 mode before call to s_stream(). + */ +enum v4l2_subdev_pre_streamon_flags { + V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP = BIT(0), +}; + /** * struct v4l2_subdev_video_ops - Callbacks used when v4l device was opened * in video mode. @@ -409,6 +419,19 @@ struct v4l2_mbus_frame_desc { * @s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev * can adjust @size to a lower value and must not write more data to the * buffer starting at @data than the original value of @size. + * + * @pre_streamon: May be called before streaming is actually started, to help + * initialising the bus. Current usage is to set a CSI-2 transmitter to + * LP-11 or LP-111 mode before streaming. See &enum + * v4l2_subdev_pre_streamon_flags. + * + * pre_streamon shall return error if it cannot perform the operation as + * indicated by the flags argument. In particular, -EACCES indicates lack + * of support for the operation. The caller shall call post_streamoff for + * each successful call of pre_streamon. + * + * @post_streamoff: Called after streaming is stopped, but if and only if + * pre_streamon was called earlier. */ struct v4l2_subdev_video_ops { int (*s_routing)(struct v4l2_subdev *sd, u32 input, u32 output, u32 config); @@ -435,6 +458,8 @@ struct v4l2_subdev_video_ops { struct v4l2_dv_timings *timings); int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf, unsigned int *size); + int (*pre_streamon)(struct v4l2_subdev *sd, u32 flags); + int (*post_streamoff)(struct v4l2_subdev *sd); }; /** From 41a95d043fa59e99ce4440c38640576232ef5f74 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 23 Jun 2021 16:20:50 +0200 Subject: [PATCH 168/195] media: ccs: Implement support for manual LP control Use the pre_streamon callback to transition the transmitter to either LP-11 or LP-111 mode if supported by the sensor. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ccs/ccs-core.c | 47 ++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 121cbe406fe4b..5363f3bcafe3d 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -1943,6 +1943,51 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) return rval; } +static int ccs_pre_streamon(struct v4l2_subdev *subdev, u32 flags) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + int rval; + + if (flags & V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP) { + switch (sensor->hwcfg.csi_signalling_mode) { + case CCS_CSI_SIGNALING_MODE_CSI_2_DPHY: + if (!(CCS_LIM(sensor, PHY_CTRL_CAPABILITY_2) & + CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_DPHY)) + return -EACCES; + break; + case CCS_CSI_SIGNALING_MODE_CSI_2_CPHY: + if (!(CCS_LIM(sensor, PHY_CTRL_CAPABILITY_2) & + CCS_PHY_CTRL_CAPABILITY_2_MANUAL_LP_CPHY)) + return -EACCES; + break; + default: + return -EACCES; + } + } + + rval = ccs_pm_get_init(sensor); + if (rval) + return rval; + + if (flags & V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP) { + rval = ccs_write(sensor, MANUAL_LP_CTRL, + CCS_MANUAL_LP_CTRL_ENABLE); + if (rval) + pm_runtime_put(&client->dev); + } + + return rval; +} + +static int ccs_post_streamoff(struct v4l2_subdev *subdev) +{ + struct ccs_sensor *sensor = to_ccs_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + return pm_runtime_put(&client->dev); +} + static int ccs_enum_mbus_code(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) @@ -3055,6 +3100,8 @@ static int ccs_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static const struct v4l2_subdev_video_ops ccs_video_ops = { .s_stream = ccs_set_stream, + .pre_streamon = ccs_pre_streamon, + .post_streamoff = ccs_post_streamoff, }; static const struct v4l2_subdev_pad_ops ccs_pad_ops = { From a40eba9b26f70c7a967647a05ce0ef84e82140ba Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 24 Jun 2021 14:05:24 +0200 Subject: [PATCH 169/195] media: v4l2-flash: Add sanity checks for flash and indicator controls The V4L2 flash API supports combinations of indicator and flash LEDs. Due to this, there's a fair amount of code that deals with all the possible options and just reading one part of the file doesn't really tell which combinations are really possible. Make the checks more explicit to keep static analysers happy and to make the code more resilient to future mishaps. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/v4l2-core/v4l2-flash-led-class.c | 52 +++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index 10ddcc48aa17e..4c096ae4648d9 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -80,6 +80,7 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, struct v4l2_ctrl *ctrl) { struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; + struct led_classdev *led_cdev; enum led_brightness brightness; if (has_flash_op(v4l2_flash, intensity_to_led_brightness)) @@ -104,12 +105,18 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) return; - led_set_brightness_sync(&v4l2_flash->fled_cdev->led_cdev, - brightness); + if (WARN_ON_ONCE(!v4l2_flash->fled_cdev)) + return; + + led_cdev = &v4l2_flash->fled_cdev->led_cdev; } else { - led_set_brightness_sync(v4l2_flash->iled_cdev, - brightness); + if (WARN_ON_ONCE(!v4l2_flash->iled_cdev)) + return; + + led_cdev = v4l2_flash->iled_cdev; } + + led_set_brightness_sync(led_cdev, brightness); } static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash, @@ -128,8 +135,15 @@ static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash, */ if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) return 0; + + if (WARN_ON_ONCE(!v4l2_flash->fled_cdev)) + return -EINVAL; + led_cdev = &v4l2_flash->fled_cdev->led_cdev; } else { + if (WARN_ON_ONCE(!v4l2_flash->iled_cdev)) + return -EINVAL; + led_cdev = v4l2_flash->iled_cdev; } @@ -159,6 +173,12 @@ static int v4l2_flash_g_volatile_ctrl(struct v4l2_ctrl *c) case V4L2_CID_FLASH_TORCH_INTENSITY: case V4L2_CID_FLASH_INDICATOR_INTENSITY: return v4l2_flash_update_led_brightness(v4l2_flash, c); + } + + if (!fled_cdev) + return -EINVAL; + + switch (c->id) { case V4L2_CID_FLASH_INTENSITY: ret = led_update_flash_brightness(fled_cdev); if (ret < 0) @@ -194,11 +214,23 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) { struct v4l2_flash *v4l2_flash = v4l2_ctrl_to_v4l2_flash(c); struct led_classdev_flash *fled_cdev = v4l2_flash->fled_cdev; - struct led_classdev *led_cdev = fled_cdev ? &fled_cdev->led_cdev : NULL; + struct led_classdev *led_cdev; struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; bool external_strobe; int ret = 0; + switch (c->id) { + case V4L2_CID_FLASH_TORCH_INTENSITY: + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + v4l2_flash_set_led_brightness(v4l2_flash, c); + return 0; + } + + if (!fled_cdev) + return -EINVAL; + + led_cdev = &fled_cdev->led_cdev; + switch (c->id) { case V4L2_CID_FLASH_LED_MODE: switch (c->val) { @@ -268,10 +300,6 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) * microamperes for flash intensity units. */ return led_set_flash_brightness(fled_cdev, c->val); - case V4L2_CID_FLASH_TORCH_INTENSITY: - case V4L2_CID_FLASH_INDICATOR_INTENSITY: - v4l2_flash_set_led_brightness(v4l2_flash, c); - return 0; } return -EINVAL; @@ -492,6 +520,9 @@ static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash) ctrls[INDICATOR_INTENSITY]); if (ctrls[FLASH_TIMEOUT]) { + if (WARN_ON_ONCE(!fled_cdev)) + return -EINVAL; + ret = led_set_flash_timeout(fled_cdev, ctrls[FLASH_TIMEOUT]->val); if (ret < 0) @@ -499,6 +530,9 @@ static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash) } if (ctrls[FLASH_INTENSITY]) { + if (WARN_ON_ONCE(!fled_cdev)) + return -EINVAL; + ret = led_set_flash_brightness(fled_cdev, ctrls[FLASH_INTENSITY]->val); if (ret < 0) From 4d7adf0236c18befcac449fa1938e32f4bd1ddad Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 24 Jun 2021 14:32:02 +0200 Subject: [PATCH 170/195] media: v4l2-flash: Check whether setting LED brightness succeeded Setting LED brightness may return an error but the return value was never checked by the V4L2 flash LED class. Do it now. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/v4l2-core/v4l2-flash-led-class.c | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index 4c096ae4648d9..e70e128ccc9c5 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -76,8 +76,8 @@ static s32 __led_brightness_to_intensity(struct v4l2_ctrl *ctrl, return (brightness * ctrl->step) + ctrl->minimum; } -static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, - struct v4l2_ctrl *ctrl) +static int v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, + struct v4l2_ctrl *ctrl) { struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; struct led_classdev *led_cdev; @@ -103,20 +103,20 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash, if (ctrl == ctrls[TORCH_INTENSITY]) { if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH) - return; + return 0; if (WARN_ON_ONCE(!v4l2_flash->fled_cdev)) - return; + return -EINVAL; led_cdev = &v4l2_flash->fled_cdev->led_cdev; } else { if (WARN_ON_ONCE(!v4l2_flash->iled_cdev)) - return; + return -EINVAL; led_cdev = v4l2_flash->iled_cdev; } - led_set_brightness_sync(led_cdev, brightness); + return led_set_brightness_sync(led_cdev, brightness); } static int v4l2_flash_update_led_brightness(struct v4l2_flash *v4l2_flash, @@ -222,8 +222,7 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) switch (c->id) { case V4L2_CID_FLASH_TORCH_INTENSITY: case V4L2_CID_FLASH_INDICATOR_INTENSITY: - v4l2_flash_set_led_brightness(v4l2_flash, c); - return 0; + return v4l2_flash_set_led_brightness(v4l2_flash, c); } if (!fled_cdev) @@ -262,9 +261,8 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c) if (ret < 0) return ret; - v4l2_flash_set_led_brightness(v4l2_flash, - ctrls[TORCH_INTENSITY]); - return 0; + return v4l2_flash_set_led_brightness(v4l2_flash, + ctrls[TORCH_INTENSITY]); } break; case V4L2_CID_FLASH_STROBE_SOURCE: @@ -511,13 +509,19 @@ static int __sync_device_with_v4l2_controls(struct v4l2_flash *v4l2_flash) struct v4l2_ctrl **ctrls = v4l2_flash->ctrls; int ret = 0; - if (ctrls[TORCH_INTENSITY]) - v4l2_flash_set_led_brightness(v4l2_flash, - ctrls[TORCH_INTENSITY]); + if (ctrls[TORCH_INTENSITY]) { + ret = v4l2_flash_set_led_brightness(v4l2_flash, + ctrls[TORCH_INTENSITY]); + if (ret < 0) + return ret; + } - if (ctrls[INDICATOR_INTENSITY]) - v4l2_flash_set_led_brightness(v4l2_flash, - ctrls[INDICATOR_INTENSITY]); + if (ctrls[INDICATOR_INTENSITY]) { + ret = v4l2_flash_set_led_brightness(v4l2_flash, + ctrls[INDICATOR_INTENSITY]); + if (ret < 0) + return ret; + } if (ctrls[FLASH_TIMEOUT]) { if (WARN_ON_ONCE(!fled_cdev)) From 84363509c72588bdbdfdd8503eb173a9b9a798f0 Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Mon, 5 Jul 2021 08:50:59 +0200 Subject: [PATCH 171/195] media: ov2740: use group write for digital gain As the RGB digital gains of ov2740 were not applied as group, some artifacts were observed in low light environment, use group write for digital gain can make the RGB digital can be guaranteed to applied together at frame boundary. Signed-off-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2740.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 599369a3d192f..934c9d65cb097 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -51,7 +51,7 @@ #define OV2740_REG_MWB_R_GAIN 0x500a #define OV2740_REG_MWB_G_GAIN 0x500c #define OV2740_REG_MWB_B_GAIN 0x500e -#define OV2740_DGTL_GAIN_MIN 0 +#define OV2740_DGTL_GAIN_MIN 1024 #define OV2740_DGTL_GAIN_MAX 4095 #define OV2740_DGTL_GAIN_STEP 1 #define OV2740_DGTL_GAIN_DEFAULT 1024 @@ -61,6 +61,12 @@ #define OV2740_TEST_PATTERN_ENABLE BIT(7) #define OV2740_TEST_PATTERN_BAR_SHIFT 2 +/* Group Access */ +#define OV2740_REG_GROUP_ACCESS 0x3208 +#define OV2740_GROUP_HOLD_START 0x0 +#define OV2740_GROUP_HOLD_END 0x10 +#define OV2740_GROUP_HOLD_LAUNCH 0xa0 + /* ISP CTRL00 */ #define OV2740_REG_ISP_CTRL00 0x5000 /* ISP CTRL01 */ @@ -438,6 +444,11 @@ static int ov2740_update_digital_gain(struct ov2740 *ov2740, u32 d_gain) { int ret = 0; + ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1, + OV2740_GROUP_HOLD_START); + if (ret) + return ret; + ret = ov2740_write_reg(ov2740, OV2740_REG_MWB_R_GAIN, 2, d_gain); if (ret) return ret; @@ -446,7 +457,18 @@ static int ov2740_update_digital_gain(struct ov2740 *ov2740, u32 d_gain) if (ret) return ret; - return ov2740_write_reg(ov2740, OV2740_REG_MWB_B_GAIN, 2, d_gain); + ret = ov2740_write_reg(ov2740, OV2740_REG_MWB_B_GAIN, 2, d_gain); + if (ret) + return ret; + + ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1, + OV2740_GROUP_HOLD_END); + if (ret) + return ret; + + ret = ov2740_write_reg(ov2740, OV2740_REG_GROUP_ACCESS, 1, + OV2740_GROUP_HOLD_LAUNCH); + return ret; } static int ov2740_test_pattern(struct ov2740 *ov2740, u32 pattern) From 0e2b8552660c5e3f9416c252e42632e780cdbb7b Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Mon, 5 Jul 2021 09:14:15 +0200 Subject: [PATCH 172/195] media: ov9734: use group write for digital gain As the RGB digital gains of ov9734 were not applied as group, some artifacts were observed in low light environment, use group write for digital gain can make the RGB digital can be guaranteed to applied together at frame boundary. Signed-off-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9734.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index af50c66cf5ce2..df538ceb71c36 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -60,6 +60,12 @@ #define OV9734_TEST_PATTERN_ENABLE BIT(7) #define OV9734_TEST_PATTERN_BAR_SHIFT 2 +/* Group Access */ +#define OV9734_REG_GROUP_ACCESS 0x3208 +#define OV9734_GROUP_HOLD_START 0x0 +#define OV9734_GROUP_HOLD_END 0x10 +#define OV9734_GROUP_HOLD_LAUNCH 0xa0 + enum { OV9734_LINK_FREQ_180MHZ_INDEX, }; @@ -433,6 +439,11 @@ static int ov9734_update_digital_gain(struct ov9734 *ov9734, u32 d_gain) { int ret; + ret = ov9734_write_reg(ov9734, OV9734_REG_GROUP_ACCESS, 1, + OV9734_GROUP_HOLD_START); + if (ret) + return ret; + ret = ov9734_write_reg(ov9734, OV9734_REG_MWB_R_GAIN, 2, d_gain); if (ret) return ret; @@ -441,7 +452,18 @@ static int ov9734_update_digital_gain(struct ov9734 *ov9734, u32 d_gain) if (ret) return ret; - return ov9734_write_reg(ov9734, OV9734_REG_MWB_B_GAIN, 2, d_gain); + ret = ov9734_write_reg(ov9734, OV9734_REG_MWB_B_GAIN, 2, d_gain); + if (ret) + return ret; + + ret = ov9734_write_reg(ov9734, OV9734_REG_GROUP_ACCESS, 1, + OV9734_GROUP_HOLD_END); + if (ret) + return ret; + + ret = ov9734_write_reg(ov9734, OV9734_REG_GROUP_ACCESS, 1, + OV9734_GROUP_HOLD_LAUNCH); + return ret; } static int ov9734_test_pattern(struct ov9734 *ov9734, u32 pattern) From d84a2e4900ff43daba4e19b0a7cc56326fe8642a Mon Sep 17 00:00:00 2001 From: Bingbu Cao Date: Tue, 6 Jul 2021 11:18:49 +0200 Subject: [PATCH 173/195] media: ov8856: ignore gpio and regulator for ov8856 with ACPI For ov8856 working with ACPI, it does not depend on the reset gpio and regulator to do reset and power control, so should get the gpio and regulator for non-ACPI cases only, otherwise it will break ov8856 with ACPI. [Sakari Ailus: Wrap a line over 80 chars.] Signed-off-by: Bingbu Cao Signed-off-by: Tianshu Qiu Cc: Robert Foss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov8856.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 88e19f30d3762..aa74744b91c7c 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -2304,25 +2304,26 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) clk_set_rate(ov8856->xvclk, xvclk_rate); xvclk_rate = clk_get_rate(ov8856->xvclk); + + ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(ov8856->reset_gpio)) + return PTR_ERR(ov8856->reset_gpio); + + for (i = 0; i < ARRAY_SIZE(ov8856_supply_names); i++) + ov8856->supplies[i].supply = ov8856_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, + ARRAY_SIZE(ov8856_supply_names), + ov8856->supplies); + if (ret) + return ret; } if (xvclk_rate != OV8856_XVCLK_19_2) dev_warn(dev, "external clock rate %u is unsupported", xvclk_rate); - ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset", - GPIOD_OUT_LOW); - if (IS_ERR(ov8856->reset_gpio)) - return PTR_ERR(ov8856->reset_gpio); - - for (i = 0; i < ARRAY_SIZE(ov8856_supply_names); i++) - ov8856->supplies[i].supply = ov8856_supply_names[i]; - - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ov8856_supply_names), - ov8856->supplies); - if (ret) - return ret; - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; From 51f93add3669f1b1f540de1cf397815afbd4c756 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 23 Jul 2021 13:22:32 +0200 Subject: [PATCH 174/195] media: imx258: Rectify mismatch of VTS value The frame_length_lines (0x0340) registers are hard-coded as follows: - 4208x3118 frame_length_lines = 0x0c50 - 2104x1560 frame_length_lines = 0x0638 - 1048x780 frame_length_lines = 0x034c The driver exposes the V4L2_CID_VBLANK control in read-only mode and sets its value to vts_def - height, where vts_def is a mode-dependent value coming from the supported_modes array. It is set using one of the following macros defined in the driver: #define IMX258_VTS_30FPS 0x0c98 #define IMX258_VTS_30FPS_2K 0x0638 #define IMX258_VTS_30FPS_VGA 0x034c There's a clear mismatch in the value for the full resolution mode i.e. IMX258_VTS_30FPS. Fix it by rectifying the macro with the value set for the frame_length_lines register as stated above. Signed-off-by: Laurent Pinchart Signed-off-by: Umang Jain Reviewed-by: Bingbu Cao Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx258.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index 7ab9e5f9f2676..4e695096e5d05 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -23,7 +23,7 @@ #define IMX258_CHIP_ID 0x0258 /* V_TIMING internal */ -#define IMX258_VTS_30FPS 0x0c98 +#define IMX258_VTS_30FPS 0x0c50 #define IMX258_VTS_30FPS_2K 0x0638 #define IMX258_VTS_30FPS_VGA 0x034c #define IMX258_VTS_MAX 0xffff From f809665ee75fff3f4ea8907f406a66d380aeb184 Mon Sep 17 00:00:00 2001 From: Umang Jain Date: Fri, 23 Jul 2021 13:22:33 +0200 Subject: [PATCH 175/195] media: imx258: Limit the max analogue gain to 480 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The range for analog gain mentioned in the datasheet is [0, 480]. The real gain formula mentioned in the datasheet is: Gain = 512 / (512 – X) Hence, values larger than 511 clearly makes no sense. The gain register field is also documented to be of 9-bits in the datasheet. Certainly, it is enough to infer that, the kernel driver currently advertises an arbitrary analog gain max. Fix it by rectifying the value as per the data sheet i.e. 480. Signed-off-by: Umang Jain Reviewed-by: Laurent Pinchart Reviewed-by: Dave Stevenson Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx258.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index 4e695096e5d05..81cdf37216ca7 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -47,7 +47,7 @@ /* Analog gain control */ #define IMX258_REG_ANALOG_GAIN 0x0204 #define IMX258_ANA_GAIN_MIN 0 -#define IMX258_ANA_GAIN_MAX 0x1fff +#define IMX258_ANA_GAIN_MAX 480 #define IMX258_ANA_GAIN_STEP 1 #define IMX258_ANA_GAIN_DEFAULT 0x0 From e8713c31f8adab67155e245a217d0c7cad05fcf5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 12 Apr 2021 04:32:48 +0200 Subject: [PATCH 176/195] media: dt-bindings: media: nxp,imx7-csi: Add i.MX8MM support The i.MX8MM integrates a CSI bridge IP core, as the i.MX7. There seems to be no difference between the two SoCs according to the reference manual, but as documentation may not be accurate, add a compatible string for the i.MX8MM, with a fallback on the compatible i.MX7. Signed-off-by: Laurent Pinchart Reviewed-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/nxp,imx7-csi.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml b/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml index d91575b8ebb93..5922a2795167f 100644 --- a/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml +++ b/Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml @@ -4,7 +4,7 @@ $id: http://devicetree.org/schemas/media/nxp,imx7-csi.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: i.MX7 CMOS Sensor Interface +title: i.MX7 and i.MX8 CSI bridge (CMOS Sensor Interface) maintainers: - Rui Miguel Silva @@ -15,9 +15,13 @@ description: | properties: compatible: - enum: - - fsl,imx7-csi - - fsl,imx6ul-csi + oneOf: + - enum: + - fsl,imx7-csi + - fsl,imx6ul-csi + - items: + - const: fsl,imx8mm-csi + - const: fsl,imx7-csi reg: maxItems: 1 From a581c87c681c6202403d74e8e816968841afe2f7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 3 Feb 2021 04:08:19 +0100 Subject: [PATCH 177/195] media: imx: imx7-media-csi: Set TWO_8BIT_SENSOR for >= 10-bit formats Sample code from NXP, as well as experiments on i.MX8MM with RAW10 capture with an OV5640 sensor connected over CSI-2, showed that the TWO_8BIT_SENSOR field of the CSICR3 register needs to be set for formats larger than 8 bits. Do so, even if the reference manual doesn't clearly describe the effect of the field. Signed-off-by: Laurent Pinchart Tested-by: Martin Kepplinger Reviewed-by: Rui Miguel Silva Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx7-media-csi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 894c4de31790e..8aefcf0e219f3 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -421,6 +421,7 @@ static void imx7_csi_configure(struct imx7_csi *csi) struct v4l2_pix_format *out_pix = &vdev->fmt; int width = out_pix->width; u32 stride = 0; + u32 cr3 = BIT_FRMCNT_RST; u32 cr1, cr18; cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); @@ -464,6 +465,7 @@ static void imx7_csi_configure(struct imx7_csi *csi) case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: + cr3 |= BIT_TWO_8BIT_SENSOR; cr18 |= BIT_MIPI_DATA_FORMAT_RAW10; break; case MEDIA_BUS_FMT_Y12_1X12: @@ -471,6 +473,7 @@ static void imx7_csi_configure(struct imx7_csi *csi) case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: + cr3 |= BIT_TWO_8BIT_SENSOR; cr18 |= BIT_MIPI_DATA_FORMAT_RAW12; break; case MEDIA_BUS_FMT_Y14_1X14: @@ -478,6 +481,7 @@ static void imx7_csi_configure(struct imx7_csi *csi) case MEDIA_BUS_FMT_SGBRG14_1X14: case MEDIA_BUS_FMT_SGRBG14_1X14: case MEDIA_BUS_FMT_SRGGB14_1X14: + cr3 |= BIT_TWO_8BIT_SENSOR; cr18 |= BIT_MIPI_DATA_FORMAT_RAW14; break; /* @@ -510,7 +514,7 @@ static void imx7_csi_configure(struct imx7_csi *csi) imx7_csi_reg_write(csi, cr1, CSI_CSICR1); imx7_csi_reg_write(csi, BIT_DMA_BURST_TYPE_RFF_INCR16, CSI_CSICR2); - imx7_csi_reg_write(csi, BIT_FRMCNT_RST, CSI_CSICR3); + imx7_csi_reg_write(csi, cr3, CSI_CSICR3); imx7_csi_reg_write(csi, cr18, CSI_CSICR18); imx7_csi_reg_write(csi, (width * out_pix->height) >> 2, CSI_CSIRXCNT); From 8b226173a1e9ea1b77dabb3d5583d376c53164c3 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 3 Feb 2021 03:57:18 +0100 Subject: [PATCH 178/195] media: imx: imx7-media-csi: Don't set PIXEL_BIT in CSICR1 The PIXEL_BIT field of the CSICR1 register is documented as setting the Bayer data width to 10 bits, and is set by the driver for all non-YUV pixel formats. Test code from NXP showed that the bit shouldn't be set for Bayer formats, and this was confirmed by experimentation with RAW8 capture (which doesn't work when setting the field) and RAW10 capture (for which setting the field doesn't seem to make a difference) on i.MX8MM with an OV5640 sensor connected over CSI-2. Don't set it. Signed-off-by: Laurent Pinchart Reviewed-by: Rui Miguel Silva Tested-by: Martin Kepplinger Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx7-media-csi.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 8aefcf0e219f3..bacbd7ca6d48f 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -495,21 +495,6 @@ static void imx7_csi_configure(struct imx7_csi *csi) cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B; break; } - - switch (out_pix->pixelformat) { - case V4L2_PIX_FMT_Y10: - case V4L2_PIX_FMT_Y12: - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_SBGGR16: - case V4L2_PIX_FMT_SGBRG16: - case V4L2_PIX_FMT_SGRBG16: - case V4L2_PIX_FMT_SRGGB16: - cr1 |= BIT_PIXEL_BIT; - break; - } } imx7_csi_reg_write(csi, cr1, CSI_CSICR1); From 0ada1697ed4256b38225319c9896661142a3572d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 12 May 2021 01:44:40 +0200 Subject: [PATCH 179/195] media: imx: imx7-media-csi: Fix buffer return upon stream start failure When the stream fails to start, the first two buffers in the queue have been moved to the active_vb2_buf array and are returned to vb2 by imx7_csi_dma_unsetup_vb2_buf(). The function is called with the buffer state set to VB2_BUF_STATE_ERROR unconditionally, which is correct when stopping the stream, but not when the start operation fails. In that case, the state should be set to VB2_BUF_STATE_QUEUED. Fix it. Signed-off-by: Laurent Pinchart Tested-by: Martin Kepplinger Reviewed-by: Rui Miguel Silva Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx7-media-csi.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index bacbd7ca6d48f..1271837329124 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -361,6 +361,7 @@ static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi, vb->timestamp = ktime_get_ns(); vb2_buffer_done(vb, return_status); + csi->active_vb2_buf[i] = NULL; } } } @@ -386,9 +387,10 @@ static int imx7_csi_dma_setup(struct imx7_csi *csi) return 0; } -static void imx7_csi_dma_cleanup(struct imx7_csi *csi) +static void imx7_csi_dma_cleanup(struct imx7_csi *csi, + enum vb2_buffer_state return_status) { - imx7_csi_dma_unsetup_vb2_buf(csi, VB2_BUF_STATE_ERROR); + imx7_csi_dma_unsetup_vb2_buf(csi, return_status); imx_media_free_dma_buf(csi->dev, &csi->underrun_buf); } @@ -526,9 +528,10 @@ static int imx7_csi_init(struct imx7_csi *csi) return 0; } -static void imx7_csi_deinit(struct imx7_csi *csi) +static void imx7_csi_deinit(struct imx7_csi *csi, + enum vb2_buffer_state return_status) { - imx7_csi_dma_cleanup(csi); + imx7_csi_dma_cleanup(csi, return_status); imx7_csi_init_default(csi); imx7_csi_dmareq_rff_disable(csi); clk_disable_unprepare(csi->mclk); @@ -691,7 +694,7 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) ret = v4l2_subdev_call(csi->src_sd, video, s_stream, 1); if (ret < 0) { - imx7_csi_deinit(csi); + imx7_csi_deinit(csi, VB2_BUF_STATE_QUEUED); goto out_unlock; } @@ -701,7 +704,7 @@ static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable) v4l2_subdev_call(csi->src_sd, video, s_stream, 0); - imx7_csi_deinit(csi); + imx7_csi_deinit(csi, VB2_BUF_STATE_ERROR); } csi->is_streaming = !!enable; From 43c3f12dfbbda169b06715bf0b090ca1b1201058 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Mon, 31 May 2021 19:43:00 +0200 Subject: [PATCH 180/195] media: imx: imx7_mipi_csis: convert some switch cases to the default Static analysis reports this false positive imx7-mipi-csis.c:1027:2: warning: 4th function call argument is an uninitialized value The variable 'align' is falsely reported as uninitialized. Even though all the cases are covered in the switch (csis_fmt->width % 8) { Because there is no default case, it is reported as uninialized. Improve the switch by converting the most numerous set of cases to the default and silence the false positive. Signed-off-by: Tom Rix Reviewed-by: Rui Miguel Silva Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx7-mipi-csis.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index ead696eb46103..41e33535de552 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -1019,10 +1019,8 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, case 6: align = 2; break; - case 1: - case 3: - case 5: - case 7: + default: + /* 1, 3, 5, 7 */ align = 3; break; } From 37255747ecbd691a0050109e8c2133096f4dab50 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Wed, 28 Jul 2021 11:12:43 +0200 Subject: [PATCH 181/195] media: dt-bindings: media: document the nxp,imx8mq-mipi-csi2 receiver phy and controller The i.MX8MQ SoC integrates a different MIPI CSI receiver as the i.MX8MM so describe the DT bindings for it. Signed-off-by: Martin Kepplinger Reviewed-by: Rob Herring Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/nxp,imx8mq-mipi-csi2.yaml | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml diff --git a/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml new file mode 100644 index 0000000000000..9c04fa85ee5c2 --- /dev/null +++ b/Documentation/devicetree/bindings/media/nxp,imx8mq-mipi-csi2.yaml @@ -0,0 +1,174 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/nxp,imx8mq-mipi-csi2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NXP i.MX8MQ MIPI CSI-2 receiver + +maintainers: + - Martin Kepplinger + +description: |- + This binding covers the CSI-2 RX PHY and host controller included in the + NXP i.MX8MQ SoC. It handles the sensor/image input and process for all the + input imaging devices. + +properties: + compatible: + enum: + - fsl,imx8mq-mipi-csi2 + + reg: + maxItems: 1 + + clocks: + items: + - description: core is the RX Controller Core Clock input. This clock + must be exactly equal to or faster than the receive + byteclock from the RX DPHY. + - description: esc is the Rx Escape Clock. This must be the same escape + clock that the RX DPHY receives. + - description: ui is the pixel clock (phy_ref up to 333Mhz). + See the reference manual for details. + + clock-names: + items: + - const: core + - const: esc + - const: ui + + power-domains: + maxItems: 1 + + resets: + items: + - description: CORE_RESET reset register bit definition + - description: PHY_REF_RESET reset register bit definition + - description: ESC_RESET reset register bit definition + + fsl,mipi-phy-gpr: + description: | + The phandle to the imx8mq syscon iomux-gpr with the register + for setting RX_ENABLE for the mipi receiver. + + The format should be as follows: + + gpr is the phandle to general purpose register node. + req_gpr is the gpr register offset of RX_ENABLE for the mipi phy. + $ref: /schemas/types.yaml#/definitions/phandle-array + items: + items: + - description: The 'gpr' is the phandle to general purpose register node. + - description: The 'req_gpr' is the gpr register offset containing + CSI2_1_RX_ENABLE or CSI2_2_RX_ENABLE respectively. + maximum: 0xff + + interconnects: + maxItems: 1 + + interconnect-names: + const: dram + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false + description: + Input port node, single endpoint describing the CSI-2 transmitter. + + properties: + endpoint: + $ref: video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + items: + minItems: 1 + maxItems: 4 + items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + + required: + - data-lanes + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: + Output port node + + required: + - port@0 + - port@1 + +required: + - compatible + - reg + - clocks + - clock-names + - power-domains + - resets + - fsl,mipi-phy-gpr + - ports + +additionalProperties: false + +examples: + - | + #include + #include + #include + + csi@30a70000 { + compatible = "fsl,imx8mq-mipi-csi2"; + reg = <0x30a70000 0x1000>; + clocks = <&clk IMX8MQ_CLK_CSI1_CORE>, + <&clk IMX8MQ_CLK_CSI1_ESC>, + <&clk IMX8MQ_CLK_CSI1_PHY_REF>; + clock-names = "core", "esc", "ui"; + assigned-clocks = <&clk IMX8MQ_CLK_CSI1_CORE>, + <&clk IMX8MQ_CLK_CSI1_PHY_REF>, + <&clk IMX8MQ_CLK_CSI1_ESC>; + assigned-clock-rates = <266000000>, <200000000>, <66000000>; + assigned-clock-parents = <&clk IMX8MQ_SYS1_PLL_266M>, + <&clk IMX8MQ_SYS2_PLL_1000M>, + <&clk IMX8MQ_SYS1_PLL_800M>; + power-domains = <&pgc_mipi_csi1>; + resets = <&src IMX8MQ_RESET_MIPI_CSI1_CORE_RESET>, + <&src IMX8MQ_RESET_MIPI_CSI1_PHY_REF_RESET>, + <&src IMX8MQ_RESET_MIPI_CSI1_ESC_RESET>; + fsl,mipi-phy-gpr = <&iomuxc_gpr 0x88>; + interconnects = <&noc IMX8MQ_ICM_CSI1 &noc IMX8MQ_ICS_DRAM>; + interconnect-names = "dram"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + imx8mm_mipi_csi_in: endpoint { + remote-endpoint = <&imx477_out>; + data-lanes = <1 2 3 4>; + }; + }; + + port@1 { + reg = <1>; + + imx8mm_mipi_csi_out: endpoint { + remote-endpoint = <&csi_in>; + }; + }; + }; + }; + +... From f33fd8d77dd0095b8841542584ba30d26625f8cb Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Wed, 28 Jul 2021 11:12:44 +0200 Subject: [PATCH 182/195] media: imx: add a driver for i.MX8MQ mipi csi rx phy and controller Add a driver to support the i.MX8MQ MIPI CSI receiver. The hardware side is based on https://source.codeaurora.org/external/imx/linux-imx/tree/drivers/media/platform/imx8/mxc-mipi-csi2_yav.c?h=imx_5.4.70_2.3.0 It's built as part of VIDEO_IMX7_CSI because that's documented to support i.MX8M platforms. This driver adds i.MX8MQ support where currently only the i.MX8MM platform has been supported. Signed-off-by: Martin Kepplinger Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/Makefile | 1 + drivers/staging/media/imx/imx8mq-mipi-csi2.c | 991 +++++++++++++++++++ 2 files changed, 992 insertions(+) create mode 100644 drivers/staging/media/imx/imx8mq-mipi-csi2.c diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile index 6ac33275cc97d..19c2fc54d4243 100644 --- a/drivers/staging/media/imx/Makefile +++ b/drivers/staging/media/imx/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-mipi-csi2.o obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-mipi-csis.o +obj-$(CONFIG_VIDEO_IMX7_CSI) += imx8mq-mipi-csi2.o diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c new file mode 100644 index 0000000000000..a6f562009b9a0 --- /dev/null +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -0,0 +1,991 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NXP i.MX8MQ SoC series MIPI-CSI2 receiver driver + * + * Copyright (C) 2021 Purism SPC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MIPI_CSI2_DRIVER_NAME "imx8mq-mipi-csi2" +#define MIPI_CSI2_SUBDEV_NAME MIPI_CSI2_DRIVER_NAME + +#define MIPI_CSI2_PAD_SINK 0 +#define MIPI_CSI2_PAD_SOURCE 1 +#define MIPI_CSI2_PADS_NUM 2 + +#define MIPI_CSI2_DEF_PIX_WIDTH 640 +#define MIPI_CSI2_DEF_PIX_HEIGHT 480 + +/* Register map definition */ + +/* i.MX8MQ CSI-2 controller CSR */ +#define CSI2RX_CFG_NUM_LANES 0x100 +#define CSI2RX_CFG_DISABLE_DATA_LANES 0x104 +#define CSI2RX_BIT_ERR 0x108 +#define CSI2RX_IRQ_STATUS 0x10c +#define CSI2RX_IRQ_MASK 0x110 +#define CSI2RX_IRQ_MASK_ALL 0x1ff +#define CSI2RX_IRQ_MASK_ULPS_STATUS_CHANGE 0x8 +#define CSI2RX_ULPS_STATUS 0x114 +#define CSI2RX_PPI_ERRSOT_HS 0x118 +#define CSI2RX_PPI_ERRSOTSYNC_HS 0x11c +#define CSI2RX_PPI_ERRESC 0x120 +#define CSI2RX_PPI_ERRSYNCESC 0x124 +#define CSI2RX_PPI_ERRCONTROL 0x128 +#define CSI2RX_CFG_DISABLE_PAYLOAD_0 0x12c +#define CSI2RX_CFG_VID_VC_IGNORE 0x180 +#define CSI2RX_CFG_VID_VC 0x184 +#define CSI2RX_CFG_VID_P_FIFO_SEND_LEVEL 0x188 +#define CSI2RX_CFG_DISABLE_PAYLOAD_1 0x130 + +enum { + ST_POWERED = 1, + ST_STREAMING = 2, + ST_SUSPENDED = 4, +}; + +enum imx8mq_mipi_csi_clk { + CSI2_CLK_CORE, + CSI2_CLK_ESC, + CSI2_CLK_UI, + CSI2_NUM_CLKS, +}; + +static const char * const imx8mq_mipi_csi_clk_id[CSI2_NUM_CLKS] = { + [CSI2_CLK_CORE] = "core", + [CSI2_CLK_ESC] = "esc", + [CSI2_CLK_UI] = "ui", +}; + +#define CSI2_NUM_CLKS ARRAY_SIZE(imx8mq_mipi_csi_clk_id) + +#define GPR_CSI2_1_RX_ENABLE BIT(13) +#define GPR_CSI2_1_VID_INTFC_ENB BIT(12) +#define GPR_CSI2_1_HSEL BIT(10) +#define GPR_CSI2_1_CONT_CLK_MODE BIT(8) +#define GPR_CSI2_1_S_PRG_RXHS_SETTLE(x) (((x) & 0x3f) << 2) + +/* + * The send level configures the number of entries that must accumulate in + * the Pixel FIFO before the data will be transferred to the video output. + * The exact value needed for this configuration is dependent on the rate at + * which the sensor transfers data to the CSI-2 Controller and the user + * video clock. + * + * The calculation is the classical rate-in rate-out type of problem: If the + * video bandwidth is 10% faster than the incoming mipi data and the video + * line length is 500 pixels, then the fifo should be allowed to fill + * 10% of the line length or 50 pixels. If the gap data is ok, then the level + * can be set to 16 and ignored. + */ +#define CSI2RX_SEND_LEVEL 64 + +struct csi_state { + struct device *dev; + void __iomem *regs; + struct clk_bulk_data clks[CSI2_NUM_CLKS]; + struct reset_control *rst; + struct regulator *mipi_phy_regulator; + + struct v4l2_subdev sd; + struct media_pad pads[MIPI_CSI2_PADS_NUM]; + struct v4l2_async_notifier notifier; + struct v4l2_subdev *src_sd; + + struct v4l2_fwnode_bus_mipi_csi2 bus; + + struct mutex lock; /* Protect csi2_fmt, format_mbus, state, hs_settle */ + const struct csi2_pix_format *csi2_fmt; + struct v4l2_mbus_framefmt format_mbus[MIPI_CSI2_PADS_NUM]; + u32 state; + u32 hs_settle; + + struct regmap *phy_gpr; + u8 phy_gpr_reg; + + struct icc_path *icc_path; + s32 icc_path_bw; +}; + +/* ----------------------------------------------------------------------------- + * Format helpers + */ + +struct csi2_pix_format { + u32 code; + u8 width; +}; + +static const struct csi2_pix_format imx8mq_mipi_csi_formats[] = { + /* RAW (Bayer and greyscale) formats. */ + { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_Y8_1X8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_Y10_1X10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_Y12_1X12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SBGGR14_1X14, + .width = 14, + }, { + .code = MEDIA_BUS_FMT_SGBRG14_1X14, + .width = 14, + }, { + .code = MEDIA_BUS_FMT_SGRBG14_1X14, + .width = 14, + }, { + .code = MEDIA_BUS_FMT_SRGGB14_1X14, + .width = 14, + }, { + /* YUV formats */ + .code = MEDIA_BUS_FMT_YUYV8_2X8, + .width = 16, + }, { + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .width = 16, + } +}; + +static const struct csi2_pix_format *find_csi2_format(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(imx8mq_mipi_csi_formats); i++) + if (code == imx8mq_mipi_csi_formats[i].code) + return &imx8mq_mipi_csi_formats[i]; + return NULL; +} + +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ + +static inline void imx8mq_mipi_csi_write(struct csi_state *state, u32 reg, u32 val) +{ + writel(val, state->regs + reg); +} + +static int imx8mq_mipi_csi_sw_reset(struct csi_state *state) +{ + int ret; + + /* + * these are most likely self-clearing reset bits. to make it + * more clear, the reset-imx7 driver should implement the + * .reset() operation. + */ + ret = reset_control_assert(state->rst); + if (ret < 0) { + dev_err(state->dev, "Failed to assert resets: %d\n", ret); + return ret; + } + + return 0; +} + +static void imx8mq_mipi_csi_system_enable(struct csi_state *state, int on) +{ + if (!on) { + imx8mq_mipi_csi_write(state, CSI2RX_CFG_DISABLE_DATA_LANES, 0xf); + return; + } + + regmap_update_bits(state->phy_gpr, + state->phy_gpr_reg, + 0x3fff, + GPR_CSI2_1_RX_ENABLE | + GPR_CSI2_1_VID_INTFC_ENB | + GPR_CSI2_1_HSEL | + GPR_CSI2_1_CONT_CLK_MODE | + GPR_CSI2_1_S_PRG_RXHS_SETTLE(state->hs_settle)); +} + +static void imx8mq_mipi_csi_set_params(struct csi_state *state) +{ + int lanes = state->bus.num_data_lanes; + + imx8mq_mipi_csi_write(state, CSI2RX_CFG_NUM_LANES, lanes - 1); + imx8mq_mipi_csi_write(state, CSI2RX_CFG_DISABLE_DATA_LANES, + (0xf << lanes) & 0xf); + imx8mq_mipi_csi_write(state, CSI2RX_IRQ_MASK, CSI2RX_IRQ_MASK_ALL); + /* + * 0x180 bit 0 controls the Virtual Channel behaviour: when set the + * interface ignores the Virtual Channel (VC) field in received packets; + * when cleared it causes the interface to only accept packets whose VC + * matches the value to which VC is set at offset 0x184. + */ + imx8mq_mipi_csi_write(state, CSI2RX_CFG_VID_VC_IGNORE, 1); + imx8mq_mipi_csi_write(state, CSI2RX_CFG_VID_P_FIFO_SEND_LEVEL, + CSI2RX_SEND_LEVEL); +} + +static int imx8mq_mipi_csi_clk_enable(struct csi_state *state) +{ + return clk_bulk_prepare_enable(CSI2_NUM_CLKS, state->clks); +} + +static void imx8mq_mipi_csi_clk_disable(struct csi_state *state) +{ + clk_bulk_disable_unprepare(CSI2_NUM_CLKS, state->clks); +} + +static int imx8mq_mipi_csi_clk_get(struct csi_state *state) +{ + unsigned int i; + + for (i = 0; i < CSI2_NUM_CLKS; i++) + state->clks[i].id = imx8mq_mipi_csi_clk_id[i]; + + return devm_clk_bulk_get(state->dev, CSI2_NUM_CLKS, state->clks); +} + +static int imx8mq_mipi_csi_calc_hs_settle(struct csi_state *state) +{ + s64 link_freq; + u32 lane_rate; + unsigned long esc_clk_rate; + u32 min_ths_settle, max_ths_settle, ths_settle_ns, esc_clk_period_ns; + + /* Calculate the line rate from the pixel rate. */ + link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler, + state->csi2_fmt->width, + state->bus.num_data_lanes * 2); + if (link_freq < 0) { + dev_err(state->dev, "Unable to obtain link frequency: %d\n", + (int)link_freq); + return link_freq; + } + + lane_rate = link_freq * 2; + if (lane_rate < 80000000 || lane_rate > 1500000000) { + dev_dbg(state->dev, "Out-of-bound lane rate %u\n", lane_rate); + return -EINVAL; + } + + /* + * The D-PHY specification requires Ths-settle to be in the range + * 85ns + 6*UI to 140ns + 10*UI, with the unit interval UI being half + * the clock period. + * + * The Ths-settle value is expressed in the hardware as a multiple of + * the Esc clock period: + * + * Ths-settle = (PRG_RXHS_SETTLE + 1) * Tperiod of RxClkInEsc + * + * Due to the one cycle inaccuracy introduced by rounding, the + * documentation recommends picking a value away from the boundaries. + * Let's pick the average. + */ + esc_clk_rate = clk_get_rate(state->clks[CSI2_CLK_ESC].clk); + if (!esc_clk_rate) { + dev_err(state->dev, "Could not get esc clock rate.\n"); + return -EINVAL; + } + + dev_dbg(state->dev, "esc clk rate: %lu\n", esc_clk_rate); + esc_clk_period_ns = 1000000000 / esc_clk_rate; + + min_ths_settle = 85 + 6 * 1000000 / (lane_rate / 1000); + max_ths_settle = 140 + 10 * 1000000 / (lane_rate / 1000); + ths_settle_ns = (min_ths_settle + max_ths_settle) / 2; + + state->hs_settle = ths_settle_ns / esc_clk_period_ns - 1; + + dev_dbg(state->dev, "lane rate %u Ths_settle %u hs_settle %u\n", + lane_rate, ths_settle_ns, state->hs_settle); + + return 0; +} + +static int imx8mq_mipi_csi_start_stream(struct csi_state *state) +{ + int ret; + + ret = imx8mq_mipi_csi_sw_reset(state); + if (ret) + return ret; + + imx8mq_mipi_csi_set_params(state); + ret = imx8mq_mipi_csi_calc_hs_settle(state); + if (ret) + return ret; + + imx8mq_mipi_csi_system_enable(state, true); + + return 0; +} + +static void imx8mq_mipi_csi_stop_stream(struct csi_state *state) +{ + imx8mq_mipi_csi_system_enable(state, false); +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev operations + */ + +static struct csi_state *mipi_sd_to_csi2_state(struct v4l2_subdev *sdev) +{ + return container_of(sdev, struct csi_state, sd); +} + +static int imx8mq_mipi_csi_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + int ret = 0; + + imx8mq_mipi_csi_write(state, CSI2RX_IRQ_MASK, + CSI2RX_IRQ_MASK_ULPS_STATUS_CHANGE); + + if (enable) { + ret = pm_runtime_resume_and_get(state->dev); + if (ret < 0) + return ret; + } + + mutex_lock(&state->lock); + + if (enable) { + if (state->state & ST_SUSPENDED) { + ret = -EBUSY; + goto unlock; + } + + ret = imx8mq_mipi_csi_start_stream(state); + if (ret < 0) + goto unlock; + + ret = v4l2_subdev_call(state->src_sd, video, s_stream, 1); + if (ret < 0) + goto unlock; + + state->state |= ST_STREAMING; + } else { + v4l2_subdev_call(state->src_sd, video, s_stream, 0); + imx8mq_mipi_csi_stop_stream(state); + state->state &= ~ST_STREAMING; + } + +unlock: + mutex_unlock(&state->lock); + + if (!enable || ret < 0) + pm_runtime_put(state->dev); + + return ret; +} + +static struct v4l2_mbus_framefmt * +imx8mq_mipi_csi_get_format(struct csi_state *state, + struct v4l2_subdev_state *sd_state, + enum v4l2_subdev_format_whence which, + unsigned int pad) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_get_try_format(&state->sd, sd_state, pad); + + return &state->format_mbus[pad]; +} + +static int imx8mq_mipi_csi_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + struct v4l2_mbus_framefmt *fmt_sink; + struct v4l2_mbus_framefmt *fmt_source; + enum v4l2_subdev_format_whence which; + + which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + fmt_sink = imx8mq_mipi_csi_get_format(state, sd_state, which, + MIPI_CSI2_PAD_SINK); + + fmt_sink->code = MEDIA_BUS_FMT_SGBRG10_1X10; + fmt_sink->width = MIPI_CSI2_DEF_PIX_WIDTH; + fmt_sink->height = MIPI_CSI2_DEF_PIX_HEIGHT; + fmt_sink->field = V4L2_FIELD_NONE; + + fmt_sink->colorspace = V4L2_COLORSPACE_RAW; + fmt_sink->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt_sink->colorspace); + fmt_sink->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt_sink->colorspace); + fmt_sink->quantization = + V4L2_MAP_QUANTIZATION_DEFAULT(false, fmt_sink->colorspace, + fmt_sink->ycbcr_enc); + + fmt_source = imx8mq_mipi_csi_get_format(state, sd_state, which, + MIPI_CSI2_PAD_SOURCE); + *fmt_source = *fmt_sink; + + return 0; +} + +static int imx8mq_mipi_csi_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *sdformat) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + struct v4l2_mbus_framefmt *fmt; + + fmt = imx8mq_mipi_csi_get_format(state, sd_state, sdformat->which, + sdformat->pad); + + mutex_lock(&state->lock); + + sdformat->format = *fmt; + + mutex_unlock(&state->lock); + + return 0; +} + +static int imx8mq_mipi_csi_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + + /* + * We can't transcode in any way, the source format is identical + * to the sink format. + */ + if (code->pad == MIPI_CSI2_PAD_SOURCE) { + struct v4l2_mbus_framefmt *fmt; + + if (code->index > 0) + return -EINVAL; + + fmt = imx8mq_mipi_csi_get_format(state, sd_state, code->which, + code->pad); + code->code = fmt->code; + return 0; + } + + if (code->pad != MIPI_CSI2_PAD_SINK) + return -EINVAL; + + if (code->index >= ARRAY_SIZE(imx8mq_mipi_csi_formats)) + return -EINVAL; + + code->code = imx8mq_mipi_csi_formats[code->index].code; + + return 0; +} + +static int imx8mq_mipi_csi_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *sdformat) +{ + struct csi_state *state = mipi_sd_to_csi2_state(sd); + struct csi2_pix_format const *csi2_fmt; + struct v4l2_mbus_framefmt *fmt; + + /* + * The device can't transcode in any way, the source format can't be + * modified. + */ + if (sdformat->pad == MIPI_CSI2_PAD_SOURCE) + return imx8mq_mipi_csi_get_fmt(sd, sd_state, sdformat); + + if (sdformat->pad != MIPI_CSI2_PAD_SINK) + return -EINVAL; + + csi2_fmt = find_csi2_format(sdformat->format.code); + if (!csi2_fmt) + csi2_fmt = &imx8mq_mipi_csi_formats[0]; + + fmt = imx8mq_mipi_csi_get_format(state, sd_state, sdformat->which, + sdformat->pad); + + mutex_lock(&state->lock); + + fmt->code = csi2_fmt->code; + fmt->width = sdformat->format.width; + fmt->height = sdformat->format.height; + + sdformat->format = *fmt; + + /* Propagate the format from sink to source. */ + fmt = imx8mq_mipi_csi_get_format(state, sd_state, sdformat->which, + MIPI_CSI2_PAD_SOURCE); + *fmt = sdformat->format; + + /* Store the CSI2 format descriptor for active formats. */ + if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) + state->csi2_fmt = csi2_fmt; + + mutex_unlock(&state->lock); + + return 0; +} + +static const struct v4l2_subdev_video_ops imx8mq_mipi_csi_video_ops = { + .s_stream = imx8mq_mipi_csi_s_stream, +}; + +static const struct v4l2_subdev_pad_ops imx8mq_mipi_csi_pad_ops = { + .init_cfg = imx8mq_mipi_csi_init_cfg, + .enum_mbus_code = imx8mq_mipi_csi_enum_mbus_code, + .get_fmt = imx8mq_mipi_csi_get_fmt, + .set_fmt = imx8mq_mipi_csi_set_fmt, +}; + +static const struct v4l2_subdev_ops imx8mq_mipi_csi_subdev_ops = { + .video = &imx8mq_mipi_csi_video_ops, + .pad = &imx8mq_mipi_csi_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +static const struct media_entity_operations imx8mq_mipi_csi_entity_ops = { + .link_validate = v4l2_subdev_link_validate, + .get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1, +}; + +/* ----------------------------------------------------------------------------- + * Async subdev notifier + */ + +static struct csi_state * +mipi_notifier_to_csi2_state(struct v4l2_async_notifier *n) +{ + return container_of(n, struct csi_state, notifier); +} + +static int imx8mq_mipi_csi_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + struct csi_state *state = mipi_notifier_to_csi2_state(notifier); + struct media_pad *sink = &state->sd.entity.pads[MIPI_CSI2_PAD_SINK]; + + state->src_sd = sd; + + return v4l2_create_fwnode_links_to_pad(sd, sink, MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); +} + +static const struct v4l2_async_notifier_operations imx8mq_mipi_csi_notify_ops = { + .bound = imx8mq_mipi_csi_notify_bound, +}; + +static int imx8mq_mipi_csi_async_register(struct csi_state *state) +{ + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct v4l2_async_subdev *asd; + struct fwnode_handle *ep; + unsigned int i; + int ret; + + v4l2_async_notifier_init(&state->notifier); + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(state->dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!ep) + return -ENOTCONN; + + ret = v4l2_fwnode_endpoint_parse(ep, &vep); + if (ret) + goto err_parse; + + for (i = 0; i < vep.bus.mipi_csi2.num_data_lanes; ++i) { + if (vep.bus.mipi_csi2.data_lanes[i] != i + 1) { + dev_err(state->dev, + "data lanes reordering is not supported"); + ret = -EINVAL; + goto err_parse; + } + } + + state->bus = vep.bus.mipi_csi2; + + dev_dbg(state->dev, "data lanes: %d flags: 0x%08x\n", + state->bus.num_data_lanes, + state->bus.flags); + + asd = v4l2_async_notifier_add_fwnode_remote_subdev(&state->notifier, + ep, struct v4l2_async_subdev); + if (IS_ERR(asd)) { + ret = PTR_ERR(asd); + goto err_parse; + } + + fwnode_handle_put(ep); + + state->notifier.ops = &imx8mq_mipi_csi_notify_ops; + + ret = v4l2_async_subdev_notifier_register(&state->sd, &state->notifier); + if (ret) + return ret; + + return v4l2_async_register_subdev(&state->sd); + +err_parse: + fwnode_handle_put(ep); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Suspend/resume + */ + +static int imx8mq_mipi_csi_pm_suspend(struct device *dev, bool runtime) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + int ret = 0; + + mutex_lock(&state->lock); + + if (state->state & ST_POWERED) { + imx8mq_mipi_csi_stop_stream(state); + imx8mq_mipi_csi_clk_disable(state); + state->state &= ~ST_POWERED; + if (!runtime) + state->state |= ST_SUSPENDED; + } + + mutex_unlock(&state->lock); + + ret = icc_set_bw(state->icc_path, 0, 0); + if (ret) + dev_err(dev, "icc_set_bw failed with %d\n", ret); + + return ret ? -EAGAIN : 0; +} + +static int imx8mq_mipi_csi_pm_resume(struct device *dev, bool runtime) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + int ret = 0; + + ret = icc_set_bw(state->icc_path, 0, state->icc_path_bw); + if (ret) { + dev_err(dev, "icc_set_bw failed with %d\n", ret); + return ret; + } + + mutex_lock(&state->lock); + + if (!runtime && !(state->state & ST_SUSPENDED)) + goto unlock; + + if (!(state->state & ST_POWERED)) { + state->state |= ST_POWERED; + ret = imx8mq_mipi_csi_clk_enable(state); + } + if (state->state & ST_STREAMING) { + ret = imx8mq_mipi_csi_start_stream(state); + if (ret) + goto unlock; + } + + state->state &= ~ST_SUSPENDED; + +unlock: + mutex_unlock(&state->lock); + + return ret ? -EAGAIN : 0; +} + +static int __maybe_unused imx8mq_mipi_csi_suspend(struct device *dev) +{ + return imx8mq_mipi_csi_pm_suspend(dev, false); +} + +static int __maybe_unused imx8mq_mipi_csi_resume(struct device *dev) +{ + return imx8mq_mipi_csi_pm_resume(dev, false); +} + +static int __maybe_unused imx8mq_mipi_csi_runtime_suspend(struct device *dev) +{ + return imx8mq_mipi_csi_pm_suspend(dev, true); +} + +static int __maybe_unused imx8mq_mipi_csi_runtime_resume(struct device *dev) +{ + return imx8mq_mipi_csi_pm_resume(dev, true); +} + +static const struct dev_pm_ops imx8mq_mipi_csi_pm_ops = { + SET_RUNTIME_PM_OPS(imx8mq_mipi_csi_runtime_suspend, + imx8mq_mipi_csi_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(imx8mq_mipi_csi_suspend, imx8mq_mipi_csi_resume) +}; + +/* ----------------------------------------------------------------------------- + * Probe/remove & platform driver + */ + +static int imx8mq_mipi_csi_subdev_init(struct csi_state *state) +{ + struct v4l2_subdev *sd = &state->sd; + + v4l2_subdev_init(sd, &imx8mq_mipi_csi_subdev_ops); + sd->owner = THIS_MODULE; + snprintf(sd->name, sizeof(sd->name), "%s %s", + MIPI_CSI2_SUBDEV_NAME, dev_name(state->dev)); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->entity.ops = &imx8mq_mipi_csi_entity_ops; + + sd->dev = state->dev; + + state->csi2_fmt = &imx8mq_mipi_csi_formats[0]; + imx8mq_mipi_csi_init_cfg(sd, NULL); + + state->pads[MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK + | MEDIA_PAD_FL_MUST_CONNECT; + state->pads[MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE + | MEDIA_PAD_FL_MUST_CONNECT; + return media_entity_pads_init(&sd->entity, MIPI_CSI2_PADS_NUM, + state->pads); +} + +static void imx8mq_mipi_csi_release_icc(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + + icc_put(state->icc_path); +} + +static int imx8mq_mipi_csi_init_icc(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(&pdev->dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + + /* Optional interconnect request */ + state->icc_path = of_icc_get(&pdev->dev, "dram"); + if (IS_ERR_OR_NULL(state->icc_path)) + return PTR_ERR_OR_ZERO(state->icc_path); + + state->icc_path_bw = MBps_to_icc(700); + + return 0; +} + +static int imx8mq_mipi_csi_parse_dt(struct csi_state *state) +{ + struct device *dev = state->dev; + struct device_node *np = state->dev->of_node; + struct device_node *node; + phandle ph; + u32 out_val[2]; + int ret = 0; + + state->rst = devm_reset_control_array_get_exclusive(dev); + if (IS_ERR(state->rst)) { + dev_err(dev, "Failed to get reset: %pe\n", state->rst); + return PTR_ERR(state->rst); + } + + ret = of_property_read_u32_array(np, "fsl,mipi-phy-gpr", out_val, + ARRAY_SIZE(out_val)); + if (ret) { + dev_err(dev, "no fsl,mipi-phy-gpr property found: %d\n", ret); + return ret; + } + + ph = *out_val; + + node = of_find_node_by_phandle(ph); + if (!node) { + dev_err(dev, "Error finding node by phandle\n"); + return -ENODEV; + } + state->phy_gpr = syscon_node_to_regmap(node); + of_node_put(node); + if (IS_ERR(state->phy_gpr)) { + dev_err(dev, "failed to get gpr regmap: %pe\n", state->phy_gpr); + return PTR_ERR(state->phy_gpr); + } + + state->phy_gpr_reg = out_val[1]; + dev_dbg(dev, "phy gpr register set to 0x%x\n", state->phy_gpr_reg); + + return ret; +} + +static int imx8mq_mipi_csi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct csi_state *state; + int ret; + + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + state->dev = dev; + + ret = imx8mq_mipi_csi_parse_dt(state); + if (ret < 0) { + dev_err(dev, "Failed to parse device tree: %d\n", ret); + return ret; + } + + /* Acquire resources. */ + state->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(state->regs)) + return PTR_ERR(state->regs); + + ret = imx8mq_mipi_csi_clk_get(state); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, &state->sd); + + mutex_init(&state->lock); + + ret = imx8mq_mipi_csi_subdev_init(state); + if (ret < 0) + goto mutex; + + ret = imx8mq_mipi_csi_init_icc(pdev); + if (ret) + goto mutex; + + /* Enable runtime PM. */ + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = imx8mq_mipi_csi_pm_resume(dev, true); + if (ret < 0) + goto icc; + } + + ret = imx8mq_mipi_csi_async_register(state); + if (ret < 0) + goto cleanup; + + return 0; + +cleanup: + pm_runtime_disable(&pdev->dev); + imx8mq_mipi_csi_pm_suspend(&pdev->dev, true); + + media_entity_cleanup(&state->sd.entity); + v4l2_async_notifier_unregister(&state->notifier); + v4l2_async_notifier_cleanup(&state->notifier); + v4l2_async_unregister_subdev(&state->sd); +icc: + imx8mq_mipi_csi_release_icc(pdev); +mutex: + mutex_destroy(&state->lock); + + return ret; +} + +static int imx8mq_mipi_csi_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + + v4l2_async_notifier_unregister(&state->notifier); + v4l2_async_notifier_cleanup(&state->notifier); + v4l2_async_unregister_subdev(&state->sd); + + pm_runtime_disable(&pdev->dev); + imx8mq_mipi_csi_pm_suspend(&pdev->dev, true); + media_entity_cleanup(&state->sd.entity); + mutex_destroy(&state->lock); + pm_runtime_set_suspended(&pdev->dev); + imx8mq_mipi_csi_release_icc(pdev); + + return 0; +} + +static const struct of_device_id imx8mq_mipi_csi_of_match[] = { + { .compatible = "fsl,imx8mq-mipi-csi2", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, imx8mq_mipi_csi_of_match); + +static struct platform_driver imx8mq_mipi_csi_driver = { + .probe = imx8mq_mipi_csi_probe, + .remove = imx8mq_mipi_csi_remove, + .driver = { + .of_match_table = imx8mq_mipi_csi_of_match, + .name = MIPI_CSI2_DRIVER_NAME, + .pm = &imx8mq_mipi_csi_pm_ops, + }, +}; + +module_platform_driver(imx8mq_mipi_csi_driver); + +MODULE_DESCRIPTION("i.MX8MQ MIPI CSI-2 receiver driver"); +MODULE_AUTHOR("Martin Kepplinger "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx8mq-mipi-csi2"); From 4108b3e6db31acc4c68133290bbcc87d4db905c9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 23 Jul 2021 10:22:59 +0200 Subject: [PATCH 183/195] media: v4l2-dv-timings.c: fix wrong condition in two for-loops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These for-loops should test against v4l2_dv_timings_presets[i].bt.width, not if i < v4l2_dv_timings_presets[i].bt.width. Luckily nothing ever broke, since the smallest width is still a lot higher than the total number of presets, but it is wrong. The last item in the presets array is all 0, so the for-loop must stop when it reaches that sentinel. Signed-off-by: Hans Verkuil Reported-by: Krzysztof Hałasa Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 230d65a642178..af48705c704f8 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -196,7 +196,7 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, if (!v4l2_valid_dv_timings(t, cap, fnc, fnc_handle)) return false; - for (i = 0; i < v4l2_dv_timings_presets[i].bt.width; i++) { + for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap, fnc, fnc_handle) && v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i, @@ -218,7 +218,7 @@ bool v4l2_find_dv_timings_cea861_vic(struct v4l2_dv_timings *t, u8 vic) { unsigned int i; - for (i = 0; i < v4l2_dv_timings_presets[i].bt.width; i++) { + for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; From 95d453661172db82ddf2a1864b0ab41ff7725e03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Mon, 26 Jul 2021 12:42:49 +0200 Subject: [PATCH 184/195] media: Fix cosmetic error in TDA1997x driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The colon isn't followed by anything here. Signed-off-by: Krzysztof Hałasa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda1997x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 3a191e257fad0..71194746c874f 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -563,7 +563,7 @@ static void tda1997x_delayed_work_enable_hpd(struct work_struct *work) delayed_work_enable_hpd); struct v4l2_subdev *sd = &state->sd; - v4l2_dbg(2, debug, sd, "%s:\n", __func__); + v4l2_dbg(2, debug, sd, "%s\n", __func__); /* Set HPD high */ tda1997x_manual_hpd(sd, HPD_HIGH_OTHER); From 7dee1030871a48d4f3c5a74227a4b4188463479a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Mon, 26 Jul 2021 12:46:28 +0200 Subject: [PATCH 185/195] media: TDA1997x: fix tda1997x_query_dv_timings() return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correctly propagate the tda1997x_detect_std error value. Signed-off-by: Krzysztof Hałasa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda1997x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 71194746c874f..98b7c39e3e9b6 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -1695,14 +1695,15 @@ static int tda1997x_query_dv_timings(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings) { struct tda1997x_state *state = to_state(sd); + int ret; v4l_dbg(1, debug, state->client, "%s\n", __func__); memset(timings, 0, sizeof(struct v4l2_dv_timings)); mutex_lock(&state->lock); - tda1997x_detect_std(state, timings); + ret = tda1997x_detect_std(state, timings); mutex_unlock(&state->lock); - return 0; + return ret; } static const struct v4l2_subdev_video_ops tda1997x_video_ops = { From 5cdd19bbad75f6cf1c44ac494b92a3b8d8826001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Mon, 26 Jul 2021 12:49:30 +0200 Subject: [PATCH 186/195] media: TDA1997x: report -ENOLINK after disconnecting HDMI source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TD1997x chip retains vper, hper and hsper register values when the HDMI source is disconnected. Use a different means of checking if the link is still valid. Signed-off-by: Krzysztof Hałasa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda1997x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c index 98b7c39e3e9b6..6070aaf0b32ea 100644 --- a/drivers/media/i2c/tda1997x.c +++ b/drivers/media/i2c/tda1997x.c @@ -1107,7 +1107,8 @@ tda1997x_detect_std(struct tda1997x_state *state, hper = io_read16(sd, REG_H_PER) & MASK_HPER; hsper = io_read16(sd, REG_HS_WIDTH) & MASK_HSWIDTH; v4l2_dbg(1, debug, sd, "Signal Timings: %u/%u/%u\n", vper, hper, hsper); - if (!vper || !hper || !hsper) + + if (!state->input_detect[0] && !state->input_detect[1]) return -ENOLINK; for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) { From c8b263937c489ec536193bbe48d810118a387e12 Mon Sep 17 00:00:00 2001 From: Deborah Brouwer Date: Wed, 28 Jul 2021 07:56:16 +0200 Subject: [PATCH 187/195] media: cec-pin: rename timer overrun variables The cec pin timer overruns are measured in microseconds, but the variable names include the millisecond symbol "ms". To avoid confusion, replace "ms" with "us" in the variable names and printed status message. Signed-off-by: Deborah Brouwer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/core/cec-pin-priv.h | 4 ++-- drivers/media/cec/core/cec-pin.c | 20 ++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/cec/core/cec-pin-priv.h b/drivers/media/cec/core/cec-pin-priv.h index f423db8855d9e..fb101f15865c8 100644 --- a/drivers/media/cec/core/cec-pin-priv.h +++ b/drivers/media/cec/core/cec-pin-priv.h @@ -209,8 +209,8 @@ struct cec_pin { u32 work_pin_events_dropped_cnt; ktime_t timer_ts; u32 timer_cnt; - u32 timer_100ms_overruns; - u32 timer_300ms_overruns; + u32 timer_100us_overruns; + u32 timer_300us_overruns; u32 timer_max_overrun; u32 timer_sum_overrun; diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c index f006bd8eec63c..8c613aa649c6f 100644 --- a/drivers/media/cec/core/cec-pin.c +++ b/drivers/media/cec/core/cec-pin.c @@ -854,9 +854,9 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) if (delta > 100 && pin->state != CEC_ST_IDLE) { /* Keep track of timer overruns */ pin->timer_sum_overrun += delta; - pin->timer_100ms_overruns++; + pin->timer_100us_overruns++; if (delta > 300) - pin->timer_300ms_overruns++; + pin->timer_300us_overruns++; if (delta > pin->timer_max_overrun) pin->timer_max_overrun = delta; } @@ -1207,15 +1207,15 @@ static void cec_pin_adap_status(struct cec_adapter *adap, seq_printf(file, "cec pin events dropped: %u\n", pin->work_pin_events_dropped_cnt); seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed); - if (pin->timer_100ms_overruns) { - seq_printf(file, "timer overruns > 100ms: %u of %u\n", - pin->timer_100ms_overruns, pin->timer_cnt); - seq_printf(file, "timer overruns > 300ms: %u of %u\n", - pin->timer_300ms_overruns, pin->timer_cnt); + if (pin->timer_100us_overruns) { + seq_printf(file, "timer overruns > 100us: %u of %u\n", + pin->timer_100us_overruns, pin->timer_cnt); + seq_printf(file, "timer overruns > 300us: %u of %u\n", + pin->timer_300us_overruns, pin->timer_cnt); seq_printf(file, "max timer overrun: %u usecs\n", pin->timer_max_overrun); seq_printf(file, "avg timer overrun: %u usecs\n", - pin->timer_sum_overrun / pin->timer_100ms_overruns); + pin->timer_sum_overrun / pin->timer_100us_overruns); } if (pin->rx_start_bit_low_too_short_cnt) seq_printf(file, @@ -1245,8 +1245,8 @@ static void cec_pin_adap_status(struct cec_adapter *adap, seq_printf(file, "tx detected low drive: %u\n", pin->tx_low_drive_cnt); pin->work_pin_events_dropped_cnt = 0; pin->timer_cnt = 0; - pin->timer_100ms_overruns = 0; - pin->timer_300ms_overruns = 0; + pin->timer_100us_overruns = 0; + pin->timer_300us_overruns = 0; pin->timer_max_overrun = 0; pin->timer_sum_overrun = 0; pin->rx_start_bit_low_too_short_cnt = 0; From 38367073c796a37a61549b1f66a71b3adb03802d Mon Sep 17 00:00:00 2001 From: Evgeny Novikov Date: Wed, 28 Jul 2021 16:44:32 +0200 Subject: [PATCH 188/195] media: tegra-cec: Handle errors of clk_prepare_enable() tegra_cec_probe() and tegra_cec_resume() ignored possible errors of clk_prepare_enable(). The patch fixes this. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Evgeny Novikov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/platform/tegra/tegra_cec.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/cec/platform/tegra/tegra_cec.c b/drivers/media/cec/platform/tegra/tegra_cec.c index 1ac0c70a59818..5e907395ca2e5 100644 --- a/drivers/media/cec/platform/tegra/tegra_cec.c +++ b/drivers/media/cec/platform/tegra/tegra_cec.c @@ -366,7 +366,11 @@ static int tegra_cec_probe(struct platform_device *pdev) return -ENOENT; } - clk_prepare_enable(cec->clk); + ret = clk_prepare_enable(cec->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to prepare clock for CEC\n"); + return ret; + } /* set context info. */ cec->dev = &pdev->dev; @@ -446,9 +450,7 @@ static int tegra_cec_resume(struct platform_device *pdev) dev_notice(&pdev->dev, "Resuming\n"); - clk_prepare_enable(cec->clk); - - return 0; + return clk_prepare_enable(cec->clk); } #endif From 331e06bbde5856059b7a6bb183f12878ed4decb1 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Wed, 7 Jul 2021 09:45:17 +0200 Subject: [PATCH 189/195] media: venus: hfi: fix return value check in sys_get_prop_image_version() In case of error, the function qcom_smem_get() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Fixes: d566e78dd6af ("media: venus : hfi: add venus image info into smem") Reported-by: Hulk Robot Signed-off-by: Zhen Lei Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi_msgs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index d9fde66f6fa8c..9a2bdb002edcc 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -261,7 +261,7 @@ sys_get_prop_image_version(struct device *dev, smem_tbl_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_IMG_VER_TBL, &smem_blk_sz); - if (smem_tbl_ptr && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ) + if (!IS_ERR(smem_tbl_ptr) && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ) memcpy(smem_tbl_ptr + SMEM_IMG_OFFSET_VENUS, img_ver, VER_STR_SZ); } From 09ea9719a423fc675d40dd05407165e161ea0c48 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 9 Jul 2021 14:30:25 +0200 Subject: [PATCH 190/195] media: venus: venc: Fix potential null pointer dereference on pointer fmt Currently the call to find_format can potentially return a NULL to fmt and the nullpointer is later dereferenced on the assignment of pixmp->num_planes = fmt->num_planes. Fix this by adding a NULL pointer check and returning NULL for the failure case. Addresses-Coverity: ("Dereference null return") Fixes: aaaa93eda64b ("[media] media: venus: venc: add video encoder files") Signed-off-by: Colin Ian King Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 8dd49d4f124cb..1d62e38065d62 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -183,6 +183,8 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) else return NULL; fmt = find_format(inst, pixmp->pixelformat, f->type); + if (!fmt) + return NULL; } pixmp->width = clamp(pixmp->width, frame_width_min(inst), From 1ac61faf6ebbce59fccbb53d7faf25576e9897ab Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Tue, 6 Jul 2021 18:21:22 +0200 Subject: [PATCH 191/195] media: venus: helper: do not set constrained parameters for UBWC Plane constraints firmware interface is to override the default alignment for a given color format. By default venus hardware has alignments as 128x32, but NV12 was defined differently to meet various usecases. Compressed NV12 has always been aligned as 128x32, hence not needed to override the default alignment. Fixes: bc28936bbba9 ("media: venus: helpers, hfi, vdec: Set actual plane constraints to FW") Signed-off-by: Mansur Alisha Shaik Reviewed-by: Bryan O'Donoghue Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/helpers.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 1fe6d463dc993..8012f5c7bf344 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -1137,6 +1137,9 @@ int venus_helper_set_format_constraints(struct venus_inst *inst) if (!IS_V6(inst->core)) return 0; + if (inst->opb_fmt == HFI_COLOR_FORMAT_NV12_UBWC) + return 0; + pconstraint.buffer_type = HFI_BUFFER_OUTPUT2; pconstraint.num_planes = 2; pconstraint.plane_format[0].stride_multiples = 128; From ea9f91199ca99dd9b3fba004b7614eed233ba1ac Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Tue, 22 Jun 2021 13:39:56 +0200 Subject: [PATCH 192/195] media: docs: ext-ctrls-codec: Document cyclic intra-refresh zero control value In all drivers _CYCLIC_INTRA_REFRESH_MB default control value is zero which means that the macroblocks will not be intra-refreshed. Document this _CYCLIC_INTRA_REFRESH_MB control behaviour in control description. Acked-by: Hans Verkuil Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index dc096a5562cdf..999b2360cef83 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1174,7 +1174,9 @@ enum v4l2_mpeg_video_h264_entropy_mode - Cyclic intra macroblock refresh. This is the number of continuous macroblocks refreshed every frame. Each frame a successive set of macroblocks is refreshed until the cycle completes and starts from - the top of the frame. Applicable to H264, H263 and MPEG4 encoder. + the top of the frame. Setting this control to zero means that + macroblocks will not be refreshed. + Applicable to H264, H263 and MPEG4 encoder. ``V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE (boolean)`` Frame level rate control enable. If this control is disabled then From 9d5adeecc409365e45cd89657f0392d0dd5c217f Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Tue, 22 Jun 2021 13:39:57 +0200 Subject: [PATCH 193/195] media: v4l2-ctrls: Add intra-refresh period control Add a control to set intra-refresh period. Acked-by: Hans Verkuil Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 17 ++++++++++++++++- drivers/media/v4l2-core/v4l2-ctrls-defs.c | 2 ++ include/uapi/linux/v4l2-controls.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index 999b2360cef83..976d34445a246 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -1175,9 +1175,24 @@ enum v4l2_mpeg_video_h264_entropy_mode - macroblocks refreshed every frame. Each frame a successive set of macroblocks is refreshed until the cycle completes and starts from the top of the frame. Setting this control to zero means that - macroblocks will not be refreshed. + macroblocks will not be refreshed. Note that this control will not + take effect when ``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD`` control + is set to non zero value. Applicable to H264, H263 and MPEG4 encoder. +``V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD (integer)`` + Intra macroblock refresh period. This sets the period to refresh + the whole frame. In other words, this defines the number of frames + for which the whole frame will be intra-refreshed. An example: + setting period to 1 means that the whole frame will be refreshed, + setting period to 2 means that the half of macroblocks will be + intra-refreshed on frameX and the other half of macroblocks + will be refreshed in frameX + 1 and so on. Setting the period to + zero means no period is specified. + Note that if the client sets this control to non zero value the + ``V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB`` control shall be + ignored. Applicable to H264 and HEVC encoders. + ``V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE (boolean)`` Frame level rate control enable. If this control is disabled then the quantization parameter for each frame type is constant and set diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index b6344bbf1e006..421300e13a416 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -833,6 +833,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: return "Decoder Slice Interface"; case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: return "MPEG4 Loop Filter Enable"; case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: return "Number of Intra Refresh MBs"; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: return "Intra Refresh Period"; case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: return "Frame Level Rate Control Enable"; case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control"; case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode"; @@ -1258,6 +1259,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: *type = V4L2_CTRL_TYPE_INTEGER; break; case V4L2_CID_MPEG_VIDEO_LTR_COUNT: diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index fdf97a6d7d18a..5532b5f684935 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -435,6 +435,7 @@ enum v4l2_mpeg_video_multi_slice_mode { #define V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX (V4L2_CID_CODEC_BASE+233) #define V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES (V4L2_CID_CODEC_BASE+234) #define V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR (V4L2_CID_CODEC_BASE+235) +#define V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD (V4L2_CID_CODEC_BASE+236) /* CIDs for the MPEG-2 Part 2 (H.262) codec */ #define V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL (V4L2_CID_CODEC_BASE+270) From f7a3d3dc5831df6f898a5ae2a6ea1d221ea95c8a Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Tue, 22 Jun 2021 13:39:58 +0200 Subject: [PATCH 194/195] media: venus: venc: Add support for intra-refresh period Add support for intra-refresh period v4l2 control and drop cyclic intra-refresh macroblock control in the same time. Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.h | 1 + drivers/media/platform/qcom/venus/venc.c | 26 +++++++++++++++++++ .../media/platform/qcom/venus/venc_ctrls.c | 14 +++++----- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 8df2d497d7067..df9f79f5b164f 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -256,6 +256,7 @@ struct venc_controls { u32 header_mode; bool aud_enable; + u32 intra_refresh_period; struct { u32 h264; diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 1d62e38065d62..a027495398ed7 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -549,6 +549,7 @@ static int venc_set_properties(struct venus_inst *inst) struct hfi_quantization_range quant_range; struct hfi_enable en; struct hfi_ltr_mode ltr_mode; + struct hfi_intra_refresh intra_refresh = {}; u32 ptype, rate_control, bitrate; u32 profile, level; int ret; @@ -804,6 +805,31 @@ static int venc_set_properties(struct venus_inst *inst) en.enable = 1; ret = hfi_session_set_property(inst, ptype, &en); + } + + if ((inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || + inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) && + (rate_control == HFI_RATE_CONTROL_CBR_VFR || + rate_control == HFI_RATE_CONTROL_CBR_CFR)) { + intra_refresh.mode = HFI_INTRA_REFRESH_NONE; + intra_refresh.cir_mbs = 0; + + if (ctr->intra_refresh_period) { + u32 mbs; + + mbs = ALIGN(inst->width, 16) * ALIGN(inst->height, 16); + mbs /= 16 * 16; + if (mbs % ctr->intra_refresh_period) + mbs++; + mbs /= ctr->intra_refresh_period; + + intra_refresh.mode = HFI_INTRA_REFRESH_RANDOM; + intra_refresh.cir_mbs = mbs; + } + + ptype = HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH; + + ret = hfi_session_set_property(inst, ptype, &intra_refresh); if (ret) return ret; } diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index 637c92f6c5be0..eb10affc62771 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -17,7 +17,6 @@ #define SLICE_BYTE_SIZE_MAX 1024 #define SLICE_BYTE_SIZE_MIN 1024 #define SLICE_MB_SIZE_MAX 300 -#define INTRA_REFRESH_MBS_MAX 300 #define AT_SLICE_BOUNDARY \ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY #define MAX_LTR_FRAME_COUNT 4 @@ -227,8 +226,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) } mutex_unlock(&inst->lock); break; - case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: - break; case V4L2_CID_MPEG_VIDEO_GOP_SIZE: ret = venc_calc_bpframes(ctrl->val, ctr->num_b_frames, &bframes, &ctr->num_p_frames); @@ -319,6 +316,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: ctr->mastering = *ctrl->p_new.p_hdr10_mastering; break; + case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: + ctr->intra_refresh_period = ctrl->val; + break; default: return -EINVAL; } @@ -502,10 +502,6 @@ int venc_ctrl_init(struct venus_inst *inst) v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0); - v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, - V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, - 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, 30); @@ -564,6 +560,10 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY, v4l2_ctrl_ptr_create(NULL)); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, 0, + ((4096 * 2304) >> 8), 1, 0); + ret = inst->ctrl_handler.error; if (ret) goto err; From bfee75f73c37a2f46a6326eaa06f5db701f76f01 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Thu, 29 Jul 2021 13:30:40 +0200 Subject: [PATCH 195/195] media: venus: venc: add support for V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM control Add support for V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM control for H264 high profile and constrained high profile. Signed-off-by: Mansur Alisha Shaik Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.h | 1 + drivers/media/platform/qcom/venus/hfi_cmds.c | 8 +++++++ .../media/platform/qcom/venus/hfi_helper.h | 5 ++++ drivers/media/platform/qcom/venus/venc.c | 12 ++++++++++ .../media/platform/qcom/venus/venc_ctrls.c | 24 ++++++++++++++++++- 5 files changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index df9f79f5b164f..5ec851115eca8 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -234,6 +234,7 @@ struct venc_controls { u32 h264_loop_filter_mode; s32 h264_loop_filter_alpha; s32 h264_loop_filter_beta; + u32 h264_8x8_transform; u32 hevc_i_qp; u32 hevc_p_qp; diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index f510247869916..60f4b8e4b8d02 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -1239,6 +1239,14 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt, break; } + case HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8: { + struct hfi_h264_8x8_transform *in = pdata, *tm = prop_data; + + tm->enable_type = in->enable_type; + pkt->shdr.hdr.size += sizeof(u32) + sizeof(*tm); + break; + } + case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE: case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER: case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE: diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index b0a9beb4163c4..bec4feb63ceb1 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -507,6 +507,7 @@ #define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES 0x2005020 #define HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC 0x2005021 #define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY 0x2005023 +#define HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8 0x2005025 #define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER 0x2005026 #define HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP 0x2005027 #define HFI_PROPERTY_PARAM_VENC_INITIAL_QP 0x2005028 @@ -562,6 +563,10 @@ struct hfi_bitrate { u32 layer_id; }; +struct hfi_h264_8x8_transform { + u32 enable_type; +}; + #define HFI_CAPABILITY_FRAME_WIDTH 0x01 #define HFI_CAPABILITY_FRAME_HEIGHT 0x02 #define HFI_CAPABILITY_MBS_PER_FRAME 0x03 diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index a027495398ed7..bc1c42dd53c04 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -570,6 +570,7 @@ static int venc_set_properties(struct venus_inst *inst) struct hfi_h264_vui_timing_info info; struct hfi_h264_entropy_control entropy; struct hfi_h264_db_control deblock; + struct hfi_h264_8x8_transform h264_transform; ptype = HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO; info.enable = 1; @@ -600,6 +601,17 @@ static int venc_set_properties(struct venus_inst *inst) ret = hfi_session_set_property(inst, ptype, &deblock); if (ret) return ret; + + ptype = HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8; + h264_transform.enable_type = 0; + if (ctr->profile.h264 == HFI_H264_PROFILE_HIGH || + ctr->profile.h264 == HFI_H264_PROFILE_CONSTRAINED_HIGH) + h264_transform.enable_type = ctr->h264_8x8_transform; + + ret = hfi_session_set_property(inst, ptype, &h264_transform); + if (ret) + return ret; + } if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index eb10affc62771..1ada42df314dc 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -319,6 +319,25 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: ctr->intra_refresh_period = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + if (ctr->profile.h264 != HFI_H264_PROFILE_HIGH && + ctr->profile.h264 != HFI_H264_PROFILE_CONSTRAINED_HIGH) + return -EINVAL; + + /* + * In video firmware, 8x8 transform is supported only for + * high profile(HP) and constrained high profile(CHP). + * If client wants to disable 8x8 transform for HP/CHP, + * it is better to set profile as main profile(MP). + * Because there is no difference between HP and MP + * if we disable 8x8 transform for HP. + */ + + if (ctrl->val == 0) + return -EINVAL; + + ctr->h264_8x8_transform = ctrl->val; + break; default: return -EINVAL; } @@ -334,7 +353,7 @@ int venc_ctrl_init(struct venus_inst *inst) { int ret; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 57); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 58); if (ret) return ret; @@ -437,6 +456,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_FRAME_MIN_QP, 1, 51, 1, 1); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, 0, 1, 1, 0); + v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP, 1, 51, 1, 1);