From 4d4389f64c5f32358f4b58e9e392ca10f14935aa Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:19 +0100 Subject: media: staging: media: zoran: move module parameter checks to zoran_probe We need to empty zoran_init() for removing it later. Furthermore, this permit to use pci_xxx instead of pr_xxx for prettier printing. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_card.c | 64 ++++++++++++++++---------------- 1 file changed, 33 insertions(+), 31 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index f259585b0689..3bc0e64f1007 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -1067,6 +1067,39 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) unsigned int nr; int err; + pci_info(pdev, "Zoran MJPEG board driver version %s\n", ZORAN_VERSION); + + /* check the parameters we have been given, adjust if necessary */ + if (v4l_nbufs < 2) + v4l_nbufs = 2; + if (v4l_nbufs > VIDEO_MAX_FRAME) + v4l_nbufs = VIDEO_MAX_FRAME; + /* The user specifies the in KB, we want them in byte (and page aligned) */ + v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); + if (v4l_bufsize < 32768) + v4l_bufsize = 32768; + /* 2 MB is arbitrary but sufficient for the maximum possible images */ + if (v4l_bufsize > 2048 * 1024) + v4l_bufsize = 2048 * 1024; + if (jpg_nbufs < 4) + jpg_nbufs = 4; + if (jpg_nbufs > BUZ_MAX_FRAME) + jpg_nbufs = BUZ_MAX_FRAME; + jpg_bufsize = PAGE_ALIGN(jpg_bufsize * 1024); + if (jpg_bufsize < 8192) + jpg_bufsize = 8192; + if (jpg_bufsize > (512 * 1024)) + jpg_bufsize = 512 * 1024; + /* Use parameter for vidmem or try to find a video card */ + if (vidmem) + pci_info(pdev, "%s: Using supplied video memory base address @ 0x%lx\n", + ZORAN_NAME, vidmem); + + /* some mainboards might not do PCI-PCI data transfer well */ + if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK)) + pci_warn(pdev, "%s: chipset does not support reliable PCI-PCI DMA\n", + ZORAN_NAME); + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) return -ENODEV; @@ -1285,37 +1318,6 @@ static int __init zoran_init(void) { int res; - pr_info("Zoran MJPEG board driver version %s\n", ZORAN_VERSION); - - /* check the parameters we have been given, adjust if necessary */ - if (v4l_nbufs < 2) - v4l_nbufs = 2; - if (v4l_nbufs > VIDEO_MAX_FRAME) - v4l_nbufs = VIDEO_MAX_FRAME; - /* The user specifies the in KB, we want them in byte (and page aligned) */ - v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); - if (v4l_bufsize < 32768) - v4l_bufsize = 32768; - /* 2 MB is arbitrary but sufficient for the maximum possible images */ - if (v4l_bufsize > 2048 * 1024) - v4l_bufsize = 2048 * 1024; - if (jpg_nbufs < 4) - jpg_nbufs = 4; - if (jpg_nbufs > BUZ_MAX_FRAME) - jpg_nbufs = BUZ_MAX_FRAME; - jpg_bufsize = PAGE_ALIGN(jpg_bufsize * 1024); - if (jpg_bufsize < 8192) - jpg_bufsize = 8192; - if (jpg_bufsize > (512 * 1024)) - jpg_bufsize = 512 * 1024; - /* Use parameter for vidmem or try to find a video card */ - if (vidmem) - pr_info("%s: Using supplied video memory base address @ 0x%lx\n", ZORAN_NAME, vidmem); - - /* some mainboards might not do PCI-PCI data transfer well */ - if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK)) - pr_warn("%s: chipset does not support reliable PCI-PCI DMA\n", ZORAN_NAME); - res = pci_register_driver(&zoran_driver); if (res) { pr_err("Unable to register ZR36057 driver\n"); -- cgit v1.2.3 From b419ee9468d9d15f3b59bb5143e808d877f91197 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:20 +0100 Subject: media: staging: media: zoran: use module_pci_driver Simplify code by using module_pci_driver() Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_card.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index 3bc0e64f1007..f1465fbf98af 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -1314,23 +1314,4 @@ static struct pci_driver zoran_driver = { .remove = zoran_remove, }; -static int __init zoran_init(void) -{ - int res; - - res = pci_register_driver(&zoran_driver); - if (res) { - pr_err("Unable to register ZR36057 driver\n"); - return res; - } - - return 0; -} - -static void __exit zoran_exit(void) -{ - pci_unregister_driver(&zoran_driver); -} - -module_init(zoran_init); -module_exit(zoran_exit); +module_pci_driver(zoran_driver); -- cgit v1.2.3 From b82cdccafd41a9c4eade57c19074ad86138b1efa Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:21 +0100 Subject: media: staging: media: zoran: rename debug module parameter All zoran module will be merged, so to prevent conflict, the debug module parameter need to be renamed Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/videocodec.c | 8 ++++---- drivers/staging/media/zoran/zr36016.c | 12 ++++++------ drivers/staging/media/zoran/zr36050.c | 8 ++++---- drivers/staging/media/zoran/zr36060.c | 9 ++++----- 4 files changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/videocodec.c b/drivers/staging/media/zoran/videocodec.c index 28031d3fd757..31019b5f377e 100644 --- a/drivers/staging/media/zoran/videocodec.c +++ b/drivers/staging/media/zoran/videocodec.c @@ -26,13 +26,13 @@ #include "videocodec.h" -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); +static int videocodec_debug; +module_param(videocodec_debug, int, 0); +MODULE_PARM_DESC(videocodec_debug, "Debug level (0-4)"); #define dprintk(num, format, args...) \ do { \ - if (debug >= num) \ + if (videocodec_debug >= num) \ printk(format, ##args); \ } while (0) diff --git a/drivers/staging/media/zoran/zr36016.c b/drivers/staging/media/zoran/zr36016.c index 9b350a885879..50605460a44b 100644 --- a/drivers/staging/media/zoran/zr36016.c +++ b/drivers/staging/media/zoran/zr36016.c @@ -22,14 +22,14 @@ /* amount of chips attached via this driver */ static int zr36016_codecs; -/* debugging is available via module parameter */ -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); +static int zr36016_debug; +module_param(zr36016_debug, int, 0); +MODULE_PARM_DESC(zr36016_debug, "Debug level (0-4)"); + #define dprintk(num, format, args...) \ do { \ - if (debug >= num) \ + if (zr36016_debug >= num) \ printk(format, ##args); \ } while (0) @@ -120,7 +120,7 @@ static u8 zr36016_read_version(struct zr36016 *ptr) static int zr36016_basic_test(struct zr36016 *ptr) { - if (debug) { + if (zr36016_debug) { int i; zr36016_writei(ptr, ZR016I_PAX_LO, 0x55); diff --git a/drivers/staging/media/zoran/zr36050.c b/drivers/staging/media/zoran/zr36050.c index c62af27f2683..4dc7927fefc3 100644 --- a/drivers/staging/media/zoran/zr36050.c +++ b/drivers/staging/media/zoran/zr36050.c @@ -32,13 +32,13 @@ static int zr36050_codecs; /* debugging is available via module parameter */ -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); +static int zr36050_debug; +module_param(zr36050_debug, int, 0); +MODULE_PARM_DESC(zr36050_debug, "Debug level (0-4)"); #define dprintk(num, format, args...) \ do { \ - if (debug >= num) \ + if (zr36050_debug >= num) \ printk(format, ##args); \ } while (0) diff --git a/drivers/staging/media/zoran/zr36060.c b/drivers/staging/media/zoran/zr36060.c index 1c3af11b5f24..7904d5b1f402 100644 --- a/drivers/staging/media/zoran/zr36060.c +++ b/drivers/staging/media/zoran/zr36060.c @@ -34,14 +34,13 @@ static bool low_bitrate; module_param(low_bitrate, bool, 0); MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate"); -/* debugging is available via module parameter */ -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); +static int zr36060_debug; +module_param(zr36060_debug, int, 0); +MODULE_PARM_DESC(zr36060_debug, "Debug level (0-4)"); #define dprintk(num, format, args...) \ do { \ - if (debug >= num) \ + if (zr36060_debug >= num) \ printk(format, ##args); \ } while (0) -- cgit v1.2.3 From 2776d278df1c1441010f576c0b441bebfabf910c Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:22 +0100 Subject: media: staging: media: zoran: add debugfs Add debugfs for displaying zoran debug and stats information. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/Kconfig | 1 + drivers/staging/media/zoran/zoran.h | 2 ++ drivers/staging/media/zoran/zoran_card.c | 36 ++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/Kconfig b/drivers/staging/media/zoran/Kconfig index 7874842033ca..6d6e4c93f873 100644 --- a/drivers/staging/media/zoran/Kconfig +++ b/drivers/staging/media/zoran/Kconfig @@ -2,6 +2,7 @@ config VIDEO_ZORAN tristate "Zoran ZR36057/36067 Video For Linux (Deprecated)" depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 depends on !ALPHA + depends on DEBUG_FS select VIDEOBUF2_DMA_CONTIG help Say Y for support for MJPEG capture cards based on the Zoran diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zoran/zoran.h index b1ad2a2b914c..981cb63ac9af 100644 --- a/drivers/staging/media/zoran/zoran.h +++ b/drivers/staging/media/zoran/zoran.h @@ -18,6 +18,7 @@ #ifndef _BUZ_H_ #define _BUZ_H_ +#include #include #include #include @@ -295,6 +296,7 @@ struct zoran { struct list_head queued_bufs; spinlock_t queued_bufs_lock; /* Protects queued_bufs */ struct zr_buffer *inuse[BUZ_NUM_STAT_COM * 2]; + struct dentry *dbgfs_dir; }; static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev) diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index f1465fbf98af..54e9ea03b88c 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -945,6 +945,8 @@ static void zoran_remove(struct pci_dev *pdev) if (!zr->initialized) goto exit_free; + debugfs_remove_recursive(zr->dbgfs_dir); + zoran_queue_exit(zr); /* unregister videocodec bus */ @@ -1051,6 +1053,37 @@ static const struct v4l2_ctrl_ops zoran_video_ctrl_ops = { .s_ctrl = zoran_video_set_ctrl, }; +static int zoran_debugfs_show(struct seq_file *seq, void *v) +{ + struct zoran *zr = seq->private; + + seq_printf(seq, "Running mode %x\n", zr->running); + seq_printf(seq, "Codec mode %x\n", zr->codec_mode); + seq_printf(seq, "Norm %llx\n", zr->norm); + seq_printf(seq, "Input %d\n", zr->input); + seq_printf(seq, "Buffersize %d\n", zr->buffer_size); + + seq_printf(seq, "V4L width %dx%d\n", zr->v4l_settings.width, zr->v4l_settings.height); + seq_printf(seq, "V4L bytesperline %d\n", zr->v4l_settings.bytesperline); + + seq_printf(seq, "JPG decimation %u\n", zr->jpg_settings.decimation); + seq_printf(seq, "JPG hor_dcm %u\n", zr->jpg_settings.hor_dcm); + seq_printf(seq, "JPG ver_dcm %u\n", zr->jpg_settings.ver_dcm); + seq_printf(seq, "JPG tmp_dcm %u\n", zr->jpg_settings.tmp_dcm); + seq_printf(seq, "JPG odd_even %u\n", zr->jpg_settings.odd_even); + seq_printf(seq, "JPG crop %dx%d %d %d\n", + zr->jpg_settings.img_x, + zr->jpg_settings.img_y, + zr->jpg_settings.img_width, + zr->jpg_settings.img_height); + + seq_printf(seq, "Prepared %u\n", zr->prepared); + seq_printf(seq, "Queued %u\n", zr->queued); + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(zoran_debugfs); + /* * Scan for a Buz card (actually for the PCI controller ZR36057), * request the irq and map the io memory @@ -1286,6 +1319,9 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) zr->map_mode = ZORAN_MAP_MODE_RAW; + zr->dbgfs_dir = debugfs_create_dir(ZR_DEVNAME(zr), NULL); + debugfs_create_file("debug", 0444, zr->dbgfs_dir, zr, + &zoran_debugfs_fops); return 0; zr_detach_vfe: -- cgit v1.2.3 From 12b65d5c4a92fb0ea6f98360da48303cbb3069b1 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:23 +0100 Subject: media: staging: media: zoran: videocode: remove procfs Now we have a debugfs, we can remove all PROCFS stuff. We keep videocodec_debugfs_show(), it will be used later Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/videocodec.c | 24 +----------------------- drivers/staging/media/zoran/videocodec.h | 3 +++ 2 files changed, 4 insertions(+), 23 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/videocodec.c b/drivers/staging/media/zoran/videocodec.c index 31019b5f377e..5bab7ba56257 100644 --- a/drivers/staging/media/zoran/videocodec.c +++ b/drivers/staging/media/zoran/videocodec.c @@ -16,14 +16,6 @@ #include #include -// kernel config is here (procfs flag) - -#ifdef CONFIG_PROC_FS -#include -#include -#include -#endif - #include "videocodec.h" static int videocodec_debug; @@ -265,8 +257,7 @@ int videocodec_unregister(const struct videocodec *codec) } EXPORT_SYMBOL(videocodec_unregister); -#ifdef CONFIG_PROC_FS -static int proc_videocodecs_show(struct seq_file *m, void *v) +int videocodec_debugfs_show(struct seq_file *m) { struct codec_list *h = codeclist_top; struct attached_list *a; @@ -293,32 +284,19 @@ static int proc_videocodecs_show(struct seq_file *m, void *v) return 0; } -#endif /* ===================== */ /* hook in driver module */ /* ===================== */ static int __init videocodec_init(void) { -#ifdef CONFIG_PROC_FS - static struct proc_dir_entry *videocodec_proc_entry; -#endif - pr_info("Linux video codec intermediate layer: %s\n", VIDEOCODEC_VERSION); -#ifdef CONFIG_PROC_FS - videocodec_proc_entry = proc_create_single("videocodecs", 0, NULL, proc_videocodecs_show); - if (!videocodec_proc_entry) - pr_err("videocodec: can't init procfs.\n"); -#endif return 0; } static void __exit videocodec_exit(void) { -#ifdef CONFIG_PROC_FS - remove_proc_entry("videocodecs", NULL); -#endif } module_init(videocodec_init); diff --git a/drivers/staging/media/zoran/videocodec.h b/drivers/staging/media/zoran/videocodec.h index 8a5003dda9f4..3a508d326049 100644 --- a/drivers/staging/media/zoran/videocodec.h +++ b/drivers/staging/media/zoran/videocodec.h @@ -123,6 +123,7 @@ M zr36055[1] 0001 0000c001 00000000 (zr36050[1]) #ifndef __LINUX_VIDEOCODEC_H #define __LINUX_VIDEOCODEC_H +#include #include #define CODEC_DO_COMPRESSION 0 @@ -305,4 +306,6 @@ extern int videocodec_unregister(const struct videocodec *); /* the other calls are directly done via the videocodec structure! */ +int videocodec_debugfs_show(struct seq_file *m); + #endif /*ifndef __LINUX_VIDEOCODEC_H */ -- cgit v1.2.3 From fe047de480ca23e59ab797465902f2bc4fd937cd Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:24 +0100 Subject: media: staging: media: zoran: merge all modules The zoran driver is split in many modules, but this lead to some problems. One of them is that load order is incorrect when everything is built-in. Having more than one module is useless, so merge all zoran modules in one. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/Kconfig | 14 ++-- drivers/staging/media/zoran/Makefile | 8 +-- drivers/staging/media/zoran/videocodec.c | 36 +--------- drivers/staging/media/zoran/videocodec.h | 1 - drivers/staging/media/zoran/zoran_card.c | 119 ++++++++++++++++++++++++++----- drivers/staging/media/zoran/zr36016.c | 13 +--- drivers/staging/media/zoran/zr36016.h | 2 + drivers/staging/media/zoran/zr36050.c | 16 +---- drivers/staging/media/zoran/zr36050.h | 2 + drivers/staging/media/zoran/zr36060.c | 14 +--- drivers/staging/media/zoran/zr36060.h | 2 + 11 files changed, 125 insertions(+), 102 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/Kconfig b/drivers/staging/media/zoran/Kconfig index 6d6e4c93f873..4067fa93d44d 100644 --- a/drivers/staging/media/zoran/Kconfig +++ b/drivers/staging/media/zoran/Kconfig @@ -15,7 +15,7 @@ config VIDEO_ZORAN module will be called zr36067. config VIDEO_ZORAN_DC30 - tristate "Pinnacle/Miro DC30(+) support" + bool "Pinnacle/Miro DC30(+) support" depends on VIDEO_ZORAN select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_VPX3220 if MEDIA_SUBDRV_AUTOSELECT @@ -25,7 +25,7 @@ config VIDEO_ZORAN_DC30 zr36050 MJPEG codec and zr36016 VFE. config VIDEO_ZORAN_ZR36060 - tristate "Zoran ZR36060" + bool "Zoran ZR36060" depends on VIDEO_ZORAN help Say Y to support Zoran boards based on 36060 chips. @@ -33,7 +33,7 @@ config VIDEO_ZORAN_ZR36060 and 33 R10 and AverMedia 6 boards. config VIDEO_ZORAN_BUZ - tristate "Iomega Buz support" + bool "Iomega Buz support" depends on VIDEO_ZORAN_ZR36060 select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT select VIDEO_SAA7185 if MEDIA_SUBDRV_AUTOSELECT @@ -41,7 +41,7 @@ config VIDEO_ZORAN_BUZ Support for the Iomega Buz MJPEG capture/playback card. config VIDEO_ZORAN_DC10 - tristate "Pinnacle/Miro DC10(+) support" + bool "Pinnacle/Miro DC10(+) support" depends on VIDEO_ZORAN_ZR36060 select VIDEO_SAA7110 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT @@ -50,7 +50,7 @@ config VIDEO_ZORAN_DC10 card. config VIDEO_ZORAN_LML33 - tristate "Linux Media Labs LML33 support" + bool "Linux Media Labs LML33 support" depends on VIDEO_ZORAN_ZR36060 select VIDEO_BT819 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT @@ -59,7 +59,7 @@ config VIDEO_ZORAN_LML33 card. config VIDEO_ZORAN_LML33R10 - tristate "Linux Media Labs LML33R10 support" + bool "Linux Media Labs LML33R10 support" depends on VIDEO_ZORAN_ZR36060 select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT select VIDEO_ADV7170 if MEDIA_SUBDRV_AUTOSELECT @@ -68,7 +68,7 @@ config VIDEO_ZORAN_LML33R10 card. config VIDEO_ZORAN_AVS6EYES - tristate "AverMedia 6 Eyes support" + bool "AverMedia 6 Eyes support" depends on VIDEO_ZORAN_ZR36060 select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_BT866 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/staging/media/zoran/Makefile b/drivers/staging/media/zoran/Makefile index 7023158e3892..9603bac0195c 100644 --- a/drivers/staging/media/zoran/Makefile +++ b/drivers/staging/media/zoran/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 zr36067-objs := zoran_device.o \ - zoran_driver.o zoran_card.o + zoran_driver.o zoran_card.o videocodec.o -obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o -obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o -obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o +obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o +zr36067-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o +zr36067-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o diff --git a/drivers/staging/media/zoran/videocodec.c b/drivers/staging/media/zoran/videocodec.c index 5bab7ba56257..3af7d02bd910 100644 --- a/drivers/staging/media/zoran/videocodec.c +++ b/drivers/staging/media/zoran/videocodec.c @@ -8,8 +8,6 @@ * (c) 2002 Wolfgang Scherr */ -#define VIDEOCODEC_VERSION "v0.2" - #include #include #include @@ -72,12 +70,9 @@ struct videocodec *videocodec_attach(struct videocodec_master *master) if ((master->flags & h->codec->flags) == master->flags) { dprintk(4, "%s: try '%s'\n", __func__, h->codec->name); - if (!try_module_get(h->codec->owner)) - return NULL; - codec = kmemdup(h->codec, sizeof(struct videocodec), GFP_KERNEL); if (!codec) - goto out_module_put; + goto out_kfree; res = strlen(codec->name); snprintf(codec->name + res, sizeof(codec->name) - res, "[%d]", h->attached); @@ -113,13 +108,10 @@ struct videocodec *videocodec_attach(struct videocodec_master *master) pr_err("%s: no codec found!\n", __func__); return NULL; - out_module_put: - module_put(h->codec->owner); out_kfree: kfree(codec); return NULL; } -EXPORT_SYMBOL(videocodec_attach); int videocodec_detach(struct videocodec *codec) { @@ -160,7 +152,6 @@ int videocodec_detach(struct videocodec *codec) prev->next = a->next; dprintk(4, "videocodec: delete middle\n"); } - module_put(a->codec->owner); kfree(a->codec); kfree(a); h->attached -= 1; @@ -175,7 +166,6 @@ int videocodec_detach(struct videocodec *codec) pr_err("%s: given codec not found!\n", __func__); return -EINVAL; } -EXPORT_SYMBOL(videocodec_detach); int videocodec_register(const struct videocodec *codec) { @@ -208,7 +198,6 @@ int videocodec_register(const struct videocodec *codec) return 0; } -EXPORT_SYMBOL(videocodec_register); int videocodec_unregister(const struct videocodec *codec) { @@ -255,7 +244,6 @@ int videocodec_unregister(const struct videocodec *codec) pr_err("%s: given codec not found!\n", __func__); return -EINVAL; } -EXPORT_SYMBOL(videocodec_unregister); int videocodec_debugfs_show(struct seq_file *m) { @@ -284,25 +272,3 @@ int videocodec_debugfs_show(struct seq_file *m) return 0; } - -/* ===================== */ -/* hook in driver module */ -/* ===================== */ -static int __init videocodec_init(void) -{ - pr_info("Linux video codec intermediate layer: %s\n", VIDEOCODEC_VERSION); - - return 0; -} - -static void __exit videocodec_exit(void) -{ -} - -module_init(videocodec_init); -module_exit(videocodec_exit); - -MODULE_AUTHOR("Wolfgang Scherr "); -MODULE_DESCRIPTION("Intermediate API module for video codecs " - VIDEOCODEC_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/zoran/videocodec.h b/drivers/staging/media/zoran/videocodec.h index 3a508d326049..9dea348fee40 100644 --- a/drivers/staging/media/zoran/videocodec.h +++ b/drivers/staging/media/zoran/videocodec.h @@ -234,7 +234,6 @@ struct jpeg_app_marker { }; struct videocodec { - struct module *owner; /* -- filled in by slave device during register -- */ char name[32]; unsigned long magic; /* may be used for client<->master attaching */ diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index 54e9ea03b88c..26a5392fef0c 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -29,6 +29,9 @@ #include "zoran.h" #include "zoran_card.h" #include "zoran_device.h" +#include "zr36016.h" +#include "zr36050.h" +#include "zr36060.h" extern const struct zoran_format zoran_formats[]; @@ -266,6 +269,96 @@ static const char *codecid_to_modulename(u16 codecid) return name; } +static int codec_init(struct zoran *zr, u16 codecid) +{ + switch (codecid) { + case CODEC_TYPE_ZR36060: +#ifdef CONFIG_VIDEO_ZORAN_ZR36060 + return zr36060_init_module(); +#else + pci_err(zr->pci_dev, "ZR36060 support is not enabled\n"); + return -EINVAL; +#endif + break; + case CODEC_TYPE_ZR36050: +#ifdef CONFIG_VIDEO_ZORAN_DC30 + return zr36050_init_module(); +#else + pci_err(zr->pci_dev, "ZR36050 support is not enabled\n"); + return -EINVAL; +#endif + break; + case CODEC_TYPE_ZR36016: +#ifdef CONFIG_VIDEO_ZORAN_DC30 + return zr36016_init_module(); +#else + pci_err(zr->pci_dev, "ZR36016 support is not enabled\n"); + return -EINVAL; +#endif + break; + } + + pci_err(zr->pci_dev, "unknown codec id %x\n", codecid); + return -EINVAL; +} + +static void codec_exit(struct zoran *zr, u16 codecid) +{ + switch (codecid) { + case CODEC_TYPE_ZR36060: +#ifdef CONFIG_VIDEO_ZORAN_ZR36060 + zr36060_cleanup_module(); +#endif + break; + case CODEC_TYPE_ZR36050: +#ifdef CONFIG_VIDEO_ZORAN_DC30 + zr36050_cleanup_module(); +#endif + break; + case CODEC_TYPE_ZR36016: +#ifdef CONFIG_VIDEO_ZORAN_DC30 + zr36016_cleanup_module(); +#endif + break; + } +} + +static int videocodec_init(struct zoran *zr) +{ + const char *codec_name, *vfe_name; + int result; + + codec_name = codecid_to_modulename(zr->card.video_codec); + if (codec_name) { + result = codec_init(zr, zr->card.video_codec); + if (result < 0) { + pci_err(zr->pci_dev, "failed to load video codec %s: %d\n", + codec_name, result); + return result; + } + } + vfe_name = codecid_to_modulename(zr->card.video_vfe); + if (vfe_name) { + result = codec_init(zr, zr->card.video_vfe); + if (result < 0) { + pci_err(zr->pci_dev, "failed to load video vfe %s: %d\n", + vfe_name, result); + if (codec_name) + codec_exit(zr, zr->card.video_codec); + return result; + } + } + return 0; +} + +static void videocodec_exit(struct zoran *zr) +{ + if (zr->card.video_codec != CODEC_TYPE_NONE) + codec_exit(zr, zr->card.video_codec); + if (zr->card.video_vfe != CODEC_TYPE_NONE) + codec_exit(zr, zr->card.video_vfe); +} + // struct tvnorm { // u16 wt, wa, h_start, h_sync_start, ht, ha, v_start; // }; @@ -954,6 +1047,7 @@ static void zoran_remove(struct pci_dev *pdev) videocodec_detach(zr->codec); if (zr->vfe) videocodec_detach(zr->vfe); + videocodec_exit(zr); /* unregister i2c bus */ zoran_unregister_i2c(zr); @@ -1079,6 +1173,8 @@ static int zoran_debugfs_show(struct seq_file *seq, void *v) seq_printf(seq, "Prepared %u\n", zr->prepared); seq_printf(seq, "Queued %u\n", zr->queued); + + videocodec_debugfs_show(seq); return 0; } @@ -1096,7 +1192,6 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct videocodec_master *master_vfe = NULL; struct videocodec_master *master_codec = NULL; int card_num; - const char *codec_name, *vfe_name; unsigned int nr; int err; @@ -1258,23 +1353,9 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) zr->card.addrs_encoder); pci_info(zr->pci_dev, "Initializing videocodec bus...\n"); - - if (zr->card.video_codec) { - codec_name = codecid_to_modulename(zr->card.video_codec); - if (codec_name) { - result = request_module(codec_name); - if (result) - pci_err(pdev, "failed to load modules %s: %d\n", codec_name, result); - } - } - if (zr->card.video_vfe) { - vfe_name = codecid_to_modulename(zr->card.video_vfe); - if (vfe_name) { - result = request_module(vfe_name); - if (result < 0) - pci_err(pdev, "failed to load modules %s: %d\n", vfe_name, result); - } - } + err = videocodec_init(zr); + if (err) + goto zr_unreg_i2c; /* reset JPEG codec */ jpeg_codec_sleep(zr, 1); @@ -1328,6 +1409,8 @@ zr_detach_vfe: videocodec_detach(zr->vfe); zr_detach_codec: videocodec_detach(zr->codec); +zr_unreg_videocodec: + videocodec_exit(zr); zr_unreg_i2c: zoran_unregister_i2c(zr); zr_free_irq: diff --git a/drivers/staging/media/zoran/zr36016.c b/drivers/staging/media/zoran/zr36016.c index 50605460a44b..26c7c32b6bc0 100644 --- a/drivers/staging/media/zoran/zr36016.c +++ b/drivers/staging/media/zoran/zr36016.c @@ -390,7 +390,6 @@ static int zr36016_setup(struct videocodec *codec) } static const struct videocodec zr36016_codec = { - .owner = THIS_MODULE, .name = "zr36016", .magic = 0L, /* magic not used */ .flags = @@ -409,14 +408,13 @@ static const struct videocodec zr36016_codec = { HOOK IN DRIVER AS KERNEL MODULE ========================================================================= */ -static int __init zr36016_init_module(void) +int zr36016_init_module(void) { - //dprintk(1, "ZR36016 driver %s\n",ZR016_VERSION); zr36016_codecs = 0; return videocodec_register(&zr36016_codec); } -static void __exit zr36016_cleanup_module(void) +void zr36016_cleanup_module(void) { if (zr36016_codecs) { dprintk(1, @@ -425,10 +423,3 @@ static void __exit zr36016_cleanup_module(void) } videocodec_unregister(&zr36016_codec); } - -module_init(zr36016_init_module); -module_exit(zr36016_cleanup_module); - -MODULE_AUTHOR("Wolfgang Scherr "); -MODULE_DESCRIPTION("Driver module for ZR36016 video frontends"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/zoran/zr36016.h b/drivers/staging/media/zoran/zr36016.h index 1475f971cc24..04afba35669d 100644 --- a/drivers/staging/media/zoran/zr36016.h +++ b/drivers/staging/media/zoran/zr36016.h @@ -89,4 +89,6 @@ struct zr36016 { #define ZR016_SIGN 0x02 #define ZR016_YMCS 0x01 +int zr36016_init_module(void); +void zr36016_cleanup_module(void); #endif /*fndef ZR36016_H */ diff --git a/drivers/staging/media/zoran/zr36050.c b/drivers/staging/media/zoran/zr36050.c index 4dc7927fefc3..38f7021e7b06 100644 --- a/drivers/staging/media/zoran/zr36050.c +++ b/drivers/staging/media/zoran/zr36050.c @@ -5,8 +5,6 @@ * Copyright (C) 2001 Wolfgang Scherr */ -#define ZR050_VERSION "v0.7.1" - #include #include #include @@ -798,7 +796,6 @@ static int zr36050_setup(struct videocodec *codec) } static const struct videocodec zr36050_codec = { - .owner = THIS_MODULE, .name = "zr36050", .magic = 0L, // magic not used .flags = @@ -817,14 +814,13 @@ static const struct videocodec zr36050_codec = { HOOK IN DRIVER AS KERNEL MODULE ========================================================================= */ -static int __init zr36050_init_module(void) +int zr36050_init_module(void) { - //dprintk(1, "ZR36050 driver %s\n",ZR050_VERSION); zr36050_codecs = 0; return videocodec_register(&zr36050_codec); } -static void __exit zr36050_cleanup_module(void) +void zr36050_cleanup_module(void) { if (zr36050_codecs) { dprintk(1, @@ -833,11 +829,3 @@ static void __exit zr36050_cleanup_module(void) } videocodec_unregister(&zr36050_codec); } - -module_init(zr36050_init_module); -module_exit(zr36050_cleanup_module); - -MODULE_AUTHOR("Wolfgang Scherr "); -MODULE_DESCRIPTION("Driver module for ZR36050 jpeg processors " - ZR050_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/zoran/zr36050.h b/drivers/staging/media/zoran/zr36050.h index 8f972d045b58..f9b58f4c77b9 100644 --- a/drivers/staging/media/zoran/zr36050.h +++ b/drivers/staging/media/zoran/zr36050.h @@ -160,4 +160,6 @@ struct zr36050 { #define ZR050_U_COMPONENT 1 #define ZR050_V_COMPONENT 2 +int zr36050_init_module(void); +void zr36050_cleanup_module(void); #endif /*fndef ZR36050_H */ diff --git a/drivers/staging/media/zoran/zr36060.c b/drivers/staging/media/zoran/zr36060.c index 7904d5b1f402..d0c369e31c81 100644 --- a/drivers/staging/media/zoran/zr36060.c +++ b/drivers/staging/media/zoran/zr36060.c @@ -5,8 +5,6 @@ * Copyright (C) 2002 Laurent Pinchart */ -#define ZR060_VERSION "v0.7" - #include #include #include @@ -831,7 +829,6 @@ static int zr36060_setup(struct videocodec *codec) } static const struct videocodec zr36060_codec = { - .owner = THIS_MODULE, .name = "zr36060", .magic = 0L, // magic not used .flags = @@ -846,13 +843,13 @@ static const struct videocodec zr36060_codec = { // others are not used }; -static int __init zr36060_init_module(void) +int zr36060_init_module(void) { zr36060_codecs = 0; return videocodec_register(&zr36060_codec); } -static void __exit zr36060_cleanup_module(void) +void zr36060_cleanup_module(void) { if (zr36060_codecs) { dprintk(1, @@ -863,10 +860,3 @@ static void __exit zr36060_cleanup_module(void) /* however, we can't just stay alive */ videocodec_unregister(&zr36060_codec); } - -module_init(zr36060_init_module); -module_exit(zr36060_cleanup_module); - -MODULE_AUTHOR("Laurent Pinchart "); -MODULE_DESCRIPTION("Driver module for ZR36060 jpeg processors " ZR060_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/zoran/zr36060.h b/drivers/staging/media/zoran/zr36060.h index d2cdc26bf625..fbf5429534ac 100644 --- a/drivers/staging/media/zoran/zr36060.h +++ b/drivers/staging/media/zoran/zr36060.h @@ -198,4 +198,6 @@ struct zr36060 { #define ZR060_SR_H_SCALE2 BIT(0) #define ZR060_SR_H_SCALE4 (2 << 0) +int zr36060_init_module(void); +void zr36060_cleanup_module(void); #endif /*fndef ZR36060_H */ -- cgit v1.2.3 From 49ebe7c38d04bf965b7d0c673788794896a2ebfd Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:25 +0100 Subject: media: staging: media: zoran: remove vidmem The vidmem parameter is no longer necessary since we removed framebuffer support. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_card.c | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index 26a5392fef0c..ffbb4ac0056e 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -39,17 +39,6 @@ static int card[BUZ_MAX] = { [0 ... (BUZ_MAX - 1)] = -1 }; module_param_array(card, int, NULL, 0444); MODULE_PARM_DESC(card, "Card type"); -/* - * The video mem address of the video card. The driver has a little database - * for some videocards to determine it from there. If your video card is not - * in there you have either to give it to the driver as a parameter or set - * in a VIDIOCSFBUF ioctl - */ - -static unsigned long vidmem; /* default = 0 - Video memory base address */ -module_param_hw(vidmem, ulong, iomem, 0444); -MODULE_PARM_DESC(vidmem, "Default video memory base address"); - /* Default input and video norm at startup of the driver. */ static unsigned int default_input; /* default 0 = Composite, 1 = S-Video */ @@ -1218,10 +1207,6 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) jpg_bufsize = 8192; if (jpg_bufsize > (512 * 1024)) jpg_bufsize = 512 * 1024; - /* Use parameter for vidmem or try to find a video card */ - if (vidmem) - pci_info(pdev, "%s: Using supplied video memory base address @ 0x%lx\n", - ZORAN_NAME, vidmem); /* some mainboards might not do PCI-PCI data transfer well */ if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK)) -- cgit v1.2.3 From 82e3a496eb56da0b9f29fdc5b63cedb3289e91de Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:26 +0100 Subject: media: staging: media: zoran: move videodev alloc Move some code out of zr36057_init() and create new functions for handling zr->video_dev. This permit to ease code reading and fix a zr->video_dev memory leak. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran.h | 2 +- drivers/staging/media/zoran/zoran_card.c | 80 +++++++++++++++++++----------- drivers/staging/media/zoran/zoran_driver.c | 5 +- 3 files changed, 54 insertions(+), 33 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zoran/zoran.h index 981cb63ac9af..c36b33f42b16 100644 --- a/drivers/staging/media/zoran/zoran.h +++ b/drivers/staging/media/zoran/zoran.h @@ -315,6 +315,6 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev) #endif -int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq); +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir); void zoran_queue_exit(struct zoran *zr); int zr_set_buf(struct zoran *zr); diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index ffbb4ac0056e..29120f2909c3 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -885,6 +885,52 @@ int zoran_check_jpg_settings(struct zoran *zr, return 0; } +static int zoran_init_video_device(struct zoran *zr, struct video_device *video_dev, int dir) +{ + int err; + + /* Now add the template and register the device unit. */ + *video_dev = zoran_template; + video_dev->v4l2_dev = &zr->v4l2_dev; + video_dev->lock = &zr->lock; + video_dev->device_caps = V4L2_CAP_STREAMING | dir; + + strscpy(video_dev->name, ZR_DEVNAME(zr), sizeof(video_dev->name)); + /* + * It's not a mem2mem device, but you can both capture and output from one and the same + * device. This should really be split up into two device nodes, but that's a job for + * another day. + */ + video_dev->vfl_dir = VFL_DIR_M2M; + zoran_queue_init(zr, &zr->vq, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + err = video_register_device(video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]); + if (err < 0) + return err; + video_set_drvdata(video_dev, zr); + return 0; +} + +static void zoran_exit_video_devices(struct zoran *zr) +{ + video_unregister_device(zr->video_dev); + kfree(zr->video_dev); +} + +static int zoran_init_video_devices(struct zoran *zr) +{ + int err; + + zr->video_dev = video_device_alloc(); + if (!zr->video_dev) + return -ENOMEM; + + err = zoran_init_video_device(zr, zr->video_dev, V4L2_CAP_VIDEO_CAPTURE); + if (err) + kfree(zr->video_dev); + return err; +} + void zoran_open_init_params(struct zoran *zr) { int i; @@ -956,17 +1002,11 @@ static int zr36057_init(struct zoran *zr) zoran_open_init_params(zr); /* allocate memory *before* doing anything to the hardware in case allocation fails */ - zr->video_dev = video_device_alloc(); - if (!zr->video_dev) { - err = -ENOMEM; - goto exit; - } zr->stat_com = dma_alloc_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), &zr->p_sc, GFP_KERNEL); if (!zr->stat_com) { - err = -ENOMEM; - goto exit_video; + return -ENOMEM; } for (j = 0; j < BUZ_NUM_STAT_COM; j++) zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ @@ -979,26 +1019,9 @@ static int zr36057_init(struct zoran *zr) goto exit_statcom; } - /* Now add the template and register the device unit. */ - *zr->video_dev = zoran_template; - zr->video_dev->v4l2_dev = &zr->v4l2_dev; - zr->video_dev->lock = &zr->lock; - zr->video_dev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; - - strscpy(zr->video_dev->name, ZR_DEVNAME(zr), sizeof(zr->video_dev->name)); - /* - * It's not a mem2mem device, but you can both capture and output from one and the same - * device. This should really be split up into two device nodes, but that's a job for - * another day. - */ - zr->video_dev->vfl_dir = VFL_DIR_M2M; - - zoran_queue_init(zr, &zr->vq); - - err = video_register_device(zr->video_dev, VFL_TYPE_VIDEO, video_nr[zr->id]); - if (err < 0) + err = zoran_init_video_devices(zr); + if (err) goto exit_statcomb; - video_set_drvdata(zr->video_dev, zr); zoran_init_hardware(zr); if (!pass_through) { @@ -1013,9 +1036,6 @@ exit_statcomb: dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb); exit_statcom: dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32), zr->stat_com, zr->p_sc); -exit_video: - kfree(zr->video_dev); -exit: return err; } @@ -1050,7 +1070,7 @@ static void zoran_remove(struct pci_dev *pdev) dma_free_coherent(&zr->pci_dev->dev, BUZ_NUM_STAT_COM * sizeof(u32) * 2, zr->stat_comb, zr->p_scb); pci_release_regions(pdev); pci_disable_device(zr->pci_dev); - video_unregister_device(zr->video_dev); + zoran_exit_video_devices(zr); exit_free: v4l2_ctrl_handler_free(&zr->hdl); v4l2_device_unregister(&zr->v4l2_dev); diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index 46382e43f1bf..551db338c7f7 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -1008,7 +1008,7 @@ static const struct vb2_ops zr_video_qops = { .wait_finish = vb2_ops_wait_finish, }; -int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq) +int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) { int err; @@ -1016,7 +1016,8 @@ int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq) INIT_LIST_HEAD(&zr->queued_bufs); vq->dev = &zr->pci_dev->dev; - vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vq->type = dir; + vq->io_modes = VB2_USERPTR | VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE; vq->drv_priv = zr; vq->buf_struct_size = sizeof(struct zr_buffer); -- cgit v1.2.3 From 3b70b0ecd7ca3f0a6ec0a271498aef6c9802a940 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:27 +0100 Subject: media: staging: media: zoran: move config select on primary kconfig Since all kconfigs for card selection are bool, this causes all selected modules to be always built-in. Prevent this by moving selects to the main tristate kconfig. By doing this, remove also all "if MEDIA_SUBDRV_AUTOSELECT" which are wrong, since zoran always need them to work. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/Kconfig | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/Kconfig b/drivers/staging/media/zoran/Kconfig index 4067fa93d44d..faef008b8554 100644 --- a/drivers/staging/media/zoran/Kconfig +++ b/drivers/staging/media/zoran/Kconfig @@ -4,6 +4,16 @@ config VIDEO_ZORAN depends on !ALPHA depends on DEBUG_FS select VIDEOBUF2_DMA_CONTIG + select VIDEO_ADV7170 if VIDEO_ZORAN_LML33R10 + select VIDEO_ADV7175 if VIDEO_ZORAN_DC10 || VIDEO_ZORAN_DC30 + select VIDEO_BT819 if VIDEO_ZORAN_LML33 + select VIDEO_BT856 if VIDEO_ZORAN_LML33 || VIDEO_ZORAN_AVS6EYES + select VIDEO_BT866 if VIDEO_ZORAN_AVS6EYES + select VIDEO_KS0127 if VIDEO_ZORAN_AVS6EYES + select VIDEO_SAA711X if VIDEO_ZORAN_BUZ || VIDEO_ZORAN_LML33R10 + select VIDEO_SAA7110 if VIDEO_ZORAN_DC10 + select VIDEO_SAA7185 if VIDEO_ZORAN_BUZ + select VIDEO_VPX3220 if VIDEO_ZORAN_DC30 help Say Y for support for MJPEG capture cards based on the Zoran 36057/36067 PCI controller chipset. This includes the Iomega @@ -17,8 +27,6 @@ config VIDEO_ZORAN config VIDEO_ZORAN_DC30 bool "Pinnacle/Miro DC30(+) support" depends on VIDEO_ZORAN - select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_VPX3220 if MEDIA_SUBDRV_AUTOSELECT help Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback card. This also supports really old DC10 cards based on the @@ -35,16 +43,12 @@ config VIDEO_ZORAN_ZR36060 config VIDEO_ZORAN_BUZ bool "Iomega Buz support" depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_SAA7185 if MEDIA_SUBDRV_AUTOSELECT help Support for the Iomega Buz MJPEG capture/playback card. config VIDEO_ZORAN_DC10 bool "Pinnacle/Miro DC10(+) support" depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA7110 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT help Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback card. @@ -52,8 +56,6 @@ config VIDEO_ZORAN_DC10 config VIDEO_ZORAN_LML33 bool "Linux Media Labs LML33 support" depends on VIDEO_ZORAN_ZR36060 - select VIDEO_BT819 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT help Support for the Linux Media Labs LML33 MJPEG capture/playback card. @@ -61,8 +63,6 @@ config VIDEO_ZORAN_LML33 config VIDEO_ZORAN_LML33R10 bool "Linux Media Labs LML33R10 support" depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_ADV7170 if MEDIA_SUBDRV_AUTOSELECT help support for the Linux Media Labs LML33R10 MJPEG capture/playback card. @@ -70,8 +70,5 @@ config VIDEO_ZORAN_LML33R10 config VIDEO_ZORAN_AVS6EYES bool "AverMedia 6 Eyes support" depends on VIDEO_ZORAN_ZR36060 - select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_BT866 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_KS0127 if MEDIA_SUBDRV_AUTOSELECT help Support for the AverMedia 6 Eyes video surveillance card. -- cgit v1.2.3 From 8f7cc5c0b0eb597bd25c81ef13d9904d55535bef Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:28 +0100 Subject: media: staging: media: zoran: introduce zoran_i2c_init Reduces the size of the probe function by adding zoran_i2c_init and zoran_i2c_exit functions. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_card.c | 73 +++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 19 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index 29120f2909c3..bcf6ef4f0359 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -931,6 +931,53 @@ static int zoran_init_video_devices(struct zoran *zr) return err; } +/* + * v4l2_device_unregister() will care about removing zr->encoder/zr->decoder + * via v4l2_i2c_subdev_unregister() + */ +static int zoran_i2c_init(struct zoran *zr) +{ + int err; + + pci_info(zr->pci_dev, "Initializing i2c bus...\n"); + + err = zoran_register_i2c(zr); + if (err) { + pci_err(zr->pci_dev, "%s - cannot initialize i2c bus\n", __func__); + return err; + } + + zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, &zr->i2c_adapter, + zr->card.i2c_decoder, 0, + zr->card.addrs_decoder); + if (!zr->decoder) { + pci_err(zr->pci_dev, "Fail to get decoder %s\n", zr->card.i2c_decoder); + err = -EINVAL; + goto error_decoder; + } + + if (zr->card.i2c_encoder) { + zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, &zr->i2c_adapter, + zr->card.i2c_encoder, 0, + zr->card.addrs_encoder); + if (!zr->encoder) { + pci_err(zr->pci_dev, "Fail to get encoder %s\n", zr->card.i2c_encoder); + err = -EINVAL; + goto error_decoder; + } + } + return 0; + +error_decoder: + zoran_unregister_i2c(zr); + return err; +} + +static void zoran_i2c_exit(struct zoran *zr) +{ + zoran_unregister_i2c(zr); +} + void zoran_open_init_params(struct zoran *zr) { int i; @@ -1059,7 +1106,7 @@ static void zoran_remove(struct pci_dev *pdev) videocodec_exit(zr); /* unregister i2c bus */ - zoran_unregister_i2c(zr); + zoran_i2c_exit(zr); /* disable PCI bus-mastering */ zoran_set_pci_master(zr, 0); /* put chip into reset */ @@ -1340,22 +1387,10 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } zr36057_restart(zr); - /* i2c */ - pci_info(zr->pci_dev, "Initializing i2c bus...\n"); - if (zoran_register_i2c(zr) < 0) { - pci_err(pdev, "%s - can't initialize i2c bus\n", __func__); + err = zoran_i2c_init(zr); + if (err) goto zr_free_irq; - } - - zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, &zr->i2c_adapter, - zr->card.i2c_decoder, 0, - zr->card.addrs_decoder); - - if (zr->card.i2c_encoder) - zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, &zr->i2c_adapter, - zr->card.i2c_encoder, 0, - zr->card.addrs_encoder); pci_info(zr->pci_dev, "Initializing videocodec bus...\n"); err = videocodec_init(zr); @@ -1370,15 +1405,15 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (zr->card.video_codec != 0) { master_codec = zoran_setup_videocodec(zr, zr->card.video_codec); if (!master_codec) - goto zr_unreg_i2c; + goto zr_unreg_videocodec; zr->codec = videocodec_attach(master_codec); if (!zr->codec) { pci_err(pdev, "%s - no codec found\n", __func__); - goto zr_unreg_i2c; + goto zr_unreg_videocodec; } if (zr->codec->type != zr->card.video_codec) { pci_err(pdev, "%s - wrong codec\n", __func__); - goto zr_detach_codec; + goto zr_unreg_videocodec; } } if (zr->card.video_vfe != 0) { @@ -1417,7 +1452,7 @@ zr_detach_codec: zr_unreg_videocodec: videocodec_exit(zr); zr_unreg_i2c: - zoran_unregister_i2c(zr); + zoran_i2c_exit(zr); zr_free_irq: btwrite(0, ZR36057_SPGPPCR); pci_free_irq(zr->pci_dev, 0, zr); -- cgit v1.2.3 From 241f5b67fb48def58643f279dfb8468bdd54b443 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:29 +0100 Subject: media: staging: media: zoran: fix usage of vb2_dma_contig_set_max_seg_size vb2_dma_contig_set_max_seg_size need to have a size in parameter and not a DMA_BIT_MASK(). While fixing this issue, also fix error handling of all DMA size setting. Reported-by: kernel test robot Fixes: d4ae3689226e5 ("media: zoran: device support only 32bit DMA address") Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_card.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index bcf6ef4f0359..bdf15df556e4 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -1282,8 +1282,10 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (err) - return -ENODEV; - vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); + return err; + err = vb2_dma_contig_set_max_seg_size(&pdev->dev, U32_MAX); + if (err) + return err; nr = zoran_num++; if (nr >= BUZ_MAX) { -- cgit v1.2.3 From 202ddbc9a33b7296c03f8b0dbcffc071a72866ed Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:30 +0100 Subject: media: staging: media: zoran: clean unused code It remains some unused code from old zoran buffer handling. Let's remove them. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran.h | 14 ------------ drivers/staging/media/zoran/zoran_card.c | 36 ------------------------------ drivers/staging/media/zoran/zoran_device.h | 2 -- drivers/staging/media/zoran/zoran_driver.c | 2 -- 4 files changed, 54 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zoran/zoran.h index c36b33f42b16..654c95fa5aba 100644 --- a/drivers/staging/media/zoran/zoran.h +++ b/drivers/staging/media/zoran/zoran.h @@ -54,22 +54,8 @@ static inline struct zr_buffer *vb2_to_zr_buffer(struct vb2_buffer *vb) #define BUZ_NUM_STAT_COM 4 #define BUZ_MASK_STAT_COM 3 -#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ -#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ - #define BUZ_MAX_INPUT 16 -#if VIDEO_MAX_FRAME <= 32 -# define V4L_MAX_FRAME 32 -#elif VIDEO_MAX_FRAME <= 64 -# define V4L_MAX_FRAME 64 -#else -# error "Too many video frame buffers to handle" -#endif -#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) - -#define MAX_FRAME (BUZ_MAX_FRAME > VIDEO_MAX_FRAME ? BUZ_MAX_FRAME : VIDEO_MAX_FRAME) - #include "zr36057.h" enum card_type { diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index bdf15df556e4..26f978a1cc72 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -60,20 +60,6 @@ static int video_nr[BUZ_MAX] = { [0 ... (BUZ_MAX - 1)] = -1 }; module_param_array(video_nr, int, NULL, 0444); MODULE_PARM_DESC(video_nr, "Video device number (-1=Auto)"); -int v4l_nbufs = 4; -int v4l_bufsize = 864; /* Everybody should be able to work with this setting */ -module_param(v4l_nbufs, int, 0644); -MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use"); -module_param(v4l_bufsize, int, 0644); -MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)"); - -int jpg_nbufs = 32; -int jpg_bufsize = 512; /* max size for 100% quality full-PAL frame */ -module_param(jpg_nbufs, int, 0644); -MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use"); -module_param(jpg_bufsize, int, 0644); -MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)"); - /* 1=Pass through TV signal when device is not used */ /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */ int pass_through; @@ -1253,28 +1239,6 @@ static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_info(pdev, "Zoran MJPEG board driver version %s\n", ZORAN_VERSION); - /* check the parameters we have been given, adjust if necessary */ - if (v4l_nbufs < 2) - v4l_nbufs = 2; - if (v4l_nbufs > VIDEO_MAX_FRAME) - v4l_nbufs = VIDEO_MAX_FRAME; - /* The user specifies the in KB, we want them in byte (and page aligned) */ - v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); - if (v4l_bufsize < 32768) - v4l_bufsize = 32768; - /* 2 MB is arbitrary but sufficient for the maximum possible images */ - if (v4l_bufsize > 2048 * 1024) - v4l_bufsize = 2048 * 1024; - if (jpg_nbufs < 4) - jpg_nbufs = 4; - if (jpg_nbufs > BUZ_MAX_FRAME) - jpg_nbufs = BUZ_MAX_FRAME; - jpg_bufsize = PAGE_ALIGN(jpg_bufsize * 1024); - if (jpg_bufsize < 8192) - jpg_bufsize = 8192; - if (jpg_bufsize > (512 * 1024)) - jpg_bufsize = 512 * 1024; - /* some mainboards might not do PCI-PCI data transfer well */ if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK)) pci_warn(pdev, "%s: chipset does not support reliable PCI-PCI DMA\n", diff --git a/drivers/staging/media/zoran/zoran_device.h b/drivers/staging/media/zoran/zoran_device.h index 6c5d70238228..322b04c55d41 100644 --- a/drivers/staging/media/zoran/zoran_device.h +++ b/drivers/staging/media/zoran/zoran_device.h @@ -47,9 +47,7 @@ extern void zr36057_restart(struct zoran *zr); extern const struct zoran_format zoran_formats[]; -extern int v4l_nbufs; extern int v4l_bufsize; -extern int jpg_nbufs; extern int jpg_bufsize; extern int pass_through; diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index 551db338c7f7..31993c266976 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -153,8 +153,6 @@ static __u32 zoran_v4l2_calc_bufsize(struct zoran_jpg_settings *settings) result <<= 1; } - if (result > jpg_bufsize) - return jpg_bufsize; if (result < 8192) return 8192; -- cgit v1.2.3 From 4e3edddb9507a28446624144da6be5d1323e6f15 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:31 +0100 Subject: media: staging: media: zoran: fix counting buffer in reserve After each capture, zoran driver complains that it remains some unused buffer. This is due to a missing count handling. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_driver.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index 31993c266976..32d76876c683 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -887,6 +887,7 @@ int zr_set_buf(struct zoran *zr) return -EINVAL; } list_del(&buf->queue); + zr->buf_in_reserve--; spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); vbuf = &buf->vbuf; -- cgit v1.2.3 From e3b86f4e558cea9eed71d894df2f19b10d60a207 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Tue, 14 Dec 2021 17:16:32 +0100 Subject: media: staging: media: zoran: calculate the right buffer number for zoran_reap_stat_com On the case tmp_dcim=1, the index of buffer is miscalculated. This generate a NULL pointer dereference later. So let's fix the calcul and add a check to prevent this to reappear. Signed-off-by: Corentin Labbe Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_device.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_device.c b/drivers/staging/media/zoran/zoran_device.c index 5b12a730a229..fb1f0465ca87 100644 --- a/drivers/staging/media/zoran/zoran_device.c +++ b/drivers/staging/media/zoran/zoran_device.c @@ -814,7 +814,7 @@ static void zoran_reap_stat_com(struct zoran *zr) if (zr->jpg_settings.tmp_dcm == 1) i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; else - i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2 + 1; + i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; stat_com = le32_to_cpu(zr->stat_com[i]); if ((stat_com & 1) == 0) { @@ -826,6 +826,11 @@ static void zoran_reap_stat_com(struct zoran *zr) size = (stat_com & GENMASK(22, 1)) >> 1; buf = zr->inuse[i]; + if (!buf) { + spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); + pci_err(zr->pci_dev, "No buffer at slot %d\n", i); + return; + } buf->vbuf.vb2_buf.timestamp = ktime_get_ns(); if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { -- cgit v1.2.3 From 914941827aad5ecddf9bf3a6dee67fbec1af1fff Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 14 Dec 2021 17:16:33 +0100 Subject: media: staging: media: zoran: fix various V4L2 compliance errors This fixes several issues found with 'v4l2-compliance -s': 1) read()/write() is supported, but not reported in the capabilities 2) S_STD(G_STD()) failed: setting the same standard should just return 0. 3) G_PARM failed to set readbuffers. 4) different field values in the format vs. what v4l2_buffer reported. 5) zero the sequence number when starting streaming. 6) drop VB_USERPTR: makes no sense with dma_contig streaming. Signed-off-by: Hans Verkuil Signed-off-by: Corentin Labbe Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_card.c | 2 +- drivers/staging/media/zoran/zoran_driver.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index 26f978a1cc72..5a67220cb9eb 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -879,7 +879,7 @@ static int zoran_init_video_device(struct zoran *zr, struct video_device *video_ *video_dev = zoran_template; video_dev->v4l2_dev = &zr->v4l2_dev; video_dev->lock = &zr->lock; - video_dev->device_caps = V4L2_CAP_STREAMING | dir; + video_dev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | dir; strscpy(video_dev->name, ZR_DEVNAME(zr), sizeof(video_dev->name)); /* diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index 32d76876c683..dd19ee023d91 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -253,8 +253,6 @@ static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability strscpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)); strscpy(cap->driver, "zoran", sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(zr->pci_dev)); - cap->device_caps = zr->video_dev->device_caps; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -580,6 +578,9 @@ static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) struct zoran *zr = video_drvdata(file); int res = 0; + if (zr->norm == std) + return 0; + if (zr->running != ZORAN_MAP_MODE_NONE) return -EBUSY; @@ -737,6 +738,7 @@ static int zoran_g_parm(struct file *file, void *priv, struct v4l2_streamparm *p if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; + parm->parm.capture.readbuffers = 9; return 0; } @@ -867,6 +869,10 @@ int zr_set_buf(struct zoran *zr) vbuf = &buf->vbuf; buf->vbuf.field = V4L2_FIELD_INTERLACED; + if (BUZ_MAX_HEIGHT < (zr->v4l_settings.height * 2)) + buf->vbuf.field = V4L2_FIELD_INTERLACED; + else + buf->vbuf.field = V4L2_FIELD_TOP; vb2_set_plane_payload(&buf->vbuf.vb2_buf, 0, zr->buffer_size); vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_DONE); zr->inuse[0] = NULL; @@ -927,6 +933,7 @@ static int zr_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) zr->stat_com[j] = cpu_to_le32(1); zr->inuse[j] = NULL; } + zr->vbseq = 0; if (zr->map_mode != ZORAN_MAP_MODE_RAW) { pci_info(zr->pci_dev, "START JPG\n"); @@ -1017,7 +1024,7 @@ int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir) vq->dev = &zr->pci_dev->dev; vq->type = dir; - vq->io_modes = VB2_USERPTR | VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE; + vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_READ | VB2_WRITE; vq->drv_priv = zr; vq->buf_struct_size = sizeof(struct zr_buffer); vq->ops = &zr_video_qops; -- cgit v1.2.3 From 35e77cea10e6c069251b1addd630439cae284a10 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 14 Dec 2021 17:16:34 +0100 Subject: media: staging: media: zoran: fix TRY_FMT handling TRY_FMT must not set actual capture values (zr->buffer_size in this case), since it is a 'try' only. zoran_try_fmt_vid_cap() also didn't fill in fmt->fmt.pix.bytesperline and fmt->fmt.pix.sizeimage correctly. Signed-off-by: Hans Verkuil Signed-off-by: Corentin Labbe Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_driver.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index dd19ee023d91..367fe4be8357 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -398,7 +398,6 @@ static int zoran_try_fmt_vid_out(struct file *file, void *__fh, V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings); - zr->buffer_size = fmt->fmt.pix.sizeimage; fmt->fmt.pix.bytesperline = 0; fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return res; @@ -433,6 +432,8 @@ static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8); v4l_bound_align_image(&fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, bpp == 2 ? 1 : 2, &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, 0, 0); + fmt->fmt.pix.bytesperline = fmt->fmt.pix.width * bpp; + fmt->fmt.pix.sizeimage = fmt->fmt.pix.bytesperline * fmt->fmt.pix.height; return 0; } -- cgit v1.2.3 From fa5fce2573ec2ed8e9698478e42e79ce7b468eb0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 14 Dec 2021 17:16:35 +0100 Subject: media: staging: media: zoran: drop kernel log spam Do not spam the kernel log with messages that result from incorrect userspace input. Those should be either dropped completely (the error code gives sufficient info) or changed to debug messages. Signed-off-by: Hans Verkuil Signed-off-by: Corentin Labbe Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_device.c | 8 ++++---- drivers/staging/media/zoran/zoran_driver.c | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_device.c b/drivers/staging/media/zoran/zoran_device.c index fb1f0465ca87..2470889a58fa 100644 --- a/drivers/staging/media/zoran/zoran_device.c +++ b/drivers/staging/media/zoran/zoran_device.c @@ -239,7 +239,7 @@ static void zr36057_set_vfe(struct zoran *zr, int video_width, int video_height, wa = tvn->wa; ha = tvn->ha; - pci_info(zr->pci_dev, "set_vfe() - width = %d, height = %d\n", video_width, video_height); + pci_dbg(zr->pci_dev, "set_vfe() - width = %d, height = %d\n", video_width, video_height); if (video_width < BUZ_MIN_WIDTH || video_height < BUZ_MIN_HEIGHT || @@ -664,7 +664,7 @@ void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO clear_interrupt_counters(zr); - pci_info(zr->pci_dev, "enable_jpg(MOTION_COMPRESS)\n"); + pci_dbg(zr->pci_dev, "enable_jpg(MOTION_COMPRESS)\n"); break; } @@ -693,7 +693,7 @@ void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO clear_interrupt_counters(zr); - pci_info(zr->pci_dev, "enable_jpg(MOTION_DECOMPRESS)\n"); + pci_dbg(zr->pci_dev, "enable_jpg(MOTION_DECOMPRESS)\n"); break; case BUZ_MODE_IDLE: @@ -720,7 +720,7 @@ void zr36057_enable_jpg(struct zoran *zr, enum zoran_codec_mode mode) decoder_call(zr, video, s_stream, 1); encoder_call(zr, video, s_routing, 0, 0, 0); - pci_info(zr->pci_dev, "enable_jpg(IDLE)\n"); + pci_dbg(zr->pci_dev, "enable_jpg(IDLE)\n"); break; } } diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index 367fe4be8357..013efdecd582 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -171,7 +171,7 @@ static int zoran_v4l_set_format(struct zoran *zr, int width, int height, if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH || height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) { - pci_err(zr->pci_dev, "%s - wrong frame size (%dx%d)\n", __func__, width, height); + pci_dbg(zr->pci_dev, "%s - wrong frame size (%dx%d)\n", __func__, width, height); return -EINVAL; } @@ -181,7 +181,7 @@ static int zoran_v4l_set_format(struct zoran *zr, int width, int height, /* Check against available buffer size */ if (height * width * bpp > zr->buffer_size) { - pci_err(zr->pci_dev, "%s - video buffer size (%d kB) is too small\n", + pci_dbg(zr->pci_dev, "%s - video buffer size (%d kB) is too small\n", __func__, zr->buffer_size >> 10); return -EINVAL; } @@ -189,7 +189,7 @@ static int zoran_v4l_set_format(struct zoran *zr, int width, int height, /* The video front end needs 4-byte alinged line sizes */ if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) { - pci_err(zr->pci_dev, "%s - wrong frame alignment\n", __func__); + pci_dbg(zr->pci_dev, "%s - wrong frame alignment\n", __func__); return -EINVAL; } @@ -205,7 +205,7 @@ static int zoran_set_norm(struct zoran *zr, v4l2_std_id norm) { if (!(norm & zr->card.norms)) { - pci_err(zr->pci_dev, "%s - unsupported norm %llx\n", __func__, norm); + pci_dbg(zr->pci_dev, "%s - unsupported norm %llx\n", __func__, norm); return -EINVAL; } @@ -231,7 +231,7 @@ static int zoran_set_input(struct zoran *zr, int input) return 0; if (input < 0 || input >= zr->card.inputs) { - pci_err(zr->pci_dev, "%s - unsupported input %d\n", __func__, input); + pci_dbg(zr->pci_dev, "%s - unsupported input %d\n", __func__, input); return -EINVAL; } @@ -532,7 +532,7 @@ static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc) break; if (i == NUM_FORMATS) { - pci_err(zr->pci_dev, "VIDIOC_S_FMT - unknown/unsupported format 0x%x\n", + pci_dbg(zr->pci_dev, "VIDIOC_S_FMT - unknown/unsupported format 0x%x\n", fmt->fmt.pix.pixelformat); /* TODO do not return here to fix the TRY_FMT cannot handle an invalid pixelformat*/ return -EINVAL; @@ -666,7 +666,7 @@ static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selectio if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - pci_err(zr->pci_dev, "%s invalid selection type combination\n", __func__); + pci_dbg(zr->pci_dev, "%s invalid selection type combination\n", __func__); return -EINVAL; } @@ -712,7 +712,7 @@ static int zoran_s_selection(struct file *file, void *__fh, struct v4l2_selectio return -EINVAL; if (zr->map_mode == ZORAN_MAP_MODE_RAW) { - pci_err(zr->pci_dev, "VIDIOC_S_SELECTION - subcapture only supported for compressed capture\n"); + pci_dbg(zr->pci_dev, "VIDIOC_S_SELECTION - subcapture only supported for compressed capture\n"); return -EINVAL; } @@ -937,7 +937,7 @@ static int zr_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) zr->vbseq = 0; if (zr->map_mode != ZORAN_MAP_MODE_RAW) { - pci_info(zr->pci_dev, "START JPG\n"); + pci_dbg(zr->pci_dev, "START JPG\n"); zr36057_restart(zr); zoran_init_hardware(zr); if (zr->map_mode == ZORAN_MAP_MODE_JPG_REC) @@ -951,7 +951,7 @@ static int zr_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) return 0; } - pci_info(zr->pci_dev, "START RAW\n"); + pci_dbg(zr->pci_dev, "START RAW\n"); zr36057_restart(zr); zoran_init_hardware(zr); @@ -1001,7 +1001,7 @@ static void zr_vb2_stop_streaming(struct vb2_queue *vq) } spin_unlock_irqrestore(&zr->queued_bufs_lock, flags); if (zr->buf_in_reserve) - pci_err(zr->pci_dev, "Buffer remaining %d\n", zr->buf_in_reserve); + pci_dbg(zr->pci_dev, "Buffer remaining %d\n", zr->buf_in_reserve); zr->map_mode = ZORAN_MAP_MODE_RAW; } -- cgit v1.2.3 From 7eba1e43273e8042e14534ec60f12e24701368d7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 14 Dec 2021 17:16:36 +0100 Subject: media: staging: media: zoran: drop read/write support This makes no sense for MJPEG formats and it is just easier to drop support for this altogether. Signed-off-by: Hans Verkuil Signed-off-by: Corentin Labbe Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/zoran/zoran_card.c | 2 +- drivers/staging/media/zoran/zoran_driver.c | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index 5a67220cb9eb..26f978a1cc72 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -879,7 +879,7 @@ static int zoran_init_video_device(struct zoran *zr, struct video_device *video_ *video_dev = zoran_template; video_dev->v4l2_dev = &zr->v4l2_dev; video_dev->lock = &zr->lock; - video_dev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | dir; + video_dev->device_caps = V4L2_CAP_STREAMING | dir; strscpy(video_dev->name, ZR_DEVNAME(zr), sizeof(video_dev->name)); /* diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c index 013efdecd582..4304b7e21709 100644 --- a/drivers/staging/media/zoran/zoran_driver.c +++ b/drivers/staging/media/zoran/zoran_driver.c @@ -734,15 +734,6 @@ static int zoran_s_selection(struct file *file, void *__fh, struct v4l2_selectio return res; } -static int zoran_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm) -{ - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - parm->parm.capture.readbuffers = 9; - return 0; -} - /* * Output is disabled temporarily * Zoran is picky about jpeg data it accepts. At least it seems to unsupport COM and APPn. @@ -750,7 +741,6 @@ static int zoran_g_parm(struct file *file, void *priv, struct v4l2_streamparm *p */ static const struct v4l2_ioctl_ops zoran_ioctl_ops = { .vidioc_querycap = zoran_querycap, - .vidioc_g_parm = zoran_g_parm, .vidioc_s_selection = zoran_s_selection, .vidioc_g_selection = zoran_g_selection, .vidioc_enum_input = zoran_enum_input, @@ -786,8 +776,6 @@ static const struct v4l2_file_operations zoran_fops = { .unlocked_ioctl = video_ioctl2, .open = v4l2_fh_open, .release = vb2_fop_release, - .read = vb2_fop_read, - .write = vb2_fop_write, .mmap = vb2_fop_mmap, .poll = vb2_fop_poll, }; -- cgit v1.2.3 From 95a1379004cba8c887278ed8b92299659fdab500 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 8 Apr 2021 03:39:53 +0200 Subject: media: staging: media: imx: imx7-mipi-csis: Dump MIPI_CSIS_FRAME_COUNTER_CH0 register The frame counter is useful debugging information, add it to the register dump printed by mipi_csis_dump_regs(). Signed-off-by: Laurent Pinchart Reviewed-by: Rui Miguel Silva Reviewed-by: Jerome Brunet Tested-by: Jerome Brunet # On i.MX8MP Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx7-mipi-csis.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index 2b73fa55c938..c9c0089ad816 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -211,6 +211,8 @@ #define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL BIT(4) #define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE BIT(0) +#define MIPI_CSIS_FRAME_COUNTER_CH(n) (0x0100 + (n) * 4) + /* Non-image packet data buffers */ #define MIPI_CSIS_PKTDATA_ODD 0x2000 #define MIPI_CSIS_PKTDATA_EVEN 0x3000 @@ -773,6 +775,7 @@ static int mipi_csis_dump_regs(struct csi_state *state) { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" }, { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" }, { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" }, + { MIPI_CSIS_FRAME_COUNTER_CH(0), "FRAME_COUNTER_CH0" }, }; unsigned int i; -- cgit v1.2.3 From 385031b6fc186aabe5aa2ab971358cd3c7ce2ecc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 24 Jun 2021 18:28:55 +0200 Subject: media: staging: media: imx: imx7_mipi_csis: Add timings override through debugfs Add two debugfs files, ths_settle and tclk_settle, to allow overriding the corresponding timing parameters for test purpose. Signed-off-by: Laurent Pinchart Reviewed-by: Rui Miguel Silva Reviewed-by: Jerome Brunet Tested-by: Jerome Brunet # On i.MX8MP Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx7-mipi-csis.c | 35 +++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index c9c0089ad816..d2f60403eb41 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -333,7 +333,11 @@ struct csi_state { spinlock_t slock; /* Protect events */ struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; struct dentry *debugfs_root; - bool debug; + struct { + bool enable; + u32 hs_settle; + u32 clk_settle; + } debug; }; /* ----------------------------------------------------------------------------- @@ -543,6 +547,18 @@ static int mipi_csis_calculate_params(struct csi_state *state) dev_dbg(state->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n", lane_rate, state->clk_settle, state->hs_settle); + if (state->debug.hs_settle < 0xff) { + dev_dbg(state->dev, "overriding Ths_settle with %u\n", + state->debug.hs_settle); + state->hs_settle = state->debug.hs_settle; + } + + if (state->debug.clk_settle < 4) { + dev_dbg(state->dev, "overriding Tclk_settle with %u\n", + state->debug.clk_settle); + state->clk_settle = state->debug.clk_settle; + } + return 0; } @@ -659,7 +675,7 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) spin_lock_irqsave(&state->slock, flags); /* Update the event/error counters */ - if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug) { + if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug.enable) { for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) { struct mipi_csis_event *event = &state->events[i]; @@ -749,7 +765,7 @@ static void mipi_csis_log_counters(struct csi_state *state, bool non_errors) spin_lock_irqsave(&state->slock, flags); for (i = 0; i < num_events; ++i) { - if (state->events[i].counter > 0 || state->debug) + if (state->events[i].counter > 0 || state->debug.enable) dev_info(state->dev, "%s events: %d\n", state->events[i].name, state->events[i].counter); @@ -801,12 +817,19 @@ DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs); static void mipi_csis_debugfs_init(struct csi_state *state) { + state->debug.hs_settle = UINT_MAX; + state->debug.clk_settle = UINT_MAX; + state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL); debugfs_create_bool("debug_enable", 0600, state->debugfs_root, - &state->debug); + &state->debug.enable); debugfs_create_file("dump_regs", 0600, state->debugfs_root, state, &mipi_csis_dump_regs_fops); + debugfs_create_u32("tclk_settle", 0600, state->debugfs_root, + &state->debug.clk_settle); + debugfs_create_u32("ths_settle", 0600, state->debugfs_root, + &state->debug.hs_settle); } static void mipi_csis_debugfs_exit(struct csi_state *state) @@ -867,7 +890,7 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) ret = 0; mipi_csis_stop_stream(state); state->state &= ~ST_STREAMING; - if (state->debug) + if (state->debug.enable) mipi_csis_log_counters(state, true); } @@ -1064,7 +1087,7 @@ static int mipi_csis_log_status(struct v4l2_subdev *sd) mutex_lock(&state->lock); mipi_csis_log_counters(state, true); - if (state->debug && (state->state & ST_POWERED)) + if (state->debug.enable && (state->state & ST_POWERED)) mipi_csis_dump_regs(state); mutex_unlock(&state->lock); -- cgit v1.2.3 From 5be7f8c91d25089be847a71b336c13b5bb0db772 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 25 Jun 2021 04:26:35 +0200 Subject: media: staging: media: imx: imx7-mipi-csis: Make subdev name unique When multiple CSIS instances are present in a single graph, they are currently all named "imx7-mipi-csis.0", which breaks the entity name uniqueness requirement. Fix it by using the device name to create the subdev name. Fixes: 7807063b862b ("media: staging/imx7: add MIPI CSI-2 receiver subdev for i.MX7") Signed-off-by: Laurent Pinchart Reviewed-by: Rui Miguel Silva Reviewed-by: Sakari Ailus Reviewed-by: Jerome Brunet Tested-by: Jerome Brunet # On i.MX8MP Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx7-mipi-csis.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index d2f60403eb41..a8710dc24560 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -32,7 +32,6 @@ #include #define CSIS_DRIVER_NAME "imx7-mipi-csis" -#define CSIS_SUBDEV_NAME CSIS_DRIVER_NAME #define CSIS_PAD_SINK 0 #define CSIS_PAD_SOURCE 1 @@ -313,7 +312,6 @@ struct csi_state { struct reset_control *mrst; struct regulator *mipi_phy_regulator; const struct mipi_csis_info *info; - u8 index; struct v4l2_subdev sd; struct media_pad pads[CSIS_PADS_NUM]; @@ -1329,8 +1327,8 @@ static int mipi_csis_subdev_init(struct csi_state *state) v4l2_subdev_init(sd, &mipi_csis_subdev_ops); sd->owner = THIS_MODULE; - snprintf(sd->name, sizeof(sd->name), "%s.%d", - CSIS_SUBDEV_NAME, state->index); + snprintf(sd->name, sizeof(sd->name), "csis-%s", + dev_name(state->dev)); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sd->ctrl_handler = NULL; -- cgit v1.2.3 From 59c2b6d51803ad6b7af28f2a60a843b24374e692 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Thu, 16 Dec 2021 10:03:35 +0100 Subject: media: imx: imx8mq-mipi-csi2: remove wrong irq config write operation The place where this register writel() that masks one interrupt is placed does not guarantee that the device is powered so that's not allowed. Moreover imx8mq_mipi_csi_start_stream() masks the interrupt anyway so the write is not even needed. Remove it as this is a mistake that slipped in with the driver. Fixes: f33fd8d77dd0 ("media: imx: add a driver for i.MX8MQ mipi csi rx phy and controller") Signed-off-by: Martin Kepplinger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx8mq-mipi-csi2.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c index 7adbdd14daa9..8f3cc138c52c 100644 --- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -398,9 +398,6 @@ 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) -- cgit v1.2.3 From f0c2ba1ed4ad868331d8c6ea9119669a729b01a9 Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Thu, 16 Dec 2021 10:03:36 +0100 Subject: media: imx: imx8mq-mipi_csi2: fix system resume during system resume, interconnect bandwidth would currently be requested even though the device is runtime suspended. This leaves the system in an unbalanced state. Fix that by only doing that in runtimem pm and splitting up runtime and system suspend to be a more readable: imx8mq_mipi_csi_pm_*() does the generic things called from system- and runtime functions that each do specific things on top. Fixes: f33fd8d77dd0 ("media: imx: add a driver for i.MX8MQ mipi csi rx phy and controller") Signed-off-by: Martin Kepplinger Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx8mq-mipi-csi2.c | 71 ++++++++++++++++++---------- 1 file changed, 47 insertions(+), 24 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c index 8f3cc138c52c..3b9fa75efac6 100644 --- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -693,7 +693,7 @@ err_parse: * Suspend/resume */ -static int imx8mq_mipi_csi_pm_suspend(struct device *dev, bool runtime) +static int imx8mq_mipi_csi_pm_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct csi_state *state = mipi_sd_to_csi2_state(sd); @@ -705,36 +705,21 @@ static int imx8mq_mipi_csi_pm_suspend(struct device *dev, bool runtime) 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) +static int imx8mq_mipi_csi_pm_resume(struct device *dev) { 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); @@ -755,22 +740,60 @@ unlock: static int __maybe_unused imx8mq_mipi_csi_suspend(struct device *dev) { - return imx8mq_mipi_csi_pm_suspend(dev, false); + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + int ret; + + ret = imx8mq_mipi_csi_pm_suspend(dev); + if (ret) + return ret; + + state->state |= ST_SUSPENDED; + + return ret; } static int __maybe_unused imx8mq_mipi_csi_resume(struct device *dev) { - return imx8mq_mipi_csi_pm_resume(dev, false); + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + + if (!(state->state & ST_SUSPENDED)) + return 0; + + return imx8mq_mipi_csi_pm_resume(dev); } static int __maybe_unused imx8mq_mipi_csi_runtime_suspend(struct device *dev) { - return imx8mq_mipi_csi_pm_suspend(dev, true); + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + int ret; + + ret = imx8mq_mipi_csi_pm_suspend(dev); + if (ret) + return ret; + + ret = icc_set_bw(state->icc_path, 0, 0); + if (ret) + dev_err(dev, "icc_set_bw failed with %d\n", ret); + + return ret; } static int __maybe_unused imx8mq_mipi_csi_runtime_resume(struct device *dev) { - return imx8mq_mipi_csi_pm_resume(dev, true); + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csi2_state(sd); + int ret; + + 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; + } + + return imx8mq_mipi_csi_pm_resume(dev); } static const struct dev_pm_ops imx8mq_mipi_csi_pm_ops = { @@ -918,7 +941,7 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev) /* Enable runtime PM. */ pm_runtime_enable(dev); if (!pm_runtime_enabled(dev)) { - ret = imx8mq_mipi_csi_pm_resume(dev, true); + ret = imx8mq_mipi_csi_runtime_resume(dev); if (ret < 0) goto icc; } @@ -931,7 +954,7 @@ static int imx8mq_mipi_csi_probe(struct platform_device *pdev) cleanup: pm_runtime_disable(&pdev->dev); - imx8mq_mipi_csi_pm_suspend(&pdev->dev, true); + imx8mq_mipi_csi_runtime_suspend(&pdev->dev); media_entity_cleanup(&state->sd.entity); v4l2_async_nf_unregister(&state->notifier); @@ -955,7 +978,7 @@ static int imx8mq_mipi_csi_remove(struct platform_device *pdev) v4l2_async_unregister_subdev(&state->sd); pm_runtime_disable(&pdev->dev); - imx8mq_mipi_csi_pm_suspend(&pdev->dev, true); + imx8mq_mipi_csi_runtime_suspend(&pdev->dev); media_entity_cleanup(&state->sd.entity); mutex_destroy(&state->lock); pm_runtime_set_suspended(&pdev->dev); -- cgit v1.2.3 From 7a3b3dc3bb2eeac4adf8b01b1b6b519bcbc48cfc Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Fri, 7 Jan 2022 16:54:54 +0100 Subject: media: hevc: Remove RPS named flags Marking a picture as long-term reference is valid for DPB but not for RPS. Change flag name to match with the description in HEVC spec chapter "8.3.2 Decoding process for reference picture set". PocStCurrBefore, PocStCurrAfter, PocLtCurr lists could be built by the kernel from the DPB entries struct v4l2_hevc_dpb_entry, using the information in the rps field. This way RPS flags becomes useless and are removed. This patch breaks the staging HEVC API because it introduces a new flag, changes a field name in v4l2_hevc_dpb_entry structure and removes V4L2_HEVC_DPB_ENTRY_RPS_* flags. [hverkuil: fixed some typos] Signed-off-by: Benjamin Gaignard Reviewed-by: Jernej Skrabec Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst | 10 +++++----- drivers/staging/media/hantro/hantro_g2_hevc_dec.c | 2 +- drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 2 +- include/media/hevc-ctrls.h | 6 ++---- 4 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers/staging') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index e141f0e4eec9..e8de13e16c3b 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -3166,11 +3166,11 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - :c:func:`v4l2_timeval_to_ns()` function to convert the struct :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. * - __u8 - - ``rps`` - - The reference set for the reference frame - (V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_BEFORE, - V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_AFTER or - V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR) + - ``flags`` + - Long term flag for the reference frame + (V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE). The flag is set as + described in the ITU HEVC specification chapter "8.3.2 Decoding + process for reference picture set". * - __u8 - ``field_pic`` - Whether the reference is a field picture or a frame. diff --git a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c index 99d8ea7543da..14e0e6414100 100644 --- a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c +++ b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c @@ -433,7 +433,7 @@ static int set_ref(struct hantro_ctx *ctx) chroma_addr = luma_addr + cr_offset; mv_addr = luma_addr + mv_offset; - if (dpb[i].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR) + if (dpb[i].flags & V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE) dpb_longterm_e |= BIT(V4L2_HEVC_DPB_ENTRIES_NUM_MAX - 1 - i); hantro_write_addr(vpu, G2_REF_LUMA_ADDR(i), luma_addr); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 8829a7bab07e..8ab2d9c6f048 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -169,7 +169,7 @@ static void cedrus_h265_ref_pic_list_write(struct cedrus_dev *dev, unsigned int index = list[i]; u8 value = list[i]; - if (dpb[index].rps == V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR) + if (dpb[index].flags & V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE) value |= VE_DEC_H265_SRAM_REF_PIC_LIST_LT_REF; /* Each SRAM word gathers up to 4 references. */ diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h index ef63bc205756..01ccda48d8c5 100644 --- a/include/media/hevc-ctrls.h +++ b/include/media/hevc-ctrls.h @@ -127,15 +127,13 @@ struct v4l2_ctrl_hevc_pps { __u64 flags; }; -#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_BEFORE 0x01 -#define V4L2_HEVC_DPB_ENTRY_RPS_ST_CURR_AFTER 0x02 -#define V4L2_HEVC_DPB_ENTRY_RPS_LT_CURR 0x03 +#define V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE 0x01 #define V4L2_HEVC_DPB_ENTRIES_NUM_MAX 16 struct v4l2_hevc_dpb_entry { __u64 timestamp; - __u8 rps; + __u8 flags; __u8 field_pic; __u16 pic_order_cnt[2]; __u8 padding[2]; -- cgit v1.2.3 From d95a63daca85f4bca3b70e622c75586b5bf0ea5c Mon Sep 17 00:00:00 2001 From: Benjamin Gaignard Date: Fri, 7 Jan 2022 16:54:55 +0100 Subject: media: hevc: Embedded indexes in RPS Reference Picture Set lists provide indices of short and long term reference in DBP array. Fix Hantro to not do a look up in DBP entries. Make documentation more clear about it. [hverkuil: fix typo in commit log] Signed-off-by: Benjamin Gaignard Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../userspace-api/media/v4l/ext-ctrls-codec.rst | 6 +++--- drivers/staging/media/hantro/hantro_g2_hevc_dec.c | 25 ++++++---------------- 2 files changed, 9 insertions(+), 22 deletions(-) (limited to 'drivers/staging') diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst index e8de13e16c3b..4cd7c541fc30 100644 --- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst +++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst @@ -3383,15 +3383,15 @@ enum v4l2_mpeg_video_hevc_size_of_length_field - * - __u8 - ``poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` - PocStCurrBefore as described in section 8.3.2 "Decoding process for reference - picture set. + picture set": provides the index of the short term before references in DPB array. * - __u8 - ``poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` - PocStCurrAfter as described in section 8.3.2 "Decoding process for reference - picture set. + picture set": provides the index of the short term after references in DPB array. * - __u8 - ``poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]`` - PocLtCurr as described in section 8.3.2 "Decoding process for reference - picture set. + picture set": provides the index of the long term references in DPB array. * - __u64 - ``flags`` - See :ref:`Decode Parameters Flags ` diff --git a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c index 14e0e6414100..c524af41baf5 100644 --- a/drivers/staging/media/hantro/hantro_g2_hevc_dec.c +++ b/drivers/staging/media/hantro/hantro_g2_hevc_dec.c @@ -255,24 +255,11 @@ static void set_params(struct hantro_ctx *ctx) hantro_reg_write(vpu, &g2_apf_threshold, 8); } -static int find_ref_pic_index(const struct v4l2_hevc_dpb_entry *dpb, int pic_order_cnt) -{ - int i; - - for (i = 0; i < V4L2_HEVC_DPB_ENTRIES_NUM_MAX; i++) { - if (dpb[i].pic_order_cnt[0] == pic_order_cnt) - return i; - } - - return 0x0; -} - static void set_ref_pic_list(struct hantro_ctx *ctx) { const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls; struct hantro_dev *vpu = ctx->dev; const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params; - const struct v4l2_hevc_dpb_entry *dpb = decode_params->dpb; u32 list0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX] = {}; u32 list1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX] = {}; static const struct hantro_reg ref_pic_regs0[] = { @@ -316,11 +303,11 @@ static void set_ref_pic_list(struct hantro_ctx *ctx) /* List 0 contains: short term before, short term after and long term */ j = 0; for (i = 0; i < decode_params->num_poc_st_curr_before && j < ARRAY_SIZE(list0); i++) - list0[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_before[i]); + list0[j++] = decode_params->poc_st_curr_before[i]; for (i = 0; i < decode_params->num_poc_st_curr_after && j < ARRAY_SIZE(list0); i++) - list0[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_after[i]); + list0[j++] = decode_params->poc_st_curr_after[i]; for (i = 0; i < decode_params->num_poc_lt_curr && j < ARRAY_SIZE(list0); i++) - list0[j++] = find_ref_pic_index(dpb, decode_params->poc_lt_curr[i]); + list0[j++] = decode_params->poc_lt_curr[i]; /* Fill the list, copying over and over */ i = 0; @@ -329,11 +316,11 @@ static void set_ref_pic_list(struct hantro_ctx *ctx) j = 0; for (i = 0; i < decode_params->num_poc_st_curr_after && j < ARRAY_SIZE(list1); i++) - list1[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_after[i]); + list1[j++] = decode_params->poc_st_curr_after[i]; for (i = 0; i < decode_params->num_poc_st_curr_before && j < ARRAY_SIZE(list1); i++) - list1[j++] = find_ref_pic_index(dpb, decode_params->poc_st_curr_before[i]); + list1[j++] = decode_params->poc_st_curr_before[i]; for (i = 0; i < decode_params->num_poc_lt_curr && j < ARRAY_SIZE(list1); i++) - list1[j++] = find_ref_pic_index(dpb, decode_params->poc_lt_curr[i]); + list1[j++] = decode_params->poc_lt_curr[i]; i = 0; while (j < ARRAY_SIZE(list1)) -- cgit v1.2.3 From c8c80c996182239ff9b05eda4db50184cf3b2e99 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Thu, 13 Jan 2022 07:59:28 +0100 Subject: media: meson: vdec: potential dereference of null pointer As the possible failure of the kzalloc(), the 'new_ts' could be NULL pointer. Therefore, it should be better to check it in order to avoid the dereference of the NULL pointer. Also, the caller esparser_queue() needs to deal with the return value of the amvdec_add_ts(). Fixes: 876f123b8956 ("media: meson: vdec: bring up to compliance") Signed-off-by: Jiasheng Jiang Suggested-by: Neil Armstrong Reviewed-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/meson/vdec/esparser.c | 7 ++++++- drivers/staging/media/meson/vdec/vdec_helpers.c | 8 ++++++-- drivers/staging/media/meson/vdec/vdec_helpers.h | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/meson/vdec/esparser.c b/drivers/staging/media/meson/vdec/esparser.c index db7022707ff8..86ccc8937afc 100644 --- a/drivers/staging/media/meson/vdec/esparser.c +++ b/drivers/staging/media/meson/vdec/esparser.c @@ -328,7 +328,12 @@ esparser_queue(struct amvdec_session *sess, struct vb2_v4l2_buffer *vbuf) offset = esparser_get_offset(sess); - amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->flags); + ret = amvdec_add_ts(sess, vb->timestamp, vbuf->timecode, offset, vbuf->flags); + if (ret) { + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + return ret; + } + dev_dbg(core->dev, "esparser: ts = %llu pld_size = %u offset = %08X flags = %08X\n", vb->timestamp, payload_size, offset, vbuf->flags); diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.c b/drivers/staging/media/meson/vdec/vdec_helpers.c index 203d7afa085d..7d2a75653250 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.c +++ b/drivers/staging/media/meson/vdec/vdec_helpers.c @@ -227,13 +227,16 @@ int amvdec_set_canvases(struct amvdec_session *sess, } EXPORT_SYMBOL_GPL(amvdec_set_canvases); -void amvdec_add_ts(struct amvdec_session *sess, u64 ts, - struct v4l2_timecode tc, u32 offset, u32 vbuf_flags) +int amvdec_add_ts(struct amvdec_session *sess, u64 ts, + struct v4l2_timecode tc, u32 offset, u32 vbuf_flags) { struct amvdec_timestamp *new_ts; unsigned long flags; new_ts = kzalloc(sizeof(*new_ts), GFP_KERNEL); + if (!new_ts) + return -ENOMEM; + new_ts->ts = ts; new_ts->tc = tc; new_ts->offset = offset; @@ -242,6 +245,7 @@ void amvdec_add_ts(struct amvdec_session *sess, u64 ts, spin_lock_irqsave(&sess->ts_spinlock, flags); list_add_tail(&new_ts->list, &sess->timestamps); spin_unlock_irqrestore(&sess->ts_spinlock, flags); + return 0; } EXPORT_SYMBOL_GPL(amvdec_add_ts); diff --git a/drivers/staging/media/meson/vdec/vdec_helpers.h b/drivers/staging/media/meson/vdec/vdec_helpers.h index 88137d15aa3a..4bf3e61d081b 100644 --- a/drivers/staging/media/meson/vdec/vdec_helpers.h +++ b/drivers/staging/media/meson/vdec/vdec_helpers.h @@ -56,8 +56,8 @@ void amvdec_dst_buf_done_offset(struct amvdec_session *sess, * @offset: offset in the VIFIFO where the associated packet was written * @flags: the vb2_v4l2_buffer flags */ -void amvdec_add_ts(struct amvdec_session *sess, u64 ts, - struct v4l2_timecode tc, u32 offset, u32 flags); +int amvdec_add_ts(struct amvdec_session *sess, u64 ts, + struct v4l2_timecode tc, u32 offset, u32 flags); void amvdec_remove_ts(struct amvdec_session *sess, u64 ts); /** -- cgit v1.2.3 From e55c90c82375378f32263cc8a738650e71b5551b Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 22 Nov 2021 08:27:07 +0100 Subject: media: imx: imx7-media-csi: add support for imx8mq Modeled after the NXP driver mx6s_capture.c that this driver is based on, imx8mq needs different settings for the baseaddr_switch mechanism. Define the needed bits and set that for imx8mq. Without these settings, the system will "sometimes" hang completely when starting to stream (the interrupt will never be called). Signed-off-by: Martin Kepplinger Acked-by: Rui Miguel Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx7-media-csi.c | 32 ++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 2288dadb2683..32311fc0e2a4 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -122,6 +123,10 @@ #define BIT_DATA_FROM_MIPI BIT(22) #define BIT_MIPI_YU_SWAP BIT(21) #define BIT_MIPI_DOUBLE_CMPNT BIT(20) +#define BIT_MASK_OPTION_FIRST_FRAME (0 << 18) +#define BIT_MASK_OPTION_CSI_EN (1 << 18) +#define BIT_MASK_OPTION_SECOND_FRAME (2 << 18) +#define BIT_MASK_OPTION_ON_DATA (3 << 18) #define BIT_BASEADDR_CHG_ERR_EN BIT(9) #define BIT_BASEADDR_SWITCH_SEL BIT(5) #define BIT_BASEADDR_SWITCH_EN BIT(4) @@ -154,6 +159,11 @@ #define CSI_CSICR18 0x48 #define CSI_CSICR19 0x4c +enum imx_csi_model { + IMX7_CSI_IMX7 = 0, + IMX7_CSI_IMX8MQ, +}; + struct imx7_csi { struct device *dev; struct v4l2_subdev sd; @@ -189,6 +199,8 @@ struct imx7_csi { bool is_csi2; struct completion last_eof_completion; + + enum imx_csi_model model; }; static struct imx7_csi * @@ -537,6 +549,16 @@ static void imx7_csi_deinit(struct imx7_csi *csi, clk_disable_unprepare(csi->mclk); } +static void imx7_csi_baseaddr_switch_on_second_frame(struct imx7_csi *csi) +{ + u32 cr18 = imx7_csi_reg_read(csi, CSI_CSICR18); + + cr18 |= BIT_BASEADDR_SWITCH_EN | BIT_BASEADDR_SWITCH_SEL | + BIT_BASEADDR_CHG_ERR_EN; + cr18 |= BIT_MASK_OPTION_SECOND_FRAME; + imx7_csi_reg_write(csi, cr18, CSI_CSICR18); +} + static void imx7_csi_enable(struct imx7_csi *csi) { /* Clear the Rx FIFO and reflash the DMA controller. */ @@ -552,6 +574,9 @@ static void imx7_csi_enable(struct imx7_csi *csi) /* Enable the RxFIFO DMA and the CSI. */ imx7_csi_dmareq_rff_enable(csi); imx7_csi_hw_enable(csi); + + if (csi->model == IMX7_CSI_IMX8MQ) + imx7_csi_baseaddr_switch_on_second_frame(csi); } static void imx7_csi_disable(struct imx7_csi *csi) @@ -1155,6 +1180,8 @@ static int imx7_csi_probe(struct platform_device *pdev) if (IS_ERR(csi->regbase)) return PTR_ERR(csi->regbase); + csi->model = (enum imx_csi_model)(uintptr_t)of_device_get_match_data(&pdev->dev); + spin_lock_init(&csi->irqlock); mutex_init(&csi->lock); @@ -1249,8 +1276,9 @@ static int imx7_csi_remove(struct platform_device *pdev) } static const struct of_device_id imx7_csi_of_match[] = { - { .compatible = "fsl,imx7-csi" }, - { .compatible = "fsl,imx6ul-csi" }, + { .compatible = "fsl,imx8mq-csi", .data = (void *)IMX7_CSI_IMX8MQ }, + { .compatible = "fsl,imx7-csi", .data = (void *)IMX7_CSI_IMX7 }, + { .compatible = "fsl,imx6ul-csi", .data = (void *)IMX7_CSI_IMX7 }, { }, }; MODULE_DEVICE_TABLE(of, imx7_csi_of_match); -- cgit v1.2.3 From 89d78e0133e71ba324fb67ca776223fba4353418 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 7 Jan 2022 10:34:49 +0100 Subject: media: hantro: Fix overfill bottom register field name The Hantro H1 hardware can crop off pixels from the right and bottom of the source frame. These are controlled with the H1_REG_IN_IMG_CTRL_OVRFLB and H1_REG_IN_IMG_CTRL_OVRFLR in the H1_REG_IN_IMG_CTRL register. The ChromeOS kernel driver that this was based on incorrectly added the _D4 suffix H1_REG_IN_IMG_CTRL_OVRFLB. This field crops the bottom of the input frame, and the number is _not_ divided by 4. [1] Correct the name to avoid confusion when crop support with the selection API is added. [1] https://chromium.googlesource.com/chromiumos/third_party/kernel/+/refs/ \ heads/chromeos-4.19/drivers/staging/media/hantro/hantro_h1_vp8_enc.c#377 Fixes: 775fec69008d ("media: add Rockchip VPU JPEG encoder driver") Fixes: a29add8c9bb2 ("media: rockchip/vpu: rename from rockchip to hantro") Signed-off-by: Chen-Yu Tsai Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_h1_jpeg_enc.c | 2 +- drivers/staging/media/hantro/hantro_h1_regs.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index 1450013d3685..c5d32048d90f 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -23,7 +23,7 @@ static void hantro_h1_set_src_img_ctrl(struct hantro_dev *vpu, reg = H1_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) | H1_REG_IN_IMG_CTRL_OVRFLR_D4(0) - | H1_REG_IN_IMG_CTRL_OVRFLB_D4(0) + | H1_REG_IN_IMG_CTRL_OVRFLB(0) | H1_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); vepu_write_relaxed(vpu, reg, H1_REG_IN_IMG_CTRL); } diff --git a/drivers/staging/media/hantro/hantro_h1_regs.h b/drivers/staging/media/hantro/hantro_h1_regs.h index d6e9825bb5c7..30e7e7b920b5 100644 --- a/drivers/staging/media/hantro/hantro_h1_regs.h +++ b/drivers/staging/media/hantro/hantro_h1_regs.h @@ -47,7 +47,7 @@ #define H1_REG_IN_IMG_CTRL 0x03c #define H1_REG_IN_IMG_CTRL_ROW_LEN(x) ((x) << 12) #define H1_REG_IN_IMG_CTRL_OVRFLR_D4(x) ((x) << 10) -#define H1_REG_IN_IMG_CTRL_OVRFLB_D4(x) ((x) << 6) +#define H1_REG_IN_IMG_CTRL_OVRFLB(x) ((x) << 6) #define H1_REG_IN_IMG_CTRL_FMT(x) ((x) << 2) #define H1_REG_ENC_CTRL0 0x040 #define H1_REG_ENC_CTRL0_INIT_QP(x) ((x) << 26) -- cgit v1.2.3 From 0ce575d432910374f7abd4748da0a1f5483c15ec Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 7 Jan 2022 10:34:50 +0100 Subject: media: hantro: Support cropping visible area for encoders Encoders typically operate on macroblocks. Thus their output or coded resolution is constrained to multiples of macroblocks. For frame sizes not aligned to macroblocks, cropping is needed to limit the visible area of the frame. Add support for cropping on the output (source) side for encoders, using the selection API. Signed-off-by: Chen-Yu Tsai Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/TODO | 3 - drivers/staging/media/hantro/hantro_h1_jpeg_enc.c | 17 +++-- drivers/staging/media/hantro/hantro_v4l2.c | 77 ++++++++++++++++++++++ .../media/hantro/rockchip_vpu2_hw_jpeg_enc.c | 17 +++-- 4 files changed, 101 insertions(+), 13 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/TODO b/drivers/staging/media/hantro/TODO index fa0c94057007..da181dc93069 100644 --- a/drivers/staging/media/hantro/TODO +++ b/drivers/staging/media/hantro/TODO @@ -5,9 +5,6 @@ For this reason, we are keeping this driver in staging for now. -* Add support for the S_SELECTION API. - See the comment for VEPU_REG_ENC_OVER_FILL_STRM_OFFSET. - * Instead of having a DMA bounce buffer, it could be possible to use a normal buffer and memmove() the payload to make space for the header. This might need to use extra JPEG markers for padding reasons. diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index c5d32048d90f..a71f90a01bfc 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -18,12 +18,21 @@ static void hantro_h1_set_src_img_ctrl(struct hantro_dev *vpu, struct hantro_ctx *ctx) { - struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; + u32 overfill_r, overfill_b; u32 reg; - reg = H1_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width) - | H1_REG_IN_IMG_CTRL_OVRFLR_D4(0) - | H1_REG_IN_IMG_CTRL_OVRFLB(0) + /* + * The format width and height are already macroblock aligned + * by .vidioc_s_fmt_vid_cap_mplane() callback. Destination + * format width and height can be further modified by + * .vidioc_s_selection(), and the width is 4-aligned. + */ + overfill_r = ctx->src_fmt.width - ctx->dst_fmt.width; + overfill_b = ctx->src_fmt.height - ctx->dst_fmt.height; + + reg = H1_REG_IN_IMG_CTRL_ROW_LEN(ctx->src_fmt.width) + | H1_REG_IN_IMG_CTRL_OVRFLR_D4(overfill_r / 4) + | H1_REG_IN_IMG_CTRL_OVRFLB(overfill_b) | H1_REG_IN_IMG_CTRL_FMT(ctx->vpu_src_fmt->enc_fmt); vepu_write_relaxed(vpu, reg, H1_REG_IN_IMG_CTRL); } diff --git a/drivers/staging/media/hantro/hantro_v4l2.c b/drivers/staging/media/hantro/hantro_v4l2.c index e595905b3bd7..67148ba346f5 100644 --- a/drivers/staging/media/hantro/hantro_v4l2.c +++ b/drivers/staging/media/hantro/hantro_v4l2.c @@ -554,6 +554,80 @@ vidioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) return hantro_set_fmt_cap(fh_to_ctx(priv), &f->fmt.pix_mp); } +static int vidioc_g_selection(struct file *file, void *priv, + struct v4l2_selection *sel) +{ + struct hantro_ctx *ctx = fh_to_ctx(priv); + + /* Crop only supported on source. */ + if (!ctx->is_encoder || + sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = ctx->src_fmt.width; + sel->r.height = ctx->src_fmt.height; + break; + case V4L2_SEL_TGT_CROP: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = ctx->dst_fmt.width; + sel->r.height = ctx->dst_fmt.height; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int vidioc_s_selection(struct file *file, void *priv, + struct v4l2_selection *sel) +{ + struct hantro_ctx *ctx = fh_to_ctx(priv); + struct v4l2_rect *rect = &sel->r; + struct vb2_queue *vq; + + /* Crop only supported on source. */ + if (!ctx->is_encoder || + sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + /* Change not allowed if the queue is streaming. */ + vq = v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx); + if (vb2_is_streaming(vq)) + return -EBUSY; + + if (sel->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + /* + * We do not support offsets, and we can crop only inside + * right-most or bottom-most macroblocks. + */ + if (rect->left != 0 || rect->top != 0 || + round_up(rect->width, MB_DIM) != ctx->src_fmt.width || + round_up(rect->height, MB_DIM) != ctx->src_fmt.height) { + /* Default to full frame for incorrect settings. */ + rect->left = 0; + rect->top = 0; + rect->width = ctx->src_fmt.width; + rect->height = ctx->src_fmt.height; + } else { + /* We support widths aligned to 4 pixels and arbitrary heights. */ + rect->width = round_up(rect->width, 4); + } + + ctx->dst_fmt.width = rect->width; + ctx->dst_fmt.height = rect->height; + + return 0; +} + const struct v4l2_ioctl_ops hantro_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_framesizes = vidioc_enum_framesizes, @@ -580,6 +654,9 @@ const struct v4l2_ioctl_ops hantro_ioctl_ops = { .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, }; static int diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c index 4df16f59fb97..41a418fe9221 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c @@ -35,18 +35,23 @@ static void rockchip_vpu2_set_src_img_ctrl(struct hantro_dev *vpu, struct hantro_ctx *ctx) { - struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; + u32 overfill_r, overfill_b; u32 reg; /* - * The pix fmt width/height are already macroblock aligned - * by .vidioc_s_fmt_vid_cap_mplane() callback + * The format width and height are already macroblock aligned + * by .vidioc_s_fmt_vid_cap_mplane() callback. Destination + * format width and height can be further modified by + * .vidioc_s_selection(), and the width is 4-aligned. */ - reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(pix_fmt->width); + overfill_r = ctx->src_fmt.width - ctx->dst_fmt.width; + overfill_b = ctx->src_fmt.height - ctx->dst_fmt.height; + + reg = VEPU_REG_IN_IMG_CTRL_ROW_LEN(ctx->src_fmt.width); vepu_write_relaxed(vpu, reg, VEPU_REG_INPUT_LUMA_INFO); - reg = VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(0) | - VEPU_REG_IN_IMG_CTRL_OVRFLB(0); + reg = VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(overfill_r / 4) | + VEPU_REG_IN_IMG_CTRL_OVRFLB(overfill_b); /* * This register controls the input crop, as the offset * from the right/bottom within the last macroblock. The offset from the -- cgit v1.2.3 From e90410d1304e93c74ac4f87338f665e44129a79c Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 7 Jan 2022 10:34:51 +0100 Subject: media: hantro: jpeg: Add JFIF APP0 segment to JPEG encoder output While the V4L2_PIX_FMT_JPEG format doesn't specify any requirements for the APP0 or APP1 segments, it would be nice if the output is JFIF compliant. While some programs can read JPEG streams that aren't, some guess work is involved. Add the standard JFIF APP0 segment to the JPEG header, so that the JPEG encoder output is JFIF compliant. Signed-off-by: Chen-Yu Tsai Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_jpeg.c | 21 +++++++++++++-------- drivers/staging/media/hantro/hantro_jpeg.h | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_jpeg.c b/drivers/staging/media/hantro/hantro_jpeg.c index df62fbdff7c9..7d4018bd6876 100644 --- a/drivers/staging/media/hantro/hantro_jpeg.c +++ b/drivers/staging/media/hantro/hantro_jpeg.c @@ -12,15 +12,15 @@ #include "hantro_jpeg.h" #include "hantro.h" -#define LUMA_QUANT_OFF 7 -#define CHROMA_QUANT_OFF 72 -#define HEIGHT_OFF 141 -#define WIDTH_OFF 143 +#define LUMA_QUANT_OFF 25 +#define CHROMA_QUANT_OFF 90 +#define HEIGHT_OFF 159 +#define WIDTH_OFF 161 -#define HUFF_LUMA_DC_OFF 160 -#define HUFF_LUMA_AC_OFF 193 -#define HUFF_CHROMA_DC_OFF 376 -#define HUFF_CHROMA_AC_OFF 409 +#define HUFF_LUMA_DC_OFF 178 +#define HUFF_LUMA_AC_OFF 211 +#define HUFF_CHROMA_DC_OFF 394 +#define HUFF_CHROMA_AC_OFF 427 /* Default tables from JPEG ITU-T.81 * (ISO/IEC 10918-1) Annex K, tables K.1 and K.2 @@ -144,6 +144,11 @@ static const unsigned char hantro_jpeg_header[JPEG_HEADER_SIZE] = { /* SOI */ 0xff, 0xd8, + /* JFIF-APP0 */ + 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, + 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, + /* DQT */ 0xff, 0xdb, 0x00, 0x84, diff --git a/drivers/staging/media/hantro/hantro_jpeg.h b/drivers/staging/media/hantro/hantro_jpeg.h index 035ab25b803f..f33c492134e4 100644 --- a/drivers/staging/media/hantro/hantro_jpeg.h +++ b/drivers/staging/media/hantro/hantro_jpeg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ -#define JPEG_HEADER_SIZE 601 +#define JPEG_HEADER_SIZE 619 #define JPEG_QUANT_SIZE 64 struct hantro_jpeg_ctx { -- cgit v1.2.3 From 00b5359bac5aea8ff20c3a55fd90cfdb1d49c835 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 7 Jan 2022 10:34:52 +0100 Subject: media: hantro: jpeg: Add COM segment to JPEG header to align image scan The JPEG header size is not 64-bit aligned. This makes the driver require a bounce buffer for the encoded JPEG image scan output. Add a COM (comment) segment to the JPEG header so that the header size is a multiple of 64 bits. This will then allow dropping the use of the bounce buffer, and instead have the hardware write out to the capture buffer directly. Signed-off-by: Chen-Yu Tsai Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_jpeg.c | 23 ++++++++++++++++++++++- drivers/staging/media/hantro/hantro_jpeg.h | 2 +- 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_jpeg.c b/drivers/staging/media/hantro/hantro_jpeg.c index 7d4018bd6876..e63eeef3952d 100644 --- a/drivers/staging/media/hantro/hantro_jpeg.c +++ b/drivers/staging/media/hantro/hantro_jpeg.c @@ -6,6 +6,9 @@ * Copyright (C) Jean-Francois Moine (http://moinejf.free.fr) * Copyright (C) 2014 Philipp Zabel, Pengutronix */ + +#include +#include #include #include #include @@ -140,7 +143,7 @@ static const unsigned char chroma_ac_table[] = { * and we'll use fixed offsets to change the width, height * quantization tables, etc. */ -static const unsigned char hantro_jpeg_header[JPEG_HEADER_SIZE] = { +static const unsigned char hantro_jpeg_header[] = { /* SOI */ 0xff, 0xd8, @@ -247,11 +250,29 @@ static const unsigned char hantro_jpeg_header[JPEG_HEADER_SIZE] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* COM */ + 0xff, 0xfe, 0x00, 0x03, 0x00, + /* SOS */ 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, }; +/* + * JPEG_HEADER_SIZE is used in other parts of the driver in lieu of + * "sizeof(hantro_jpeg_header)". The two must be equal. + */ +static_assert(sizeof(hantro_jpeg_header) == JPEG_HEADER_SIZE); + +/* + * hantro_jpeg_header is padded with a COM segment, so that the payload + * of the SOS segment (the entropy-encoded image scan), which should + * trail the whole header, is 8-byte aligned for the hardware to write + * to directly. + */ +static_assert(IS_ALIGNED(sizeof(hantro_jpeg_header), 8), + "Hantro JPEG header size needs to be 8-byte aligned."); + static unsigned char jpeg_scale_qp(const unsigned char qp, int scale) { unsigned int temp; diff --git a/drivers/staging/media/hantro/hantro_jpeg.h b/drivers/staging/media/hantro/hantro_jpeg.h index f33c492134e4..0b49d0b82caa 100644 --- a/drivers/staging/media/hantro/hantro_jpeg.h +++ b/drivers/staging/media/hantro/hantro_jpeg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ -#define JPEG_HEADER_SIZE 619 +#define JPEG_HEADER_SIZE 624 #define JPEG_QUANT_SIZE 64 struct hantro_jpeg_ctx { -- cgit v1.2.3 From 7464f055e9c348b86ca09abf7f2c2df017cdedbf Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 7 Jan 2022 10:34:53 +0100 Subject: media: hantro: Implement V4L2_CID_JPEG_ACTIVE_MARKER control The Hantro JPEG encoder driver adds various segments to the JPEG header. While it would be quite complicated to make these segments selectable to userspace, given that the driver has to fill in various fields in these segments, and also take care of alignment, it would be nice if the driver could signal to userspace what segments are included. Implement the V4L2_CID_JPEG_ACTIVE_MARKER control, and make it read only so that it always returns the set of segments that the driver adds. Signed-off-by: Chen-Yu Tsai Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 6a51f39dde56..b376b9d94b01 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -332,6 +332,11 @@ static const struct v4l2_ctrl_ops hantro_hevc_ctrl_ops = { .s_ctrl = hantro_hevc_s_ctrl, }; +#define HANTRO_JPEG_ACTIVE_MARKERS (V4L2_JPEG_ACTIVE_MARKER_APP0 | \ + V4L2_JPEG_ACTIVE_MARKER_COM | \ + V4L2_JPEG_ACTIVE_MARKER_DQT | \ + V4L2_JPEG_ACTIVE_MARKER_DHT) + static const struct hantro_ctrl controls[] = { { .codec = HANTRO_JPEG_ENCODER, @@ -343,6 +348,22 @@ static const struct hantro_ctrl controls[] = { .def = 50, .ops = &hantro_jpeg_ctrl_ops, }, + }, { + .codec = HANTRO_JPEG_ENCODER, + .cfg = { + .id = V4L2_CID_JPEG_ACTIVE_MARKER, + .max = HANTRO_JPEG_ACTIVE_MARKERS, + .def = HANTRO_JPEG_ACTIVE_MARKERS, + /* + * Changing the set of active markers/segments also + * messes up the alignment of the JPEG header, which + * is needed to allow the hardware to write directly + * to the output buffer. Implementing this introduces + * a lot of complexity for little gain, as the markers + * enabled is already the minimum required set. + */ + .flags = V4L2_CTRL_FLAG_READ_ONLY, + }, }, { .codec = HANTRO_MPEG2_DECODER, .cfg = { -- cgit v1.2.3 From dc8bfe1e482de4395cf39f2c7cb3b885793ec7b8 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 7 Jan 2022 10:34:54 +0100 Subject: media: hantro: output encoded JPEG content directly to capture buffers Now that the JPEG header length is aligned with bus access boundaries, the JPEG encoder can output to the capture buffers directly without going through a bounce buffer. Do just that, and get rid of all the bounce buffer related code. Signed-off-by: Chen-Yu Tsai Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/TODO | 4 ---- drivers/staging/media/hantro/hantro.h | 1 - drivers/staging/media/hantro/hantro_drv.c | 20 ++++++---------- drivers/staging/media/hantro/hantro_h1_jpeg_enc.c | 24 +++++++++---------- drivers/staging/media/hantro/hantro_hw.h | 11 --------- drivers/staging/media/hantro/hantro_jpeg.c | 28 ---------------------- .../media/hantro/rockchip_vpu2_hw_jpeg_enc.c | 27 +++++++++++---------- drivers/staging/media/hantro/rockchip_vpu_hw.c | 6 ----- 8 files changed, 34 insertions(+), 87 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/TODO b/drivers/staging/media/hantro/TODO index da181dc93069..1d7fed936019 100644 --- a/drivers/staging/media/hantro/TODO +++ b/drivers/staging/media/hantro/TODO @@ -4,7 +4,3 @@ the uABI, it will be required to have the driver in staging. For this reason, we are keeping this driver in staging for now. - -* Instead of having a DMA bounce buffer, it could be possible to use a - normal buffer and memmove() the payload to make space for the header. - This might need to use extra JPEG markers for padding reasons. diff --git a/drivers/staging/media/hantro/hantro.h b/drivers/staging/media/hantro/hantro.h index 06d0f3597694..357f83b86809 100644 --- a/drivers/staging/media/hantro/hantro.h +++ b/drivers/staging/media/hantro/hantro.h @@ -259,7 +259,6 @@ struct hantro_ctx { /* Specific for particular codec modes. */ union { struct hantro_h264_dec_hw_ctx h264_dec; - struct hantro_jpeg_enc_hw_ctx jpeg_enc; struct hantro_mpeg2_dec_hw_ctx mpeg2_dec; struct hantro_vp8_dec_hw_ctx vp8_dec; struct hantro_hevc_dec_hw_ctx hevc_dec; diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index b376b9d94b01..bc9bcb4eaf46 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -219,21 +219,15 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) if (ret) return ret; + dst_vq->bidirectional = true; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES; /* - * When encoding, the CAPTURE queue doesn't need dma memory, - * as the CPU needs to create the JPEG frames, from the - * hardware-produced JPEG payload. - * - * For the DMA destination buffer, we use a bounce buffer. + * The Kernel needs access to the JPEG destination buffer for the + * JPEG encoder to fill in the JPEG headers. */ - if (ctx->is_encoder) { - dst_vq->mem_ops = &vb2_vmalloc_memops; - } else { - dst_vq->bidirectional = true; - dst_vq->mem_ops = &vb2_dma_contig_memops; - dst_vq->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES | - DMA_ATTR_NO_KERNEL_MAPPING; - } + if (!ctx->is_encoder) + dst_vq->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; diff --git a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c index a71f90a01bfc..12d69503d6ba 100644 --- a/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c +++ b/drivers/staging/media/hantro/hantro_h1_jpeg_enc.c @@ -39,17 +39,23 @@ static void hantro_h1_set_src_img_ctrl(struct hantro_dev *vpu, static void hantro_h1_jpeg_enc_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, - struct vb2_buffer *src_buf) + struct vb2_buffer *src_buf, + struct vb2_buffer *dst_buf) { struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; dma_addr_t src[3]; + u32 size_left; + + size_left = vb2_plane_size(dst_buf, 0) - ctx->vpu_dst_fmt->header_size; + if (WARN_ON(vb2_plane_size(dst_buf, 0) < ctx->vpu_dst_fmt->header_size)) + size_left = 0; WARN_ON(pix_fmt->num_planes > 3); - vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma, + vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(dst_buf, 0) + + ctx->vpu_dst_fmt->header_size, H1_REG_ADDR_OUTPUT_STREAM); - vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size, - H1_REG_STR_BUF_LIMIT); + vepu_write_relaxed(vpu, size_left, H1_REG_STR_BUF_LIMIT); if (pix_fmt->num_planes == 1) { src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); @@ -121,7 +127,8 @@ int hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx) H1_REG_ENC_CTRL); hantro_h1_set_src_img_ctrl(vpu, ctx); - hantro_h1_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); + hantro_h1_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf, + &dst_buf->vb2_buf); hantro_h1_jpeg_enc_set_qtable(vpu, jpeg_ctx.hw_luma_qtable, jpeg_ctx.hw_chroma_qtable); @@ -154,13 +161,6 @@ void hantro_h1_jpeg_enc_done(struct hantro_ctx *ctx) u32 bytesused = vepu_read(vpu, H1_REG_STR_BUF_LIMIT) / 8; struct vb2_v4l2_buffer *dst_buf = hantro_get_dst_buf(ctx); - /* - * TODO: Rework the JPEG encoder to eliminate the need - * for a bounce buffer. - */ - memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + - ctx->vpu_dst_fmt->header_size, - ctx->jpeg_enc.bounce_buffer.cpu, bytesused); vb2_set_plane_payload(&dst_buf->vb2_buf, 0, ctx->vpu_dst_fmt->header_size + bytesused); } diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 4a19ae8940b9..c1fd807bc090 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -43,15 +43,6 @@ struct hantro_aux_buf { unsigned long attrs; }; -/** - * struct hantro_jpeg_enc_hw_ctx - * - * @bounce_buffer: Bounce buffer - */ -struct hantro_jpeg_enc_hw_ctx { - struct hantro_aux_buf bounce_buffer; -}; - /* Max. number of entries in the DPB (HW limitation). */ #define HANTRO_H264_DPB_SIZE 16 @@ -327,8 +318,6 @@ void hantro_g1_reset(struct hantro_ctx *ctx); int hantro_h1_jpeg_enc_run(struct hantro_ctx *ctx); int rockchip_vpu2_jpeg_enc_run(struct hantro_ctx *ctx); -int hantro_jpeg_enc_init(struct hantro_ctx *ctx); -void hantro_jpeg_enc_exit(struct hantro_ctx *ctx); void hantro_h1_jpeg_enc_done(struct hantro_ctx *ctx); void rockchip_vpu2_jpeg_enc_done(struct hantro_ctx *ctx); diff --git a/drivers/staging/media/hantro/hantro_jpeg.c b/drivers/staging/media/hantro/hantro_jpeg.c index e63eeef3952d..84d3f0bfff00 100644 --- a/drivers/staging/media/hantro/hantro_jpeg.c +++ b/drivers/staging/media/hantro/hantro_jpeg.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include "hantro_jpeg.h" @@ -339,30 +338,3 @@ void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx) jpeg_set_quality(ctx); } - -int hantro_jpeg_enc_init(struct hantro_ctx *ctx) -{ - ctx->jpeg_enc.bounce_buffer.size = - ctx->dst_fmt.plane_fmt[0].sizeimage - - ctx->vpu_dst_fmt->header_size; - - ctx->jpeg_enc.bounce_buffer.cpu = - dma_alloc_attrs(ctx->dev->dev, - ctx->jpeg_enc.bounce_buffer.size, - &ctx->jpeg_enc.bounce_buffer.dma, - GFP_KERNEL, - DMA_ATTR_ALLOC_SINGLE_PAGES); - if (!ctx->jpeg_enc.bounce_buffer.cpu) - return -ENOMEM; - - return 0; -} - -void hantro_jpeg_enc_exit(struct hantro_ctx *ctx) -{ - dma_free_attrs(ctx->dev->dev, - ctx->jpeg_enc.bounce_buffer.size, - ctx->jpeg_enc.bounce_buffer.cpu, - ctx->jpeg_enc.bounce_buffer.dma, - DMA_ATTR_ALLOC_SINGLE_PAGES); -} diff --git a/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c b/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c index 41a418fe9221..8395c4d48dd0 100644 --- a/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c +++ b/drivers/staging/media/hantro/rockchip_vpu2_hw_jpeg_enc.c @@ -66,17 +66,23 @@ static void rockchip_vpu2_set_src_img_ctrl(struct hantro_dev *vpu, static void rockchip_vpu2_jpeg_enc_set_buffers(struct hantro_dev *vpu, struct hantro_ctx *ctx, - struct vb2_buffer *src_buf) + struct vb2_buffer *src_buf, + struct vb2_buffer *dst_buf) { struct v4l2_pix_format_mplane *pix_fmt = &ctx->src_fmt; dma_addr_t src[3]; + u32 size_left; + + size_left = vb2_plane_size(dst_buf, 0) - ctx->vpu_dst_fmt->header_size; + if (WARN_ON(vb2_plane_size(dst_buf, 0) < ctx->vpu_dst_fmt->header_size)) + size_left = 0; WARN_ON(pix_fmt->num_planes > 3); - vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.dma, + vepu_write_relaxed(vpu, vb2_dma_contig_plane_dma_addr(dst_buf, 0) + + ctx->vpu_dst_fmt->header_size, VEPU_REG_ADDR_OUTPUT_STREAM); - vepu_write_relaxed(vpu, ctx->jpeg_enc.bounce_buffer.size, - VEPU_REG_STR_BUF_LIMIT); + vepu_write_relaxed(vpu, size_left, VEPU_REG_STR_BUF_LIMIT); if (pix_fmt->num_planes == 1) { src[0] = vb2_dma_contig_plane_dma_addr(src_buf, 0); @@ -137,6 +143,9 @@ int rockchip_vpu2_jpeg_enc_run(struct hantro_ctx *ctx) memset(&jpeg_ctx, 0, sizeof(jpeg_ctx)); jpeg_ctx.buffer = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); + if (!jpeg_ctx.buffer) + return -ENOMEM; + jpeg_ctx.width = ctx->dst_fmt.width; jpeg_ctx.height = ctx->dst_fmt.height; jpeg_ctx.quality = ctx->jpeg_quality; @@ -147,7 +156,8 @@ int rockchip_vpu2_jpeg_enc_run(struct hantro_ctx *ctx) VEPU_REG_ENCODE_START); rockchip_vpu2_set_src_img_ctrl(vpu, ctx); - rockchip_vpu2_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf); + rockchip_vpu2_jpeg_enc_set_buffers(vpu, ctx, &src_buf->vb2_buf, + &dst_buf->vb2_buf); rockchip_vpu2_jpeg_enc_set_qtable(vpu, jpeg_ctx.hw_luma_qtable, jpeg_ctx.hw_chroma_qtable); @@ -182,13 +192,6 @@ void rockchip_vpu2_jpeg_enc_done(struct hantro_ctx *ctx) u32 bytesused = vepu_read(vpu, VEPU_REG_STR_BUF_LIMIT) / 8; struct vb2_v4l2_buffer *dst_buf = hantro_get_dst_buf(ctx); - /* - * TODO: Rework the JPEG encoder to eliminate the need - * for a bounce buffer. - */ - memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0) + - ctx->vpu_dst_fmt->header_size, - ctx->jpeg_enc.bounce_buffer.cpu, bytesused); vb2_set_plane_payload(&dst_buf->vb2_buf, 0, ctx->vpu_dst_fmt->header_size + bytesused); } diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c index c203b606e6e7..163cf92eafca 100644 --- a/drivers/staging/media/hantro/rockchip_vpu_hw.c +++ b/drivers/staging/media/hantro/rockchip_vpu_hw.c @@ -343,9 +343,7 @@ static const struct hantro_codec_ops rk3066_vpu_codec_ops[] = { [HANTRO_MODE_JPEG_ENC] = { .run = hantro_h1_jpeg_enc_run, .reset = rockchip_vpu1_enc_reset, - .init = hantro_jpeg_enc_init, .done = hantro_h1_jpeg_enc_done, - .exit = hantro_jpeg_enc_exit, }, [HANTRO_MODE_H264_DEC] = { .run = hantro_g1_h264_dec_run, @@ -371,9 +369,7 @@ static const struct hantro_codec_ops rk3288_vpu_codec_ops[] = { [HANTRO_MODE_JPEG_ENC] = { .run = hantro_h1_jpeg_enc_run, .reset = rockchip_vpu1_enc_reset, - .init = hantro_jpeg_enc_init, .done = hantro_h1_jpeg_enc_done, - .exit = hantro_jpeg_enc_exit, }, [HANTRO_MODE_H264_DEC] = { .run = hantro_g1_h264_dec_run, @@ -399,9 +395,7 @@ static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = { [HANTRO_MODE_JPEG_ENC] = { .run = rockchip_vpu2_jpeg_enc_run, .reset = rockchip_vpu2_enc_reset, - .init = hantro_jpeg_enc_init, .done = rockchip_vpu2_jpeg_enc_done, - .exit = hantro_jpeg_enc_exit, }, [HANTRO_MODE_H264_DEC] = { .run = rockchip_vpu2_h264_dec_run, -- cgit v1.2.3 From 70b0911ad81ceef6ad5a4c7a7053a26368dacb80 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 7 Jan 2022 10:34:55 +0100 Subject: media: hantro: jpeg: Remove open-coded size in quantization table code The quantization tables used in the Hantro JPEG encoder driver are implicitly sized by the data they contain, but the loop that scales the tables based on the compression quality hard codes the size to 64. No code exists to check whether the two actually match. Commit 85bdcb7eaae7 ("media: hantro: Write the quantization tables in proper order") introduced two new tables, with sizes hardcoded to 64, but still no checking if all the sizes are the same. Commit 41479adb5e52 ("media: hantro: Avoid global variable for jpeg quantization tables") added the macro JPEG_QUANT_SIZE, but only the newly added fields used this. This has resulted in code scattered with magic numbers and array sizes that happen to match up, without any sort of sanity checking to enforce it. Drop the hard-coded array sizes, replace the magic loop count with a proper JPEG_QUANT_SIZE macro, and add BUILD_BUG_ON()s to check that all the table sizes match up. Signed-off-by: Chen-Yu Tsai Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_jpeg.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_jpeg.c b/drivers/staging/media/hantro/hantro_jpeg.c index 84d3f0bfff00..d07b1b449b61 100644 --- a/drivers/staging/media/hantro/hantro_jpeg.c +++ b/drivers/staging/media/hantro/hantro_jpeg.c @@ -49,7 +49,7 @@ static const unsigned char chroma_q_table[] = { 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 }; -static const unsigned char zigzag[64] = { +static const unsigned char zigzag[] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, @@ -60,7 +60,7 @@ static const unsigned char zigzag[64] = { 53, 60, 61, 54, 47, 55, 62, 63 }; -static const u32 hw_reorder[64] = { +static const u32 hw_reorder[] = { 0, 8, 16, 24, 1, 9, 17, 25, 32, 40, 48, 56, 33, 41, 49, 57, 2, 10, 18, 26, 3, 11, 19, 27, @@ -292,7 +292,10 @@ jpeg_scale_quant_table(unsigned char *file_q_tab, { int i; - for (i = 0; i < 64; i++) { + BUILD_BUG_ON(ARRAY_SIZE(zigzag) != JPEG_QUANT_SIZE); + BUILD_BUG_ON(ARRAY_SIZE(hw_reorder) != JPEG_QUANT_SIZE); + + for (i = 0; i < JPEG_QUANT_SIZE; i++) { file_q_tab[i] = jpeg_scale_qp(tab[zigzag[i]], scale); reordered_q_tab[i] = jpeg_scale_qp(tab[hw_reorder[i]], scale); } @@ -311,6 +314,11 @@ static void jpeg_set_quality(struct hantro_jpeg_ctx *ctx) else scale = 200 - 2 * ctx->quality; + BUILD_BUG_ON(ARRAY_SIZE(luma_q_table) != JPEG_QUANT_SIZE); + BUILD_BUG_ON(ARRAY_SIZE(chroma_q_table) != JPEG_QUANT_SIZE); + BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_luma_qtable) != JPEG_QUANT_SIZE); + BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_chroma_qtable) != JPEG_QUANT_SIZE); + jpeg_scale_quant_table(ctx->buffer + LUMA_QUANT_OFF, ctx->hw_luma_qtable, luma_q_table, scale); jpeg_scale_quant_table(ctx->buffer + CHROMA_QUANT_OFF, -- cgit v1.2.3 From 94d964e58ad6ba907c4169be99267ef517796614 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 3 Jan 2022 17:24:10 +0100 Subject: media: v4l2-fwnode: Move bus config structure to v4l2_mediabus.h To prepare for usage of the v4l2_fwnode_bus_* data structures to describe bus configuration in the subdev .get_mbus_config() operation, rename the structures with a v4l2_mbus_config_ prefix instead of v4l2_fwnode_bus_, and move them to v4l2_mediabus.h. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5648.c | 4 +- drivers/media/i2c/ov8865.c | 4 +- drivers/media/i2c/tc358743.c | 2 +- drivers/media/platform/qcom/camss/camss.c | 2 +- drivers/media/platform/rcar-vin/rcar-vin.h | 2 +- drivers/media/platform/stm32/stm32-dcmi.c | 2 +- drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h | 2 +- drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c | 2 +- drivers/media/platform/ti-vpe/cal-camerarx.c | 6 +-- drivers/media/v4l2-core/v4l2-fwnode.c | 12 ++--- drivers/staging/media/imx/imx7-mipi-csis.c | 2 +- drivers/staging/media/imx/imx8mq-mipi-csi2.c | 2 +- drivers/staging/media/max96712/max96712.c | 2 +- include/media/v4l2-fwnode.h | 61 +++------------------- include/media/v4l2-mediabus.h | 49 +++++++++++++++++ 15 files changed, 77 insertions(+), 77 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c index 947d437ed0ef..87f9b724cd7f 100644 --- a/drivers/media/i2c/ov5648.c +++ b/drivers/media/i2c/ov5648.c @@ -1112,7 +1112,7 @@ static int ov5648_pad_configure(struct ov5648_sensor *sensor) static int ov5648_mipi_configure(struct ov5648_sensor *sensor) { - struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = + struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 = &sensor->endpoint.bus.mipi_csi2; unsigned int lanes_count = bus_mipi_csi2->num_data_lanes; int ret; @@ -1692,7 +1692,7 @@ static int ov5648_state_mipi_configure(struct ov5648_sensor *sensor, u32 mbus_code) { struct ov5648_ctrls *ctrls = &sensor->ctrls; - struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = + struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 = &sensor->endpoint.bus.mipi_csi2; unsigned long mipi_clk_rate; unsigned int bits_per_sample; diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index d9d016cfa9ac..2b18d8e54098 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -1471,7 +1471,7 @@ static int ov8865_charge_pump_configure(struct ov8865_sensor *sensor) static int ov8865_mipi_configure(struct ov8865_sensor *sensor) { - struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = + struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 = &sensor->endpoint.bus.mipi_csi2; unsigned int lanes_count = bus_mipi_csi2->num_data_lanes; int ret; @@ -2241,7 +2241,7 @@ static int ov8865_state_mipi_configure(struct ov8865_sensor *sensor, u32 mbus_code) { struct ov8865_ctrls *ctrls = &sensor->ctrls; - struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = + struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 = &sensor->endpoint.bus.mipi_csi2; unsigned long mipi_clk_rate; unsigned int bits_per_sample; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 3205cd8298dd..40512004afba 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -69,7 +69,7 @@ static const struct v4l2_dv_timings_cap tc358743_timings_cap = { struct tc358743_state { struct tc358743_platform_data pdata; - struct v4l2_fwnode_bus_mipi_csi2 bus; + struct v4l2_mbus_config_mipi_csi2 bus; struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler hdl; diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c index d9905e737d88..04be5e71feca 100644 --- a/drivers/media/platform/qcom/camss/camss.c +++ b/drivers/media/platform/qcom/camss/camss.c @@ -1035,7 +1035,7 @@ static int camss_of_parse_endpoint_node(struct device *dev, struct camss_async_subdev *csd) { struct csiphy_lanes_cfg *lncfg = &csd->interface.csi2.lane_cfg; - struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2; + struct v4l2_mbus_config_mipi_csi2 *mipi_csi2; struct v4l2_fwnode_endpoint vep = { { 0 } }; unsigned int i; diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 6c06320174a2..7e86e35ca42b 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -118,7 +118,7 @@ struct rvin_parallel_entity { struct v4l2_subdev *subdev; enum v4l2_mbus_type mbus_type; - struct v4l2_fwnode_bus_parallel bus; + struct v4l2_mbus_config_parallel bus; unsigned int source_pad; unsigned int sink_pad; diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index bf76b420352d..c4c65d852525 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -150,7 +150,7 @@ struct stm32_dcmi { struct mutex lock; struct vb2_queue queue; - struct v4l2_fwnode_bus_parallel bus; + struct v4l2_mbus_config_parallel bus; enum v4l2_mbus_type bus_type; struct completion complete; struct clk *mclk; diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h index a5f61ee0ec4d..8eeed87bfb13 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h @@ -124,7 +124,7 @@ struct sun4i_csi { dma_addr_t paddr; } scratch; - struct v4l2_fwnode_bus_parallel bus; + struct v4l2_mbus_config_parallel bus; /* Main Device */ struct v4l2_device v4l; diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c index 2c39cd7f2862..0912a1b6d525 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c @@ -226,7 +226,7 @@ static void return_all_buffers(struct sun4i_csi *csi, static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count) { struct sun4i_csi *csi = vb2_get_drv_priv(vq); - struct v4l2_fwnode_bus_parallel *bus = &csi->bus; + struct v4l2_mbus_config_parallel *bus = &csi->bus; const struct sun4i_csi_format *csi_fmt; unsigned long href_pol, pclk_pol, vref_pol; unsigned long flags; diff --git a/drivers/media/platform/ti-vpe/cal-camerarx.c b/drivers/media/platform/ti-vpe/cal-camerarx.c index 4bf7a8c2e711..6b43a1525b45 100644 --- a/drivers/media/platform/ti-vpe/cal-camerarx.c +++ b/drivers/media/platform/ti-vpe/cal-camerarx.c @@ -47,7 +47,7 @@ static inline void camerarx_write(struct cal_camerarx *phy, u32 offset, u32 val) 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; + struct v4l2_mbus_config_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2; u32 num_lanes = mipi_csi2->num_data_lanes; const struct cal_format_info *fmtinfo; u32 bpp; @@ -76,7 +76,7 @@ static void cal_camerarx_lane_config(struct cal_camerarx *phy) u32 val = cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)); u32 lane_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK; u32 polarity_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK; - struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = + struct v4l2_mbus_config_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2; int lane; @@ -518,7 +518,7 @@ static int cal_camerarx_regmap_init(struct cal_dev *cal, static int cal_camerarx_parse_dt(struct cal_camerarx *phy) { struct v4l2_fwnode_endpoint *endpoint = &phy->endpoint; - char data_lanes[V4L2_FWNODE_CSI2_MAX_DATA_LANES * 2]; + char data_lanes[V4L2_MBUS_CSI2_MAX_DATA_LANES * 2]; struct device_node *ep_node; unsigned int i; int ret; diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 00457e1e93f6..9ff3ebb230e7 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -119,11 +119,11 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep, enum v4l2_mbus_type bus_type) { - struct v4l2_fwnode_bus_mipi_csi2 *bus = &vep->bus.mipi_csi2; + struct v4l2_mbus_config_mipi_csi2 *bus = &vep->bus.mipi_csi2; bool have_clk_lane = false, have_data_lanes = false, have_lane_polarities = false; unsigned int flags = 0, lanes_used = 0; - u32 array[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES]; + u32 array[1 + V4L2_MBUS_CSI2_MAX_DATA_LANES]; u32 clock_lane = 0; unsigned int num_data_lanes = 0; bool use_default_lane_mapping = false; @@ -136,7 +136,7 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, use_default_lane_mapping = true; num_data_lanes = min_t(u32, bus->num_data_lanes, - V4L2_FWNODE_CSI2_MAX_DATA_LANES); + V4L2_MBUS_CSI2_MAX_DATA_LANES); clock_lane = bus->clock_lane; if (clock_lane) @@ -155,7 +155,7 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, rval = fwnode_property_count_u32(fwnode, "data-lanes"); if (rval > 0) { num_data_lanes = - min_t(int, V4L2_FWNODE_CSI2_MAX_DATA_LANES, rval); + min_t(int, V4L2_MBUS_CSI2_MAX_DATA_LANES, rval); fwnode_property_read_u32_array(fwnode, "data-lanes", array, num_data_lanes); @@ -263,7 +263,7 @@ v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep, enum v4l2_mbus_type bus_type) { - struct v4l2_fwnode_bus_parallel *bus = &vep->bus.parallel; + struct v4l2_mbus_config_parallel *bus = &vep->bus.parallel; unsigned int flags = 0; u32 v; @@ -369,7 +369,7 @@ v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep, enum v4l2_mbus_type bus_type) { - struct v4l2_fwnode_bus_mipi_csi1 *bus = &vep->bus.mipi_csi1; + struct v4l2_mbus_config_mipi_csi1 *bus = &vep->bus.mipi_csi1; u32 v; if (!fwnode_property_read_u32(fwnode, "clock-inv", &v)) { diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index a8710dc24560..a22d0e6b3d44 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -318,7 +318,7 @@ struct csi_state { struct v4l2_async_notifier notifier; struct v4l2_subdev *src_sd; - struct v4l2_fwnode_bus_mipi_csi2 bus; + struct v4l2_mbus_config_mipi_csi2 bus; u32 clk_frequency; u32 hs_settle; u32 clk_settle; diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c index 3b9fa75efac6..56ef3b3b2906 100644 --- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -117,7 +117,7 @@ struct csi_state { struct v4l2_async_notifier notifier; struct v4l2_subdev *src_sd; - struct v4l2_fwnode_bus_mipi_csi2 bus; + struct v4l2_mbus_config_mipi_csi2 bus; struct mutex lock; /* Protect csi2_fmt, format_mbus, state, hs_settle */ const struct csi2_pix_format *csi2_fmt; diff --git a/drivers/staging/media/max96712/max96712.c b/drivers/staging/media/max96712/max96712.c index 9bc72d9a858b..6b5abd958bff 100644 --- a/drivers/staging/media/max96712/max96712.c +++ b/drivers/staging/media/max96712/max96712.c @@ -30,7 +30,7 @@ struct max96712_priv { struct regmap *regmap; struct gpio_desc *gpiod_pwdn; - struct v4l2_fwnode_bus_mipi_csi2 mipi; + struct v4l2_mbus_config_mipi_csi2 mipi; struct v4l2_subdev sd; struct v4l2_ctrl_handler ctrl_handler; diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index 9c97f1dbd1c6..feb132df45a3 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -25,68 +25,19 @@ struct fwnode_handle; struct v4l2_async_notifier; struct v4l2_async_subdev; -#define V4L2_FWNODE_CSI2_MAX_DATA_LANES 8 - -/** - * struct v4l2_fwnode_bus_mipi_csi2 - MIPI CSI-2 bus data structure - * @flags: media bus (V4L2_MBUS_*) flags - * @data_lanes: an array of physical data lane indexes - * @clock_lane: physical lane index of the clock lane - * @num_data_lanes: number of data lanes - * @lane_polarities: polarity of the lanes. The order is the same of - * the physical lanes. - */ -struct v4l2_fwnode_bus_mipi_csi2 { - unsigned int flags; - unsigned char data_lanes[V4L2_FWNODE_CSI2_MAX_DATA_LANES]; - unsigned char clock_lane; - unsigned char num_data_lanes; - bool lane_polarities[1 + V4L2_FWNODE_CSI2_MAX_DATA_LANES]; -}; - -/** - * struct v4l2_fwnode_bus_parallel - parallel data bus data structure - * @flags: media bus (V4L2_MBUS_*) flags - * @bus_width: bus width in bits - * @data_shift: data shift in bits - */ -struct v4l2_fwnode_bus_parallel { - unsigned int flags; - unsigned char bus_width; - unsigned char data_shift; -}; - -/** - * struct v4l2_fwnode_bus_mipi_csi1 - CSI-1/CCP2 data bus structure - * @clock_inv: polarity of clock/strobe signal - * false - not inverted, true - inverted - * @strobe: false - data/clock, true - data/strobe - * @lane_polarity: the polarities of the clock (index 0) and data lanes - * index (1) - * @data_lane: the number of the data lane - * @clock_lane: the number of the clock lane - */ -struct v4l2_fwnode_bus_mipi_csi1 { - unsigned char clock_inv:1; - unsigned char strobe:1; - bool lane_polarity[2]; - unsigned char data_lane; - unsigned char clock_lane; -}; - /** * struct v4l2_fwnode_endpoint - the endpoint data structure * @base: fwnode endpoint of the v4l2_fwnode * @bus_type: bus type * @bus: bus configuration data structure - * @bus.parallel: embedded &struct v4l2_fwnode_bus_parallel. + * @bus.parallel: embedded &struct v4l2_mbus_config_parallel. * Used if the bus is parallel. - * @bus.mipi_csi1: embedded &struct v4l2_fwnode_bus_mipi_csi1. + * @bus.mipi_csi1: embedded &struct v4l2_mbus_config_mipi_csi1. * Used if the bus is MIPI Alliance's Camera Serial * Interface version 1 (MIPI CSI1) or Standard * Mobile Imaging Architecture's Compact Camera Port 2 * (SMIA CCP2). - * @bus.mipi_csi2: embedded &struct v4l2_fwnode_bus_mipi_csi2. + * @bus.mipi_csi2: embedded &struct v4l2_mbus_config_mipi_csi2. * Used if the bus is MIPI Alliance's Camera Serial * Interface version 2 (MIPI CSI2). * @link_frequencies: array of supported link frequencies @@ -100,9 +51,9 @@ struct v4l2_fwnode_endpoint { */ enum v4l2_mbus_type bus_type; struct { - struct v4l2_fwnode_bus_parallel parallel; - struct v4l2_fwnode_bus_mipi_csi1 mipi_csi1; - struct v4l2_fwnode_bus_mipi_csi2 mipi_csi2; + struct v4l2_mbus_config_parallel parallel; + struct v4l2_mbus_config_mipi_csi1 mipi_csi1; + struct v4l2_mbus_config_mipi_csi2 mipi_csi2; } bus; u64 *link_frequencies; unsigned int nr_of_link_frequencies; diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index 96af9cedacde..9c4970fbd8ea 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -92,6 +92,55 @@ V4L2_MBUS_CSI2_CHANNEL_2 | \ V4L2_MBUS_CSI2_CHANNEL_3) +#define V4L2_MBUS_CSI2_MAX_DATA_LANES 8 + +/** + * struct v4l2_mbus_config_mipi_csi2 - MIPI CSI-2 data bus configuration + * @flags: media bus (V4L2_MBUS_*) flags + * @data_lanes: an array of physical data lane indexes + * @clock_lane: physical lane index of the clock lane + * @num_data_lanes: number of data lanes + * @lane_polarities: polarity of the lanes. The order is the same of + * the physical lanes. + */ +struct v4l2_mbus_config_mipi_csi2 { + unsigned int flags; + unsigned char data_lanes[V4L2_MBUS_CSI2_MAX_DATA_LANES]; + unsigned char clock_lane; + unsigned char num_data_lanes; + bool lane_polarities[1 + V4L2_MBUS_CSI2_MAX_DATA_LANES]; +}; + +/** + * struct v4l2_mbus_config_parallel - parallel data bus configuration + * @flags: media bus (V4L2_MBUS_*) flags + * @bus_width: bus width in bits + * @data_shift: data shift in bits + */ +struct v4l2_mbus_config_parallel { + unsigned int flags; + unsigned char bus_width; + unsigned char data_shift; +}; + +/** + * struct v4l2_mbus_config_mipi_csi1 - CSI-1/CCP2 data bus configuration + * @clock_inv: polarity of clock/strobe signal + * false - not inverted, true - inverted + * @strobe: false - data/clock, true - data/strobe + * @lane_polarity: the polarities of the clock (index 0) and data lanes + * index (1) + * @data_lane: the number of the data lane + * @clock_lane: the number of the clock lane + */ +struct v4l2_mbus_config_mipi_csi1 { + unsigned char clock_inv:1; + unsigned char strobe:1; + bool lane_polarity[2]; + unsigned char data_lane; + unsigned char clock_lane; +}; + /** * enum v4l2_mbus_type - media bus type * @V4L2_MBUS_UNKNOWN: unknown bus type, no V4L2 mediabus configuration -- cgit v1.2.3 From 01f4eab2d24498931aaeb7131f25c9a523604772 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 16 Jan 2022 22:51:56 +0100 Subject: media: atomisp: Don't use ifdef on IS_ISP2401 IS_ISP2401 is a function like macro which is always defined, so it must not be used together with #ifdef. #ifdef checks should check for "ISP2401", not "IS_ISP2401". Link: https://lore.kernel.org/linux-media/20220116215204.307649-2-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_compat_css20.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c index 1173be0e72b0..781a11cca599 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp_compat_css20.c @@ -963,7 +963,7 @@ int atomisp_css_irq_translate(struct atomisp_device *isp, void atomisp_css_rx_get_irq_info(enum mipi_port_id port, unsigned int *infos) { -#ifndef IS_ISP2401 +#ifndef ISP2401 ia_css_isys_rx_get_irq_info(port, infos); #else *infos = 0; @@ -973,7 +973,7 @@ void atomisp_css_rx_get_irq_info(enum mipi_port_id port, void atomisp_css_rx_clear_irq_info(enum mipi_port_id port, unsigned int infos) { -#ifndef IS_ISP2401 +#ifndef ISP2401 ia_css_isys_rx_clear_irq_info(port, infos); #endif } -- cgit v1.2.3 From 3a465823170bfb99e7281d8aa25f025854552b71 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 16 Jan 2022 22:51:57 +0100 Subject: media: atomisp: Don't use ifdef ISP2400 IPS2400 is never defined, for ISP2401 builds ISP2401 gets defined and for ISP2400 nothing gets defined, so any #ifdef ISP2400 checks should be #ifndef ISP2401 checks instead. Link: https://lore.kernel.org/linux-media/20220116215204.307649-3-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 1b240891a6e2..52a367feaeee 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -1467,7 +1467,7 @@ static bool is_valid_device(struct pci_dev *pdev, const struct pci_device_id *id * remove the if once the driver become generic */ -#if defined(ISP2400) +#ifndef ISP2401 if (IS_ISP2401) { dev_err(&pdev->dev, "Support for %s (ISP2401) was disabled at compile time\n", name); -- cgit v1.2.3 From 144593116bf3c028aa0700ba1ba60acfc19d737e Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 16 Jan 2022 22:51:58 +0100 Subject: media: atomisp: Use irci_stable_candrpv_0415_20150423_1753 fw for byt There is no irci_stable_candrpv_0415_20150521_0458 build for the isp2400/byt version of the atomisp2. There is however an irci_stable_candrpv_0415_20150423_1753 version which according to: https://github.com/intel/ProductionKernelQuilts/blob/master/uefi/cht-m1stable/patches/cam-041 Has the exact same fw ABI, so use that on the isp2400. Link: https://lore.kernel.org/linux-media/20220116215204.307649-4-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/sh_css_firmware.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/sh_css_firmware.c index 94149647b98b..dd688f8ab649 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/sh_css_firmware.c @@ -56,7 +56,11 @@ static struct firmware_header *firmware_header; * which will be replaced with the actual RELEASE_VERSION * during package generation. Please do not modify */ +#ifdef ISP2401 static const char *release_version = STR(irci_stable_candrpv_0415_20150521_0458); +#else +static const char *release_version = STR(irci_stable_candrpv_0415_20150423_1753); +#endif #define MAX_FW_REL_VER_NAME 300 static char FW_rel_ver_name[MAX_FW_REL_VER_NAME] = "---"; -- cgit v1.2.3 From 9bad7640dcd64d7054601b0f43b52a0af387413f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 16 Jan 2022 22:51:59 +0100 Subject: media: atomisp_gmin_platform: Fix axp_regulator_set() writing to the wrong register The second write done in axp_regulator_set() must go to the ctrl_reg which turns the various regulators on/off. This replaces the second write writing the sel_reg, which sets the voltage for the regulator, for a second time with a wrong value. Link: https://lore.kernel.org/linux-media/20220116215204.307649-5-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 1cc581074ba7..a29e5086ffe1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -741,7 +741,7 @@ static int axp_regulator_set(struct device *dev, struct gmin_subdev *gs, val = on ? 1 << shift : 0; - ret = gmin_i2c_write(dev, gs->pwm_i2c_addr, sel_reg, val, 1 << shift); + ret = gmin_i2c_write(dev, gs->pwm_i2c_addr, ctrl_reg, val, 1 << shift); if (ret) return ret; -- cgit v1.2.3 From 74bfe151d0aa06c76d35ae5ee02f6897240a2094 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 16 Jan 2022 22:52:00 +0100 Subject: media: atomisp_gmin_platform: Add enable-count to gmin_[v1p8|v2p8]_ctrl() On devices with 2 sensors the 2 sensors may get probed simultaneously and the v1p8 and v2p8 regulators are ususally shared between the 2 sensors. This means that the probe() function of sensor 1 may end up calling gmin_v1p8_ctrl(..., false) turning the regulator off while sensor 2's probe() function still needs it to be on, causing the probe() of sensor 2 to sometimes fail. Fix this by adding an enable-count for both regulators and only disabling them again when that goes to 0. Note all this really should be converted to use the standard kernel regulator framework, I have doing this on my long term TODO list, this fix is only meant as a temporary workaround for the issue. Link: https://lore.kernel.org/linux-media/20220116215204.307649-6-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp_gmin_platform.c | 86 ++++++++++++++++------ 1 file changed, 65 insertions(+), 21 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index a29e5086ffe1..960c64ecdfe4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -118,6 +118,10 @@ static const char *pmic_name[] = { [PMIC_CRYSTALCOVE] = "Crystal Cove PMIC", }; +static DEFINE_MUTEX(gmin_regulator_mutex); +static int gmin_v1p8_enable_count; +static int gmin_v2p8_enable_count; + /* The atomisp uses type==0 for the end-of-list marker, so leave space. */ static struct intel_v4l2_subdev_table pdata_subdevs[MAX_SUBDEVS + 1]; @@ -851,38 +855,58 @@ static int gmin_v1p8_ctrl(struct v4l2_subdev *subdev, int on) gs->v1p8_on = on; + ret = 0; + mutex_lock(&gmin_regulator_mutex); + if (on) { + gmin_v1p8_enable_count++; + if (gmin_v1p8_enable_count > 1) + goto out; /* Already on */ + } else { + gmin_v1p8_enable_count--; + if (gmin_v1p8_enable_count > 0) + goto out; /* Still needed */ + } + if (gs->v1p8_gpio >= 0) gpio_set_value(gs->v1p8_gpio, on); if (gs->v1p8_reg) { regulator_set_voltage(gs->v1p8_reg, 1800000, 1800000); if (on) - return regulator_enable(gs->v1p8_reg); + ret = regulator_enable(gs->v1p8_reg); else - return regulator_disable(gs->v1p8_reg); + ret = regulator_disable(gs->v1p8_reg); + + goto out; } switch (pmic_id) { case PMIC_AXP: if (on) - return axp_v1p8_on(subdev->dev, gs); + ret = axp_v1p8_on(subdev->dev, gs); else - return axp_v1p8_off(subdev->dev, gs); + ret = axp_v1p8_off(subdev->dev, gs); + break; case PMIC_TI: value = on ? LDO_1P8V_ON : LDO_1P8V_OFF; - return gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - LDO10_REG, value, 0xff); + ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, + LDO10_REG, value, 0xff); + break; case PMIC_CRYSTALCOVE: value = on ? CRYSTAL_ON : CRYSTAL_OFF; - return gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_1P8V_REG, value, 0xff); + ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, + CRYSTAL_1P8V_REG, value, 0xff); + break; default: - dev_err(subdev->dev, "Couldn't set power mode for v1p2\n"); + dev_err(subdev->dev, "Couldn't set power mode for v1p8\n"); + ret = -EINVAL; } - return -EINVAL; +out: + mutex_unlock(&gmin_regulator_mutex); + return ret; } static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) @@ -908,37 +932,57 @@ static int gmin_v2p8_ctrl(struct v4l2_subdev *subdev, int on) return 0; gs->v2p8_on = on; + ret = 0; + mutex_lock(&gmin_regulator_mutex); + if (on) { + gmin_v2p8_enable_count++; + if (gmin_v2p8_enable_count > 1) + goto out; /* Already on */ + } else { + gmin_v2p8_enable_count--; + if (gmin_v2p8_enable_count > 0) + goto out; /* Still needed */ + } + if (gs->v2p8_gpio >= 0) gpio_set_value(gs->v2p8_gpio, on); if (gs->v2p8_reg) { regulator_set_voltage(gs->v2p8_reg, 2900000, 2900000); if (on) - return regulator_enable(gs->v2p8_reg); + ret = regulator_enable(gs->v2p8_reg); else - return regulator_disable(gs->v2p8_reg); + ret = regulator_disable(gs->v2p8_reg); + + goto out; } switch (pmic_id) { case PMIC_AXP: - return axp_regulator_set(subdev->dev, gs, ALDO1_SEL_REG, - ALDO1_2P8V, ALDO1_CTRL3_REG, - ALDO1_CTRL3_SHIFT, on); + ret = axp_regulator_set(subdev->dev, gs, ALDO1_SEL_REG, + ALDO1_2P8V, ALDO1_CTRL3_REG, + ALDO1_CTRL3_SHIFT, on); + break; case PMIC_TI: value = on ? LDO_2P8V_ON : LDO_2P8V_OFF; - return gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - LDO9_REG, value, 0xff); + ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, + LDO9_REG, value, 0xff); + break; case PMIC_CRYSTALCOVE: value = on ? CRYSTAL_ON : CRYSTAL_OFF; - return gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, - CRYSTAL_2P8V_REG, value, 0xff); + ret = gmin_i2c_write(subdev->dev, gs->pwm_i2c_addr, + CRYSTAL_2P8V_REG, value, 0xff); + break; default: - dev_err(subdev->dev, "Couldn't set power mode for v1p2\n"); + dev_err(subdev->dev, "Couldn't set power mode for v2p8\n"); + ret = -EINVAL; } - return -EINVAL; +out: + mutex_unlock(&gmin_regulator_mutex); + return ret; } static int gmin_acpi_pm_ctrl(struct v4l2_subdev *subdev, int on) -- cgit v1.2.3 From 9aa32cb5c69dc9284a799f60ea2a5e21eae78058 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 16 Jan 2022 22:52:01 +0100 Subject: media: atomisp_gmin_platform: Set ELDO1 to 1.6V on devices with an AXP288 PMIC Testing on multiple tablet models has shown that Android always uses 1.6V for ELDO1, adjust our code to match. This also matches with how ELDO1 is used in the DSDTs on these devices, where for Cherry Trail (ISP2401) based devices ELDO1 is used for an ACPI power-resource which is named "P16P". Note on Bay Trail (ISP2400) based devices the power-resource is called "P15P", which suggests that 1.5V might be a better value there. Link: https://lore.kernel.org/linux-media/20220116215204.307649-7-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 960c64ecdfe4..1c3fd72895ec 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -38,7 +38,7 @@ enum clock_rate { #define ELDO_CTRL_REG 0x12 #define ELDO1_SEL_REG 0x19 -#define ELDO1_1P8V 0x16 +#define ELDO1_1P6V 0x12 #define ELDO1_CTRL_SHIFT 0x00 #define ELDO2_SEL_REG 0x1a @@ -89,7 +89,7 @@ struct gmin_subdev { u8 pwm_i2c_addr; /* For PMIC AXP */ - int eldo1_sel_reg, eldo1_1p8v, eldo1_ctrl_shift; + int eldo1_sel_reg, eldo1_1p6v, eldo1_ctrl_shift; int eldo2_sel_reg, eldo2_1p8v, eldo2_ctrl_shift; }; @@ -685,9 +685,9 @@ static int gmin_subdev_add(struct gmin_subdev *gs) break; case PMIC_AXP: - gs->eldo1_1p8v = gmin_get_var_int(dev, false, + gs->eldo1_1p6v = gmin_get_var_int(dev, false, "eldo1_1p8v", - ELDO1_1P8V); + ELDO1_1P6V); gs->eldo1_sel_reg = gmin_get_var_int(dev, false, "eldo1_sel_reg", ELDO1_SEL_REG); @@ -767,8 +767,8 @@ static int axp_v1p8_on(struct device *dev, struct gmin_subdev *gs) */ usleep_range(110, 150); - ret = axp_regulator_set(dev, gs, gs->eldo1_sel_reg, gs->eldo1_1p8v, - ELDO_CTRL_REG, gs->eldo1_ctrl_shift, true); + ret = axp_regulator_set(dev, gs, gs->eldo1_sel_reg, gs->eldo1_1p6v, + ELDO_CTRL_REG, gs->eldo1_ctrl_shift, true); if (ret) return ret; @@ -781,7 +781,7 @@ static int axp_v1p8_off(struct device *dev, struct gmin_subdev *gs) { int ret; - ret = axp_regulator_set(dev, gs, gs->eldo1_sel_reg, gs->eldo1_1p8v, + ret = axp_regulator_set(dev, gs, gs->eldo1_sel_reg, gs->eldo1_1p6v, ELDO_CTRL_REG, gs->eldo1_ctrl_shift, false); if (ret) return ret; -- cgit v1.2.3 From ee328dded2274a7e1a65988b289337d52e70951c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 16 Jan 2022 22:52:02 +0100 Subject: media: atomisp_gmin_platform: Do not turn ELDO2 off from axp_v1p8_on() Fix axp_v1p8_on() turning ELDO2 off at the end again by removing the bogus code which turns it off again after just having turned it on. Link: https://lore.kernel.org/linux-media/20220116215204.307649-8-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 1c3fd72895ec..84a453118bd9 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -769,11 +769,6 @@ static int axp_v1p8_on(struct device *dev, struct gmin_subdev *gs) ret = axp_regulator_set(dev, gs, gs->eldo1_sel_reg, gs->eldo1_1p6v, ELDO_CTRL_REG, gs->eldo1_ctrl_shift, true); - if (ret) - return ret; - - ret = axp_regulator_set(dev, gs, gs->eldo2_sel_reg, gs->eldo2_1p8v, - ELDO_CTRL_REG, gs->eldo2_ctrl_shift, false); return ret; } -- cgit v1.2.3 From f88fba1a411cc461b2563fb08715831745012830 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 16 Jan 2022 22:52:03 +0100 Subject: media: atomisp_gmin_platform: Base CsiPort default on detected CLK On devices with 2 cameras and no _DSM / EFI-vars providing CsiPort clock info, defaulting to CsiPort 0 obviously is wrong for 1 of the 2 cameras. The Intel Cherry Trail (ISP2401) reference design combines: pmc_plt_clk_2 with CsiPort 0 pmc_plt_clk_4 with CsiPort 1 The Intel Bay Trail (ISP2400) reference design combines: pmc_plt_clk_1 with CsiPort 0 pmc_plt_clk_0 with CsiPort 1 Use this knowledge to set the default CsiPort value based on the detected CLK for the sensor. Link: https://lore.kernel.org/linux-media/20220116215204.307649-9-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp_gmin_platform.c | 23 +++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 84a453118bd9..544e3e7b3aaf 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -540,7 +540,7 @@ static int gmin_subdev_add(struct gmin_subdev *gs) struct i2c_client *client = v4l2_get_subdevdata(gs->subdev); struct device *dev = &client->dev; struct acpi_device *adev = ACPI_COMPANION(dev); - int ret, clock_num = -1; + int ret, default_val, clock_num = -1; dev_info(dev, "%s: ACPI path is %pfw\n", __func__, dev_fwnode(dev)); @@ -548,7 +548,20 @@ static int gmin_subdev_add(struct gmin_subdev *gs) gs->clock_src = gmin_get_var_int(dev, false, "ClkSrc", VLV2_CLK_PLL_19P2MHZ); - gs->csi_port = gmin_get_var_int(dev, false, "CsiPort", 0); + /* + * Get ACPI _PR0 derived clock here already because it is used + * to determine the csi_port default. + */ + if (acpi_device_power_manageable(adev)) + clock_num = atomisp_get_acpi_power(dev); + + /* Compare clock to CsiPort 1 pmc-clock used in the CHT/BYT reference designs */ + if (IS_ISP2401) + default_val = clock_num == 4 ? 1 : 0; + else + default_val = clock_num == 0 ? 1 : 0; + + gs->csi_port = gmin_get_var_int(dev, false, "CsiPort", default_val); gs->csi_lanes = gmin_get_var_int(dev, false, "CsiLanes", 1); gs->gpio0 = gpiod_get_index(dev, NULL, 0, GPIOD_OUT_LOW); @@ -629,11 +642,7 @@ static int gmin_subdev_add(struct gmin_subdev *gs) * otherwise. */ - /* Try first to use ACPI to get the clock resource */ - if (acpi_device_power_manageable(adev)) - clock_num = atomisp_get_acpi_power(dev); - - /* Fall-back use EFI and/or DMI match */ + /* If getting the clock from _PR0 above failed, fall-back to EFI and/or DMI match */ if (clock_num < 0) clock_num = gmin_get_var_int(dev, false, "CamClk", 0); -- cgit v1.2.3 From 2c39a01154ea57d596470afa1d278e3be3b37f6a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 16 Jan 2022 22:52:04 +0100 Subject: media: atomisp_gmin_platform: Add DMI quirk to not turn AXP ELDO2 regulator off on some boards The TrekStor SurfTab duo W1 10.1 has a hw bug where turning eldo2 back on after having turned it off causes the CPLM3218 ambient-light-sensor on the front camera sensor's I2C bus to crash, hanging the bus. Add a DMI quirk table for systems on which to leave eldo2 on. Note an alternative fix is to turn off the CPLM3218 ambient-light-sensor as long as the camera sensor is being used, this is what Windows seems to do as a workaround (based on analyzing the DSDT). But that is not easy to do cleanly under Linux. Link: https://lore.kernel.org/linux-media/20220116215204.307649-10-hdegoede@redhat.com Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/atomisp_gmin_platform.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c index 544e3e7b3aaf..7e47db82de07 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/pci/atomisp_gmin_platform.c @@ -761,6 +761,21 @@ static int axp_regulator_set(struct device *dev, struct gmin_subdev *gs, return 0; } +/* + * Some boards contain a hw-bug where turning eldo2 back on after having turned + * it off causes the CPLM3218 ambient-light-sensor on the image-sensor's I2C bus + * to crash, hanging the bus. Do not turn eldo2 off on these systems. + */ +static const struct dmi_system_id axp_leave_eldo2_on_ids[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), + DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab duo W1 10.1 (VT4)"), + }, + }, + { } +}; + static int axp_v1p8_on(struct device *dev, struct gmin_subdev *gs) { int ret; @@ -790,6 +805,9 @@ static int axp_v1p8_off(struct device *dev, struct gmin_subdev *gs) if (ret) return ret; + if (dmi_check_system(axp_leave_eldo2_on_ids)) + return 0; + ret = axp_regulator_set(dev, gs, gs->eldo2_sel_reg, gs->eldo2_1p8v, ELDO_CTRL_REG, gs->eldo2_ctrl_shift, false); return ret; -- cgit v1.2.3 From 4caba767ca7b07fde3e895780d945b004d6a4275 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 9 Jan 2022 20:51:29 +0100 Subject: media: atomisp: make array idx_map static const Don't populate the read-only array idx_map on the stack but instead it static const. Also makes the object code a little smaller. Link: https://lore.kernel.org/linux-media/20220109195129.46118-1-colin.i.king@gmail.com Signed-off-by: Colin Ian King Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.c index 562662ab8a44..a70bce1179da 100644 --- a/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.c +++ b/drivers/staging/media/atomisp/pci/isp/kernels/macc/macc1_5/ia_css_macc1_5.host.c @@ -44,7 +44,7 @@ ia_css_macc1_5_vmem_encode( unsigned int size) { unsigned int i, j, k, idx; - unsigned int idx_map[] = { + static const unsigned int idx_map[] = { 0, 1, 3, 2, 6, 7, 5, 4, 12, 13, 15, 14, 10, 11, 9, 8 }; -- cgit v1.2.3 From 64288aa9e4199078fffc091b2bcf7ca9834317b9 Mon Sep 17 00:00:00 2001 From: Moses Christopher Bollavarapu Date: Sun, 6 Feb 2022 19:52:32 +0100 Subject: media: staging: media: atomisp: Use BIT macro instead of left shifting There is a BIT(nr) macro available in Linux Kernel, which does the same thing. Example: BIT(7) = (1UL << 7) Link: https://lore.kernel.org/linux-media/20220206185232.21726-1-mosescb.dev@gmail.com Signed-off-by: Moses Christopher Bollavarapu Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_v4l2.c | 19 +++--- .../staging/media/atomisp/pci/ia_css_acc_types.h | 5 +- drivers/staging/media/atomisp/pci/ia_css_env.h | 9 +-- .../media/atomisp/pci/ia_css_event_public.h | 33 +++++----- drivers/staging/media/atomisp/pci/ia_css_irq.h | 77 +++++++++++----------- .../pci/runtime/debug/interface/ia_css_debug.h | 31 ++++----- 6 files changed, 90 insertions(+), 84 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c index 52a367feaeee..49ccfb1646da 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -626,11 +627,11 @@ static int atomisp_mrfld_pre_power_down(struct atomisp_device *isp) * IRQ, if so, waiting for it to be served */ pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &irq); - irq = irq & 1 << INTR_IIR; + irq &= BIT(INTR_IIR); pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, irq); pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &irq); - if (!(irq & (1 << INTR_IIR))) + if (!(irq & BIT(INTR_IIR))) goto done; atomisp_css2_hw_store_32(MRFLD_INTR_CLEAR_REG, 0xFFFFFFFF); @@ -643,11 +644,11 @@ static int atomisp_mrfld_pre_power_down(struct atomisp_device *isp) return -EAGAIN; } else { pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &irq); - irq = irq & 1 << INTR_IIR; + irq &= BIT(INTR_IIR); pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, irq); pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &irq); - if (!(irq & (1 << INTR_IIR))) { + if (!(irq & BIT(INTR_IIR))) { atomisp_css2_hw_store_32(MRFLD_INTR_ENABLE_REG, 0x0); goto done; } @@ -666,7 +667,7 @@ done: * HW sighting:4568410. */ pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &irq); - irq &= ~(1 << INTR_IER); + irq &= ~BIT(INTR_IER); pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, irq); atomisp_msi_irq_uninit(isp); @@ -1549,7 +1550,7 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i start = pci_resource_start(pdev, ATOM_ISP_PCI_BAR); dev_dbg(&pdev->dev, "start: 0x%x\n", start); - err = pcim_iomap_regions(pdev, 1 << ATOM_ISP_PCI_BAR, pci_name(pdev)); + err = pcim_iomap_regions(pdev, BIT(ATOM_ISP_PCI_BAR), pci_name(pdev)); if (err) { dev_err(&pdev->dev, "Failed to I/O memory remapping (%d)\n", err); goto ioremap_fail; @@ -1838,11 +1839,11 @@ load_fw_fail: */ pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &irq); - irq = irq & 1 << INTR_IIR; + irq &= BIT(INTR_IIR); pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, irq); pci_read_config_dword(pdev, PCI_INTERRUPT_CTRL, &irq); - irq &= ~(1 << INTR_IER); + irq &= ~BIT(INTR_IER); pci_write_config_dword(pdev, PCI_INTERRUPT_CTRL, irq); atomisp_msi_irq_uninit(isp); @@ -1854,7 +1855,7 @@ load_fw_fail: dev_err(&pdev->dev, "Failed to switch off ISP\n"); atomisp_dev_alloc_fail: - pcim_iounmap_regions(pdev, 1 << ATOM_ISP_PCI_BAR); + pcim_iounmap_regions(pdev, BIT(ATOM_ISP_PCI_BAR)); ioremap_fail: return err; diff --git a/drivers/staging/media/atomisp/pci/ia_css_acc_types.h b/drivers/staging/media/atomisp/pci/ia_css_acc_types.h index d0ce2f8ba653..a20879aedef6 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_acc_types.h +++ b/drivers/staging/media/atomisp/pci/ia_css_acc_types.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "ia_css_types.h" #include "ia_css_frame_format.h" @@ -466,7 +467,7 @@ struct ia_css_acc_fw { enum ia_css_sp_sleep_mode { SP_DISABLE_SLEEP_MODE = 0, - SP_SLEEP_AFTER_FRAME = 1 << 0, - SP_SLEEP_AFTER_IRQ = 1 << 1 + SP_SLEEP_AFTER_FRAME = BIT(0), + SP_SLEEP_AFTER_IRQ = BIT(1), }; #endif /* _IA_CSS_ACC_TYPES_H */ diff --git a/drivers/staging/media/atomisp/pci/ia_css_env.h b/drivers/staging/media/atomisp/pci/ia_css_env.h index 3b89bbd837a0..42bb1ec1c22d 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_env.h +++ b/drivers/staging/media/atomisp/pci/ia_css_env.h @@ -18,6 +18,7 @@ #include #include /* va_list */ +#include #include "ia_css_types.h" #include "ia_css_acc_types.h" @@ -28,10 +29,10 @@ /* Memory allocation attributes, for use in ia_css_css_mem_env. */ enum ia_css_mem_attr { - IA_CSS_MEM_ATTR_CACHED = 1 << 0, - IA_CSS_MEM_ATTR_ZEROED = 1 << 1, - IA_CSS_MEM_ATTR_PAGEALIGN = 1 << 2, - IA_CSS_MEM_ATTR_CONTIGUOUS = 1 << 3, + IA_CSS_MEM_ATTR_CACHED = BIT(0), + IA_CSS_MEM_ATTR_ZEROED = BIT(1), + IA_CSS_MEM_ATTR_PAGEALIGN = BIT(2), + IA_CSS_MEM_ATTR_CONTIGUOUS = BIT(3), }; /* Environment with function pointers for local IA memory allocation. diff --git a/drivers/staging/media/atomisp/pci/ia_css_event_public.h b/drivers/staging/media/atomisp/pci/ia_css_event_public.h index 76219d741d2e..b052648d4fc2 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_event_public.h +++ b/drivers/staging/media/atomisp/pci/ia_css_event_public.h @@ -24,6 +24,7 @@ #include /* ia_css_err */ #include /* ia_css_pipe */ #include /* ia_css_timer */ +#include /* The event type, distinguishes the kind of events that * can are generated by the CSS system. @@ -35,38 +36,38 @@ * 4) "enum ia_css_event_type convert_event_sp_to_host_domain" (sh_css.c) */ enum ia_css_event_type { - IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE = 1 << 0, + IA_CSS_EVENT_TYPE_OUTPUT_FRAME_DONE = BIT(0), /** Output frame ready. */ - IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE = 1 << 1, + IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE = BIT(1), /** Second output frame ready. */ - IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE = 1 << 2, + IA_CSS_EVENT_TYPE_VF_OUTPUT_FRAME_DONE = BIT(2), /** Viewfinder Output frame ready. */ - IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE = 1 << 3, + IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE = BIT(3), /** Second viewfinder Output frame ready. */ - IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE = 1 << 4, + IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE = BIT(4), /** Indication that 3A statistics are available. */ - IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE = 1 << 5, + IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE = BIT(5), /** Indication that DIS statistics are available. */ - IA_CSS_EVENT_TYPE_PIPELINE_DONE = 1 << 6, + IA_CSS_EVENT_TYPE_PIPELINE_DONE = BIT(6), /** Pipeline Done event, sent after last pipeline stage. */ - IA_CSS_EVENT_TYPE_FRAME_TAGGED = 1 << 7, + IA_CSS_EVENT_TYPE_FRAME_TAGGED = BIT(7), /** Frame tagged. */ - IA_CSS_EVENT_TYPE_INPUT_FRAME_DONE = 1 << 8, + IA_CSS_EVENT_TYPE_INPUT_FRAME_DONE = BIT(8), /** Input frame ready. */ - IA_CSS_EVENT_TYPE_METADATA_DONE = 1 << 9, + IA_CSS_EVENT_TYPE_METADATA_DONE = BIT(9), /** Metadata ready. */ - IA_CSS_EVENT_TYPE_LACE_STATISTICS_DONE = 1 << 10, + IA_CSS_EVENT_TYPE_LACE_STATISTICS_DONE = BIT(10), /** Indication that LACE statistics are available. */ - IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE = 1 << 11, + IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE = BIT(11), /** Extension stage complete. */ - IA_CSS_EVENT_TYPE_TIMER = 1 << 12, + IA_CSS_EVENT_TYPE_TIMER = BIT(12), /** Timer event for measuring the SP side latencies. It contains the 32-bit timer value from the SP */ - IA_CSS_EVENT_TYPE_PORT_EOF = 1 << 13, + IA_CSS_EVENT_TYPE_PORT_EOF = BIT(13), /** End Of Frame event, sent when in buffered sensor mode. */ - IA_CSS_EVENT_TYPE_FW_WARNING = 1 << 14, + IA_CSS_EVENT_TYPE_FW_WARNING = BIT(14), /** Performance warning encounter by FW */ - IA_CSS_EVENT_TYPE_FW_ASSERT = 1 << 15, + IA_CSS_EVENT_TYPE_FW_ASSERT = BIT(15), /** Assertion hit by FW */ }; diff --git a/drivers/staging/media/atomisp/pci/ia_css_irq.h b/drivers/staging/media/atomisp/pci/ia_css_irq.h index 3b81a39cfe97..26b1b3c8ba62 100644 --- a/drivers/staging/media/atomisp/pci/ia_css_irq.h +++ b/drivers/staging/media/atomisp/pci/ia_css_irq.h @@ -23,6 +23,7 @@ #include "ia_css_err.h" #include "ia_css_pipe_public.h" #include "ia_css_input_port.h" +#include /* Interrupt types, these enumerate all supported interrupt types. */ @@ -46,49 +47,49 @@ enum ia_css_irq_type { * (SW) interrupts */ enum ia_css_irq_info { - IA_CSS_IRQ_INFO_CSS_RECEIVER_ERROR = 1 << 0, + IA_CSS_IRQ_INFO_CSS_RECEIVER_ERROR = BIT(0), /** the css receiver has encountered an error */ - IA_CSS_IRQ_INFO_CSS_RECEIVER_FIFO_OVERFLOW = 1 << 1, + IA_CSS_IRQ_INFO_CSS_RECEIVER_FIFO_OVERFLOW = BIT(1), /** the FIFO in the csi receiver has overflown */ - IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF = 1 << 2, + IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF = BIT(2), /** the css receiver received the start of frame */ - IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF = 1 << 3, + IA_CSS_IRQ_INFO_CSS_RECEIVER_EOF = BIT(3), /** the css receiver received the end of frame */ - IA_CSS_IRQ_INFO_CSS_RECEIVER_SOL = 1 << 4, + IA_CSS_IRQ_INFO_CSS_RECEIVER_SOL = BIT(4), /** the css receiver received the start of line */ - IA_CSS_IRQ_INFO_EVENTS_READY = 1 << 5, + IA_CSS_IRQ_INFO_EVENTS_READY = BIT(5), /** One or more events are available in the PSYS event queue */ - IA_CSS_IRQ_INFO_CSS_RECEIVER_EOL = 1 << 6, + IA_CSS_IRQ_INFO_CSS_RECEIVER_EOL = BIT(6), /** the css receiver received the end of line */ - IA_CSS_IRQ_INFO_CSS_RECEIVER_SIDEBAND_CHANGED = 1 << 7, + IA_CSS_IRQ_INFO_CSS_RECEIVER_SIDEBAND_CHANGED = BIT(7), /** the css receiver received a change in side band signals */ - IA_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_0 = 1 << 8, + IA_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_0 = BIT(8), /** generic short packets (0) */ - IA_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_1 = 1 << 9, + IA_CSS_IRQ_INFO_CSS_RECEIVER_GEN_SHORT_1 = BIT(9), /** generic short packets (1) */ - IA_CSS_IRQ_INFO_IF_PRIM_ERROR = 1 << 10, + IA_CSS_IRQ_INFO_IF_PRIM_ERROR = BIT(10), /** the primary input formatter (A) has encountered an error */ - IA_CSS_IRQ_INFO_IF_PRIM_B_ERROR = 1 << 11, + IA_CSS_IRQ_INFO_IF_PRIM_B_ERROR = BIT(11), /** the primary input formatter (B) has encountered an error */ - IA_CSS_IRQ_INFO_IF_SEC_ERROR = 1 << 12, + IA_CSS_IRQ_INFO_IF_SEC_ERROR = BIT(12), /** the secondary input formatter has encountered an error */ - IA_CSS_IRQ_INFO_STREAM_TO_MEM_ERROR = 1 << 13, + IA_CSS_IRQ_INFO_STREAM_TO_MEM_ERROR = BIT(13), /** the stream-to-memory device has encountered an error */ - IA_CSS_IRQ_INFO_SW_0 = 1 << 14, + IA_CSS_IRQ_INFO_SW_0 = BIT(14), /** software interrupt 0 */ - IA_CSS_IRQ_INFO_SW_1 = 1 << 15, + IA_CSS_IRQ_INFO_SW_1 = BIT(15), /** software interrupt 1 */ - IA_CSS_IRQ_INFO_SW_2 = 1 << 16, + IA_CSS_IRQ_INFO_SW_2 = BIT(16), /** software interrupt 2 */ - IA_CSS_IRQ_INFO_ISP_BINARY_STATISTICS_READY = 1 << 17, + IA_CSS_IRQ_INFO_ISP_BINARY_STATISTICS_READY = BIT(17), /** ISP binary statistics are ready */ - IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR = 1 << 18, + IA_CSS_IRQ_INFO_INPUT_SYSTEM_ERROR = BIT(18), /** the input system in in error */ - IA_CSS_IRQ_INFO_IF_ERROR = 1 << 19, + IA_CSS_IRQ_INFO_IF_ERROR = BIT(19), /** the input formatter in in error */ - IA_CSS_IRQ_INFO_DMA_ERROR = 1 << 20, + IA_CSS_IRQ_INFO_DMA_ERROR = BIT(20), /** the dma in in error */ - IA_CSS_IRQ_INFO_ISYS_EVENTS_READY = 1 << 21, + IA_CSS_IRQ_INFO_ISYS_EVENTS_READY = BIT(21), /** end-of-frame events are ready in the isys_event queue */ }; @@ -103,23 +104,23 @@ enum ia_css_irq_info { * different receiver types, or possibly none in case of tests systems. */ enum ia_css_rx_irq_info { - IA_CSS_RX_IRQ_INFO_BUFFER_OVERRUN = 1U << 0, /** buffer overrun */ - IA_CSS_RX_IRQ_INFO_ENTER_SLEEP_MODE = 1U << 1, /** entering sleep mode */ - IA_CSS_RX_IRQ_INFO_EXIT_SLEEP_MODE = 1U << 2, /** exited sleep mode */ - IA_CSS_RX_IRQ_INFO_ECC_CORRECTED = 1U << 3, /** ECC corrected */ - IA_CSS_RX_IRQ_INFO_ERR_SOT = 1U << 4, + IA_CSS_RX_IRQ_INFO_BUFFER_OVERRUN = BIT(0), /** buffer overrun */ + IA_CSS_RX_IRQ_INFO_ENTER_SLEEP_MODE = BIT(1), /** entering sleep mode */ + IA_CSS_RX_IRQ_INFO_EXIT_SLEEP_MODE = BIT(2), /** exited sleep mode */ + IA_CSS_RX_IRQ_INFO_ECC_CORRECTED = BIT(3), /** ECC corrected */ + IA_CSS_RX_IRQ_INFO_ERR_SOT = BIT(4), /** Start of transmission */ - IA_CSS_RX_IRQ_INFO_ERR_SOT_SYNC = 1U << 5, /** SOT sync (??) */ - IA_CSS_RX_IRQ_INFO_ERR_CONTROL = 1U << 6, /** Control (??) */ - IA_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE = 1U << 7, /** Double ECC */ - IA_CSS_RX_IRQ_INFO_ERR_CRC = 1U << 8, /** CRC error */ - IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID = 1U << 9, /** Unknown ID */ - IA_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC = 1U << 10,/** Frame sync error */ - IA_CSS_RX_IRQ_INFO_ERR_FRAME_DATA = 1U << 11,/** Frame data error */ - IA_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT = 1U << 12,/** Timeout occurred */ - IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC = 1U << 13,/** Unknown escape seq. */ - IA_CSS_RX_IRQ_INFO_ERR_LINE_SYNC = 1U << 14,/** Line Sync error */ - IA_CSS_RX_IRQ_INFO_INIT_TIMEOUT = 1U << 15, + IA_CSS_RX_IRQ_INFO_ERR_SOT_SYNC = BIT(5), /** SOT sync (??) */ + IA_CSS_RX_IRQ_INFO_ERR_CONTROL = BIT(6), /** Control (??) */ + IA_CSS_RX_IRQ_INFO_ERR_ECC_DOUBLE = BIT(7), /** Double ECC */ + IA_CSS_RX_IRQ_INFO_ERR_CRC = BIT(8), /** CRC error */ + IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ID = BIT(9), /** Unknown ID */ + IA_CSS_RX_IRQ_INFO_ERR_FRAME_SYNC = BIT(10), /** Frame sync error */ + IA_CSS_RX_IRQ_INFO_ERR_FRAME_DATA = BIT(11), /** Frame data error */ + IA_CSS_RX_IRQ_INFO_ERR_DATA_TIMEOUT = BIT(12), /** Timeout occurred */ + IA_CSS_RX_IRQ_INFO_ERR_UNKNOWN_ESC = BIT(13), /** Unknown escape seq. */ + IA_CSS_RX_IRQ_INFO_ERR_LINE_SYNC = BIT(14), /** Line Sync error */ + IA_CSS_RX_IRQ_INFO_INIT_TIMEOUT = BIT(15), }; /* Interrupt info structure. This structure contains information about an diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h index e37ef4232c55..fff89e9b4b01 100644 --- a/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h +++ b/drivers/staging/media/atomisp/pci/runtime/debug/interface/ia_css_debug.h @@ -20,6 +20,7 @@ #include #include +#include #include "ia_css_types.h" #include "ia_css_binary.h" #include "ia_css_frame_public.h" @@ -53,21 +54,21 @@ extern int dbg_level; * Values can be combined to dump a combination of sets. */ enum ia_css_debug_enable_param_dump { - IA_CSS_DEBUG_DUMP_FPN = 1 << 0, /** FPN table */ - IA_CSS_DEBUG_DUMP_OB = 1 << 1, /** OB table */ - IA_CSS_DEBUG_DUMP_SC = 1 << 2, /** Shading table */ - IA_CSS_DEBUG_DUMP_WB = 1 << 3, /** White balance */ - IA_CSS_DEBUG_DUMP_DP = 1 << 4, /** Defect Pixel */ - IA_CSS_DEBUG_DUMP_BNR = 1 << 5, /** Bayer Noise Reductions */ - IA_CSS_DEBUG_DUMP_S3A = 1 << 6, /** 3A Statistics */ - IA_CSS_DEBUG_DUMP_DE = 1 << 7, /** De Mosaicing */ - IA_CSS_DEBUG_DUMP_YNR = 1 << 8, /** Luma Noise Reduction */ - IA_CSS_DEBUG_DUMP_CSC = 1 << 9, /** Color Space Conversion */ - IA_CSS_DEBUG_DUMP_GC = 1 << 10, /** Gamma Correction */ - IA_CSS_DEBUG_DUMP_TNR = 1 << 11, /** Temporal Noise Reduction */ - IA_CSS_DEBUG_DUMP_ANR = 1 << 12, /** Advanced Noise Reduction */ - IA_CSS_DEBUG_DUMP_CE = 1 << 13, /** Chroma Enhancement */ - IA_CSS_DEBUG_DUMP_ALL = 1 << 14 /** Dump all device parameters */ + IA_CSS_DEBUG_DUMP_FPN = BIT(0), /** FPN table */ + IA_CSS_DEBUG_DUMP_OB = BIT(1), /** OB table */ + IA_CSS_DEBUG_DUMP_SC = BIT(2), /** Shading table */ + IA_CSS_DEBUG_DUMP_WB = BIT(3), /** White balance */ + IA_CSS_DEBUG_DUMP_DP = BIT(4), /** Defect Pixel */ + IA_CSS_DEBUG_DUMP_BNR = BIT(5), /** Bayer Noise Reductions */ + IA_CSS_DEBUG_DUMP_S3A = BIT(6), /** 3A Statistics */ + IA_CSS_DEBUG_DUMP_DE = BIT(7), /** De Mosaicing */ + IA_CSS_DEBUG_DUMP_YNR = BIT(8), /** Luma Noise Reduction */ + IA_CSS_DEBUG_DUMP_CSC = BIT(9), /** Color Space Conversion */ + IA_CSS_DEBUG_DUMP_GC = BIT(10), /** Gamma Correction */ + IA_CSS_DEBUG_DUMP_TNR = BIT(11), /** Temporal Noise Reduction */ + IA_CSS_DEBUG_DUMP_ANR = BIT(12), /** Advanced Noise Reduction */ + IA_CSS_DEBUG_DUMP_CE = BIT(13), /** Chroma Enhancement */ + IA_CSS_DEBUG_DUMP_ALL = BIT(14), /** Dump all device parameters */ }; #define IA_CSS_ERROR(fmt, ...) \ -- cgit v1.2.3 From 127efdbc51fe6064336c0452ce9c910b3e107cf0 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 17 Oct 2021 18:23:33 +0200 Subject: media: atomisp: fix dummy_ptr check to avoid duplicate active_bo The dummy_ptr check in hmm_init() [1] results in the following "hmm_init Failed to create sysfs" error exactly once every two times on atomisp reload by rmmod/insmod (although atomisp module loads and works fine regardless of this error): [ 140.230662] sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:03.0/active_bo' [ 140.230668] CPU: 1 PID: 2502 Comm: insmod Tainted: G C OE 5.15.0-rc4-1-surface-mainline #1 b8acf6eb64994414b2e20bad312a7a2c45f748f9 [ 140.230675] Hardware name: OEMB OEMB/OEMB, BIOS 1.51116.238 03/09/2015 [ 140.230678] Call Trace: [ 140.230687] dump_stack_lvl+0x46/0x5a [ 140.230702] sysfs_warn_dup.cold+0x17/0x24 [ 140.230710] sysfs_add_file_mode_ns+0x160/0x170 [ 140.230717] internal_create_group+0x126/0x390 [ 140.230723] hmm_init+0x5c/0x70 [atomisp 7a6a680bf400629363d2a6f58fd10e7299678b99] [ 140.230811] atomisp_pci_probe.cold+0x1136/0x148e [atomisp 7a6a680bf400629363d2a6f58fd10e7299678b99] [ 140.230875] local_pci_probe+0x45/0x80 [ 140.230882] ? pci_match_device+0xd7/0x130 [ 140.230887] pci_device_probe+0xfa/0x1b0 [ 140.230892] really_probe+0x1f5/0x3f0 [ 140.230899] __driver_probe_device+0xfe/0x180 [ 140.230903] driver_probe_device+0x1e/0x90 [ 140.230908] __driver_attach+0xc0/0x1c0 [ 140.230912] ? __device_attach_driver+0xe0/0xe0 [ 140.230915] ? __device_attach_driver+0xe0/0xe0 [ 140.230919] bus_for_each_dev+0x89/0xd0 [ 140.230924] bus_add_driver+0x12b/0x1e0 [ 140.230929] driver_register+0x8f/0xe0 [ 140.230933] ? 0xffffffffc153f000 [ 140.230937] do_one_initcall+0x57/0x220 [ 140.230945] do_init_module+0x5c/0x260 [ 140.230952] load_module+0x24bd/0x26a0 [ 140.230962] ? __do_sys_finit_module+0xae/0x110 [ 140.230966] __do_sys_finit_module+0xae/0x110 [ 140.230972] do_syscall_64+0x5c/0x80 [ 140.230979] ? syscall_exit_to_user_mode+0x23/0x40 [ 140.230983] ? do_syscall_64+0x69/0x80 [ 140.230988] ? exc_page_fault+0x72/0x170 [ 140.230991] entry_SYSCALL_64_after_hwframe+0x44/0xae [ 140.230997] RIP: 0033:0x7f7fd5d8718d [ 140.231003] Code: b4 0c 00 0f 05 eb a9 66 0f 1f 44 00 00 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d b3 6c 0c 00 f7 d8 64 89 01 48 [ 140.231006] RSP: 002b:00007ffefc25f0e8 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 140.231012] RAX: ffffffffffffffda RBX: 000055ac3edcd7f0 RCX: 00007f7fd5d8718d [ 140.231015] RDX: 0000000000000000 RSI: 000055ac3d723270 RDI: 0000000000000003 [ 140.231017] RBP: 0000000000000000 R08: 0000000000000000 R09: 00007f7fd5e52380 [ 140.231019] R10: 0000000000000003 R11: 0000000000000246 R12: 000055ac3d723270 [ 140.231021] R13: 0000000000000000 R14: 000055ac3edd06e0 R15: 0000000000000000 [ 140.231038] atomisp-isp2 0000:00:03.0: hmm_init Failed to create sysfs The problem is that dummy_ptr == 0 is a valid value. So, change the logic which checks if dummy_ptr was allocated. At this point, atomisp now gives WARN_ON() in hmm_free() [2] on atomisp reload by rmmod/insmod. Again, the check is wrong there. So, change both checks for mmgr_EXCEPTION, which is the error value when HMM allocation fails, and initialize dummy_ptr with such value. [1] added on commit d9ab83953fa7 ("media: atomisp: don't cause a warn if probe failed") [2] added on commit b83cc378dfc4 ("atomisp: clean up the hmm init/cleanup indirections") Link: https://lore.kernel.org/linux-media/20211017162337.44860-3-kitakar@gmail.com Signed-off-by: Tsuchiya Yuto Co-developed-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/hmm/hmm.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm.c b/drivers/staging/media/atomisp/pci/hmm/hmm.c index 6a5ee4607089..c1cda16f2dc0 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm.c @@ -39,7 +39,7 @@ struct hmm_bo_device bo_device; struct hmm_pool dynamic_pool; struct hmm_pool reserved_pool; -static ia_css_ptr dummy_ptr; +static ia_css_ptr dummy_ptr = mmgr_EXCEPTION; static bool hmm_initialized; struct _hmm_mem_stat hmm_mem_stat; @@ -209,7 +209,7 @@ int hmm_init(void) void hmm_cleanup(void) { - if (!dummy_ptr) + if (dummy_ptr == mmgr_EXCEPTION) return; sysfs_remove_group(&atomisp_dev->kobj, atomisp_attribute_group); @@ -288,7 +288,8 @@ void hmm_free(ia_css_ptr virt) dev_dbg(atomisp_dev, "%s: free 0x%08x\n", __func__, virt); - WARN_ON(!virt); + if (WARN_ON(virt == mmgr_EXCEPTION)) + return; bo = hmm_bo_device_search_start(&bo_device, (unsigned int)virt); -- cgit v1.2.3 From 6a7bdd89f50d399dd02847e6f398d408b086df50 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 3 Jan 2022 17:24:11 +0100 Subject: media: v4l2-mediabus: Use structures to describe bus configuration The media bus configuration is specified through a set of flags, some of which being mutually exclusive. This doesn't scale to express more complex configurations. Improve the API by replacing the single flags field in v4l2_mbus_config by a union of v4l2_mbus_config_* structures. The flags themselves are still used in those structures, so they are kept here. Drivers are however updated to use structure fields instead of flags when already possible. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/gpu/ipu-v3/ipu-csi.c | 6 +++--- drivers/media/i2c/adv7180.c | 8 +++++--- drivers/media/i2c/adv748x/adv748x-csi2.c | 18 +----------------- drivers/media/i2c/ml86v7667.c | 5 +++-- drivers/media/i2c/mt9m001.c | 8 +++++--- drivers/media/i2c/mt9m111.c | 14 ++++++++------ drivers/media/i2c/ov6650.c | 14 +++++++------- drivers/media/i2c/ov9640.c | 8 +++++--- drivers/media/i2c/tc358743.c | 20 ++------------------ drivers/media/i2c/tvp5150.c | 6 ++++-- drivers/media/platform/atmel/microchip-csi2dc.c | 2 +- drivers/media/platform/pxa_camera.c | 12 +++++++----- drivers/media/platform/rcar-vin/rcar-csi2.c | 16 +++------------- drivers/staging/media/imx/imx-media-csi.c | 7 ++++--- drivers/staging/media/imx/imx6-mipi-csi2.c | 25 +++---------------------- include/media/v4l2-mediabus.h | 20 +++++++++++++++++--- 16 files changed, 78 insertions(+), 111 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c index a9639d098893..778bc26d3ba5 100644 --- a/drivers/gpu/ipu-v3/ipu-csi.c +++ b/drivers/gpu/ipu-v3/ipu-csi.c @@ -357,11 +357,11 @@ static int fill_csi_bus_cfg(struct ipu_csi_bus_config *csicfg, switch (mbus_cfg->type) { case V4L2_MBUS_PARALLEL: csicfg->ext_vsync = 1; - csicfg->vsync_pol = (mbus_cfg->flags & + csicfg->vsync_pol = (mbus_cfg->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) ? 1 : 0; - csicfg->hsync_pol = (mbus_cfg->flags & + csicfg->hsync_pol = (mbus_cfg->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) ? 1 : 0; - csicfg->pixclk_pol = (mbus_cfg->flags & + csicfg->pixclk_pol = (mbus_cfg->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) ? 1 : 0; csicfg->clk_mode = IPU_CSI_CLK_MODE_GATED_CLK; break; diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index d9a99fcfacb1..286f5017d9c3 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -784,7 +784,8 @@ static int adv7180_get_mbus_config(struct v4l2_subdev *sd, if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) { cfg->type = V4L2_MBUS_CSI2_DPHY; - cfg->flags = V4L2_MBUS_CSI2_1_LANE | + cfg->bus.mipi_csi2.num_data_lanes = 1; + cfg->bus.mipi_csi2.flags = V4L2_MBUS_CSI2_CHANNEL_0 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; } else { @@ -792,8 +793,9 @@ static int adv7180_get_mbus_config(struct v4l2_subdev *sd, * The ADV7180 sensor supports BT.601/656 output modes. * The BT.656 is default and not yet configurable by s/w. */ - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | - V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->bus.parallel.flags = V4L2_MBUS_MASTER | + V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_DATA_ACTIVE_HIGH; cfg->type = V4L2_MBUS_BT656; } diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c index 589e9644fcdc..bd4f3fe0e309 100644 --- a/drivers/media/i2c/adv748x/adv748x-csi2.c +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c @@ -222,23 +222,7 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad return -EINVAL; config->type = V4L2_MBUS_CSI2_DPHY; - switch (tx->active_lanes) { - case 1: - config->flags = V4L2_MBUS_CSI2_1_LANE; - break; - - case 2: - config->flags = V4L2_MBUS_CSI2_2_LANE; - break; - - case 3: - config->flags = V4L2_MBUS_CSI2_3_LANE; - break; - - case 4: - config->flags = V4L2_MBUS_CSI2_4_LANE; - break; - } + config->bus.mipi_csi2.num_data_lanes = tx->active_lanes; return 0; } diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c index 4a1410ebb4c8..48cc0b0922f4 100644 --- a/drivers/media/i2c/ml86v7667.c +++ b/drivers/media/i2c/ml86v7667.c @@ -223,9 +223,10 @@ static int ml86v7667_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_config *cfg) { - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING | - V4L2_MBUS_DATA_ACTIVE_HIGH; cfg->type = V4L2_MBUS_BT656; + cfg->bus.parallel.flags = V4L2_MBUS_MASTER | + V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_DATA_ACTIVE_HIGH; return 0; } diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index c9f0bd997ea7..ad13b0c890c0 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -695,10 +695,12 @@ static int mt9m001_get_mbus_config(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg) { /* MT9M001 has all capture_format parameters fixed */ - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER; cfg->type = V4L2_MBUS_PARALLEL; + cfg->bus.parallel.flags = V4L2_MBUS_PCLK_SAMPLE_FALLING | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH | + V4L2_MBUS_MASTER; return 0; } diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 91a44359bcd3..6cf3ccf85d27 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -1143,14 +1143,16 @@ static int mt9m111_get_mbus_config(struct v4l2_subdev *sd, { struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - cfg->flags = V4L2_MBUS_MASTER | - V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; - cfg->flags |= mt9m111->pclk_sample ? V4L2_MBUS_PCLK_SAMPLE_RISING : - V4L2_MBUS_PCLK_SAMPLE_FALLING; + cfg->bus.parallel.flags = V4L2_MBUS_MASTER | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; - cfg->type = V4L2_MBUS_PARALLEL; + cfg->bus.parallel.flags |= mt9m111->pclk_sample ? + V4L2_MBUS_PCLK_SAMPLE_RISING : + V4L2_MBUS_PCLK_SAMPLE_FALLING; return 0; } diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index d9c1548f43fc..6458e96d9091 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -984,15 +984,15 @@ static int ov6650_get_mbus_config(struct v4l2_subdev *sd, if (ret) return ret; - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH - | ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH - : V4L2_MBUS_VSYNC_ACTIVE_LOW) - | ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW - : V4L2_MBUS_HSYNC_ACTIVE_HIGH) - | ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING - : V4L2_MBUS_PCLK_SAMPLE_FALLING); cfg->type = V4L2_MBUS_PARALLEL; + cfg->bus.parallel.flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH + | ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH + : V4L2_MBUS_VSYNC_ACTIVE_LOW) + | ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW + : V4L2_MBUS_HSYNC_ACTIVE_HIGH) + | ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING + : V4L2_MBUS_PCLK_SAMPLE_FALLING); return 0; } diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index 0bab8c2cf160..9f44ed52d164 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -652,10 +652,12 @@ static int ov9640_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, struct v4l2_mbus_config *cfg) { - cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | - V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | - V4L2_MBUS_DATA_ACTIVE_HIGH; cfg->type = V4L2_MBUS_PARALLEL; + cfg->bus.parallel.flags = V4L2_MBUS_PCLK_SAMPLE_RISING | + V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | + V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; return 0; } diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 40512004afba..dfbc42675143 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1613,24 +1613,8 @@ static int tc358743_get_mbus_config(struct v4l2_subdev *sd, cfg->type = V4L2_MBUS_CSI2_DPHY; /* Support for non-continuous CSI-2 clock is missing in the driver */ - cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; - - switch (state->csi_lanes_in_use) { - case 1: - cfg->flags |= V4L2_MBUS_CSI2_1_LANE; - break; - case 2: - cfg->flags |= V4L2_MBUS_CSI2_2_LANE; - break; - case 3: - cfg->flags |= V4L2_MBUS_CSI2_3_LANE; - break; - case 4: - cfg->flags |= V4L2_MBUS_CSI2_4_LANE; - break; - default: - return -EINVAL; - } + cfg->bus.mipi_csi2.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + cfg->bus.mipi_csi2.num_data_lanes = state->csi_lanes_in_use; return 0; } diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 4b16ffcaef98..65472438444b 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1198,8 +1198,10 @@ static int tvp5150_get_mbus_config(struct v4l2_subdev *sd, struct tvp5150 *decoder = to_tvp5150(sd); cfg->type = decoder->mbus_type; - cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING - | V4L2_MBUS_FIELD_EVEN_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->bus.parallel.flags = V4L2_MBUS_MASTER + | V4L2_MBUS_PCLK_SAMPLE_RISING + | V4L2_MBUS_FIELD_EVEN_LOW + | V4L2_MBUS_DATA_ACTIVE_HIGH; return 0; } diff --git a/drivers/media/platform/atmel/microchip-csi2dc.c b/drivers/media/platform/atmel/microchip-csi2dc.c index 6a7f5b4b0e3b..2487978db1f1 100644 --- a/drivers/media/platform/atmel/microchip-csi2dc.c +++ b/drivers/media/platform/atmel/microchip-csi2dc.c @@ -359,7 +359,7 @@ static int csi2dc_get_mbus_config(struct csi2dc_device *csi2dc) dev_dbg(csi2dc->dev, "subdev sending on channel %d\n", csi2dc->vc); - csi2dc->clk_gated = mbus_config.flags & + csi2dc->clk_gated = mbus_config.bus.parallel.flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; dev_dbg(csi2dc->dev, "mbus_config: %s clock\n", diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index b5644cf37fe9..35145e3348f0 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -1587,24 +1587,26 @@ static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev) * PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering * roles should match. */ - if (cfg.flags != mbus_config) { + if (cfg.bus.parallel.flags != mbus_config) { unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE); - if (pxa_mbus_role != (cfg.flags & (V4L2_MBUS_MASTER | - V4L2_MBUS_SLAVE))) { + unsigned int flags = cfg.bus.parallel.flags; + + if (pxa_mbus_role != (flags & (V4L2_MBUS_MASTER | + V4L2_MBUS_SLAVE))) { dev_err(pcdev_to_dev(pcdev), "Unsupported mbus configuration: bus mastering\n"); return -EINVAL; } - if (cfg.flags & V4L2_MBUS_DATA_ACTIVE_LOW) { + if (flags & V4L2_MBUS_DATA_ACTIVE_LOW) { dev_err(pcdev_to_dev(pcdev), "Unsupported mbus configuration: DATA_ACTIVE_LOW\n"); return -EINVAL; } } - pxa_camera_setup_cicr(pcdev, cfg.flags, pixfmt); + pxa_camera_setup_cicr(pcdev, cfg.bus.parallel.flags, pixfmt); return 0; } diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index 8c939cb3073d..cbac5801720b 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -603,7 +603,6 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, unsigned int *lanes) { struct v4l2_mbus_config mbus_config = { 0 }; - unsigned int num_lanes = UINT_MAX; int ret; *lanes = priv->lanes; @@ -626,23 +625,14 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, return -EINVAL; } - if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE) - num_lanes = 1; - else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE) - num_lanes = 2; - else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE) - num_lanes = 3; - else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE) - num_lanes = 4; - - if (num_lanes > priv->lanes) { + if (mbus_config.bus.mipi_csi2.num_data_lanes > priv->lanes) { dev_err(priv->dev, "Unsupported mbus config: too many data lanes %u\n", - num_lanes); + mbus_config.bus.mipi_csi2.num_data_lanes); return -EINVAL; } - *lanes = num_lanes; + *lanes = mbus_config.bus.mipi_csi2.num_data_lanes; return 0; } diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index bd7f156f2d52..b2b1f4dd41d7 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -718,9 +718,10 @@ static int csi_setup(struct csi_priv *priv) /* compose mbus_config from the upstream endpoint */ mbus_cfg.type = priv->upstream_ep.bus_type; - mbus_cfg.flags = is_parallel_bus(&priv->upstream_ep) ? - priv->upstream_ep.bus.parallel.flags : - priv->upstream_ep.bus.mipi_csi2.flags; + if (is_parallel_bus(&priv->upstream_ep)) + mbus_cfg.bus.parallel = priv->upstream_ep.bus.parallel; + else + mbus_cfg.bus.mipi_csi2 = priv->upstream_ep.bus.mipi_csi2; if_fmt = *infmt; crop = priv->crop; diff --git a/drivers/staging/media/imx/imx6-mipi-csi2.c b/drivers/staging/media/imx/imx6-mipi-csi2.c index 558b256ac935..c4cb558a85c6 100644 --- a/drivers/staging/media/imx/imx6-mipi-csi2.c +++ b/drivers/staging/media/imx/imx6-mipi-csi2.c @@ -303,7 +303,6 @@ static void csi2ipu_gasket_init(struct csi2_dev *csi2) static int csi2_get_active_lanes(struct csi2_dev *csi2, unsigned int *lanes) { struct v4l2_mbus_config mbus_config = { 0 }; - unsigned int num_lanes = UINT_MAX; int ret; *lanes = csi2->data_lanes; @@ -326,32 +325,14 @@ static int csi2_get_active_lanes(struct csi2_dev *csi2, unsigned int *lanes) return -EINVAL; } - switch (mbus_config.flags & V4L2_MBUS_CSI2_LANES) { - case V4L2_MBUS_CSI2_1_LANE: - num_lanes = 1; - break; - case V4L2_MBUS_CSI2_2_LANE: - num_lanes = 2; - break; - case V4L2_MBUS_CSI2_3_LANE: - num_lanes = 3; - break; - case V4L2_MBUS_CSI2_4_LANE: - num_lanes = 4; - break; - default: - num_lanes = csi2->data_lanes; - break; - } - - if (num_lanes > csi2->data_lanes) { + if (mbus_config.bus.mipi_csi2.num_data_lanes > csi2->data_lanes) { dev_err(csi2->dev, "Unsupported mbus config: too many data lanes %u\n", - num_lanes); + mbus_config.bus.mipi_csi2.num_data_lanes); return -EINVAL; } - *lanes = num_lanes; + *lanes = mbus_config.bus.mipi_csi2.num_data_lanes; return 0; } diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h index 9c4970fbd8ea..269aaf57ba32 100644 --- a/include/media/v4l2-mediabus.h +++ b/include/media/v4l2-mediabus.h @@ -166,12 +166,26 @@ enum v4l2_mbus_type { /** * struct v4l2_mbus_config - media bus configuration - * @type: in: interface type - * @flags: in / out: configuration flags, depending on @type + * @type: interface type + * @bus: bus configuration data structure + * @bus.parallel: embedded &struct v4l2_mbus_config_parallel. + * Used if the bus is parallel or BT.656. + * @bus.mipi_csi1: embedded &struct v4l2_mbus_config_mipi_csi1. + * Used if the bus is MIPI Alliance's Camera Serial + * Interface version 1 (MIPI CSI1) or Standard + * Mobile Imaging Architecture's Compact Camera Port 2 + * (SMIA CCP2). + * @bus.mipi_csi2: embedded &struct v4l2_mbus_config_mipi_csi2. + * Used if the bus is MIPI Alliance's Camera Serial + * Interface version 2 (MIPI CSI2). */ struct v4l2_mbus_config { enum v4l2_mbus_type type; - unsigned int flags; + union { + struct v4l2_mbus_config_parallel parallel; + struct v4l2_mbus_config_mipi_csi1 mipi_csi1; + struct v4l2_mbus_config_mipi_csi2 mipi_csi2; + } bus; }; /** -- cgit v1.2.3 From a7a52e146d0ec6f9fa45db9472c2024a06f1216c Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Fri, 11 Feb 2022 15:27:48 +0100 Subject: media: staging: media: imx: imx7_mipi_csis: Store colorspace in set_fmt as well Without this the default (SMPTE 170M) from init_cfg stays unchanged. Even after configuring 'srgb' colorspace (or 'raw') $ media-ctl -V "'csis-32e30000.mipi-csi':0 [colorspace:srgb]" the colorspace does not change at all: $ media-ctl --get-v4l2 "'csis-32e30000.mipi-csi':0" [fmt:SRGGB10_1X10/1920x1080 field:none colorspace:smpte170m xfer:709 ycbcr:601 quantization:lim-range] Signed-off-by: Alexander Stein Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx7-mipi-csis.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index a22d0e6b3d44..388cfd012212 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -1062,6 +1062,10 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, fmt->code = csis_fmt->code; fmt->width = sdformat->format.width; fmt->height = sdformat->format.height; + fmt->colorspace = sdformat->format.colorspace; + fmt->quantization = sdformat->format.quantization; + fmt->xfer_func = sdformat->format.xfer_func; + fmt->ycbcr_enc = sdformat->format.ycbcr_enc; sdformat->format = *fmt; -- cgit v1.2.3 From 7c38a551bda1b7adea7e98e5c6786f5bee7100b8 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 1 Feb 2022 19:33:24 +0100 Subject: media: cedrus: Add watchdog for job completion Currently, if job is not completed for whatever reason, userspace application can hang on ioctl and thus become unkillable. In order to prevent that, implement watchdog, which will complete job after 2 seconds with error state. Concept is borrowed from hantro driver. Signed-off-by: Jernej Skrabec Reviewed-by: Ezequiel Garcia Reviewed-by: Paul Kocialkowski Signed-off-by: Hans Verkuil --- drivers/staging/media/sunxi/cedrus/cedrus.c | 2 ++ drivers/staging/media/sunxi/cedrus/cedrus.h | 3 +++ drivers/staging/media/sunxi/cedrus/cedrus_dec.c | 4 ++++ drivers/staging/media/sunxi/cedrus/cedrus_hw.c | 25 +++++++++++++++++++++++++ drivers/staging/media/sunxi/cedrus/cedrus_hw.h | 2 ++ 5 files changed, 36 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 4a4b714b0f26..68b3dcdb5df3 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -439,6 +439,8 @@ static int cedrus_probe(struct platform_device *pdev) mutex_init(&dev->dev_mutex); + INIT_DELAYED_WORK(&dev->watchdog_work, cedrus_watchdog); + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) { dev_err(&pdev->dev, "Failed to register V4L2 device\n"); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index c345f2984041..3bc094eb497f 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -24,6 +24,7 @@ #include #include +#include #define CEDRUS_NAME "cedrus" @@ -194,6 +195,8 @@ struct cedrus_dev { struct reset_control *rstc; unsigned int capabilities; + + struct delayed_work watchdog_work; }; extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index a16c1422558f..9c7200299465 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -97,4 +97,8 @@ void cedrus_device_run(void *priv) v4l2_ctrl_request_complete(src_req, &ctx->hdl); dev->dec_ops[ctx->current_codec]->trigger(ctx); + + /* Start the watchdog timer. */ + schedule_delayed_work(&dev->watchdog_work, + msecs_to_jiffies(2000)); } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index 2d7663726467..a6470a89851e 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -118,6 +118,13 @@ static irqreturn_t cedrus_irq(int irq, void *data) enum vb2_buffer_state state; enum cedrus_irq_status status; + /* + * If cancel_delayed_work returns false it means watchdog already + * executed and finished the job. + */ + if (!cancel_delayed_work(&dev->watchdog_work)) + return IRQ_HANDLED; + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); if (!ctx) { v4l2_err(&dev->v4l2_dev, @@ -143,6 +150,24 @@ static irqreturn_t cedrus_irq(int irq, void *data) return IRQ_HANDLED; } +void cedrus_watchdog(struct work_struct *work) +{ + struct cedrus_dev *dev; + struct cedrus_ctx *ctx; + + dev = container_of(to_delayed_work(work), + struct cedrus_dev, watchdog_work); + + ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev); + if (!ctx) + return; + + v4l2_err(&dev->v4l2_dev, "frame processing timed out!\n"); + reset_control_reset(dev->rstc); + v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, + VB2_BUF_STATE_ERROR); +} + int cedrus_hw_suspend(struct device *device) { struct cedrus_dev *dev = dev_get_drvdata(device); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h index 45f641f0bfa2..7c92f00e36da 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.h @@ -28,4 +28,6 @@ int cedrus_hw_resume(struct device *device); int cedrus_hw_probe(struct cedrus_dev *dev); void cedrus_hw_remove(struct cedrus_dev *dev); +void cedrus_watchdog(struct work_struct *work); + #endif -- cgit v1.2.3 From 11c778182a81d3060a35e8f033520f31d2eca665 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Wed, 9 Feb 2022 15:31:50 +0000 Subject: drivers: meson: vdec: add VP9 support to GXM VP9 support for GXM appears to have been missed from the original codec submission [0] but it works well, so let's add support. [0] https://github.com/torvalds/linux/commit/00c43088aa680989407b6afbda295f67b3f123f1 Signed-off-by: Christian Hewitt Acked-by: Neil Armstrong Signed-off-by: Hans Verkuil --- drivers/staging/media/meson/vdec/vdec_platform.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c index eabbebab2da2..88c9d72e1c83 100644 --- a/drivers/staging/media/meson/vdec/vdec_platform.c +++ b/drivers/staging/media/meson/vdec/vdec_platform.c @@ -103,6 +103,18 @@ static const struct amvdec_format vdec_formats_gxl[] = { static const struct amvdec_format vdec_formats_gxm[] = { { + .pixfmt = V4L2_PIX_FMT_VP9, + .min_buffers = 16, + .max_buffers = 24, + .max_width = 3840, + .max_height = 2160, + .vdec_ops = &vdec_hevc_ops, + .codec_ops = &codec_vp9_ops, + .firmware_path = "meson/vdec/gxl_vp9.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, + .flags = V4L2_FMT_FLAG_COMPRESSED | + V4L2_FMT_FLAG_DYN_RESOLUTION, + }, { .pixfmt = V4L2_PIX_FMT_H264, .min_buffers = 2, .max_buffers = 24, -- cgit v1.2.3 From ee8b887329c78971967506f3ac79b9302c9f83c1 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Sat, 12 Feb 2022 08:42:41 +0100 Subject: media: cedrus: H265: Fix neighbour info buffer size Neighbour info buffer size needs to be 794 kiB in H6. This is actually already indirectly mentioned in the comment, but smaller size is used nevertheless. Increase buffer size to cover H6 needs. Since increase is not that big in absolute numbers, it doesn't make sense to complicate logic for older generations. Bug was discovered using iommu, which reported access error when trying to play H265 video. Fixes: 86caab29da78 ("media: cedrus: Add HEVC/H.265 decoding support") Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil --- drivers/staging/media/sunxi/cedrus/cedrus_h265.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c index 8ab2d9c6f048..44f385be9f6c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h265.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h265.c @@ -23,7 +23,7 @@ * Subsequent BSP implementations seem to double the neighbor info buffer size * for the H6 SoC, which may be related to 10 bit H265 support. */ -#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (397 * SZ_1K) +#define CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE (794 * SZ_1K) #define CEDRUS_H265_ENTRY_POINTS_BUF_SIZE (4 * SZ_1K) #define CEDRUS_H265_MV_COL_BUF_UNIT_CTB_SIZE 160 -- cgit v1.2.3 From fecd363ae2d5042553370b0adf60c47e35c34a83 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Mon, 14 Feb 2022 20:08:39 +0100 Subject: media: cedrus: h264: Fix neighbour info buffer size According to BSP library source, H264 neighbour info buffer size needs to be 32 kiB for H6. This is similar to H265 decoding, which also needs double buffer size in comparison to older Cedrus core generations. Increase buffer size to cover H6 needs. Since increase is not that big in absolute numbers, it doesn't make sense to complicate logic for older generations. Issue was discovered using iommu and cross checked with BSP library source. Fixes: 6eb9b758e307 ("media: cedrus: Add H264 decoding support") Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil --- drivers/staging/media/sunxi/cedrus/cedrus_h264.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c index b4173a8926d6..d8fb93035470 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c @@ -38,7 +38,7 @@ struct cedrus_h264_sram_ref_pic { #define CEDRUS_H264_FRAME_NUM 18 -#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (16 * SZ_1K) +#define CEDRUS_NEIGHBOR_INFO_BUF_SIZE (32 * SZ_1K) #define CEDRUS_MIN_PIC_INFO_BUF_SIZE (130 * SZ_1K) static void cedrus_h264_write_sram(struct cedrus_dev *dev, -- cgit v1.2.3 From 85fa189b2c829a005224cab3c2d88635dd36d777 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 21 Feb 2022 18:47:21 +0100 Subject: media: imx: De-stage imx7-mipi-csis The imx7-mipi-csis driver is in a good state and can be destaged. Move the imx7-mipi-csis.c driver to the newly created drivers/media/platform/imx directory and plumb the related options in Kconfig and in Makefile. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Acked-by: Rui Miguel Silva Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil --- MAINTAINERS | 2 +- drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 1 + drivers/media/platform/imx/Kconfig | 24 + drivers/media/platform/imx/Makefile | 1 + drivers/media/platform/imx/imx7-mipi-csis.c | 1522 +++++++++++++++++++++++++++ drivers/staging/media/imx/Makefile | 1 - drivers/staging/media/imx/imx7-mipi-csis.c | 1522 --------------------------- 8 files changed, 1550 insertions(+), 1524 deletions(-) create mode 100644 drivers/media/platform/imx/Kconfig create mode 100644 drivers/media/platform/imx/Makefile create mode 100644 drivers/media/platform/imx/imx7-mipi-csis.c delete mode 100644 drivers/staging/media/imx/imx7-mipi-csis.c (limited to 'drivers/staging') diff --git a/MAINTAINERS b/MAINTAINERS index 83d27b57016f..5bdb8c881b0b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11891,8 +11891,8 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/admin-guide/media/imx7.rst F: Documentation/devicetree/bindings/media/nxp,imx7-csi.yaml F: Documentation/devicetree/bindings/media/nxp,imx7-mipi-csi2.yaml +F: drivers/media/platform/imx/imx7-mipi-csis.c F: drivers/staging/media/imx/imx7-media-csi.c -F: drivers/staging/media/imx/imx7-mipi-csis.c MEDIA DRIVERS FOR HELENE M: Abylay Ospan diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 9fbdba0fd1e7..d9eeccffea69 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -171,6 +171,7 @@ source "drivers/media/platform/xilinx/Kconfig" source "drivers/media/platform/rcar-vin/Kconfig" source "drivers/media/platform/atmel/Kconfig" source "drivers/media/platform/sunxi/Kconfig" +source "drivers/media/platform/imx/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 28eb4aadbf45..a9466c854610 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -20,6 +20,7 @@ obj-y += ti-vpe/ obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o obj-$(CONFIG_VIDEO_CODA) += coda/ +obj-$(CONFIG_VIDEO_IMX) += imx/ obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o obj-$(CONFIG_VIDEO_IMX8_JPEG) += imx-jpeg/ diff --git a/drivers/media/platform/imx/Kconfig b/drivers/media/platform/imx/Kconfig new file mode 100644 index 000000000000..683863572c20 --- /dev/null +++ b/drivers/media/platform/imx/Kconfig @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-only + +menuconfig VIDEO_IMX + bool "V4L2 capture drivers for NXP i.MX devices" + depends on ARCH_MXC || COMPILE_TEST + depends on VIDEO_DEV && VIDEO_V4L2 + help + Say yes here to enable support for capture drivers on i.MX SoCs. + Support for the single SoC features are selectable in the sub-menu + options. + +if VIDEO_IMX + +config VIDEO_IMX_MIPI_CSIS + tristate "MIPI CSI-2 CSIS receiver found on i.MX7 and i.MX8 models" + select MEDIA_CONTROLLER + select V4L2_FWNODE + select VIDEO_V4L2_SUBDEV_API + default n + help + Video4Linux2 sub-device driver for the MIPI CSI-2 CSIS receiver + v3.3/v3.6.3 found on some i.MX7 and i.MX8 SoCs. + +endif # VIDEO_IMX diff --git a/drivers/media/platform/imx/Makefile b/drivers/media/platform/imx/Makefile new file mode 100644 index 000000000000..ee272234c8d7 --- /dev/null +++ b/drivers/media/platform/imx/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx7-mipi-csis.o diff --git a/drivers/media/platform/imx/imx7-mipi-csis.c b/drivers/media/platform/imx/imx7-mipi-csis.c new file mode 100644 index 000000000000..388cfd012212 --- /dev/null +++ b/drivers/media/platform/imx/imx7-mipi-csis.c @@ -0,0 +1,1522 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Freescale i.MX7 SoC series MIPI-CSI V3.3 receiver driver + * + * Copyright (C) 2019 Linaro Ltd + * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define CSIS_DRIVER_NAME "imx7-mipi-csis" + +#define CSIS_PAD_SINK 0 +#define CSIS_PAD_SOURCE 1 +#define CSIS_PADS_NUM 2 + +#define MIPI_CSIS_DEF_PIX_WIDTH 640 +#define MIPI_CSIS_DEF_PIX_HEIGHT 480 + +/* Register map definition */ + +/* CSIS common control */ +#define MIPI_CSIS_CMN_CTRL 0x04 +#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW BIT(16) +#define MIPI_CSIS_CMN_CTRL_INTER_MODE BIT(10) +#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL BIT(2) +#define MIPI_CSIS_CMN_CTRL_RESET BIT(1) +#define MIPI_CSIS_CMN_CTRL_ENABLE BIT(0) + +#define MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET 8 +#define MIPI_CSIS_CMN_CTRL_LANE_NR_MASK (3 << 8) + +/* CSIS clock control */ +#define MIPI_CSIS_CLK_CTRL 0x08 +#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH3(x) ((x) << 28) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH2(x) ((x) << 24) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH1(x) ((x) << 20) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(x) ((x) << 16) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK (0xf << 4) +#define MIPI_CSIS_CLK_CTRL_WCLK_SRC BIT(0) + +/* CSIS Interrupt mask */ +#define MIPI_CSIS_INT_MSK 0x10 +#define MIPI_CSIS_INT_MSK_EVEN_BEFORE BIT(31) +#define MIPI_CSIS_INT_MSK_EVEN_AFTER BIT(30) +#define MIPI_CSIS_INT_MSK_ODD_BEFORE BIT(29) +#define MIPI_CSIS_INT_MSK_ODD_AFTER BIT(28) +#define MIPI_CSIS_INT_MSK_FRAME_START BIT(24) +#define MIPI_CSIS_INT_MSK_FRAME_END BIT(20) +#define MIPI_CSIS_INT_MSK_ERR_SOT_HS BIT(16) +#define MIPI_CSIS_INT_MSK_ERR_LOST_FS BIT(12) +#define MIPI_CSIS_INT_MSK_ERR_LOST_FE BIT(8) +#define MIPI_CSIS_INT_MSK_ERR_OVER BIT(4) +#define MIPI_CSIS_INT_MSK_ERR_WRONG_CFG BIT(3) +#define MIPI_CSIS_INT_MSK_ERR_ECC BIT(2) +#define MIPI_CSIS_INT_MSK_ERR_CRC BIT(1) +#define MIPI_CSIS_INT_MSK_ERR_UNKNOWN BIT(0) + +/* CSIS Interrupt source */ +#define MIPI_CSIS_INT_SRC 0x14 +#define MIPI_CSIS_INT_SRC_EVEN_BEFORE BIT(31) +#define MIPI_CSIS_INT_SRC_EVEN_AFTER BIT(30) +#define MIPI_CSIS_INT_SRC_EVEN BIT(30) +#define MIPI_CSIS_INT_SRC_ODD_BEFORE BIT(29) +#define MIPI_CSIS_INT_SRC_ODD_AFTER BIT(28) +#define MIPI_CSIS_INT_SRC_ODD (0x3 << 28) +#define MIPI_CSIS_INT_SRC_NON_IMAGE_DATA (0xf << 28) +#define MIPI_CSIS_INT_SRC_FRAME_START BIT(24) +#define MIPI_CSIS_INT_SRC_FRAME_END BIT(20) +#define MIPI_CSIS_INT_SRC_ERR_SOT_HS BIT(16) +#define MIPI_CSIS_INT_SRC_ERR_LOST_FS BIT(12) +#define MIPI_CSIS_INT_SRC_ERR_LOST_FE BIT(8) +#define MIPI_CSIS_INT_SRC_ERR_OVER BIT(4) +#define MIPI_CSIS_INT_SRC_ERR_WRONG_CFG BIT(3) +#define MIPI_CSIS_INT_SRC_ERR_ECC BIT(2) +#define MIPI_CSIS_INT_SRC_ERR_CRC BIT(1) +#define MIPI_CSIS_INT_SRC_ERR_UNKNOWN BIT(0) +#define MIPI_CSIS_INT_SRC_ERRORS 0xfffff + +/* D-PHY status control */ +#define MIPI_CSIS_DPHY_STATUS 0x20 +#define MIPI_CSIS_DPHY_STATUS_ULPS_DAT BIT(8) +#define MIPI_CSIS_DPHY_STATUS_STOPSTATE_DAT BIT(4) +#define MIPI_CSIS_DPHY_STATUS_ULPS_CLK BIT(1) +#define MIPI_CSIS_DPHY_STATUS_STOPSTATE_CLK BIT(0) + +/* D-PHY common control */ +#define MIPI_CSIS_DPHY_CMN_CTRL 0x24 +#define MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(n) ((n) << 24) +#define MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE_MASK GENMASK(31, 24) +#define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(n) ((n) << 22) +#define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE_MASK GENMASK(23, 22) +#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_CLK BIT(6) +#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_DAT BIT(5) +#define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_DAT BIT(1) +#define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_CLK BIT(0) +#define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE (0x1f << 0) + +/* D-PHY Master and Slave Control register Low */ +#define MIPI_CSIS_DPHY_BCTRL_L 0x30 +#define MIPI_CSIS_DPHY_BCTRL_L_USER_DATA_PATTERN_LOW(n) (((n) & 3U) << 30) +#define MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_715MV (0 << 28) +#define MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_724MV (1 << 28) +#define MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_733MV (2 << 28) +#define MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_706MV (3 << 28) +#define MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_FREQ_3MHZ (0 << 27) +#define MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_FREQ_1_5MHZ (1 << 27) +#define MIPI_CSIS_DPHY_BCTRL_L_VREG12_EXTPWR_EN_CTL BIT(26) +#define MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_2V (0 << 24) +#define MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_23V (1 << 24) +#define MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_17V (2 << 24) +#define MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_26V (3 << 24) +#define MIPI_CSIS_DPHY_BCTRL_L_REG_1P2_LVL_SEL BIT(23) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_80MV (0 << 21) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_100MV (1 << 21) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_120MV (2 << 21) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_140MV (3 << 21) +#define MIPI_CSIS_DPHY_BCTRL_L_VREF_SRC_SEL BIT(20) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_715MV (0 << 18) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_743MV (1 << 18) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_650MV (2 << 18) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_682MV (3 << 18) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_PULSE_REJECT BIT(17) +#define MIPI_CSIS_DPHY_BCTRL_L_MSTRCLK_LP_SLEW_RATE_DOWN_0 (0 << 15) +#define MIPI_CSIS_DPHY_BCTRL_L_MSTRCLK_LP_SLEW_RATE_DOWN_15P (1 << 15) +#define MIPI_CSIS_DPHY_BCTRL_L_MSTRCLK_LP_SLEW_RATE_DOWN_30P (3 << 15) +#define MIPI_CSIS_DPHY_BCTRL_L_MSTRCLK_LP_SLEW_RATE_UP BIT(14) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_CD_HYS_60MV (0 << 13) +#define MIPI_CSIS_DPHY_BCTRL_L_LP_CD_HYS_70MV (1 << 13) +#define MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_EN BIT(12) +#define MIPI_CSIS_DPHY_BCTRL_L_ERRCONTENTION_LP_EN BIT(11) +#define MIPI_CSIS_DPHY_BCTRL_L_TXTRIGGER_CLK_EN BIT(10) +#define MIPI_CSIS_DPHY_BCTRL_L_B_DPHYCTRL(n) (((n) * 25 / 1000000) << 0) + +/* D-PHY Master and Slave Control register High */ +#define MIPI_CSIS_DPHY_BCTRL_H 0x34 +/* D-PHY Slave Control register Low */ +#define MIPI_CSIS_DPHY_SCTRL_L 0x38 +/* D-PHY Slave Control register High */ +#define MIPI_CSIS_DPHY_SCTRL_H 0x3c + +/* ISP Configuration register */ +#define MIPI_CSIS_ISP_CONFIG_CH(n) (0x40 + (n) * 0x10) +#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK (0xff << 24) +#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x) ((x) << 24) +#define MIPI_CSIS_ISPCFG_PIXEL_MODE_SINGLE (0 << 12) +#define MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL (1 << 12) +#define MIPI_CSIS_ISPCFG_PIXEL_MODE_QUAD (2 << 12) /* i.MX8M[MNP] only */ +#define MIPI_CSIS_ISPCFG_ALIGN_32BIT BIT(11) +#define MIPI_CSIS_ISPCFG_FMT(fmt) ((fmt) << 2) +#define MIPI_CSIS_ISPCFG_FMT_MASK (0x3f << 2) + +/* ISP Image Resolution register */ +#define MIPI_CSIS_ISP_RESOL_CH(n) (0x44 + (n) * 0x10) +#define CSIS_MAX_PIX_WIDTH 0xffff +#define CSIS_MAX_PIX_HEIGHT 0xffff + +/* ISP SYNC register */ +#define MIPI_CSIS_ISP_SYNC_CH(n) (0x48 + (n) * 0x10) +#define MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET 18 +#define MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET 12 +#define MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET 0 + +/* ISP shadow registers */ +#define MIPI_CSIS_SDW_CONFIG_CH(n) (0x80 + (n) * 0x10) +#define MIPI_CSIS_SDW_RESOL_CH(n) (0x84 + (n) * 0x10) +#define MIPI_CSIS_SDW_SYNC_CH(n) (0x88 + (n) * 0x10) + +/* Debug control register */ +#define MIPI_CSIS_DBG_CTRL 0xc0 +#define MIPI_CSIS_DBG_INTR_MSK 0xc4 +#define MIPI_CSIS_DBG_INTR_MSK_DT_NOT_SUPPORT BIT(25) +#define MIPI_CSIS_DBG_INTR_MSK_DT_IGNORE BIT(24) +#define MIPI_CSIS_DBG_INTR_MSK_ERR_FRAME_SIZE BIT(20) +#define MIPI_CSIS_DBG_INTR_MSK_TRUNCATED_FRAME BIT(16) +#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FE BIT(12) +#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FS BIT(8) +#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_FALL BIT(4) +#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_RISE BIT(0) +#define MIPI_CSIS_DBG_INTR_SRC 0xc8 +#define MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT BIT(25) +#define MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE BIT(24) +#define MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE BIT(20) +#define MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME BIT(16) +#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FE BIT(12) +#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FS BIT(8) +#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL BIT(4) +#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE BIT(0) + +#define MIPI_CSIS_FRAME_COUNTER_CH(n) (0x0100 + (n) * 4) + +/* Non-image packet data buffers */ +#define MIPI_CSIS_PKTDATA_ODD 0x2000 +#define MIPI_CSIS_PKTDATA_EVEN 0x3000 +#define MIPI_CSIS_PKTDATA_SIZE SZ_4K + +#define DEFAULT_SCLK_CSIS_FREQ 166000000UL + +/* MIPI CSI-2 Data Types */ +#define MIPI_CSI2_DATA_TYPE_YUV420_8 0x18 +#define MIPI_CSI2_DATA_TYPE_YUV420_10 0x19 +#define MIPI_CSI2_DATA_TYPE_LE_YUV420_8 0x1a +#define MIPI_CSI2_DATA_TYPE_CS_YUV420_8 0x1c +#define MIPI_CSI2_DATA_TYPE_CS_YUV420_10 0x1d +#define MIPI_CSI2_DATA_TYPE_YUV422_8 0x1e +#define MIPI_CSI2_DATA_TYPE_YUV422_10 0x1f +#define MIPI_CSI2_DATA_TYPE_RGB565 0x22 +#define MIPI_CSI2_DATA_TYPE_RGB666 0x23 +#define MIPI_CSI2_DATA_TYPE_RGB888 0x24 +#define MIPI_CSI2_DATA_TYPE_RAW6 0x28 +#define MIPI_CSI2_DATA_TYPE_RAW7 0x29 +#define MIPI_CSI2_DATA_TYPE_RAW8 0x2a +#define MIPI_CSI2_DATA_TYPE_RAW10 0x2b +#define MIPI_CSI2_DATA_TYPE_RAW12 0x2c +#define MIPI_CSI2_DATA_TYPE_RAW14 0x2d +#define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x)) + +enum { + ST_POWERED = 1, + ST_STREAMING = 2, + ST_SUSPENDED = 4, +}; + +struct mipi_csis_event { + bool debug; + u32 mask; + const char * const name; + unsigned int counter; +}; + +static const struct mipi_csis_event mipi_csis_events[] = { + /* Errors */ + { false, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" }, + { false, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" }, + { true, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" }, + { true, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" }, + { true, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error" }, + { true, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame" }, + { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End" }, + { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start" }, + /* Non-image data receive events */ + { false, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" }, + { false, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" }, + { false, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" }, + { false, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" }, + /* Frame start/end */ + { false, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" }, + { false, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" }, + { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge" }, + { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge" }, +}; + +#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events) + +enum mipi_csis_clk { + MIPI_CSIS_CLK_PCLK, + MIPI_CSIS_CLK_WRAP, + MIPI_CSIS_CLK_PHY, + MIPI_CSIS_CLK_AXI, +}; + +static const char * const mipi_csis_clk_id[] = { + "pclk", + "wrap", + "phy", + "axi", +}; + +enum mipi_csis_version { + MIPI_CSIS_V3_3, + MIPI_CSIS_V3_6_3, +}; + +struct mipi_csis_info { + enum mipi_csis_version version; + unsigned int num_clocks; +}; + +struct csi_state { + struct device *dev; + void __iomem *regs; + struct clk_bulk_data *clks; + struct reset_control *mrst; + struct regulator *mipi_phy_regulator; + const struct mipi_csis_info *info; + + struct v4l2_subdev sd; + struct media_pad pads[CSIS_PADS_NUM]; + struct v4l2_async_notifier notifier; + struct v4l2_subdev *src_sd; + + struct v4l2_mbus_config_mipi_csi2 bus; + u32 clk_frequency; + u32 hs_settle; + u32 clk_settle; + + struct mutex lock; /* Protect csis_fmt, format_mbus and state */ + const struct csis_pix_format *csis_fmt; + struct v4l2_mbus_framefmt format_mbus; + u32 state; + + spinlock_t slock; /* Protect events */ + struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; + struct dentry *debugfs_root; + struct { + bool enable; + u32 hs_settle; + u32 clk_settle; + } debug; +}; + +/* ----------------------------------------------------------------------------- + * Format helpers + */ + +struct csis_pix_format { + u32 code; + u32 data_type; + u8 width; +}; + +static const struct csis_pix_format mipi_csis_formats[] = { + /* YUV formats. */ + { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .data_type = MIPI_CSI2_DATA_TYPE_YUV422_8, + .width = 16, + }, + /* RAW (Bayer and greyscale) formats. */ + { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_Y8_1X8, + .data_type = MIPI_CSI2_DATA_TYPE_RAW8, + .width = 8, + }, { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_Y10_1X10, + .data_type = MIPI_CSI2_DATA_TYPE_RAW10, + .width = 10, + }, { + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_Y12_1X12, + .data_type = MIPI_CSI2_DATA_TYPE_RAW12, + .width = 12, + }, { + .code = MEDIA_BUS_FMT_SBGGR14_1X14, + .data_type = MIPI_CSI2_DATA_TYPE_RAW14, + .width = 14, + }, { + .code = MEDIA_BUS_FMT_SGBRG14_1X14, + .data_type = MIPI_CSI2_DATA_TYPE_RAW14, + .width = 14, + }, { + .code = MEDIA_BUS_FMT_SGRBG14_1X14, + .data_type = MIPI_CSI2_DATA_TYPE_RAW14, + .width = 14, + }, { + .code = MEDIA_BUS_FMT_SRGGB14_1X14, + .data_type = MIPI_CSI2_DATA_TYPE_RAW14, + .width = 14, + } +}; + +static const struct csis_pix_format *find_csis_format(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++) + if (code == mipi_csis_formats[i].code) + return &mipi_csis_formats[i]; + return NULL; +} + +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ + +static inline u32 mipi_csis_read(struct csi_state *state, u32 reg) +{ + return readl(state->regs + reg); +} + +static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val) +{ + writel(val, state->regs + reg); +} + +static void mipi_csis_enable_interrupts(struct csi_state *state, bool on) +{ + mipi_csis_write(state, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0); + mipi_csis_write(state, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0); +} + +static void mipi_csis_sw_reset(struct csi_state *state) +{ + u32 val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + + mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, + val | MIPI_CSIS_CMN_CTRL_RESET); + usleep_range(10, 20); +} + +static void mipi_csis_system_enable(struct csi_state *state, int on) +{ + u32 val, mask; + + val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + if (on) + val |= MIPI_CSIS_CMN_CTRL_ENABLE; + else + val &= ~MIPI_CSIS_CMN_CTRL_ENABLE; + mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); + + val = mipi_csis_read(state, MIPI_CSIS_DPHY_CMN_CTRL); + val &= ~MIPI_CSIS_DPHY_CMN_CTRL_ENABLE; + if (on) { + mask = (1 << (state->bus.num_data_lanes + 1)) - 1; + val |= (mask & MIPI_CSIS_DPHY_CMN_CTRL_ENABLE); + } + mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, val); +} + +/* Called with the state.lock mutex held */ +static void __mipi_csis_set_format(struct csi_state *state) +{ + struct v4l2_mbus_framefmt *mf = &state->format_mbus; + u32 val; + + /* Color format */ + val = mipi_csis_read(state, MIPI_CSIS_ISP_CONFIG_CH(0)); + val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK); + val |= MIPI_CSIS_ISPCFG_FMT(state->csis_fmt->data_type); + mipi_csis_write(state, MIPI_CSIS_ISP_CONFIG_CH(0), val); + + /* Pixel resolution */ + val = mf->width | (mf->height << 16); + mipi_csis_write(state, MIPI_CSIS_ISP_RESOL_CH(0), val); +} + +static int mipi_csis_calculate_params(struct csi_state *state) +{ + s64 link_freq; + u32 lane_rate; + + /* Calculate the line rate from the pixel rate. */ + link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler, + state->csis_fmt->width, + state->bus.num_data_lanes * 2); + 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 HSSETTLE counter value is document in a table, but can also + * easily be calculated. Hardcode the CLKSETTLE value to 0 for now + * (which is documented as corresponding to CSI-2 v0.87 to v1.00) until + * we figure out how to compute it correctly. + */ + state->hs_settle = (lane_rate - 5000000) / 45000000; + state->clk_settle = 0; + + dev_dbg(state->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n", + lane_rate, state->clk_settle, state->hs_settle); + + if (state->debug.hs_settle < 0xff) { + dev_dbg(state->dev, "overriding Ths_settle with %u\n", + state->debug.hs_settle); + state->hs_settle = state->debug.hs_settle; + } + + if (state->debug.clk_settle < 4) { + dev_dbg(state->dev, "overriding Tclk_settle with %u\n", + state->debug.clk_settle); + state->clk_settle = state->debug.clk_settle; + } + + return 0; +} + +static void mipi_csis_set_params(struct csi_state *state) +{ + int lanes = state->bus.num_data_lanes; + u32 val; + + val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK; + val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET; + if (state->info->version == MIPI_CSIS_V3_3) + val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; + mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); + + __mipi_csis_set_format(state); + + mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, + MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle) | + MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(state->clk_settle)); + + val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET) + | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET) + | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET); + mipi_csis_write(state, MIPI_CSIS_ISP_SYNC_CH(0), val); + + val = mipi_csis_read(state, MIPI_CSIS_CLK_CTRL); + val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC; + val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15); + val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK; + mipi_csis_write(state, MIPI_CSIS_CLK_CTRL, val); + + mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_L, + MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_715MV | + MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_FREQ_3MHZ | + MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_2V | + MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_80MV | + MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_715MV | + MIPI_CSIS_DPHY_BCTRL_L_LP_CD_HYS_60MV | + MIPI_CSIS_DPHY_BCTRL_L_B_DPHYCTRL(20000000)); + mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_H, 0); + + /* Update the shadow register. */ + val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); + mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, + val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW | + MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL); +} + +static int mipi_csis_clk_enable(struct csi_state *state) +{ + return clk_bulk_prepare_enable(state->info->num_clocks, state->clks); +} + +static void mipi_csis_clk_disable(struct csi_state *state) +{ + clk_bulk_disable_unprepare(state->info->num_clocks, state->clks); +} + +static int mipi_csis_clk_get(struct csi_state *state) +{ + unsigned int i; + int ret; + + state->clks = devm_kcalloc(state->dev, state->info->num_clocks, + sizeof(*state->clks), GFP_KERNEL); + + if (!state->clks) + return -ENOMEM; + + for (i = 0; i < state->info->num_clocks; i++) + state->clks[i].id = mipi_csis_clk_id[i]; + + ret = devm_clk_bulk_get(state->dev, state->info->num_clocks, + state->clks); + if (ret < 0) + return ret; + + /* Set clock rate */ + ret = clk_set_rate(state->clks[MIPI_CSIS_CLK_WRAP].clk, + state->clk_frequency); + if (ret < 0) + dev_err(state->dev, "set rate=%d failed: %d\n", + state->clk_frequency, ret); + + return ret; +} + +static void mipi_csis_start_stream(struct csi_state *state) +{ + mipi_csis_sw_reset(state); + mipi_csis_set_params(state); + mipi_csis_system_enable(state, true); + mipi_csis_enable_interrupts(state, true); +} + +static void mipi_csis_stop_stream(struct csi_state *state) +{ + mipi_csis_enable_interrupts(state, false); + mipi_csis_system_enable(state, false); +} + +static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) +{ + struct csi_state *state = dev_id; + unsigned long flags; + unsigned int i; + u32 status; + u32 dbg_status; + + status = mipi_csis_read(state, MIPI_CSIS_INT_SRC); + dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC); + + spin_lock_irqsave(&state->slock, flags); + + /* Update the event/error counters */ + if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug.enable) { + for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) { + struct mipi_csis_event *event = &state->events[i]; + + if ((!event->debug && (status & event->mask)) || + (event->debug && (dbg_status & event->mask))) + event->counter++; + } + } + spin_unlock_irqrestore(&state->slock, flags); + + mipi_csis_write(state, MIPI_CSIS_INT_SRC, status); + mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status); + + return IRQ_HANDLED; +} + +/* ----------------------------------------------------------------------------- + * PHY regulator and reset + */ + +static int mipi_csis_phy_enable(struct csi_state *state) +{ + if (state->info->version != MIPI_CSIS_V3_3) + return 0; + + return regulator_enable(state->mipi_phy_regulator); +} + +static int mipi_csis_phy_disable(struct csi_state *state) +{ + if (state->info->version != MIPI_CSIS_V3_3) + return 0; + + return regulator_disable(state->mipi_phy_regulator); +} + +static void mipi_csis_phy_reset(struct csi_state *state) +{ + if (state->info->version != MIPI_CSIS_V3_3) + return; + + reset_control_assert(state->mrst); + msleep(20); + reset_control_deassert(state->mrst); +} + +static int mipi_csis_phy_init(struct csi_state *state) +{ + if (state->info->version != MIPI_CSIS_V3_3) + return 0; + + /* Get MIPI PHY reset and regulator. */ + state->mrst = devm_reset_control_get_exclusive(state->dev, NULL); + if (IS_ERR(state->mrst)) + return PTR_ERR(state->mrst); + + state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy"); + if (IS_ERR(state->mipi_phy_regulator)) + return PTR_ERR(state->mipi_phy_regulator); + + return regulator_set_voltage(state->mipi_phy_regulator, 1000000, + 1000000); +} + +/* ----------------------------------------------------------------------------- + * Debug + */ + +static void mipi_csis_clear_counters(struct csi_state *state) +{ + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&state->slock, flags); + for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) + state->events[i].counter = 0; + spin_unlock_irqrestore(&state->slock, flags); +} + +static void mipi_csis_log_counters(struct csi_state *state, bool non_errors) +{ + unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS + : MIPI_CSIS_NUM_EVENTS - 8; + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&state->slock, flags); + + for (i = 0; i < num_events; ++i) { + if (state->events[i].counter > 0 || state->debug.enable) + dev_info(state->dev, "%s events: %d\n", + state->events[i].name, + state->events[i].counter); + } + spin_unlock_irqrestore(&state->slock, flags); +} + +static int mipi_csis_dump_regs(struct csi_state *state) +{ + static const struct { + u32 offset; + const char * const name; + } registers[] = { + { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" }, + { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" }, + { MIPI_CSIS_INT_MSK, "INT_MSK" }, + { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" }, + { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" }, + { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" }, + { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" }, + { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" }, + { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" }, + { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" }, + { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" }, + { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" }, + { MIPI_CSIS_FRAME_COUNTER_CH(0), "FRAME_COUNTER_CH0" }, + }; + + unsigned int i; + u32 cfg; + + dev_info(state->dev, "--- REGISTERS ---\n"); + + for (i = 0; i < ARRAY_SIZE(registers); i++) { + cfg = mipi_csis_read(state, registers[i].offset); + dev_info(state->dev, "%14s: 0x%08x\n", registers[i].name, cfg); + } + + return 0; +} + +static int mipi_csis_dump_regs_show(struct seq_file *m, void *private) +{ + struct csi_state *state = m->private; + + return mipi_csis_dump_regs(state); +} +DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs); + +static void mipi_csis_debugfs_init(struct csi_state *state) +{ + state->debug.hs_settle = UINT_MAX; + state->debug.clk_settle = UINT_MAX; + + state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL); + + debugfs_create_bool("debug_enable", 0600, state->debugfs_root, + &state->debug.enable); + debugfs_create_file("dump_regs", 0600, state->debugfs_root, state, + &mipi_csis_dump_regs_fops); + debugfs_create_u32("tclk_settle", 0600, state->debugfs_root, + &state->debug.clk_settle); + debugfs_create_u32("ths_settle", 0600, state->debugfs_root, + &state->debug.hs_settle); +} + +static void mipi_csis_debugfs_exit(struct csi_state *state) +{ + debugfs_remove_recursive(state->debugfs_root); +} + +/* ----------------------------------------------------------------------------- + * V4L2 subdev operations + */ + +static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev) +{ + return container_of(sdev, struct csi_state, sd); +} + +static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct csi_state *state = mipi_sd_to_csis_state(sd); + int ret; + + if (enable) { + ret = mipi_csis_calculate_params(state); + if (ret < 0) + return ret; + + mipi_csis_clear_counters(state); + + ret = pm_runtime_resume_and_get(state->dev); + if (ret < 0) + return ret; + + ret = v4l2_subdev_call(state->src_sd, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) + goto done; + } + + mutex_lock(&state->lock); + + if (enable) { + if (state->state & ST_SUSPENDED) { + ret = -EBUSY; + goto unlock; + } + + mipi_csis_start_stream(state); + ret = v4l2_subdev_call(state->src_sd, video, s_stream, 1); + if (ret < 0) + goto unlock; + + mipi_csis_log_counters(state, true); + + state->state |= ST_STREAMING; + } else { + v4l2_subdev_call(state->src_sd, video, s_stream, 0); + ret = v4l2_subdev_call(state->src_sd, core, s_power, 0); + if (ret == -ENOIOCTLCMD) + ret = 0; + mipi_csis_stop_stream(state); + state->state &= ~ST_STREAMING; + if (state->debug.enable) + mipi_csis_log_counters(state, true); + } + +unlock: + mutex_unlock(&state->lock); + +done: + if (!enable || ret < 0) + pm_runtime_put(state->dev); + + return ret; +} + +static struct v4l2_mbus_framefmt * +mipi_csis_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; +} + +static int mipi_csis_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct csi_state *state = mipi_sd_to_csis_state(sd); + struct v4l2_mbus_framefmt *fmt_sink; + struct v4l2_mbus_framefmt *fmt_source; + enum v4l2_subdev_format_whence which; + + which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + fmt_sink = mipi_csis_get_format(state, sd_state, which, CSIS_PAD_SINK); + + fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16; + fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH; + fmt_sink->height = MIPI_CSIS_DEF_PIX_HEIGHT; + fmt_sink->field = V4L2_FIELD_NONE; + + fmt_sink->colorspace = V4L2_COLORSPACE_SMPTE170M; + 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); + + /* + * When called from mipi_csis_subdev_init() to initialize the active + * configuration, cfg is NULL, which indicates there's no source pad + * configuration to set. + */ + if (!sd_state) + return 0; + + fmt_source = mipi_csis_get_format(state, sd_state, which, + CSIS_PAD_SOURCE); + *fmt_source = *fmt_sink; + + return 0; +} + +static int mipi_csis_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *sdformat) +{ + struct csi_state *state = mipi_sd_to_csis_state(sd); + struct v4l2_mbus_framefmt *fmt; + + fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + sdformat->pad); + + mutex_lock(&state->lock); + sdformat->format = *fmt; + mutex_unlock(&state->lock); + + return 0; +} + +static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct csi_state *state = mipi_sd_to_csis_state(sd); + + /* + * The CSIS can't transcode in any way, the source format is identical + * to the sink format. + */ + if (code->pad == CSIS_PAD_SOURCE) { + struct v4l2_mbus_framefmt *fmt; + + if (code->index > 0) + return -EINVAL; + + fmt = mipi_csis_get_format(state, sd_state, code->which, + code->pad); + code->code = fmt->code; + return 0; + } + + if (code->pad != CSIS_PAD_SINK) + return -EINVAL; + + if (code->index >= ARRAY_SIZE(mipi_csis_formats)) + return -EINVAL; + + code->code = mipi_csis_formats[code->index].code; + + return 0; +} + +static int mipi_csis_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *sdformat) +{ + struct csi_state *state = mipi_sd_to_csis_state(sd); + struct csis_pix_format const *csis_fmt; + struct v4l2_mbus_framefmt *fmt; + unsigned int align; + + /* + * The CSIS can't transcode in any way, the source format can't be + * modified. + */ + if (sdformat->pad == CSIS_PAD_SOURCE) + return mipi_csis_get_fmt(sd, sd_state, sdformat); + + if (sdformat->pad != CSIS_PAD_SINK) + return -EINVAL; + + /* + * Validate the media bus code and clamp and align the size. + * + * The total number of bits per line must be a multiple of 8. We thus + * need to align the width for formats that are not multiples of 8 + * bits. + */ + csis_fmt = find_csis_format(sdformat->format.code); + if (!csis_fmt) + csis_fmt = &mipi_csis_formats[0]; + + switch (csis_fmt->width % 8) { + case 0: + align = 0; + break; + case 4: + align = 1; + break; + case 2: + case 6: + align = 2; + break; + default: + /* 1, 3, 5, 7 */ + align = 3; + break; + } + + v4l_bound_align_image(&sdformat->format.width, 1, + CSIS_MAX_PIX_WIDTH, align, + &sdformat->format.height, 1, + CSIS_MAX_PIX_HEIGHT, 0, 0); + + fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + sdformat->pad); + + mutex_lock(&state->lock); + + fmt->code = csis_fmt->code; + fmt->width = sdformat->format.width; + fmt->height = sdformat->format.height; + fmt->colorspace = sdformat->format.colorspace; + fmt->quantization = sdformat->format.quantization; + fmt->xfer_func = sdformat->format.xfer_func; + fmt->ycbcr_enc = sdformat->format.ycbcr_enc; + + sdformat->format = *fmt; + + /* Propagate the format from sink to source. */ + fmt = mipi_csis_get_format(state, sd_state, sdformat->which, + CSIS_PAD_SOURCE); + *fmt = sdformat->format; + + /* Store the CSIS format descriptor for active formats. */ + if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) + state->csis_fmt = csis_fmt; + + mutex_unlock(&state->lock); + + return 0; +} + +static int mipi_csis_log_status(struct v4l2_subdev *sd) +{ + struct csi_state *state = mipi_sd_to_csis_state(sd); + + mutex_lock(&state->lock); + mipi_csis_log_counters(state, true); + if (state->debug.enable && (state->state & ST_POWERED)) + mipi_csis_dump_regs(state); + mutex_unlock(&state->lock); + + return 0; +} + +static const struct v4l2_subdev_core_ops mipi_csis_core_ops = { + .log_status = mipi_csis_log_status, +}; + +static const struct v4l2_subdev_video_ops mipi_csis_video_ops = { + .s_stream = mipi_csis_s_stream, +}; + +static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = { + .init_cfg = mipi_csis_init_cfg, + .enum_mbus_code = mipi_csis_enum_mbus_code, + .get_fmt = mipi_csis_get_fmt, + .set_fmt = mipi_csis_set_fmt, +}; + +static const struct v4l2_subdev_ops mipi_csis_subdev_ops = { + .core = &mipi_csis_core_ops, + .video = &mipi_csis_video_ops, + .pad = &mipi_csis_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Media entity operations + */ + +static int mipi_csis_link_setup(struct media_entity *entity, + const struct media_pad *local_pad, + const struct media_pad *remote_pad, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct csi_state *state = mipi_sd_to_csis_state(sd); + struct v4l2_subdev *remote_sd; + + dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name, + local_pad->entity->name); + + /* We only care about the link to the source. */ + if (!(local_pad->flags & MEDIA_PAD_FL_SINK)) + return 0; + + remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); + + if (flags & MEDIA_LNK_FL_ENABLED) { + if (state->src_sd) + return -EBUSY; + + state->src_sd = remote_sd; + } else { + state->src_sd = NULL; + } + + return 0; +} + +static const struct media_entity_operations mipi_csis_entity_ops = { + .link_setup = mipi_csis_link_setup, + .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_csis_state(struct v4l2_async_notifier *n) +{ + return container_of(n, struct csi_state, notifier); +} + +static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) +{ + struct csi_state *state = mipi_notifier_to_csis_state(notifier); + struct media_pad *sink = &state->sd.entity.pads[CSIS_PAD_SINK]; + + return v4l2_create_fwnode_links_to_pad(sd, sink, 0); +} + +static const struct v4l2_async_notifier_operations mipi_csis_notify_ops = { + .bound = mipi_csis_notify_bound, +}; + +static int mipi_csis_async_register(struct csi_state *state) +{ + 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_nf_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\n", state->bus.num_data_lanes); + dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags); + + asd = v4l2_async_nf_add_fwnode_remote(&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 = &mipi_csis_notify_ops; + + ret = v4l2_async_subdev_nf_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 mipi_csis_pm_suspend(struct device *dev, bool runtime) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csis_state(sd); + int ret = 0; + + mutex_lock(&state->lock); + if (state->state & ST_POWERED) { + mipi_csis_stop_stream(state); + ret = mipi_csis_phy_disable(state); + if (ret) + goto unlock; + mipi_csis_clk_disable(state); + state->state &= ~ST_POWERED; + if (!runtime) + state->state |= ST_SUSPENDED; + } + +unlock: + mutex_unlock(&state->lock); + + return ret ? -EAGAIN : 0; +} + +static int mipi_csis_pm_resume(struct device *dev, bool runtime) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct csi_state *state = mipi_sd_to_csis_state(sd); + int ret = 0; + + mutex_lock(&state->lock); + if (!runtime && !(state->state & ST_SUSPENDED)) + goto unlock; + + if (!(state->state & ST_POWERED)) { + ret = mipi_csis_phy_enable(state); + if (ret) + goto unlock; + + state->state |= ST_POWERED; + mipi_csis_clk_enable(state); + } + if (state->state & ST_STREAMING) + mipi_csis_start_stream(state); + + state->state &= ~ST_SUSPENDED; + +unlock: + mutex_unlock(&state->lock); + + return ret ? -EAGAIN : 0; +} + +static int __maybe_unused mipi_csis_suspend(struct device *dev) +{ + return mipi_csis_pm_suspend(dev, false); +} + +static int __maybe_unused mipi_csis_resume(struct device *dev) +{ + return mipi_csis_pm_resume(dev, false); +} + +static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) +{ + return mipi_csis_pm_suspend(dev, true); +} + +static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) +{ + return mipi_csis_pm_resume(dev, true); +} + +static const struct dev_pm_ops mipi_csis_pm_ops = { + SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume) +}; + +/* ----------------------------------------------------------------------------- + * Probe/remove & platform driver + */ + +static int mipi_csis_subdev_init(struct csi_state *state) +{ + struct v4l2_subdev *sd = &state->sd; + + v4l2_subdev_init(sd, &mipi_csis_subdev_ops); + sd->owner = THIS_MODULE; + snprintf(sd->name, sizeof(sd->name), "csis-%s", + dev_name(state->dev)); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->ctrl_handler = NULL; + + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->entity.ops = &mipi_csis_entity_ops; + + sd->dev = state->dev; + + state->csis_fmt = &mipi_csis_formats[0]; + mipi_csis_init_cfg(sd, NULL); + + state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK + | MEDIA_PAD_FL_MUST_CONNECT; + state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE + | MEDIA_PAD_FL_MUST_CONNECT; + return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, + state->pads); +} + +static int mipi_csis_parse_dt(struct csi_state *state) +{ + struct device_node *node = state->dev->of_node; + + if (of_property_read_u32(node, "clock-frequency", + &state->clk_frequency)) + state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; + + return 0; +} + +static int mipi_csis_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct csi_state *state; + int irq; + int ret; + + state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + mutex_init(&state->lock); + spin_lock_init(&state->slock); + + state->dev = dev; + state->info = of_device_get_match_data(dev); + + memcpy(state->events, mipi_csis_events, sizeof(state->events)); + + /* Parse DT properties. */ + ret = mipi_csis_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); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = mipi_csis_phy_init(state); + if (ret < 0) + return ret; + + ret = mipi_csis_clk_get(state); + if (ret < 0) + return ret; + + /* Reset PHY and enable the clocks. */ + mipi_csis_phy_reset(state); + + ret = mipi_csis_clk_enable(state); + if (ret < 0) { + dev_err(state->dev, "failed to enable clocks: %d\n", ret); + return ret; + } + + /* Now that the hardware is initialized, request the interrupt. */ + ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0, + dev_name(dev), state); + if (ret) { + dev_err(dev, "Interrupt request failed\n"); + goto disable_clock; + } + + /* Initialize and register the subdev. */ + ret = mipi_csis_subdev_init(state); + if (ret < 0) + goto disable_clock; + + platform_set_drvdata(pdev, &state->sd); + + ret = mipi_csis_async_register(state); + if (ret < 0) { + dev_err(dev, "async register failed: %d\n", ret); + goto cleanup; + } + + /* Initialize debugfs. */ + mipi_csis_debugfs_init(state); + + /* Enable runtime PM. */ + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = mipi_csis_pm_resume(dev, true); + if (ret < 0) + goto unregister_all; + } + + dev_info(dev, "lanes: %d, freq: %u\n", + state->bus.num_data_lanes, state->clk_frequency); + + return 0; + +unregister_all: + mipi_csis_debugfs_exit(state); +cleanup: + media_entity_cleanup(&state->sd.entity); + v4l2_async_nf_unregister(&state->notifier); + v4l2_async_nf_cleanup(&state->notifier); + v4l2_async_unregister_subdev(&state->sd); +disable_clock: + mipi_csis_clk_disable(state); + mutex_destroy(&state->lock); + + return ret; +} + +static int mipi_csis_remove(struct platform_device *pdev) +{ + struct v4l2_subdev *sd = platform_get_drvdata(pdev); + struct csi_state *state = mipi_sd_to_csis_state(sd); + + mipi_csis_debugfs_exit(state); + v4l2_async_nf_unregister(&state->notifier); + v4l2_async_nf_cleanup(&state->notifier); + v4l2_async_unregister_subdev(&state->sd); + + pm_runtime_disable(&pdev->dev); + mipi_csis_pm_suspend(&pdev->dev, true); + mipi_csis_clk_disable(state); + media_entity_cleanup(&state->sd.entity); + mutex_destroy(&state->lock); + pm_runtime_set_suspended(&pdev->dev); + + return 0; +} + +static const struct of_device_id mipi_csis_of_match[] = { + { + .compatible = "fsl,imx7-mipi-csi2", + .data = &(const struct mipi_csis_info){ + .version = MIPI_CSIS_V3_3, + .num_clocks = 3, + }, + }, { + .compatible = "fsl,imx8mm-mipi-csi2", + .data = &(const struct mipi_csis_info){ + .version = MIPI_CSIS_V3_6_3, + .num_clocks = 4, + }, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, mipi_csis_of_match); + +static struct platform_driver mipi_csis_driver = { + .probe = mipi_csis_probe, + .remove = mipi_csis_remove, + .driver = { + .of_match_table = mipi_csis_of_match, + .name = CSIS_DRIVER_NAME, + .pm = &mipi_csis_pm_ops, + }, +}; + +module_platform_driver(mipi_csis_driver); + +MODULE_DESCRIPTION("i.MX7 & i.MX8 MIPI CSI-2 receiver driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:imx7-mipi-csi2"); diff --git a/drivers/staging/media/imx/Makefile b/drivers/staging/media/imx/Makefile index 19c2fc54d424..d82be898145b 100644 --- a/drivers/staging/media/imx/Makefile +++ b/drivers/staging/media/imx/Makefile @@ -15,5 +15,4 @@ obj-$(CONFIG_VIDEO_IMX_CSI) += imx6-media-csi.o 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/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c deleted file mode 100644 index 388cfd012212..000000000000 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ /dev/null @@ -1,1522 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Freescale i.MX7 SoC series MIPI-CSI V3.3 receiver driver - * - * Copyright (C) 2019 Linaro Ltd - * Copyright (C) 2015-2016 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define CSIS_DRIVER_NAME "imx7-mipi-csis" - -#define CSIS_PAD_SINK 0 -#define CSIS_PAD_SOURCE 1 -#define CSIS_PADS_NUM 2 - -#define MIPI_CSIS_DEF_PIX_WIDTH 640 -#define MIPI_CSIS_DEF_PIX_HEIGHT 480 - -/* Register map definition */ - -/* CSIS common control */ -#define MIPI_CSIS_CMN_CTRL 0x04 -#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW BIT(16) -#define MIPI_CSIS_CMN_CTRL_INTER_MODE BIT(10) -#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL BIT(2) -#define MIPI_CSIS_CMN_CTRL_RESET BIT(1) -#define MIPI_CSIS_CMN_CTRL_ENABLE BIT(0) - -#define MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET 8 -#define MIPI_CSIS_CMN_CTRL_LANE_NR_MASK (3 << 8) - -/* CSIS clock control */ -#define MIPI_CSIS_CLK_CTRL 0x08 -#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH3(x) ((x) << 28) -#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH2(x) ((x) << 24) -#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH1(x) ((x) << 20) -#define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(x) ((x) << 16) -#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK (0xf << 4) -#define MIPI_CSIS_CLK_CTRL_WCLK_SRC BIT(0) - -/* CSIS Interrupt mask */ -#define MIPI_CSIS_INT_MSK 0x10 -#define MIPI_CSIS_INT_MSK_EVEN_BEFORE BIT(31) -#define MIPI_CSIS_INT_MSK_EVEN_AFTER BIT(30) -#define MIPI_CSIS_INT_MSK_ODD_BEFORE BIT(29) -#define MIPI_CSIS_INT_MSK_ODD_AFTER BIT(28) -#define MIPI_CSIS_INT_MSK_FRAME_START BIT(24) -#define MIPI_CSIS_INT_MSK_FRAME_END BIT(20) -#define MIPI_CSIS_INT_MSK_ERR_SOT_HS BIT(16) -#define MIPI_CSIS_INT_MSK_ERR_LOST_FS BIT(12) -#define MIPI_CSIS_INT_MSK_ERR_LOST_FE BIT(8) -#define MIPI_CSIS_INT_MSK_ERR_OVER BIT(4) -#define MIPI_CSIS_INT_MSK_ERR_WRONG_CFG BIT(3) -#define MIPI_CSIS_INT_MSK_ERR_ECC BIT(2) -#define MIPI_CSIS_INT_MSK_ERR_CRC BIT(1) -#define MIPI_CSIS_INT_MSK_ERR_UNKNOWN BIT(0) - -/* CSIS Interrupt source */ -#define MIPI_CSIS_INT_SRC 0x14 -#define MIPI_CSIS_INT_SRC_EVEN_BEFORE BIT(31) -#define MIPI_CSIS_INT_SRC_EVEN_AFTER BIT(30) -#define MIPI_CSIS_INT_SRC_EVEN BIT(30) -#define MIPI_CSIS_INT_SRC_ODD_BEFORE BIT(29) -#define MIPI_CSIS_INT_SRC_ODD_AFTER BIT(28) -#define MIPI_CSIS_INT_SRC_ODD (0x3 << 28) -#define MIPI_CSIS_INT_SRC_NON_IMAGE_DATA (0xf << 28) -#define MIPI_CSIS_INT_SRC_FRAME_START BIT(24) -#define MIPI_CSIS_INT_SRC_FRAME_END BIT(20) -#define MIPI_CSIS_INT_SRC_ERR_SOT_HS BIT(16) -#define MIPI_CSIS_INT_SRC_ERR_LOST_FS BIT(12) -#define MIPI_CSIS_INT_SRC_ERR_LOST_FE BIT(8) -#define MIPI_CSIS_INT_SRC_ERR_OVER BIT(4) -#define MIPI_CSIS_INT_SRC_ERR_WRONG_CFG BIT(3) -#define MIPI_CSIS_INT_SRC_ERR_ECC BIT(2) -#define MIPI_CSIS_INT_SRC_ERR_CRC BIT(1) -#define MIPI_CSIS_INT_SRC_ERR_UNKNOWN BIT(0) -#define MIPI_CSIS_INT_SRC_ERRORS 0xfffff - -/* D-PHY status control */ -#define MIPI_CSIS_DPHY_STATUS 0x20 -#define MIPI_CSIS_DPHY_STATUS_ULPS_DAT BIT(8) -#define MIPI_CSIS_DPHY_STATUS_STOPSTATE_DAT BIT(4) -#define MIPI_CSIS_DPHY_STATUS_ULPS_CLK BIT(1) -#define MIPI_CSIS_DPHY_STATUS_STOPSTATE_CLK BIT(0) - -/* D-PHY common control */ -#define MIPI_CSIS_DPHY_CMN_CTRL 0x24 -#define MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(n) ((n) << 24) -#define MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE_MASK GENMASK(31, 24) -#define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(n) ((n) << 22) -#define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE_MASK GENMASK(23, 22) -#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_CLK BIT(6) -#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_DAT BIT(5) -#define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_DAT BIT(1) -#define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_CLK BIT(0) -#define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE (0x1f << 0) - -/* D-PHY Master and Slave Control register Low */ -#define MIPI_CSIS_DPHY_BCTRL_L 0x30 -#define MIPI_CSIS_DPHY_BCTRL_L_USER_DATA_PATTERN_LOW(n) (((n) & 3U) << 30) -#define MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_715MV (0 << 28) -#define MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_724MV (1 << 28) -#define MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_733MV (2 << 28) -#define MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_706MV (3 << 28) -#define MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_FREQ_3MHZ (0 << 27) -#define MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_FREQ_1_5MHZ (1 << 27) -#define MIPI_CSIS_DPHY_BCTRL_L_VREG12_EXTPWR_EN_CTL BIT(26) -#define MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_2V (0 << 24) -#define MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_23V (1 << 24) -#define MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_17V (2 << 24) -#define MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_26V (3 << 24) -#define MIPI_CSIS_DPHY_BCTRL_L_REG_1P2_LVL_SEL BIT(23) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_80MV (0 << 21) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_100MV (1 << 21) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_120MV (2 << 21) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_140MV (3 << 21) -#define MIPI_CSIS_DPHY_BCTRL_L_VREF_SRC_SEL BIT(20) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_715MV (0 << 18) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_743MV (1 << 18) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_650MV (2 << 18) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_682MV (3 << 18) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_RX_PULSE_REJECT BIT(17) -#define MIPI_CSIS_DPHY_BCTRL_L_MSTRCLK_LP_SLEW_RATE_DOWN_0 (0 << 15) -#define MIPI_CSIS_DPHY_BCTRL_L_MSTRCLK_LP_SLEW_RATE_DOWN_15P (1 << 15) -#define MIPI_CSIS_DPHY_BCTRL_L_MSTRCLK_LP_SLEW_RATE_DOWN_30P (3 << 15) -#define MIPI_CSIS_DPHY_BCTRL_L_MSTRCLK_LP_SLEW_RATE_UP BIT(14) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_CD_HYS_60MV (0 << 13) -#define MIPI_CSIS_DPHY_BCTRL_L_LP_CD_HYS_70MV (1 << 13) -#define MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_EN BIT(12) -#define MIPI_CSIS_DPHY_BCTRL_L_ERRCONTENTION_LP_EN BIT(11) -#define MIPI_CSIS_DPHY_BCTRL_L_TXTRIGGER_CLK_EN BIT(10) -#define MIPI_CSIS_DPHY_BCTRL_L_B_DPHYCTRL(n) (((n) * 25 / 1000000) << 0) - -/* D-PHY Master and Slave Control register High */ -#define MIPI_CSIS_DPHY_BCTRL_H 0x34 -/* D-PHY Slave Control register Low */ -#define MIPI_CSIS_DPHY_SCTRL_L 0x38 -/* D-PHY Slave Control register High */ -#define MIPI_CSIS_DPHY_SCTRL_H 0x3c - -/* ISP Configuration register */ -#define MIPI_CSIS_ISP_CONFIG_CH(n) (0x40 + (n) * 0x10) -#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP_MSK (0xff << 24) -#define MIPI_CSIS_ISPCFG_MEM_FULL_GAP(x) ((x) << 24) -#define MIPI_CSIS_ISPCFG_PIXEL_MODE_SINGLE (0 << 12) -#define MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL (1 << 12) -#define MIPI_CSIS_ISPCFG_PIXEL_MODE_QUAD (2 << 12) /* i.MX8M[MNP] only */ -#define MIPI_CSIS_ISPCFG_ALIGN_32BIT BIT(11) -#define MIPI_CSIS_ISPCFG_FMT(fmt) ((fmt) << 2) -#define MIPI_CSIS_ISPCFG_FMT_MASK (0x3f << 2) - -/* ISP Image Resolution register */ -#define MIPI_CSIS_ISP_RESOL_CH(n) (0x44 + (n) * 0x10) -#define CSIS_MAX_PIX_WIDTH 0xffff -#define CSIS_MAX_PIX_HEIGHT 0xffff - -/* ISP SYNC register */ -#define MIPI_CSIS_ISP_SYNC_CH(n) (0x48 + (n) * 0x10) -#define MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET 18 -#define MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET 12 -#define MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET 0 - -/* ISP shadow registers */ -#define MIPI_CSIS_SDW_CONFIG_CH(n) (0x80 + (n) * 0x10) -#define MIPI_CSIS_SDW_RESOL_CH(n) (0x84 + (n) * 0x10) -#define MIPI_CSIS_SDW_SYNC_CH(n) (0x88 + (n) * 0x10) - -/* Debug control register */ -#define MIPI_CSIS_DBG_CTRL 0xc0 -#define MIPI_CSIS_DBG_INTR_MSK 0xc4 -#define MIPI_CSIS_DBG_INTR_MSK_DT_NOT_SUPPORT BIT(25) -#define MIPI_CSIS_DBG_INTR_MSK_DT_IGNORE BIT(24) -#define MIPI_CSIS_DBG_INTR_MSK_ERR_FRAME_SIZE BIT(20) -#define MIPI_CSIS_DBG_INTR_MSK_TRUNCATED_FRAME BIT(16) -#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FE BIT(12) -#define MIPI_CSIS_DBG_INTR_MSK_EARLY_FS BIT(8) -#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_FALL BIT(4) -#define MIPI_CSIS_DBG_INTR_MSK_CAM_VSYNC_RISE BIT(0) -#define MIPI_CSIS_DBG_INTR_SRC 0xc8 -#define MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT BIT(25) -#define MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE BIT(24) -#define MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE BIT(20) -#define MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME BIT(16) -#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FE BIT(12) -#define MIPI_CSIS_DBG_INTR_SRC_EARLY_FS BIT(8) -#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL BIT(4) -#define MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE BIT(0) - -#define MIPI_CSIS_FRAME_COUNTER_CH(n) (0x0100 + (n) * 4) - -/* Non-image packet data buffers */ -#define MIPI_CSIS_PKTDATA_ODD 0x2000 -#define MIPI_CSIS_PKTDATA_EVEN 0x3000 -#define MIPI_CSIS_PKTDATA_SIZE SZ_4K - -#define DEFAULT_SCLK_CSIS_FREQ 166000000UL - -/* MIPI CSI-2 Data Types */ -#define MIPI_CSI2_DATA_TYPE_YUV420_8 0x18 -#define MIPI_CSI2_DATA_TYPE_YUV420_10 0x19 -#define MIPI_CSI2_DATA_TYPE_LE_YUV420_8 0x1a -#define MIPI_CSI2_DATA_TYPE_CS_YUV420_8 0x1c -#define MIPI_CSI2_DATA_TYPE_CS_YUV420_10 0x1d -#define MIPI_CSI2_DATA_TYPE_YUV422_8 0x1e -#define MIPI_CSI2_DATA_TYPE_YUV422_10 0x1f -#define MIPI_CSI2_DATA_TYPE_RGB565 0x22 -#define MIPI_CSI2_DATA_TYPE_RGB666 0x23 -#define MIPI_CSI2_DATA_TYPE_RGB888 0x24 -#define MIPI_CSI2_DATA_TYPE_RAW6 0x28 -#define MIPI_CSI2_DATA_TYPE_RAW7 0x29 -#define MIPI_CSI2_DATA_TYPE_RAW8 0x2a -#define MIPI_CSI2_DATA_TYPE_RAW10 0x2b -#define MIPI_CSI2_DATA_TYPE_RAW12 0x2c -#define MIPI_CSI2_DATA_TYPE_RAW14 0x2d -#define MIPI_CSI2_DATA_TYPE_USER(x) (0x30 + (x)) - -enum { - ST_POWERED = 1, - ST_STREAMING = 2, - ST_SUSPENDED = 4, -}; - -struct mipi_csis_event { - bool debug; - u32 mask; - const char * const name; - unsigned int counter; -}; - -static const struct mipi_csis_event mipi_csis_events[] = { - /* Errors */ - { false, MIPI_CSIS_INT_SRC_ERR_SOT_HS, "SOT Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_LOST_FS, "Lost Frame Start Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_LOST_FE, "Lost Frame End Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_OVER, "FIFO Overflow Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_WRONG_CFG, "Wrong Configuration Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_ECC, "ECC Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_CRC, "CRC Error" }, - { false, MIPI_CSIS_INT_SRC_ERR_UNKNOWN, "Unknown Error" }, - { true, MIPI_CSIS_DBG_INTR_SRC_DT_NOT_SUPPORT, "Data Type Not Supported" }, - { true, MIPI_CSIS_DBG_INTR_SRC_DT_IGNORE, "Data Type Ignored" }, - { true, MIPI_CSIS_DBG_INTR_SRC_ERR_FRAME_SIZE, "Frame Size Error" }, - { true, MIPI_CSIS_DBG_INTR_SRC_TRUNCATED_FRAME, "Truncated Frame" }, - { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FE, "Early Frame End" }, - { true, MIPI_CSIS_DBG_INTR_SRC_EARLY_FS, "Early Frame Start" }, - /* Non-image data receive events */ - { false, MIPI_CSIS_INT_SRC_EVEN_BEFORE, "Non-image data before even frame" }, - { false, MIPI_CSIS_INT_SRC_EVEN_AFTER, "Non-image data after even frame" }, - { false, MIPI_CSIS_INT_SRC_ODD_BEFORE, "Non-image data before odd frame" }, - { false, MIPI_CSIS_INT_SRC_ODD_AFTER, "Non-image data after odd frame" }, - /* Frame start/end */ - { false, MIPI_CSIS_INT_SRC_FRAME_START, "Frame Start" }, - { false, MIPI_CSIS_INT_SRC_FRAME_END, "Frame End" }, - { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_FALL, "VSYNC Falling Edge" }, - { true, MIPI_CSIS_DBG_INTR_SRC_CAM_VSYNC_RISE, "VSYNC Rising Edge" }, -}; - -#define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events) - -enum mipi_csis_clk { - MIPI_CSIS_CLK_PCLK, - MIPI_CSIS_CLK_WRAP, - MIPI_CSIS_CLK_PHY, - MIPI_CSIS_CLK_AXI, -}; - -static const char * const mipi_csis_clk_id[] = { - "pclk", - "wrap", - "phy", - "axi", -}; - -enum mipi_csis_version { - MIPI_CSIS_V3_3, - MIPI_CSIS_V3_6_3, -}; - -struct mipi_csis_info { - enum mipi_csis_version version; - unsigned int num_clocks; -}; - -struct csi_state { - struct device *dev; - void __iomem *regs; - struct clk_bulk_data *clks; - struct reset_control *mrst; - struct regulator *mipi_phy_regulator; - const struct mipi_csis_info *info; - - struct v4l2_subdev sd; - struct media_pad pads[CSIS_PADS_NUM]; - struct v4l2_async_notifier notifier; - struct v4l2_subdev *src_sd; - - struct v4l2_mbus_config_mipi_csi2 bus; - u32 clk_frequency; - u32 hs_settle; - u32 clk_settle; - - struct mutex lock; /* Protect csis_fmt, format_mbus and state */ - const struct csis_pix_format *csis_fmt; - struct v4l2_mbus_framefmt format_mbus; - u32 state; - - spinlock_t slock; /* Protect events */ - struct mipi_csis_event events[MIPI_CSIS_NUM_EVENTS]; - struct dentry *debugfs_root; - struct { - bool enable; - u32 hs_settle; - u32 clk_settle; - } debug; -}; - -/* ----------------------------------------------------------------------------- - * Format helpers - */ - -struct csis_pix_format { - u32 code; - u32 data_type; - u8 width; -}; - -static const struct csis_pix_format mipi_csis_formats[] = { - /* YUV formats. */ - { - .code = MEDIA_BUS_FMT_UYVY8_1X16, - .data_type = MIPI_CSI2_DATA_TYPE_YUV422_8, - .width = 16, - }, - /* RAW (Bayer and greyscale) formats. */ - { - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, - .width = 8, - }, { - .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, - .width = 8, - }, { - .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, - .width = 8, - }, { - .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, - .width = 8, - }, { - .code = MEDIA_BUS_FMT_Y8_1X8, - .data_type = MIPI_CSI2_DATA_TYPE_RAW8, - .width = 8, - }, { - .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, - .width = 10, - }, { - .code = MEDIA_BUS_FMT_SGBRG10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, - .width = 10, - }, { - .code = MEDIA_BUS_FMT_SGRBG10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, - .width = 10, - }, { - .code = MEDIA_BUS_FMT_SRGGB10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, - .width = 10, - }, { - .code = MEDIA_BUS_FMT_Y10_1X10, - .data_type = MIPI_CSI2_DATA_TYPE_RAW10, - .width = 10, - }, { - .code = MEDIA_BUS_FMT_SBGGR12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, - .width = 12, - }, { - .code = MEDIA_BUS_FMT_SGBRG12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, - .width = 12, - }, { - .code = MEDIA_BUS_FMT_SGRBG12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, - .width = 12, - }, { - .code = MEDIA_BUS_FMT_SRGGB12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, - .width = 12, - }, { - .code = MEDIA_BUS_FMT_Y12_1X12, - .data_type = MIPI_CSI2_DATA_TYPE_RAW12, - .width = 12, - }, { - .code = MEDIA_BUS_FMT_SBGGR14_1X14, - .data_type = MIPI_CSI2_DATA_TYPE_RAW14, - .width = 14, - }, { - .code = MEDIA_BUS_FMT_SGBRG14_1X14, - .data_type = MIPI_CSI2_DATA_TYPE_RAW14, - .width = 14, - }, { - .code = MEDIA_BUS_FMT_SGRBG14_1X14, - .data_type = MIPI_CSI2_DATA_TYPE_RAW14, - .width = 14, - }, { - .code = MEDIA_BUS_FMT_SRGGB14_1X14, - .data_type = MIPI_CSI2_DATA_TYPE_RAW14, - .width = 14, - } -}; - -static const struct csis_pix_format *find_csis_format(u32 code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++) - if (code == mipi_csis_formats[i].code) - return &mipi_csis_formats[i]; - return NULL; -} - -/* ----------------------------------------------------------------------------- - * Hardware configuration - */ - -static inline u32 mipi_csis_read(struct csi_state *state, u32 reg) -{ - return readl(state->regs + reg); -} - -static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val) -{ - writel(val, state->regs + reg); -} - -static void mipi_csis_enable_interrupts(struct csi_state *state, bool on) -{ - mipi_csis_write(state, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0); - mipi_csis_write(state, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0); -} - -static void mipi_csis_sw_reset(struct csi_state *state) -{ - u32 val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); - - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, - val | MIPI_CSIS_CMN_CTRL_RESET); - usleep_range(10, 20); -} - -static void mipi_csis_system_enable(struct csi_state *state, int on) -{ - u32 val, mask; - - val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); - if (on) - val |= MIPI_CSIS_CMN_CTRL_ENABLE; - else - val &= ~MIPI_CSIS_CMN_CTRL_ENABLE; - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); - - val = mipi_csis_read(state, MIPI_CSIS_DPHY_CMN_CTRL); - val &= ~MIPI_CSIS_DPHY_CMN_CTRL_ENABLE; - if (on) { - mask = (1 << (state->bus.num_data_lanes + 1)) - 1; - val |= (mask & MIPI_CSIS_DPHY_CMN_CTRL_ENABLE); - } - mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, val); -} - -/* Called with the state.lock mutex held */ -static void __mipi_csis_set_format(struct csi_state *state) -{ - struct v4l2_mbus_framefmt *mf = &state->format_mbus; - u32 val; - - /* Color format */ - val = mipi_csis_read(state, MIPI_CSIS_ISP_CONFIG_CH(0)); - val &= ~(MIPI_CSIS_ISPCFG_ALIGN_32BIT | MIPI_CSIS_ISPCFG_FMT_MASK); - val |= MIPI_CSIS_ISPCFG_FMT(state->csis_fmt->data_type); - mipi_csis_write(state, MIPI_CSIS_ISP_CONFIG_CH(0), val); - - /* Pixel resolution */ - val = mf->width | (mf->height << 16); - mipi_csis_write(state, MIPI_CSIS_ISP_RESOL_CH(0), val); -} - -static int mipi_csis_calculate_params(struct csi_state *state) -{ - s64 link_freq; - u32 lane_rate; - - /* Calculate the line rate from the pixel rate. */ - link_freq = v4l2_get_link_freq(state->src_sd->ctrl_handler, - state->csis_fmt->width, - state->bus.num_data_lanes * 2); - 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 HSSETTLE counter value is document in a table, but can also - * easily be calculated. Hardcode the CLKSETTLE value to 0 for now - * (which is documented as corresponding to CSI-2 v0.87 to v1.00) until - * we figure out how to compute it correctly. - */ - state->hs_settle = (lane_rate - 5000000) / 45000000; - state->clk_settle = 0; - - dev_dbg(state->dev, "lane rate %u, Tclk_settle %u, Ths_settle %u\n", - lane_rate, state->clk_settle, state->hs_settle); - - if (state->debug.hs_settle < 0xff) { - dev_dbg(state->dev, "overriding Ths_settle with %u\n", - state->debug.hs_settle); - state->hs_settle = state->debug.hs_settle; - } - - if (state->debug.clk_settle < 4) { - dev_dbg(state->dev, "overriding Tclk_settle with %u\n", - state->debug.clk_settle); - state->clk_settle = state->debug.clk_settle; - } - - return 0; -} - -static void mipi_csis_set_params(struct csi_state *state) -{ - int lanes = state->bus.num_data_lanes; - u32 val; - - val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); - val &= ~MIPI_CSIS_CMN_CTRL_LANE_NR_MASK; - val |= (lanes - 1) << MIPI_CSIS_CMN_CTRL_LANE_NR_OFFSET; - if (state->info->version == MIPI_CSIS_V3_3) - val |= MIPI_CSIS_CMN_CTRL_INTER_MODE; - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, val); - - __mipi_csis_set_format(state); - - mipi_csis_write(state, MIPI_CSIS_DPHY_CMN_CTRL, - MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(state->hs_settle) | - MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(state->clk_settle)); - - val = (0 << MIPI_CSIS_ISP_SYNC_HSYNC_LINTV_OFFSET) - | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_SINTV_OFFSET) - | (0 << MIPI_CSIS_ISP_SYNC_VSYNC_EINTV_OFFSET); - mipi_csis_write(state, MIPI_CSIS_ISP_SYNC_CH(0), val); - - val = mipi_csis_read(state, MIPI_CSIS_CLK_CTRL); - val |= MIPI_CSIS_CLK_CTRL_WCLK_SRC; - val |= MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL_CH0(15); - val &= ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK; - mipi_csis_write(state, MIPI_CSIS_CLK_CTRL, val); - - mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_L, - MIPI_CSIS_DPHY_BCTRL_L_BIAS_REF_VOLT_715MV | - MIPI_CSIS_DPHY_BCTRL_L_BGR_CHOPPER_FREQ_3MHZ | - MIPI_CSIS_DPHY_BCTRL_L_REG_12P_LVL_CTL_1_2V | - MIPI_CSIS_DPHY_BCTRL_L_LP_RX_HYS_LVL_80MV | - MIPI_CSIS_DPHY_BCTRL_L_LP_RX_VREF_LVL_715MV | - MIPI_CSIS_DPHY_BCTRL_L_LP_CD_HYS_60MV | - MIPI_CSIS_DPHY_BCTRL_L_B_DPHYCTRL(20000000)); - mipi_csis_write(state, MIPI_CSIS_DPHY_BCTRL_H, 0); - - /* Update the shadow register. */ - val = mipi_csis_read(state, MIPI_CSIS_CMN_CTRL); - mipi_csis_write(state, MIPI_CSIS_CMN_CTRL, - val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW | - MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL); -} - -static int mipi_csis_clk_enable(struct csi_state *state) -{ - return clk_bulk_prepare_enable(state->info->num_clocks, state->clks); -} - -static void mipi_csis_clk_disable(struct csi_state *state) -{ - clk_bulk_disable_unprepare(state->info->num_clocks, state->clks); -} - -static int mipi_csis_clk_get(struct csi_state *state) -{ - unsigned int i; - int ret; - - state->clks = devm_kcalloc(state->dev, state->info->num_clocks, - sizeof(*state->clks), GFP_KERNEL); - - if (!state->clks) - return -ENOMEM; - - for (i = 0; i < state->info->num_clocks; i++) - state->clks[i].id = mipi_csis_clk_id[i]; - - ret = devm_clk_bulk_get(state->dev, state->info->num_clocks, - state->clks); - if (ret < 0) - return ret; - - /* Set clock rate */ - ret = clk_set_rate(state->clks[MIPI_CSIS_CLK_WRAP].clk, - state->clk_frequency); - if (ret < 0) - dev_err(state->dev, "set rate=%d failed: %d\n", - state->clk_frequency, ret); - - return ret; -} - -static void mipi_csis_start_stream(struct csi_state *state) -{ - mipi_csis_sw_reset(state); - mipi_csis_set_params(state); - mipi_csis_system_enable(state, true); - mipi_csis_enable_interrupts(state, true); -} - -static void mipi_csis_stop_stream(struct csi_state *state) -{ - mipi_csis_enable_interrupts(state, false); - mipi_csis_system_enable(state, false); -} - -static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) -{ - struct csi_state *state = dev_id; - unsigned long flags; - unsigned int i; - u32 status; - u32 dbg_status; - - status = mipi_csis_read(state, MIPI_CSIS_INT_SRC); - dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC); - - spin_lock_irqsave(&state->slock, flags); - - /* Update the event/error counters */ - if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug.enable) { - for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) { - struct mipi_csis_event *event = &state->events[i]; - - if ((!event->debug && (status & event->mask)) || - (event->debug && (dbg_status & event->mask))) - event->counter++; - } - } - spin_unlock_irqrestore(&state->slock, flags); - - mipi_csis_write(state, MIPI_CSIS_INT_SRC, status); - mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status); - - return IRQ_HANDLED; -} - -/* ----------------------------------------------------------------------------- - * PHY regulator and reset - */ - -static int mipi_csis_phy_enable(struct csi_state *state) -{ - if (state->info->version != MIPI_CSIS_V3_3) - return 0; - - return regulator_enable(state->mipi_phy_regulator); -} - -static int mipi_csis_phy_disable(struct csi_state *state) -{ - if (state->info->version != MIPI_CSIS_V3_3) - return 0; - - return regulator_disable(state->mipi_phy_regulator); -} - -static void mipi_csis_phy_reset(struct csi_state *state) -{ - if (state->info->version != MIPI_CSIS_V3_3) - return; - - reset_control_assert(state->mrst); - msleep(20); - reset_control_deassert(state->mrst); -} - -static int mipi_csis_phy_init(struct csi_state *state) -{ - if (state->info->version != MIPI_CSIS_V3_3) - return 0; - - /* Get MIPI PHY reset and regulator. */ - state->mrst = devm_reset_control_get_exclusive(state->dev, NULL); - if (IS_ERR(state->mrst)) - return PTR_ERR(state->mrst); - - state->mipi_phy_regulator = devm_regulator_get(state->dev, "phy"); - if (IS_ERR(state->mipi_phy_regulator)) - return PTR_ERR(state->mipi_phy_regulator); - - return regulator_set_voltage(state->mipi_phy_regulator, 1000000, - 1000000); -} - -/* ----------------------------------------------------------------------------- - * Debug - */ - -static void mipi_csis_clear_counters(struct csi_state *state) -{ - unsigned long flags; - unsigned int i; - - spin_lock_irqsave(&state->slock, flags); - for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) - state->events[i].counter = 0; - spin_unlock_irqrestore(&state->slock, flags); -} - -static void mipi_csis_log_counters(struct csi_state *state, bool non_errors) -{ - unsigned int num_events = non_errors ? MIPI_CSIS_NUM_EVENTS - : MIPI_CSIS_NUM_EVENTS - 8; - unsigned long flags; - unsigned int i; - - spin_lock_irqsave(&state->slock, flags); - - for (i = 0; i < num_events; ++i) { - if (state->events[i].counter > 0 || state->debug.enable) - dev_info(state->dev, "%s events: %d\n", - state->events[i].name, - state->events[i].counter); - } - spin_unlock_irqrestore(&state->slock, flags); -} - -static int mipi_csis_dump_regs(struct csi_state *state) -{ - static const struct { - u32 offset; - const char * const name; - } registers[] = { - { MIPI_CSIS_CMN_CTRL, "CMN_CTRL" }, - { MIPI_CSIS_CLK_CTRL, "CLK_CTRL" }, - { MIPI_CSIS_INT_MSK, "INT_MSK" }, - { MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" }, - { MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" }, - { MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" }, - { MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" }, - { MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" }, - { MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" }, - { MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" }, - { MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" }, - { MIPI_CSIS_DBG_CTRL, "DBG_CTRL" }, - { MIPI_CSIS_FRAME_COUNTER_CH(0), "FRAME_COUNTER_CH0" }, - }; - - unsigned int i; - u32 cfg; - - dev_info(state->dev, "--- REGISTERS ---\n"); - - for (i = 0; i < ARRAY_SIZE(registers); i++) { - cfg = mipi_csis_read(state, registers[i].offset); - dev_info(state->dev, "%14s: 0x%08x\n", registers[i].name, cfg); - } - - return 0; -} - -static int mipi_csis_dump_regs_show(struct seq_file *m, void *private) -{ - struct csi_state *state = m->private; - - return mipi_csis_dump_regs(state); -} -DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs); - -static void mipi_csis_debugfs_init(struct csi_state *state) -{ - state->debug.hs_settle = UINT_MAX; - state->debug.clk_settle = UINT_MAX; - - state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL); - - debugfs_create_bool("debug_enable", 0600, state->debugfs_root, - &state->debug.enable); - debugfs_create_file("dump_regs", 0600, state->debugfs_root, state, - &mipi_csis_dump_regs_fops); - debugfs_create_u32("tclk_settle", 0600, state->debugfs_root, - &state->debug.clk_settle); - debugfs_create_u32("ths_settle", 0600, state->debugfs_root, - &state->debug.hs_settle); -} - -static void mipi_csis_debugfs_exit(struct csi_state *state) -{ - debugfs_remove_recursive(state->debugfs_root); -} - -/* ----------------------------------------------------------------------------- - * V4L2 subdev operations - */ - -static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev) -{ - return container_of(sdev, struct csi_state, sd); -} - -static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct csi_state *state = mipi_sd_to_csis_state(sd); - int ret; - - if (enable) { - ret = mipi_csis_calculate_params(state); - if (ret < 0) - return ret; - - mipi_csis_clear_counters(state); - - ret = pm_runtime_resume_and_get(state->dev); - if (ret < 0) - return ret; - - ret = v4l2_subdev_call(state->src_sd, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) - goto done; - } - - mutex_lock(&state->lock); - - if (enable) { - if (state->state & ST_SUSPENDED) { - ret = -EBUSY; - goto unlock; - } - - mipi_csis_start_stream(state); - ret = v4l2_subdev_call(state->src_sd, video, s_stream, 1); - if (ret < 0) - goto unlock; - - mipi_csis_log_counters(state, true); - - state->state |= ST_STREAMING; - } else { - v4l2_subdev_call(state->src_sd, video, s_stream, 0); - ret = v4l2_subdev_call(state->src_sd, core, s_power, 0); - if (ret == -ENOIOCTLCMD) - ret = 0; - mipi_csis_stop_stream(state); - state->state &= ~ST_STREAMING; - if (state->debug.enable) - mipi_csis_log_counters(state, true); - } - -unlock: - mutex_unlock(&state->lock); - -done: - if (!enable || ret < 0) - pm_runtime_put(state->dev); - - return ret; -} - -static struct v4l2_mbus_framefmt * -mipi_csis_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; -} - -static int mipi_csis_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state) -{ - struct csi_state *state = mipi_sd_to_csis_state(sd); - struct v4l2_mbus_framefmt *fmt_sink; - struct v4l2_mbus_framefmt *fmt_source; - enum v4l2_subdev_format_whence which; - - which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; - fmt_sink = mipi_csis_get_format(state, sd_state, which, CSIS_PAD_SINK); - - fmt_sink->code = MEDIA_BUS_FMT_UYVY8_1X16; - fmt_sink->width = MIPI_CSIS_DEF_PIX_WIDTH; - fmt_sink->height = MIPI_CSIS_DEF_PIX_HEIGHT; - fmt_sink->field = V4L2_FIELD_NONE; - - fmt_sink->colorspace = V4L2_COLORSPACE_SMPTE170M; - 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); - - /* - * When called from mipi_csis_subdev_init() to initialize the active - * configuration, cfg is NULL, which indicates there's no source pad - * configuration to set. - */ - if (!sd_state) - return 0; - - fmt_source = mipi_csis_get_format(state, sd_state, which, - CSIS_PAD_SOURCE); - *fmt_source = *fmt_sink; - - return 0; -} - -static int mipi_csis_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *sdformat) -{ - struct csi_state *state = mipi_sd_to_csis_state(sd); - struct v4l2_mbus_framefmt *fmt; - - fmt = mipi_csis_get_format(state, sd_state, sdformat->which, - sdformat->pad); - - mutex_lock(&state->lock); - sdformat->format = *fmt; - mutex_unlock(&state->lock); - - return 0; -} - -static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct csi_state *state = mipi_sd_to_csis_state(sd); - - /* - * The CSIS can't transcode in any way, the source format is identical - * to the sink format. - */ - if (code->pad == CSIS_PAD_SOURCE) { - struct v4l2_mbus_framefmt *fmt; - - if (code->index > 0) - return -EINVAL; - - fmt = mipi_csis_get_format(state, sd_state, code->which, - code->pad); - code->code = fmt->code; - return 0; - } - - if (code->pad != CSIS_PAD_SINK) - return -EINVAL; - - if (code->index >= ARRAY_SIZE(mipi_csis_formats)) - return -EINVAL; - - code->code = mipi_csis_formats[code->index].code; - - return 0; -} - -static int mipi_csis_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *sdformat) -{ - struct csi_state *state = mipi_sd_to_csis_state(sd); - struct csis_pix_format const *csis_fmt; - struct v4l2_mbus_framefmt *fmt; - unsigned int align; - - /* - * The CSIS can't transcode in any way, the source format can't be - * modified. - */ - if (sdformat->pad == CSIS_PAD_SOURCE) - return mipi_csis_get_fmt(sd, sd_state, sdformat); - - if (sdformat->pad != CSIS_PAD_SINK) - return -EINVAL; - - /* - * Validate the media bus code and clamp and align the size. - * - * The total number of bits per line must be a multiple of 8. We thus - * need to align the width for formats that are not multiples of 8 - * bits. - */ - csis_fmt = find_csis_format(sdformat->format.code); - if (!csis_fmt) - csis_fmt = &mipi_csis_formats[0]; - - switch (csis_fmt->width % 8) { - case 0: - align = 0; - break; - case 4: - align = 1; - break; - case 2: - case 6: - align = 2; - break; - default: - /* 1, 3, 5, 7 */ - align = 3; - break; - } - - v4l_bound_align_image(&sdformat->format.width, 1, - CSIS_MAX_PIX_WIDTH, align, - &sdformat->format.height, 1, - CSIS_MAX_PIX_HEIGHT, 0, 0); - - fmt = mipi_csis_get_format(state, sd_state, sdformat->which, - sdformat->pad); - - mutex_lock(&state->lock); - - fmt->code = csis_fmt->code; - fmt->width = sdformat->format.width; - fmt->height = sdformat->format.height; - fmt->colorspace = sdformat->format.colorspace; - fmt->quantization = sdformat->format.quantization; - fmt->xfer_func = sdformat->format.xfer_func; - fmt->ycbcr_enc = sdformat->format.ycbcr_enc; - - sdformat->format = *fmt; - - /* Propagate the format from sink to source. */ - fmt = mipi_csis_get_format(state, sd_state, sdformat->which, - CSIS_PAD_SOURCE); - *fmt = sdformat->format; - - /* Store the CSIS format descriptor for active formats. */ - if (sdformat->which == V4L2_SUBDEV_FORMAT_ACTIVE) - state->csis_fmt = csis_fmt; - - mutex_unlock(&state->lock); - - return 0; -} - -static int mipi_csis_log_status(struct v4l2_subdev *sd) -{ - struct csi_state *state = mipi_sd_to_csis_state(sd); - - mutex_lock(&state->lock); - mipi_csis_log_counters(state, true); - if (state->debug.enable && (state->state & ST_POWERED)) - mipi_csis_dump_regs(state); - mutex_unlock(&state->lock); - - return 0; -} - -static const struct v4l2_subdev_core_ops mipi_csis_core_ops = { - .log_status = mipi_csis_log_status, -}; - -static const struct v4l2_subdev_video_ops mipi_csis_video_ops = { - .s_stream = mipi_csis_s_stream, -}; - -static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = { - .init_cfg = mipi_csis_init_cfg, - .enum_mbus_code = mipi_csis_enum_mbus_code, - .get_fmt = mipi_csis_get_fmt, - .set_fmt = mipi_csis_set_fmt, -}; - -static const struct v4l2_subdev_ops mipi_csis_subdev_ops = { - .core = &mipi_csis_core_ops, - .video = &mipi_csis_video_ops, - .pad = &mipi_csis_pad_ops, -}; - -/* ----------------------------------------------------------------------------- - * Media entity operations - */ - -static int mipi_csis_link_setup(struct media_entity *entity, - const struct media_pad *local_pad, - const struct media_pad *remote_pad, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct csi_state *state = mipi_sd_to_csis_state(sd); - struct v4l2_subdev *remote_sd; - - dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name, - local_pad->entity->name); - - /* We only care about the link to the source. */ - if (!(local_pad->flags & MEDIA_PAD_FL_SINK)) - return 0; - - remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); - - if (flags & MEDIA_LNK_FL_ENABLED) { - if (state->src_sd) - return -EBUSY; - - state->src_sd = remote_sd; - } else { - state->src_sd = NULL; - } - - return 0; -} - -static const struct media_entity_operations mipi_csis_entity_ops = { - .link_setup = mipi_csis_link_setup, - .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_csis_state(struct v4l2_async_notifier *n) -{ - return container_of(n, struct csi_state, notifier); -} - -static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) -{ - struct csi_state *state = mipi_notifier_to_csis_state(notifier); - struct media_pad *sink = &state->sd.entity.pads[CSIS_PAD_SINK]; - - return v4l2_create_fwnode_links_to_pad(sd, sink, 0); -} - -static const struct v4l2_async_notifier_operations mipi_csis_notify_ops = { - .bound = mipi_csis_notify_bound, -}; - -static int mipi_csis_async_register(struct csi_state *state) -{ - 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_nf_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\n", state->bus.num_data_lanes); - dev_dbg(state->dev, "flags: 0x%08x\n", state->bus.flags); - - asd = v4l2_async_nf_add_fwnode_remote(&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 = &mipi_csis_notify_ops; - - ret = v4l2_async_subdev_nf_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 mipi_csis_pm_suspend(struct device *dev, bool runtime) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct csi_state *state = mipi_sd_to_csis_state(sd); - int ret = 0; - - mutex_lock(&state->lock); - if (state->state & ST_POWERED) { - mipi_csis_stop_stream(state); - ret = mipi_csis_phy_disable(state); - if (ret) - goto unlock; - mipi_csis_clk_disable(state); - state->state &= ~ST_POWERED; - if (!runtime) - state->state |= ST_SUSPENDED; - } - -unlock: - mutex_unlock(&state->lock); - - return ret ? -EAGAIN : 0; -} - -static int mipi_csis_pm_resume(struct device *dev, bool runtime) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct csi_state *state = mipi_sd_to_csis_state(sd); - int ret = 0; - - mutex_lock(&state->lock); - if (!runtime && !(state->state & ST_SUSPENDED)) - goto unlock; - - if (!(state->state & ST_POWERED)) { - ret = mipi_csis_phy_enable(state); - if (ret) - goto unlock; - - state->state |= ST_POWERED; - mipi_csis_clk_enable(state); - } - if (state->state & ST_STREAMING) - mipi_csis_start_stream(state); - - state->state &= ~ST_SUSPENDED; - -unlock: - mutex_unlock(&state->lock); - - return ret ? -EAGAIN : 0; -} - -static int __maybe_unused mipi_csis_suspend(struct device *dev) -{ - return mipi_csis_pm_suspend(dev, false); -} - -static int __maybe_unused mipi_csis_resume(struct device *dev) -{ - return mipi_csis_pm_resume(dev, false); -} - -static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev) -{ - return mipi_csis_pm_suspend(dev, true); -} - -static int __maybe_unused mipi_csis_runtime_resume(struct device *dev) -{ - return mipi_csis_pm_resume(dev, true); -} - -static const struct dev_pm_ops mipi_csis_pm_ops = { - SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume) -}; - -/* ----------------------------------------------------------------------------- - * Probe/remove & platform driver - */ - -static int mipi_csis_subdev_init(struct csi_state *state) -{ - struct v4l2_subdev *sd = &state->sd; - - v4l2_subdev_init(sd, &mipi_csis_subdev_ops); - sd->owner = THIS_MODULE; - snprintf(sd->name, sizeof(sd->name), "csis-%s", - dev_name(state->dev)); - - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - sd->ctrl_handler = NULL; - - sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; - sd->entity.ops = &mipi_csis_entity_ops; - - sd->dev = state->dev; - - state->csis_fmt = &mipi_csis_formats[0]; - mipi_csis_init_cfg(sd, NULL); - - state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK - | MEDIA_PAD_FL_MUST_CONNECT; - state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE - | MEDIA_PAD_FL_MUST_CONNECT; - return media_entity_pads_init(&sd->entity, CSIS_PADS_NUM, - state->pads); -} - -static int mipi_csis_parse_dt(struct csi_state *state) -{ - struct device_node *node = state->dev->of_node; - - if (of_property_read_u32(node, "clock-frequency", - &state->clk_frequency)) - state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; - - return 0; -} - -static int mipi_csis_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct csi_state *state; - int irq; - int ret; - - state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); - if (!state) - return -ENOMEM; - - mutex_init(&state->lock); - spin_lock_init(&state->slock); - - state->dev = dev; - state->info = of_device_get_match_data(dev); - - memcpy(state->events, mipi_csis_events, sizeof(state->events)); - - /* Parse DT properties. */ - ret = mipi_csis_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); - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - ret = mipi_csis_phy_init(state); - if (ret < 0) - return ret; - - ret = mipi_csis_clk_get(state); - if (ret < 0) - return ret; - - /* Reset PHY and enable the clocks. */ - mipi_csis_phy_reset(state); - - ret = mipi_csis_clk_enable(state); - if (ret < 0) { - dev_err(state->dev, "failed to enable clocks: %d\n", ret); - return ret; - } - - /* Now that the hardware is initialized, request the interrupt. */ - ret = devm_request_irq(dev, irq, mipi_csis_irq_handler, 0, - dev_name(dev), state); - if (ret) { - dev_err(dev, "Interrupt request failed\n"); - goto disable_clock; - } - - /* Initialize and register the subdev. */ - ret = mipi_csis_subdev_init(state); - if (ret < 0) - goto disable_clock; - - platform_set_drvdata(pdev, &state->sd); - - ret = mipi_csis_async_register(state); - if (ret < 0) { - dev_err(dev, "async register failed: %d\n", ret); - goto cleanup; - } - - /* Initialize debugfs. */ - mipi_csis_debugfs_init(state); - - /* Enable runtime PM. */ - pm_runtime_enable(dev); - if (!pm_runtime_enabled(dev)) { - ret = mipi_csis_pm_resume(dev, true); - if (ret < 0) - goto unregister_all; - } - - dev_info(dev, "lanes: %d, freq: %u\n", - state->bus.num_data_lanes, state->clk_frequency); - - return 0; - -unregister_all: - mipi_csis_debugfs_exit(state); -cleanup: - media_entity_cleanup(&state->sd.entity); - v4l2_async_nf_unregister(&state->notifier); - v4l2_async_nf_cleanup(&state->notifier); - v4l2_async_unregister_subdev(&state->sd); -disable_clock: - mipi_csis_clk_disable(state); - mutex_destroy(&state->lock); - - return ret; -} - -static int mipi_csis_remove(struct platform_device *pdev) -{ - struct v4l2_subdev *sd = platform_get_drvdata(pdev); - struct csi_state *state = mipi_sd_to_csis_state(sd); - - mipi_csis_debugfs_exit(state); - v4l2_async_nf_unregister(&state->notifier); - v4l2_async_nf_cleanup(&state->notifier); - v4l2_async_unregister_subdev(&state->sd); - - pm_runtime_disable(&pdev->dev); - mipi_csis_pm_suspend(&pdev->dev, true); - mipi_csis_clk_disable(state); - media_entity_cleanup(&state->sd.entity); - mutex_destroy(&state->lock); - pm_runtime_set_suspended(&pdev->dev); - - return 0; -} - -static const struct of_device_id mipi_csis_of_match[] = { - { - .compatible = "fsl,imx7-mipi-csi2", - .data = &(const struct mipi_csis_info){ - .version = MIPI_CSIS_V3_3, - .num_clocks = 3, - }, - }, { - .compatible = "fsl,imx8mm-mipi-csi2", - .data = &(const struct mipi_csis_info){ - .version = MIPI_CSIS_V3_6_3, - .num_clocks = 4, - }, - }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, mipi_csis_of_match); - -static struct platform_driver mipi_csis_driver = { - .probe = mipi_csis_probe, - .remove = mipi_csis_remove, - .driver = { - .of_match_table = mipi_csis_of_match, - .name = CSIS_DRIVER_NAME, - .pm = &mipi_csis_pm_ops, - }, -}; - -module_platform_driver(mipi_csis_driver); - -MODULE_DESCRIPTION("i.MX7 & i.MX8 MIPI CSI-2 receiver driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:imx7-mipi-csi2"); -- cgit v1.2.3 From 9babbbaaeb87dee9a9a10dd2923b173902acf7ea Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 21 Feb 2022 18:47:23 +0100 Subject: media: imx: imx7-media-csi: Use dual sampling for YUV 1X16 The CSI bridge should operate in dual components mode when it is connected to a pixel transmitter that transfers two components at a time in YUV 422 formats (16 bits, Y + U/V). Use the image format variants to determine if single or dual component mode should be used. Add a note to the TODO file to record that the list of supported formats should be restricted to the SoC model the CSI bridge is integrated on to avoid potential pipeline mis-configurations. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Acked-by: Rui Miguel Silva Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil --- drivers/staging/media/imx/TODO | 25 +++++++++++++++++++++++ drivers/staging/media/imx/imx7-media-csi.c | 32 ++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 4 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/TODO b/drivers/staging/media/imx/TODO index 06c94f20ecf8..5d3a337c8702 100644 --- a/drivers/staging/media/imx/TODO +++ b/drivers/staging/media/imx/TODO @@ -27,3 +27,28 @@ - i.MX7: all of the above, since it uses the imx media core - i.MX7: use Frame Interval Monitor + +- imx7-media-csi: Restrict the supported formats list to the SoC version. + + The imx7 CSI bridge can be configured to sample pixel components from the Rx + queue in single (8bpp) or double (16bpp) component modes. Image format + variants with different sample sizes (ie YUYV_2X8 vs YUYV_1X16) determine the + pixel components sampling size per each clock cycle and their packing mode + (see imx7_csi_configure() for details). + + As the imx7 CSI bridge can be interfaced with different IP blocks depending on + the SoC model it is integrated on, the Rx queue sampling size should match + the size of the samples transferred by the transmitting IP block. + + To avoid mis-configurations of the capture pipeline, the enumeration of the + supported formats should be restricted to match the pixel source transmitting + mode. + + Example: i.MX8MM SoC integrates the CSI bridge with the Samsung CSIS CSI-2 + receiver which operates in dual pixel sampling mode. The CSI bridge should + only expose the 1X16 formats variant which instructs it to operate in dual + pixel sampling mode. When the CSI bridge is instead integrated on an i.MX7, + which supports both serial and parallel input, it should expose both variants. + + This currently only applies to YUYV formats, but other formats might need + to be handled in the same way. diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 32311fc0e2a4..8467a1491048 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -498,16 +498,40 @@ static void imx7_csi_configure(struct imx7_csi *csi) cr3 |= BIT_TWO_8BIT_SENSOR; cr18 |= BIT_MIPI_DATA_FORMAT_RAW14; break; + /* - * CSI-2 sources are supposed to use the 1X16 formats, but not - * all of them comply. Support both variants. + * The CSI bridge has a 16-bit input bus. Depending on the + * connected source, data may be transmitted with 8 or 10 bits + * per clock sample (in bits [9:2] or [9:0] respectively) or + * with 16 bits per clock sample (in bits [15:0]). The data is + * then packed into a 32-bit FIFO (as shown in figure 13-11 of + * the i.MX8MM reference manual rev. 3). + * + * The data packing in a 32-bit FIFO input word is controlled by + * the CR3 TWO_8BIT_SENSOR field (also known as SENSOR_16BITS in + * the i.MX8MM reference manual). When set to 0, data packing + * groups four 8-bit input samples (bits [9:2]). When set to 1, + * data packing groups two 16-bit input samples (bits [15:0]). + * + * The register field CR18 MIPI_DOUBLE_CMPNT also needs to be + * configured according to the input format for YUV 4:2:2 data. + * The field controls the gasket between the CSI-2 receiver and + * the CSI bridge. On i.MX7 and i.MX8MM, the field must be set + * to 1 when the CSIS outputs 16-bit samples. On i.MX8MQ, the + * gasket ignores the MIPI_DOUBLE_CMPNT bit and YUV 4:2:2 always + * uses 16-bit samples. Setting MIPI_DOUBLE_CMPNT in that case + * has no effect, but doesn't cause any issue. */ case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_UYVY8_1X16: case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_YUYV8_1X16: cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B; break; + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_YUYV8_1X16: + cr3 |= BIT_TWO_8BIT_SENSOR; + cr18 |= BIT_MIPI_DATA_FORMAT_YUV422_8B | + BIT_MIPI_DOUBLE_CMPNT; + break; } } -- cgit v1.2.3 From 884c8bd91828d851ede5489cb5b4134ffc61f965 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Mon, 21 Feb 2022 19:17:08 +0100 Subject: media: imx: imx8mq-mipi-csi2: Remove YUV422 2X8 The 2X8 variants of MEDIA_BUS_FMT_YUYV8_2X8 does not apply to serial busses. Drop it and while at it also add the canonical UYVY wire format for packed YUV422 when transmitted on the CSI-2 serial bus. Also beautify a little the formats declaration list by putting the opening curly brace after the comment. Signed-off-by: Jacopo Mondi Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil --- drivers/staging/media/imx/imx8mq-mipi-csi2.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c index 56ef3b3b2906..449796a0b942 100644 --- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -200,12 +200,13 @@ static const struct csi2_pix_format imx8mq_mipi_csi_formats[] = { }, { .code = MEDIA_BUS_FMT_SRGGB14_1X14, .width = 14, - }, { + }, /* YUV formats */ - .code = MEDIA_BUS_FMT_YUYV8_2X8, + { + .code = MEDIA_BUS_FMT_YUYV8_1X16, .width = 16, }, { - .code = MEDIA_BUS_FMT_YUYV8_1X16, + .code = MEDIA_BUS_FMT_UYVY8_1X16, .width = 16, } }; -- cgit v1.2.3 From 17e83a0a1e134401616120b6976f65234e7ccc45 Mon Sep 17 00:00:00 2001 From: Jernej Skrabec Date: Tue, 22 Feb 2022 19:03:28 +0100 Subject: media: hantro: sunxi: Fix VP9 steps It turns out that postproc on Allwinner H6 needs width and height to be multiple of 32. Fixes: 86790a4fdf4b ("media: hantro: Add support for Allwinner H6") Signed-off-by: Jernej Skrabec Signed-off-by: Hans Verkuil --- drivers/staging/media/hantro/sunxi_vpu_hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/sunxi_vpu_hw.c b/drivers/staging/media/hantro/sunxi_vpu_hw.c index 90633406c4eb..c0edd5856a0c 100644 --- a/drivers/staging/media/hantro/sunxi_vpu_hw.c +++ b/drivers/staging/media/hantro/sunxi_vpu_hw.c @@ -29,10 +29,10 @@ static const struct hantro_fmt sunxi_vpu_dec_fmts[] = { .frmsize = { .min_width = 48, .max_width = 3840, - .step_width = MB_DIM, + .step_width = 32, .min_height = 48, .max_height = 2160, - .step_height = MB_DIM, + .step_height = 32, }, }, }; -- cgit v1.2.3 From 6971efb70ac3e43d19bf33ef5f83bea0271831ee Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Tue, 25 Jan 2022 18:11:23 +0100 Subject: media: hantro: Allow i.MX8MQ G1 and G2 to run independently The VPU in the i.MX8MQ is really the combination of Hantro G1 and Hantro G2. With the updated vpu-blk-ctrl, the power domains system can enable and disable them separately as well as pull them out of reset. This simplifies the code and lets them run independently while still retaining backwards compatibility with older device trees for those using G1. Signed-off-by: Adam Ford Reviewed-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/hantro/hantro_drv.c | 10 ++++++ drivers/staging/media/hantro/hantro_hw.h | 1 + drivers/staging/media/hantro/imx8m_vpu_hw.c | 50 +++++++++++++++++++++-------- 3 files changed, 48 insertions(+), 13 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index bc9bcb4eaf46..5a76bedde3b0 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -631,6 +631,7 @@ static const struct of_device_id of_hantro_match[] = { #endif #ifdef CONFIG_VIDEO_HANTRO_IMX8M { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, }, + { .compatible = "nxp,imx8mq-vpu-g1", .data = &imx8mq_vpu_g1_variant }, { .compatible = "nxp,imx8mq-vpu-g2", .data = &imx8mq_vpu_g2_variant }, #endif #ifdef CONFIG_VIDEO_HANTRO_SAMA5D4 @@ -905,6 +906,15 @@ static int hantro_probe(struct platform_device *pdev) match = of_match_node(of_hantro_match, pdev->dev.of_node); vpu->variant = match->data; + /* + * Support for nxp,imx8mq-vpu is kept for backwards compatibility + * but it's deprecated. Please update your DTS file to use + * nxp,imx8mq-vpu-g1 or nxp,imx8mq-vpu-g2 instead. + */ + if (of_device_is_compatible(pdev->dev.of_node, "nxp,imx8mq-vpu")) + dev_warn(&pdev->dev, "%s compatible is deprecated\n", + match->compatible); + INIT_DELAYED_WORK(&vpu->watchdog_work, hantro_watchdog); vpu->clocks = devm_kcalloc(&pdev->dev, vpu->variant->num_clocks, diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index c1fd807bc090..2bd094bbfc82 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -290,6 +290,7 @@ enum hantro_enc_fmt { ROCKCHIP_VPU_ENC_FMT_UYVY422 = 3, }; +extern const struct hantro_variant imx8mq_vpu_g1_variant; 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; diff --git a/drivers/staging/media/hantro/imx8m_vpu_hw.c b/drivers/staging/media/hantro/imx8m_vpu_hw.c index f5991b8e553a..849ea7122d47 100644 --- a/drivers/staging/media/hantro/imx8m_vpu_hw.c +++ b/drivers/staging/media/hantro/imx8m_vpu_hw.c @@ -205,13 +205,6 @@ static void imx8m_vpu_g1_reset(struct hantro_ctx *ctx) imx8m_soft_reset(vpu, RESET_G1); } -static void imx8m_vpu_g2_reset(struct hantro_ctx *ctx) -{ - struct hantro_dev *vpu = ctx->dev; - - imx8m_soft_reset(vpu, RESET_G2); -} - /* * Supported codec ops. */ @@ -237,17 +230,33 @@ static const struct hantro_codec_ops imx8mq_vpu_codec_ops[] = { }, }; +static const struct hantro_codec_ops imx8mq_vpu_g1_codec_ops[] = { + [HANTRO_MODE_MPEG2_DEC] = { + .run = hantro_g1_mpeg2_dec_run, + .init = hantro_mpeg2_dec_init, + .exit = hantro_mpeg2_dec_exit, + }, + [HANTRO_MODE_VP8_DEC] = { + .run = hantro_g1_vp8_dec_run, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, + [HANTRO_MODE_H264_DEC] = { + .run = hantro_g1_h264_dec_run, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, +}; + static const struct hantro_codec_ops imx8mq_vpu_g2_codec_ops[] = { [HANTRO_MODE_HEVC_DEC] = { .run = hantro_g2_hevc_dec_run, - .reset = imx8m_vpu_g2_reset, .init = hantro_hevc_dec_init, .exit = hantro_hevc_dec_exit, }, [HANTRO_MODE_VP9_DEC] = { .run = hantro_g2_vp9_dec_run, .done = hantro_g2_vp9_dec_done, - .reset = imx8m_vpu_g2_reset, .init = hantro_vp9_dec_init, .exit = hantro_vp9_dec_exit, }, @@ -267,6 +276,8 @@ static const struct hantro_irq imx8mq_g2_irqs[] = { static const char * const imx8mq_clk_names[] = { "g1", "g2", "bus" }; static const char * const imx8mq_reg_names[] = { "g1", "g2", "ctrl" }; +static const char * const imx8mq_g1_clk_names[] = { "g1" }; +static const char * const imx8mq_g2_clk_names[] = { "g2" }; const struct hantro_variant imx8mq_vpu_variant = { .dec_fmts = imx8m_vpu_dec_fmts, @@ -287,6 +298,21 @@ const struct hantro_variant imx8mq_vpu_variant = { .num_regs = ARRAY_SIZE(imx8mq_reg_names) }; +const struct hantro_variant imx8mq_vpu_g1_variant = { + .dec_fmts = imx8m_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts), + .postproc_fmts = imx8m_vpu_postproc_fmts, + .num_postproc_fmts = ARRAY_SIZE(imx8m_vpu_postproc_fmts), + .postproc_ops = &hantro_g1_postproc_ops, + .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | + HANTRO_H264_DECODER, + .codec_ops = imx8mq_vpu_g1_codec_ops, + .irqs = imx8mq_irqs, + .num_irqs = ARRAY_SIZE(imx8mq_irqs), + .clk_names = imx8mq_g1_clk_names, + .num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names), +}; + const struct hantro_variant imx8mq_vpu_g2_variant = { .dec_offset = 0x0, .dec_fmts = imx8m_vpu_g2_dec_fmts, @@ -296,10 +322,8 @@ const struct hantro_variant imx8mq_vpu_g2_variant = { .postproc_ops = &hantro_g2_postproc_ops, .codec = HANTRO_HEVC_DECODER | HANTRO_VP9_DECODER, .codec_ops = imx8mq_vpu_g2_codec_ops, - .init = imx8mq_vpu_hw_init, - .runtime_resume = imx8mq_runtime_resume, .irqs = imx8mq_g2_irqs, .num_irqs = ARRAY_SIZE(imx8mq_g2_irqs), - .clk_names = imx8mq_clk_names, - .num_clocks = ARRAY_SIZE(imx8mq_clk_names), + .clk_names = imx8mq_g2_clk_names, + .num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names), }; -- cgit v1.2.3 From cf1abc501a5c76e390efdf74edf63e9328efdbad Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Tue, 25 Jan 2022 18:11:27 +0100 Subject: media: hantro: Add support for i.MX8MM Hantro-G1 The i.MX8MM has a Hantro G1 video decoder similar to the imx8mq but lacks the post-processor present in the imx8mq. Add support in the driver for it with the post-processing removed. Signed-off-by: Adam Ford Reviewed-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/imx8m_vpu_hw.c | 12 ++++++++++++ 3 files changed, 14 insertions(+) (limited to 'drivers/staging') diff --git a/drivers/staging/media/hantro/hantro_drv.c b/drivers/staging/media/hantro/hantro_drv.c index 5a76bedde3b0..dc768884cb79 100644 --- a/drivers/staging/media/hantro/hantro_drv.c +++ b/drivers/staging/media/hantro/hantro_drv.c @@ -630,6 +630,7 @@ static const struct of_device_id of_hantro_match[] = { { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, }, #endif #ifdef CONFIG_VIDEO_HANTRO_IMX8M + { .compatible = "nxp,imx8mm-vpu-g1", .data = &imx8mm_vpu_g1_variant, }, { .compatible = "nxp,imx8mq-vpu", .data = &imx8mq_vpu_variant, }, { .compatible = "nxp,imx8mq-vpu-g1", .data = &imx8mq_vpu_g1_variant }, { .compatible = "nxp,imx8mq-vpu-g2", .data = &imx8mq_vpu_g2_variant }, diff --git a/drivers/staging/media/hantro/hantro_hw.h b/drivers/staging/media/hantro/hantro_hw.h index 2bd094bbfc82..ed018e293ba0 100644 --- a/drivers/staging/media/hantro/hantro_hw.h +++ b/drivers/staging/media/hantro/hantro_hw.h @@ -290,6 +290,7 @@ enum hantro_enc_fmt { ROCKCHIP_VPU_ENC_FMT_UYVY422 = 3, }; +extern const struct hantro_variant imx8mm_vpu_g1_variant; extern const struct hantro_variant imx8mq_vpu_g1_variant; extern const struct hantro_variant imx8mq_vpu_g2_variant; extern const struct hantro_variant imx8mq_vpu_variant; diff --git a/drivers/staging/media/hantro/imx8m_vpu_hw.c b/drivers/staging/media/hantro/imx8m_vpu_hw.c index 849ea7122d47..9802508bade2 100644 --- a/drivers/staging/media/hantro/imx8m_vpu_hw.c +++ b/drivers/staging/media/hantro/imx8m_vpu_hw.c @@ -327,3 +327,15 @@ const struct hantro_variant imx8mq_vpu_g2_variant = { .clk_names = imx8mq_g2_clk_names, .num_clocks = ARRAY_SIZE(imx8mq_g2_clk_names), }; + +const struct hantro_variant imx8mm_vpu_g1_variant = { + .dec_fmts = imx8m_vpu_dec_fmts, + .num_dec_fmts = ARRAY_SIZE(imx8m_vpu_dec_fmts), + .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER | + HANTRO_H264_DECODER, + .codec_ops = imx8mq_vpu_g1_codec_ops, + .irqs = imx8mq_irqs, + .num_irqs = ARRAY_SIZE(imx8mq_irqs), + .clk_names = imx8mq_g1_clk_names, + .num_clocks = ARRAY_SIZE(imx8mq_g1_clk_names), +}; -- cgit v1.2.3 From 3a6cddab2d807242b8461404203e51e0ca490f77 Mon Sep 17 00:00:00 2001 From: Muhammad Usama Anjum Date: Fri, 28 Jan 2022 18:07:22 +0100 Subject: media: imx: imx8mq-mipi_csi2: Remove unneeded code ret is constant in imx8mq_mipi_csi_pm_suspend(). This function cannot return error. Remove the return variable. Simplify other functions which are using this function. Signed-off-by: Muhammad Usama Anjum Reviewed-by: Fabio Estevam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx8mq-mipi-csi2.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/imx/imx8mq-mipi-csi2.c b/drivers/staging/media/imx/imx8mq-mipi-csi2.c index 56ef3b3b2906..476ee8e14f19 100644 --- a/drivers/staging/media/imx/imx8mq-mipi-csi2.c +++ b/drivers/staging/media/imx/imx8mq-mipi-csi2.c @@ -693,11 +693,10 @@ err_parse: * Suspend/resume */ -static int imx8mq_mipi_csi_pm_suspend(struct device *dev) +static void imx8mq_mipi_csi_pm_suspend(struct device *dev) { 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); @@ -708,8 +707,6 @@ static int imx8mq_mipi_csi_pm_suspend(struct device *dev) } mutex_unlock(&state->lock); - - return ret ? -EAGAIN : 0; } static int imx8mq_mipi_csi_pm_resume(struct device *dev) @@ -742,15 +739,12 @@ static int __maybe_unused imx8mq_mipi_csi_suspend(struct device *dev) { struct v4l2_subdev *sd = dev_get_drvdata(dev); struct csi_state *state = mipi_sd_to_csi2_state(sd); - int ret; - ret = imx8mq_mipi_csi_pm_suspend(dev); - if (ret) - return ret; + imx8mq_mipi_csi_pm_suspend(dev); state->state |= ST_SUSPENDED; - return ret; + return 0; } static int __maybe_unused imx8mq_mipi_csi_resume(struct device *dev) @@ -770,9 +764,7 @@ static int __maybe_unused imx8mq_mipi_csi_runtime_suspend(struct device *dev) struct csi_state *state = mipi_sd_to_csi2_state(sd); int ret; - ret = imx8mq_mipi_csi_pm_suspend(dev); - if (ret) - return ret; + imx8mq_mipi_csi_pm_suspend(dev); ret = icc_set_bw(state->icc_path, 0, 0); if (ret) -- cgit v1.2.3 From 9aa94a316466dc4df6808a4754f13f68bc2e2fa7 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 20 Feb 2022 21:46:17 +0100 Subject: media: staging: tegra-vde: Factor out H.264 code Factor out H.264 hardware programming code into separate source file in a preparation to support V4L API by the Tegra video decoder driver. Signed-off-by: Dmitry Osipenko Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/tegra-vde/Makefile | 2 +- drivers/staging/media/tegra-vde/h264.c | 647 +++++++++++++++++++++++++++++++ drivers/staging/media/tegra-vde/vde.c | 626 +----------------------------- drivers/staging/media/tegra-vde/vde.h | 42 ++ 4 files changed, 706 insertions(+), 611 deletions(-) create mode 100644 drivers/staging/media/tegra-vde/h264.c (limited to 'drivers/staging') diff --git a/drivers/staging/media/tegra-vde/Makefile b/drivers/staging/media/tegra-vde/Makefile index 2827f7601de8..43525b08b3b0 100644 --- a/drivers/staging/media/tegra-vde/Makefile +++ b/drivers/staging/media/tegra-vde/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -tegra-vde-y := vde.o iommu.o dmabuf-cache.o +tegra-vde-y := vde.o iommu.o dmabuf-cache.o h264.o obj-$(CONFIG_TEGRA_VDE) += tegra-vde.o diff --git a/drivers/staging/media/tegra-vde/h264.c b/drivers/staging/media/tegra-vde/h264.c new file mode 100644 index 000000000000..03faa705bf71 --- /dev/null +++ b/drivers/staging/media/tegra-vde/h264.c @@ -0,0 +1,647 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2016-2022 Dmitry Osipenko + * + */ + +#include +#include +#include +#include + +#include "trace.h" +#include "uapi.h" +#include "vde.h" + +static int tegra_vde_wait_mbe(struct tegra_vde *vde) +{ + u32 tmp; + + return readl_relaxed_poll_timeout(vde->mbe + 0x8C, tmp, + tmp >= 0x10, 1, 100); +} + +static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde, + unsigned int refs_nb, + bool setup_refs) +{ + u32 value, frame_idx_enb_mask = 0; + unsigned int frame_idx; + unsigned int idx; + int err; + + tegra_vde_writel(vde, 0xD0000000 | (0 << 23), vde->mbe, 0x80); + tegra_vde_writel(vde, 0xD0200000 | (0 << 23), vde->mbe, 0x80); + + err = tegra_vde_wait_mbe(vde); + if (err) + return err; + + if (!setup_refs) + return 0; + + for (idx = 0, frame_idx = 1; idx < refs_nb; idx++, frame_idx++) { + tegra_vde_writel(vde, 0xD0000000 | (frame_idx << 23), + vde->mbe, 0x80); + tegra_vde_writel(vde, 0xD0200000 | (frame_idx << 23), + vde->mbe, 0x80); + + frame_idx_enb_mask |= frame_idx << (6 * (idx % 4)); + + if (idx % 4 == 3 || idx == refs_nb - 1) { + value = 0xC0000000; + value |= (idx >> 2) << 24; + value |= frame_idx_enb_mask; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + err = tegra_vde_wait_mbe(vde); + if (err) + return err; + + frame_idx_enb_mask = 0; + } + } + + return 0; +} + +static void tegra_vde_mbe_set_0xa_reg(struct tegra_vde *vde, int reg, u32 val) +{ + tegra_vde_writel(vde, 0xA0000000 | (reg << 24) | (val & 0xFFFF), + vde->mbe, 0x80); + tegra_vde_writel(vde, 0xA0000000 | ((reg + 1) << 24) | (val >> 16), + vde->mbe, 0x80); +} + +static int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma) +{ + struct device *dev = vde->dev; + u32 value; + int err; + + err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, + !(value & BIT(2)), 1, 100); + if (err) { + dev_err(dev, "BSEV unknown bit timeout\n"); + return err; + } + + err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, + (value & BSE_ICMDQUE_EMPTY), 1, 100); + if (err) { + dev_err(dev, "BSEV ICMDQUE flush timeout\n"); + return err; + } + + if (!wait_dma) + return 0; + + err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, + !(value & BSE_DMA_BUSY), 1, 100); + if (err) { + dev_err(dev, "BSEV DMA timeout\n"); + return err; + } + + return 0; +} + +static int tegra_vde_push_to_bsev_icmdqueue(struct tegra_vde *vde, + u32 value, bool wait_dma) +{ + tegra_vde_writel(vde, value, vde->bsev, ICMDQUE_WR); + + return tegra_vde_wait_bsev(vde, wait_dma); +} + +static void tegra_vde_setup_frameid(struct tegra_vde *vde, + struct tegra_video_frame *frame, + unsigned int frameid, + u32 mbs_width, u32 mbs_height) +{ + u32 y_addr = frame ? frame->y_addr : 0x6CDEAD00; + u32 cb_addr = frame ? frame->cb_addr : 0x6CDEAD00; + u32 cr_addr = frame ? frame->cr_addr : 0x6CDEAD00; + u32 value1 = frame ? ((mbs_width << 16) | mbs_height) : 0; + u32 value2 = frame ? ((((mbs_width + 1) >> 1) << 6) | 1) : 0; + + tegra_vde_writel(vde, y_addr >> 8, vde->frameid, 0x000 + frameid * 4); + tegra_vde_writel(vde, cb_addr >> 8, vde->frameid, 0x100 + frameid * 4); + tegra_vde_writel(vde, cr_addr >> 8, vde->frameid, 0x180 + frameid * 4); + tegra_vde_writel(vde, value1, vde->frameid, 0x080 + frameid * 4); + tegra_vde_writel(vde, value2, vde->frameid, 0x280 + frameid * 4); +} + +static void tegra_setup_frameidx(struct tegra_vde *vde, + struct tegra_video_frame *frames, + unsigned int frames_nb, + u32 mbs_width, u32 mbs_height) +{ + unsigned int idx; + + for (idx = 0; idx < frames_nb; idx++) + tegra_vde_setup_frameid(vde, &frames[idx], idx, + mbs_width, mbs_height); + + for (; idx < 17; idx++) + tegra_vde_setup_frameid(vde, NULL, idx, 0, 0); +} + +static void tegra_vde_setup_iram_entry(struct tegra_vde *vde, + unsigned int table, + unsigned int row, + u32 value1, u32 value2) +{ + u32 *iram_tables = vde->iram; + + trace_vde_setup_iram_entry(table, row, value1, value2); + + iram_tables[0x20 * table + row * 2 + 0] = value1; + iram_tables[0x20 * table + row * 2 + 1] = value2; +} + +static void tegra_vde_setup_iram_tables(struct tegra_vde *vde, + struct tegra_video_frame *dpb_frames, + unsigned int ref_frames_nb, + unsigned int with_earlier_poc_nb) +{ + struct tegra_video_frame *frame; + int with_later_poc_nb; + u32 value, aux_addr; + unsigned int i, k; + + trace_vde_ref_l0(dpb_frames[0].frame_num); + + for (i = 0; i < 16; i++) { + if (i < ref_frames_nb) { + frame = &dpb_frames[i + 1]; + + aux_addr = frame->aux_addr; + + value = (i + 1) << 26; + value |= !(frame->flags & FLAG_B_FRAME) << 25; + value |= 1 << 24; + value |= frame->frame_num; + } else { + aux_addr = 0x6ADEAD00; + value = 0x3f; + } + + tegra_vde_setup_iram_entry(vde, 0, i, value, aux_addr); + tegra_vde_setup_iram_entry(vde, 1, i, value, aux_addr); + tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); + tegra_vde_setup_iram_entry(vde, 3, i, value, aux_addr); + } + + if (!(dpb_frames[0].flags & FLAG_B_FRAME)) + return; + + if (with_earlier_poc_nb >= ref_frames_nb) + return; + + with_later_poc_nb = ref_frames_nb - with_earlier_poc_nb; + + trace_vde_ref_l1(with_later_poc_nb, with_earlier_poc_nb); + + for (i = 0, k = with_earlier_poc_nb; i < with_later_poc_nb; i++, k++) { + frame = &dpb_frames[k + 1]; + + aux_addr = frame->aux_addr; + + value = (k + 1) << 26; + value |= !(frame->flags & FLAG_B_FRAME) << 25; + value |= 1 << 24; + value |= frame->frame_num; + + tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); + } + + for (k = 0; i < ref_frames_nb; i++, k++) { + frame = &dpb_frames[k + 1]; + + aux_addr = frame->aux_addr; + + value = (k + 1) << 26; + value |= !(frame->flags & FLAG_B_FRAME) << 25; + value |= 1 << 24; + value |= frame->frame_num; + + tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); + } +} + +static int tegra_vde_setup_hw_context(struct tegra_vde *vde, + struct tegra_vde_h264_decoder_ctx *ctx, + struct tegra_video_frame *dpb_frames, + dma_addr_t bitstream_data_addr, + size_t bitstream_data_size, + unsigned int macroblocks_nb) +{ + struct device *dev = vde->dev; + u32 value; + int err; + + tegra_vde_set_bits(vde, 0x000A, vde->sxe, 0xF0); + tegra_vde_set_bits(vde, 0x000B, vde->bsev, CMDQUE_CONTROL); + tegra_vde_set_bits(vde, 0x8002, vde->mbe, 0x50); + tegra_vde_set_bits(vde, 0x000A, vde->mbe, 0xA0); + tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x14); + tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x28); + tegra_vde_set_bits(vde, 0x0A00, vde->mce, 0x08); + tegra_vde_set_bits(vde, 0x000A, vde->tfe, 0x00); + tegra_vde_set_bits(vde, 0x0005, vde->vdma, 0x04); + + tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x1C); + tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x00); + tegra_vde_writel(vde, 0x00000007, vde->vdma, 0x04); + tegra_vde_writel(vde, 0x00000007, vde->frameid, 0x200); + tegra_vde_writel(vde, 0x00000005, vde->tfe, 0x04); + tegra_vde_writel(vde, 0x00000000, vde->mbe, 0x84); + tegra_vde_writel(vde, 0x00000010, vde->sxe, 0x08); + tegra_vde_writel(vde, 0x00000150, vde->sxe, 0x54); + tegra_vde_writel(vde, 0x0000054C, vde->sxe, 0x58); + tegra_vde_writel(vde, 0x00000E34, vde->sxe, 0x5C); + tegra_vde_writel(vde, 0x063C063C, vde->mce, 0x10); + tegra_vde_writel(vde, 0x0003FC00, vde->bsev, INTR_STATUS); + tegra_vde_writel(vde, 0x0000150D, vde->bsev, BSE_CONFIG); + tegra_vde_writel(vde, 0x00000100, vde->bsev, BSE_INT_ENB); + tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x98); + tegra_vde_writel(vde, 0x00000060, vde->bsev, 0x9C); + + memset(vde->iram + 128, 0, macroblocks_nb / 2); + + tegra_setup_frameidx(vde, dpb_frames, ctx->dpb_frames_nb, + ctx->pic_width_in_mbs, ctx->pic_height_in_mbs); + + tegra_vde_setup_iram_tables(vde, dpb_frames, + ctx->dpb_frames_nb - 1, + ctx->dpb_ref_frames_with_earlier_poc_nb); + + /* + * The IRAM mapping is write-combine, ensure that CPU buffers have + * been flushed at this point. + */ + wmb(); + + tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x8C); + tegra_vde_writel(vde, bitstream_data_addr + bitstream_data_size, + vde->bsev, 0x54); + + vde->bitstream_data_addr = bitstream_data_addr; + + value = ctx->pic_width_in_mbs << 11 | ctx->pic_height_in_mbs << 3; + + tegra_vde_writel(vde, value, vde->bsev, 0x88); + + err = tegra_vde_wait_bsev(vde, false); + if (err) + return err; + + err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x800003FC, false); + if (err) + return err; + + value = 0x01500000; + value |= ((vde->iram_lists_addr + 512) >> 2) & 0xFFFF; + + err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); + if (err) + return err; + + err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x840F054C, false); + if (err) + return err; + + err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x80000080, false); + if (err) + return err; + + value = 0x0E340000 | ((vde->iram_lists_addr >> 2) & 0xFFFF); + + err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); + if (err) + return err; + + value = 0x00800005; + value |= ctx->pic_width_in_mbs << 11; + value |= ctx->pic_height_in_mbs << 3; + + tegra_vde_writel(vde, value, vde->sxe, 0x10); + + value = !ctx->baseline_profile << 17; + value |= ctx->level_idc << 13; + value |= ctx->log2_max_pic_order_cnt_lsb << 7; + value |= ctx->pic_order_cnt_type << 5; + value |= ctx->log2_max_frame_num; + + tegra_vde_writel(vde, value, vde->sxe, 0x40); + + value = ctx->pic_init_qp << 25; + value |= !!(ctx->deblocking_filter_control_present_flag) << 2; + value |= !!ctx->pic_order_present_flag; + + tegra_vde_writel(vde, value, vde->sxe, 0x44); + + value = ctx->chroma_qp_index_offset; + value |= ctx->num_ref_idx_l0_active_minus1 << 5; + value |= ctx->num_ref_idx_l1_active_minus1 << 10; + value |= !!ctx->constrained_intra_pred_flag << 15; + + tegra_vde_writel(vde, value, vde->sxe, 0x48); + + value = 0x0C000000; + value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 24; + + tegra_vde_writel(vde, value, vde->sxe, 0x4C); + + value = 0x03800000; + value |= bitstream_data_size & GENMASK(19, 15); + + tegra_vde_writel(vde, value, vde->sxe, 0x68); + + tegra_vde_writel(vde, bitstream_data_addr, vde->sxe, 0x6C); + + if (vde->soc->supports_ref_pic_marking) + tegra_vde_writel(vde, vde->secure_bo->dma_addr, vde->sxe, 0x7c); + + value = 0x10000005; + value |= ctx->pic_width_in_mbs << 11; + value |= ctx->pic_height_in_mbs << 3; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + value = 0x26800000; + value |= ctx->level_idc << 4; + value |= !ctx->baseline_profile << 1; + value |= !!ctx->direct_8x8_inference_flag; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + tegra_vde_writel(vde, 0xF4000001, vde->mbe, 0x80); + tegra_vde_writel(vde, 0x20000000, vde->mbe, 0x80); + tegra_vde_writel(vde, 0xF4000101, vde->mbe, 0x80); + + value = 0x20000000; + value |= ctx->chroma_qp_index_offset << 8; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + err = tegra_vde_setup_mbe_frame_idx(vde, + ctx->dpb_frames_nb - 1, + ctx->pic_order_cnt_type == 0); + if (err) { + dev_err(dev, "MBE frames setup failed %d\n", err); + return err; + } + + tegra_vde_mbe_set_0xa_reg(vde, 0, 0x000009FC); + tegra_vde_mbe_set_0xa_reg(vde, 2, 0x61DEAD00); + tegra_vde_mbe_set_0xa_reg(vde, 4, 0x62DEAD00); + tegra_vde_mbe_set_0xa_reg(vde, 6, 0x63DEAD00); + tegra_vde_mbe_set_0xa_reg(vde, 8, dpb_frames[0].aux_addr); + + value = 0xFC000000; + value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 2; + + if (!ctx->baseline_profile) + value |= !!(dpb_frames[0].flags & FLAG_REFERENCE) << 1; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + err = tegra_vde_wait_mbe(vde); + if (err) { + dev_err(dev, "MBE programming failed %d\n", err); + return err; + } + + return 0; +} + +static void tegra_vde_decode_frame(struct tegra_vde *vde, + unsigned int macroblocks_nb) +{ + reinit_completion(&vde->decode_completion); + + tegra_vde_writel(vde, 0x00000001, vde->bsev, 0x8C); + tegra_vde_writel(vde, 0x20000000 | (macroblocks_nb - 1), + vde->sxe, 0x00); +} + +int tegra_vde_validate_h264_frame(struct device *dev, + struct tegra_vde_h264_frame *frame) +{ + if (frame->frame_num > 0x7FFFFF) { + dev_err(dev, "Bad frame_num %u\n", frame->frame_num); + return -EINVAL; + } + + return 0; +} + +int tegra_vde_validate_h264_ctx(struct device *dev, + struct tegra_vde_h264_decoder_ctx *ctx) +{ + if (ctx->dpb_frames_nb == 0 || ctx->dpb_frames_nb > 17) { + dev_err(dev, "Bad DPB size %u\n", ctx->dpb_frames_nb); + return -EINVAL; + } + + if (ctx->level_idc > 15) { + dev_err(dev, "Bad level value %u\n", ctx->level_idc); + return -EINVAL; + } + + if (ctx->pic_init_qp > 52) { + dev_err(dev, "Bad pic_init_qp value %u\n", ctx->pic_init_qp); + return -EINVAL; + } + + if (ctx->log2_max_pic_order_cnt_lsb > 16) { + dev_err(dev, "Bad log2_max_pic_order_cnt_lsb value %u\n", + ctx->log2_max_pic_order_cnt_lsb); + return -EINVAL; + } + + if (ctx->log2_max_frame_num > 16) { + dev_err(dev, "Bad log2_max_frame_num value %u\n", + ctx->log2_max_frame_num); + return -EINVAL; + } + + if (ctx->chroma_qp_index_offset > 31) { + dev_err(dev, "Bad chroma_qp_index_offset value %u\n", + ctx->chroma_qp_index_offset); + return -EINVAL; + } + + if (ctx->pic_order_cnt_type > 2) { + dev_err(dev, "Bad pic_order_cnt_type value %u\n", + ctx->pic_order_cnt_type); + return -EINVAL; + } + + if (ctx->num_ref_idx_l0_active_minus1 > 15) { + dev_err(dev, "Bad num_ref_idx_l0_active_minus1 value %u\n", + ctx->num_ref_idx_l0_active_minus1); + return -EINVAL; + } + + if (ctx->num_ref_idx_l1_active_minus1 > 15) { + dev_err(dev, "Bad num_ref_idx_l1_active_minus1 value %u\n", + ctx->num_ref_idx_l1_active_minus1); + return -EINVAL; + } + + if (!ctx->pic_width_in_mbs || ctx->pic_width_in_mbs > 127) { + dev_err(dev, "Bad pic_width_in_mbs value %u\n", + ctx->pic_width_in_mbs); + return -EINVAL; + } + + if (!ctx->pic_height_in_mbs || ctx->pic_height_in_mbs > 127) { + dev_err(dev, "Bad pic_height_in_mbs value %u\n", + ctx->pic_height_in_mbs); + return -EINVAL; + } + + return 0; +} + +static int tegra_vde_decode_begin(struct tegra_vde *vde, + struct tegra_vde_h264_decoder_ctx *ctx, + struct tegra_video_frame *dpb_frames, + dma_addr_t bitstream_data_addr, + size_t bitstream_data_size) +{ + struct device *dev = vde->dev; + unsigned int macroblocks_nb; + int err; + + err = mutex_lock_interruptible(&vde->lock); + if (err) + return err; + + err = pm_runtime_resume_and_get(dev); + if (err < 0) + goto unlock; + + /* + * We rely on the VDE registers reset value, otherwise VDE + * causes bus lockup. + */ + err = reset_control_assert(vde->rst_mc); + if (err) { + dev_err(dev, "DEC start: Failed to assert MC reset: %d\n", + err); + goto put_runtime_pm; + } + + err = reset_control_reset(vde->rst); + if (err) { + dev_err(dev, "DEC start: Failed to reset HW: %d\n", err); + goto put_runtime_pm; + } + + err = reset_control_deassert(vde->rst_mc); + if (err) { + dev_err(dev, "DEC start: Failed to deassert MC reset: %d\n", + err); + goto put_runtime_pm; + } + + macroblocks_nb = ctx->pic_width_in_mbs * ctx->pic_height_in_mbs; + + err = tegra_vde_setup_hw_context(vde, ctx, dpb_frames, + bitstream_data_addr, + bitstream_data_size, + macroblocks_nb); + if (err) + goto put_runtime_pm; + + tegra_vde_decode_frame(vde, macroblocks_nb); + + return 0; + +put_runtime_pm: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + +unlock: + mutex_unlock(&vde->lock); + + return err; +} + +static void tegra_vde_decode_abort(struct tegra_vde *vde) +{ + struct device *dev = vde->dev; + int err; + + /* + * At first reset memory client to avoid resetting VDE HW in the + * middle of DMA which could result into memory corruption or hang + * the whole system. + */ + err = reset_control_assert(vde->rst_mc); + if (err) + dev_err(dev, "DEC end: Failed to assert MC reset: %d\n", err); + + err = reset_control_assert(vde->rst); + if (err) + dev_err(dev, "DEC end: Failed to assert HW reset: %d\n", err); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + mutex_unlock(&vde->lock); +} + +static int tegra_vde_decode_end(struct tegra_vde *vde) +{ + unsigned int read_bytes, macroblocks_nb; + struct device *dev = vde->dev; + dma_addr_t bsev_ptr; + long timeout; + int ret; + + timeout = wait_for_completion_interruptible_timeout( + &vde->decode_completion, msecs_to_jiffies(1000)); + if (timeout == 0) { + bsev_ptr = tegra_vde_readl(vde, vde->bsev, 0x10); + macroblocks_nb = tegra_vde_readl(vde, vde->sxe, 0xC8) & 0x1FFF; + read_bytes = bsev_ptr ? bsev_ptr - vde->bitstream_data_addr : 0; + + dev_err(dev, "Decoding failed: read 0x%X bytes, %u macroblocks parsed\n", + read_bytes, macroblocks_nb); + + ret = -EIO; + } else if (timeout < 0) { + ret = timeout; + } else { + ret = 0; + } + + tegra_vde_decode_abort(vde); + + return ret; +} + +int tegra_vde_decode_h264(struct tegra_vde *vde, + struct tegra_vde_h264_decoder_ctx *ctx, + struct tegra_video_frame *dpb_frames, + dma_addr_t bitstream_data_addr, + size_t bitstream_data_size) +{ + int err; + + err = tegra_vde_decode_begin(vde, ctx, dpb_frames, + bitstream_data_addr, + bitstream_data_size); + if (err) + return err; + + return tegra_vde_decode_end(vde); +} diff --git a/drivers/staging/media/tegra-vde/vde.c b/drivers/staging/media/tegra-vde/vde.c index a8f1a024c343..36f5595c0fd8 100644 --- a/drivers/staging/media/tegra-vde/vde.c +++ b/drivers/staging/media/tegra-vde/vde.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -29,38 +28,15 @@ #define CREATE_TRACE_POINTS #include "trace.h" -#define ICMDQUE_WR 0x00 -#define CMDQUE_CONTROL 0x08 -#define INTR_STATUS 0x18 -#define BSE_INT_ENB 0x40 -#define BSE_CONFIG 0x44 - -#define BSE_ICMDQUE_EMPTY BIT(3) -#define BSE_DMA_BUSY BIT(23) - -struct video_frame { - struct dma_buf_attachment *y_dmabuf_attachment; - struct dma_buf_attachment *cb_dmabuf_attachment; - struct dma_buf_attachment *cr_dmabuf_attachment; - struct dma_buf_attachment *aux_dmabuf_attachment; - dma_addr_t y_addr; - dma_addr_t cb_addr; - dma_addr_t cr_addr; - dma_addr_t aux_addr; - u32 frame_num; - u32 flags; -}; - -static void tegra_vde_writel(struct tegra_vde *vde, - u32 value, void __iomem *base, u32 offset) +void tegra_vde_writel(struct tegra_vde *vde, u32 value, + void __iomem *base, u32 offset) { trace_vde_writel(vde, base, offset, value); writel_relaxed(value, base + offset); } -static u32 tegra_vde_readl(struct tegra_vde *vde, - void __iomem *base, u32 offset) +u32 tegra_vde_readl(struct tegra_vde *vde, void __iomem *base, u32 offset) { u32 value = readl_relaxed(base + offset); @@ -69,22 +45,14 @@ static u32 tegra_vde_readl(struct tegra_vde *vde, return value; } -static void tegra_vde_set_bits(struct tegra_vde *vde, - u32 mask, void __iomem *base, u32 offset) +void tegra_vde_set_bits(struct tegra_vde *vde, u32 mask, + void __iomem *base, u32 offset) { u32 value = tegra_vde_readl(vde, base, offset); tegra_vde_writel(vde, value | mask, base, offset); } -static int tegra_vde_wait_mbe(struct tegra_vde *vde) -{ - u32 tmp; - - return readl_relaxed_poll_timeout(vde->mbe + 0x8C, tmp, - (tmp >= 0x10), 1, 100); -} - static int tegra_vde_alloc_bo(struct tegra_vde *vde, struct tegra_vde_bo **ret_bo, enum dma_data_direction dma_dir, @@ -175,412 +143,6 @@ static void tegra_vde_free_bo(struct tegra_vde_bo *bo) kfree(bo); } -static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde, - unsigned int refs_nb, - bool setup_refs) -{ - u32 frame_idx_enb_mask = 0; - u32 value; - unsigned int frame_idx; - unsigned int idx; - int err; - - tegra_vde_writel(vde, 0xD0000000 | (0 << 23), vde->mbe, 0x80); - tegra_vde_writel(vde, 0xD0200000 | (0 << 23), vde->mbe, 0x80); - - err = tegra_vde_wait_mbe(vde); - if (err) - return err; - - if (!setup_refs) - return 0; - - for (idx = 0, frame_idx = 1; idx < refs_nb; idx++, frame_idx++) { - tegra_vde_writel(vde, 0xD0000000 | (frame_idx << 23), - vde->mbe, 0x80); - tegra_vde_writel(vde, 0xD0200000 | (frame_idx << 23), - vde->mbe, 0x80); - - frame_idx_enb_mask |= frame_idx << (6 * (idx % 4)); - - if (idx % 4 == 3 || idx == refs_nb - 1) { - value = 0xC0000000; - value |= (idx >> 2) << 24; - value |= frame_idx_enb_mask; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - err = tegra_vde_wait_mbe(vde); - if (err) - return err; - - frame_idx_enb_mask = 0; - } - } - - return 0; -} - -static void tegra_vde_mbe_set_0xa_reg(struct tegra_vde *vde, int reg, u32 val) -{ - tegra_vde_writel(vde, 0xA0000000 | (reg << 24) | (val & 0xFFFF), - vde->mbe, 0x80); - tegra_vde_writel(vde, 0xA0000000 | ((reg + 1) << 24) | (val >> 16), - vde->mbe, 0x80); -} - -static int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma) -{ - struct device *dev = vde->miscdev.parent; - u32 value; - int err; - - err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, - !(value & BIT(2)), 1, 100); - if (err) { - dev_err(dev, "BSEV unknown bit timeout\n"); - return err; - } - - err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, - (value & BSE_ICMDQUE_EMPTY), 1, 100); - if (err) { - dev_err(dev, "BSEV ICMDQUE flush timeout\n"); - return err; - } - - if (!wait_dma) - return 0; - - err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, - !(value & BSE_DMA_BUSY), 1, 100); - if (err) { - dev_err(dev, "BSEV DMA timeout\n"); - return err; - } - - return 0; -} - -static int tegra_vde_push_to_bsev_icmdqueue(struct tegra_vde *vde, - u32 value, bool wait_dma) -{ - tegra_vde_writel(vde, value, vde->bsev, ICMDQUE_WR); - - return tegra_vde_wait_bsev(vde, wait_dma); -} - -static void tegra_vde_setup_frameid(struct tegra_vde *vde, - struct video_frame *frame, - unsigned int frameid, - u32 mbs_width, u32 mbs_height) -{ - u32 y_addr = frame ? frame->y_addr : 0x6CDEAD00; - u32 cb_addr = frame ? frame->cb_addr : 0x6CDEAD00; - u32 cr_addr = frame ? frame->cr_addr : 0x6CDEAD00; - u32 value1 = frame ? ((mbs_width << 16) | mbs_height) : 0; - u32 value2 = frame ? ((((mbs_width + 1) >> 1) << 6) | 1) : 0; - - tegra_vde_writel(vde, y_addr >> 8, vde->frameid, 0x000 + frameid * 4); - tegra_vde_writel(vde, cb_addr >> 8, vde->frameid, 0x100 + frameid * 4); - tegra_vde_writel(vde, cr_addr >> 8, vde->frameid, 0x180 + frameid * 4); - tegra_vde_writel(vde, value1, vde->frameid, 0x080 + frameid * 4); - tegra_vde_writel(vde, value2, vde->frameid, 0x280 + frameid * 4); -} - -static void tegra_setup_frameidx(struct tegra_vde *vde, - struct video_frame *frames, - unsigned int frames_nb, - u32 mbs_width, u32 mbs_height) -{ - unsigned int idx; - - for (idx = 0; idx < frames_nb; idx++) - tegra_vde_setup_frameid(vde, &frames[idx], idx, - mbs_width, mbs_height); - - for (; idx < 17; idx++) - tegra_vde_setup_frameid(vde, NULL, idx, 0, 0); -} - -static void tegra_vde_setup_iram_entry(struct tegra_vde *vde, - unsigned int table, - unsigned int row, - u32 value1, u32 value2) -{ - u32 *iram_tables = vde->iram; - - trace_vde_setup_iram_entry(table, row, value1, value2); - - iram_tables[0x20 * table + row * 2] = value1; - iram_tables[0x20 * table + row * 2 + 1] = value2; -} - -static void tegra_vde_setup_iram_tables(struct tegra_vde *vde, - struct video_frame *dpb_frames, - unsigned int ref_frames_nb, - unsigned int with_earlier_poc_nb) -{ - struct video_frame *frame; - u32 value, aux_addr; - int with_later_poc_nb; - unsigned int i, k; - - trace_vde_ref_l0(dpb_frames[0].frame_num); - - for (i = 0; i < 16; i++) { - if (i < ref_frames_nb) { - frame = &dpb_frames[i + 1]; - - aux_addr = frame->aux_addr; - - value = (i + 1) << 26; - value |= !(frame->flags & FLAG_B_FRAME) << 25; - value |= 1 << 24; - value |= frame->frame_num; - } else { - aux_addr = 0x6ADEAD00; - value = 0x3f; - } - - tegra_vde_setup_iram_entry(vde, 0, i, value, aux_addr); - tegra_vde_setup_iram_entry(vde, 1, i, value, aux_addr); - tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); - tegra_vde_setup_iram_entry(vde, 3, i, value, aux_addr); - } - - if (!(dpb_frames[0].flags & FLAG_B_FRAME)) - return; - - if (with_earlier_poc_nb >= ref_frames_nb) - return; - - with_later_poc_nb = ref_frames_nb - with_earlier_poc_nb; - - trace_vde_ref_l1(with_later_poc_nb, with_earlier_poc_nb); - - for (i = 0, k = with_earlier_poc_nb; i < with_later_poc_nb; i++, k++) { - frame = &dpb_frames[k + 1]; - - aux_addr = frame->aux_addr; - - value = (k + 1) << 26; - value |= !(frame->flags & FLAG_B_FRAME) << 25; - value |= 1 << 24; - value |= frame->frame_num; - - tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); - } - - for (k = 0; i < ref_frames_nb; i++, k++) { - frame = &dpb_frames[k + 1]; - - aux_addr = frame->aux_addr; - - value = (k + 1) << 26; - value |= !(frame->flags & FLAG_B_FRAME) << 25; - value |= 1 << 24; - value |= frame->frame_num; - - tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); - } -} - -static int tegra_vde_setup_hw_context(struct tegra_vde *vde, - struct tegra_vde_h264_decoder_ctx *ctx, - struct video_frame *dpb_frames, - dma_addr_t bitstream_data_addr, - size_t bitstream_data_size, - unsigned int macroblocks_nb) -{ - struct device *dev = vde->miscdev.parent; - u32 value; - int err; - - tegra_vde_set_bits(vde, 0x000A, vde->sxe, 0xF0); - tegra_vde_set_bits(vde, 0x000B, vde->bsev, CMDQUE_CONTROL); - tegra_vde_set_bits(vde, 0x8002, vde->mbe, 0x50); - tegra_vde_set_bits(vde, 0x000A, vde->mbe, 0xA0); - tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x14); - tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x28); - tegra_vde_set_bits(vde, 0x0A00, vde->mce, 0x08); - tegra_vde_set_bits(vde, 0x000A, vde->tfe, 0x00); - tegra_vde_set_bits(vde, 0x0005, vde->vdma, 0x04); - - tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x1C); - tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x00); - tegra_vde_writel(vde, 0x00000007, vde->vdma, 0x04); - tegra_vde_writel(vde, 0x00000007, vde->frameid, 0x200); - tegra_vde_writel(vde, 0x00000005, vde->tfe, 0x04); - tegra_vde_writel(vde, 0x00000000, vde->mbe, 0x84); - tegra_vde_writel(vde, 0x00000010, vde->sxe, 0x08); - tegra_vde_writel(vde, 0x00000150, vde->sxe, 0x54); - tegra_vde_writel(vde, 0x0000054C, vde->sxe, 0x58); - tegra_vde_writel(vde, 0x00000E34, vde->sxe, 0x5C); - tegra_vde_writel(vde, 0x063C063C, vde->mce, 0x10); - tegra_vde_writel(vde, 0x0003FC00, vde->bsev, INTR_STATUS); - tegra_vde_writel(vde, 0x0000150D, vde->bsev, BSE_CONFIG); - tegra_vde_writel(vde, 0x00000100, vde->bsev, BSE_INT_ENB); - tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x98); - tegra_vde_writel(vde, 0x00000060, vde->bsev, 0x9C); - - memset(vde->iram + 128, 0, macroblocks_nb / 2); - - tegra_setup_frameidx(vde, dpb_frames, ctx->dpb_frames_nb, - ctx->pic_width_in_mbs, ctx->pic_height_in_mbs); - - tegra_vde_setup_iram_tables(vde, dpb_frames, - ctx->dpb_frames_nb - 1, - ctx->dpb_ref_frames_with_earlier_poc_nb); - - /* - * The IRAM mapping is write-combine, ensure that CPU buffers have - * been flushed at this point. - */ - wmb(); - - tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x8C); - tegra_vde_writel(vde, bitstream_data_addr + bitstream_data_size, - vde->bsev, 0x54); - - value = ctx->pic_width_in_mbs << 11 | ctx->pic_height_in_mbs << 3; - - tegra_vde_writel(vde, value, vde->bsev, 0x88); - - err = tegra_vde_wait_bsev(vde, false); - if (err) - return err; - - err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x800003FC, false); - if (err) - return err; - - value = 0x01500000; - value |= ((vde->iram_lists_addr + 512) >> 2) & 0xFFFF; - - err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); - if (err) - return err; - - err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x840F054C, false); - if (err) - return err; - - err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x80000080, false); - if (err) - return err; - - value = 0x0E340000 | ((vde->iram_lists_addr >> 2) & 0xFFFF); - - err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); - if (err) - return err; - - value = 0x00800005; - value |= ctx->pic_width_in_mbs << 11; - value |= ctx->pic_height_in_mbs << 3; - - tegra_vde_writel(vde, value, vde->sxe, 0x10); - - value = !ctx->baseline_profile << 17; - value |= ctx->level_idc << 13; - value |= ctx->log2_max_pic_order_cnt_lsb << 7; - value |= ctx->pic_order_cnt_type << 5; - value |= ctx->log2_max_frame_num; - - tegra_vde_writel(vde, value, vde->sxe, 0x40); - - value = ctx->pic_init_qp << 25; - value |= !!(ctx->deblocking_filter_control_present_flag) << 2; - value |= !!ctx->pic_order_present_flag; - - tegra_vde_writel(vde, value, vde->sxe, 0x44); - - value = ctx->chroma_qp_index_offset; - value |= ctx->num_ref_idx_l0_active_minus1 << 5; - value |= ctx->num_ref_idx_l1_active_minus1 << 10; - value |= !!ctx->constrained_intra_pred_flag << 15; - - tegra_vde_writel(vde, value, vde->sxe, 0x48); - - value = 0x0C000000; - value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 24; - - tegra_vde_writel(vde, value, vde->sxe, 0x4C); - - value = 0x03800000; - value |= bitstream_data_size & GENMASK(19, 15); - - tegra_vde_writel(vde, value, vde->sxe, 0x68); - - tegra_vde_writel(vde, bitstream_data_addr, vde->sxe, 0x6C); - - if (vde->soc->supports_ref_pic_marking) - tegra_vde_writel(vde, vde->secure_bo->dma_addr, vde->sxe, 0x7c); - - value = 0x10000005; - value |= ctx->pic_width_in_mbs << 11; - value |= ctx->pic_height_in_mbs << 3; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - value = 0x26800000; - value |= ctx->level_idc << 4; - value |= !ctx->baseline_profile << 1; - value |= !!ctx->direct_8x8_inference_flag; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - tegra_vde_writel(vde, 0xF4000001, vde->mbe, 0x80); - tegra_vde_writel(vde, 0x20000000, vde->mbe, 0x80); - tegra_vde_writel(vde, 0xF4000101, vde->mbe, 0x80); - - value = 0x20000000; - value |= ctx->chroma_qp_index_offset << 8; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - err = tegra_vde_setup_mbe_frame_idx(vde, - ctx->dpb_frames_nb - 1, - ctx->pic_order_cnt_type == 0); - if (err) { - dev_err(dev, "MBE frames setup failed %d\n", err); - return err; - } - - tegra_vde_mbe_set_0xa_reg(vde, 0, 0x000009FC); - tegra_vde_mbe_set_0xa_reg(vde, 2, 0x61DEAD00); - tegra_vde_mbe_set_0xa_reg(vde, 4, 0x62DEAD00); - tegra_vde_mbe_set_0xa_reg(vde, 6, 0x63DEAD00); - tegra_vde_mbe_set_0xa_reg(vde, 8, dpb_frames[0].aux_addr); - - value = 0xFC000000; - value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 2; - - if (!ctx->baseline_profile) - value |= !!(dpb_frames[0].flags & FLAG_REFERENCE) << 1; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - err = tegra_vde_wait_mbe(vde); - if (err) { - dev_err(dev, "MBE programming failed %d\n", err); - return err; - } - - return 0; -} - -static void tegra_vde_decode_frame(struct tegra_vde *vde, - unsigned int macroblocks_nb) -{ - reinit_completion(&vde->decode_completion); - - tegra_vde_writel(vde, 0x00000001, vde->bsev, 0x8C); - tegra_vde_writel(vde, 0x20000000 | (macroblocks_nb - 1), - vde->sxe, 0x00); -} - static int tegra_vde_attach_dmabuf(struct tegra_vde *vde, int fd, unsigned long offset, @@ -631,7 +193,7 @@ err_put: } static int tegra_vde_attach_dmabufs_to_frame(struct tegra_vde *vde, - struct video_frame *frame, + struct tegra_video_frame *frame, struct tegra_vde_h264_frame *src, enum dma_data_direction dma_dir, bool baseline_profile, @@ -689,7 +251,7 @@ err_release_y: } static void tegra_vde_release_frame_dmabufs(struct tegra_vde *vde, - struct video_frame *frame, + struct tegra_video_frame *frame, enum dma_data_direction dma_dir, bool baseline_profile, bool release) @@ -703,106 +265,22 @@ static void tegra_vde_release_frame_dmabufs(struct tegra_vde *vde, tegra_vde_dmabuf_cache_unmap(vde, frame->y_dmabuf_attachment, release); } -static int tegra_vde_validate_frame(struct device *dev, - struct tegra_vde_h264_frame *frame) -{ - if (frame->frame_num > 0x7FFFFF) { - dev_err(dev, "Bad frame_num %u\n", frame->frame_num); - return -EINVAL; - } - - return 0; -} - -static int tegra_vde_validate_h264_ctx(struct device *dev, - struct tegra_vde_h264_decoder_ctx *ctx) -{ - if (ctx->dpb_frames_nb == 0 || ctx->dpb_frames_nb > 17) { - dev_err(dev, "Bad DPB size %u\n", ctx->dpb_frames_nb); - return -EINVAL; - } - - if (ctx->level_idc > 15) { - dev_err(dev, "Bad level value %u\n", ctx->level_idc); - return -EINVAL; - } - - if (ctx->pic_init_qp > 52) { - dev_err(dev, "Bad pic_init_qp value %u\n", ctx->pic_init_qp); - return -EINVAL; - } - - if (ctx->log2_max_pic_order_cnt_lsb > 16) { - dev_err(dev, "Bad log2_max_pic_order_cnt_lsb value %u\n", - ctx->log2_max_pic_order_cnt_lsb); - return -EINVAL; - } - - if (ctx->log2_max_frame_num > 16) { - dev_err(dev, "Bad log2_max_frame_num value %u\n", - ctx->log2_max_frame_num); - return -EINVAL; - } - - if (ctx->chroma_qp_index_offset > 31) { - dev_err(dev, "Bad chroma_qp_index_offset value %u\n", - ctx->chroma_qp_index_offset); - return -EINVAL; - } - - if (ctx->pic_order_cnt_type > 2) { - dev_err(dev, "Bad pic_order_cnt_type value %u\n", - ctx->pic_order_cnt_type); - return -EINVAL; - } - - if (ctx->num_ref_idx_l0_active_minus1 > 15) { - dev_err(dev, "Bad num_ref_idx_l0_active_minus1 value %u\n", - ctx->num_ref_idx_l0_active_minus1); - return -EINVAL; - } - - if (ctx->num_ref_idx_l1_active_minus1 > 15) { - dev_err(dev, "Bad num_ref_idx_l1_active_minus1 value %u\n", - ctx->num_ref_idx_l1_active_minus1); - return -EINVAL; - } - - if (!ctx->pic_width_in_mbs || ctx->pic_width_in_mbs > 127) { - dev_err(dev, "Bad pic_width_in_mbs value %u\n", - ctx->pic_width_in_mbs); - return -EINVAL; - } - - if (!ctx->pic_height_in_mbs || ctx->pic_height_in_mbs > 127) { - dev_err(dev, "Bad pic_height_in_mbs value %u\n", - ctx->pic_height_in_mbs); - return -EINVAL; - } - - return 0; -} - static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, unsigned long vaddr) { + struct dma_buf_attachment *bitstream_data_dmabuf_attachment; + struct tegra_vde_h264_frame __user *frames_user; + size_t bitstream_data_size, lsize, csize; struct device *dev = vde->miscdev.parent; struct tegra_vde_h264_decoder_ctx ctx; + struct tegra_video_frame *dpb_frames; struct tegra_vde_h264_frame *frames; - struct tegra_vde_h264_frame __user *frames_user; - struct video_frame *dpb_frames; - struct dma_buf_attachment *bitstream_data_dmabuf_attachment; enum dma_data_direction dma_dir; dma_addr_t bitstream_data_addr; - dma_addr_t bsev_ptr; - size_t lsize, csize; - size_t bitstream_data_size; unsigned int macroblocks_nb; - unsigned int read_bytes; unsigned int cstride; unsigned int i; - long timeout; - int ret, err; + int ret; if (copy_from_user(&ctx, (void __user *)vaddr, sizeof(ctx))) return -EFAULT; @@ -848,7 +326,7 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, lsize = macroblocks_nb * 256; for (i = 0; i < ctx.dpb_frames_nb; i++) { - ret = tegra_vde_validate_frame(dev, &frames[i]); + ret = tegra_vde_validate_h264_frame(dev, &frames[i]); if (ret) goto release_dpb_frames; @@ -865,81 +343,8 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, goto release_dpb_frames; } - ret = mutex_lock_interruptible(&vde->lock); - if (ret) - goto release_dpb_frames; - - ret = pm_runtime_resume_and_get(dev); - if (ret < 0) - goto unlock; - - /* - * We rely on the VDE registers reset value, otherwise VDE - * causes bus lockup. - */ - ret = reset_control_assert(vde->rst_mc); - if (ret) { - dev_err(dev, "DEC start: Failed to assert MC reset: %d\n", - ret); - goto put_runtime_pm; - } - - ret = reset_control_reset(vde->rst); - if (ret) { - dev_err(dev, "DEC start: Failed to reset HW: %d\n", ret); - goto put_runtime_pm; - } - - ret = reset_control_deassert(vde->rst_mc); - if (ret) { - dev_err(dev, "DEC start: Failed to deassert MC reset: %d\n", - ret); - goto put_runtime_pm; - } - - ret = tegra_vde_setup_hw_context(vde, &ctx, dpb_frames, - bitstream_data_addr, - bitstream_data_size, - macroblocks_nb); - if (ret) - goto put_runtime_pm; - - tegra_vde_decode_frame(vde, macroblocks_nb); - - timeout = wait_for_completion_interruptible_timeout( - &vde->decode_completion, msecs_to_jiffies(1000)); - if (timeout == 0) { - bsev_ptr = tegra_vde_readl(vde, vde->bsev, 0x10); - macroblocks_nb = tegra_vde_readl(vde, vde->sxe, 0xC8) & 0x1FFF; - read_bytes = bsev_ptr ? bsev_ptr - bitstream_data_addr : 0; - - dev_err(dev, "Decoding failed: read 0x%X bytes, %u macroblocks parsed\n", - read_bytes, macroblocks_nb); - - ret = -EIO; - } else if (timeout < 0) { - ret = timeout; - } - - /* - * At first reset memory client to avoid resetting VDE HW in the - * middle of DMA which could result into memory corruption or hang - * the whole system. - */ - err = reset_control_assert(vde->rst_mc); - if (err) - dev_err(dev, "DEC end: Failed to assert MC reset: %d\n", err); - - err = reset_control_assert(vde->rst); - if (err) - dev_err(dev, "DEC end: Failed to assert HW reset: %d\n", err); - -put_runtime_pm: - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - -unlock: - mutex_unlock(&vde->lock); + ret = tegra_vde_decode_h264(vde, &ctx, dpb_frames, + bitstream_data_addr, bitstream_data_size); release_dpb_frames: while (i--) { @@ -1088,6 +493,7 @@ static int tegra_vde_probe(struct platform_device *pdev) platform_set_drvdata(pdev, vde); vde->soc = of_device_get_match_data(&pdev->dev); + vde->dev = dev; vde->sxe = devm_platform_ioremap_resource_byname(pdev, "sxe"); if (IS_ERR(vde->sxe)) diff --git a/drivers/staging/media/tegra-vde/vde.h b/drivers/staging/media/tegra-vde/vde.h index bbd42b8d9991..8ba6a71e3e40 100644 --- a/drivers/staging/media/tegra-vde/vde.h +++ b/drivers/staging/media/tegra-vde/vde.h @@ -16,6 +16,15 @@ #include #include +#define ICMDQUE_WR 0x00 +#define CMDQUE_CONTROL 0x08 +#define INTR_STATUS 0x18 +#define BSE_INT_ENB 0x40 +#define BSE_CONFIG 0x44 + +#define BSE_ICMDQUE_EMPTY BIT(3) +#define BSE_DMA_BUSY BIT(23) + struct clk; struct dma_buf; struct gen_pool; @@ -23,6 +32,21 @@ struct iommu_group; struct iommu_domain; struct reset_control; struct dma_buf_attachment; +struct tegra_vde_h264_frame; +struct tegra_vde_h264_decoder_ctx; + +struct tegra_video_frame { + struct dma_buf_attachment *y_dmabuf_attachment; + struct dma_buf_attachment *cb_dmabuf_attachment; + struct dma_buf_attachment *cr_dmabuf_attachment; + struct dma_buf_attachment *aux_dmabuf_attachment; + dma_addr_t y_addr; + dma_addr_t cb_addr; + dma_addr_t cr_addr; + dma_addr_t aux_addr; + u32 frame_num; + u32 flags; +}; struct tegra_vde_soc { bool supports_ref_pic_marking; @@ -50,6 +74,7 @@ struct tegra_vde { void __iomem *ppb; void __iomem *vdma; void __iomem *frameid; + struct device *dev; struct mutex lock; struct mutex map_lock; struct list_head map_list; @@ -66,10 +91,27 @@ struct tegra_vde { struct iova *iova_resv_last_page; const struct tegra_vde_soc *soc; struct tegra_vde_bo *secure_bo; + dma_addr_t bitstream_data_addr; dma_addr_t iram_lists_addr; u32 *iram; }; +void tegra_vde_writel(struct tegra_vde *vde, u32 value, void __iomem *base, + u32 offset); +u32 tegra_vde_readl(struct tegra_vde *vde, void __iomem *base, u32 offset); +void tegra_vde_set_bits(struct tegra_vde *vde, u32 mask, void __iomem *base, + u32 offset); + +int tegra_vde_validate_h264_frame(struct device *dev, + struct tegra_vde_h264_frame *frame); +int tegra_vde_validate_h264_ctx(struct device *dev, + struct tegra_vde_h264_decoder_ctx *ctx); +int tegra_vde_decode_h264(struct tegra_vde *vde, + struct tegra_vde_h264_decoder_ctx *ctx, + struct tegra_video_frame *dpb_frames, + dma_addr_t bitstream_data_addr, + size_t bitstream_data_size); + int tegra_vde_iommu_init(struct tegra_vde *vde); void tegra_vde_iommu_deinit(struct tegra_vde *vde); int tegra_vde_iommu_map(struct tegra_vde *vde, -- cgit v1.2.3 From 24d5d2bafb4609e787d6f8454c5df80734499987 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 20 Feb 2022 21:46:18 +0100 Subject: media: staging: tegra-vde: Support V4L stateless video decoder API Expose Tegra video decoder as a generic V4L M2M stateless video decoder. Signed-off-by: Dmitry Osipenko Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/tegra-vde/Kconfig | 7 + drivers/staging/media/tegra-vde/Makefile | 2 +- drivers/staging/media/tegra-vde/h264.c | 304 ++++++++- drivers/staging/media/tegra-vde/v4l2.c | 1018 ++++++++++++++++++++++++++++++ drivers/staging/media/tegra-vde/vde.c | 74 ++- drivers/staging/media/tegra-vde/vde.h | 86 +++ 6 files changed, 1483 insertions(+), 8 deletions(-) create mode 100644 drivers/staging/media/tegra-vde/v4l2.c (limited to 'drivers/staging') diff --git a/drivers/staging/media/tegra-vde/Kconfig b/drivers/staging/media/tegra-vde/Kconfig index 0dc78afd09e0..07dbc1f44ca8 100644 --- a/drivers/staging/media/tegra-vde/Kconfig +++ b/drivers/staging/media/tegra-vde/Kconfig @@ -2,9 +2,16 @@ config TEGRA_VDE tristate "NVIDIA Tegra Video Decoder Engine driver" depends on ARCH_TEGRA || COMPILE_TEST + depends on VIDEO_DEV && VIDEO_V4L2 select DMA_SHARED_BUFFER select IOMMU_IOVA + select MEDIA_CONTROLLER + select MEDIA_CONTROLLER_REQUEST_API select SRAM + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_DMA_SG + select V4L2_H264 + select V4L2_MEM2MEM_DEV help Say Y here to enable support for the NVIDIA Tegra video decoder driver. diff --git a/drivers/staging/media/tegra-vde/Makefile b/drivers/staging/media/tegra-vde/Makefile index 43525b08b3b0..1758aa201baa 100644 --- a/drivers/staging/media/tegra-vde/Makefile +++ b/drivers/staging/media/tegra-vde/Makefile @@ -1,3 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -tegra-vde-y := vde.o iommu.o dmabuf-cache.o h264.o +tegra-vde-y := vde.o iommu.o dmabuf-cache.o h264.o v4l2.o obj-$(CONFIG_TEGRA_VDE) += tegra-vde.o diff --git a/drivers/staging/media/tegra-vde/h264.c b/drivers/staging/media/tegra-vde/h264.c index 03faa705bf71..cbf27f0cfdb1 100644 --- a/drivers/staging/media/tegra-vde/h264.c +++ b/drivers/staging/media/tegra-vde/h264.c @@ -11,10 +11,18 @@ #include #include +#include + #include "trace.h" #include "uapi.h" #include "vde.h" +struct h264_reflists { + u8 p[V4L2_H264_NUM_DPB_ENTRIES]; + u8 b0[V4L2_H264_NUM_DPB_ENTRIES]; + u8 b1[V4L2_H264_NUM_DPB_ENTRIES]; +}; + static int tegra_vde_wait_mbe(struct tegra_vde *vde) { u32 tmp; @@ -125,8 +133,8 @@ static void tegra_vde_setup_frameid(struct tegra_vde *vde, u32 y_addr = frame ? frame->y_addr : 0x6CDEAD00; u32 cb_addr = frame ? frame->cb_addr : 0x6CDEAD00; u32 cr_addr = frame ? frame->cr_addr : 0x6CDEAD00; - u32 value1 = frame ? ((mbs_width << 16) | mbs_height) : 0; - u32 value2 = frame ? ((((mbs_width + 1) >> 1) << 6) | 1) : 0; + u32 value1 = frame ? ((frame->luma_atoms_pitch << 16) | mbs_height) : 0; + u32 value2 = frame ? ((frame->chroma_atoms_pitch << 6) | 1) : 0; tegra_vde_writel(vde, y_addr >> 8, vde->frameid, 0x000 + frameid * 4); tegra_vde_writel(vde, cb_addr >> 8, vde->frameid, 0x100 + frameid * 4); @@ -645,3 +653,295 @@ int tegra_vde_decode_h264(struct tegra_vde *vde, return tegra_vde_decode_end(vde); } + +static struct vb2_buffer *get_ref_buf(struct tegra_ctx *ctx, + struct vb2_v4l2_buffer *dst, + unsigned int dpb_idx) +{ + const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + int buf_idx = -1; + + if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + buf_idx = vb2_find_timestamp(cap_q, + dpb[dpb_idx].reference_ts, 0); + + /* + * If a DPB entry is unused or invalid, address of current destination + * buffer is returned. + */ + if (buf_idx < 0) + return &dst->vb2_buf; + + return vb2_get_buffer(cap_q, buf_idx); +} + +static int tegra_vde_validate_vb_size(struct tegra_ctx *ctx, + struct vb2_buffer *vb, + unsigned int plane_id, + size_t min_size) +{ + u64 offset = vb->planes[plane_id].data_offset; + struct device *dev = ctx->vde->dev; + + if (offset + min_size > vb2_plane_size(vb, plane_id)) { + dev_err(dev, "Too small plane[%u] size %lu @0x%llX, should be at least %zu\n", + plane_id, vb2_plane_size(vb, plane_id), offset, min_size); + return -EINVAL; + } + + return 0; +} + +static int tegra_vde_h264_setup_frame(struct tegra_ctx *ctx, + struct tegra_vde_h264_decoder_ctx *h264, + struct v4l2_h264_reflist_builder *b, + struct vb2_buffer *vb, + unsigned int ref_id, + unsigned int id) +{ + struct v4l2_pix_format_mplane *pixfmt = &ctx->decoded_fmt.fmt.pix_mp; + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); + struct tegra_ctx_h264 *h = &ctx->h264; + struct tegra_vde *vde = ctx->vde; + struct device *dev = vde->dev; + unsigned int cstride, lstride; + unsigned int flags = 0; + size_t lsize, csize; + int err, frame_num; + + lsize = h264->pic_width_in_mbs * 16 * h264->pic_height_in_mbs * 16; + csize = h264->pic_width_in_mbs * 8 * h264->pic_height_in_mbs * 8; + lstride = pixfmt->plane_fmt[0].bytesperline; + cstride = pixfmt->plane_fmt[1].bytesperline; + + err = tegra_vde_validate_vb_size(ctx, vb, 0, lsize); + if (err) + return err; + + err = tegra_vde_validate_vb_size(ctx, vb, 1, csize); + if (err) + return err; + + err = tegra_vde_validate_vb_size(ctx, vb, 2, csize); + if (err) + return err; + + if (!tb->aux || tb->aux->size < csize) { + dev_err(dev, "Too small aux size %zd, should be at least %zu\n", + tb->aux ? tb->aux->size : -1, csize); + return -EINVAL; + } + + if (id == 0) { + frame_num = h->decode_params->frame_num; + + if (h->decode_params->nal_ref_idc) + flags |= FLAG_REFERENCE; + } else { + frame_num = b->refs[ref_id].frame_num; + } + + if (tb->b_frame) + flags |= FLAG_B_FRAME; + + vde->frames[id].flags = flags; + vde->frames[id].y_addr = tb->dma_addr[0]; + vde->frames[id].cb_addr = tb->dma_addr[1]; + vde->frames[id].cr_addr = tb->dma_addr[2]; + vde->frames[id].aux_addr = tb->aux->dma_addr; + vde->frames[id].frame_num = frame_num & 0x7fffff; + vde->frames[id].luma_atoms_pitch = lstride / VDE_ATOM; + vde->frames[id].chroma_atoms_pitch = cstride / VDE_ATOM; + + return 0; +} + +static int tegra_vde_h264_setup_frames(struct tegra_ctx *ctx, + struct tegra_vde_h264_decoder_ctx *h264) +{ + struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct vb2_v4l2_buffer *dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(&dst->vb2_buf); + struct tegra_ctx_h264 *h = &ctx->h264; + struct v4l2_h264_reflist_builder b; + struct h264_reflists reflists; + struct vb2_buffer *ref; + unsigned int i; + u8 *dpb_id; + int err; + + /* + * Tegra hardware requires information about frame's type, assuming + * that frame consists of the same type slices. Userspace must tag + * frame's type appropriately. + * + * Decoding of a non-uniform frames isn't supported by hardware and + * require software preprocessing that we don't implement. Decoding + * is expected to fail in this case. Such video streams are rare in + * practice, so not a big deal. + * + * If userspace doesn't tell us frame's type, then we will try decode + * as-is. + */ + v4l2_m2m_buf_copy_metadata(src, dst, true); + + if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) + tb->b_frame = true; + else + tb->b_frame = false; + + err = tegra_vde_h264_setup_frame(ctx, h264, NULL, &dst->vb2_buf, 0, + h264->dpb_frames_nb++); + if (err) + return err; + + if (!(h->decode_params->flags & (V4L2_H264_DECODE_PARAM_FLAG_PFRAME | + V4L2_H264_DECODE_PARAM_FLAG_BFRAME))) + return 0; + + v4l2_h264_init_reflist_builder(&b, h->decode_params, h->sps, dpb); + + if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) { + v4l2_h264_build_b_ref_lists(&b, reflists.b0, reflists.b1); + dpb_id = reflists.b0; + } else { + v4l2_h264_build_p_ref_list(&b, reflists.p); + dpb_id = reflists.p; + } + + for (i = 0; i < b.num_valid; i++) { + ref = get_ref_buf(ctx, dst, dpb_id[i]); + + err = tegra_vde_h264_setup_frame(ctx, h264, &b, ref, dpb_id[i], + h264->dpb_frames_nb++); + if (err) + return err; + + if (b.refs[dpb_id[i]].pic_order_count < b.cur_pic_order_count) + h264->dpb_ref_frames_with_earlier_poc_nb++; + } + + return 0; +} + +static unsigned int to_tegra_vde_h264_level_idc(unsigned int level_idc) +{ + switch (level_idc) { + case 11: + return 2; + case 12: + return 3; + case 13: + return 4; + case 20: + return 5; + case 21: + return 6; + case 22: + return 7; + case 30: + return 8; + case 31: + return 9; + case 32: + return 10; + case 40: + return 11; + case 41: + return 12; + case 42: + return 13; + case 50: + return 14; + default: + break; + } + + return 15; +} + +static int tegra_vde_h264_setup_context(struct tegra_ctx *ctx, + struct tegra_vde_h264_decoder_ctx *h264) +{ + struct tegra_ctx_h264 *h = &ctx->h264; + struct tegra_vde *vde = ctx->vde; + struct device *dev = vde->dev; + int err; + + memset(h264, 0, sizeof(*h264)); + memset(vde->frames, 0, sizeof(vde->frames)); + + tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_SPS); + tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_PPS); + + /* CABAC unsupported by hardware, requires software preprocessing */ + if (h->pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) + return -EOPNOTSUPP; + + if (h->sps->profile_idc == 66) + h264->baseline_profile = 1; + + if (h->sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) + h264->direct_8x8_inference_flag = 1; + + if (h->pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) + h264->constrained_intra_pred_flag = 1; + + if (h->pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) + h264->deblocking_filter_control_present_flag = 1; + + if (h->pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT) + h264->pic_order_present_flag = 1; + + h264->level_idc = to_tegra_vde_h264_level_idc(h->sps->level_idc); + h264->log2_max_pic_order_cnt_lsb = h->sps->log2_max_pic_order_cnt_lsb_minus4 + 4; + h264->log2_max_frame_num = h->sps->log2_max_frame_num_minus4 + 4; + h264->pic_order_cnt_type = h->sps->pic_order_cnt_type; + h264->pic_width_in_mbs = h->sps->pic_width_in_mbs_minus1 + 1; + h264->pic_height_in_mbs = h->sps->pic_height_in_map_units_minus1 + 1; + + h264->num_ref_idx_l0_active_minus1 = h->pps->num_ref_idx_l0_default_active_minus1; + h264->num_ref_idx_l1_active_minus1 = h->pps->num_ref_idx_l1_default_active_minus1; + h264->chroma_qp_index_offset = h->pps->chroma_qp_index_offset & 0x1f; + h264->pic_init_qp = h->pps->pic_init_qp_minus26 + 26; + + err = tegra_vde_h264_setup_frames(ctx, h264); + if (err) + return err; + + err = tegra_vde_validate_h264_ctx(dev, h264); + if (err) + return err; + + return 0; +} + +int tegra_vde_h264_decode_run(struct tegra_ctx *ctx) +{ + struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct tegra_m2m_buffer *bitstream = vb_to_tegra_buf(&src->vb2_buf); + size_t bitstream_size = vb2_get_plane_payload(&src->vb2_buf, 0); + struct tegra_vde_h264_decoder_ctx h264; + struct tegra_vde *vde = ctx->vde; + int err; + + err = tegra_vde_h264_setup_context(ctx, &h264); + if (err) + return err; + + err = tegra_vde_decode_begin(vde, &h264, vde->frames, + bitstream->dma_addr[0], + bitstream_size); + if (err) + return err; + + return 0; +} + +int tegra_vde_h264_decode_wait(struct tegra_ctx *ctx) +{ + return tegra_vde_decode_end(ctx->vde); +} diff --git a/drivers/staging/media/tegra-vde/v4l2.c b/drivers/staging/media/tegra-vde/v4l2.c new file mode 100644 index 000000000000..bd8c207d5b54 --- /dev/null +++ b/drivers/staging/media/tegra-vde/v4l2.c @@ -0,0 +1,1018 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2019-2022 Dmitry Osipenko + * + * Based on Cedrus driver by Bootlin. + * Copyright (C) 2016 Florent Revest + * Copyright (C) 2018 Paul Kocialkowski + * + * Based on Rockchip driver by Collabora. + * Copyright (C) 2019 Boris Brezillon + */ + +#include +#include + +#include "vde.h" + +static const struct v4l2_ctrl_config ctrl_cfgs[] = { + { .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, }, + { .id = V4L2_CID_STATELESS_H264_SPS, }, + { .id = V4L2_CID_STATELESS_H264_PPS, }, + { + .id = V4L2_CID_STATELESS_H264_DECODE_MODE, + .min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + }, + { + .id = V4L2_CID_STATELESS_H264_START_CODE, + .min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, + .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + }, +}; + +static inline struct tegra_ctx *fh_to_tegra_ctx(struct v4l2_fh *fh) +{ + return container_of(fh, struct tegra_ctx, fh); +} + +static void tegra_set_control_data(struct tegra_ctx *ctx, void *data, u32 id) +{ + switch (id) { + case V4L2_CID_STATELESS_H264_DECODE_PARAMS: + ctx->h264.decode_params = data; + break; + case V4L2_CID_STATELESS_H264_SPS: + ctx->h264.sps = data; + break; + case V4L2_CID_STATELESS_H264_PPS: + ctx->h264.pps = data; + break; + } +} + +void tegra_vde_prepare_control_data(struct tegra_ctx *ctx, u32 id) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ctrl_cfgs); i++) { + if (ctx->ctrls[i]->id == id) { + tegra_set_control_data(ctx, ctx->ctrls[i]->p_cur.p, id); + return; + } + } + + tegra_set_control_data(ctx, NULL, id); +} + +static int tegra_queue_setup(struct vb2_queue *vq, + unsigned int *nbufs, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + struct v4l2_format *f; + unsigned int i; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + f = &ctx->coded_fmt; + else + f = &ctx->decoded_fmt; + + if (*num_planes) { + if (*num_planes != f->fmt.pix_mp.num_planes) + return -EINVAL; + + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { + if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage) + return -EINVAL; + } + } else { + *num_planes = f->fmt.pix_mp.num_planes; + + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) + sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + return 0; +} + +static int tegra_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + +static void __tegra_buf_cleanup(struct vb2_buffer *vb, unsigned int i) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); + + while (i--) { + if (tb->a[i]) { + tegra_vde_dmabuf_cache_unmap(ctx->vde, tb->a[i], true); + tb->a[i] = NULL; + } + + if (tb->iova[i]) { + tegra_vde_iommu_unmap(ctx->vde, tb->iova[i]); + tb->iova[i] = NULL; + } + } + + if (tb->aux) { + tegra_vde_free_bo(tb->aux); + tb->aux = NULL; + } +} + +static int tegra_buf_init(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); + struct tegra_vde *vde = ctx->vde; + enum dma_data_direction dma_dir; + struct sg_table *sgt; + unsigned int i; + int err; + + if (V4L2_TYPE_IS_CAPTURE(vq->type) && vb->num_planes > 1) { + /* + * Tegra decoder writes auxiliary data for I/P frames. + * This data is needed for decoding of B frames. + */ + err = tegra_vde_alloc_bo(vde, &tb->aux, DMA_FROM_DEVICE, + vb2_plane_size(vb, 1)); + if (err) + return err; + } + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + dma_dir = DMA_TO_DEVICE; + else + dma_dir = DMA_FROM_DEVICE; + + for (i = 0; i < vb->num_planes; i++) { + if (vq->memory == VB2_MEMORY_DMABUF) { + get_dma_buf(vb->planes[i].dbuf); + + err = tegra_vde_dmabuf_cache_map(vde, vb->planes[i].dbuf, + dma_dir, &tb->a[i], + &tb->dma_base[i]); + if (err) { + dma_buf_put(vb->planes[i].dbuf); + goto cleanup; + } + + continue; + } + + if (vde->domain) { + sgt = vb2_dma_sg_plane_desc(vb, i); + + err = tegra_vde_iommu_map(vde, sgt, &tb->iova[i], + vb2_plane_size(vb, i)); + if (err) + goto cleanup; + + tb->dma_base[i] = iova_dma_addr(&vde->iova, tb->iova[i]); + } else { + tb->dma_base[i] = vb2_dma_contig_plane_dma_addr(vb, i); + } + } + + return 0; + +cleanup: + __tegra_buf_cleanup(vb, i); + + return err; +} + +static void tegra_buf_cleanup(struct vb2_buffer *vb) +{ + __tegra_buf_cleanup(vb, vb->num_planes); +} + +static int tegra_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); + size_t hw_align, hw_size, hw_payload, size, offset; + struct v4l2_pix_format_mplane *pixfmt; + unsigned int i; + void *vb_data; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + hw_align = BSEV_ALIGN; + pixfmt = &ctx->coded_fmt.fmt.pix_mp; + } else { + hw_align = FRAMEID_ALIGN; + pixfmt = &ctx->decoded_fmt.fmt.pix_mp; + } + + for (i = 0; i < vb->num_planes; i++) { + offset = vb->planes[i].data_offset; + + if (offset & (hw_align - 1)) + return -EINVAL; + + if (V4L2_TYPE_IS_CAPTURE(vq->type)) { + size = pixfmt->plane_fmt[i].sizeimage; + hw_payload = ALIGN(size, VDE_ATOM); + } else { + size = vb2_get_plane_payload(vb, i) - offset; + hw_payload = ALIGN(size + VDE_ATOM, SXE_BUFFER); + } + + hw_size = offset + hw_payload; + + if (vb2_plane_size(vb, i) < hw_size) + return -EINVAL; + + vb2_set_plane_payload(vb, i, hw_payload); + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + vb_data = vb2_plane_vaddr(vb, i); + + /* + * Hardware requires zero-padding of coded data. + * Otherwise it will fail to parse the trailing + * data and abort the decoding. + */ + if (vb_data) + memset(vb_data + offset + size, 0, + hw_size - offset - size); + } + + tb->dma_addr[i] = tb->dma_base[i] + offset; + } + + switch (pixfmt->pixelformat) { + case V4L2_PIX_FMT_YVU420M: + swap(tb->dma_addr[1], tb->dma_addr[2]); + break; + } + + return 0; +} + +static void tegra_buf_queue(struct vb2_buffer *vb) +{ + struct tegra_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static void tegra_buf_request_complete(struct vb2_buffer *vb) +{ + struct tegra_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); +} + +static int tegra_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + return 0; +} + +static void tegra_stop_streaming(struct vb2_queue *vq) +{ + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + + while (true) { + struct vb2_v4l2_buffer *vbuf; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + if (!vbuf) + break; + + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &ctx->hdl); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + } +} + +static const struct vb2_ops tegra_qops = { + .queue_setup = tegra_queue_setup, + .buf_init = tegra_buf_init, + .buf_cleanup = tegra_buf_cleanup, + .buf_prepare = tegra_buf_prepare, + .buf_queue = tegra_buf_queue, + .buf_out_validate = tegra_buf_out_validate, + .buf_request_complete = tegra_buf_request_complete, + .start_streaming = tegra_start_streaming, + .stop_streaming = tegra_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int tegra_queue_init(void *priv, + struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct tegra_ctx *ctx = priv; + struct tegra_vde *vde = ctx->vde; + const struct vb2_mem_ops *mem_ops; + unsigned long dma_attrs; + int err; + + /* + * TODO: Switch to use of vb2_dma_contig_memops uniformly once we + * will add IOMMU_DOMAIN support for video decoder to tegra-smmu + * driver. For now we need to stick with SG ops in order to be able + * to get SGT table easily. This is suboptimal since SG mappings are + * wasting CPU cache and we don't need that caching. + */ + if (vde->domain) + mem_ops = &vb2_dma_sg_memops; + else + mem_ops = &vb2_dma_contig_memops; + + dma_attrs = DMA_ATTR_WRITE_COMBINE; + + src_vq->buf_struct_size = sizeof(struct tegra_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->supports_requests = true; + src_vq->requires_requests = true; + src_vq->lock = &vde->v4l2_lock; + src_vq->dma_attrs = dma_attrs; + src_vq->mem_ops = mem_ops; + src_vq->ops = &tegra_qops; + src_vq->drv_priv = ctx; + src_vq->dev = vde->dev; + + err = vb2_queue_init(src_vq); + if (err) { + v4l2_err(&vde->v4l2_dev, + "failed to initialize src queue: %d\n", err); + return err; + } + + /* + * We may need to zero the end of bitstream in kernel if userspace + * doesn't do that, hence kmap is needed for the coded data. It's not + * needed for framebuffers. + */ + dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; + + dst_vq->buf_struct_size = sizeof(struct tegra_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->lock = &vde->v4l2_lock; + dst_vq->dma_attrs = dma_attrs; + dst_vq->mem_ops = mem_ops; + dst_vq->ops = &tegra_qops; + dst_vq->drv_priv = ctx; + dst_vq->dev = vde->dev; + + err = vb2_queue_init(dst_vq); + if (err) { + v4l2_err(&vde->v4l2_dev, + "failed to initialize dst queue: %d\n", err); + return err; + } + + return 0; +} + +static void tegra_reset_fmt(struct tegra_ctx *ctx, struct v4l2_format *f, + u32 fourcc) +{ + memset(f, 0, sizeof(*f)); + f->fmt.pix_mp.pixelformat = fourcc; + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; +} + +static void tegra_reset_coded_fmt(struct tegra_ctx *ctx) +{ + const struct tegra_vde_soc *soc = ctx->vde->soc; + struct v4l2_format *f = &ctx->coded_fmt; + + ctx->coded_fmt_desc = &soc->coded_fmts[0]; + tegra_reset_fmt(ctx, f, ctx->coded_fmt_desc->fourcc); + + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + f->fmt.pix_mp.width = ctx->coded_fmt_desc->frmsize.min_width; + f->fmt.pix_mp.height = ctx->coded_fmt_desc->frmsize.min_height; +} + +static void tegra_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, + u32 pixelformat, u32 width, u32 height) +{ + const struct v4l2_format_info *info = v4l2_format_info(pixelformat); + struct v4l2_plane_pix_format *plane; + unsigned int i; + + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_YVU420M: + pixfmt->width = width; + pixfmt->height = height; + pixfmt->pixelformat = pixelformat; + pixfmt->num_planes = info->mem_planes; + + for (i = 0; i < pixfmt->num_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : 2; + unsigned int vdiv = (i == 0) ? 1 : 2; + + /* + * VDE is connected to Graphics Memory using 128bit port, + * all memory accesses are made using 16B atoms. + * + * V4L requires Cb/Cr strides to be exactly half of the + * Y stride, hence we're aligning Y to 16B x 2. + */ + plane = &pixfmt->plane_fmt[i]; + plane->bytesperline = ALIGN(width, VDE_ATOM * 2) / hdiv; + plane->sizeimage = plane->bytesperline * height / vdiv; + } + + break; + } +} + +static void tegra_reset_decoded_fmt(struct tegra_ctx *ctx) +{ + struct v4l2_format *f = &ctx->decoded_fmt; + + tegra_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + tegra_fill_pixfmt_mp(&f->fmt.pix_mp, + ctx->coded_fmt_desc->decoded_fmts[0], + ctx->coded_fmt.fmt.pix_mp.width, + ctx->coded_fmt.fmt.pix_mp.height); +} + +static void tegra_job_finish(struct tegra_ctx *ctx, + enum vb2_buffer_state result) +{ + v4l2_m2m_buf_done_and_job_finish(ctx->vde->m2m, ctx->fh.m2m_ctx, + result); +} + +static void tegra_decode_complete(struct work_struct *work) +{ + struct tegra_ctx *ctx = container_of(work, struct tegra_ctx, work); + int err; + + err = ctx->coded_fmt_desc->decode_wait(ctx); + if (err) + tegra_job_finish(ctx, VB2_BUF_STATE_ERROR); + else + tegra_job_finish(ctx, VB2_BUF_STATE_DONE); +} + +static int tegra_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->bus_info, "platform:tegra-vde", sizeof(cap->bus_info)); + strscpy(cap->driver, "tegra-vde", sizeof(cap->driver)); + strscpy(cap->card, "tegra-vde", sizeof(cap->card)); + + return 0; +} + +static int tegra_enum_decoded_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + + if (WARN_ON(!ctx->coded_fmt_desc)) + return -EINVAL; + + if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts) + return -EINVAL; + + f->pixelformat = ctx->coded_fmt_desc->decoded_fmts[f->index]; + + return 0; +} + +static int tegra_g_decoded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + + *f = ctx->decoded_fmt; + return 0; +} + +static int tegra_try_decoded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + const struct tegra_coded_fmt_desc *coded_desc; + unsigned int i; + + /* + * The codec context should point to a coded format desc, if the format + * on the coded end has not been set yet, it should point to the + * default value. + */ + coded_desc = ctx->coded_fmt_desc; + if (WARN_ON(!coded_desc)) + return -EINVAL; + + if (!coded_desc->num_decoded_fmts) + return -EINVAL; + + for (i = 0; i < coded_desc->num_decoded_fmts; i++) { + if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) + break; + } + + if (i == coded_desc->num_decoded_fmts) + pix_mp->pixelformat = coded_desc->decoded_fmts[0]; + + /* always apply the frmsize constraint of the coded end */ + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &coded_desc->frmsize); + + tegra_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, + pix_mp->width, pix_mp->height); + pix_mp->field = V4L2_FIELD_NONE; + + return 0; +} + +static int tegra_s_decoded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct vb2_queue *vq; + int err; + + /* change not allowed if queue is busy */ + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (vb2_is_busy(vq)) + return -EBUSY; + + err = tegra_try_decoded_fmt(file, priv, f); + if (err) + return err; + + ctx->decoded_fmt = *f; + + return 0; +} + +static int tegra_enum_coded_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + const struct tegra_vde_soc *soc = ctx->vde->soc; + + if (f->index >= soc->num_coded_fmts) + return -EINVAL; + + f->pixelformat = soc->coded_fmts[f->index].fourcc; + + return 0; +} + +static int tegra_g_coded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + + *f = ctx->coded_fmt; + return 0; +} + +static const struct tegra_coded_fmt_desc * +tegra_find_coded_fmt_desc(struct tegra_ctx *ctx, u32 fourcc) +{ + const struct tegra_vde_soc *soc = ctx->vde->soc; + unsigned int i; + + for (i = 0; i < soc->num_coded_fmts; i++) { + if (soc->coded_fmts[i].fourcc == fourcc) + return &soc->coded_fmts[i]; + } + + return NULL; +} + +static int tegra_try_coded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + const struct tegra_vde_soc *soc = ctx->vde->soc; + int size = pix_mp->plane_fmt[0].sizeimage; + const struct tegra_coded_fmt_desc *desc; + + desc = tegra_find_coded_fmt_desc(ctx, pix_mp->pixelformat); + if (!desc) { + pix_mp->pixelformat = soc->coded_fmts[0].fourcc; + desc = &soc->coded_fmts[0]; + } + + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &desc->frmsize); + + pix_mp->plane_fmt[0].sizeimage = max(ALIGN(size, SXE_BUFFER), SZ_2M); + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->num_planes = 1; + + return 0; +} + +static int tegra_s_coded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; + const struct tegra_coded_fmt_desc *desc; + struct vb2_queue *peer_vq, *vq; + struct v4l2_format *cap_fmt; + int err; + + /* + * In order to support dynamic resolution change, the decoder admits + * a resolution change, as long as the pixelformat remains. Can't be + * done if streaming. + */ + vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (vb2_is_streaming(vq) || + (vb2_is_busy(vq) && + f->fmt.pix_mp.pixelformat != ctx->coded_fmt.fmt.pix_mp.pixelformat)) + return -EBUSY; + + /* + * Since format change on the OUTPUT queue will reset the CAPTURE + * queue, we can't allow doing so when the CAPTURE queue has buffers + * allocated. + */ + peer_vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (vb2_is_busy(peer_vq)) + return -EBUSY; + + err = tegra_try_coded_fmt(file, priv, f); + if (err) + return err; + + desc = tegra_find_coded_fmt_desc(ctx, f->fmt.pix_mp.pixelformat); + if (!desc) + return -EINVAL; + + ctx->coded_fmt_desc = desc; + ctx->coded_fmt = *f; + + /* + * Current decoded format might have become invalid with newly + * selected codec, so reset it to default just to be safe and + * keep internal driver state sane. User is mandated to set + * the decoded format again after we return, so we don't need + * anything smarter. + * + * Note that this will propagates any size changes to the decoded format. + */ + tegra_reset_decoded_fmt(ctx); + + /* propagate colorspace information to capture */ + cap_fmt = &ctx->decoded_fmt; + cap_fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + cap_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + cap_fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + cap_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + + return 0; +} + +static int tegra_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + const struct tegra_coded_fmt_desc *fmt; + + if (fsize->index) + return -EINVAL; + + fmt = tegra_find_coded_fmt_desc(ctx, fsize->pixel_format); + if (!fmt) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = fmt->frmsize; + + return 0; +} + +static const struct v4l2_ioctl_ops tegra_v4l2_ioctl_ops = { + .vidioc_querycap = tegra_querycap, + .vidioc_enum_framesizes = tegra_enum_framesizes, + + .vidioc_try_fmt_vid_out_mplane = tegra_try_coded_fmt, + .vidioc_g_fmt_vid_out_mplane = tegra_g_coded_fmt, + .vidioc_s_fmt_vid_out_mplane = tegra_s_coded_fmt, + .vidioc_enum_fmt_vid_out = tegra_enum_coded_fmt, + + .vidioc_try_fmt_vid_cap_mplane = tegra_try_decoded_fmt, + .vidioc_g_fmt_vid_cap_mplane = tegra_g_decoded_fmt, + .vidioc_s_fmt_vid_cap_mplane = tegra_s_decoded_fmt, + .vidioc_enum_fmt_vid_cap = tegra_enum_decoded_fmt, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int tegra_init_ctrls(struct tegra_ctx *ctx) +{ + unsigned int i; + int err; + + err = v4l2_ctrl_handler_init(&ctx->hdl, ARRAY_SIZE(ctrl_cfgs)); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(ctrl_cfgs); i++) { + ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->hdl, &ctrl_cfgs[i], + NULL); + if (ctx->hdl.error) { + err = ctx->hdl.error; + goto free_ctrls; + } + } + + err = v4l2_ctrl_handler_setup(&ctx->hdl); + if (err) + goto free_ctrls; + + ctx->fh.ctrl_handler = &ctx->hdl; + + return 0; + +free_ctrls: + v4l2_ctrl_handler_free(&ctx->hdl); + + return err; +} + +static int tegra_init_m2m(struct tegra_ctx *ctx) +{ + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(ctx->vde->m2m, + ctx, tegra_queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) + return PTR_ERR(ctx->fh.m2m_ctx); + + return 0; +} + +static int tegra_open(struct file *file) +{ + struct tegra_vde *vde = video_drvdata(file); + struct tegra_ctx *ctx; + int err; + + ctx = kzalloc(offsetof(struct tegra_ctx, ctrls[ARRAY_SIZE(ctrl_cfgs)]), + GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->vde = vde; + v4l2_fh_init(&ctx->fh, video_devdata(file)); + INIT_WORK(&ctx->work, tegra_decode_complete); + + err = tegra_init_ctrls(ctx); + if (err) { + v4l2_err(&vde->v4l2_dev, "failed to add controls: %d\n", err); + goto free_ctx; + } + + err = tegra_init_m2m(ctx); + if (err) { + v4l2_err(&vde->v4l2_dev, "failed to initialize m2m: %d\n", err); + goto free_ctrls; + } + + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + tegra_reset_coded_fmt(ctx); + tegra_try_coded_fmt(file, file->private_data, &ctx->coded_fmt); + + tegra_reset_decoded_fmt(ctx); + tegra_try_decoded_fmt(file, file->private_data, &ctx->decoded_fmt); + + return 0; + +free_ctrls: + v4l2_ctrl_handler_free(&ctx->hdl); +free_ctx: + kfree(ctx); + + return err; +} + +static int tegra_release(struct file *file) +{ + struct v4l2_fh *fh = file->private_data; + struct tegra_ctx *ctx = fh_to_tegra_ctx(fh); + struct tegra_vde *vde = ctx->vde; + + v4l2_fh_del(fh); + v4l2_m2m_ctx_release(fh->m2m_ctx); + v4l2_ctrl_handler_free(&ctx->hdl); + v4l2_fh_exit(fh); + kfree(ctx); + + tegra_vde_dmabuf_cache_unmap_sync(vde); + + return 0; +} + +static const struct v4l2_file_operations tegra_v4l2_fops = { + .owner = THIS_MODULE, + .open = tegra_open, + .poll = v4l2_m2m_fop_poll, + .mmap = v4l2_m2m_fop_mmap, + .release = tegra_release, + .unlocked_ioctl = video_ioctl2, +}; + +static void tegra_device_run(void *priv) +{ + struct tegra_ctx *ctx = priv; + struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct media_request *src_req = src->vb2_buf.req_obj.req; + int err; + + v4l2_ctrl_request_setup(src_req, &ctx->hdl); + + err = ctx->coded_fmt_desc->decode_run(ctx); + + v4l2_ctrl_request_complete(src_req, &ctx->hdl); + + if (err) + tegra_job_finish(ctx, VB2_BUF_STATE_ERROR); + else + queue_work(ctx->vde->wq, &ctx->work); +} + +static const struct v4l2_m2m_ops tegra_v4l2_m2m_ops = { + .device_run = tegra_device_run, +}; + +static int tegra_request_validate(struct media_request *req) +{ + unsigned int count; + + count = vb2_request_buffer_cnt(req); + if (!count) + return -ENOENT; + else if (count > 1) + return -EINVAL; + + return vb2_request_validate(req); +} + +static const struct media_device_ops tegra_media_device_ops = { + .req_validate = tegra_request_validate, + .req_queue = v4l2_m2m_request_queue, +}; + +int tegra_vde_v4l2_init(struct tegra_vde *vde) +{ + struct device *dev = vde->dev; + int err; + + mutex_init(&vde->v4l2_lock); + media_device_init(&vde->mdev); + video_set_drvdata(&vde->vdev, vde); + + vde->vdev.lock = &vde->v4l2_lock, + vde->vdev.fops = &tegra_v4l2_fops, + vde->vdev.vfl_dir = VFL_DIR_M2M, + vde->vdev.release = video_device_release_empty, + vde->vdev.v4l2_dev = &vde->v4l2_dev; + vde->vdev.ioctl_ops = &tegra_v4l2_ioctl_ops, + vde->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, + + vde->v4l2_dev.mdev = &vde->mdev; + vde->mdev.ops = &tegra_media_device_ops; + vde->mdev.dev = dev; + + strscpy(vde->mdev.model, "tegra-vde", sizeof(vde->mdev.model)); + strscpy(vde->vdev.name, "tegra-vde", sizeof(vde->vdev.name)); + strscpy(vde->mdev.bus_info, "platform:tegra-vde", + sizeof(vde->mdev.bus_info)); + + vde->wq = create_workqueue("tegra-vde"); + if (!vde->wq) + return -ENOMEM; + + err = media_device_register(&vde->mdev); + if (err) { + dev_err(dev, "failed to register media device: %d\n", err); + goto clean_up_media_device; + } + + err = v4l2_device_register(dev, &vde->v4l2_dev); + if (err) { + dev_err(dev, "failed to register v4l2 device: %d\n", err); + goto unreg_media_device; + } + + err = video_register_device(&vde->vdev, VFL_TYPE_VIDEO, -1); + if (err) { + dev_err(dev, "failed to register video device: %d\n", err); + goto unreg_v4l2; + } + + vde->m2m = v4l2_m2m_init(&tegra_v4l2_m2m_ops); + err = PTR_ERR_OR_ZERO(vde->m2m); + if (err) { + dev_err(dev, "failed to initialize m2m device: %d\n", err); + goto unreg_video_device; + } + + err = v4l2_m2m_register_media_controller(vde->m2m, &vde->vdev, + MEDIA_ENT_F_PROC_VIDEO_DECODER); + if (err) { + dev_err(dev, "failed to register media controller: %d\n", err); + goto release_m2m; + } + + v4l2_info(&vde->v4l2_dev, "v4l2 device registered as /dev/video%d\n", + vde->vdev.num); + + return 0; + +release_m2m: + v4l2_m2m_release(vde->m2m); +unreg_video_device: + video_unregister_device(&vde->vdev); +unreg_v4l2: + v4l2_device_unregister(&vde->v4l2_dev); +unreg_media_device: + media_device_unregister(&vde->mdev); +clean_up_media_device: + media_device_cleanup(&vde->mdev); + + destroy_workqueue(vde->wq); + + return err; +} + +void tegra_vde_v4l2_deinit(struct tegra_vde *vde) +{ + v4l2_m2m_unregister_media_controller(vde->m2m); + v4l2_m2m_release(vde->m2m); + + video_unregister_device(&vde->vdev); + v4l2_device_unregister(&vde->v4l2_dev); + + media_device_unregister(&vde->mdev); + media_device_cleanup(&vde->mdev); + + destroy_workqueue(vde->wq); +} diff --git a/drivers/staging/media/tegra-vde/vde.c b/drivers/staging/media/tegra-vde/vde.c index 36f5595c0fd8..c147d58c3bfb 100644 --- a/drivers/staging/media/tegra-vde/vde.c +++ b/drivers/staging/media/tegra-vde/vde.c @@ -53,10 +53,10 @@ void tegra_vde_set_bits(struct tegra_vde *vde, u32 mask, tegra_vde_writel(vde, value | mask, base, offset); } -static int tegra_vde_alloc_bo(struct tegra_vde *vde, - struct tegra_vde_bo **ret_bo, - enum dma_data_direction dma_dir, - size_t size) +int tegra_vde_alloc_bo(struct tegra_vde *vde, + struct tegra_vde_bo **ret_bo, + enum dma_data_direction dma_dir, + size_t size) { struct device *dev = vde->miscdev.parent; struct tegra_vde_bo *bo; @@ -126,7 +126,7 @@ free_bo: return err; } -static void tegra_vde_free_bo(struct tegra_vde_bo *bo) +void tegra_vde_free_bo(struct tegra_vde_bo *bo) { struct tegra_vde *vde = bo->vde; struct device *dev = vde->miscdev.parent; @@ -332,6 +332,8 @@ static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, dpb_frames[i].flags = frames[i].flags; dpb_frames[i].frame_num = frames[i].frame_num; + dpb_frames[i].luma_atoms_pitch = ctx.pic_width_in_mbs; + dpb_frames[i].chroma_atoms_pitch = cstride / VDE_ATOM; dma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; @@ -626,8 +628,16 @@ static int tegra_vde_probe(struct platform_device *pdev) goto err_free_secure_bo; } + err = tegra_vde_v4l2_init(vde); + if (err) { + dev_err(dev, "Failed to initialize V4L2: %d\n", err); + goto misc_unreg; + } + return 0; +misc_unreg: + misc_deregister(&vde->miscdev); err_free_secure_bo: tegra_vde_free_bo(vde->secure_bo); err_pm_runtime: @@ -648,6 +658,7 @@ static int tegra_vde_remove(struct platform_device *pdev) struct tegra_vde *vde = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; + tegra_vde_v4l2_deinit(vde); misc_deregister(&vde->miscdev); tegra_vde_free_bo(vde->secure_bo); @@ -722,20 +733,73 @@ static const struct dev_pm_ops tegra_vde_pm_ops = { tegra_vde_pm_resume) }; +static const u32 tegra124_decoded_fmts[] = { + /* TBD: T124 supports only a non-standard Tegra tiled format */ +}; + +static const struct tegra_coded_fmt_desc tegra124_coded_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .frmsize = { + .min_width = 16, + .max_width = 1920, + .step_width = 16, + .min_height = 16, + .max_height = 2032, + .step_height = 16, + }, + .num_decoded_fmts = ARRAY_SIZE(tegra124_decoded_fmts), + .decoded_fmts = tegra124_decoded_fmts, + .decode_run = tegra_vde_h264_decode_run, + .decode_wait = tegra_vde_h264_decode_wait, + }, +}; + +static const u32 tegra20_decoded_fmts[] = { + V4L2_PIX_FMT_YUV420M, + V4L2_PIX_FMT_YVU420M, +}; + +static const struct tegra_coded_fmt_desc tegra20_coded_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .frmsize = { + .min_width = 16, + .max_width = 1920, + .step_width = 16, + .min_height = 16, + .max_height = 2032, + .step_height = 16, + }, + .num_decoded_fmts = ARRAY_SIZE(tegra20_decoded_fmts), + .decoded_fmts = tegra20_decoded_fmts, + .decode_run = tegra_vde_h264_decode_run, + .decode_wait = tegra_vde_h264_decode_wait, + }, +}; + static const struct tegra_vde_soc tegra124_vde_soc = { .supports_ref_pic_marking = true, + .coded_fmts = tegra124_coded_fmts, + .num_coded_fmts = ARRAY_SIZE(tegra124_coded_fmts), }; static const struct tegra_vde_soc tegra114_vde_soc = { .supports_ref_pic_marking = true, + .coded_fmts = tegra20_coded_fmts, + .num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts), }; static const struct tegra_vde_soc tegra30_vde_soc = { .supports_ref_pic_marking = false, + .coded_fmts = tegra20_coded_fmts, + .num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts), }; static const struct tegra_vde_soc tegra20_vde_soc = { .supports_ref_pic_marking = false, + .coded_fmts = tegra20_coded_fmts, + .num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts), }; static const struct of_device_id tegra_vde_of_match[] = { diff --git a/drivers/staging/media/tegra-vde/vde.h b/drivers/staging/media/tegra-vde/vde.h index 8ba6a71e3e40..e0396bb0b986 100644 --- a/drivers/staging/media/tegra-vde/vde.h +++ b/drivers/staging/media/tegra-vde/vde.h @@ -15,6 +15,16 @@ #include #include #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include #define ICMDQUE_WR 0x00 #define CMDQUE_CONTROL 0x08 @@ -25,9 +35,15 @@ #define BSE_ICMDQUE_EMPTY BIT(3) #define BSE_DMA_BUSY BIT(23) +#define BSEV_ALIGN SZ_1 +#define FRAMEID_ALIGN SZ_256 +#define SXE_BUFFER SZ_32K +#define VDE_ATOM SZ_16 + struct clk; struct dma_buf; struct gen_pool; +struct tegra_ctx; struct iommu_group; struct iommu_domain; struct reset_control; @@ -46,10 +62,23 @@ struct tegra_video_frame { dma_addr_t aux_addr; u32 frame_num; u32 flags; + u32 luma_atoms_pitch; + u32 chroma_atoms_pitch; +}; + +struct tegra_coded_fmt_desc { + u32 fourcc; + struct v4l2_frmsize_stepwise frmsize; + unsigned int num_decoded_fmts; + const u32 *decoded_fmts; + int (*decode_run)(struct tegra_ctx *ctx); + int (*decode_wait)(struct tegra_ctx *ctx); }; struct tegra_vde_soc { bool supports_ref_pic_marking; + const struct tegra_coded_fmt_desc *coded_fmts; + u32 num_coded_fmts; }; struct tegra_vde_bo { @@ -94,8 +123,60 @@ struct tegra_vde { dma_addr_t bitstream_data_addr; dma_addr_t iram_lists_addr; u32 *iram; + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m; + struct media_device mdev; + struct video_device vdev; + struct mutex v4l2_lock; + struct workqueue_struct *wq; + struct tegra_video_frame frames[V4L2_H264_NUM_DPB_ENTRIES + 1]; +}; + +int tegra_vde_alloc_bo(struct tegra_vde *vde, + struct tegra_vde_bo **ret_bo, + enum dma_data_direction dma_dir, + size_t size); +void tegra_vde_free_bo(struct tegra_vde_bo *bo); + +struct tegra_ctx_h264 { + const struct v4l2_ctrl_h264_decode_params *decode_params; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; +}; + +struct tegra_ctx { + struct tegra_vde *vde; + struct tegra_ctx_h264 h264; + struct work_struct work; + struct v4l2_fh fh; + struct v4l2_ctrl_handler hdl; + struct v4l2_format coded_fmt; + struct v4l2_format decoded_fmt; + const struct tegra_coded_fmt_desc *coded_fmt_desc; + struct v4l2_ctrl *ctrls[]; +}; + +struct tegra_m2m_buffer { + struct v4l2_m2m_buffer m2m; + struct dma_buf_attachment *a[VB2_MAX_PLANES]; + dma_addr_t dma_base[VB2_MAX_PLANES]; + dma_addr_t dma_addr[VB2_MAX_PLANES]; + struct iova *iova[VB2_MAX_PLANES]; + struct tegra_vde_bo *aux; + bool b_frame; }; +static inline struct tegra_m2m_buffer * +vb_to_tegra_buf(struct vb2_buffer *vb) +{ + struct v4l2_m2m_buffer *m2m = container_of(vb, struct v4l2_m2m_buffer, + vb.vb2_buf); + + return container_of(m2m, struct tegra_m2m_buffer, m2m); +} + +void tegra_vde_prepare_control_data(struct tegra_ctx *ctx, u32 id); + void tegra_vde_writel(struct tegra_vde *vde, u32 value, void __iomem *base, u32 offset); u32 tegra_vde_readl(struct tegra_vde *vde, void __iomem *base, u32 offset); @@ -111,6 +192,8 @@ int tegra_vde_decode_h264(struct tegra_vde *vde, struct tegra_video_frame *dpb_frames, dma_addr_t bitstream_data_addr, size_t bitstream_data_size); +int tegra_vde_h264_decode_run(struct tegra_ctx *ctx); +int tegra_vde_h264_decode_wait(struct tegra_ctx *ctx); int tegra_vde_iommu_init(struct tegra_vde *vde); void tegra_vde_iommu_deinit(struct tegra_vde *vde); @@ -164,4 +247,7 @@ tegra_vde_reg_base_name(struct tegra_vde *vde, void __iomem *base) return "???"; } +int tegra_vde_v4l2_init(struct tegra_vde *vde); +void tegra_vde_v4l2_deinit(struct tegra_vde *vde); + #endif /* TEGRA_VDE_H */ -- cgit v1.2.3 From 313db7d235a0af753ad163a140cb46350d4d1d08 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 20 Feb 2022 21:46:19 +0100 Subject: media: staging: tegra-vde: Remove legacy UAPI support The legacy UAPI became unnecessary with the V4L stateless decoder API support addition to the Tegra decoder driver. Remove legacy UAPI support. Signed-off-by: Dmitry Osipenko Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/tegra-vde/dmabuf-cache.c | 2 +- drivers/staging/media/tegra-vde/h264.c | 61 +++--- drivers/staging/media/tegra-vde/iommu.c | 2 +- drivers/staging/media/tegra-vde/uapi.h | 73 ------- drivers/staging/media/tegra-vde/vde.c | 283 +------------------------ drivers/staging/media/tegra-vde/vde.h | 11 - 6 files changed, 35 insertions(+), 397 deletions(-) delete mode 100644 drivers/staging/media/tegra-vde/uapi.h (limited to 'drivers/staging') diff --git a/drivers/staging/media/tegra-vde/dmabuf-cache.c b/drivers/staging/media/tegra-vde/dmabuf-cache.c index a98d03419b8f..69c346148070 100644 --- a/drivers/staging/media/tegra-vde/dmabuf-cache.c +++ b/drivers/staging/media/tegra-vde/dmabuf-cache.c @@ -66,9 +66,9 @@ int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde, struct dma_buf_attachment **ap, dma_addr_t *addrp) { - struct device *dev = vde->miscdev.parent; struct dma_buf_attachment *attachment; struct tegra_vde_cache_entry *entry; + struct device *dev = vde->dev; struct sg_table *sgt; struct iova *iova; int err; diff --git a/drivers/staging/media/tegra-vde/h264.c b/drivers/staging/media/tegra-vde/h264.c index cbf27f0cfdb1..a46c648a26c6 100644 --- a/drivers/staging/media/tegra-vde/h264.c +++ b/drivers/staging/media/tegra-vde/h264.c @@ -14,9 +14,36 @@ #include #include "trace.h" -#include "uapi.h" #include "vde.h" +#define FLAG_B_FRAME 0x1 +#define FLAG_REFERENCE 0x2 + +struct tegra_vde_h264_frame { + unsigned int frame_num; + unsigned int flags; +}; + +struct tegra_vde_h264_decoder_ctx { + unsigned int dpb_frames_nb; + unsigned int dpb_ref_frames_with_earlier_poc_nb; + unsigned int baseline_profile; + unsigned int level_idc; + unsigned int log2_max_pic_order_cnt_lsb; + unsigned int log2_max_frame_num; + unsigned int pic_order_cnt_type; + unsigned int direct_8x8_inference_flag; + unsigned int pic_width_in_mbs; + unsigned int pic_height_in_mbs; + unsigned int pic_init_qp; + unsigned int deblocking_filter_control_present_flag; + unsigned int constrained_intra_pred_flag; + unsigned int chroma_qp_index_offset; + unsigned int pic_order_present_flag; + unsigned int num_ref_idx_l0_active_minus1; + unsigned int num_ref_idx_l1_active_minus1; +}; + struct h264_reflists { u8 p[V4L2_H264_NUM_DPB_ENTRIES]; u8 b0[V4L2_H264_NUM_DPB_ENTRIES]; @@ -438,19 +465,8 @@ static void tegra_vde_decode_frame(struct tegra_vde *vde, vde->sxe, 0x00); } -int tegra_vde_validate_h264_frame(struct device *dev, - struct tegra_vde_h264_frame *frame) -{ - if (frame->frame_num > 0x7FFFFF) { - dev_err(dev, "Bad frame_num %u\n", frame->frame_num); - return -EINVAL; - } - - return 0; -} - -int tegra_vde_validate_h264_ctx(struct device *dev, - struct tegra_vde_h264_decoder_ctx *ctx) +static int tegra_vde_validate_h264_ctx(struct device *dev, + struct tegra_vde_h264_decoder_ctx *ctx) { if (ctx->dpb_frames_nb == 0 || ctx->dpb_frames_nb > 17) { dev_err(dev, "Bad DPB size %u\n", ctx->dpb_frames_nb); @@ -637,23 +653,6 @@ static int tegra_vde_decode_end(struct tegra_vde *vde) return ret; } -int tegra_vde_decode_h264(struct tegra_vde *vde, - struct tegra_vde_h264_decoder_ctx *ctx, - struct tegra_video_frame *dpb_frames, - dma_addr_t bitstream_data_addr, - size_t bitstream_data_size) -{ - int err; - - err = tegra_vde_decode_begin(vde, ctx, dpb_frames, - bitstream_data_addr, - bitstream_data_size); - if (err) - return err; - - return tegra_vde_decode_end(vde); -} - static struct vb2_buffer *get_ref_buf(struct tegra_ctx *ctx, struct vb2_v4l2_buffer *dst, unsigned int dpb_idx) diff --git a/drivers/staging/media/tegra-vde/iommu.c b/drivers/staging/media/tegra-vde/iommu.c index adf8dc7ee25c..5521ed3e465f 100644 --- a/drivers/staging/media/tegra-vde/iommu.c +++ b/drivers/staging/media/tegra-vde/iommu.c @@ -60,7 +60,7 @@ void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova) int tegra_vde_iommu_init(struct tegra_vde *vde) { - struct device *dev = vde->miscdev.parent; + struct device *dev = vde->dev; struct iova *iova; unsigned long order; unsigned long shift; diff --git a/drivers/staging/media/tegra-vde/uapi.h b/drivers/staging/media/tegra-vde/uapi.h deleted file mode 100644 index ffb4983e5bb6..000000000000 --- a/drivers/staging/media/tegra-vde/uapi.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* Copyright (C) 2016-2017 Dmitry Osipenko */ -#ifndef _UAPI_TEGRA_VDE_H_ -#define _UAPI_TEGRA_VDE_H_ - -#include -#include - -#define FLAG_B_FRAME 0x1 -#define FLAG_REFERENCE 0x2 - -struct tegra_vde_h264_frame { - __s32 y_fd; - __s32 cb_fd; - __s32 cr_fd; - __s32 aux_fd; - __u32 y_offset; - __u32 cb_offset; - __u32 cr_offset; - __u32 aux_offset; - __u32 frame_num; - __u32 flags; - - // Must be zero'ed - __u32 reserved[6]; -}; - -struct tegra_vde_h264_decoder_ctx { - __s32 bitstream_data_fd; - __u32 bitstream_data_offset; - - __u64 dpb_frames_ptr; - __u32 dpb_frames_nb; - __u32 dpb_ref_frames_with_earlier_poc_nb; - - // SPS - __u32 baseline_profile; - __u32 level_idc; - __u32 log2_max_pic_order_cnt_lsb; - __u32 log2_max_frame_num; - __u32 pic_order_cnt_type; - __u32 direct_8x8_inference_flag; - __u32 pic_width_in_mbs; - __u32 pic_height_in_mbs; - - // PPS - __u32 pic_init_qp; - __u32 deblocking_filter_control_present_flag; - __u32 constrained_intra_pred_flag; - __u32 chroma_qp_index_offset; - __u32 pic_order_present_flag; - - // Slice header - __u32 num_ref_idx_l0_active_minus1; - __u32 num_ref_idx_l1_active_minus1; - - // Must be zero'ed - __u32 reserved[11]; -}; - -#define VDE_IOCTL_BASE ('v' + 0x20) - -#define VDE_IO(nr) _IO(VDE_IOCTL_BASE, nr) -#define VDE_IOR(nr, type) _IOR(VDE_IOCTL_BASE, nr, type) -#define VDE_IOW(nr, type) _IOW(VDE_IOCTL_BASE, nr, type) -#define VDE_IOWR(nr, type) _IOWR(VDE_IOCTL_BASE, nr, type) - -#define TEGRA_VDE_DECODE_H264 0x00 - -#define TEGRA_VDE_IOCTL_DECODE_H264 \ - VDE_IOW(TEGRA_VDE_DECODE_H264, struct tegra_vde_h264_decoder_ctx) - -#endif // _UAPI_TEGRA_VDE_H_ diff --git a/drivers/staging/media/tegra-vde/vde.c b/drivers/staging/media/tegra-vde/vde.c index c147d58c3bfb..f3e863a94c5a 100644 --- a/drivers/staging/media/tegra-vde/vde.c +++ b/drivers/staging/media/tegra-vde/vde.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -22,7 +21,6 @@ #include #include -#include "uapi.h" #include "vde.h" #define CREATE_TRACE_POINTS @@ -58,7 +56,7 @@ int tegra_vde_alloc_bo(struct tegra_vde *vde, enum dma_data_direction dma_dir, size_t size) { - struct device *dev = vde->miscdev.parent; + struct device *dev = vde->dev; struct tegra_vde_bo *bo; int err; @@ -129,7 +127,7 @@ free_bo: void tegra_vde_free_bo(struct tegra_vde_bo *bo) { struct tegra_vde *vde = bo->vde; - struct device *dev = vde->miscdev.parent; + struct device *dev = vde->dev; if (vde->domain) tegra_vde_iommu_unmap(vde, bo->iova); @@ -143,266 +141,6 @@ void tegra_vde_free_bo(struct tegra_vde_bo *bo) kfree(bo); } -static int tegra_vde_attach_dmabuf(struct tegra_vde *vde, - int fd, - unsigned long offset, - size_t min_size, - size_t align_size, - struct dma_buf_attachment **a, - dma_addr_t *addrp, - size_t *size, - enum dma_data_direction dma_dir) -{ - struct device *dev = vde->miscdev.parent; - struct dma_buf *dmabuf; - int err; - - dmabuf = dma_buf_get(fd); - if (IS_ERR(dmabuf)) { - dev_err(dev, "Invalid dmabuf FD\n"); - return PTR_ERR(dmabuf); - } - - if (dmabuf->size & (align_size - 1)) { - dev_err(dev, "Unaligned dmabuf 0x%zX, should be aligned to 0x%zX\n", - dmabuf->size, align_size); - return -EINVAL; - } - - if ((u64)offset + min_size > dmabuf->size) { - dev_err(dev, "Too small dmabuf size %zu @0x%lX, should be at least %zu\n", - dmabuf->size, offset, min_size); - return -EINVAL; - } - - err = tegra_vde_dmabuf_cache_map(vde, dmabuf, dma_dir, a, addrp); - if (err) - goto err_put; - - *addrp = *addrp + offset; - - if (size) - *size = dmabuf->size - offset; - - return 0; - -err_put: - dma_buf_put(dmabuf); - - return err; -} - -static int tegra_vde_attach_dmabufs_to_frame(struct tegra_vde *vde, - struct tegra_video_frame *frame, - struct tegra_vde_h264_frame *src, - enum dma_data_direction dma_dir, - bool baseline_profile, - size_t lsize, size_t csize) -{ - int err; - - err = tegra_vde_attach_dmabuf(vde, src->y_fd, - src->y_offset, lsize, SZ_256, - &frame->y_dmabuf_attachment, - &frame->y_addr, - NULL, dma_dir); - if (err) - return err; - - err = tegra_vde_attach_dmabuf(vde, src->cb_fd, - src->cb_offset, csize, SZ_256, - &frame->cb_dmabuf_attachment, - &frame->cb_addr, - NULL, dma_dir); - if (err) - goto err_release_y; - - err = tegra_vde_attach_dmabuf(vde, src->cr_fd, - src->cr_offset, csize, SZ_256, - &frame->cr_dmabuf_attachment, - &frame->cr_addr, - NULL, dma_dir); - if (err) - goto err_release_cb; - - if (baseline_profile) { - frame->aux_addr = 0x64DEAD00; - return 0; - } - - err = tegra_vde_attach_dmabuf(vde, src->aux_fd, - src->aux_offset, csize, SZ_256, - &frame->aux_dmabuf_attachment, - &frame->aux_addr, - NULL, dma_dir); - if (err) - goto err_release_cr; - - return 0; - -err_release_cr: - tegra_vde_dmabuf_cache_unmap(vde, frame->cr_dmabuf_attachment, true); -err_release_cb: - tegra_vde_dmabuf_cache_unmap(vde, frame->cb_dmabuf_attachment, true); -err_release_y: - tegra_vde_dmabuf_cache_unmap(vde, frame->y_dmabuf_attachment, true); - - return err; -} - -static void tegra_vde_release_frame_dmabufs(struct tegra_vde *vde, - struct tegra_video_frame *frame, - enum dma_data_direction dma_dir, - bool baseline_profile, - bool release) -{ - if (!baseline_profile) - tegra_vde_dmabuf_cache_unmap(vde, frame->aux_dmabuf_attachment, - release); - - tegra_vde_dmabuf_cache_unmap(vde, frame->cr_dmabuf_attachment, release); - tegra_vde_dmabuf_cache_unmap(vde, frame->cb_dmabuf_attachment, release); - tegra_vde_dmabuf_cache_unmap(vde, frame->y_dmabuf_attachment, release); -} - -static int tegra_vde_ioctl_decode_h264(struct tegra_vde *vde, - unsigned long vaddr) -{ - struct dma_buf_attachment *bitstream_data_dmabuf_attachment; - struct tegra_vde_h264_frame __user *frames_user; - size_t bitstream_data_size, lsize, csize; - struct device *dev = vde->miscdev.parent; - struct tegra_vde_h264_decoder_ctx ctx; - struct tegra_video_frame *dpb_frames; - struct tegra_vde_h264_frame *frames; - enum dma_data_direction dma_dir; - dma_addr_t bitstream_data_addr; - unsigned int macroblocks_nb; - unsigned int cstride; - unsigned int i; - int ret; - - if (copy_from_user(&ctx, (void __user *)vaddr, sizeof(ctx))) - return -EFAULT; - - ret = tegra_vde_validate_h264_ctx(dev, &ctx); - if (ret) - return ret; - - ret = tegra_vde_attach_dmabuf(vde, ctx.bitstream_data_fd, - ctx.bitstream_data_offset, - SZ_16K, SZ_16K, - &bitstream_data_dmabuf_attachment, - &bitstream_data_addr, - &bitstream_data_size, - DMA_TO_DEVICE); - if (ret) - return ret; - - frames = kmalloc_array(ctx.dpb_frames_nb, sizeof(*frames), GFP_KERNEL); - if (!frames) { - ret = -ENOMEM; - goto release_bitstream_dmabuf; - } - - dpb_frames = kcalloc(ctx.dpb_frames_nb, sizeof(*dpb_frames), - GFP_KERNEL); - if (!dpb_frames) { - ret = -ENOMEM; - goto free_frames; - } - - macroblocks_nb = ctx.pic_width_in_mbs * ctx.pic_height_in_mbs; - frames_user = u64_to_user_ptr(ctx.dpb_frames_ptr); - - if (copy_from_user(frames, frames_user, - ctx.dpb_frames_nb * sizeof(*frames))) { - ret = -EFAULT; - goto free_dpb_frames; - } - - cstride = ALIGN(ctx.pic_width_in_mbs * 8, 16); - csize = cstride * ctx.pic_height_in_mbs * 8; - lsize = macroblocks_nb * 256; - - for (i = 0; i < ctx.dpb_frames_nb; i++) { - ret = tegra_vde_validate_h264_frame(dev, &frames[i]); - if (ret) - goto release_dpb_frames; - - dpb_frames[i].flags = frames[i].flags; - dpb_frames[i].frame_num = frames[i].frame_num; - dpb_frames[i].luma_atoms_pitch = ctx.pic_width_in_mbs; - dpb_frames[i].chroma_atoms_pitch = cstride / VDE_ATOM; - - dma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - - ret = tegra_vde_attach_dmabufs_to_frame(vde, &dpb_frames[i], - &frames[i], dma_dir, - ctx.baseline_profile, - lsize, csize); - if (ret) - goto release_dpb_frames; - } - - ret = tegra_vde_decode_h264(vde, &ctx, dpb_frames, - bitstream_data_addr, bitstream_data_size); - -release_dpb_frames: - while (i--) { - dma_dir = (i == 0) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - - tegra_vde_release_frame_dmabufs(vde, &dpb_frames[i], dma_dir, - ctx.baseline_profile, ret != 0); - } - -free_dpb_frames: - kfree(dpb_frames); - -free_frames: - kfree(frames); - -release_bitstream_dmabuf: - tegra_vde_dmabuf_cache_unmap(vde, bitstream_data_dmabuf_attachment, - ret != 0); - - return ret; -} - -static long tegra_vde_unlocked_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct miscdevice *miscdev = filp->private_data; - struct tegra_vde *vde = container_of(miscdev, struct tegra_vde, - miscdev); - - switch (cmd) { - case TEGRA_VDE_IOCTL_DECODE_H264: - return tegra_vde_ioctl_decode_h264(vde, arg); - } - - dev_err(miscdev->parent, "Invalid IOCTL command %u\n", cmd); - - return -ENOTTY; -} - -static int tegra_vde_release_file(struct inode *inode, struct file *filp) -{ - struct miscdevice *miscdev = filp->private_data; - struct tegra_vde *vde = container_of(miscdev, struct tegra_vde, - miscdev); - - tegra_vde_dmabuf_cache_unmap_sync(vde); - - return 0; -} - -static const struct file_operations tegra_vde_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = tegra_vde_unlocked_ioctl, - .release = tegra_vde_release_file, -}; - static irqreturn_t tegra_vde_isr(int irq, void *data) { struct tegra_vde *vde = data; @@ -590,11 +328,6 @@ static int tegra_vde_probe(struct platform_device *pdev) mutex_init(&vde->lock); init_completion(&vde->decode_completion); - vde->miscdev.minor = MISC_DYNAMIC_MINOR; - vde->miscdev.name = "tegra_vde"; - vde->miscdev.fops = &tegra_vde_fops; - vde->miscdev.parent = dev; - err = tegra_vde_iommu_init(vde); if (err) { dev_err(dev, "Failed to initialize IOMMU: %d\n", err); @@ -622,22 +355,14 @@ static int tegra_vde_probe(struct platform_device *pdev) goto err_pm_runtime; } - err = misc_register(&vde->miscdev); - if (err) { - dev_err(dev, "Failed to register misc device: %d\n", err); - goto err_free_secure_bo; - } - err = tegra_vde_v4l2_init(vde); if (err) { dev_err(dev, "Failed to initialize V4L2: %d\n", err); - goto misc_unreg; + goto err_free_secure_bo; } return 0; -misc_unreg: - misc_deregister(&vde->miscdev); err_free_secure_bo: tegra_vde_free_bo(vde->secure_bo); err_pm_runtime: @@ -659,8 +384,6 @@ static int tegra_vde_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; tegra_vde_v4l2_deinit(vde); - misc_deregister(&vde->miscdev); - tegra_vde_free_bo(vde->secure_bo); /* diff --git a/drivers/staging/media/tegra-vde/vde.h b/drivers/staging/media/tegra-vde/vde.h index e0396bb0b986..0fbb1f3d2c88 100644 --- a/drivers/staging/media/tegra-vde/vde.h +++ b/drivers/staging/media/tegra-vde/vde.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -107,7 +106,6 @@ struct tegra_vde { struct mutex lock; struct mutex map_lock; struct list_head map_list; - struct miscdevice miscdev; struct reset_control *rst; struct reset_control *rst_mc; struct gen_pool *iram_pool; @@ -183,15 +181,6 @@ u32 tegra_vde_readl(struct tegra_vde *vde, void __iomem *base, u32 offset); void tegra_vde_set_bits(struct tegra_vde *vde, u32 mask, void __iomem *base, u32 offset); -int tegra_vde_validate_h264_frame(struct device *dev, - struct tegra_vde_h264_frame *frame); -int tegra_vde_validate_h264_ctx(struct device *dev, - struct tegra_vde_h264_decoder_ctx *ctx); -int tegra_vde_decode_h264(struct tegra_vde *vde, - struct tegra_vde_h264_decoder_ctx *ctx, - struct tegra_video_frame *dpb_frames, - dma_addr_t bitstream_data_addr, - size_t bitstream_data_size); int tegra_vde_h264_decode_run(struct tegra_ctx *ctx); int tegra_vde_h264_decode_wait(struct tegra_ctx *ctx); -- cgit v1.2.3 From a097abd401f208d5f8d6cb1727a37ee20b8658e2 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 20 Feb 2022 21:46:20 +0100 Subject: media: staging: tegra-vde: Bump BSEV DMA timeout BSEV DMA timeouts if VDE is downclocked by x10. Bump the timeout to allow DMA to complete. We don't support freq scaling yet, this is just a minor improvement which may become useful sometime later. Signed-off-by: Dmitry Osipenko Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/tegra-vde/h264.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/tegra-vde/h264.c b/drivers/staging/media/tegra-vde/h264.c index a46c648a26c6..d8e5534e80c8 100644 --- a/drivers/staging/media/tegra-vde/h264.c +++ b/drivers/staging/media/tegra-vde/h264.c @@ -135,7 +135,7 @@ static int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma) return 0; err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, - !(value & BSE_DMA_BUSY), 1, 100); + !(value & BSE_DMA_BUSY), 1, 1000); if (err) { dev_err(dev, "BSEV DMA timeout\n"); return err; -- cgit v1.2.3 From 8bd4aaf438e39f88e4321e0cad2d42284c2269af Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 20 Feb 2022 21:46:21 +0100 Subject: media: staging: tegra-vde: De-stage driver The TODO of tegra-vde driver has been completed, driver now supports V4L2 stateless video decoding API. Relocate driver to drivers/media. Signed-off-by: Dmitry Osipenko Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 2 +- drivers/media/platform/Kconfig | 17 + drivers/media/platform/Makefile | 2 + drivers/media/platform/tegra/vde/Makefile | 3 + drivers/media/platform/tegra/vde/dmabuf-cache.c | 229 +++++ drivers/media/platform/tegra/vde/h264.c | 946 +++++++++++++++++++++ drivers/media/platform/tegra/vde/iommu.c | 157 ++++ drivers/media/platform/tegra/vde/trace.h | 95 +++ drivers/media/platform/tegra/vde/v4l2.c | 1018 +++++++++++++++++++++++ drivers/media/platform/tegra/vde/vde.c | 551 ++++++++++++ drivers/media/platform/tegra/vde/vde.h | 242 ++++++ drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/tegra-vde/Kconfig | 17 - drivers/staging/media/tegra-vde/Makefile | 3 - drivers/staging/media/tegra-vde/TODO | 4 - drivers/staging/media/tegra-vde/dmabuf-cache.c | 229 ----- drivers/staging/media/tegra-vde/h264.c | 946 --------------------- drivers/staging/media/tegra-vde/iommu.c | 157 ---- drivers/staging/media/tegra-vde/trace.h | 95 --- drivers/staging/media/tegra-vde/v4l2.c | 1018 ----------------------- drivers/staging/media/tegra-vde/vde.c | 551 ------------ drivers/staging/media/tegra-vde/vde.h | 242 ------ 23 files changed, 3261 insertions(+), 3266 deletions(-) create mode 100644 drivers/media/platform/tegra/vde/Makefile create mode 100644 drivers/media/platform/tegra/vde/dmabuf-cache.c create mode 100644 drivers/media/platform/tegra/vde/h264.c create mode 100644 drivers/media/platform/tegra/vde/iommu.c create mode 100644 drivers/media/platform/tegra/vde/trace.h create mode 100644 drivers/media/platform/tegra/vde/v4l2.c create mode 100644 drivers/media/platform/tegra/vde/vde.c create mode 100644 drivers/media/platform/tegra/vde/vde.h delete mode 100644 drivers/staging/media/tegra-vde/Kconfig delete mode 100644 drivers/staging/media/tegra-vde/Makefile delete mode 100644 drivers/staging/media/tegra-vde/TODO delete mode 100644 drivers/staging/media/tegra-vde/dmabuf-cache.c delete mode 100644 drivers/staging/media/tegra-vde/h264.c delete mode 100644 drivers/staging/media/tegra-vde/iommu.c delete mode 100644 drivers/staging/media/tegra-vde/trace.h delete mode 100644 drivers/staging/media/tegra-vde/v4l2.c delete mode 100644 drivers/staging/media/tegra-vde/vde.c delete mode 100644 drivers/staging/media/tegra-vde/vde.h (limited to 'drivers/staging') diff --git a/MAINTAINERS b/MAINTAINERS index 83d27b57016f..f2d313bf0c54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11947,7 +11947,7 @@ L: linux-tegra@vger.kernel.org S: Maintained T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt -F: drivers/staging/media/tegra-vde/ +F: drivers/media/platform/tegra/vde/ MEDIA DRIVERS FOR RENESAS - CEU M: Jacopo Mondi diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 9fbdba0fd1e7..97a191a3c0a1 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -630,6 +630,23 @@ config VIDEO_SUN8I_ROTATE Support for the Allwinner DE2 rotation unit. To compile this driver as a module choose m here. +config VIDEO_TEGRA_VDE + tristate "NVIDIA Tegra Video Decoder Engine driver" + depends on ARCH_TEGRA || COMPILE_TEST + depends on VIDEO_DEV && VIDEO_V4L2 + select DMA_SHARED_BUFFER + select IOMMU_IOVA + select MEDIA_CONTROLLER + select MEDIA_CONTROLLER_REQUEST_API + select SRAM + select VIDEOBUF2_DMA_CONTIG + select VIDEOBUF2_DMA_SG + select V4L2_H264 + select V4L2_MEM2MEM_DEV + help + Support for the NVIDIA Tegra video decoder unit. + To compile this driver as a module choose m here. + endif # V4L_MEM2MEM_DRIVERS # TI VIDEO PORT Helper Modules diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 28eb4aadbf45..4c6fdca75b9f 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -89,3 +89,5 @@ obj-$(CONFIG_VIDEO_QCOM_VENUS) += qcom/venus/ obj-y += sunxi/ obj-$(CONFIG_VIDEO_MESON_GE2D) += meson/ge2d/ + +obj-$(CONFIG_VIDEO_TEGRA_VDE) += tegra/vde/ diff --git a/drivers/media/platform/tegra/vde/Makefile b/drivers/media/platform/tegra/vde/Makefile new file mode 100644 index 000000000000..4e96f3305567 --- /dev/null +++ b/drivers/media/platform/tegra/vde/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +tegra-vde-y := vde.o iommu.o dmabuf-cache.o h264.o v4l2.o +obj-$(CONFIG_VIDEO_TEGRA_VDE) += tegra-vde.o diff --git a/drivers/media/platform/tegra/vde/dmabuf-cache.c b/drivers/media/platform/tegra/vde/dmabuf-cache.c new file mode 100644 index 000000000000..69c346148070 --- /dev/null +++ b/drivers/media/platform/tegra/vde/dmabuf-cache.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2016-2019 GRATE-DRIVER project + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vde.h" + +MODULE_IMPORT_NS(DMA_BUF); + +struct tegra_vde_cache_entry { + enum dma_data_direction dma_dir; + struct dma_buf_attachment *a; + struct delayed_work dwork; + struct tegra_vde *vde; + struct list_head list; + struct sg_table *sgt; + struct iova *iova; + unsigned int refcnt; +}; + +static void tegra_vde_release_entry(struct tegra_vde_cache_entry *entry) +{ + struct dma_buf *dmabuf = entry->a->dmabuf; + + WARN_ON_ONCE(entry->refcnt); + + if (entry->vde->domain) + tegra_vde_iommu_unmap(entry->vde, entry->iova); + + dma_buf_unmap_attachment(entry->a, entry->sgt, entry->dma_dir); + dma_buf_detach(dmabuf, entry->a); + dma_buf_put(dmabuf); + + list_del(&entry->list); + kfree(entry); +} + +static void tegra_vde_delayed_unmap(struct work_struct *work) +{ + struct tegra_vde_cache_entry *entry; + struct tegra_vde *vde; + + entry = container_of(work, struct tegra_vde_cache_entry, + dwork.work); + vde = entry->vde; + + mutex_lock(&vde->map_lock); + tegra_vde_release_entry(entry); + mutex_unlock(&vde->map_lock); +} + +int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde, + struct dma_buf *dmabuf, + enum dma_data_direction dma_dir, + struct dma_buf_attachment **ap, + dma_addr_t *addrp) +{ + struct dma_buf_attachment *attachment; + struct tegra_vde_cache_entry *entry; + struct device *dev = vde->dev; + struct sg_table *sgt; + struct iova *iova; + int err; + + mutex_lock(&vde->map_lock); + + list_for_each_entry(entry, &vde->map_list, list) { + if (entry->a->dmabuf != dmabuf) + continue; + + if (!cancel_delayed_work(&entry->dwork)) + continue; + + if (entry->dma_dir != dma_dir) + entry->dma_dir = DMA_BIDIRECTIONAL; + + dma_buf_put(dmabuf); + + if (vde->domain) + *addrp = iova_dma_addr(&vde->iova, entry->iova); + else + *addrp = sg_dma_address(entry->sgt->sgl); + + goto ref; + } + + attachment = dma_buf_attach(dmabuf, dev); + if (IS_ERR(attachment)) { + dev_err(dev, "Failed to attach dmabuf\n"); + err = PTR_ERR(attachment); + goto err_unlock; + } + + sgt = dma_buf_map_attachment(attachment, dma_dir); + if (IS_ERR(sgt)) { + dev_err(dev, "Failed to get dmabufs sg_table\n"); + err = PTR_ERR(sgt); + goto err_detach; + } + + if (!vde->domain && sgt->nents > 1) { + dev_err(dev, "Sparse DMA region is unsupported, please enable IOMMU\n"); + err = -EINVAL; + goto err_unmap; + } + + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) { + err = -ENOMEM; + goto err_unmap; + } + + if (vde->domain) { + err = tegra_vde_iommu_map(vde, sgt, &iova, dmabuf->size); + if (err) + goto err_free; + + *addrp = iova_dma_addr(&vde->iova, iova); + } else { + *addrp = sg_dma_address(sgt->sgl); + iova = NULL; + } + + INIT_DELAYED_WORK(&entry->dwork, tegra_vde_delayed_unmap); + list_add(&entry->list, &vde->map_list); + + entry->dma_dir = dma_dir; + entry->iova = iova; + entry->vde = vde; + entry->sgt = sgt; + entry->a = attachment; +ref: + entry->refcnt++; + + *ap = entry->a; + + mutex_unlock(&vde->map_lock); + + return 0; + +err_free: + kfree(entry); +err_unmap: + dma_buf_unmap_attachment(attachment, sgt, dma_dir); +err_detach: + dma_buf_detach(dmabuf, attachment); +err_unlock: + mutex_unlock(&vde->map_lock); + + return err; +} + +void tegra_vde_dmabuf_cache_unmap(struct tegra_vde *vde, + struct dma_buf_attachment *a, + bool release) +{ + struct tegra_vde_cache_entry *entry; + + mutex_lock(&vde->map_lock); + + list_for_each_entry(entry, &vde->map_list, list) { + if (entry->a != a) + continue; + + WARN_ON_ONCE(!entry->refcnt); + + if (--entry->refcnt == 0) { + if (release) + tegra_vde_release_entry(entry); + else + schedule_delayed_work(&entry->dwork, 5 * HZ); + } + break; + } + + mutex_unlock(&vde->map_lock); +} + +void tegra_vde_dmabuf_cache_unmap_sync(struct tegra_vde *vde) +{ + struct tegra_vde_cache_entry *entry, *tmp; + + mutex_lock(&vde->map_lock); + + list_for_each_entry_safe(entry, tmp, &vde->map_list, list) { + if (entry->refcnt) + continue; + + if (!cancel_delayed_work(&entry->dwork)) + continue; + + tegra_vde_release_entry(entry); + } + + mutex_unlock(&vde->map_lock); +} + +void tegra_vde_dmabuf_cache_unmap_all(struct tegra_vde *vde) +{ + struct tegra_vde_cache_entry *entry, *tmp; + + mutex_lock(&vde->map_lock); + + while (!list_empty(&vde->map_list)) { + list_for_each_entry_safe(entry, tmp, &vde->map_list, list) { + if (!cancel_delayed_work(&entry->dwork)) + continue; + + tegra_vde_release_entry(entry); + } + + mutex_unlock(&vde->map_lock); + schedule(); + mutex_lock(&vde->map_lock); + } + + mutex_unlock(&vde->map_lock); +} diff --git a/drivers/media/platform/tegra/vde/h264.c b/drivers/media/platform/tegra/vde/h264.c new file mode 100644 index 000000000000..d8e5534e80c8 --- /dev/null +++ b/drivers/media/platform/tegra/vde/h264.c @@ -0,0 +1,946 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2016-2022 Dmitry Osipenko + * + */ + +#include +#include +#include +#include + +#include + +#include "trace.h" +#include "vde.h" + +#define FLAG_B_FRAME 0x1 +#define FLAG_REFERENCE 0x2 + +struct tegra_vde_h264_frame { + unsigned int frame_num; + unsigned int flags; +}; + +struct tegra_vde_h264_decoder_ctx { + unsigned int dpb_frames_nb; + unsigned int dpb_ref_frames_with_earlier_poc_nb; + unsigned int baseline_profile; + unsigned int level_idc; + unsigned int log2_max_pic_order_cnt_lsb; + unsigned int log2_max_frame_num; + unsigned int pic_order_cnt_type; + unsigned int direct_8x8_inference_flag; + unsigned int pic_width_in_mbs; + unsigned int pic_height_in_mbs; + unsigned int pic_init_qp; + unsigned int deblocking_filter_control_present_flag; + unsigned int constrained_intra_pred_flag; + unsigned int chroma_qp_index_offset; + unsigned int pic_order_present_flag; + unsigned int num_ref_idx_l0_active_minus1; + unsigned int num_ref_idx_l1_active_minus1; +}; + +struct h264_reflists { + u8 p[V4L2_H264_NUM_DPB_ENTRIES]; + u8 b0[V4L2_H264_NUM_DPB_ENTRIES]; + u8 b1[V4L2_H264_NUM_DPB_ENTRIES]; +}; + +static int tegra_vde_wait_mbe(struct tegra_vde *vde) +{ + u32 tmp; + + return readl_relaxed_poll_timeout(vde->mbe + 0x8C, tmp, + tmp >= 0x10, 1, 100); +} + +static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde, + unsigned int refs_nb, + bool setup_refs) +{ + u32 value, frame_idx_enb_mask = 0; + unsigned int frame_idx; + unsigned int idx; + int err; + + tegra_vde_writel(vde, 0xD0000000 | (0 << 23), vde->mbe, 0x80); + tegra_vde_writel(vde, 0xD0200000 | (0 << 23), vde->mbe, 0x80); + + err = tegra_vde_wait_mbe(vde); + if (err) + return err; + + if (!setup_refs) + return 0; + + for (idx = 0, frame_idx = 1; idx < refs_nb; idx++, frame_idx++) { + tegra_vde_writel(vde, 0xD0000000 | (frame_idx << 23), + vde->mbe, 0x80); + tegra_vde_writel(vde, 0xD0200000 | (frame_idx << 23), + vde->mbe, 0x80); + + frame_idx_enb_mask |= frame_idx << (6 * (idx % 4)); + + if (idx % 4 == 3 || idx == refs_nb - 1) { + value = 0xC0000000; + value |= (idx >> 2) << 24; + value |= frame_idx_enb_mask; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + err = tegra_vde_wait_mbe(vde); + if (err) + return err; + + frame_idx_enb_mask = 0; + } + } + + return 0; +} + +static void tegra_vde_mbe_set_0xa_reg(struct tegra_vde *vde, int reg, u32 val) +{ + tegra_vde_writel(vde, 0xA0000000 | (reg << 24) | (val & 0xFFFF), + vde->mbe, 0x80); + tegra_vde_writel(vde, 0xA0000000 | ((reg + 1) << 24) | (val >> 16), + vde->mbe, 0x80); +} + +static int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma) +{ + struct device *dev = vde->dev; + u32 value; + int err; + + err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, + !(value & BIT(2)), 1, 100); + if (err) { + dev_err(dev, "BSEV unknown bit timeout\n"); + return err; + } + + err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, + (value & BSE_ICMDQUE_EMPTY), 1, 100); + if (err) { + dev_err(dev, "BSEV ICMDQUE flush timeout\n"); + return err; + } + + if (!wait_dma) + return 0; + + err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, + !(value & BSE_DMA_BUSY), 1, 1000); + if (err) { + dev_err(dev, "BSEV DMA timeout\n"); + return err; + } + + return 0; +} + +static int tegra_vde_push_to_bsev_icmdqueue(struct tegra_vde *vde, + u32 value, bool wait_dma) +{ + tegra_vde_writel(vde, value, vde->bsev, ICMDQUE_WR); + + return tegra_vde_wait_bsev(vde, wait_dma); +} + +static void tegra_vde_setup_frameid(struct tegra_vde *vde, + struct tegra_video_frame *frame, + unsigned int frameid, + u32 mbs_width, u32 mbs_height) +{ + u32 y_addr = frame ? frame->y_addr : 0x6CDEAD00; + u32 cb_addr = frame ? frame->cb_addr : 0x6CDEAD00; + u32 cr_addr = frame ? frame->cr_addr : 0x6CDEAD00; + u32 value1 = frame ? ((frame->luma_atoms_pitch << 16) | mbs_height) : 0; + u32 value2 = frame ? ((frame->chroma_atoms_pitch << 6) | 1) : 0; + + tegra_vde_writel(vde, y_addr >> 8, vde->frameid, 0x000 + frameid * 4); + tegra_vde_writel(vde, cb_addr >> 8, vde->frameid, 0x100 + frameid * 4); + tegra_vde_writel(vde, cr_addr >> 8, vde->frameid, 0x180 + frameid * 4); + tegra_vde_writel(vde, value1, vde->frameid, 0x080 + frameid * 4); + tegra_vde_writel(vde, value2, vde->frameid, 0x280 + frameid * 4); +} + +static void tegra_setup_frameidx(struct tegra_vde *vde, + struct tegra_video_frame *frames, + unsigned int frames_nb, + u32 mbs_width, u32 mbs_height) +{ + unsigned int idx; + + for (idx = 0; idx < frames_nb; idx++) + tegra_vde_setup_frameid(vde, &frames[idx], idx, + mbs_width, mbs_height); + + for (; idx < 17; idx++) + tegra_vde_setup_frameid(vde, NULL, idx, 0, 0); +} + +static void tegra_vde_setup_iram_entry(struct tegra_vde *vde, + unsigned int table, + unsigned int row, + u32 value1, u32 value2) +{ + u32 *iram_tables = vde->iram; + + trace_vde_setup_iram_entry(table, row, value1, value2); + + iram_tables[0x20 * table + row * 2 + 0] = value1; + iram_tables[0x20 * table + row * 2 + 1] = value2; +} + +static void tegra_vde_setup_iram_tables(struct tegra_vde *vde, + struct tegra_video_frame *dpb_frames, + unsigned int ref_frames_nb, + unsigned int with_earlier_poc_nb) +{ + struct tegra_video_frame *frame; + int with_later_poc_nb; + u32 value, aux_addr; + unsigned int i, k; + + trace_vde_ref_l0(dpb_frames[0].frame_num); + + for (i = 0; i < 16; i++) { + if (i < ref_frames_nb) { + frame = &dpb_frames[i + 1]; + + aux_addr = frame->aux_addr; + + value = (i + 1) << 26; + value |= !(frame->flags & FLAG_B_FRAME) << 25; + value |= 1 << 24; + value |= frame->frame_num; + } else { + aux_addr = 0x6ADEAD00; + value = 0x3f; + } + + tegra_vde_setup_iram_entry(vde, 0, i, value, aux_addr); + tegra_vde_setup_iram_entry(vde, 1, i, value, aux_addr); + tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); + tegra_vde_setup_iram_entry(vde, 3, i, value, aux_addr); + } + + if (!(dpb_frames[0].flags & FLAG_B_FRAME)) + return; + + if (with_earlier_poc_nb >= ref_frames_nb) + return; + + with_later_poc_nb = ref_frames_nb - with_earlier_poc_nb; + + trace_vde_ref_l1(with_later_poc_nb, with_earlier_poc_nb); + + for (i = 0, k = with_earlier_poc_nb; i < with_later_poc_nb; i++, k++) { + frame = &dpb_frames[k + 1]; + + aux_addr = frame->aux_addr; + + value = (k + 1) << 26; + value |= !(frame->flags & FLAG_B_FRAME) << 25; + value |= 1 << 24; + value |= frame->frame_num; + + tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); + } + + for (k = 0; i < ref_frames_nb; i++, k++) { + frame = &dpb_frames[k + 1]; + + aux_addr = frame->aux_addr; + + value = (k + 1) << 26; + value |= !(frame->flags & FLAG_B_FRAME) << 25; + value |= 1 << 24; + value |= frame->frame_num; + + tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); + } +} + +static int tegra_vde_setup_hw_context(struct tegra_vde *vde, + struct tegra_vde_h264_decoder_ctx *ctx, + struct tegra_video_frame *dpb_frames, + dma_addr_t bitstream_data_addr, + size_t bitstream_data_size, + unsigned int macroblocks_nb) +{ + struct device *dev = vde->dev; + u32 value; + int err; + + tegra_vde_set_bits(vde, 0x000A, vde->sxe, 0xF0); + tegra_vde_set_bits(vde, 0x000B, vde->bsev, CMDQUE_CONTROL); + tegra_vde_set_bits(vde, 0x8002, vde->mbe, 0x50); + tegra_vde_set_bits(vde, 0x000A, vde->mbe, 0xA0); + tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x14); + tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x28); + tegra_vde_set_bits(vde, 0x0A00, vde->mce, 0x08); + tegra_vde_set_bits(vde, 0x000A, vde->tfe, 0x00); + tegra_vde_set_bits(vde, 0x0005, vde->vdma, 0x04); + + tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x1C); + tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x00); + tegra_vde_writel(vde, 0x00000007, vde->vdma, 0x04); + tegra_vde_writel(vde, 0x00000007, vde->frameid, 0x200); + tegra_vde_writel(vde, 0x00000005, vde->tfe, 0x04); + tegra_vde_writel(vde, 0x00000000, vde->mbe, 0x84); + tegra_vde_writel(vde, 0x00000010, vde->sxe, 0x08); + tegra_vde_writel(vde, 0x00000150, vde->sxe, 0x54); + tegra_vde_writel(vde, 0x0000054C, vde->sxe, 0x58); + tegra_vde_writel(vde, 0x00000E34, vde->sxe, 0x5C); + tegra_vde_writel(vde, 0x063C063C, vde->mce, 0x10); + tegra_vde_writel(vde, 0x0003FC00, vde->bsev, INTR_STATUS); + tegra_vde_writel(vde, 0x0000150D, vde->bsev, BSE_CONFIG); + tegra_vde_writel(vde, 0x00000100, vde->bsev, BSE_INT_ENB); + tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x98); + tegra_vde_writel(vde, 0x00000060, vde->bsev, 0x9C); + + memset(vde->iram + 128, 0, macroblocks_nb / 2); + + tegra_setup_frameidx(vde, dpb_frames, ctx->dpb_frames_nb, + ctx->pic_width_in_mbs, ctx->pic_height_in_mbs); + + tegra_vde_setup_iram_tables(vde, dpb_frames, + ctx->dpb_frames_nb - 1, + ctx->dpb_ref_frames_with_earlier_poc_nb); + + /* + * The IRAM mapping is write-combine, ensure that CPU buffers have + * been flushed at this point. + */ + wmb(); + + tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x8C); + tegra_vde_writel(vde, bitstream_data_addr + bitstream_data_size, + vde->bsev, 0x54); + + vde->bitstream_data_addr = bitstream_data_addr; + + value = ctx->pic_width_in_mbs << 11 | ctx->pic_height_in_mbs << 3; + + tegra_vde_writel(vde, value, vde->bsev, 0x88); + + err = tegra_vde_wait_bsev(vde, false); + if (err) + return err; + + err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x800003FC, false); + if (err) + return err; + + value = 0x01500000; + value |= ((vde->iram_lists_addr + 512) >> 2) & 0xFFFF; + + err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); + if (err) + return err; + + err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x840F054C, false); + if (err) + return err; + + err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x80000080, false); + if (err) + return err; + + value = 0x0E340000 | ((vde->iram_lists_addr >> 2) & 0xFFFF); + + err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); + if (err) + return err; + + value = 0x00800005; + value |= ctx->pic_width_in_mbs << 11; + value |= ctx->pic_height_in_mbs << 3; + + tegra_vde_writel(vde, value, vde->sxe, 0x10); + + value = !ctx->baseline_profile << 17; + value |= ctx->level_idc << 13; + value |= ctx->log2_max_pic_order_cnt_lsb << 7; + value |= ctx->pic_order_cnt_type << 5; + value |= ctx->log2_max_frame_num; + + tegra_vde_writel(vde, value, vde->sxe, 0x40); + + value = ctx->pic_init_qp << 25; + value |= !!(ctx->deblocking_filter_control_present_flag) << 2; + value |= !!ctx->pic_order_present_flag; + + tegra_vde_writel(vde, value, vde->sxe, 0x44); + + value = ctx->chroma_qp_index_offset; + value |= ctx->num_ref_idx_l0_active_minus1 << 5; + value |= ctx->num_ref_idx_l1_active_minus1 << 10; + value |= !!ctx->constrained_intra_pred_flag << 15; + + tegra_vde_writel(vde, value, vde->sxe, 0x48); + + value = 0x0C000000; + value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 24; + + tegra_vde_writel(vde, value, vde->sxe, 0x4C); + + value = 0x03800000; + value |= bitstream_data_size & GENMASK(19, 15); + + tegra_vde_writel(vde, value, vde->sxe, 0x68); + + tegra_vde_writel(vde, bitstream_data_addr, vde->sxe, 0x6C); + + if (vde->soc->supports_ref_pic_marking) + tegra_vde_writel(vde, vde->secure_bo->dma_addr, vde->sxe, 0x7c); + + value = 0x10000005; + value |= ctx->pic_width_in_mbs << 11; + value |= ctx->pic_height_in_mbs << 3; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + value = 0x26800000; + value |= ctx->level_idc << 4; + value |= !ctx->baseline_profile << 1; + value |= !!ctx->direct_8x8_inference_flag; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + tegra_vde_writel(vde, 0xF4000001, vde->mbe, 0x80); + tegra_vde_writel(vde, 0x20000000, vde->mbe, 0x80); + tegra_vde_writel(vde, 0xF4000101, vde->mbe, 0x80); + + value = 0x20000000; + value |= ctx->chroma_qp_index_offset << 8; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + err = tegra_vde_setup_mbe_frame_idx(vde, + ctx->dpb_frames_nb - 1, + ctx->pic_order_cnt_type == 0); + if (err) { + dev_err(dev, "MBE frames setup failed %d\n", err); + return err; + } + + tegra_vde_mbe_set_0xa_reg(vde, 0, 0x000009FC); + tegra_vde_mbe_set_0xa_reg(vde, 2, 0x61DEAD00); + tegra_vde_mbe_set_0xa_reg(vde, 4, 0x62DEAD00); + tegra_vde_mbe_set_0xa_reg(vde, 6, 0x63DEAD00); + tegra_vde_mbe_set_0xa_reg(vde, 8, dpb_frames[0].aux_addr); + + value = 0xFC000000; + value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 2; + + if (!ctx->baseline_profile) + value |= !!(dpb_frames[0].flags & FLAG_REFERENCE) << 1; + + tegra_vde_writel(vde, value, vde->mbe, 0x80); + + err = tegra_vde_wait_mbe(vde); + if (err) { + dev_err(dev, "MBE programming failed %d\n", err); + return err; + } + + return 0; +} + +static void tegra_vde_decode_frame(struct tegra_vde *vde, + unsigned int macroblocks_nb) +{ + reinit_completion(&vde->decode_completion); + + tegra_vde_writel(vde, 0x00000001, vde->bsev, 0x8C); + tegra_vde_writel(vde, 0x20000000 | (macroblocks_nb - 1), + vde->sxe, 0x00); +} + +static int tegra_vde_validate_h264_ctx(struct device *dev, + struct tegra_vde_h264_decoder_ctx *ctx) +{ + if (ctx->dpb_frames_nb == 0 || ctx->dpb_frames_nb > 17) { + dev_err(dev, "Bad DPB size %u\n", ctx->dpb_frames_nb); + return -EINVAL; + } + + if (ctx->level_idc > 15) { + dev_err(dev, "Bad level value %u\n", ctx->level_idc); + return -EINVAL; + } + + if (ctx->pic_init_qp > 52) { + dev_err(dev, "Bad pic_init_qp value %u\n", ctx->pic_init_qp); + return -EINVAL; + } + + if (ctx->log2_max_pic_order_cnt_lsb > 16) { + dev_err(dev, "Bad log2_max_pic_order_cnt_lsb value %u\n", + ctx->log2_max_pic_order_cnt_lsb); + return -EINVAL; + } + + if (ctx->log2_max_frame_num > 16) { + dev_err(dev, "Bad log2_max_frame_num value %u\n", + ctx->log2_max_frame_num); + return -EINVAL; + } + + if (ctx->chroma_qp_index_offset > 31) { + dev_err(dev, "Bad chroma_qp_index_offset value %u\n", + ctx->chroma_qp_index_offset); + return -EINVAL; + } + + if (ctx->pic_order_cnt_type > 2) { + dev_err(dev, "Bad pic_order_cnt_type value %u\n", + ctx->pic_order_cnt_type); + return -EINVAL; + } + + if (ctx->num_ref_idx_l0_active_minus1 > 15) { + dev_err(dev, "Bad num_ref_idx_l0_active_minus1 value %u\n", + ctx->num_ref_idx_l0_active_minus1); + return -EINVAL; + } + + if (ctx->num_ref_idx_l1_active_minus1 > 15) { + dev_err(dev, "Bad num_ref_idx_l1_active_minus1 value %u\n", + ctx->num_ref_idx_l1_active_minus1); + return -EINVAL; + } + + if (!ctx->pic_width_in_mbs || ctx->pic_width_in_mbs > 127) { + dev_err(dev, "Bad pic_width_in_mbs value %u\n", + ctx->pic_width_in_mbs); + return -EINVAL; + } + + if (!ctx->pic_height_in_mbs || ctx->pic_height_in_mbs > 127) { + dev_err(dev, "Bad pic_height_in_mbs value %u\n", + ctx->pic_height_in_mbs); + return -EINVAL; + } + + return 0; +} + +static int tegra_vde_decode_begin(struct tegra_vde *vde, + struct tegra_vde_h264_decoder_ctx *ctx, + struct tegra_video_frame *dpb_frames, + dma_addr_t bitstream_data_addr, + size_t bitstream_data_size) +{ + struct device *dev = vde->dev; + unsigned int macroblocks_nb; + int err; + + err = mutex_lock_interruptible(&vde->lock); + if (err) + return err; + + err = pm_runtime_resume_and_get(dev); + if (err < 0) + goto unlock; + + /* + * We rely on the VDE registers reset value, otherwise VDE + * causes bus lockup. + */ + err = reset_control_assert(vde->rst_mc); + if (err) { + dev_err(dev, "DEC start: Failed to assert MC reset: %d\n", + err); + goto put_runtime_pm; + } + + err = reset_control_reset(vde->rst); + if (err) { + dev_err(dev, "DEC start: Failed to reset HW: %d\n", err); + goto put_runtime_pm; + } + + err = reset_control_deassert(vde->rst_mc); + if (err) { + dev_err(dev, "DEC start: Failed to deassert MC reset: %d\n", + err); + goto put_runtime_pm; + } + + macroblocks_nb = ctx->pic_width_in_mbs * ctx->pic_height_in_mbs; + + err = tegra_vde_setup_hw_context(vde, ctx, dpb_frames, + bitstream_data_addr, + bitstream_data_size, + macroblocks_nb); + if (err) + goto put_runtime_pm; + + tegra_vde_decode_frame(vde, macroblocks_nb); + + return 0; + +put_runtime_pm: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + +unlock: + mutex_unlock(&vde->lock); + + return err; +} + +static void tegra_vde_decode_abort(struct tegra_vde *vde) +{ + struct device *dev = vde->dev; + int err; + + /* + * At first reset memory client to avoid resetting VDE HW in the + * middle of DMA which could result into memory corruption or hang + * the whole system. + */ + err = reset_control_assert(vde->rst_mc); + if (err) + dev_err(dev, "DEC end: Failed to assert MC reset: %d\n", err); + + err = reset_control_assert(vde->rst); + if (err) + dev_err(dev, "DEC end: Failed to assert HW reset: %d\n", err); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + mutex_unlock(&vde->lock); +} + +static int tegra_vde_decode_end(struct tegra_vde *vde) +{ + unsigned int read_bytes, macroblocks_nb; + struct device *dev = vde->dev; + dma_addr_t bsev_ptr; + long timeout; + int ret; + + timeout = wait_for_completion_interruptible_timeout( + &vde->decode_completion, msecs_to_jiffies(1000)); + if (timeout == 0) { + bsev_ptr = tegra_vde_readl(vde, vde->bsev, 0x10); + macroblocks_nb = tegra_vde_readl(vde, vde->sxe, 0xC8) & 0x1FFF; + read_bytes = bsev_ptr ? bsev_ptr - vde->bitstream_data_addr : 0; + + dev_err(dev, "Decoding failed: read 0x%X bytes, %u macroblocks parsed\n", + read_bytes, macroblocks_nb); + + ret = -EIO; + } else if (timeout < 0) { + ret = timeout; + } else { + ret = 0; + } + + tegra_vde_decode_abort(vde); + + return ret; +} + +static struct vb2_buffer *get_ref_buf(struct tegra_ctx *ctx, + struct vb2_v4l2_buffer *dst, + unsigned int dpb_idx) +{ + const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + int buf_idx = -1; + + if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + buf_idx = vb2_find_timestamp(cap_q, + dpb[dpb_idx].reference_ts, 0); + + /* + * If a DPB entry is unused or invalid, address of current destination + * buffer is returned. + */ + if (buf_idx < 0) + return &dst->vb2_buf; + + return vb2_get_buffer(cap_q, buf_idx); +} + +static int tegra_vde_validate_vb_size(struct tegra_ctx *ctx, + struct vb2_buffer *vb, + unsigned int plane_id, + size_t min_size) +{ + u64 offset = vb->planes[plane_id].data_offset; + struct device *dev = ctx->vde->dev; + + if (offset + min_size > vb2_plane_size(vb, plane_id)) { + dev_err(dev, "Too small plane[%u] size %lu @0x%llX, should be at least %zu\n", + plane_id, vb2_plane_size(vb, plane_id), offset, min_size); + return -EINVAL; + } + + return 0; +} + +static int tegra_vde_h264_setup_frame(struct tegra_ctx *ctx, + struct tegra_vde_h264_decoder_ctx *h264, + struct v4l2_h264_reflist_builder *b, + struct vb2_buffer *vb, + unsigned int ref_id, + unsigned int id) +{ + struct v4l2_pix_format_mplane *pixfmt = &ctx->decoded_fmt.fmt.pix_mp; + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); + struct tegra_ctx_h264 *h = &ctx->h264; + struct tegra_vde *vde = ctx->vde; + struct device *dev = vde->dev; + unsigned int cstride, lstride; + unsigned int flags = 0; + size_t lsize, csize; + int err, frame_num; + + lsize = h264->pic_width_in_mbs * 16 * h264->pic_height_in_mbs * 16; + csize = h264->pic_width_in_mbs * 8 * h264->pic_height_in_mbs * 8; + lstride = pixfmt->plane_fmt[0].bytesperline; + cstride = pixfmt->plane_fmt[1].bytesperline; + + err = tegra_vde_validate_vb_size(ctx, vb, 0, lsize); + if (err) + return err; + + err = tegra_vde_validate_vb_size(ctx, vb, 1, csize); + if (err) + return err; + + err = tegra_vde_validate_vb_size(ctx, vb, 2, csize); + if (err) + return err; + + if (!tb->aux || tb->aux->size < csize) { + dev_err(dev, "Too small aux size %zd, should be at least %zu\n", + tb->aux ? tb->aux->size : -1, csize); + return -EINVAL; + } + + if (id == 0) { + frame_num = h->decode_params->frame_num; + + if (h->decode_params->nal_ref_idc) + flags |= FLAG_REFERENCE; + } else { + frame_num = b->refs[ref_id].frame_num; + } + + if (tb->b_frame) + flags |= FLAG_B_FRAME; + + vde->frames[id].flags = flags; + vde->frames[id].y_addr = tb->dma_addr[0]; + vde->frames[id].cb_addr = tb->dma_addr[1]; + vde->frames[id].cr_addr = tb->dma_addr[2]; + vde->frames[id].aux_addr = tb->aux->dma_addr; + vde->frames[id].frame_num = frame_num & 0x7fffff; + vde->frames[id].luma_atoms_pitch = lstride / VDE_ATOM; + vde->frames[id].chroma_atoms_pitch = cstride / VDE_ATOM; + + return 0; +} + +static int tegra_vde_h264_setup_frames(struct tegra_ctx *ctx, + struct tegra_vde_h264_decoder_ctx *h264) +{ + struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct vb2_v4l2_buffer *dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(&dst->vb2_buf); + struct tegra_ctx_h264 *h = &ctx->h264; + struct v4l2_h264_reflist_builder b; + struct h264_reflists reflists; + struct vb2_buffer *ref; + unsigned int i; + u8 *dpb_id; + int err; + + /* + * Tegra hardware requires information about frame's type, assuming + * that frame consists of the same type slices. Userspace must tag + * frame's type appropriately. + * + * Decoding of a non-uniform frames isn't supported by hardware and + * require software preprocessing that we don't implement. Decoding + * is expected to fail in this case. Such video streams are rare in + * practice, so not a big deal. + * + * If userspace doesn't tell us frame's type, then we will try decode + * as-is. + */ + v4l2_m2m_buf_copy_metadata(src, dst, true); + + if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) + tb->b_frame = true; + else + tb->b_frame = false; + + err = tegra_vde_h264_setup_frame(ctx, h264, NULL, &dst->vb2_buf, 0, + h264->dpb_frames_nb++); + if (err) + return err; + + if (!(h->decode_params->flags & (V4L2_H264_DECODE_PARAM_FLAG_PFRAME | + V4L2_H264_DECODE_PARAM_FLAG_BFRAME))) + return 0; + + v4l2_h264_init_reflist_builder(&b, h->decode_params, h->sps, dpb); + + if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) { + v4l2_h264_build_b_ref_lists(&b, reflists.b0, reflists.b1); + dpb_id = reflists.b0; + } else { + v4l2_h264_build_p_ref_list(&b, reflists.p); + dpb_id = reflists.p; + } + + for (i = 0; i < b.num_valid; i++) { + ref = get_ref_buf(ctx, dst, dpb_id[i]); + + err = tegra_vde_h264_setup_frame(ctx, h264, &b, ref, dpb_id[i], + h264->dpb_frames_nb++); + if (err) + return err; + + if (b.refs[dpb_id[i]].pic_order_count < b.cur_pic_order_count) + h264->dpb_ref_frames_with_earlier_poc_nb++; + } + + return 0; +} + +static unsigned int to_tegra_vde_h264_level_idc(unsigned int level_idc) +{ + switch (level_idc) { + case 11: + return 2; + case 12: + return 3; + case 13: + return 4; + case 20: + return 5; + case 21: + return 6; + case 22: + return 7; + case 30: + return 8; + case 31: + return 9; + case 32: + return 10; + case 40: + return 11; + case 41: + return 12; + case 42: + return 13; + case 50: + return 14; + default: + break; + } + + return 15; +} + +static int tegra_vde_h264_setup_context(struct tegra_ctx *ctx, + struct tegra_vde_h264_decoder_ctx *h264) +{ + struct tegra_ctx_h264 *h = &ctx->h264; + struct tegra_vde *vde = ctx->vde; + struct device *dev = vde->dev; + int err; + + memset(h264, 0, sizeof(*h264)); + memset(vde->frames, 0, sizeof(vde->frames)); + + tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); + tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_SPS); + tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_PPS); + + /* CABAC unsupported by hardware, requires software preprocessing */ + if (h->pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) + return -EOPNOTSUPP; + + if (h->sps->profile_idc == 66) + h264->baseline_profile = 1; + + if (h->sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) + h264->direct_8x8_inference_flag = 1; + + if (h->pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) + h264->constrained_intra_pred_flag = 1; + + if (h->pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) + h264->deblocking_filter_control_present_flag = 1; + + if (h->pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT) + h264->pic_order_present_flag = 1; + + h264->level_idc = to_tegra_vde_h264_level_idc(h->sps->level_idc); + h264->log2_max_pic_order_cnt_lsb = h->sps->log2_max_pic_order_cnt_lsb_minus4 + 4; + h264->log2_max_frame_num = h->sps->log2_max_frame_num_minus4 + 4; + h264->pic_order_cnt_type = h->sps->pic_order_cnt_type; + h264->pic_width_in_mbs = h->sps->pic_width_in_mbs_minus1 + 1; + h264->pic_height_in_mbs = h->sps->pic_height_in_map_units_minus1 + 1; + + h264->num_ref_idx_l0_active_minus1 = h->pps->num_ref_idx_l0_default_active_minus1; + h264->num_ref_idx_l1_active_minus1 = h->pps->num_ref_idx_l1_default_active_minus1; + h264->chroma_qp_index_offset = h->pps->chroma_qp_index_offset & 0x1f; + h264->pic_init_qp = h->pps->pic_init_qp_minus26 + 26; + + err = tegra_vde_h264_setup_frames(ctx, h264); + if (err) + return err; + + err = tegra_vde_validate_h264_ctx(dev, h264); + if (err) + return err; + + return 0; +} + +int tegra_vde_h264_decode_run(struct tegra_ctx *ctx) +{ + struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct tegra_m2m_buffer *bitstream = vb_to_tegra_buf(&src->vb2_buf); + size_t bitstream_size = vb2_get_plane_payload(&src->vb2_buf, 0); + struct tegra_vde_h264_decoder_ctx h264; + struct tegra_vde *vde = ctx->vde; + int err; + + err = tegra_vde_h264_setup_context(ctx, &h264); + if (err) + return err; + + err = tegra_vde_decode_begin(vde, &h264, vde->frames, + bitstream->dma_addr[0], + bitstream_size); + if (err) + return err; + + return 0; +} + +int tegra_vde_h264_decode_wait(struct tegra_ctx *ctx) +{ + return tegra_vde_decode_end(ctx->vde); +} diff --git a/drivers/media/platform/tegra/vde/iommu.c b/drivers/media/platform/tegra/vde/iommu.c new file mode 100644 index 000000000000..5521ed3e465f --- /dev/null +++ b/drivers/media/platform/tegra/vde/iommu.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2016-2019 GRATE-DRIVER project + */ + +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) +#include +#endif + +#include "vde.h" + +int tegra_vde_iommu_map(struct tegra_vde *vde, + struct sg_table *sgt, + struct iova **iovap, + size_t size) +{ + struct iova *iova; + unsigned long shift; + unsigned long end; + dma_addr_t addr; + + end = vde->domain->geometry.aperture_end; + size = iova_align(&vde->iova, size); + shift = iova_shift(&vde->iova); + + iova = alloc_iova(&vde->iova, size >> shift, end >> shift, true); + if (!iova) + return -ENOMEM; + + addr = iova_dma_addr(&vde->iova, iova); + + size = iommu_map_sgtable(vde->domain, addr, sgt, + IOMMU_READ | IOMMU_WRITE); + if (!size) { + __free_iova(&vde->iova, iova); + return -ENXIO; + } + + *iovap = iova; + + return 0; +} + +void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova) +{ + unsigned long shift = iova_shift(&vde->iova); + unsigned long size = iova_size(iova) << shift; + dma_addr_t addr = iova_dma_addr(&vde->iova, iova); + + iommu_unmap(vde->domain, addr, size); + __free_iova(&vde->iova, iova); +} + +int tegra_vde_iommu_init(struct tegra_vde *vde) +{ + struct device *dev = vde->dev; + struct iova *iova; + unsigned long order; + unsigned long shift; + int err; + + vde->group = iommu_group_get(dev); + if (!vde->group) + return 0; + +#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) + if (dev->archdata.mapping) { + struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); + + arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); + } +#endif + vde->domain = iommu_domain_alloc(&platform_bus_type); + if (!vde->domain) { + err = -ENOMEM; + goto put_group; + } + + err = iova_cache_get(); + if (err) + goto free_domain; + + order = __ffs(vde->domain->pgsize_bitmap); + init_iova_domain(&vde->iova, 1UL << order, 0); + + err = iommu_attach_group(vde->domain, vde->group); + if (err) + goto put_iova; + + /* + * We're using some static addresses that are not accessible by VDE + * to trap invalid memory accesses. + */ + shift = iova_shift(&vde->iova); + iova = reserve_iova(&vde->iova, 0x60000000 >> shift, + 0x70000000 >> shift); + if (!iova) { + err = -ENOMEM; + goto detach_group; + } + + vde->iova_resv_static_addresses = iova; + + /* + * BSEV's end-address wraps around due to integer overflow during + * of hardware context preparation if IOVA is allocated at the end + * of address space and VDE can't handle that. Hence simply reserve + * the last page to avoid the problem. + */ + iova = reserve_iova(&vde->iova, 0xffffffff >> shift, + (0xffffffff >> shift) + 1); + if (!iova) { + err = -ENOMEM; + goto unreserve_iova; + } + + vde->iova_resv_last_page = iova; + + return 0; + +unreserve_iova: + __free_iova(&vde->iova, vde->iova_resv_static_addresses); +detach_group: + iommu_detach_group(vde->domain, vde->group); +put_iova: + put_iova_domain(&vde->iova); + iova_cache_put(); +free_domain: + iommu_domain_free(vde->domain); +put_group: + iommu_group_put(vde->group); + + return err; +} + +void tegra_vde_iommu_deinit(struct tegra_vde *vde) +{ + if (vde->domain) { + __free_iova(&vde->iova, vde->iova_resv_last_page); + __free_iova(&vde->iova, vde->iova_resv_static_addresses); + iommu_detach_group(vde->domain, vde->group); + put_iova_domain(&vde->iova); + iova_cache_put(); + iommu_domain_free(vde->domain); + iommu_group_put(vde->group); + + vde->domain = NULL; + } +} diff --git a/drivers/media/platform/tegra/vde/trace.h b/drivers/media/platform/tegra/vde/trace.h new file mode 100644 index 000000000000..77358ddfdb8f --- /dev/null +++ b/drivers/media/platform/tegra/vde/trace.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM tegra_vde + +#if !defined(TEGRA_VDE_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define TEGRA_VDE_TRACE_H + +#include + +#include "vde.h" + +DECLARE_EVENT_CLASS(register_access, + TP_PROTO(struct tegra_vde *vde, void __iomem *base, + u32 offset, u32 value), + TP_ARGS(vde, base, offset, value), + TP_STRUCT__entry( + __string(hw_name, tegra_vde_reg_base_name(vde, base)) + __field(u32, offset) + __field(u32, value) + ), + TP_fast_assign( + __assign_str(hw_name, tegra_vde_reg_base_name(vde, base)); + __entry->offset = offset; + __entry->value = value; + ), + TP_printk("%s:0x%03x 0x%08x", __get_str(hw_name), __entry->offset, + __entry->value) +); + +DEFINE_EVENT(register_access, vde_writel, + TP_PROTO(struct tegra_vde *vde, void __iomem *base, + u32 offset, u32 value), + TP_ARGS(vde, base, offset, value)); +DEFINE_EVENT(register_access, vde_readl, + TP_PROTO(struct tegra_vde *vde, void __iomem *base, + u32 offset, u32 value), + TP_ARGS(vde, base, offset, value)); + +TRACE_EVENT(vde_setup_iram_entry, + TP_PROTO(unsigned int table, unsigned int row, u32 value, u32 aux_addr), + TP_ARGS(table, row, value, aux_addr), + TP_STRUCT__entry( + __field(unsigned int, table) + __field(unsigned int, row) + __field(u32, value) + __field(u32, aux_addr) + ), + TP_fast_assign( + __entry->table = table; + __entry->row = row; + __entry->value = value; + __entry->aux_addr = aux_addr; + ), + TP_printk("[%u][%u] = { 0x%08x (flags = \"%s\", frame_num = %u); 0x%08x }", + __entry->table, __entry->row, __entry->value, + __print_flags(__entry->value, " ", { (1 << 25), "B" }), + __entry->value & 0x7FFFFF, __entry->aux_addr) +); + +TRACE_EVENT(vde_ref_l0, + TP_PROTO(unsigned int frame_num), + TP_ARGS(frame_num), + TP_STRUCT__entry( + __field(unsigned int, frame_num) + ), + TP_fast_assign( + __entry->frame_num = frame_num; + ), + TP_printk("REF L0: DPB: Frame 0: frame_num = %u", __entry->frame_num) +); + +TRACE_EVENT(vde_ref_l1, + TP_PROTO(unsigned int with_later_poc_nb, + unsigned int with_earlier_poc_nb), + TP_ARGS(with_later_poc_nb, with_earlier_poc_nb), + TP_STRUCT__entry( + __field(unsigned int, with_later_poc_nb) + __field(unsigned int, with_earlier_poc_nb) + ), + TP_fast_assign( + __entry->with_later_poc_nb = with_later_poc_nb; + __entry->with_earlier_poc_nb = with_earlier_poc_nb; + ), + TP_printk("REF L1: with_later_poc_nb %u, with_earlier_poc_nb %u", + __entry->with_later_poc_nb, __entry->with_earlier_poc_nb) +); + +#endif /* TEGRA_VDE_TRACE_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH ../../drivers/media/platform/tegra/vde +#define TRACE_INCLUDE_FILE trace +#include diff --git a/drivers/media/platform/tegra/vde/v4l2.c b/drivers/media/platform/tegra/vde/v4l2.c new file mode 100644 index 000000000000..bd8c207d5b54 --- /dev/null +++ b/drivers/media/platform/tegra/vde/v4l2.c @@ -0,0 +1,1018 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2019-2022 Dmitry Osipenko + * + * Based on Cedrus driver by Bootlin. + * Copyright (C) 2016 Florent Revest + * Copyright (C) 2018 Paul Kocialkowski + * + * Based on Rockchip driver by Collabora. + * Copyright (C) 2019 Boris Brezillon + */ + +#include +#include + +#include "vde.h" + +static const struct v4l2_ctrl_config ctrl_cfgs[] = { + { .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, }, + { .id = V4L2_CID_STATELESS_H264_SPS, }, + { .id = V4L2_CID_STATELESS_H264_PPS, }, + { + .id = V4L2_CID_STATELESS_H264_DECODE_MODE, + .min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + .def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, + }, + { + .id = V4L2_CID_STATELESS_H264_START_CODE, + .min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + .def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .max = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, + .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + }, +}; + +static inline struct tegra_ctx *fh_to_tegra_ctx(struct v4l2_fh *fh) +{ + return container_of(fh, struct tegra_ctx, fh); +} + +static void tegra_set_control_data(struct tegra_ctx *ctx, void *data, u32 id) +{ + switch (id) { + case V4L2_CID_STATELESS_H264_DECODE_PARAMS: + ctx->h264.decode_params = data; + break; + case V4L2_CID_STATELESS_H264_SPS: + ctx->h264.sps = data; + break; + case V4L2_CID_STATELESS_H264_PPS: + ctx->h264.pps = data; + break; + } +} + +void tegra_vde_prepare_control_data(struct tegra_ctx *ctx, u32 id) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ctrl_cfgs); i++) { + if (ctx->ctrls[i]->id == id) { + tegra_set_control_data(ctx, ctx->ctrls[i]->p_cur.p, id); + return; + } + } + + tegra_set_control_data(ctx, NULL, id); +} + +static int tegra_queue_setup(struct vb2_queue *vq, + unsigned int *nbufs, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + struct v4l2_format *f; + unsigned int i; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + f = &ctx->coded_fmt; + else + f = &ctx->decoded_fmt; + + if (*num_planes) { + if (*num_planes != f->fmt.pix_mp.num_planes) + return -EINVAL; + + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { + if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage) + return -EINVAL; + } + } else { + *num_planes = f->fmt.pix_mp.num_planes; + + for (i = 0; i < f->fmt.pix_mp.num_planes; i++) + sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + return 0; +} + +static int tegra_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + +static void __tegra_buf_cleanup(struct vb2_buffer *vb, unsigned int i) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); + + while (i--) { + if (tb->a[i]) { + tegra_vde_dmabuf_cache_unmap(ctx->vde, tb->a[i], true); + tb->a[i] = NULL; + } + + if (tb->iova[i]) { + tegra_vde_iommu_unmap(ctx->vde, tb->iova[i]); + tb->iova[i] = NULL; + } + } + + if (tb->aux) { + tegra_vde_free_bo(tb->aux); + tb->aux = NULL; + } +} + +static int tegra_buf_init(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); + struct tegra_vde *vde = ctx->vde; + enum dma_data_direction dma_dir; + struct sg_table *sgt; + unsigned int i; + int err; + + if (V4L2_TYPE_IS_CAPTURE(vq->type) && vb->num_planes > 1) { + /* + * Tegra decoder writes auxiliary data for I/P frames. + * This data is needed for decoding of B frames. + */ + err = tegra_vde_alloc_bo(vde, &tb->aux, DMA_FROM_DEVICE, + vb2_plane_size(vb, 1)); + if (err) + return err; + } + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + dma_dir = DMA_TO_DEVICE; + else + dma_dir = DMA_FROM_DEVICE; + + for (i = 0; i < vb->num_planes; i++) { + if (vq->memory == VB2_MEMORY_DMABUF) { + get_dma_buf(vb->planes[i].dbuf); + + err = tegra_vde_dmabuf_cache_map(vde, vb->planes[i].dbuf, + dma_dir, &tb->a[i], + &tb->dma_base[i]); + if (err) { + dma_buf_put(vb->planes[i].dbuf); + goto cleanup; + } + + continue; + } + + if (vde->domain) { + sgt = vb2_dma_sg_plane_desc(vb, i); + + err = tegra_vde_iommu_map(vde, sgt, &tb->iova[i], + vb2_plane_size(vb, i)); + if (err) + goto cleanup; + + tb->dma_base[i] = iova_dma_addr(&vde->iova, tb->iova[i]); + } else { + tb->dma_base[i] = vb2_dma_contig_plane_dma_addr(vb, i); + } + } + + return 0; + +cleanup: + __tegra_buf_cleanup(vb, i); + + return err; +} + +static void tegra_buf_cleanup(struct vb2_buffer *vb) +{ + __tegra_buf_cleanup(vb, vb->num_planes); +} + +static int tegra_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); + size_t hw_align, hw_size, hw_payload, size, offset; + struct v4l2_pix_format_mplane *pixfmt; + unsigned int i; + void *vb_data; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + hw_align = BSEV_ALIGN; + pixfmt = &ctx->coded_fmt.fmt.pix_mp; + } else { + hw_align = FRAMEID_ALIGN; + pixfmt = &ctx->decoded_fmt.fmt.pix_mp; + } + + for (i = 0; i < vb->num_planes; i++) { + offset = vb->planes[i].data_offset; + + if (offset & (hw_align - 1)) + return -EINVAL; + + if (V4L2_TYPE_IS_CAPTURE(vq->type)) { + size = pixfmt->plane_fmt[i].sizeimage; + hw_payload = ALIGN(size, VDE_ATOM); + } else { + size = vb2_get_plane_payload(vb, i) - offset; + hw_payload = ALIGN(size + VDE_ATOM, SXE_BUFFER); + } + + hw_size = offset + hw_payload; + + if (vb2_plane_size(vb, i) < hw_size) + return -EINVAL; + + vb2_set_plane_payload(vb, i, hw_payload); + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) { + vb_data = vb2_plane_vaddr(vb, i); + + /* + * Hardware requires zero-padding of coded data. + * Otherwise it will fail to parse the trailing + * data and abort the decoding. + */ + if (vb_data) + memset(vb_data + offset + size, 0, + hw_size - offset - size); + } + + tb->dma_addr[i] = tb->dma_base[i] + offset; + } + + switch (pixfmt->pixelformat) { + case V4L2_PIX_FMT_YVU420M: + swap(tb->dma_addr[1], tb->dma_addr[2]); + break; + } + + return 0; +} + +static void tegra_buf_queue(struct vb2_buffer *vb) +{ + struct tegra_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static void tegra_buf_request_complete(struct vb2_buffer *vb) +{ + struct tegra_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); +} + +static int tegra_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + return 0; +} + +static void tegra_stop_streaming(struct vb2_queue *vq) +{ + struct tegra_ctx *ctx = vb2_get_drv_priv(vq); + + while (true) { + struct vb2_v4l2_buffer *vbuf; + + if (V4L2_TYPE_IS_OUTPUT(vq->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + if (!vbuf) + break; + + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &ctx->hdl); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + } +} + +static const struct vb2_ops tegra_qops = { + .queue_setup = tegra_queue_setup, + .buf_init = tegra_buf_init, + .buf_cleanup = tegra_buf_cleanup, + .buf_prepare = tegra_buf_prepare, + .buf_queue = tegra_buf_queue, + .buf_out_validate = tegra_buf_out_validate, + .buf_request_complete = tegra_buf_request_complete, + .start_streaming = tegra_start_streaming, + .stop_streaming = tegra_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int tegra_queue_init(void *priv, + struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct tegra_ctx *ctx = priv; + struct tegra_vde *vde = ctx->vde; + const struct vb2_mem_ops *mem_ops; + unsigned long dma_attrs; + int err; + + /* + * TODO: Switch to use of vb2_dma_contig_memops uniformly once we + * will add IOMMU_DOMAIN support for video decoder to tegra-smmu + * driver. For now we need to stick with SG ops in order to be able + * to get SGT table easily. This is suboptimal since SG mappings are + * wasting CPU cache and we don't need that caching. + */ + if (vde->domain) + mem_ops = &vb2_dma_sg_memops; + else + mem_ops = &vb2_dma_contig_memops; + + dma_attrs = DMA_ATTR_WRITE_COMBINE; + + src_vq->buf_struct_size = sizeof(struct tegra_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->supports_requests = true; + src_vq->requires_requests = true; + src_vq->lock = &vde->v4l2_lock; + src_vq->dma_attrs = dma_attrs; + src_vq->mem_ops = mem_ops; + src_vq->ops = &tegra_qops; + src_vq->drv_priv = ctx; + src_vq->dev = vde->dev; + + err = vb2_queue_init(src_vq); + if (err) { + v4l2_err(&vde->v4l2_dev, + "failed to initialize src queue: %d\n", err); + return err; + } + + /* + * We may need to zero the end of bitstream in kernel if userspace + * doesn't do that, hence kmap is needed for the coded data. It's not + * needed for framebuffers. + */ + dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; + + dst_vq->buf_struct_size = sizeof(struct tegra_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->lock = &vde->v4l2_lock; + dst_vq->dma_attrs = dma_attrs; + dst_vq->mem_ops = mem_ops; + dst_vq->ops = &tegra_qops; + dst_vq->drv_priv = ctx; + dst_vq->dev = vde->dev; + + err = vb2_queue_init(dst_vq); + if (err) { + v4l2_err(&vde->v4l2_dev, + "failed to initialize dst queue: %d\n", err); + return err; + } + + return 0; +} + +static void tegra_reset_fmt(struct tegra_ctx *ctx, struct v4l2_format *f, + u32 fourcc) +{ + memset(f, 0, sizeof(*f)); + f->fmt.pix_mp.pixelformat = fourcc; + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; +} + +static void tegra_reset_coded_fmt(struct tegra_ctx *ctx) +{ + const struct tegra_vde_soc *soc = ctx->vde->soc; + struct v4l2_format *f = &ctx->coded_fmt; + + ctx->coded_fmt_desc = &soc->coded_fmts[0]; + tegra_reset_fmt(ctx, f, ctx->coded_fmt_desc->fourcc); + + f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + f->fmt.pix_mp.width = ctx->coded_fmt_desc->frmsize.min_width; + f->fmt.pix_mp.height = ctx->coded_fmt_desc->frmsize.min_height; +} + +static void tegra_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, + u32 pixelformat, u32 width, u32 height) +{ + const struct v4l2_format_info *info = v4l2_format_info(pixelformat); + struct v4l2_plane_pix_format *plane; + unsigned int i; + + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_YVU420M: + pixfmt->width = width; + pixfmt->height = height; + pixfmt->pixelformat = pixelformat; + pixfmt->num_planes = info->mem_planes; + + for (i = 0; i < pixfmt->num_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : 2; + unsigned int vdiv = (i == 0) ? 1 : 2; + + /* + * VDE is connected to Graphics Memory using 128bit port, + * all memory accesses are made using 16B atoms. + * + * V4L requires Cb/Cr strides to be exactly half of the + * Y stride, hence we're aligning Y to 16B x 2. + */ + plane = &pixfmt->plane_fmt[i]; + plane->bytesperline = ALIGN(width, VDE_ATOM * 2) / hdiv; + plane->sizeimage = plane->bytesperline * height / vdiv; + } + + break; + } +} + +static void tegra_reset_decoded_fmt(struct tegra_ctx *ctx) +{ + struct v4l2_format *f = &ctx->decoded_fmt; + + tegra_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]); + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + tegra_fill_pixfmt_mp(&f->fmt.pix_mp, + ctx->coded_fmt_desc->decoded_fmts[0], + ctx->coded_fmt.fmt.pix_mp.width, + ctx->coded_fmt.fmt.pix_mp.height); +} + +static void tegra_job_finish(struct tegra_ctx *ctx, + enum vb2_buffer_state result) +{ + v4l2_m2m_buf_done_and_job_finish(ctx->vde->m2m, ctx->fh.m2m_ctx, + result); +} + +static void tegra_decode_complete(struct work_struct *work) +{ + struct tegra_ctx *ctx = container_of(work, struct tegra_ctx, work); + int err; + + err = ctx->coded_fmt_desc->decode_wait(ctx); + if (err) + tegra_job_finish(ctx, VB2_BUF_STATE_ERROR); + else + tegra_job_finish(ctx, VB2_BUF_STATE_DONE); +} + +static int tegra_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->bus_info, "platform:tegra-vde", sizeof(cap->bus_info)); + strscpy(cap->driver, "tegra-vde", sizeof(cap->driver)); + strscpy(cap->card, "tegra-vde", sizeof(cap->card)); + + return 0; +} + +static int tegra_enum_decoded_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + + if (WARN_ON(!ctx->coded_fmt_desc)) + return -EINVAL; + + if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts) + return -EINVAL; + + f->pixelformat = ctx->coded_fmt_desc->decoded_fmts[f->index]; + + return 0; +} + +static int tegra_g_decoded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + + *f = ctx->decoded_fmt; + return 0; +} + +static int tegra_try_decoded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + const struct tegra_coded_fmt_desc *coded_desc; + unsigned int i; + + /* + * The codec context should point to a coded format desc, if the format + * on the coded end has not been set yet, it should point to the + * default value. + */ + coded_desc = ctx->coded_fmt_desc; + if (WARN_ON(!coded_desc)) + return -EINVAL; + + if (!coded_desc->num_decoded_fmts) + return -EINVAL; + + for (i = 0; i < coded_desc->num_decoded_fmts; i++) { + if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) + break; + } + + if (i == coded_desc->num_decoded_fmts) + pix_mp->pixelformat = coded_desc->decoded_fmts[0]; + + /* always apply the frmsize constraint of the coded end */ + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &coded_desc->frmsize); + + tegra_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, + pix_mp->width, pix_mp->height); + pix_mp->field = V4L2_FIELD_NONE; + + return 0; +} + +static int tegra_s_decoded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct vb2_queue *vq; + int err; + + /* change not allowed if queue is busy */ + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (vb2_is_busy(vq)) + return -EBUSY; + + err = tegra_try_decoded_fmt(file, priv, f); + if (err) + return err; + + ctx->decoded_fmt = *f; + + return 0; +} + +static int tegra_enum_coded_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + const struct tegra_vde_soc *soc = ctx->vde->soc; + + if (f->index >= soc->num_coded_fmts) + return -EINVAL; + + f->pixelformat = soc->coded_fmts[f->index].fourcc; + + return 0; +} + +static int tegra_g_coded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + + *f = ctx->coded_fmt; + return 0; +} + +static const struct tegra_coded_fmt_desc * +tegra_find_coded_fmt_desc(struct tegra_ctx *ctx, u32 fourcc) +{ + const struct tegra_vde_soc *soc = ctx->vde->soc; + unsigned int i; + + for (i = 0; i < soc->num_coded_fmts; i++) { + if (soc->coded_fmts[i].fourcc == fourcc) + return &soc->coded_fmts[i]; + } + + return NULL; +} + +static int tegra_try_coded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + const struct tegra_vde_soc *soc = ctx->vde->soc; + int size = pix_mp->plane_fmt[0].sizeimage; + const struct tegra_coded_fmt_desc *desc; + + desc = tegra_find_coded_fmt_desc(ctx, pix_mp->pixelformat); + if (!desc) { + pix_mp->pixelformat = soc->coded_fmts[0].fourcc; + desc = &soc->coded_fmts[0]; + } + + v4l2_apply_frmsize_constraints(&pix_mp->width, + &pix_mp->height, + &desc->frmsize); + + pix_mp->plane_fmt[0].sizeimage = max(ALIGN(size, SXE_BUFFER), SZ_2M); + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->num_planes = 1; + + return 0; +} + +static int tegra_s_coded_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; + const struct tegra_coded_fmt_desc *desc; + struct vb2_queue *peer_vq, *vq; + struct v4l2_format *cap_fmt; + int err; + + /* + * In order to support dynamic resolution change, the decoder admits + * a resolution change, as long as the pixelformat remains. Can't be + * done if streaming. + */ + vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + if (vb2_is_streaming(vq) || + (vb2_is_busy(vq) && + f->fmt.pix_mp.pixelformat != ctx->coded_fmt.fmt.pix_mp.pixelformat)) + return -EBUSY; + + /* + * Since format change on the OUTPUT queue will reset the CAPTURE + * queue, we can't allow doing so when the CAPTURE queue has buffers + * allocated. + */ + peer_vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (vb2_is_busy(peer_vq)) + return -EBUSY; + + err = tegra_try_coded_fmt(file, priv, f); + if (err) + return err; + + desc = tegra_find_coded_fmt_desc(ctx, f->fmt.pix_mp.pixelformat); + if (!desc) + return -EINVAL; + + ctx->coded_fmt_desc = desc; + ctx->coded_fmt = *f; + + /* + * Current decoded format might have become invalid with newly + * selected codec, so reset it to default just to be safe and + * keep internal driver state sane. User is mandated to set + * the decoded format again after we return, so we don't need + * anything smarter. + * + * Note that this will propagates any size changes to the decoded format. + */ + tegra_reset_decoded_fmt(ctx); + + /* propagate colorspace information to capture */ + cap_fmt = &ctx->decoded_fmt; + cap_fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + cap_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + cap_fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + cap_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + + return 0; +} + +static int tegra_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); + const struct tegra_coded_fmt_desc *fmt; + + if (fsize->index) + return -EINVAL; + + fmt = tegra_find_coded_fmt_desc(ctx, fsize->pixel_format); + if (!fmt) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = fmt->frmsize; + + return 0; +} + +static const struct v4l2_ioctl_ops tegra_v4l2_ioctl_ops = { + .vidioc_querycap = tegra_querycap, + .vidioc_enum_framesizes = tegra_enum_framesizes, + + .vidioc_try_fmt_vid_out_mplane = tegra_try_coded_fmt, + .vidioc_g_fmt_vid_out_mplane = tegra_g_coded_fmt, + .vidioc_s_fmt_vid_out_mplane = tegra_s_coded_fmt, + .vidioc_enum_fmt_vid_out = tegra_enum_coded_fmt, + + .vidioc_try_fmt_vid_cap_mplane = tegra_try_decoded_fmt, + .vidioc_g_fmt_vid_cap_mplane = tegra_g_decoded_fmt, + .vidioc_s_fmt_vid_cap_mplane = tegra_s_decoded_fmt, + .vidioc_enum_fmt_vid_cap = tegra_enum_decoded_fmt, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int tegra_init_ctrls(struct tegra_ctx *ctx) +{ + unsigned int i; + int err; + + err = v4l2_ctrl_handler_init(&ctx->hdl, ARRAY_SIZE(ctrl_cfgs)); + if (err) + return err; + + for (i = 0; i < ARRAY_SIZE(ctrl_cfgs); i++) { + ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->hdl, &ctrl_cfgs[i], + NULL); + if (ctx->hdl.error) { + err = ctx->hdl.error; + goto free_ctrls; + } + } + + err = v4l2_ctrl_handler_setup(&ctx->hdl); + if (err) + goto free_ctrls; + + ctx->fh.ctrl_handler = &ctx->hdl; + + return 0; + +free_ctrls: + v4l2_ctrl_handler_free(&ctx->hdl); + + return err; +} + +static int tegra_init_m2m(struct tegra_ctx *ctx) +{ + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(ctx->vde->m2m, + ctx, tegra_queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) + return PTR_ERR(ctx->fh.m2m_ctx); + + return 0; +} + +static int tegra_open(struct file *file) +{ + struct tegra_vde *vde = video_drvdata(file); + struct tegra_ctx *ctx; + int err; + + ctx = kzalloc(offsetof(struct tegra_ctx, ctrls[ARRAY_SIZE(ctrl_cfgs)]), + GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->vde = vde; + v4l2_fh_init(&ctx->fh, video_devdata(file)); + INIT_WORK(&ctx->work, tegra_decode_complete); + + err = tegra_init_ctrls(ctx); + if (err) { + v4l2_err(&vde->v4l2_dev, "failed to add controls: %d\n", err); + goto free_ctx; + } + + err = tegra_init_m2m(ctx); + if (err) { + v4l2_err(&vde->v4l2_dev, "failed to initialize m2m: %d\n", err); + goto free_ctrls; + } + + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + tegra_reset_coded_fmt(ctx); + tegra_try_coded_fmt(file, file->private_data, &ctx->coded_fmt); + + tegra_reset_decoded_fmt(ctx); + tegra_try_decoded_fmt(file, file->private_data, &ctx->decoded_fmt); + + return 0; + +free_ctrls: + v4l2_ctrl_handler_free(&ctx->hdl); +free_ctx: + kfree(ctx); + + return err; +} + +static int tegra_release(struct file *file) +{ + struct v4l2_fh *fh = file->private_data; + struct tegra_ctx *ctx = fh_to_tegra_ctx(fh); + struct tegra_vde *vde = ctx->vde; + + v4l2_fh_del(fh); + v4l2_m2m_ctx_release(fh->m2m_ctx); + v4l2_ctrl_handler_free(&ctx->hdl); + v4l2_fh_exit(fh); + kfree(ctx); + + tegra_vde_dmabuf_cache_unmap_sync(vde); + + return 0; +} + +static const struct v4l2_file_operations tegra_v4l2_fops = { + .owner = THIS_MODULE, + .open = tegra_open, + .poll = v4l2_m2m_fop_poll, + .mmap = v4l2_m2m_fop_mmap, + .release = tegra_release, + .unlocked_ioctl = video_ioctl2, +}; + +static void tegra_device_run(void *priv) +{ + struct tegra_ctx *ctx = priv; + struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + struct media_request *src_req = src->vb2_buf.req_obj.req; + int err; + + v4l2_ctrl_request_setup(src_req, &ctx->hdl); + + err = ctx->coded_fmt_desc->decode_run(ctx); + + v4l2_ctrl_request_complete(src_req, &ctx->hdl); + + if (err) + tegra_job_finish(ctx, VB2_BUF_STATE_ERROR); + else + queue_work(ctx->vde->wq, &ctx->work); +} + +static const struct v4l2_m2m_ops tegra_v4l2_m2m_ops = { + .device_run = tegra_device_run, +}; + +static int tegra_request_validate(struct media_request *req) +{ + unsigned int count; + + count = vb2_request_buffer_cnt(req); + if (!count) + return -ENOENT; + else if (count > 1) + return -EINVAL; + + return vb2_request_validate(req); +} + +static const struct media_device_ops tegra_media_device_ops = { + .req_validate = tegra_request_validate, + .req_queue = v4l2_m2m_request_queue, +}; + +int tegra_vde_v4l2_init(struct tegra_vde *vde) +{ + struct device *dev = vde->dev; + int err; + + mutex_init(&vde->v4l2_lock); + media_device_init(&vde->mdev); + video_set_drvdata(&vde->vdev, vde); + + vde->vdev.lock = &vde->v4l2_lock, + vde->vdev.fops = &tegra_v4l2_fops, + vde->vdev.vfl_dir = VFL_DIR_M2M, + vde->vdev.release = video_device_release_empty, + vde->vdev.v4l2_dev = &vde->v4l2_dev; + vde->vdev.ioctl_ops = &tegra_v4l2_ioctl_ops, + vde->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, + + vde->v4l2_dev.mdev = &vde->mdev; + vde->mdev.ops = &tegra_media_device_ops; + vde->mdev.dev = dev; + + strscpy(vde->mdev.model, "tegra-vde", sizeof(vde->mdev.model)); + strscpy(vde->vdev.name, "tegra-vde", sizeof(vde->vdev.name)); + strscpy(vde->mdev.bus_info, "platform:tegra-vde", + sizeof(vde->mdev.bus_info)); + + vde->wq = create_workqueue("tegra-vde"); + if (!vde->wq) + return -ENOMEM; + + err = media_device_register(&vde->mdev); + if (err) { + dev_err(dev, "failed to register media device: %d\n", err); + goto clean_up_media_device; + } + + err = v4l2_device_register(dev, &vde->v4l2_dev); + if (err) { + dev_err(dev, "failed to register v4l2 device: %d\n", err); + goto unreg_media_device; + } + + err = video_register_device(&vde->vdev, VFL_TYPE_VIDEO, -1); + if (err) { + dev_err(dev, "failed to register video device: %d\n", err); + goto unreg_v4l2; + } + + vde->m2m = v4l2_m2m_init(&tegra_v4l2_m2m_ops); + err = PTR_ERR_OR_ZERO(vde->m2m); + if (err) { + dev_err(dev, "failed to initialize m2m device: %d\n", err); + goto unreg_video_device; + } + + err = v4l2_m2m_register_media_controller(vde->m2m, &vde->vdev, + MEDIA_ENT_F_PROC_VIDEO_DECODER); + if (err) { + dev_err(dev, "failed to register media controller: %d\n", err); + goto release_m2m; + } + + v4l2_info(&vde->v4l2_dev, "v4l2 device registered as /dev/video%d\n", + vde->vdev.num); + + return 0; + +release_m2m: + v4l2_m2m_release(vde->m2m); +unreg_video_device: + video_unregister_device(&vde->vdev); +unreg_v4l2: + v4l2_device_unregister(&vde->v4l2_dev); +unreg_media_device: + media_device_unregister(&vde->mdev); +clean_up_media_device: + media_device_cleanup(&vde->mdev); + + destroy_workqueue(vde->wq); + + return err; +} + +void tegra_vde_v4l2_deinit(struct tegra_vde *vde) +{ + v4l2_m2m_unregister_media_controller(vde->m2m); + v4l2_m2m_release(vde->m2m); + + video_unregister_device(&vde->vdev); + v4l2_device_unregister(&vde->v4l2_dev); + + media_device_unregister(&vde->mdev); + media_device_cleanup(&vde->mdev); + + destroy_workqueue(vde->wq); +} diff --git a/drivers/media/platform/tegra/vde/vde.c b/drivers/media/platform/tegra/vde/vde.c new file mode 100644 index 000000000000..f3e863a94c5a --- /dev/null +++ b/drivers/media/platform/tegra/vde/vde.c @@ -0,0 +1,551 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2016-2017 Dmitry Osipenko + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "vde.h" + +#define CREATE_TRACE_POINTS +#include "trace.h" + +void tegra_vde_writel(struct tegra_vde *vde, u32 value, + void __iomem *base, u32 offset) +{ + trace_vde_writel(vde, base, offset, value); + + writel_relaxed(value, base + offset); +} + +u32 tegra_vde_readl(struct tegra_vde *vde, void __iomem *base, u32 offset) +{ + u32 value = readl_relaxed(base + offset); + + trace_vde_readl(vde, base, offset, value); + + return value; +} + +void tegra_vde_set_bits(struct tegra_vde *vde, u32 mask, + void __iomem *base, u32 offset) +{ + u32 value = tegra_vde_readl(vde, base, offset); + + tegra_vde_writel(vde, value | mask, base, offset); +} + +int tegra_vde_alloc_bo(struct tegra_vde *vde, + struct tegra_vde_bo **ret_bo, + enum dma_data_direction dma_dir, + size_t size) +{ + struct device *dev = vde->dev; + struct tegra_vde_bo *bo; + int err; + + bo = kzalloc(sizeof(*bo), GFP_KERNEL); + if (!bo) + return -ENOMEM; + + bo->vde = vde; + bo->size = size; + bo->dma_dir = dma_dir; + bo->dma_attrs = DMA_ATTR_WRITE_COMBINE | + DMA_ATTR_NO_KERNEL_MAPPING; + + if (!vde->domain) + bo->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS; + + bo->dma_cookie = dma_alloc_attrs(dev, bo->size, &bo->dma_handle, + GFP_KERNEL, bo->dma_attrs); + if (!bo->dma_cookie) { + dev_err(dev, "Failed to allocate DMA buffer of size: %zu\n", + bo->size); + err = -ENOMEM; + goto free_bo; + } + + err = dma_get_sgtable_attrs(dev, &bo->sgt, bo->dma_cookie, + bo->dma_handle, bo->size, bo->dma_attrs); + if (err) { + dev_err(dev, "Failed to get DMA buffer SG table: %d\n", err); + goto free_attrs; + } + + err = dma_map_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs); + if (err) { + dev_err(dev, "Failed to map DMA buffer SG table: %d\n", err); + goto free_table; + } + + if (vde->domain) { + err = tegra_vde_iommu_map(vde, &bo->sgt, &bo->iova, bo->size); + if (err) { + dev_err(dev, "Failed to map DMA buffer IOVA: %d\n", err); + goto unmap_sgtable; + } + + bo->dma_addr = iova_dma_addr(&vde->iova, bo->iova); + } else { + bo->dma_addr = sg_dma_address(bo->sgt.sgl); + } + + *ret_bo = bo; + + return 0; + +unmap_sgtable: + dma_unmap_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs); +free_table: + sg_free_table(&bo->sgt); +free_attrs: + dma_free_attrs(dev, bo->size, bo->dma_cookie, bo->dma_handle, + bo->dma_attrs); +free_bo: + kfree(bo); + + return err; +} + +void tegra_vde_free_bo(struct tegra_vde_bo *bo) +{ + struct tegra_vde *vde = bo->vde; + struct device *dev = vde->dev; + + if (vde->domain) + tegra_vde_iommu_unmap(vde, bo->iova); + + dma_unmap_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs); + + sg_free_table(&bo->sgt); + + dma_free_attrs(dev, bo->size, bo->dma_cookie, bo->dma_handle, + bo->dma_attrs); + kfree(bo); +} + +static irqreturn_t tegra_vde_isr(int irq, void *data) +{ + struct tegra_vde *vde = data; + + if (completion_done(&vde->decode_completion)) + return IRQ_NONE; + + tegra_vde_set_bits(vde, 0, vde->frameid, 0x208); + complete(&vde->decode_completion); + + return IRQ_HANDLED; +} + +static __maybe_unused int tegra_vde_runtime_suspend(struct device *dev) +{ + struct tegra_vde *vde = dev_get_drvdata(dev); + int err; + + if (!dev->pm_domain) { + err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC); + if (err) { + dev_err(dev, "Failed to power down HW: %d\n", err); + return err; + } + } + + clk_disable_unprepare(vde->clk); + reset_control_release(vde->rst); + reset_control_release(vde->rst_mc); + + return 0; +} + +static __maybe_unused int tegra_vde_runtime_resume(struct device *dev) +{ + struct tegra_vde *vde = dev_get_drvdata(dev); + int err; + + err = reset_control_acquire(vde->rst_mc); + if (err) { + dev_err(dev, "Failed to acquire mc reset: %d\n", err); + return err; + } + + err = reset_control_acquire(vde->rst); + if (err) { + dev_err(dev, "Failed to acquire reset: %d\n", err); + goto release_mc_reset; + } + + if (!dev->pm_domain) { + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC, + vde->clk, vde->rst); + if (err) { + dev_err(dev, "Failed to power up HW : %d\n", err); + goto release_reset; + } + } else { + /* + * tegra_powergate_sequence_power_up() leaves clocks enabled, + * while GENPD not. + */ + err = clk_prepare_enable(vde->clk); + if (err) { + dev_err(dev, "Failed to enable clock: %d\n", err); + goto release_reset; + } + } + + return 0; + +release_reset: + reset_control_release(vde->rst); +release_mc_reset: + reset_control_release(vde->rst_mc); + + return err; +} + +static int tegra_vde_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra_vde *vde; + int irq, err; + + vde = devm_kzalloc(dev, sizeof(*vde), GFP_KERNEL); + if (!vde) + return -ENOMEM; + + platform_set_drvdata(pdev, vde); + + vde->soc = of_device_get_match_data(&pdev->dev); + vde->dev = dev; + + vde->sxe = devm_platform_ioremap_resource_byname(pdev, "sxe"); + if (IS_ERR(vde->sxe)) + return PTR_ERR(vde->sxe); + + vde->bsev = devm_platform_ioremap_resource_byname(pdev, "bsev"); + if (IS_ERR(vde->bsev)) + return PTR_ERR(vde->bsev); + + vde->mbe = devm_platform_ioremap_resource_byname(pdev, "mbe"); + if (IS_ERR(vde->mbe)) + return PTR_ERR(vde->mbe); + + vde->ppe = devm_platform_ioremap_resource_byname(pdev, "ppe"); + if (IS_ERR(vde->ppe)) + return PTR_ERR(vde->ppe); + + vde->mce = devm_platform_ioremap_resource_byname(pdev, "mce"); + if (IS_ERR(vde->mce)) + return PTR_ERR(vde->mce); + + vde->tfe = devm_platform_ioremap_resource_byname(pdev, "tfe"); + if (IS_ERR(vde->tfe)) + return PTR_ERR(vde->tfe); + + vde->ppb = devm_platform_ioremap_resource_byname(pdev, "ppb"); + if (IS_ERR(vde->ppb)) + return PTR_ERR(vde->ppb); + + vde->vdma = devm_platform_ioremap_resource_byname(pdev, "vdma"); + if (IS_ERR(vde->vdma)) + return PTR_ERR(vde->vdma); + + vde->frameid = devm_platform_ioremap_resource_byname(pdev, "frameid"); + if (IS_ERR(vde->frameid)) + return PTR_ERR(vde->frameid); + + vde->clk = devm_clk_get(dev, NULL); + if (IS_ERR(vde->clk)) { + err = PTR_ERR(vde->clk); + dev_err(dev, "Could not get VDE clk %d\n", err); + return err; + } + + vde->rst = devm_reset_control_get_exclusive_released(dev, NULL); + if (IS_ERR(vde->rst)) { + err = PTR_ERR(vde->rst); + dev_err(dev, "Could not get VDE reset %d\n", err); + return err; + } + + vde->rst_mc = devm_reset_control_get_optional_exclusive_released(dev, "mc"); + if (IS_ERR(vde->rst_mc)) { + err = PTR_ERR(vde->rst_mc); + dev_err(dev, "Could not get MC reset %d\n", err); + return err; + } + + irq = platform_get_irq_byname(pdev, "sync-token"); + if (irq < 0) + return irq; + + err = devm_request_irq(dev, irq, tegra_vde_isr, 0, + dev_name(dev), vde); + if (err) { + dev_err(dev, "Could not request IRQ %d\n", err); + return err; + } + + err = devm_tegra_core_dev_init_opp_table_common(dev); + if (err) { + dev_err(dev, "Could initialize OPP table %d\n", err); + return err; + } + + vde->iram_pool = of_gen_pool_get(dev->of_node, "iram", 0); + if (!vde->iram_pool) { + dev_err(dev, "Could not get IRAM pool\n"); + return -EPROBE_DEFER; + } + + vde->iram = gen_pool_dma_alloc(vde->iram_pool, + gen_pool_size(vde->iram_pool), + &vde->iram_lists_addr); + if (!vde->iram) { + dev_err(dev, "Could not reserve IRAM\n"); + return -ENOMEM; + } + + INIT_LIST_HEAD(&vde->map_list); + mutex_init(&vde->map_lock); + mutex_init(&vde->lock); + init_completion(&vde->decode_completion); + + err = tegra_vde_iommu_init(vde); + if (err) { + dev_err(dev, "Failed to initialize IOMMU: %d\n", err); + goto err_gen_free; + } + + pm_runtime_enable(dev); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, 300); + + /* + * VDE partition may be left ON after bootloader, hence let's + * power-cycle it in order to put hardware into a predictable lower + * power state. + */ + err = pm_runtime_resume_and_get(dev); + if (err) + goto err_pm_runtime; + + pm_runtime_put(dev); + + err = tegra_vde_alloc_bo(vde, &vde->secure_bo, DMA_FROM_DEVICE, 4096); + if (err) { + dev_err(dev, "Failed to allocate secure BO: %d\n", err); + goto err_pm_runtime; + } + + err = tegra_vde_v4l2_init(vde); + if (err) { + dev_err(dev, "Failed to initialize V4L2: %d\n", err); + goto err_free_secure_bo; + } + + return 0; + +err_free_secure_bo: + tegra_vde_free_bo(vde->secure_bo); +err_pm_runtime: + pm_runtime_dont_use_autosuspend(dev); + pm_runtime_disable(dev); + + tegra_vde_iommu_deinit(vde); + +err_gen_free: + gen_pool_free(vde->iram_pool, (unsigned long)vde->iram, + gen_pool_size(vde->iram_pool)); + + return err; +} + +static int tegra_vde_remove(struct platform_device *pdev) +{ + struct tegra_vde *vde = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + + tegra_vde_v4l2_deinit(vde); + tegra_vde_free_bo(vde->secure_bo); + + /* + * As it increments RPM usage_count even on errors, we don't need to + * check the returned code here. + */ + pm_runtime_get_sync(dev); + + pm_runtime_dont_use_autosuspend(dev); + pm_runtime_disable(dev); + + /* + * Balance RPM state, the VDE power domain is left ON and hardware + * is clock-gated. It's safe to reboot machine now. + */ + pm_runtime_put_noidle(dev); + clk_disable_unprepare(vde->clk); + + tegra_vde_dmabuf_cache_unmap_all(vde); + tegra_vde_iommu_deinit(vde); + + gen_pool_free(vde->iram_pool, (unsigned long)vde->iram, + gen_pool_size(vde->iram_pool)); + + return 0; +} + +static void tegra_vde_shutdown(struct platform_device *pdev) +{ + /* + * On some devices bootloader isn't ready to a power-gated VDE on + * a warm-reboot, machine will hang in that case. + */ + pm_runtime_get_sync(&pdev->dev); +} + +static __maybe_unused int tegra_vde_pm_suspend(struct device *dev) +{ + struct tegra_vde *vde = dev_get_drvdata(dev); + int err; + + mutex_lock(&vde->lock); + + err = pm_runtime_force_suspend(dev); + if (err < 0) + return err; + + return 0; +} + +static __maybe_unused int tegra_vde_pm_resume(struct device *dev) +{ + struct tegra_vde *vde = dev_get_drvdata(dev); + int err; + + err = pm_runtime_force_resume(dev); + if (err < 0) + return err; + + mutex_unlock(&vde->lock); + + return 0; +} + +static const struct dev_pm_ops tegra_vde_pm_ops = { + SET_RUNTIME_PM_OPS(tegra_vde_runtime_suspend, + tegra_vde_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(tegra_vde_pm_suspend, + tegra_vde_pm_resume) +}; + +static const u32 tegra124_decoded_fmts[] = { + /* TBD: T124 supports only a non-standard Tegra tiled format */ +}; + +static const struct tegra_coded_fmt_desc tegra124_coded_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .frmsize = { + .min_width = 16, + .max_width = 1920, + .step_width = 16, + .min_height = 16, + .max_height = 2032, + .step_height = 16, + }, + .num_decoded_fmts = ARRAY_SIZE(tegra124_decoded_fmts), + .decoded_fmts = tegra124_decoded_fmts, + .decode_run = tegra_vde_h264_decode_run, + .decode_wait = tegra_vde_h264_decode_wait, + }, +}; + +static const u32 tegra20_decoded_fmts[] = { + V4L2_PIX_FMT_YUV420M, + V4L2_PIX_FMT_YVU420M, +}; + +static const struct tegra_coded_fmt_desc tegra20_coded_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .frmsize = { + .min_width = 16, + .max_width = 1920, + .step_width = 16, + .min_height = 16, + .max_height = 2032, + .step_height = 16, + }, + .num_decoded_fmts = ARRAY_SIZE(tegra20_decoded_fmts), + .decoded_fmts = tegra20_decoded_fmts, + .decode_run = tegra_vde_h264_decode_run, + .decode_wait = tegra_vde_h264_decode_wait, + }, +}; + +static const struct tegra_vde_soc tegra124_vde_soc = { + .supports_ref_pic_marking = true, + .coded_fmts = tegra124_coded_fmts, + .num_coded_fmts = ARRAY_SIZE(tegra124_coded_fmts), +}; + +static const struct tegra_vde_soc tegra114_vde_soc = { + .supports_ref_pic_marking = true, + .coded_fmts = tegra20_coded_fmts, + .num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts), +}; + +static const struct tegra_vde_soc tegra30_vde_soc = { + .supports_ref_pic_marking = false, + .coded_fmts = tegra20_coded_fmts, + .num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts), +}; + +static const struct tegra_vde_soc tegra20_vde_soc = { + .supports_ref_pic_marking = false, + .coded_fmts = tegra20_coded_fmts, + .num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts), +}; + +static const struct of_device_id tegra_vde_of_match[] = { + { .compatible = "nvidia,tegra124-vde", .data = &tegra124_vde_soc }, + { .compatible = "nvidia,tegra114-vde", .data = &tegra114_vde_soc }, + { .compatible = "nvidia,tegra30-vde", .data = &tegra30_vde_soc }, + { .compatible = "nvidia,tegra20-vde", .data = &tegra20_vde_soc }, + { }, +}; +MODULE_DEVICE_TABLE(of, tegra_vde_of_match); + +static struct platform_driver tegra_vde_driver = { + .probe = tegra_vde_probe, + .remove = tegra_vde_remove, + .shutdown = tegra_vde_shutdown, + .driver = { + .name = "tegra-vde", + .of_match_table = tegra_vde_of_match, + .pm = &tegra_vde_pm_ops, + }, +}; +module_platform_driver(tegra_vde_driver); + +MODULE_DESCRIPTION("NVIDIA Tegra Video Decoder driver"); +MODULE_AUTHOR("Dmitry Osipenko "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/tegra/vde/vde.h b/drivers/media/platform/tegra/vde/vde.h new file mode 100644 index 000000000000..0fbb1f3d2c88 --- /dev/null +++ b/drivers/media/platform/tegra/vde/vde.h @@ -0,0 +1,242 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * NVIDIA Tegra Video decoder driver + * + * Copyright (C) 2016-2019 GRATE-DRIVER project + */ + +#ifndef TEGRA_VDE_H +#define TEGRA_VDE_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ICMDQUE_WR 0x00 +#define CMDQUE_CONTROL 0x08 +#define INTR_STATUS 0x18 +#define BSE_INT_ENB 0x40 +#define BSE_CONFIG 0x44 + +#define BSE_ICMDQUE_EMPTY BIT(3) +#define BSE_DMA_BUSY BIT(23) + +#define BSEV_ALIGN SZ_1 +#define FRAMEID_ALIGN SZ_256 +#define SXE_BUFFER SZ_32K +#define VDE_ATOM SZ_16 + +struct clk; +struct dma_buf; +struct gen_pool; +struct tegra_ctx; +struct iommu_group; +struct iommu_domain; +struct reset_control; +struct dma_buf_attachment; +struct tegra_vde_h264_frame; +struct tegra_vde_h264_decoder_ctx; + +struct tegra_video_frame { + struct dma_buf_attachment *y_dmabuf_attachment; + struct dma_buf_attachment *cb_dmabuf_attachment; + struct dma_buf_attachment *cr_dmabuf_attachment; + struct dma_buf_attachment *aux_dmabuf_attachment; + dma_addr_t y_addr; + dma_addr_t cb_addr; + dma_addr_t cr_addr; + dma_addr_t aux_addr; + u32 frame_num; + u32 flags; + u32 luma_atoms_pitch; + u32 chroma_atoms_pitch; +}; + +struct tegra_coded_fmt_desc { + u32 fourcc; + struct v4l2_frmsize_stepwise frmsize; + unsigned int num_decoded_fmts; + const u32 *decoded_fmts; + int (*decode_run)(struct tegra_ctx *ctx); + int (*decode_wait)(struct tegra_ctx *ctx); +}; + +struct tegra_vde_soc { + bool supports_ref_pic_marking; + const struct tegra_coded_fmt_desc *coded_fmts; + u32 num_coded_fmts; +}; + +struct tegra_vde_bo { + struct iova *iova; + struct sg_table sgt; + struct tegra_vde *vde; + enum dma_data_direction dma_dir; + unsigned long dma_attrs; + dma_addr_t dma_handle; + dma_addr_t dma_addr; + void *dma_cookie; + size_t size; +}; + +struct tegra_vde { + void __iomem *sxe; + void __iomem *bsev; + void __iomem *mbe; + void __iomem *ppe; + void __iomem *mce; + void __iomem *tfe; + void __iomem *ppb; + void __iomem *vdma; + void __iomem *frameid; + struct device *dev; + struct mutex lock; + struct mutex map_lock; + struct list_head map_list; + struct reset_control *rst; + struct reset_control *rst_mc; + struct gen_pool *iram_pool; + struct completion decode_completion; + struct clk *clk; + struct iommu_domain *domain; + struct iommu_group *group; + struct iova_domain iova; + struct iova *iova_resv_static_addresses; + struct iova *iova_resv_last_page; + const struct tegra_vde_soc *soc; + struct tegra_vde_bo *secure_bo; + dma_addr_t bitstream_data_addr; + dma_addr_t iram_lists_addr; + u32 *iram; + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m; + struct media_device mdev; + struct video_device vdev; + struct mutex v4l2_lock; + struct workqueue_struct *wq; + struct tegra_video_frame frames[V4L2_H264_NUM_DPB_ENTRIES + 1]; +}; + +int tegra_vde_alloc_bo(struct tegra_vde *vde, + struct tegra_vde_bo **ret_bo, + enum dma_data_direction dma_dir, + size_t size); +void tegra_vde_free_bo(struct tegra_vde_bo *bo); + +struct tegra_ctx_h264 { + const struct v4l2_ctrl_h264_decode_params *decode_params; + const struct v4l2_ctrl_h264_sps *sps; + const struct v4l2_ctrl_h264_pps *pps; +}; + +struct tegra_ctx { + struct tegra_vde *vde; + struct tegra_ctx_h264 h264; + struct work_struct work; + struct v4l2_fh fh; + struct v4l2_ctrl_handler hdl; + struct v4l2_format coded_fmt; + struct v4l2_format decoded_fmt; + const struct tegra_coded_fmt_desc *coded_fmt_desc; + struct v4l2_ctrl *ctrls[]; +}; + +struct tegra_m2m_buffer { + struct v4l2_m2m_buffer m2m; + struct dma_buf_attachment *a[VB2_MAX_PLANES]; + dma_addr_t dma_base[VB2_MAX_PLANES]; + dma_addr_t dma_addr[VB2_MAX_PLANES]; + struct iova *iova[VB2_MAX_PLANES]; + struct tegra_vde_bo *aux; + bool b_frame; +}; + +static inline struct tegra_m2m_buffer * +vb_to_tegra_buf(struct vb2_buffer *vb) +{ + struct v4l2_m2m_buffer *m2m = container_of(vb, struct v4l2_m2m_buffer, + vb.vb2_buf); + + return container_of(m2m, struct tegra_m2m_buffer, m2m); +} + +void tegra_vde_prepare_control_data(struct tegra_ctx *ctx, u32 id); + +void tegra_vde_writel(struct tegra_vde *vde, u32 value, void __iomem *base, + u32 offset); +u32 tegra_vde_readl(struct tegra_vde *vde, void __iomem *base, u32 offset); +void tegra_vde_set_bits(struct tegra_vde *vde, u32 mask, void __iomem *base, + u32 offset); + +int tegra_vde_h264_decode_run(struct tegra_ctx *ctx); +int tegra_vde_h264_decode_wait(struct tegra_ctx *ctx); + +int tegra_vde_iommu_init(struct tegra_vde *vde); +void tegra_vde_iommu_deinit(struct tegra_vde *vde); +int tegra_vde_iommu_map(struct tegra_vde *vde, + struct sg_table *sgt, + struct iova **iovap, + size_t size); +void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova); + +int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde, + struct dma_buf *dmabuf, + enum dma_data_direction dma_dir, + struct dma_buf_attachment **ap, + dma_addr_t *addrp); +void tegra_vde_dmabuf_cache_unmap(struct tegra_vde *vde, + struct dma_buf_attachment *a, + bool release); +void tegra_vde_dmabuf_cache_unmap_sync(struct tegra_vde *vde); +void tegra_vde_dmabuf_cache_unmap_all(struct tegra_vde *vde); + +static __maybe_unused char const * +tegra_vde_reg_base_name(struct tegra_vde *vde, void __iomem *base) +{ + if (vde->sxe == base) + return "SXE"; + + if (vde->bsev == base) + return "BSEV"; + + if (vde->mbe == base) + return "MBE"; + + if (vde->ppe == base) + return "PPE"; + + if (vde->mce == base) + return "MCE"; + + if (vde->tfe == base) + return "TFE"; + + if (vde->ppb == base) + return "PPB"; + + if (vde->vdma == base) + return "VDMA"; + + if (vde->frameid == base) + return "FRAMEID"; + + return "???"; +} + +int tegra_vde_v4l2_init(struct tegra_vde *vde); +void tegra_vde_v4l2_deinit(struct tegra_vde *vde); + +#endif /* TEGRA_VDE_H */ diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index b81cfa74edb7..1fd6a0c6e1d8 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -36,8 +36,6 @@ source "drivers/staging/media/rkvdec/Kconfig" source "drivers/staging/media/sunxi/Kconfig" -source "drivers/staging/media/tegra-vde/Kconfig" - source "drivers/staging/media/zoran/Kconfig" source "drivers/staging/media/tegra-video/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 7e2c86e3695d..66d6f6d51c86 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -7,7 +7,6 @@ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC) += rkvdec/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_VIDEO_TEGRA) += tegra-video/ -obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ obj-$(CONFIG_VIDEO_HANTRO) += hantro/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_VIDEO_ZORAN) += zoran/ diff --git a/drivers/staging/media/tegra-vde/Kconfig b/drivers/staging/media/tegra-vde/Kconfig deleted file mode 100644 index 07dbc1f44ca8..000000000000 --- a/drivers/staging/media/tegra-vde/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config TEGRA_VDE - tristate "NVIDIA Tegra Video Decoder Engine driver" - depends on ARCH_TEGRA || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 - select DMA_SHARED_BUFFER - select IOMMU_IOVA - select MEDIA_CONTROLLER - select MEDIA_CONTROLLER_REQUEST_API - select SRAM - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_DMA_SG - select V4L2_H264 - select V4L2_MEM2MEM_DEV - help - Say Y here to enable support for the NVIDIA Tegra video decoder - driver. diff --git a/drivers/staging/media/tegra-vde/Makefile b/drivers/staging/media/tegra-vde/Makefile deleted file mode 100644 index 1758aa201baa..000000000000 --- a/drivers/staging/media/tegra-vde/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -tegra-vde-y := vde.o iommu.o dmabuf-cache.o h264.o v4l2.o -obj-$(CONFIG_TEGRA_VDE) += tegra-vde.o diff --git a/drivers/staging/media/tegra-vde/TODO b/drivers/staging/media/tegra-vde/TODO deleted file mode 100644 index 31aaa3e66d80..000000000000 --- a/drivers/staging/media/tegra-vde/TODO +++ /dev/null @@ -1,4 +0,0 @@ -TODO: - - Implement V4L2 API once it gains support for stateless decoders. - -Contact: Dmitry Osipenko diff --git a/drivers/staging/media/tegra-vde/dmabuf-cache.c b/drivers/staging/media/tegra-vde/dmabuf-cache.c deleted file mode 100644 index 69c346148070..000000000000 --- a/drivers/staging/media/tegra-vde/dmabuf-cache.c +++ /dev/null @@ -1,229 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * NVIDIA Tegra Video decoder driver - * - * Copyright (C) 2016-2019 GRATE-DRIVER project - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vde.h" - -MODULE_IMPORT_NS(DMA_BUF); - -struct tegra_vde_cache_entry { - enum dma_data_direction dma_dir; - struct dma_buf_attachment *a; - struct delayed_work dwork; - struct tegra_vde *vde; - struct list_head list; - struct sg_table *sgt; - struct iova *iova; - unsigned int refcnt; -}; - -static void tegra_vde_release_entry(struct tegra_vde_cache_entry *entry) -{ - struct dma_buf *dmabuf = entry->a->dmabuf; - - WARN_ON_ONCE(entry->refcnt); - - if (entry->vde->domain) - tegra_vde_iommu_unmap(entry->vde, entry->iova); - - dma_buf_unmap_attachment(entry->a, entry->sgt, entry->dma_dir); - dma_buf_detach(dmabuf, entry->a); - dma_buf_put(dmabuf); - - list_del(&entry->list); - kfree(entry); -} - -static void tegra_vde_delayed_unmap(struct work_struct *work) -{ - struct tegra_vde_cache_entry *entry; - struct tegra_vde *vde; - - entry = container_of(work, struct tegra_vde_cache_entry, - dwork.work); - vde = entry->vde; - - mutex_lock(&vde->map_lock); - tegra_vde_release_entry(entry); - mutex_unlock(&vde->map_lock); -} - -int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde, - struct dma_buf *dmabuf, - enum dma_data_direction dma_dir, - struct dma_buf_attachment **ap, - dma_addr_t *addrp) -{ - struct dma_buf_attachment *attachment; - struct tegra_vde_cache_entry *entry; - struct device *dev = vde->dev; - struct sg_table *sgt; - struct iova *iova; - int err; - - mutex_lock(&vde->map_lock); - - list_for_each_entry(entry, &vde->map_list, list) { - if (entry->a->dmabuf != dmabuf) - continue; - - if (!cancel_delayed_work(&entry->dwork)) - continue; - - if (entry->dma_dir != dma_dir) - entry->dma_dir = DMA_BIDIRECTIONAL; - - dma_buf_put(dmabuf); - - if (vde->domain) - *addrp = iova_dma_addr(&vde->iova, entry->iova); - else - *addrp = sg_dma_address(entry->sgt->sgl); - - goto ref; - } - - attachment = dma_buf_attach(dmabuf, dev); - if (IS_ERR(attachment)) { - dev_err(dev, "Failed to attach dmabuf\n"); - err = PTR_ERR(attachment); - goto err_unlock; - } - - sgt = dma_buf_map_attachment(attachment, dma_dir); - if (IS_ERR(sgt)) { - dev_err(dev, "Failed to get dmabufs sg_table\n"); - err = PTR_ERR(sgt); - goto err_detach; - } - - if (!vde->domain && sgt->nents > 1) { - dev_err(dev, "Sparse DMA region is unsupported, please enable IOMMU\n"); - err = -EINVAL; - goto err_unmap; - } - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - err = -ENOMEM; - goto err_unmap; - } - - if (vde->domain) { - err = tegra_vde_iommu_map(vde, sgt, &iova, dmabuf->size); - if (err) - goto err_free; - - *addrp = iova_dma_addr(&vde->iova, iova); - } else { - *addrp = sg_dma_address(sgt->sgl); - iova = NULL; - } - - INIT_DELAYED_WORK(&entry->dwork, tegra_vde_delayed_unmap); - list_add(&entry->list, &vde->map_list); - - entry->dma_dir = dma_dir; - entry->iova = iova; - entry->vde = vde; - entry->sgt = sgt; - entry->a = attachment; -ref: - entry->refcnt++; - - *ap = entry->a; - - mutex_unlock(&vde->map_lock); - - return 0; - -err_free: - kfree(entry); -err_unmap: - dma_buf_unmap_attachment(attachment, sgt, dma_dir); -err_detach: - dma_buf_detach(dmabuf, attachment); -err_unlock: - mutex_unlock(&vde->map_lock); - - return err; -} - -void tegra_vde_dmabuf_cache_unmap(struct tegra_vde *vde, - struct dma_buf_attachment *a, - bool release) -{ - struct tegra_vde_cache_entry *entry; - - mutex_lock(&vde->map_lock); - - list_for_each_entry(entry, &vde->map_list, list) { - if (entry->a != a) - continue; - - WARN_ON_ONCE(!entry->refcnt); - - if (--entry->refcnt == 0) { - if (release) - tegra_vde_release_entry(entry); - else - schedule_delayed_work(&entry->dwork, 5 * HZ); - } - break; - } - - mutex_unlock(&vde->map_lock); -} - -void tegra_vde_dmabuf_cache_unmap_sync(struct tegra_vde *vde) -{ - struct tegra_vde_cache_entry *entry, *tmp; - - mutex_lock(&vde->map_lock); - - list_for_each_entry_safe(entry, tmp, &vde->map_list, list) { - if (entry->refcnt) - continue; - - if (!cancel_delayed_work(&entry->dwork)) - continue; - - tegra_vde_release_entry(entry); - } - - mutex_unlock(&vde->map_lock); -} - -void tegra_vde_dmabuf_cache_unmap_all(struct tegra_vde *vde) -{ - struct tegra_vde_cache_entry *entry, *tmp; - - mutex_lock(&vde->map_lock); - - while (!list_empty(&vde->map_list)) { - list_for_each_entry_safe(entry, tmp, &vde->map_list, list) { - if (!cancel_delayed_work(&entry->dwork)) - continue; - - tegra_vde_release_entry(entry); - } - - mutex_unlock(&vde->map_lock); - schedule(); - mutex_lock(&vde->map_lock); - } - - mutex_unlock(&vde->map_lock); -} diff --git a/drivers/staging/media/tegra-vde/h264.c b/drivers/staging/media/tegra-vde/h264.c deleted file mode 100644 index d8e5534e80c8..000000000000 --- a/drivers/staging/media/tegra-vde/h264.c +++ /dev/null @@ -1,946 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * NVIDIA Tegra Video decoder driver - * - * Copyright (C) 2016-2022 Dmitry Osipenko - * - */ - -#include -#include -#include -#include - -#include - -#include "trace.h" -#include "vde.h" - -#define FLAG_B_FRAME 0x1 -#define FLAG_REFERENCE 0x2 - -struct tegra_vde_h264_frame { - unsigned int frame_num; - unsigned int flags; -}; - -struct tegra_vde_h264_decoder_ctx { - unsigned int dpb_frames_nb; - unsigned int dpb_ref_frames_with_earlier_poc_nb; - unsigned int baseline_profile; - unsigned int level_idc; - unsigned int log2_max_pic_order_cnt_lsb; - unsigned int log2_max_frame_num; - unsigned int pic_order_cnt_type; - unsigned int direct_8x8_inference_flag; - unsigned int pic_width_in_mbs; - unsigned int pic_height_in_mbs; - unsigned int pic_init_qp; - unsigned int deblocking_filter_control_present_flag; - unsigned int constrained_intra_pred_flag; - unsigned int chroma_qp_index_offset; - unsigned int pic_order_present_flag; - unsigned int num_ref_idx_l0_active_minus1; - unsigned int num_ref_idx_l1_active_minus1; -}; - -struct h264_reflists { - u8 p[V4L2_H264_NUM_DPB_ENTRIES]; - u8 b0[V4L2_H264_NUM_DPB_ENTRIES]; - u8 b1[V4L2_H264_NUM_DPB_ENTRIES]; -}; - -static int tegra_vde_wait_mbe(struct tegra_vde *vde) -{ - u32 tmp; - - return readl_relaxed_poll_timeout(vde->mbe + 0x8C, tmp, - tmp >= 0x10, 1, 100); -} - -static int tegra_vde_setup_mbe_frame_idx(struct tegra_vde *vde, - unsigned int refs_nb, - bool setup_refs) -{ - u32 value, frame_idx_enb_mask = 0; - unsigned int frame_idx; - unsigned int idx; - int err; - - tegra_vde_writel(vde, 0xD0000000 | (0 << 23), vde->mbe, 0x80); - tegra_vde_writel(vde, 0xD0200000 | (0 << 23), vde->mbe, 0x80); - - err = tegra_vde_wait_mbe(vde); - if (err) - return err; - - if (!setup_refs) - return 0; - - for (idx = 0, frame_idx = 1; idx < refs_nb; idx++, frame_idx++) { - tegra_vde_writel(vde, 0xD0000000 | (frame_idx << 23), - vde->mbe, 0x80); - tegra_vde_writel(vde, 0xD0200000 | (frame_idx << 23), - vde->mbe, 0x80); - - frame_idx_enb_mask |= frame_idx << (6 * (idx % 4)); - - if (idx % 4 == 3 || idx == refs_nb - 1) { - value = 0xC0000000; - value |= (idx >> 2) << 24; - value |= frame_idx_enb_mask; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - err = tegra_vde_wait_mbe(vde); - if (err) - return err; - - frame_idx_enb_mask = 0; - } - } - - return 0; -} - -static void tegra_vde_mbe_set_0xa_reg(struct tegra_vde *vde, int reg, u32 val) -{ - tegra_vde_writel(vde, 0xA0000000 | (reg << 24) | (val & 0xFFFF), - vde->mbe, 0x80); - tegra_vde_writel(vde, 0xA0000000 | ((reg + 1) << 24) | (val >> 16), - vde->mbe, 0x80); -} - -static int tegra_vde_wait_bsev(struct tegra_vde *vde, bool wait_dma) -{ - struct device *dev = vde->dev; - u32 value; - int err; - - err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, - !(value & BIT(2)), 1, 100); - if (err) { - dev_err(dev, "BSEV unknown bit timeout\n"); - return err; - } - - err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, - (value & BSE_ICMDQUE_EMPTY), 1, 100); - if (err) { - dev_err(dev, "BSEV ICMDQUE flush timeout\n"); - return err; - } - - if (!wait_dma) - return 0; - - err = readl_relaxed_poll_timeout(vde->bsev + INTR_STATUS, value, - !(value & BSE_DMA_BUSY), 1, 1000); - if (err) { - dev_err(dev, "BSEV DMA timeout\n"); - return err; - } - - return 0; -} - -static int tegra_vde_push_to_bsev_icmdqueue(struct tegra_vde *vde, - u32 value, bool wait_dma) -{ - tegra_vde_writel(vde, value, vde->bsev, ICMDQUE_WR); - - return tegra_vde_wait_bsev(vde, wait_dma); -} - -static void tegra_vde_setup_frameid(struct tegra_vde *vde, - struct tegra_video_frame *frame, - unsigned int frameid, - u32 mbs_width, u32 mbs_height) -{ - u32 y_addr = frame ? frame->y_addr : 0x6CDEAD00; - u32 cb_addr = frame ? frame->cb_addr : 0x6CDEAD00; - u32 cr_addr = frame ? frame->cr_addr : 0x6CDEAD00; - u32 value1 = frame ? ((frame->luma_atoms_pitch << 16) | mbs_height) : 0; - u32 value2 = frame ? ((frame->chroma_atoms_pitch << 6) | 1) : 0; - - tegra_vde_writel(vde, y_addr >> 8, vde->frameid, 0x000 + frameid * 4); - tegra_vde_writel(vde, cb_addr >> 8, vde->frameid, 0x100 + frameid * 4); - tegra_vde_writel(vde, cr_addr >> 8, vde->frameid, 0x180 + frameid * 4); - tegra_vde_writel(vde, value1, vde->frameid, 0x080 + frameid * 4); - tegra_vde_writel(vde, value2, vde->frameid, 0x280 + frameid * 4); -} - -static void tegra_setup_frameidx(struct tegra_vde *vde, - struct tegra_video_frame *frames, - unsigned int frames_nb, - u32 mbs_width, u32 mbs_height) -{ - unsigned int idx; - - for (idx = 0; idx < frames_nb; idx++) - tegra_vde_setup_frameid(vde, &frames[idx], idx, - mbs_width, mbs_height); - - for (; idx < 17; idx++) - tegra_vde_setup_frameid(vde, NULL, idx, 0, 0); -} - -static void tegra_vde_setup_iram_entry(struct tegra_vde *vde, - unsigned int table, - unsigned int row, - u32 value1, u32 value2) -{ - u32 *iram_tables = vde->iram; - - trace_vde_setup_iram_entry(table, row, value1, value2); - - iram_tables[0x20 * table + row * 2 + 0] = value1; - iram_tables[0x20 * table + row * 2 + 1] = value2; -} - -static void tegra_vde_setup_iram_tables(struct tegra_vde *vde, - struct tegra_video_frame *dpb_frames, - unsigned int ref_frames_nb, - unsigned int with_earlier_poc_nb) -{ - struct tegra_video_frame *frame; - int with_later_poc_nb; - u32 value, aux_addr; - unsigned int i, k; - - trace_vde_ref_l0(dpb_frames[0].frame_num); - - for (i = 0; i < 16; i++) { - if (i < ref_frames_nb) { - frame = &dpb_frames[i + 1]; - - aux_addr = frame->aux_addr; - - value = (i + 1) << 26; - value |= !(frame->flags & FLAG_B_FRAME) << 25; - value |= 1 << 24; - value |= frame->frame_num; - } else { - aux_addr = 0x6ADEAD00; - value = 0x3f; - } - - tegra_vde_setup_iram_entry(vde, 0, i, value, aux_addr); - tegra_vde_setup_iram_entry(vde, 1, i, value, aux_addr); - tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); - tegra_vde_setup_iram_entry(vde, 3, i, value, aux_addr); - } - - if (!(dpb_frames[0].flags & FLAG_B_FRAME)) - return; - - if (with_earlier_poc_nb >= ref_frames_nb) - return; - - with_later_poc_nb = ref_frames_nb - with_earlier_poc_nb; - - trace_vde_ref_l1(with_later_poc_nb, with_earlier_poc_nb); - - for (i = 0, k = with_earlier_poc_nb; i < with_later_poc_nb; i++, k++) { - frame = &dpb_frames[k + 1]; - - aux_addr = frame->aux_addr; - - value = (k + 1) << 26; - value |= !(frame->flags & FLAG_B_FRAME) << 25; - value |= 1 << 24; - value |= frame->frame_num; - - tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); - } - - for (k = 0; i < ref_frames_nb; i++, k++) { - frame = &dpb_frames[k + 1]; - - aux_addr = frame->aux_addr; - - value = (k + 1) << 26; - value |= !(frame->flags & FLAG_B_FRAME) << 25; - value |= 1 << 24; - value |= frame->frame_num; - - tegra_vde_setup_iram_entry(vde, 2, i, value, aux_addr); - } -} - -static int tegra_vde_setup_hw_context(struct tegra_vde *vde, - struct tegra_vde_h264_decoder_ctx *ctx, - struct tegra_video_frame *dpb_frames, - dma_addr_t bitstream_data_addr, - size_t bitstream_data_size, - unsigned int macroblocks_nb) -{ - struct device *dev = vde->dev; - u32 value; - int err; - - tegra_vde_set_bits(vde, 0x000A, vde->sxe, 0xF0); - tegra_vde_set_bits(vde, 0x000B, vde->bsev, CMDQUE_CONTROL); - tegra_vde_set_bits(vde, 0x8002, vde->mbe, 0x50); - tegra_vde_set_bits(vde, 0x000A, vde->mbe, 0xA0); - tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x14); - tegra_vde_set_bits(vde, 0x000A, vde->ppe, 0x28); - tegra_vde_set_bits(vde, 0x0A00, vde->mce, 0x08); - tegra_vde_set_bits(vde, 0x000A, vde->tfe, 0x00); - tegra_vde_set_bits(vde, 0x0005, vde->vdma, 0x04); - - tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x1C); - tegra_vde_writel(vde, 0x00000000, vde->vdma, 0x00); - tegra_vde_writel(vde, 0x00000007, vde->vdma, 0x04); - tegra_vde_writel(vde, 0x00000007, vde->frameid, 0x200); - tegra_vde_writel(vde, 0x00000005, vde->tfe, 0x04); - tegra_vde_writel(vde, 0x00000000, vde->mbe, 0x84); - tegra_vde_writel(vde, 0x00000010, vde->sxe, 0x08); - tegra_vde_writel(vde, 0x00000150, vde->sxe, 0x54); - tegra_vde_writel(vde, 0x0000054C, vde->sxe, 0x58); - tegra_vde_writel(vde, 0x00000E34, vde->sxe, 0x5C); - tegra_vde_writel(vde, 0x063C063C, vde->mce, 0x10); - tegra_vde_writel(vde, 0x0003FC00, vde->bsev, INTR_STATUS); - tegra_vde_writel(vde, 0x0000150D, vde->bsev, BSE_CONFIG); - tegra_vde_writel(vde, 0x00000100, vde->bsev, BSE_INT_ENB); - tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x98); - tegra_vde_writel(vde, 0x00000060, vde->bsev, 0x9C); - - memset(vde->iram + 128, 0, macroblocks_nb / 2); - - tegra_setup_frameidx(vde, dpb_frames, ctx->dpb_frames_nb, - ctx->pic_width_in_mbs, ctx->pic_height_in_mbs); - - tegra_vde_setup_iram_tables(vde, dpb_frames, - ctx->dpb_frames_nb - 1, - ctx->dpb_ref_frames_with_earlier_poc_nb); - - /* - * The IRAM mapping is write-combine, ensure that CPU buffers have - * been flushed at this point. - */ - wmb(); - - tegra_vde_writel(vde, 0x00000000, vde->bsev, 0x8C); - tegra_vde_writel(vde, bitstream_data_addr + bitstream_data_size, - vde->bsev, 0x54); - - vde->bitstream_data_addr = bitstream_data_addr; - - value = ctx->pic_width_in_mbs << 11 | ctx->pic_height_in_mbs << 3; - - tegra_vde_writel(vde, value, vde->bsev, 0x88); - - err = tegra_vde_wait_bsev(vde, false); - if (err) - return err; - - err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x800003FC, false); - if (err) - return err; - - value = 0x01500000; - value |= ((vde->iram_lists_addr + 512) >> 2) & 0xFFFF; - - err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); - if (err) - return err; - - err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x840F054C, false); - if (err) - return err; - - err = tegra_vde_push_to_bsev_icmdqueue(vde, 0x80000080, false); - if (err) - return err; - - value = 0x0E340000 | ((vde->iram_lists_addr >> 2) & 0xFFFF); - - err = tegra_vde_push_to_bsev_icmdqueue(vde, value, true); - if (err) - return err; - - value = 0x00800005; - value |= ctx->pic_width_in_mbs << 11; - value |= ctx->pic_height_in_mbs << 3; - - tegra_vde_writel(vde, value, vde->sxe, 0x10); - - value = !ctx->baseline_profile << 17; - value |= ctx->level_idc << 13; - value |= ctx->log2_max_pic_order_cnt_lsb << 7; - value |= ctx->pic_order_cnt_type << 5; - value |= ctx->log2_max_frame_num; - - tegra_vde_writel(vde, value, vde->sxe, 0x40); - - value = ctx->pic_init_qp << 25; - value |= !!(ctx->deblocking_filter_control_present_flag) << 2; - value |= !!ctx->pic_order_present_flag; - - tegra_vde_writel(vde, value, vde->sxe, 0x44); - - value = ctx->chroma_qp_index_offset; - value |= ctx->num_ref_idx_l0_active_minus1 << 5; - value |= ctx->num_ref_idx_l1_active_minus1 << 10; - value |= !!ctx->constrained_intra_pred_flag << 15; - - tegra_vde_writel(vde, value, vde->sxe, 0x48); - - value = 0x0C000000; - value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 24; - - tegra_vde_writel(vde, value, vde->sxe, 0x4C); - - value = 0x03800000; - value |= bitstream_data_size & GENMASK(19, 15); - - tegra_vde_writel(vde, value, vde->sxe, 0x68); - - tegra_vde_writel(vde, bitstream_data_addr, vde->sxe, 0x6C); - - if (vde->soc->supports_ref_pic_marking) - tegra_vde_writel(vde, vde->secure_bo->dma_addr, vde->sxe, 0x7c); - - value = 0x10000005; - value |= ctx->pic_width_in_mbs << 11; - value |= ctx->pic_height_in_mbs << 3; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - value = 0x26800000; - value |= ctx->level_idc << 4; - value |= !ctx->baseline_profile << 1; - value |= !!ctx->direct_8x8_inference_flag; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - tegra_vde_writel(vde, 0xF4000001, vde->mbe, 0x80); - tegra_vde_writel(vde, 0x20000000, vde->mbe, 0x80); - tegra_vde_writel(vde, 0xF4000101, vde->mbe, 0x80); - - value = 0x20000000; - value |= ctx->chroma_qp_index_offset << 8; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - err = tegra_vde_setup_mbe_frame_idx(vde, - ctx->dpb_frames_nb - 1, - ctx->pic_order_cnt_type == 0); - if (err) { - dev_err(dev, "MBE frames setup failed %d\n", err); - return err; - } - - tegra_vde_mbe_set_0xa_reg(vde, 0, 0x000009FC); - tegra_vde_mbe_set_0xa_reg(vde, 2, 0x61DEAD00); - tegra_vde_mbe_set_0xa_reg(vde, 4, 0x62DEAD00); - tegra_vde_mbe_set_0xa_reg(vde, 6, 0x63DEAD00); - tegra_vde_mbe_set_0xa_reg(vde, 8, dpb_frames[0].aux_addr); - - value = 0xFC000000; - value |= !!(dpb_frames[0].flags & FLAG_B_FRAME) << 2; - - if (!ctx->baseline_profile) - value |= !!(dpb_frames[0].flags & FLAG_REFERENCE) << 1; - - tegra_vde_writel(vde, value, vde->mbe, 0x80); - - err = tegra_vde_wait_mbe(vde); - if (err) { - dev_err(dev, "MBE programming failed %d\n", err); - return err; - } - - return 0; -} - -static void tegra_vde_decode_frame(struct tegra_vde *vde, - unsigned int macroblocks_nb) -{ - reinit_completion(&vde->decode_completion); - - tegra_vde_writel(vde, 0x00000001, vde->bsev, 0x8C); - tegra_vde_writel(vde, 0x20000000 | (macroblocks_nb - 1), - vde->sxe, 0x00); -} - -static int tegra_vde_validate_h264_ctx(struct device *dev, - struct tegra_vde_h264_decoder_ctx *ctx) -{ - if (ctx->dpb_frames_nb == 0 || ctx->dpb_frames_nb > 17) { - dev_err(dev, "Bad DPB size %u\n", ctx->dpb_frames_nb); - return -EINVAL; - } - - if (ctx->level_idc > 15) { - dev_err(dev, "Bad level value %u\n", ctx->level_idc); - return -EINVAL; - } - - if (ctx->pic_init_qp > 52) { - dev_err(dev, "Bad pic_init_qp value %u\n", ctx->pic_init_qp); - return -EINVAL; - } - - if (ctx->log2_max_pic_order_cnt_lsb > 16) { - dev_err(dev, "Bad log2_max_pic_order_cnt_lsb value %u\n", - ctx->log2_max_pic_order_cnt_lsb); - return -EINVAL; - } - - if (ctx->log2_max_frame_num > 16) { - dev_err(dev, "Bad log2_max_frame_num value %u\n", - ctx->log2_max_frame_num); - return -EINVAL; - } - - if (ctx->chroma_qp_index_offset > 31) { - dev_err(dev, "Bad chroma_qp_index_offset value %u\n", - ctx->chroma_qp_index_offset); - return -EINVAL; - } - - if (ctx->pic_order_cnt_type > 2) { - dev_err(dev, "Bad pic_order_cnt_type value %u\n", - ctx->pic_order_cnt_type); - return -EINVAL; - } - - if (ctx->num_ref_idx_l0_active_minus1 > 15) { - dev_err(dev, "Bad num_ref_idx_l0_active_minus1 value %u\n", - ctx->num_ref_idx_l0_active_minus1); - return -EINVAL; - } - - if (ctx->num_ref_idx_l1_active_minus1 > 15) { - dev_err(dev, "Bad num_ref_idx_l1_active_minus1 value %u\n", - ctx->num_ref_idx_l1_active_minus1); - return -EINVAL; - } - - if (!ctx->pic_width_in_mbs || ctx->pic_width_in_mbs > 127) { - dev_err(dev, "Bad pic_width_in_mbs value %u\n", - ctx->pic_width_in_mbs); - return -EINVAL; - } - - if (!ctx->pic_height_in_mbs || ctx->pic_height_in_mbs > 127) { - dev_err(dev, "Bad pic_height_in_mbs value %u\n", - ctx->pic_height_in_mbs); - return -EINVAL; - } - - return 0; -} - -static int tegra_vde_decode_begin(struct tegra_vde *vde, - struct tegra_vde_h264_decoder_ctx *ctx, - struct tegra_video_frame *dpb_frames, - dma_addr_t bitstream_data_addr, - size_t bitstream_data_size) -{ - struct device *dev = vde->dev; - unsigned int macroblocks_nb; - int err; - - err = mutex_lock_interruptible(&vde->lock); - if (err) - return err; - - err = pm_runtime_resume_and_get(dev); - if (err < 0) - goto unlock; - - /* - * We rely on the VDE registers reset value, otherwise VDE - * causes bus lockup. - */ - err = reset_control_assert(vde->rst_mc); - if (err) { - dev_err(dev, "DEC start: Failed to assert MC reset: %d\n", - err); - goto put_runtime_pm; - } - - err = reset_control_reset(vde->rst); - if (err) { - dev_err(dev, "DEC start: Failed to reset HW: %d\n", err); - goto put_runtime_pm; - } - - err = reset_control_deassert(vde->rst_mc); - if (err) { - dev_err(dev, "DEC start: Failed to deassert MC reset: %d\n", - err); - goto put_runtime_pm; - } - - macroblocks_nb = ctx->pic_width_in_mbs * ctx->pic_height_in_mbs; - - err = tegra_vde_setup_hw_context(vde, ctx, dpb_frames, - bitstream_data_addr, - bitstream_data_size, - macroblocks_nb); - if (err) - goto put_runtime_pm; - - tegra_vde_decode_frame(vde, macroblocks_nb); - - return 0; - -put_runtime_pm: - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - -unlock: - mutex_unlock(&vde->lock); - - return err; -} - -static void tegra_vde_decode_abort(struct tegra_vde *vde) -{ - struct device *dev = vde->dev; - int err; - - /* - * At first reset memory client to avoid resetting VDE HW in the - * middle of DMA which could result into memory corruption or hang - * the whole system. - */ - err = reset_control_assert(vde->rst_mc); - if (err) - dev_err(dev, "DEC end: Failed to assert MC reset: %d\n", err); - - err = reset_control_assert(vde->rst); - if (err) - dev_err(dev, "DEC end: Failed to assert HW reset: %d\n", err); - - pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); - - mutex_unlock(&vde->lock); -} - -static int tegra_vde_decode_end(struct tegra_vde *vde) -{ - unsigned int read_bytes, macroblocks_nb; - struct device *dev = vde->dev; - dma_addr_t bsev_ptr; - long timeout; - int ret; - - timeout = wait_for_completion_interruptible_timeout( - &vde->decode_completion, msecs_to_jiffies(1000)); - if (timeout == 0) { - bsev_ptr = tegra_vde_readl(vde, vde->bsev, 0x10); - macroblocks_nb = tegra_vde_readl(vde, vde->sxe, 0xC8) & 0x1FFF; - read_bytes = bsev_ptr ? bsev_ptr - vde->bitstream_data_addr : 0; - - dev_err(dev, "Decoding failed: read 0x%X bytes, %u macroblocks parsed\n", - read_bytes, macroblocks_nb); - - ret = -EIO; - } else if (timeout < 0) { - ret = timeout; - } else { - ret = 0; - } - - tegra_vde_decode_abort(vde); - - return ret; -} - -static struct vb2_buffer *get_ref_buf(struct tegra_ctx *ctx, - struct vb2_v4l2_buffer *dst, - unsigned int dpb_idx) -{ - const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; - struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; - int buf_idx = -1; - - if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - buf_idx = vb2_find_timestamp(cap_q, - dpb[dpb_idx].reference_ts, 0); - - /* - * If a DPB entry is unused or invalid, address of current destination - * buffer is returned. - */ - if (buf_idx < 0) - return &dst->vb2_buf; - - return vb2_get_buffer(cap_q, buf_idx); -} - -static int tegra_vde_validate_vb_size(struct tegra_ctx *ctx, - struct vb2_buffer *vb, - unsigned int plane_id, - size_t min_size) -{ - u64 offset = vb->planes[plane_id].data_offset; - struct device *dev = ctx->vde->dev; - - if (offset + min_size > vb2_plane_size(vb, plane_id)) { - dev_err(dev, "Too small plane[%u] size %lu @0x%llX, should be at least %zu\n", - plane_id, vb2_plane_size(vb, plane_id), offset, min_size); - return -EINVAL; - } - - return 0; -} - -static int tegra_vde_h264_setup_frame(struct tegra_ctx *ctx, - struct tegra_vde_h264_decoder_ctx *h264, - struct v4l2_h264_reflist_builder *b, - struct vb2_buffer *vb, - unsigned int ref_id, - unsigned int id) -{ - struct v4l2_pix_format_mplane *pixfmt = &ctx->decoded_fmt.fmt.pix_mp; - struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); - struct tegra_ctx_h264 *h = &ctx->h264; - struct tegra_vde *vde = ctx->vde; - struct device *dev = vde->dev; - unsigned int cstride, lstride; - unsigned int flags = 0; - size_t lsize, csize; - int err, frame_num; - - lsize = h264->pic_width_in_mbs * 16 * h264->pic_height_in_mbs * 16; - csize = h264->pic_width_in_mbs * 8 * h264->pic_height_in_mbs * 8; - lstride = pixfmt->plane_fmt[0].bytesperline; - cstride = pixfmt->plane_fmt[1].bytesperline; - - err = tegra_vde_validate_vb_size(ctx, vb, 0, lsize); - if (err) - return err; - - err = tegra_vde_validate_vb_size(ctx, vb, 1, csize); - if (err) - return err; - - err = tegra_vde_validate_vb_size(ctx, vb, 2, csize); - if (err) - return err; - - if (!tb->aux || tb->aux->size < csize) { - dev_err(dev, "Too small aux size %zd, should be at least %zu\n", - tb->aux ? tb->aux->size : -1, csize); - return -EINVAL; - } - - if (id == 0) { - frame_num = h->decode_params->frame_num; - - if (h->decode_params->nal_ref_idc) - flags |= FLAG_REFERENCE; - } else { - frame_num = b->refs[ref_id].frame_num; - } - - if (tb->b_frame) - flags |= FLAG_B_FRAME; - - vde->frames[id].flags = flags; - vde->frames[id].y_addr = tb->dma_addr[0]; - vde->frames[id].cb_addr = tb->dma_addr[1]; - vde->frames[id].cr_addr = tb->dma_addr[2]; - vde->frames[id].aux_addr = tb->aux->dma_addr; - vde->frames[id].frame_num = frame_num & 0x7fffff; - vde->frames[id].luma_atoms_pitch = lstride / VDE_ATOM; - vde->frames[id].chroma_atoms_pitch = cstride / VDE_ATOM; - - return 0; -} - -static int tegra_vde_h264_setup_frames(struct tegra_ctx *ctx, - struct tegra_vde_h264_decoder_ctx *h264) -{ - struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - struct vb2_v4l2_buffer *dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb; - struct tegra_m2m_buffer *tb = vb_to_tegra_buf(&dst->vb2_buf); - struct tegra_ctx_h264 *h = &ctx->h264; - struct v4l2_h264_reflist_builder b; - struct h264_reflists reflists; - struct vb2_buffer *ref; - unsigned int i; - u8 *dpb_id; - int err; - - /* - * Tegra hardware requires information about frame's type, assuming - * that frame consists of the same type slices. Userspace must tag - * frame's type appropriately. - * - * Decoding of a non-uniform frames isn't supported by hardware and - * require software preprocessing that we don't implement. Decoding - * is expected to fail in this case. Such video streams are rare in - * practice, so not a big deal. - * - * If userspace doesn't tell us frame's type, then we will try decode - * as-is. - */ - v4l2_m2m_buf_copy_metadata(src, dst, true); - - if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) - tb->b_frame = true; - else - tb->b_frame = false; - - err = tegra_vde_h264_setup_frame(ctx, h264, NULL, &dst->vb2_buf, 0, - h264->dpb_frames_nb++); - if (err) - return err; - - if (!(h->decode_params->flags & (V4L2_H264_DECODE_PARAM_FLAG_PFRAME | - V4L2_H264_DECODE_PARAM_FLAG_BFRAME))) - return 0; - - v4l2_h264_init_reflist_builder(&b, h->decode_params, h->sps, dpb); - - if (h->decode_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BFRAME) { - v4l2_h264_build_b_ref_lists(&b, reflists.b0, reflists.b1); - dpb_id = reflists.b0; - } else { - v4l2_h264_build_p_ref_list(&b, reflists.p); - dpb_id = reflists.p; - } - - for (i = 0; i < b.num_valid; i++) { - ref = get_ref_buf(ctx, dst, dpb_id[i]); - - err = tegra_vde_h264_setup_frame(ctx, h264, &b, ref, dpb_id[i], - h264->dpb_frames_nb++); - if (err) - return err; - - if (b.refs[dpb_id[i]].pic_order_count < b.cur_pic_order_count) - h264->dpb_ref_frames_with_earlier_poc_nb++; - } - - return 0; -} - -static unsigned int to_tegra_vde_h264_level_idc(unsigned int level_idc) -{ - switch (level_idc) { - case 11: - return 2; - case 12: - return 3; - case 13: - return 4; - case 20: - return 5; - case 21: - return 6; - case 22: - return 7; - case 30: - return 8; - case 31: - return 9; - case 32: - return 10; - case 40: - return 11; - case 41: - return 12; - case 42: - return 13; - case 50: - return 14; - default: - break; - } - - return 15; -} - -static int tegra_vde_h264_setup_context(struct tegra_ctx *ctx, - struct tegra_vde_h264_decoder_ctx *h264) -{ - struct tegra_ctx_h264 *h = &ctx->h264; - struct tegra_vde *vde = ctx->vde; - struct device *dev = vde->dev; - int err; - - memset(h264, 0, sizeof(*h264)); - memset(vde->frames, 0, sizeof(vde->frames)); - - tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_DECODE_PARAMS); - tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_SPS); - tegra_vde_prepare_control_data(ctx, V4L2_CID_STATELESS_H264_PPS); - - /* CABAC unsupported by hardware, requires software preprocessing */ - if (h->pps->flags & V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE) - return -EOPNOTSUPP; - - if (h->sps->profile_idc == 66) - h264->baseline_profile = 1; - - if (h->sps->flags & V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE) - h264->direct_8x8_inference_flag = 1; - - if (h->pps->flags & V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED) - h264->constrained_intra_pred_flag = 1; - - if (h->pps->flags & V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT) - h264->deblocking_filter_control_present_flag = 1; - - if (h->pps->flags & V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT) - h264->pic_order_present_flag = 1; - - h264->level_idc = to_tegra_vde_h264_level_idc(h->sps->level_idc); - h264->log2_max_pic_order_cnt_lsb = h->sps->log2_max_pic_order_cnt_lsb_minus4 + 4; - h264->log2_max_frame_num = h->sps->log2_max_frame_num_minus4 + 4; - h264->pic_order_cnt_type = h->sps->pic_order_cnt_type; - h264->pic_width_in_mbs = h->sps->pic_width_in_mbs_minus1 + 1; - h264->pic_height_in_mbs = h->sps->pic_height_in_map_units_minus1 + 1; - - h264->num_ref_idx_l0_active_minus1 = h->pps->num_ref_idx_l0_default_active_minus1; - h264->num_ref_idx_l1_active_minus1 = h->pps->num_ref_idx_l1_default_active_minus1; - h264->chroma_qp_index_offset = h->pps->chroma_qp_index_offset & 0x1f; - h264->pic_init_qp = h->pps->pic_init_qp_minus26 + 26; - - err = tegra_vde_h264_setup_frames(ctx, h264); - if (err) - return err; - - err = tegra_vde_validate_h264_ctx(dev, h264); - if (err) - return err; - - return 0; -} - -int tegra_vde_h264_decode_run(struct tegra_ctx *ctx) -{ - struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - struct tegra_m2m_buffer *bitstream = vb_to_tegra_buf(&src->vb2_buf); - size_t bitstream_size = vb2_get_plane_payload(&src->vb2_buf, 0); - struct tegra_vde_h264_decoder_ctx h264; - struct tegra_vde *vde = ctx->vde; - int err; - - err = tegra_vde_h264_setup_context(ctx, &h264); - if (err) - return err; - - err = tegra_vde_decode_begin(vde, &h264, vde->frames, - bitstream->dma_addr[0], - bitstream_size); - if (err) - return err; - - return 0; -} - -int tegra_vde_h264_decode_wait(struct tegra_ctx *ctx) -{ - return tegra_vde_decode_end(ctx->vde); -} diff --git a/drivers/staging/media/tegra-vde/iommu.c b/drivers/staging/media/tegra-vde/iommu.c deleted file mode 100644 index 5521ed3e465f..000000000000 --- a/drivers/staging/media/tegra-vde/iommu.c +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * NVIDIA Tegra Video decoder driver - * - * Copyright (C) 2016-2019 GRATE-DRIVER project - */ - -#include -#include -#include -#include - -#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) -#include -#endif - -#include "vde.h" - -int tegra_vde_iommu_map(struct tegra_vde *vde, - struct sg_table *sgt, - struct iova **iovap, - size_t size) -{ - struct iova *iova; - unsigned long shift; - unsigned long end; - dma_addr_t addr; - - end = vde->domain->geometry.aperture_end; - size = iova_align(&vde->iova, size); - shift = iova_shift(&vde->iova); - - iova = alloc_iova(&vde->iova, size >> shift, end >> shift, true); - if (!iova) - return -ENOMEM; - - addr = iova_dma_addr(&vde->iova, iova); - - size = iommu_map_sgtable(vde->domain, addr, sgt, - IOMMU_READ | IOMMU_WRITE); - if (!size) { - __free_iova(&vde->iova, iova); - return -ENXIO; - } - - *iovap = iova; - - return 0; -} - -void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova) -{ - unsigned long shift = iova_shift(&vde->iova); - unsigned long size = iova_size(iova) << shift; - dma_addr_t addr = iova_dma_addr(&vde->iova, iova); - - iommu_unmap(vde->domain, addr, size); - __free_iova(&vde->iova, iova); -} - -int tegra_vde_iommu_init(struct tegra_vde *vde) -{ - struct device *dev = vde->dev; - struct iova *iova; - unsigned long order; - unsigned long shift; - int err; - - vde->group = iommu_group_get(dev); - if (!vde->group) - return 0; - -#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU) - if (dev->archdata.mapping) { - struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev); - - arm_iommu_detach_device(dev); - arm_iommu_release_mapping(mapping); - } -#endif - vde->domain = iommu_domain_alloc(&platform_bus_type); - if (!vde->domain) { - err = -ENOMEM; - goto put_group; - } - - err = iova_cache_get(); - if (err) - goto free_domain; - - order = __ffs(vde->domain->pgsize_bitmap); - init_iova_domain(&vde->iova, 1UL << order, 0); - - err = iommu_attach_group(vde->domain, vde->group); - if (err) - goto put_iova; - - /* - * We're using some static addresses that are not accessible by VDE - * to trap invalid memory accesses. - */ - shift = iova_shift(&vde->iova); - iova = reserve_iova(&vde->iova, 0x60000000 >> shift, - 0x70000000 >> shift); - if (!iova) { - err = -ENOMEM; - goto detach_group; - } - - vde->iova_resv_static_addresses = iova; - - /* - * BSEV's end-address wraps around due to integer overflow during - * of hardware context preparation if IOVA is allocated at the end - * of address space and VDE can't handle that. Hence simply reserve - * the last page to avoid the problem. - */ - iova = reserve_iova(&vde->iova, 0xffffffff >> shift, - (0xffffffff >> shift) + 1); - if (!iova) { - err = -ENOMEM; - goto unreserve_iova; - } - - vde->iova_resv_last_page = iova; - - return 0; - -unreserve_iova: - __free_iova(&vde->iova, vde->iova_resv_static_addresses); -detach_group: - iommu_detach_group(vde->domain, vde->group); -put_iova: - put_iova_domain(&vde->iova); - iova_cache_put(); -free_domain: - iommu_domain_free(vde->domain); -put_group: - iommu_group_put(vde->group); - - return err; -} - -void tegra_vde_iommu_deinit(struct tegra_vde *vde) -{ - if (vde->domain) { - __free_iova(&vde->iova, vde->iova_resv_last_page); - __free_iova(&vde->iova, vde->iova_resv_static_addresses); - iommu_detach_group(vde->domain, vde->group); - put_iova_domain(&vde->iova); - iova_cache_put(); - iommu_domain_free(vde->domain); - iommu_group_put(vde->group); - - vde->domain = NULL; - } -} diff --git a/drivers/staging/media/tegra-vde/trace.h b/drivers/staging/media/tegra-vde/trace.h deleted file mode 100644 index e5714107db58..000000000000 --- a/drivers/staging/media/tegra-vde/trace.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM tegra_vde - -#if !defined(TEGRA_VDE_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -#define TEGRA_VDE_TRACE_H - -#include - -#include "vde.h" - -DECLARE_EVENT_CLASS(register_access, - TP_PROTO(struct tegra_vde *vde, void __iomem *base, - u32 offset, u32 value), - TP_ARGS(vde, base, offset, value), - TP_STRUCT__entry( - __string(hw_name, tegra_vde_reg_base_name(vde, base)) - __field(u32, offset) - __field(u32, value) - ), - TP_fast_assign( - __assign_str(hw_name, tegra_vde_reg_base_name(vde, base)); - __entry->offset = offset; - __entry->value = value; - ), - TP_printk("%s:0x%03x 0x%08x", __get_str(hw_name), __entry->offset, - __entry->value) -); - -DEFINE_EVENT(register_access, vde_writel, - TP_PROTO(struct tegra_vde *vde, void __iomem *base, - u32 offset, u32 value), - TP_ARGS(vde, base, offset, value)); -DEFINE_EVENT(register_access, vde_readl, - TP_PROTO(struct tegra_vde *vde, void __iomem *base, - u32 offset, u32 value), - TP_ARGS(vde, base, offset, value)); - -TRACE_EVENT(vde_setup_iram_entry, - TP_PROTO(unsigned int table, unsigned int row, u32 value, u32 aux_addr), - TP_ARGS(table, row, value, aux_addr), - TP_STRUCT__entry( - __field(unsigned int, table) - __field(unsigned int, row) - __field(u32, value) - __field(u32, aux_addr) - ), - TP_fast_assign( - __entry->table = table; - __entry->row = row; - __entry->value = value; - __entry->aux_addr = aux_addr; - ), - TP_printk("[%u][%u] = { 0x%08x (flags = \"%s\", frame_num = %u); 0x%08x }", - __entry->table, __entry->row, __entry->value, - __print_flags(__entry->value, " ", { (1 << 25), "B" }), - __entry->value & 0x7FFFFF, __entry->aux_addr) -); - -TRACE_EVENT(vde_ref_l0, - TP_PROTO(unsigned int frame_num), - TP_ARGS(frame_num), - TP_STRUCT__entry( - __field(unsigned int, frame_num) - ), - TP_fast_assign( - __entry->frame_num = frame_num; - ), - TP_printk("REF L0: DPB: Frame 0: frame_num = %u", __entry->frame_num) -); - -TRACE_EVENT(vde_ref_l1, - TP_PROTO(unsigned int with_later_poc_nb, - unsigned int with_earlier_poc_nb), - TP_ARGS(with_later_poc_nb, with_earlier_poc_nb), - TP_STRUCT__entry( - __field(unsigned int, with_later_poc_nb) - __field(unsigned int, with_earlier_poc_nb) - ), - TP_fast_assign( - __entry->with_later_poc_nb = with_later_poc_nb; - __entry->with_earlier_poc_nb = with_earlier_poc_nb; - ), - TP_printk("REF L1: with_later_poc_nb %u, with_earlier_poc_nb %u", - __entry->with_later_poc_nb, __entry->with_earlier_poc_nb) -); - -#endif /* TEGRA_VDE_TRACE_H */ - -/* This part must be outside protection */ -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH ../../drivers/staging/media/tegra-vde -#define TRACE_INCLUDE_FILE trace -#include diff --git a/drivers/staging/media/tegra-vde/v4l2.c b/drivers/staging/media/tegra-vde/v4l2.c deleted file mode 100644 index bd8c207d5b54..000000000000 --- a/drivers/staging/media/tegra-vde/v4l2.c +++ /dev/null @@ -1,1018 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * NVIDIA Tegra Video decoder driver - * - * Copyright (C) 2019-2022 Dmitry Osipenko - * - * Based on Cedrus driver by Bootlin. - * Copyright (C) 2016 Florent Revest - * Copyright (C) 2018 Paul Kocialkowski - * - * Based on Rockchip driver by Collabora. - * Copyright (C) 2019 Boris Brezillon - */ - -#include -#include - -#include "vde.h" - -static const struct v4l2_ctrl_config ctrl_cfgs[] = { - { .id = V4L2_CID_STATELESS_H264_DECODE_PARAMS, }, - { .id = V4L2_CID_STATELESS_H264_SPS, }, - { .id = V4L2_CID_STATELESS_H264_PPS, }, - { - .id = V4L2_CID_STATELESS_H264_DECODE_MODE, - .min = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, - .max = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, - .def = V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED, - }, - { - .id = V4L2_CID_STATELESS_H264_START_CODE, - .min = V4L2_STATELESS_H264_START_CODE_ANNEX_B, - .max = V4L2_STATELESS_H264_START_CODE_ANNEX_B, - .def = V4L2_STATELESS_H264_START_CODE_ANNEX_B, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, - .min = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, - .max = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, - .def = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, - .min = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, - .max = V4L2_MPEG_VIDEO_H264_LEVEL_5_1, - }, -}; - -static inline struct tegra_ctx *fh_to_tegra_ctx(struct v4l2_fh *fh) -{ - return container_of(fh, struct tegra_ctx, fh); -} - -static void tegra_set_control_data(struct tegra_ctx *ctx, void *data, u32 id) -{ - switch (id) { - case V4L2_CID_STATELESS_H264_DECODE_PARAMS: - ctx->h264.decode_params = data; - break; - case V4L2_CID_STATELESS_H264_SPS: - ctx->h264.sps = data; - break; - case V4L2_CID_STATELESS_H264_PPS: - ctx->h264.pps = data; - break; - } -} - -void tegra_vde_prepare_control_data(struct tegra_ctx *ctx, u32 id) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(ctrl_cfgs); i++) { - if (ctx->ctrls[i]->id == id) { - tegra_set_control_data(ctx, ctx->ctrls[i]->p_cur.p, id); - return; - } - } - - tegra_set_control_data(ctx, NULL, id); -} - -static int tegra_queue_setup(struct vb2_queue *vq, - unsigned int *nbufs, - unsigned int *num_planes, - unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct tegra_ctx *ctx = vb2_get_drv_priv(vq); - struct v4l2_format *f; - unsigned int i; - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) - f = &ctx->coded_fmt; - else - f = &ctx->decoded_fmt; - - if (*num_planes) { - if (*num_planes != f->fmt.pix_mp.num_planes) - return -EINVAL; - - for (i = 0; i < f->fmt.pix_mp.num_planes; i++) { - if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage) - return -EINVAL; - } - } else { - *num_planes = f->fmt.pix_mp.num_planes; - - for (i = 0; i < f->fmt.pix_mp.num_planes; i++) - sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage; - } - - return 0; -} - -static int tegra_buf_out_validate(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - - vbuf->field = V4L2_FIELD_NONE; - return 0; -} - -static void __tegra_buf_cleanup(struct vb2_buffer *vb, unsigned int i) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct tegra_ctx *ctx = vb2_get_drv_priv(vq); - struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); - - while (i--) { - if (tb->a[i]) { - tegra_vde_dmabuf_cache_unmap(ctx->vde, tb->a[i], true); - tb->a[i] = NULL; - } - - if (tb->iova[i]) { - tegra_vde_iommu_unmap(ctx->vde, tb->iova[i]); - tb->iova[i] = NULL; - } - } - - if (tb->aux) { - tegra_vde_free_bo(tb->aux); - tb->aux = NULL; - } -} - -static int tegra_buf_init(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct tegra_ctx *ctx = vb2_get_drv_priv(vq); - struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); - struct tegra_vde *vde = ctx->vde; - enum dma_data_direction dma_dir; - struct sg_table *sgt; - unsigned int i; - int err; - - if (V4L2_TYPE_IS_CAPTURE(vq->type) && vb->num_planes > 1) { - /* - * Tegra decoder writes auxiliary data for I/P frames. - * This data is needed for decoding of B frames. - */ - err = tegra_vde_alloc_bo(vde, &tb->aux, DMA_FROM_DEVICE, - vb2_plane_size(vb, 1)); - if (err) - return err; - } - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) - dma_dir = DMA_TO_DEVICE; - else - dma_dir = DMA_FROM_DEVICE; - - for (i = 0; i < vb->num_planes; i++) { - if (vq->memory == VB2_MEMORY_DMABUF) { - get_dma_buf(vb->planes[i].dbuf); - - err = tegra_vde_dmabuf_cache_map(vde, vb->planes[i].dbuf, - dma_dir, &tb->a[i], - &tb->dma_base[i]); - if (err) { - dma_buf_put(vb->planes[i].dbuf); - goto cleanup; - } - - continue; - } - - if (vde->domain) { - sgt = vb2_dma_sg_plane_desc(vb, i); - - err = tegra_vde_iommu_map(vde, sgt, &tb->iova[i], - vb2_plane_size(vb, i)); - if (err) - goto cleanup; - - tb->dma_base[i] = iova_dma_addr(&vde->iova, tb->iova[i]); - } else { - tb->dma_base[i] = vb2_dma_contig_plane_dma_addr(vb, i); - } - } - - return 0; - -cleanup: - __tegra_buf_cleanup(vb, i); - - return err; -} - -static void tegra_buf_cleanup(struct vb2_buffer *vb) -{ - __tegra_buf_cleanup(vb, vb->num_planes); -} - -static int tegra_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct tegra_ctx *ctx = vb2_get_drv_priv(vq); - struct tegra_m2m_buffer *tb = vb_to_tegra_buf(vb); - size_t hw_align, hw_size, hw_payload, size, offset; - struct v4l2_pix_format_mplane *pixfmt; - unsigned int i; - void *vb_data; - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) { - hw_align = BSEV_ALIGN; - pixfmt = &ctx->coded_fmt.fmt.pix_mp; - } else { - hw_align = FRAMEID_ALIGN; - pixfmt = &ctx->decoded_fmt.fmt.pix_mp; - } - - for (i = 0; i < vb->num_planes; i++) { - offset = vb->planes[i].data_offset; - - if (offset & (hw_align - 1)) - return -EINVAL; - - if (V4L2_TYPE_IS_CAPTURE(vq->type)) { - size = pixfmt->plane_fmt[i].sizeimage; - hw_payload = ALIGN(size, VDE_ATOM); - } else { - size = vb2_get_plane_payload(vb, i) - offset; - hw_payload = ALIGN(size + VDE_ATOM, SXE_BUFFER); - } - - hw_size = offset + hw_payload; - - if (vb2_plane_size(vb, i) < hw_size) - return -EINVAL; - - vb2_set_plane_payload(vb, i, hw_payload); - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) { - vb_data = vb2_plane_vaddr(vb, i); - - /* - * Hardware requires zero-padding of coded data. - * Otherwise it will fail to parse the trailing - * data and abort the decoding. - */ - if (vb_data) - memset(vb_data + offset + size, 0, - hw_size - offset - size); - } - - tb->dma_addr[i] = tb->dma_base[i] + offset; - } - - switch (pixfmt->pixelformat) { - case V4L2_PIX_FMT_YVU420M: - swap(tb->dma_addr[1], tb->dma_addr[2]); - break; - } - - return 0; -} - -static void tegra_buf_queue(struct vb2_buffer *vb) -{ - struct tegra_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); -} - -static void tegra_buf_request_complete(struct vb2_buffer *vb) -{ - struct tegra_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); -} - -static int tegra_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - return 0; -} - -static void tegra_stop_streaming(struct vb2_queue *vq) -{ - struct tegra_ctx *ctx = vb2_get_drv_priv(vq); - - while (true) { - struct vb2_v4l2_buffer *vbuf; - - if (V4L2_TYPE_IS_OUTPUT(vq->type)) - vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - else - vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - - if (!vbuf) - break; - - v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, &ctx->hdl); - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); - } -} - -static const struct vb2_ops tegra_qops = { - .queue_setup = tegra_queue_setup, - .buf_init = tegra_buf_init, - .buf_cleanup = tegra_buf_cleanup, - .buf_prepare = tegra_buf_prepare, - .buf_queue = tegra_buf_queue, - .buf_out_validate = tegra_buf_out_validate, - .buf_request_complete = tegra_buf_request_complete, - .start_streaming = tegra_start_streaming, - .stop_streaming = tegra_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -static int tegra_queue_init(void *priv, - struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - struct tegra_ctx *ctx = priv; - struct tegra_vde *vde = ctx->vde; - const struct vb2_mem_ops *mem_ops; - unsigned long dma_attrs; - int err; - - /* - * TODO: Switch to use of vb2_dma_contig_memops uniformly once we - * will add IOMMU_DOMAIN support for video decoder to tegra-smmu - * driver. For now we need to stick with SG ops in order to be able - * to get SGT table easily. This is suboptimal since SG mappings are - * wasting CPU cache and we don't need that caching. - */ - if (vde->domain) - mem_ops = &vb2_dma_sg_memops; - else - mem_ops = &vb2_dma_contig_memops; - - dma_attrs = DMA_ATTR_WRITE_COMBINE; - - src_vq->buf_struct_size = sizeof(struct tegra_m2m_buffer); - src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_DMABUF | VB2_MMAP; - src_vq->supports_requests = true; - src_vq->requires_requests = true; - src_vq->lock = &vde->v4l2_lock; - src_vq->dma_attrs = dma_attrs; - src_vq->mem_ops = mem_ops; - src_vq->ops = &tegra_qops; - src_vq->drv_priv = ctx; - src_vq->dev = vde->dev; - - err = vb2_queue_init(src_vq); - if (err) { - v4l2_err(&vde->v4l2_dev, - "failed to initialize src queue: %d\n", err); - return err; - } - - /* - * We may need to zero the end of bitstream in kernel if userspace - * doesn't do that, hence kmap is needed for the coded data. It's not - * needed for framebuffers. - */ - dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; - - dst_vq->buf_struct_size = sizeof(struct tegra_m2m_buffer); - dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; - dst_vq->lock = &vde->v4l2_lock; - dst_vq->dma_attrs = dma_attrs; - dst_vq->mem_ops = mem_ops; - dst_vq->ops = &tegra_qops; - dst_vq->drv_priv = ctx; - dst_vq->dev = vde->dev; - - err = vb2_queue_init(dst_vq); - if (err) { - v4l2_err(&vde->v4l2_dev, - "failed to initialize dst queue: %d\n", err); - return err; - } - - return 0; -} - -static void tegra_reset_fmt(struct tegra_ctx *ctx, struct v4l2_format *f, - u32 fourcc) -{ - memset(f, 0, sizeof(*f)); - f->fmt.pix_mp.pixelformat = fourcc; - f->fmt.pix_mp.field = V4L2_FIELD_NONE; - f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; - f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; - f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; -} - -static void tegra_reset_coded_fmt(struct tegra_ctx *ctx) -{ - const struct tegra_vde_soc *soc = ctx->vde->soc; - struct v4l2_format *f = &ctx->coded_fmt; - - ctx->coded_fmt_desc = &soc->coded_fmts[0]; - tegra_reset_fmt(ctx, f, ctx->coded_fmt_desc->fourcc); - - f->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - f->fmt.pix_mp.width = ctx->coded_fmt_desc->frmsize.min_width; - f->fmt.pix_mp.height = ctx->coded_fmt_desc->frmsize.min_height; -} - -static void tegra_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, - u32 pixelformat, u32 width, u32 height) -{ - const struct v4l2_format_info *info = v4l2_format_info(pixelformat); - struct v4l2_plane_pix_format *plane; - unsigned int i; - - switch (pixelformat) { - case V4L2_PIX_FMT_YUV420M: - case V4L2_PIX_FMT_YVU420M: - pixfmt->width = width; - pixfmt->height = height; - pixfmt->pixelformat = pixelformat; - pixfmt->num_planes = info->mem_planes; - - for (i = 0; i < pixfmt->num_planes; i++) { - unsigned int hdiv = (i == 0) ? 1 : 2; - unsigned int vdiv = (i == 0) ? 1 : 2; - - /* - * VDE is connected to Graphics Memory using 128bit port, - * all memory accesses are made using 16B atoms. - * - * V4L requires Cb/Cr strides to be exactly half of the - * Y stride, hence we're aligning Y to 16B x 2. - */ - plane = &pixfmt->plane_fmt[i]; - plane->bytesperline = ALIGN(width, VDE_ATOM * 2) / hdiv; - plane->sizeimage = plane->bytesperline * height / vdiv; - } - - break; - } -} - -static void tegra_reset_decoded_fmt(struct tegra_ctx *ctx) -{ - struct v4l2_format *f = &ctx->decoded_fmt; - - tegra_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]); - f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - tegra_fill_pixfmt_mp(&f->fmt.pix_mp, - ctx->coded_fmt_desc->decoded_fmts[0], - ctx->coded_fmt.fmt.pix_mp.width, - ctx->coded_fmt.fmt.pix_mp.height); -} - -static void tegra_job_finish(struct tegra_ctx *ctx, - enum vb2_buffer_state result) -{ - v4l2_m2m_buf_done_and_job_finish(ctx->vde->m2m, ctx->fh.m2m_ctx, - result); -} - -static void tegra_decode_complete(struct work_struct *work) -{ - struct tegra_ctx *ctx = container_of(work, struct tegra_ctx, work); - int err; - - err = ctx->coded_fmt_desc->decode_wait(ctx); - if (err) - tegra_job_finish(ctx, VB2_BUF_STATE_ERROR); - else - tegra_job_finish(ctx, VB2_BUF_STATE_DONE); -} - -static int tegra_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strscpy(cap->bus_info, "platform:tegra-vde", sizeof(cap->bus_info)); - strscpy(cap->driver, "tegra-vde", sizeof(cap->driver)); - strscpy(cap->card, "tegra-vde", sizeof(cap->card)); - - return 0; -} - -static int tegra_enum_decoded_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); - - if (WARN_ON(!ctx->coded_fmt_desc)) - return -EINVAL; - - if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts) - return -EINVAL; - - f->pixelformat = ctx->coded_fmt_desc->decoded_fmts[f->index]; - - return 0; -} - -static int tegra_g_decoded_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); - - *f = ctx->decoded_fmt; - return 0; -} - -static int tegra_try_decoded_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); - const struct tegra_coded_fmt_desc *coded_desc; - unsigned int i; - - /* - * The codec context should point to a coded format desc, if the format - * on the coded end has not been set yet, it should point to the - * default value. - */ - coded_desc = ctx->coded_fmt_desc; - if (WARN_ON(!coded_desc)) - return -EINVAL; - - if (!coded_desc->num_decoded_fmts) - return -EINVAL; - - for (i = 0; i < coded_desc->num_decoded_fmts; i++) { - if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) - break; - } - - if (i == coded_desc->num_decoded_fmts) - pix_mp->pixelformat = coded_desc->decoded_fmts[0]; - - /* always apply the frmsize constraint of the coded end */ - v4l2_apply_frmsize_constraints(&pix_mp->width, - &pix_mp->height, - &coded_desc->frmsize); - - tegra_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, - pix_mp->width, pix_mp->height); - pix_mp->field = V4L2_FIELD_NONE; - - return 0; -} - -static int tegra_s_decoded_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); - struct vb2_queue *vq; - int err; - - /* change not allowed if queue is busy */ - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (vb2_is_busy(vq)) - return -EBUSY; - - err = tegra_try_decoded_fmt(file, priv, f); - if (err) - return err; - - ctx->decoded_fmt = *f; - - return 0; -} - -static int tegra_enum_coded_fmt(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); - const struct tegra_vde_soc *soc = ctx->vde->soc; - - if (f->index >= soc->num_coded_fmts) - return -EINVAL; - - f->pixelformat = soc->coded_fmts[f->index].fourcc; - - return 0; -} - -static int tegra_g_coded_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); - - *f = ctx->coded_fmt; - return 0; -} - -static const struct tegra_coded_fmt_desc * -tegra_find_coded_fmt_desc(struct tegra_ctx *ctx, u32 fourcc) -{ - const struct tegra_vde_soc *soc = ctx->vde->soc; - unsigned int i; - - for (i = 0; i < soc->num_coded_fmts; i++) { - if (soc->coded_fmts[i].fourcc == fourcc) - return &soc->coded_fmts[i]; - } - - return NULL; -} - -static int tegra_try_coded_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); - const struct tegra_vde_soc *soc = ctx->vde->soc; - int size = pix_mp->plane_fmt[0].sizeimage; - const struct tegra_coded_fmt_desc *desc; - - desc = tegra_find_coded_fmt_desc(ctx, pix_mp->pixelformat); - if (!desc) { - pix_mp->pixelformat = soc->coded_fmts[0].fourcc; - desc = &soc->coded_fmts[0]; - } - - v4l2_apply_frmsize_constraints(&pix_mp->width, - &pix_mp->height, - &desc->frmsize); - - pix_mp->plane_fmt[0].sizeimage = max(ALIGN(size, SXE_BUFFER), SZ_2M); - pix_mp->field = V4L2_FIELD_NONE; - pix_mp->num_planes = 1; - - return 0; -} - -static int tegra_s_coded_fmt(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); - struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; - const struct tegra_coded_fmt_desc *desc; - struct vb2_queue *peer_vq, *vq; - struct v4l2_format *cap_fmt; - int err; - - /* - * In order to support dynamic resolution change, the decoder admits - * a resolution change, as long as the pixelformat remains. Can't be - * done if streaming. - */ - vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); - if (vb2_is_streaming(vq) || - (vb2_is_busy(vq) && - f->fmt.pix_mp.pixelformat != ctx->coded_fmt.fmt.pix_mp.pixelformat)) - return -EBUSY; - - /* - * Since format change on the OUTPUT queue will reset the CAPTURE - * queue, we can't allow doing so when the CAPTURE queue has buffers - * allocated. - */ - peer_vq = v4l2_m2m_get_vq(m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); - if (vb2_is_busy(peer_vq)) - return -EBUSY; - - err = tegra_try_coded_fmt(file, priv, f); - if (err) - return err; - - desc = tegra_find_coded_fmt_desc(ctx, f->fmt.pix_mp.pixelformat); - if (!desc) - return -EINVAL; - - ctx->coded_fmt_desc = desc; - ctx->coded_fmt = *f; - - /* - * Current decoded format might have become invalid with newly - * selected codec, so reset it to default just to be safe and - * keep internal driver state sane. User is mandated to set - * the decoded format again after we return, so we don't need - * anything smarter. - * - * Note that this will propagates any size changes to the decoded format. - */ - tegra_reset_decoded_fmt(ctx); - - /* propagate colorspace information to capture */ - cap_fmt = &ctx->decoded_fmt; - cap_fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; - cap_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; - cap_fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; - cap_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; - - return 0; -} - -static int tegra_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - struct tegra_ctx *ctx = fh_to_tegra_ctx(priv); - const struct tegra_coded_fmt_desc *fmt; - - if (fsize->index) - return -EINVAL; - - fmt = tegra_find_coded_fmt_desc(ctx, fsize->pixel_format); - if (!fmt) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = fmt->frmsize; - - return 0; -} - -static const struct v4l2_ioctl_ops tegra_v4l2_ioctl_ops = { - .vidioc_querycap = tegra_querycap, - .vidioc_enum_framesizes = tegra_enum_framesizes, - - .vidioc_try_fmt_vid_out_mplane = tegra_try_coded_fmt, - .vidioc_g_fmt_vid_out_mplane = tegra_g_coded_fmt, - .vidioc_s_fmt_vid_out_mplane = tegra_s_coded_fmt, - .vidioc_enum_fmt_vid_out = tegra_enum_coded_fmt, - - .vidioc_try_fmt_vid_cap_mplane = tegra_try_decoded_fmt, - .vidioc_g_fmt_vid_cap_mplane = tegra_g_decoded_fmt, - .vidioc_s_fmt_vid_cap_mplane = tegra_s_decoded_fmt, - .vidioc_enum_fmt_vid_cap = tegra_enum_decoded_fmt, - - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, - .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, - .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, - .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static int tegra_init_ctrls(struct tegra_ctx *ctx) -{ - unsigned int i; - int err; - - err = v4l2_ctrl_handler_init(&ctx->hdl, ARRAY_SIZE(ctrl_cfgs)); - if (err) - return err; - - for (i = 0; i < ARRAY_SIZE(ctrl_cfgs); i++) { - ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->hdl, &ctrl_cfgs[i], - NULL); - if (ctx->hdl.error) { - err = ctx->hdl.error; - goto free_ctrls; - } - } - - err = v4l2_ctrl_handler_setup(&ctx->hdl); - if (err) - goto free_ctrls; - - ctx->fh.ctrl_handler = &ctx->hdl; - - return 0; - -free_ctrls: - v4l2_ctrl_handler_free(&ctx->hdl); - - return err; -} - -static int tegra_init_m2m(struct tegra_ctx *ctx) -{ - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(ctx->vde->m2m, - ctx, tegra_queue_init); - if (IS_ERR(ctx->fh.m2m_ctx)) - return PTR_ERR(ctx->fh.m2m_ctx); - - return 0; -} - -static int tegra_open(struct file *file) -{ - struct tegra_vde *vde = video_drvdata(file); - struct tegra_ctx *ctx; - int err; - - ctx = kzalloc(offsetof(struct tegra_ctx, ctrls[ARRAY_SIZE(ctrl_cfgs)]), - GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->vde = vde; - v4l2_fh_init(&ctx->fh, video_devdata(file)); - INIT_WORK(&ctx->work, tegra_decode_complete); - - err = tegra_init_ctrls(ctx); - if (err) { - v4l2_err(&vde->v4l2_dev, "failed to add controls: %d\n", err); - goto free_ctx; - } - - err = tegra_init_m2m(ctx); - if (err) { - v4l2_err(&vde->v4l2_dev, "failed to initialize m2m: %d\n", err); - goto free_ctrls; - } - - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - - tegra_reset_coded_fmt(ctx); - tegra_try_coded_fmt(file, file->private_data, &ctx->coded_fmt); - - tegra_reset_decoded_fmt(ctx); - tegra_try_decoded_fmt(file, file->private_data, &ctx->decoded_fmt); - - return 0; - -free_ctrls: - v4l2_ctrl_handler_free(&ctx->hdl); -free_ctx: - kfree(ctx); - - return err; -} - -static int tegra_release(struct file *file) -{ - struct v4l2_fh *fh = file->private_data; - struct tegra_ctx *ctx = fh_to_tegra_ctx(fh); - struct tegra_vde *vde = ctx->vde; - - v4l2_fh_del(fh); - v4l2_m2m_ctx_release(fh->m2m_ctx); - v4l2_ctrl_handler_free(&ctx->hdl); - v4l2_fh_exit(fh); - kfree(ctx); - - tegra_vde_dmabuf_cache_unmap_sync(vde); - - return 0; -} - -static const struct v4l2_file_operations tegra_v4l2_fops = { - .owner = THIS_MODULE, - .open = tegra_open, - .poll = v4l2_m2m_fop_poll, - .mmap = v4l2_m2m_fop_mmap, - .release = tegra_release, - .unlocked_ioctl = video_ioctl2, -}; - -static void tegra_device_run(void *priv) -{ - struct tegra_ctx *ctx = priv; - struct vb2_v4l2_buffer *src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - struct media_request *src_req = src->vb2_buf.req_obj.req; - int err; - - v4l2_ctrl_request_setup(src_req, &ctx->hdl); - - err = ctx->coded_fmt_desc->decode_run(ctx); - - v4l2_ctrl_request_complete(src_req, &ctx->hdl); - - if (err) - tegra_job_finish(ctx, VB2_BUF_STATE_ERROR); - else - queue_work(ctx->vde->wq, &ctx->work); -} - -static const struct v4l2_m2m_ops tegra_v4l2_m2m_ops = { - .device_run = tegra_device_run, -}; - -static int tegra_request_validate(struct media_request *req) -{ - unsigned int count; - - count = vb2_request_buffer_cnt(req); - if (!count) - return -ENOENT; - else if (count > 1) - return -EINVAL; - - return vb2_request_validate(req); -} - -static const struct media_device_ops tegra_media_device_ops = { - .req_validate = tegra_request_validate, - .req_queue = v4l2_m2m_request_queue, -}; - -int tegra_vde_v4l2_init(struct tegra_vde *vde) -{ - struct device *dev = vde->dev; - int err; - - mutex_init(&vde->v4l2_lock); - media_device_init(&vde->mdev); - video_set_drvdata(&vde->vdev, vde); - - vde->vdev.lock = &vde->v4l2_lock, - vde->vdev.fops = &tegra_v4l2_fops, - vde->vdev.vfl_dir = VFL_DIR_M2M, - vde->vdev.release = video_device_release_empty, - vde->vdev.v4l2_dev = &vde->v4l2_dev; - vde->vdev.ioctl_ops = &tegra_v4l2_ioctl_ops, - vde->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, - - vde->v4l2_dev.mdev = &vde->mdev; - vde->mdev.ops = &tegra_media_device_ops; - vde->mdev.dev = dev; - - strscpy(vde->mdev.model, "tegra-vde", sizeof(vde->mdev.model)); - strscpy(vde->vdev.name, "tegra-vde", sizeof(vde->vdev.name)); - strscpy(vde->mdev.bus_info, "platform:tegra-vde", - sizeof(vde->mdev.bus_info)); - - vde->wq = create_workqueue("tegra-vde"); - if (!vde->wq) - return -ENOMEM; - - err = media_device_register(&vde->mdev); - if (err) { - dev_err(dev, "failed to register media device: %d\n", err); - goto clean_up_media_device; - } - - err = v4l2_device_register(dev, &vde->v4l2_dev); - if (err) { - dev_err(dev, "failed to register v4l2 device: %d\n", err); - goto unreg_media_device; - } - - err = video_register_device(&vde->vdev, VFL_TYPE_VIDEO, -1); - if (err) { - dev_err(dev, "failed to register video device: %d\n", err); - goto unreg_v4l2; - } - - vde->m2m = v4l2_m2m_init(&tegra_v4l2_m2m_ops); - err = PTR_ERR_OR_ZERO(vde->m2m); - if (err) { - dev_err(dev, "failed to initialize m2m device: %d\n", err); - goto unreg_video_device; - } - - err = v4l2_m2m_register_media_controller(vde->m2m, &vde->vdev, - MEDIA_ENT_F_PROC_VIDEO_DECODER); - if (err) { - dev_err(dev, "failed to register media controller: %d\n", err); - goto release_m2m; - } - - v4l2_info(&vde->v4l2_dev, "v4l2 device registered as /dev/video%d\n", - vde->vdev.num); - - return 0; - -release_m2m: - v4l2_m2m_release(vde->m2m); -unreg_video_device: - video_unregister_device(&vde->vdev); -unreg_v4l2: - v4l2_device_unregister(&vde->v4l2_dev); -unreg_media_device: - media_device_unregister(&vde->mdev); -clean_up_media_device: - media_device_cleanup(&vde->mdev); - - destroy_workqueue(vde->wq); - - return err; -} - -void tegra_vde_v4l2_deinit(struct tegra_vde *vde) -{ - v4l2_m2m_unregister_media_controller(vde->m2m); - v4l2_m2m_release(vde->m2m); - - video_unregister_device(&vde->vdev); - v4l2_device_unregister(&vde->v4l2_dev); - - media_device_unregister(&vde->mdev); - media_device_cleanup(&vde->mdev); - - destroy_workqueue(vde->wq); -} diff --git a/drivers/staging/media/tegra-vde/vde.c b/drivers/staging/media/tegra-vde/vde.c deleted file mode 100644 index f3e863a94c5a..000000000000 --- a/drivers/staging/media/tegra-vde/vde.c +++ /dev/null @@ -1,551 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * NVIDIA Tegra Video decoder driver - * - * Copyright (C) 2016-2017 Dmitry Osipenko - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "vde.h" - -#define CREATE_TRACE_POINTS -#include "trace.h" - -void tegra_vde_writel(struct tegra_vde *vde, u32 value, - void __iomem *base, u32 offset) -{ - trace_vde_writel(vde, base, offset, value); - - writel_relaxed(value, base + offset); -} - -u32 tegra_vde_readl(struct tegra_vde *vde, void __iomem *base, u32 offset) -{ - u32 value = readl_relaxed(base + offset); - - trace_vde_readl(vde, base, offset, value); - - return value; -} - -void tegra_vde_set_bits(struct tegra_vde *vde, u32 mask, - void __iomem *base, u32 offset) -{ - u32 value = tegra_vde_readl(vde, base, offset); - - tegra_vde_writel(vde, value | mask, base, offset); -} - -int tegra_vde_alloc_bo(struct tegra_vde *vde, - struct tegra_vde_bo **ret_bo, - enum dma_data_direction dma_dir, - size_t size) -{ - struct device *dev = vde->dev; - struct tegra_vde_bo *bo; - int err; - - bo = kzalloc(sizeof(*bo), GFP_KERNEL); - if (!bo) - return -ENOMEM; - - bo->vde = vde; - bo->size = size; - bo->dma_dir = dma_dir; - bo->dma_attrs = DMA_ATTR_WRITE_COMBINE | - DMA_ATTR_NO_KERNEL_MAPPING; - - if (!vde->domain) - bo->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS; - - bo->dma_cookie = dma_alloc_attrs(dev, bo->size, &bo->dma_handle, - GFP_KERNEL, bo->dma_attrs); - if (!bo->dma_cookie) { - dev_err(dev, "Failed to allocate DMA buffer of size: %zu\n", - bo->size); - err = -ENOMEM; - goto free_bo; - } - - err = dma_get_sgtable_attrs(dev, &bo->sgt, bo->dma_cookie, - bo->dma_handle, bo->size, bo->dma_attrs); - if (err) { - dev_err(dev, "Failed to get DMA buffer SG table: %d\n", err); - goto free_attrs; - } - - err = dma_map_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs); - if (err) { - dev_err(dev, "Failed to map DMA buffer SG table: %d\n", err); - goto free_table; - } - - if (vde->domain) { - err = tegra_vde_iommu_map(vde, &bo->sgt, &bo->iova, bo->size); - if (err) { - dev_err(dev, "Failed to map DMA buffer IOVA: %d\n", err); - goto unmap_sgtable; - } - - bo->dma_addr = iova_dma_addr(&vde->iova, bo->iova); - } else { - bo->dma_addr = sg_dma_address(bo->sgt.sgl); - } - - *ret_bo = bo; - - return 0; - -unmap_sgtable: - dma_unmap_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs); -free_table: - sg_free_table(&bo->sgt); -free_attrs: - dma_free_attrs(dev, bo->size, bo->dma_cookie, bo->dma_handle, - bo->dma_attrs); -free_bo: - kfree(bo); - - return err; -} - -void tegra_vde_free_bo(struct tegra_vde_bo *bo) -{ - struct tegra_vde *vde = bo->vde; - struct device *dev = vde->dev; - - if (vde->domain) - tegra_vde_iommu_unmap(vde, bo->iova); - - dma_unmap_sgtable(dev, &bo->sgt, bo->dma_dir, bo->dma_attrs); - - sg_free_table(&bo->sgt); - - dma_free_attrs(dev, bo->size, bo->dma_cookie, bo->dma_handle, - bo->dma_attrs); - kfree(bo); -} - -static irqreturn_t tegra_vde_isr(int irq, void *data) -{ - struct tegra_vde *vde = data; - - if (completion_done(&vde->decode_completion)) - return IRQ_NONE; - - tegra_vde_set_bits(vde, 0, vde->frameid, 0x208); - complete(&vde->decode_completion); - - return IRQ_HANDLED; -} - -static __maybe_unused int tegra_vde_runtime_suspend(struct device *dev) -{ - struct tegra_vde *vde = dev_get_drvdata(dev); - int err; - - if (!dev->pm_domain) { - err = tegra_powergate_power_off(TEGRA_POWERGATE_VDEC); - if (err) { - dev_err(dev, "Failed to power down HW: %d\n", err); - return err; - } - } - - clk_disable_unprepare(vde->clk); - reset_control_release(vde->rst); - reset_control_release(vde->rst_mc); - - return 0; -} - -static __maybe_unused int tegra_vde_runtime_resume(struct device *dev) -{ - struct tegra_vde *vde = dev_get_drvdata(dev); - int err; - - err = reset_control_acquire(vde->rst_mc); - if (err) { - dev_err(dev, "Failed to acquire mc reset: %d\n", err); - return err; - } - - err = reset_control_acquire(vde->rst); - if (err) { - dev_err(dev, "Failed to acquire reset: %d\n", err); - goto release_mc_reset; - } - - if (!dev->pm_domain) { - err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC, - vde->clk, vde->rst); - if (err) { - dev_err(dev, "Failed to power up HW : %d\n", err); - goto release_reset; - } - } else { - /* - * tegra_powergate_sequence_power_up() leaves clocks enabled, - * while GENPD not. - */ - err = clk_prepare_enable(vde->clk); - if (err) { - dev_err(dev, "Failed to enable clock: %d\n", err); - goto release_reset; - } - } - - return 0; - -release_reset: - reset_control_release(vde->rst); -release_mc_reset: - reset_control_release(vde->rst_mc); - - return err; -} - -static int tegra_vde_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct tegra_vde *vde; - int irq, err; - - vde = devm_kzalloc(dev, sizeof(*vde), GFP_KERNEL); - if (!vde) - return -ENOMEM; - - platform_set_drvdata(pdev, vde); - - vde->soc = of_device_get_match_data(&pdev->dev); - vde->dev = dev; - - vde->sxe = devm_platform_ioremap_resource_byname(pdev, "sxe"); - if (IS_ERR(vde->sxe)) - return PTR_ERR(vde->sxe); - - vde->bsev = devm_platform_ioremap_resource_byname(pdev, "bsev"); - if (IS_ERR(vde->bsev)) - return PTR_ERR(vde->bsev); - - vde->mbe = devm_platform_ioremap_resource_byname(pdev, "mbe"); - if (IS_ERR(vde->mbe)) - return PTR_ERR(vde->mbe); - - vde->ppe = devm_platform_ioremap_resource_byname(pdev, "ppe"); - if (IS_ERR(vde->ppe)) - return PTR_ERR(vde->ppe); - - vde->mce = devm_platform_ioremap_resource_byname(pdev, "mce"); - if (IS_ERR(vde->mce)) - return PTR_ERR(vde->mce); - - vde->tfe = devm_platform_ioremap_resource_byname(pdev, "tfe"); - if (IS_ERR(vde->tfe)) - return PTR_ERR(vde->tfe); - - vde->ppb = devm_platform_ioremap_resource_byname(pdev, "ppb"); - if (IS_ERR(vde->ppb)) - return PTR_ERR(vde->ppb); - - vde->vdma = devm_platform_ioremap_resource_byname(pdev, "vdma"); - if (IS_ERR(vde->vdma)) - return PTR_ERR(vde->vdma); - - vde->frameid = devm_platform_ioremap_resource_byname(pdev, "frameid"); - if (IS_ERR(vde->frameid)) - return PTR_ERR(vde->frameid); - - vde->clk = devm_clk_get(dev, NULL); - if (IS_ERR(vde->clk)) { - err = PTR_ERR(vde->clk); - dev_err(dev, "Could not get VDE clk %d\n", err); - return err; - } - - vde->rst = devm_reset_control_get_exclusive_released(dev, NULL); - if (IS_ERR(vde->rst)) { - err = PTR_ERR(vde->rst); - dev_err(dev, "Could not get VDE reset %d\n", err); - return err; - } - - vde->rst_mc = devm_reset_control_get_optional_exclusive_released(dev, "mc"); - if (IS_ERR(vde->rst_mc)) { - err = PTR_ERR(vde->rst_mc); - dev_err(dev, "Could not get MC reset %d\n", err); - return err; - } - - irq = platform_get_irq_byname(pdev, "sync-token"); - if (irq < 0) - return irq; - - err = devm_request_irq(dev, irq, tegra_vde_isr, 0, - dev_name(dev), vde); - if (err) { - dev_err(dev, "Could not request IRQ %d\n", err); - return err; - } - - err = devm_tegra_core_dev_init_opp_table_common(dev); - if (err) { - dev_err(dev, "Could initialize OPP table %d\n", err); - return err; - } - - vde->iram_pool = of_gen_pool_get(dev->of_node, "iram", 0); - if (!vde->iram_pool) { - dev_err(dev, "Could not get IRAM pool\n"); - return -EPROBE_DEFER; - } - - vde->iram = gen_pool_dma_alloc(vde->iram_pool, - gen_pool_size(vde->iram_pool), - &vde->iram_lists_addr); - if (!vde->iram) { - dev_err(dev, "Could not reserve IRAM\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&vde->map_list); - mutex_init(&vde->map_lock); - mutex_init(&vde->lock); - init_completion(&vde->decode_completion); - - err = tegra_vde_iommu_init(vde); - if (err) { - dev_err(dev, "Failed to initialize IOMMU: %d\n", err); - goto err_gen_free; - } - - pm_runtime_enable(dev); - pm_runtime_use_autosuspend(dev); - pm_runtime_set_autosuspend_delay(dev, 300); - - /* - * VDE partition may be left ON after bootloader, hence let's - * power-cycle it in order to put hardware into a predictable lower - * power state. - */ - err = pm_runtime_resume_and_get(dev); - if (err) - goto err_pm_runtime; - - pm_runtime_put(dev); - - err = tegra_vde_alloc_bo(vde, &vde->secure_bo, DMA_FROM_DEVICE, 4096); - if (err) { - dev_err(dev, "Failed to allocate secure BO: %d\n", err); - goto err_pm_runtime; - } - - err = tegra_vde_v4l2_init(vde); - if (err) { - dev_err(dev, "Failed to initialize V4L2: %d\n", err); - goto err_free_secure_bo; - } - - return 0; - -err_free_secure_bo: - tegra_vde_free_bo(vde->secure_bo); -err_pm_runtime: - pm_runtime_dont_use_autosuspend(dev); - pm_runtime_disable(dev); - - tegra_vde_iommu_deinit(vde); - -err_gen_free: - gen_pool_free(vde->iram_pool, (unsigned long)vde->iram, - gen_pool_size(vde->iram_pool)); - - return err; -} - -static int tegra_vde_remove(struct platform_device *pdev) -{ - struct tegra_vde *vde = platform_get_drvdata(pdev); - struct device *dev = &pdev->dev; - - tegra_vde_v4l2_deinit(vde); - tegra_vde_free_bo(vde->secure_bo); - - /* - * As it increments RPM usage_count even on errors, we don't need to - * check the returned code here. - */ - pm_runtime_get_sync(dev); - - pm_runtime_dont_use_autosuspend(dev); - pm_runtime_disable(dev); - - /* - * Balance RPM state, the VDE power domain is left ON and hardware - * is clock-gated. It's safe to reboot machine now. - */ - pm_runtime_put_noidle(dev); - clk_disable_unprepare(vde->clk); - - tegra_vde_dmabuf_cache_unmap_all(vde); - tegra_vde_iommu_deinit(vde); - - gen_pool_free(vde->iram_pool, (unsigned long)vde->iram, - gen_pool_size(vde->iram_pool)); - - return 0; -} - -static void tegra_vde_shutdown(struct platform_device *pdev) -{ - /* - * On some devices bootloader isn't ready to a power-gated VDE on - * a warm-reboot, machine will hang in that case. - */ - pm_runtime_get_sync(&pdev->dev); -} - -static __maybe_unused int tegra_vde_pm_suspend(struct device *dev) -{ - struct tegra_vde *vde = dev_get_drvdata(dev); - int err; - - mutex_lock(&vde->lock); - - err = pm_runtime_force_suspend(dev); - if (err < 0) - return err; - - return 0; -} - -static __maybe_unused int tegra_vde_pm_resume(struct device *dev) -{ - struct tegra_vde *vde = dev_get_drvdata(dev); - int err; - - err = pm_runtime_force_resume(dev); - if (err < 0) - return err; - - mutex_unlock(&vde->lock); - - return 0; -} - -static const struct dev_pm_ops tegra_vde_pm_ops = { - SET_RUNTIME_PM_OPS(tegra_vde_runtime_suspend, - tegra_vde_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(tegra_vde_pm_suspend, - tegra_vde_pm_resume) -}; - -static const u32 tegra124_decoded_fmts[] = { - /* TBD: T124 supports only a non-standard Tegra tiled format */ -}; - -static const struct tegra_coded_fmt_desc tegra124_coded_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_H264_SLICE, - .frmsize = { - .min_width = 16, - .max_width = 1920, - .step_width = 16, - .min_height = 16, - .max_height = 2032, - .step_height = 16, - }, - .num_decoded_fmts = ARRAY_SIZE(tegra124_decoded_fmts), - .decoded_fmts = tegra124_decoded_fmts, - .decode_run = tegra_vde_h264_decode_run, - .decode_wait = tegra_vde_h264_decode_wait, - }, -}; - -static const u32 tegra20_decoded_fmts[] = { - V4L2_PIX_FMT_YUV420M, - V4L2_PIX_FMT_YVU420M, -}; - -static const struct tegra_coded_fmt_desc tegra20_coded_fmts[] = { - { - .fourcc = V4L2_PIX_FMT_H264_SLICE, - .frmsize = { - .min_width = 16, - .max_width = 1920, - .step_width = 16, - .min_height = 16, - .max_height = 2032, - .step_height = 16, - }, - .num_decoded_fmts = ARRAY_SIZE(tegra20_decoded_fmts), - .decoded_fmts = tegra20_decoded_fmts, - .decode_run = tegra_vde_h264_decode_run, - .decode_wait = tegra_vde_h264_decode_wait, - }, -}; - -static const struct tegra_vde_soc tegra124_vde_soc = { - .supports_ref_pic_marking = true, - .coded_fmts = tegra124_coded_fmts, - .num_coded_fmts = ARRAY_SIZE(tegra124_coded_fmts), -}; - -static const struct tegra_vde_soc tegra114_vde_soc = { - .supports_ref_pic_marking = true, - .coded_fmts = tegra20_coded_fmts, - .num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts), -}; - -static const struct tegra_vde_soc tegra30_vde_soc = { - .supports_ref_pic_marking = false, - .coded_fmts = tegra20_coded_fmts, - .num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts), -}; - -static const struct tegra_vde_soc tegra20_vde_soc = { - .supports_ref_pic_marking = false, - .coded_fmts = tegra20_coded_fmts, - .num_coded_fmts = ARRAY_SIZE(tegra20_coded_fmts), -}; - -static const struct of_device_id tegra_vde_of_match[] = { - { .compatible = "nvidia,tegra124-vde", .data = &tegra124_vde_soc }, - { .compatible = "nvidia,tegra114-vde", .data = &tegra114_vde_soc }, - { .compatible = "nvidia,tegra30-vde", .data = &tegra30_vde_soc }, - { .compatible = "nvidia,tegra20-vde", .data = &tegra20_vde_soc }, - { }, -}; -MODULE_DEVICE_TABLE(of, tegra_vde_of_match); - -static struct platform_driver tegra_vde_driver = { - .probe = tegra_vde_probe, - .remove = tegra_vde_remove, - .shutdown = tegra_vde_shutdown, - .driver = { - .name = "tegra-vde", - .of_match_table = tegra_vde_of_match, - .pm = &tegra_vde_pm_ops, - }, -}; -module_platform_driver(tegra_vde_driver); - -MODULE_DESCRIPTION("NVIDIA Tegra Video Decoder driver"); -MODULE_AUTHOR("Dmitry Osipenko "); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/tegra-vde/vde.h b/drivers/staging/media/tegra-vde/vde.h deleted file mode 100644 index 0fbb1f3d2c88..000000000000 --- a/drivers/staging/media/tegra-vde/vde.h +++ /dev/null @@ -1,242 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * NVIDIA Tegra Video decoder driver - * - * Copyright (C) 2016-2019 GRATE-DRIVER project - */ - -#ifndef TEGRA_VDE_H -#define TEGRA_VDE_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define ICMDQUE_WR 0x00 -#define CMDQUE_CONTROL 0x08 -#define INTR_STATUS 0x18 -#define BSE_INT_ENB 0x40 -#define BSE_CONFIG 0x44 - -#define BSE_ICMDQUE_EMPTY BIT(3) -#define BSE_DMA_BUSY BIT(23) - -#define BSEV_ALIGN SZ_1 -#define FRAMEID_ALIGN SZ_256 -#define SXE_BUFFER SZ_32K -#define VDE_ATOM SZ_16 - -struct clk; -struct dma_buf; -struct gen_pool; -struct tegra_ctx; -struct iommu_group; -struct iommu_domain; -struct reset_control; -struct dma_buf_attachment; -struct tegra_vde_h264_frame; -struct tegra_vde_h264_decoder_ctx; - -struct tegra_video_frame { - struct dma_buf_attachment *y_dmabuf_attachment; - struct dma_buf_attachment *cb_dmabuf_attachment; - struct dma_buf_attachment *cr_dmabuf_attachment; - struct dma_buf_attachment *aux_dmabuf_attachment; - dma_addr_t y_addr; - dma_addr_t cb_addr; - dma_addr_t cr_addr; - dma_addr_t aux_addr; - u32 frame_num; - u32 flags; - u32 luma_atoms_pitch; - u32 chroma_atoms_pitch; -}; - -struct tegra_coded_fmt_desc { - u32 fourcc; - struct v4l2_frmsize_stepwise frmsize; - unsigned int num_decoded_fmts; - const u32 *decoded_fmts; - int (*decode_run)(struct tegra_ctx *ctx); - int (*decode_wait)(struct tegra_ctx *ctx); -}; - -struct tegra_vde_soc { - bool supports_ref_pic_marking; - const struct tegra_coded_fmt_desc *coded_fmts; - u32 num_coded_fmts; -}; - -struct tegra_vde_bo { - struct iova *iova; - struct sg_table sgt; - struct tegra_vde *vde; - enum dma_data_direction dma_dir; - unsigned long dma_attrs; - dma_addr_t dma_handle; - dma_addr_t dma_addr; - void *dma_cookie; - size_t size; -}; - -struct tegra_vde { - void __iomem *sxe; - void __iomem *bsev; - void __iomem *mbe; - void __iomem *ppe; - void __iomem *mce; - void __iomem *tfe; - void __iomem *ppb; - void __iomem *vdma; - void __iomem *frameid; - struct device *dev; - struct mutex lock; - struct mutex map_lock; - struct list_head map_list; - struct reset_control *rst; - struct reset_control *rst_mc; - struct gen_pool *iram_pool; - struct completion decode_completion; - struct clk *clk; - struct iommu_domain *domain; - struct iommu_group *group; - struct iova_domain iova; - struct iova *iova_resv_static_addresses; - struct iova *iova_resv_last_page; - const struct tegra_vde_soc *soc; - struct tegra_vde_bo *secure_bo; - dma_addr_t bitstream_data_addr; - dma_addr_t iram_lists_addr; - u32 *iram; - struct v4l2_device v4l2_dev; - struct v4l2_m2m_dev *m2m; - struct media_device mdev; - struct video_device vdev; - struct mutex v4l2_lock; - struct workqueue_struct *wq; - struct tegra_video_frame frames[V4L2_H264_NUM_DPB_ENTRIES + 1]; -}; - -int tegra_vde_alloc_bo(struct tegra_vde *vde, - struct tegra_vde_bo **ret_bo, - enum dma_data_direction dma_dir, - size_t size); -void tegra_vde_free_bo(struct tegra_vde_bo *bo); - -struct tegra_ctx_h264 { - const struct v4l2_ctrl_h264_decode_params *decode_params; - const struct v4l2_ctrl_h264_sps *sps; - const struct v4l2_ctrl_h264_pps *pps; -}; - -struct tegra_ctx { - struct tegra_vde *vde; - struct tegra_ctx_h264 h264; - struct work_struct work; - struct v4l2_fh fh; - struct v4l2_ctrl_handler hdl; - struct v4l2_format coded_fmt; - struct v4l2_format decoded_fmt; - const struct tegra_coded_fmt_desc *coded_fmt_desc; - struct v4l2_ctrl *ctrls[]; -}; - -struct tegra_m2m_buffer { - struct v4l2_m2m_buffer m2m; - struct dma_buf_attachment *a[VB2_MAX_PLANES]; - dma_addr_t dma_base[VB2_MAX_PLANES]; - dma_addr_t dma_addr[VB2_MAX_PLANES]; - struct iova *iova[VB2_MAX_PLANES]; - struct tegra_vde_bo *aux; - bool b_frame; -}; - -static inline struct tegra_m2m_buffer * -vb_to_tegra_buf(struct vb2_buffer *vb) -{ - struct v4l2_m2m_buffer *m2m = container_of(vb, struct v4l2_m2m_buffer, - vb.vb2_buf); - - return container_of(m2m, struct tegra_m2m_buffer, m2m); -} - -void tegra_vde_prepare_control_data(struct tegra_ctx *ctx, u32 id); - -void tegra_vde_writel(struct tegra_vde *vde, u32 value, void __iomem *base, - u32 offset); -u32 tegra_vde_readl(struct tegra_vde *vde, void __iomem *base, u32 offset); -void tegra_vde_set_bits(struct tegra_vde *vde, u32 mask, void __iomem *base, - u32 offset); - -int tegra_vde_h264_decode_run(struct tegra_ctx *ctx); -int tegra_vde_h264_decode_wait(struct tegra_ctx *ctx); - -int tegra_vde_iommu_init(struct tegra_vde *vde); -void tegra_vde_iommu_deinit(struct tegra_vde *vde); -int tegra_vde_iommu_map(struct tegra_vde *vde, - struct sg_table *sgt, - struct iova **iovap, - size_t size); -void tegra_vde_iommu_unmap(struct tegra_vde *vde, struct iova *iova); - -int tegra_vde_dmabuf_cache_map(struct tegra_vde *vde, - struct dma_buf *dmabuf, - enum dma_data_direction dma_dir, - struct dma_buf_attachment **ap, - dma_addr_t *addrp); -void tegra_vde_dmabuf_cache_unmap(struct tegra_vde *vde, - struct dma_buf_attachment *a, - bool release); -void tegra_vde_dmabuf_cache_unmap_sync(struct tegra_vde *vde); -void tegra_vde_dmabuf_cache_unmap_all(struct tegra_vde *vde); - -static __maybe_unused char const * -tegra_vde_reg_base_name(struct tegra_vde *vde, void __iomem *base) -{ - if (vde->sxe == base) - return "SXE"; - - if (vde->bsev == base) - return "BSEV"; - - if (vde->mbe == base) - return "MBE"; - - if (vde->ppe == base) - return "PPE"; - - if (vde->mce == base) - return "MCE"; - - if (vde->tfe == base) - return "TFE"; - - if (vde->ppb == base) - return "PPB"; - - if (vde->vdma == base) - return "VDMA"; - - if (vde->frameid == base) - return "FRAMEID"; - - return "???"; -} - -int tegra_vde_v4l2_init(struct tegra_vde *vde); -void tegra_vde_v4l2_deinit(struct tegra_vde *vde); - -#endif /* TEGRA_VDE_H */ -- cgit v1.2.3 From 9958d30f38b96fb763a10d44d18ddad39127d5f4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Mar 2022 07:25:46 +0100 Subject: media: Kconfig: cleanup VIDEO_DEV dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit media Kconfig has two entries associated to V4L API: VIDEO_DEV and VIDEO_V4L2. On Kernel 2.6.x, there were two V4L APIs, each one with its own flag. VIDEO_DEV were meant to: 1) enable Video4Linux and make its Kconfig options to appear; 2) it makes the Kernel build the V4L core. while VIDEO_V4L2 where used to distinguish between drivers that implement the newer API and drivers that implemented the former one. With time, such meaning changed, specially after the removal of all V4L version 1 drivers. At the current implementation, VIDEO_DEV only does (1): it enables the media options related to V4L, that now has: menu "Video4Linux options" visible if VIDEO_DEV source "drivers/media/v4l2-core/Kconfig" endmenu but it doesn't affect anymore the V4L core drivers. The rationale is that the V4L2 core has a "soft" dependency at the I2C bus, and now requires to select a number of other Kconfig options: config VIDEO_V4L2 tristate depends on (I2C || I2C=n) && VIDEO_DEV select RATIONAL select VIDEOBUF2_V4L2 if VIDEOBUF2_CORE default (I2C || I2C=n) && VIDEO_DEV In the past, merging them would be tricky, but it seems that it is now possible to merge those symbols, in order to simplify V4L dependencies. Let's keep VIDEO_DEV, as this one is used on some make *defconfig configurations. Suggested-by: Laurent Pinchart Reviewed-by: Laurent Pinchart Reviewed-by: Jacopo Mondi Reviewed-by: Neil Armstrong # for meson-vdec & meson-ge2d Acked-by: Andrzej Pietrasiewicz Acked-by: Łukasz Stelmach Signed-off-by: Mauro Carvalho Chehab --- drivers/input/rmi4/Kconfig | 2 +- drivers/input/touchscreen/Kconfig | 4 +- drivers/media/Kconfig | 3 + drivers/media/common/saa7146/Kconfig | 2 +- drivers/media/dvb-core/Kconfig | 2 +- drivers/media/dvb-frontends/Kconfig | 4 +- drivers/media/i2c/Kconfig | 250 ++++++++++----------- drivers/media/i2c/ccs/Kconfig | 2 +- drivers/media/i2c/cx25840/Kconfig | 2 +- drivers/media/i2c/et8ek8/Kconfig | 2 +- drivers/media/i2c/m5mols/Kconfig | 2 +- drivers/media/pci/Kconfig | 2 +- drivers/media/pci/bt8xx/Kconfig | 2 +- drivers/media/pci/cobalt/Kconfig | 2 +- drivers/media/pci/cx18/Kconfig | 2 +- drivers/media/pci/dt3155/Kconfig | 2 +- drivers/media/pci/intel/ipu3/Kconfig | 2 +- drivers/media/pci/ivtv/Kconfig | 2 +- drivers/media/pci/meye/Kconfig | 2 +- drivers/media/pci/saa7146/Kconfig | 6 +- drivers/media/pci/sta2x11/Kconfig | 2 +- drivers/media/pci/tw5864/Kconfig | 2 +- drivers/media/pci/tw68/Kconfig | 2 +- drivers/media/pci/tw686x/Kconfig | 2 +- drivers/media/platform/Kconfig | 6 +- drivers/media/platform/allegro-dvt/Kconfig | 2 +- drivers/media/platform/amlogic/meson-ge2d/Kconfig | 2 +- drivers/media/platform/amphion/Kconfig | 1 - drivers/media/platform/aspeed/Kconfig | 2 +- drivers/media/platform/atmel/Kconfig | 8 +- drivers/media/platform/cadence/Kconfig | 4 +- drivers/media/platform/chips-media/Kconfig | 2 +- drivers/media/platform/intel/Kconfig | 2 +- drivers/media/platform/marvell/Kconfig | 4 +- drivers/media/platform/mediatek/mtk-jpeg/Kconfig | 2 +- drivers/media/platform/mediatek/mtk-mdp/Kconfig | 2 +- drivers/media/platform/mediatek/mtk-vcodec/Kconfig | 2 +- drivers/media/platform/mediatek/mtk-vpu/Kconfig | 2 +- drivers/media/platform/nvidia/tegra-vde/Kconfig | 2 +- drivers/media/platform/nxp/Kconfig | 6 +- drivers/media/platform/nxp/imx-jpeg/Kconfig | 2 +- drivers/media/platform/qcom/camss/Kconfig | 2 +- drivers/media/platform/qcom/venus/Kconfig | 2 +- drivers/media/platform/renesas/Kconfig | 30 +-- drivers/media/platform/renesas/rcar-vin/Kconfig | 4 +- drivers/media/platform/rockchip/rga/Kconfig | 2 +- drivers/media/platform/rockchip/rkisp1/Kconfig | 2 +- drivers/media/platform/samsung/exynos-gsc/Kconfig | 2 +- drivers/media/platform/samsung/exynos4-is/Kconfig | 2 +- drivers/media/platform/samsung/s3c-camif/Kconfig | 2 +- drivers/media/platform/samsung/s5p-g2d/Kconfig | 2 +- drivers/media/platform/samsung/s5p-jpeg/Kconfig | 2 +- drivers/media/platform/samsung/s5p-mfc/Kconfig | 2 +- drivers/media/platform/st/sti/bdisp/Kconfig | 2 +- drivers/media/platform/st/sti/delta/Kconfig | 2 +- drivers/media/platform/st/sti/hva/Kconfig | 2 +- drivers/media/platform/st/stm32/Kconfig | 4 +- drivers/media/platform/sunxi/sun4i-csi/Kconfig | 2 +- drivers/media/platform/sunxi/sun6i-csi/Kconfig | 2 +- drivers/media/platform/sunxi/sun8i-di/Kconfig | 2 +- drivers/media/platform/sunxi/sun8i-rotate/Kconfig | 2 +- drivers/media/platform/ti/am437x/Kconfig | 2 +- drivers/media/platform/ti/davinci/Kconfig | 12 +- drivers/media/platform/ti/omap/Kconfig | 2 +- drivers/media/platform/ti/omap3isp/Kconfig | 2 +- drivers/media/platform/via/Kconfig | 2 +- drivers/media/platform/xilinx/Kconfig | 2 +- drivers/media/radio/Kconfig | 42 ++-- drivers/media/radio/si470x/Kconfig | 2 +- drivers/media/radio/wl128x/Kconfig | 2 +- drivers/media/spi/Kconfig | 4 +- drivers/media/test-drivers/Kconfig | 2 +- drivers/media/test-drivers/vicodec/Kconfig | 2 +- drivers/media/test-drivers/vimc/Kconfig | 2 +- drivers/media/test-drivers/vivid/Kconfig | 2 +- drivers/media/tuners/Kconfig | 6 +- drivers/media/tuners/e4000.c | 6 +- drivers/media/tuners/fc2580.c | 6 +- drivers/media/usb/airspy/Kconfig | 2 +- drivers/media/usb/au0828/Kconfig | 6 +- drivers/media/usb/cpia2/Kconfig | 2 +- drivers/media/usb/dvb-usb-v2/Kconfig | 8 +- drivers/media/usb/dvb-usb/Kconfig | 4 +- drivers/media/usb/gspca/Kconfig | 96 ++++---- drivers/media/usb/gspca/gl860/Kconfig | 2 +- drivers/media/usb/gspca/m5602/Kconfig | 2 +- drivers/media/usb/hackrf/Kconfig | 2 +- drivers/media/usb/hdpvr/Kconfig | 2 +- drivers/media/usb/msi2500/Kconfig | 2 +- drivers/media/usb/pvrusb2/Kconfig | 2 +- drivers/media/usb/pwc/Kconfig | 2 +- drivers/media/usb/s2255/Kconfig | 2 +- drivers/media/usb/stkwebcam/Kconfig | 2 +- drivers/media/usb/usbtv/Kconfig | 2 +- drivers/media/usb/uvc/Kconfig | 2 +- drivers/media/usb/zr364xx/Kconfig | 2 +- drivers/media/v4l2-core/Kconfig | 12 +- drivers/media/v4l2-core/Makefile | 2 +- drivers/staging/media/atomisp/Kconfig | 2 +- drivers/staging/media/atomisp/i2c/Kconfig | 14 +- drivers/staging/media/hantro/Kconfig | 2 +- drivers/staging/media/imx/Kconfig | 2 +- drivers/staging/media/ipu3/Kconfig | 2 +- drivers/staging/media/max96712/Kconfig | 2 +- drivers/staging/media/meson/vdec/Kconfig | 2 +- drivers/staging/media/omap4iss/Kconfig | 2 +- drivers/staging/media/rkvdec/Kconfig | 2 +- drivers/staging/media/sunxi/cedrus/Kconfig | 2 +- drivers/staging/media/tegra-video/Kconfig | 2 +- drivers/staging/media/zoran/Kconfig | 2 +- drivers/staging/most/video/Kconfig | 2 +- .../staging/vc04_services/bcm2835-camera/Kconfig | 2 +- drivers/usb/gadget/Kconfig | 2 +- drivers/usb/gadget/legacy/Kconfig | 2 +- sound/pci/Kconfig | 4 +- 115 files changed, 356 insertions(+), 374 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index 16119f760d11..c0163b983ce6 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -110,7 +110,7 @@ config RMI4_F3A config RMI4_F54 bool "RMI4 Function 54 (Analog diagnostics)" - depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m) + depends on VIDEO_DEV=y || (RMI4_CORE=m && VIDEO_DEV=m) select VIDEOBUF2_VMALLOC select RMI4_F55 help diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 2f6adfb7b938..ff7794cecf69 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -131,7 +131,7 @@ config TOUCHSCREEN_ATMEL_MXT config TOUCHSCREEN_ATMEL_MXT_T37 bool "Support T37 Diagnostic Data" depends on TOUCHSCREEN_ATMEL_MXT - depends on VIDEO_V4L2=y || (TOUCHSCREEN_ATMEL_MXT=m && VIDEO_V4L2=m) + depends on VIDEO_DEV=y || (TOUCHSCREEN_ATMEL_MXT=m && VIDEO_DEV=m) select VIDEOBUF2_VMALLOC help Say Y here if you want support to output data from the T37 @@ -1252,7 +1252,7 @@ config TOUCHSCREEN_SUN4I config TOUCHSCREEN_SUR40 tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" depends on USB && MEDIA_USB_SUPPORT && HAS_DMA - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_DMA_SG help Say Y here if you want support for the Samsung SUR40 touchscreen diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 1a75058df374..ba6592b3dab2 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -160,6 +160,9 @@ menu "Media core support" config VIDEO_DEV tristate "Video4Linux core" default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT || MEDIA_TEST_SUPPORT + depends on (I2C || I2C=n) + select RATIONAL + select VIDEOBUF2_V4L2 if VIDEOBUF2_CORE help Enables the V4L2 API, used by cameras, analog TV, video grabbers, radio devices and by some input devices. diff --git a/drivers/media/common/saa7146/Kconfig b/drivers/media/common/saa7146/Kconfig index 3e85c0c3fd9a..a0aa155e5d85 100644 --- a/drivers/media/common/saa7146/Kconfig +++ b/drivers/media/common/saa7146/Kconfig @@ -5,6 +5,6 @@ config VIDEO_SAA7146 config VIDEO_SAA7146_VV tristate - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF_DMA_SG select VIDEO_SAA7146 diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig index 6ffac618417b..8b3f2d53cd62 100644 --- a/drivers/media/dvb-core/Kconfig +++ b/drivers/media/dvb-core/Kconfig @@ -6,7 +6,7 @@ config DVB_MMAP bool "Enable DVB memory-mapped API (EXPERIMENTAL)" depends on DVB_CORE - depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE + depends on VIDEO_DEV=y || VIDEO_DEV=DVB_CORE select VIDEOBUF2_VMALLOC help This option enables DVB experimental memory-mapped API, which diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 2c1ed98d43c5..4101f9b1e731 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -510,7 +510,7 @@ config DVB_RTL2832 config DVB_RTL2832_SDR tristate "Realtek RTL2832 SDR" - depends on DVB_CORE && I2C && I2C_MUX && VIDEO_V4L2 && MEDIA_SDR_SUPPORT && USB + depends on DVB_CORE && I2C && I2C_MUX && VIDEO_DEV && MEDIA_SDR_SUPPORT && USB select DVB_RTL2832 select VIDEOBUF2_VMALLOC default m if !MEDIA_SUBDRV_AUTOSELECT @@ -681,7 +681,7 @@ config DVB_AU8522_DTV config DVB_AU8522_V4L tristate "Auvitek AU8522 based ATV demod" - depends on VIDEO_V4L2 && DVB_CORE && I2C + depends on VIDEO_DEV && DVB_CORE && I2C select DVB_AU8522 default m if !MEDIA_SUBDRV_AUTOSELECT help diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index e7194c1be4d2..5abc169f0a5c 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -3,7 +3,7 @@ # Multimedia Video device configuration # -if VIDEO_V4L2 +if VIDEO_DEV comment "IR I2C driver auto-selected by 'Autoselect ancillary drivers'" depends on MEDIA_SUBDRV_AUTOSELECT && I2C && RC_CORE @@ -36,7 +36,7 @@ menu "Audio decoders, processors and mixers" config VIDEO_TVAUDIO tristate "Simple audio decoder chips" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for several audio decoder chips found on some bt8xx boards: Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, @@ -48,7 +48,7 @@ config VIDEO_TVAUDIO config VIDEO_TDA7432 tristate "Philips TDA7432 audio processor" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for tda7432 audio decoder chip found on some bt8xx boards. @@ -66,7 +66,7 @@ config VIDEO_TDA9840 config VIDEO_TDA1997X tristate "NXP TDA1997x HDMI receiver" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on SND_SOC select HDMI select SND_PCM @@ -99,7 +99,7 @@ config VIDEO_TEA6420 config VIDEO_MSP3400 tristate "Micronas MSP34xx audio decoders" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Micronas MSP34xx series of audio decoders. @@ -108,7 +108,7 @@ config VIDEO_MSP3400 config VIDEO_CS3308 tristate "Cirrus Logic CS3308 audio ADC" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Cirrus Logic CS3308 High Performance 8-Channel Analog Volume Control @@ -118,7 +118,7 @@ config VIDEO_CS3308 config VIDEO_CS5345 tristate "Cirrus Logic CS5345 audio ADC" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Cirrus Logic CS5345 24-bit, 192 kHz stereo A/D converter. @@ -128,7 +128,7 @@ config VIDEO_CS5345 config VIDEO_CS53L32A tristate "Cirrus Logic CS53L32A audio ADC" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Cirrus Logic CS53L32A low voltage stereo A/D converter. @@ -138,7 +138,7 @@ config VIDEO_CS53L32A config VIDEO_TLV320AIC23B tristate "Texas Instruments TLV320AIC23B audio codec" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Texas Instruments TLV320AIC23B audio codec. @@ -147,7 +147,7 @@ config VIDEO_TLV320AIC23B config VIDEO_UDA1342 tristate "Philips UDA1342 audio codec" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Philips UDA1342 audio codec. @@ -156,7 +156,7 @@ config VIDEO_UDA1342 config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Wolfson Microelectronics WM8775 high performance stereo A/D Converter with a 4 channel input mixer. @@ -166,7 +166,7 @@ config VIDEO_WM8775 config VIDEO_WM8739 tristate "Wolfson Microelectronics WM8739 stereo audio ADC" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Wolfson Microelectronics WM8739 stereo A/D Converter. @@ -176,7 +176,7 @@ config VIDEO_WM8739 config VIDEO_VP27SMPX tristate "Panasonic VP27's internal MPX" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the internal MPX of the Panasonic VP27s tuner. @@ -185,7 +185,7 @@ config VIDEO_VP27SMPX config VIDEO_SONY_BTF_MPX tristate "Sony BTF's internal MPX" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the internal MPX of the Sony BTF-PG472Z tuner. @@ -198,7 +198,7 @@ menu "RDS decoders" config VIDEO_SAA6588 tristate "SAA6588 Radio Chip RDS decoder support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for this Radio Data System (RDS) decoder. This allows @@ -214,7 +214,7 @@ menu "Video decoders" config VIDEO_ADV7180 tristate "Analog Devices ADV7180 decoder" - depends on GPIOLIB && VIDEO_V4L2 && I2C + depends on GPIOLIB && VIDEO_DEV && I2C select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_ASYNC @@ -226,7 +226,7 @@ config VIDEO_ADV7180 config VIDEO_ADV7183 tristate "Analog Devices ADV7183 decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help V4l2 subdevice driver for the Analog Devices ADV7183 video decoder. @@ -236,7 +236,7 @@ config VIDEO_ADV7183 config VIDEO_ADV748X tristate "Analog Devices ADV748x decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on OF select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -251,7 +251,7 @@ config VIDEO_ADV748X config VIDEO_ADV7604 tristate "Analog Devices ADV7604 decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on GPIOLIB || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -277,7 +277,7 @@ config VIDEO_ADV7604_CEC config VIDEO_ADV7842 tristate "Analog Devices ADV7842 decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select HDMI @@ -300,7 +300,7 @@ config VIDEO_ADV7842_CEC config VIDEO_BT819 tristate "BT819A VideoStream decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for BT819A video decoder. @@ -309,7 +309,7 @@ config VIDEO_BT819 config VIDEO_BT856 tristate "BT856 VideoStream decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for BT856 video decoder. @@ -318,7 +318,7 @@ config VIDEO_BT856 config VIDEO_BT866 tristate "BT866 VideoStream decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for BT866 video decoder. @@ -327,7 +327,7 @@ config VIDEO_BT866 config VIDEO_ISL7998X tristate "Intersil ISL7998x video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on OF_GPIO select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -337,7 +337,7 @@ config VIDEO_ISL7998X config VIDEO_KS0127 tristate "KS0127 video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for KS0127 video decoder. @@ -349,7 +349,7 @@ config VIDEO_KS0127 config VIDEO_ML86V7667 tristate "OKI ML86V7667 video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the OKI Semiconductor ML86V7667 video decoder. @@ -358,7 +358,7 @@ config VIDEO_ML86V7667 config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Philips SAA7110 video decoders. @@ -367,7 +367,7 @@ config VIDEO_SAA7110 config VIDEO_SAA711X tristate "Philips SAA7111/3/4/5 video decoders" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Philips SAA7111/3/4/5 video decoders. @@ -376,7 +376,7 @@ config VIDEO_SAA711X config VIDEO_TC358743 tristate "Toshiba TC358743 decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select HDMI @@ -397,7 +397,7 @@ config VIDEO_TC358743_CEC config VIDEO_TVP514X tristate "Texas Instruments TVP514x video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the TI TVP5146/47 @@ -409,7 +409,7 @@ config VIDEO_TVP514X config VIDEO_TVP5150 tristate "Texas Instruments TVP5150 video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select V4L2_FWNODE select REGMAP_I2C help @@ -420,7 +420,7 @@ config VIDEO_TVP5150 config VIDEO_TVP7002 tristate "Texas Instruments TVP7002 video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select V4L2_FWNODE help Support for the Texas Instruments TVP7002 video decoder. @@ -430,7 +430,7 @@ config VIDEO_TVP7002 config VIDEO_TW2804 tristate "Techwell TW2804 multiple video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Techwell tw2804 multiple video decoder. @@ -439,7 +439,7 @@ config VIDEO_TW2804 config VIDEO_TW9903 tristate "Techwell TW9903 video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Techwell tw9903 multi-standard video decoder with high quality down scaler. @@ -449,7 +449,7 @@ config VIDEO_TW9903 config VIDEO_TW9906 tristate "Techwell TW9906 video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Techwell tw9906 enhanced multi-standard comb filter video decoder with YCbCr input support. @@ -459,7 +459,7 @@ config VIDEO_TW9906 config VIDEO_TW9910 tristate "Techwell TW9910 video decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select V4L2_ASYNC help Support for Techwell TW9910 NTSC/PAL/SECAM video decoder. @@ -469,7 +469,7 @@ config VIDEO_TW9910 config VIDEO_VPX3220 tristate "vpx3220a, vpx3216b & vpx3214c video decoders" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for VPX322x video decoders. @@ -479,7 +479,7 @@ config VIDEO_VPX3220 config VIDEO_MAX9286 tristate "Maxim MAX9286 GMSL deserializer support" depends on I2C && I2C_MUX - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on OF_GPIO select V4L2_FWNODE select VIDEO_V4L2_SUBDEV_API @@ -494,7 +494,7 @@ comment "Video and audio decoders" config VIDEO_SAA717X tristate "Philips SAA7171/3/4 audio/video decoders" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Philips SAA7171/3/4 audio/video decoders. @@ -510,7 +510,7 @@ menu "Video encoders" config VIDEO_SAA7127 tristate "Philips SAA7127/9 digital video encoders" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Philips SAA7127/9 digital video encoders. @@ -519,7 +519,7 @@ config VIDEO_SAA7127 config VIDEO_SAA7185 tristate "Philips SAA7185 video encoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Philips SAA7185 video encoder. @@ -528,7 +528,7 @@ config VIDEO_SAA7185 config VIDEO_ADV7170 tristate "Analog Devices ADV7170 video encoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Analog Devices ADV7170 video encoder driver @@ -537,7 +537,7 @@ config VIDEO_ADV7170 config VIDEO_ADV7175 tristate "Analog Devices ADV7175 video encoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Analog Devices ADV7175 video encoder driver @@ -565,7 +565,7 @@ config VIDEO_ADV7393 config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on DRM_I2C_ADV7511=n || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -588,7 +588,7 @@ config VIDEO_ADV7511_CEC config VIDEO_AD9389B tristate "Analog Devices AD9389B encoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -608,7 +608,7 @@ config VIDEO_AK881X config VIDEO_THS8200 tristate "Texas Instruments THS8200 video encoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select V4L2_ASYNC help Support for the Texas Instruments THS8200 video encoder. @@ -622,7 +622,7 @@ menu "Video improvement chips" config VIDEO_UPD64031A tristate "NEC Electronics uPD64031A Ghost Reduction" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select V4L2_ASYNC help Support for the NEC Electronics uPD64031A Ghost Reduction @@ -635,7 +635,7 @@ config VIDEO_UPD64031A config VIDEO_UPD64083 tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the NEC Electronics uPD64083 3-Dimensional Y/C separation video chip. It is used to improve the quality of @@ -650,7 +650,7 @@ menu "Audio/Video compression chips" config VIDEO_SAA6752HS tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select CRC32 help Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3 @@ -666,7 +666,7 @@ menu "SDR tuner chips" config SDR_MAX2175 tristate "Maxim 2175 RF to Bits tuner" - depends on VIDEO_V4L2 && MEDIA_SDR_SUPPORT && I2C + depends on VIDEO_DEV && MEDIA_SDR_SUPPORT && I2C select REGMAP_I2C select V4L2_ASYNC help @@ -684,7 +684,7 @@ menu "Miscellaneous helper chips" config VIDEO_THS7303 tristate "THS7303/53 Video Amplifier" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select V4L2_ASYNC help Support for TI THS7303/53 video amplifier @@ -694,7 +694,7 @@ config VIDEO_THS7303 config VIDEO_M52790 tristate "Mitsubishi M52790 A/V switch" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Mitsubishi M52790 A/V switch. @@ -703,7 +703,7 @@ config VIDEO_M52790 config VIDEO_I2C tristate "I2C transport video support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select VIDEOBUF2_VMALLOC imply HWMON help @@ -717,7 +717,7 @@ config VIDEO_I2C config VIDEO_ST_MIPID02 tristate "STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -745,7 +745,7 @@ config VIDEO_CCS_PLL config VIDEO_HI556 tristate "Hynix Hi-556 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -758,7 +758,7 @@ config VIDEO_HI556 config VIDEO_HI846 tristate "Hynix Hi-846 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -771,7 +771,7 @@ config VIDEO_HI846 config VIDEO_HI847 tristate "Hynix Hi-847 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -784,7 +784,7 @@ config VIDEO_HI847 config VIDEO_IMX208 tristate "Sony IMX208 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_DEV && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT help This is a Video4Linux2 sensor driver for the Sony @@ -795,7 +795,7 @@ config VIDEO_IMX208 config VIDEO_IMX214 tristate "Sony IMX214 sensor support" - depends on GPIOLIB && I2C && VIDEO_V4L2 + depends on GPIOLIB && I2C && VIDEO_DEV select V4L2_FWNODE select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -809,7 +809,7 @@ config VIDEO_IMX214 config VIDEO_IMX219 tristate "Sony IMX219 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -822,7 +822,7 @@ config VIDEO_IMX219 config VIDEO_IMX258 tristate "Sony IMX258 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help @@ -834,7 +834,7 @@ config VIDEO_IMX258 config VIDEO_IMX274 tristate "Sony IMX274 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select REGMAP_I2C @@ -844,7 +844,7 @@ config VIDEO_IMX274 config VIDEO_IMX290 tristate "Sony IMX290 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select REGMAP_I2C @@ -858,7 +858,7 @@ config VIDEO_IMX290 config VIDEO_IMX319 tristate "Sony IMX319 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help @@ -871,7 +871,7 @@ config VIDEO_IMX319 config VIDEO_IMX334 tristate "Sony IMX334 sensor support" depends on OF_GPIO - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select VIDEO_V4L2_SUBDEV_API select MEDIA_CONTROLLER select V4L2_FWNODE @@ -885,7 +885,7 @@ config VIDEO_IMX334 config VIDEO_IMX335 tristate "Sony IMX335 sensor support" depends on OF_GPIO - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select VIDEO_V4L2_SUBDEV_API select MEDIA_CONTROLLER select V4L2_FWNODE @@ -898,7 +898,7 @@ config VIDEO_IMX335 config VIDEO_IMX355 tristate "Sony IMX355 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help @@ -911,7 +911,7 @@ config VIDEO_IMX355 config VIDEO_IMX412 tristate "Sony IMX412 sensor support" depends on OF_GPIO - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select VIDEO_V4L2_SUBDEV_API select MEDIA_CONTROLLER select V4L2_FWNODE @@ -924,7 +924,7 @@ config VIDEO_IMX412 config VIDEO_OG01A1B tristate "OmniVision OG01A1B sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -937,7 +937,7 @@ config VIDEO_OG01A1B config VIDEO_OV02A10 tristate "OmniVision OV02A10 sensor support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -950,7 +950,7 @@ config VIDEO_OV02A10 config VIDEO_OV08D10 tristate "OmniVision OV08D10 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -963,7 +963,7 @@ config VIDEO_OV08D10 config VIDEO_OV2640 tristate "OmniVision OV2640 sensor support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help This is a Video4Linux2 sensor driver for the OmniVision OV2640 camera. @@ -973,7 +973,7 @@ config VIDEO_OV2640 config VIDEO_OV2659 tristate "OmniVision OV2659 sensor support" - depends on VIDEO_V4L2 && I2C && GPIOLIB + depends on VIDEO_DEV && I2C && GPIOLIB select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -984,7 +984,7 @@ config VIDEO_OV2659 config VIDEO_OV2680 tristate "OmniVision OV2680 sensor support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select MEDIA_CONTROLLER select V4L2_FWNODE help @@ -996,7 +996,7 @@ config VIDEO_OV2680 config VIDEO_OV2685 tristate "OmniVision OV2685 sensor support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select MEDIA_CONTROLLER select V4L2_FWNODE help @@ -1008,7 +1008,7 @@ config VIDEO_OV2685 config VIDEO_OV2740 tristate "OmniVision OV2740 sensor support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on ACPI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -1024,7 +1024,7 @@ config VIDEO_OV2740 config VIDEO_OV5640 tristate "OmniVision OV5640 sensor support" depends on OF - depends on GPIOLIB && VIDEO_V4L2 && I2C + depends on GPIOLIB && VIDEO_DEV && I2C select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1035,7 +1035,7 @@ config VIDEO_OV5640 config VIDEO_OV5645 tristate "OmniVision OV5645 sensor support" depends on OF - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1048,7 +1048,7 @@ config VIDEO_OV5645 config VIDEO_OV5647 tristate "OmniVision OV5647 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1061,7 +1061,7 @@ config VIDEO_OV5647 config VIDEO_OV5648 tristate "OmniVision OV5648 sensor support" - depends on I2C && PM && VIDEO_V4L2 + depends on I2C && PM && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1074,7 +1074,7 @@ config VIDEO_OV5648 config VIDEO_OV6650 tristate "OmniVision OV6650 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor driver for the OmniVision OV6650 camera. @@ -1084,7 +1084,7 @@ config VIDEO_OV6650 config VIDEO_OV5670 tristate "OmniVision OV5670 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1097,7 +1097,7 @@ config VIDEO_OV5670 config VIDEO_OV5675 tristate "OmniVision OV5675 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1110,7 +1110,7 @@ config VIDEO_OV5675 config VIDEO_OV5693 tristate "OmniVision OV5693 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -1121,7 +1121,7 @@ config VIDEO_OV5693 config VIDEO_OV5695 tristate "OmniVision OV5695 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -1132,7 +1132,7 @@ config VIDEO_OV5695 config VIDEO_OV7251 tristate "OmniVision OV7251 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1145,7 +1145,7 @@ config VIDEO_OV7251 config VIDEO_OV772X tristate "OmniVision OV772x sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select REGMAP_SCCB select V4L2_FWNODE help @@ -1157,7 +1157,7 @@ config VIDEO_OV772X config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor driver for the OmniVision OV7640 camera. @@ -1167,7 +1167,7 @@ config VIDEO_OV7640 config VIDEO_OV7670 tristate "OmniVision OV7670 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -1176,7 +1176,7 @@ config VIDEO_OV7670 config VIDEO_OV7740 tristate "OmniVision OV7740 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select REGMAP_SCCB help This is a Video4Linux2 sensor driver for the OmniVision @@ -1184,7 +1184,7 @@ config VIDEO_OV7740 config VIDEO_OV8856 tristate "OmniVision OV8856 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1197,7 +1197,7 @@ config VIDEO_OV8856 config VIDEO_OV8865 tristate "OmniVision OV8865 sensor support" - depends on I2C && PM && VIDEO_V4L2 + depends on I2C && PM && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1211,7 +1211,7 @@ config VIDEO_OV8865 config VIDEO_OV9282 tristate "OmniVision OV9282 sensor support" depends on OF_GPIO - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select VIDEO_V4L2_SUBDEV_API select MEDIA_CONTROLLER select V4L2_FWNODE @@ -1224,14 +1224,14 @@ config VIDEO_OV9282 config VIDEO_OV9640 tristate "OmniVision OV9640 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor driver for the OmniVision OV9640 camera sensor. config VIDEO_OV9650 tristate "OmniVision OV9650/OV9652 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select REGMAP_SCCB @@ -1241,7 +1241,7 @@ config VIDEO_OV9650 config VIDEO_OV9734 tristate "OmniVision OV9734 sensor support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on ACPI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -1255,7 +1255,7 @@ config VIDEO_OV9734 config VIDEO_OV13858 tristate "OmniVision OV13858 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1265,7 +1265,7 @@ config VIDEO_OV13858 config VIDEO_OV13B10 tristate "OmniVision OV13B10 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1275,7 +1275,7 @@ config VIDEO_OV13B10 config VIDEO_VS6624 tristate "ST VS6624 sensor support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help This is a Video4Linux2 sensor driver for the ST VS6624 camera. @@ -1285,7 +1285,7 @@ config VIDEO_VS6624 config VIDEO_MT9M001 tristate "mt9m001 support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help @@ -1294,7 +1294,7 @@ config VIDEO_MT9M001 config VIDEO_MT9M032 tristate "MT9M032 camera sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEO_APTINA_PLL @@ -1304,7 +1304,7 @@ config VIDEO_MT9M032 config VIDEO_MT9M111 tristate "mt9m111, mt9m112 and mt9m131 support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select V4L2_FWNODE help This driver supports MT9M111, MT9M112 and MT9M131 cameras from @@ -1312,7 +1312,7 @@ config VIDEO_MT9M111 config VIDEO_MT9P031 tristate "Aptina MT9P031 support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEO_APTINA_PLL @@ -1323,7 +1323,7 @@ config VIDEO_MT9P031 config VIDEO_MT9T001 tristate "Aptina MT9T001 support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help @@ -1332,7 +1332,7 @@ config VIDEO_MT9T001 config VIDEO_MT9T112 tristate "Aptina MT9T111/MT9T112 support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor driver for the Aptina (Micron) MT9T111 and MT9T112 3 Mpixel camera. @@ -1342,7 +1342,7 @@ config VIDEO_MT9T112 config VIDEO_MT9V011 tristate "Micron mt9v011 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor driver for the Micron mt0v011 1.3 Mpixel camera. It currently only works with the @@ -1350,7 +1350,7 @@ config VIDEO_MT9V011 config VIDEO_MT9V032 tristate "Micron MT9V032 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select REGMAP_I2C @@ -1361,7 +1361,7 @@ config VIDEO_MT9V032 config VIDEO_MT9V111 tristate "Aptina MT9V111 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor driver for the Aptina/Micron MT9V111 sensor. @@ -1371,13 +1371,13 @@ config VIDEO_MT9V111 config VIDEO_SR030PC30 tristate "Siliconfile SR030PC30 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This driver supports SR030PC30 VGA camera from Siliconfile config VIDEO_NOON010PC30 tristate "Siliconfile NOON010PC30 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help @@ -1418,7 +1418,7 @@ config VIDEO_RDACM21 config VIDEO_RJ54N1 tristate "Sharp RJ54N1CB0C sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a V4L2 sensor driver for Sharp RJ54N1CB0C CMOS image sensor. @@ -1428,7 +1428,7 @@ config VIDEO_RJ54N1 config VIDEO_S5K6AA tristate "Samsung S5K6AAFX sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help @@ -1437,7 +1437,7 @@ config VIDEO_S5K6AA config VIDEO_S5K6A3 tristate "Samsung S5K6A3 sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help @@ -1446,7 +1446,7 @@ config VIDEO_S5K6A3 config VIDEO_S5K4ECGX tristate "Samsung S5K4ECGX sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select CRC32 @@ -1456,7 +1456,7 @@ config VIDEO_S5K4ECGX config VIDEO_S5K5BAF tristate "Samsung S5K5BAF sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1469,7 +1469,7 @@ source "drivers/media/i2c/et8ek8/Kconfig" config VIDEO_S5C73M3 tristate "Samsung S5C73M3 sensor support" - depends on I2C && SPI && VIDEO_V4L2 + depends on I2C && SPI && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1484,7 +1484,7 @@ menu "Lens drivers" config VIDEO_AD5820 tristate "AD5820 lens voice coil support" - depends on GPIOLIB && I2C && VIDEO_V4L2 + depends on GPIOLIB && I2C && VIDEO_DEV select MEDIA_CONTROLLER select V4L2_ASYNC help @@ -1493,7 +1493,7 @@ config VIDEO_AD5820 config VIDEO_AK7375 tristate "AK7375 lens voice coil support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_ASYNC @@ -1505,7 +1505,7 @@ config VIDEO_AK7375 config VIDEO_DW9714 tristate "DW9714 lens voice coil support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_ASYNC @@ -1517,7 +1517,7 @@ config VIDEO_DW9714 config VIDEO_DW9768 tristate "DW9768 lens voice coil support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -1529,7 +1529,7 @@ config VIDEO_DW9768 config VIDEO_DW9807_VCM tristate "DW9807 lens voice coil support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_ASYNC @@ -1546,7 +1546,7 @@ menu "Flash devices" config VIDEO_ADP1653 tristate "ADP1653 flash support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select V4L2_ASYNC help @@ -1555,7 +1555,7 @@ config VIDEO_ADP1653 config VIDEO_LM3560 tristate "LM3560 dual flash driver support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select REGMAP_I2C select V4L2_ASYNC @@ -1565,7 +1565,7 @@ config VIDEO_LM3560 config VIDEO_LM3646 tristate "LM3646 dual flash driver support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select REGMAP_I2C select V4L2_ASYNC @@ -1574,4 +1574,4 @@ config VIDEO_LM3646 flash, torch LEDs. endmenu -endif # VIDEO_V4L2 +endif # VIDEO_DEV diff --git a/drivers/media/i2c/ccs/Kconfig b/drivers/media/i2c/ccs/Kconfig index 59f35b33ddc1..71671db3d993 100644 --- a/drivers/media/i2c/ccs/Kconfig +++ b/drivers/media/i2c/ccs/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_CCS tristate "MIPI CCS/SMIA++/SMIA sensor support" - depends on I2C && VIDEO_V4L2 && HAVE_CLK + depends on I2C && VIDEO_DEV && HAVE_CLK select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEO_CCS_PLL diff --git a/drivers/media/i2c/cx25840/Kconfig b/drivers/media/i2c/cx25840/Kconfig index e392f8e023f6..46f15702cf55 100644 --- a/drivers/media/i2c/cx25840/Kconfig +++ b/drivers/media/i2c/cx25840/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_CX25840 tristate "Conexant CX2584x audio/video decoders" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help Support for the Conexant CX2584x audio/video decoders. diff --git a/drivers/media/i2c/et8ek8/Kconfig b/drivers/media/i2c/et8ek8/Kconfig index afcc4ea764f6..398dd4d21df1 100644 --- a/drivers/media/i2c/et8ek8/Kconfig +++ b/drivers/media/i2c/et8ek8/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_ET8EK8 tristate "ET8EK8 camera sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE diff --git a/drivers/media/i2c/m5mols/Kconfig b/drivers/media/i2c/m5mols/Kconfig index 6f0ef33b7ee1..7f0af32f4376 100644 --- a/drivers/media/i2c/m5mols/Kconfig +++ b/drivers/media/i2c/m5mols/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_M5MOLS tristate "Fujitsu M-5MOLS 8MP sensor support" - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 2cd8e328dda9..92b156530d91 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -61,7 +61,7 @@ config VIDEO_PCI_SKELETON tristate "Skeleton PCI V4L2 driver" depends on SAMPLES depends on MEDIA_TEST_SUPPORT - depends on PCI && VIDEO_V4L2 + depends on PCI && VIDEO_DEV select VIDEOBUF2_MEMOPS select VIDEOBUF2_DMA_CONTIG help diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig index 3f56decbb681..927190281bd5 100644 --- a/drivers/media/pci/bt8xx/Kconfig +++ b/drivers/media/pci/bt8xx/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_BT848 tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 + depends on PCI && I2C && VIDEO_DEV select I2C_ALGOBIT select VIDEOBUF_DMA_SG depends on RC_CORE diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index d8d9ea6b09bc..e13e36141199 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_COBALT tristate "Cisco Cobalt support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on PCI_MSI && MTD_COMPLEX_MAPPINGS depends on (GPIOLIB && DRM_I2C_ADV7511=n) || COMPILE_TEST depends on SND diff --git a/drivers/media/pci/cx18/Kconfig b/drivers/media/pci/cx18/Kconfig index 7074a1071302..a4e32fdcfd3d 100644 --- a/drivers/media/pci/cx18/Kconfig +++ b/drivers/media/pci/cx18/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_CX18 tristate "Conexant cx23418 MPEG encoder support" - depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C + depends on VIDEO_DEV && DVB_CORE && PCI && I2C select I2C_ALGOBIT select VIDEOBUF_VMALLOC depends on RC_CORE diff --git a/drivers/media/pci/dt3155/Kconfig b/drivers/media/pci/dt3155/Kconfig index a3d24b8a719b..2b76de195aa5 100644 --- a/drivers/media/pci/dt3155/Kconfig +++ b/drivers/media/pci/dt3155/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_DT3155 tristate "DT3155 frame grabber" - depends on PCI && VIDEO_DEV && VIDEO_V4L2 + depends on PCI && VIDEO_DEV select VIDEOBUF2_DMA_CONTIG help Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. diff --git a/drivers/media/pci/intel/ipu3/Kconfig b/drivers/media/pci/intel/ipu3/Kconfig index dce8274c81e6..39bd3be0b43d 100644 --- a/drivers/media/pci/intel/ipu3/Kconfig +++ b/drivers/media/pci/intel/ipu3/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_IPU3_CIO2 tristate "Intel ipu3-cio2 driver" - depends on VIDEO_V4L2 && PCI + depends on VIDEO_DEV && PCI depends on ACPI || COMPILE_TEST depends on X86 select MEDIA_CONTROLLER diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig index e70502902b73..9be52101bc4f 100644 --- a/drivers/media/pci/ivtv/Kconfig +++ b/drivers/media/pci/ivtv/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_IVTV tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" - depends on VIDEO_V4L2 && PCI && I2C + depends on VIDEO_DEV && PCI && I2C select I2C_ALGOBIT depends on RC_CORE select VIDEO_TUNER diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig index fed1f4a01817..3e69b66f1a5b 100644 --- a/drivers/media/pci/meye/Kconfig +++ b/drivers/media/pci/meye/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" - depends on PCI && VIDEO_V4L2 + depends on PCI && VIDEO_DEV depends on SONY_LAPTOP depends on X86 || COMPILE_TEST help diff --git a/drivers/media/pci/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig index 8e83cd044075..3bbb68a0ed7b 100644 --- a/drivers/media/pci/saa7146/Kconfig +++ b/drivers/media/pci/saa7146/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_HEXIUM_GEMINI tristate "Hexium Gemini frame grabber" - depends on PCI && VIDEO_V4L2 && I2C + depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV help This is a video4linux driver for the Hexium Gemini frame @@ -13,7 +13,7 @@ config VIDEO_HEXIUM_GEMINI config VIDEO_HEXIUM_ORION tristate "Hexium HV-PCI6 and Orion frame grabber" - depends on PCI && VIDEO_V4L2 && I2C + depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV help This is a video4linux driver for the Hexium HV-PCI6 and @@ -24,7 +24,7 @@ config VIDEO_HEXIUM_ORION config VIDEO_MXB tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" - depends on PCI && VIDEO_V4L2 && I2C + depends on PCI && VIDEO_DEV && I2C select VIDEO_SAA7146_VV select VIDEO_TUNER select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index 27bb78513631..a96e170ab04e 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config STA2X11_VIP tristate "STA2X11 VIP Video For Linux" - depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS && I2C + depends on PCI && VIDEO_DEV && VIRT_TO_BUS && I2C depends on STA2X11 || COMPILE_TEST select GPIOLIB if MEDIA_SUBDRV_AUTOSELECT select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/tw5864/Kconfig b/drivers/media/pci/tw5864/Kconfig index d376d4ed65b9..111da223efb0 100644 --- a/drivers/media/pci/tw5864/Kconfig +++ b/drivers/media/pci/tw5864/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_TW5864 tristate "Techwell TW5864 video/audio grabber and encoder" - depends on VIDEO_DEV && PCI && VIDEO_V4L2 + depends on VIDEO_DEV && PCI select VIDEOBUF2_DMA_CONTIG help Support for boards based on Techwell TW5864 chip which provides diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig index af0cb60337bb..ef9c0e886a09 100644 --- a/drivers/media/pci/tw68/Kconfig +++ b/drivers/media/pci/tw68/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_TW68 tristate "Techwell tw68x Video For Linux" - depends on VIDEO_DEV && PCI && VIDEO_V4L2 + depends on VIDEO_DEV && PCI select VIDEOBUF2_DMA_SG help Support for Techwell tw68xx based frame grabber boards. diff --git a/drivers/media/pci/tw686x/Kconfig b/drivers/media/pci/tw686x/Kconfig index 631c90868b8b..a4edad6aaf89 100644 --- a/drivers/media/pci/tw686x/Kconfig +++ b/drivers/media/pci/tw686x/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_TW686X tristate "Intersil/Techwell TW686x video capture cards" - depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND + depends on PCI && VIDEO_DEV && SND select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_SG diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index b4f6281bf2c6..f1056ceaf5a8 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -30,7 +30,7 @@ config DVB_PLATFORM_DRIVERS config V4L_MEM2MEM_DRIVERS bool "Memory-to-memory multimedia devices" - depends on VIDEO_V4L2 + depends on VIDEO_DEV help Say Y here to enable selecting drivers for V4L devices that use system memory for both source and destination buffers, as opposed @@ -42,7 +42,7 @@ config V4L_MEM2MEM_DRIVERS config VIDEO_MEM2MEM_DEINTERLACE tristate "Deinterlace support" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV @@ -53,7 +53,7 @@ config VIDEO_MUX tristate "Video Multiplexer" depends on V4L_PLATFORM_DRIVERS select MULTIPLEXER - depends on VIDEO_V4L2 && OF + depends on VIDEO_DEV && OF select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select REGMAP diff --git a/drivers/media/platform/allegro-dvt/Kconfig b/drivers/media/platform/allegro-dvt/Kconfig index 253d577a2c47..2182e1277568 100644 --- a/drivers/media/platform/allegro-dvt/Kconfig +++ b/drivers/media/platform/allegro-dvt/Kconfig @@ -5,7 +5,7 @@ comment "Allegro DVT media platform drivers" config VIDEO_ALLEGRO_DVT tristate "Allegro DVT Video IP Core" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_ZYNQMP || COMPILE_TEST select V4L2_MEM2MEM_DEV select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/platform/amlogic/meson-ge2d/Kconfig b/drivers/media/platform/amlogic/meson-ge2d/Kconfig index 8c3f3b1b6b05..312c4169e3c2 100644 --- a/drivers/media/platform/amlogic/meson-ge2d/Kconfig +++ b/drivers/media/platform/amlogic/meson-ge2d/Kconfig @@ -1,7 +1,7 @@ config VIDEO_MESON_GE2D tristate "Amlogic 2D Graphic Acceleration Unit" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_MESON || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/amphion/Kconfig b/drivers/media/platform/amphion/Kconfig index e0e8098965bd..6eea97b7063a 100644 --- a/drivers/media/platform/amphion/Kconfig +++ b/drivers/media/platform/amphion/Kconfig @@ -8,7 +8,6 @@ config VIDEO_AMPHION_VPU depends on ARCH_MXC || COMPILE_TEST depends on MEDIA_SUPPORT depends on VIDEO_DEV - depends on VIDEO_V4L2 select MEDIA_CONTROLLER select V4L2_MEM2MEM_DEV select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/platform/aspeed/Kconfig b/drivers/media/platform/aspeed/Kconfig index f46dfdf36f1c..c871eda33570 100644 --- a/drivers/media/platform/aspeed/Kconfig +++ b/drivers/media/platform/aspeed/Kconfig @@ -5,7 +5,7 @@ comment "Aspeed media platform drivers" config VIDEO_ASPEED tristate "Aspeed AST2400 and AST2500 Video Engine driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_DMA_CONTIG help Support for the Aspeed Video Engine (VE) embedded in the Aspeed diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig index eab5befa6177..83aebee0c8eb 100644 --- a/drivers/media/platform/atmel/Kconfig +++ b/drivers/media/platform/atmel/Kconfig @@ -5,7 +5,7 @@ comment "Atmel media platform drivers" config VIDEO_ATMEL_ISC tristate "ATMEL Image Sensor Controller (ISC) support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && COMMON_CLK + depends on VIDEO_DEV && COMMON_CLK depends on ARCH_AT91 || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -20,7 +20,7 @@ config VIDEO_ATMEL_ISC config VIDEO_ATMEL_XISC tristate "ATMEL eXtended Image Sensor Controller (XISC) support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_DEV && COMMON_CLK && VIDEO_V4L2_SUBDEV_API depends on ARCH_AT91 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select REGMAP_MMIO @@ -39,7 +39,7 @@ config VIDEO_ATMEL_ISC_BASE config VIDEO_ATMEL_ISI tristate "ATMEL Image Sensor Interface (ISI) support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && OF + depends on VIDEO_DEV && OF depends on ARCH_AT91 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE @@ -50,7 +50,7 @@ config VIDEO_ATMEL_ISI config VIDEO_MICROCHIP_CSI2DC tristate "Microchip CSI2 Demux Controller" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && COMMON_CLK && OF + depends on VIDEO_DEV && COMMON_CLK && OF depends on ARCH_AT91 || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/cadence/Kconfig b/drivers/media/platform/cadence/Kconfig index f7904a27ec1c..480325d053de 100644 --- a/drivers/media/platform/cadence/Kconfig +++ b/drivers/media/platform/cadence/Kconfig @@ -4,7 +4,7 @@ comment "Cadence media platform drivers" config VIDEO_CADENCE_CSI2RX tristate "Cadence MIPI-CSI2 RX Controller" - depends on VIDEO_V4L2 + depends on VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE @@ -16,7 +16,7 @@ config VIDEO_CADENCE_CSI2RX config VIDEO_CADENCE_CSI2TX tristate "Cadence MIPI-CSI2 TX Controller" - depends on VIDEO_V4L2 + depends on VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE diff --git a/drivers/media/platform/chips-media/Kconfig b/drivers/media/platform/chips-media/Kconfig index 5f8bceb906ba..57f8f8a22df8 100644 --- a/drivers/media/platform/chips-media/Kconfig +++ b/drivers/media/platform/chips-media/Kconfig @@ -5,7 +5,7 @@ comment "Chips&Media media platform drivers" config VIDEO_CODA tristate "Chips&Media Coda multi-standard codec IP" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 && OF && (ARCH_MXC || COMPILE_TEST) + depends on VIDEO_DEV && OF && (ARCH_MXC || COMPILE_TEST) select SRAM select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC diff --git a/drivers/media/platform/intel/Kconfig b/drivers/media/platform/intel/Kconfig index a80640cdd4b0..724e80a9086d 100644 --- a/drivers/media/platform/intel/Kconfig +++ b/drivers/media/platform/intel/Kconfig @@ -5,7 +5,7 @@ comment "Intel media platform drivers" config VIDEO_PXA27x tristate "PXA27x Quick Capture Interface driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on PXA27x || COMPILE_TEST select VIDEOBUF2_DMA_SG select SG_SPLIT diff --git a/drivers/media/platform/marvell/Kconfig b/drivers/media/platform/marvell/Kconfig index 5fcaea2182c3..ec1a16734a28 100644 --- a/drivers/media/platform/marvell/Kconfig +++ b/drivers/media/platform/marvell/Kconfig @@ -5,7 +5,7 @@ comment "Marvell media platform drivers" config VIDEO_CAFE_CCIC tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" depends on V4L_PLATFORM_DRIVERS - depends on PCI && I2C && VIDEO_V4L2 + depends on PCI && I2C && VIDEO_DEV depends on COMMON_CLK select VIDEO_OV7670 select VIDEOBUF2_VMALLOC @@ -19,7 +19,7 @@ config VIDEO_CAFE_CCIC config VIDEO_MMP_CAMERA tristate "Marvell Armada 610 integrated camera controller support" depends on V4L_PLATFORM_DRIVERS - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV depends on ARCH_MMP || COMPILE_TEST depends on COMMON_CLK select VIDEO_OV7670 diff --git a/drivers/media/platform/mediatek/mtk-jpeg/Kconfig b/drivers/media/platform/mediatek/mtk-jpeg/Kconfig index 72ed920b011a..39c4d1bc66ce 100644 --- a/drivers/media/platform/mediatek/mtk-jpeg/Kconfig +++ b/drivers/media/platform/mediatek/mtk-jpeg/Kconfig @@ -3,7 +3,7 @@ config VIDEO_MEDIATEK_JPEG tristate "Mediatek JPEG Codec driver" depends on V4L_MEM2MEM_DRIVERS depends on MTK_IOMMU_V1 || MTK_IOMMU || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_MEDIATEK || COMPILE_TEST depends on MTK_SMI || (COMPILE_TEST && MTK_SMI=n) select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/platform/mediatek/mtk-mdp/Kconfig b/drivers/media/platform/mediatek/mtk-mdp/Kconfig index 0cc743165a1a..9f13a42899bd 100644 --- a/drivers/media/platform/mediatek/mtk-mdp/Kconfig +++ b/drivers/media/platform/mediatek/mtk-mdp/Kconfig @@ -3,7 +3,7 @@ config VIDEO_MEDIATEK_MDP tristate "Mediatek MDP driver" depends on V4L_MEM2MEM_DRIVERS depends on MTK_IOMMU || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_MEDIATEK || COMPILE_TEST depends on MTK_SMI || (COMPILE_TEST && MTK_SMI=n) select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/platform/mediatek/mtk-vcodec/Kconfig b/drivers/media/platform/mediatek/mtk-vcodec/Kconfig index 635801a19d55..c5c76753c626 100644 --- a/drivers/media/platform/mediatek/mtk-vcodec/Kconfig +++ b/drivers/media/platform/mediatek/mtk-vcodec/Kconfig @@ -9,7 +9,7 @@ config VIDEO_MEDIATEK_VCODEC tristate "Mediatek Video Codec driver" depends on V4L_MEM2MEM_DRIVERS depends on MTK_IOMMU || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_MEDIATEK || COMPILE_TEST depends on VIDEO_MEDIATEK_VPU || MTK_SCP # The two following lines ensure we have the same state ("m" or "y") as diff --git a/drivers/media/platform/mediatek/mtk-vpu/Kconfig b/drivers/media/platform/mediatek/mtk-vpu/Kconfig index df679ea79ed0..2a8443a93ce0 100644 --- a/drivers/media/platform/mediatek/mtk-vpu/Kconfig +++ b/drivers/media/platform/mediatek/mtk-vpu/Kconfig @@ -3,7 +3,7 @@ config VIDEO_MEDIATEK_VPU tristate "Mediatek Video Processor Unit" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_MEDIATEK || COMPILE_TEST help This driver provides downloading VPU firmware and diff --git a/drivers/media/platform/nvidia/tegra-vde/Kconfig b/drivers/media/platform/nvidia/tegra-vde/Kconfig index 584b78d8d66c..f7454823bbbb 100644 --- a/drivers/media/platform/nvidia/tegra-vde/Kconfig +++ b/drivers/media/platform/nvidia/tegra-vde/Kconfig @@ -2,7 +2,7 @@ config VIDEO_TEGRA_VDE tristate "NVIDIA Tegra Video Decoder Engine driver" depends on V4L_MEM2MEM_DRIVERS depends on ARCH_TEGRA || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV select DMA_SHARED_BUFFER select IOMMU_IOVA select MEDIA_CONTROLLER diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig index 3f5b8ed3c6ad..7473096f5885 100644 --- a/drivers/media/platform/nxp/Kconfig +++ b/drivers/media/platform/nxp/Kconfig @@ -17,7 +17,7 @@ config VIDEO_IMX_MIPI_CSIS config VIDEO_VIU tristate "NXP VIU Video Driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && (PPC_MPC512x || COMPILE_TEST) && I2C + depends on VIDEO_DEV && (PPC_MPC512x || COMPILE_TEST) && I2C select VIDEOBUF_DMA_CONTIG default y help @@ -32,7 +32,7 @@ config VIDEO_VIU config VIDEO_IMX_PXP tristate "NXP i.MX Pixel Pipeline (PXP)" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 && (ARCH_MXC || COMPILE_TEST) + depends on VIDEO_DEV && (ARCH_MXC || COMPILE_TEST) select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV help @@ -42,7 +42,7 @@ config VIDEO_IMX_PXP config VIDEO_MX2_EMMAPRP tristate "NXP MX2 eMMa-PrP support" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on SOC_IMX27 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/nxp/imx-jpeg/Kconfig b/drivers/media/platform/nxp/imx-jpeg/Kconfig index cbf6101a8b1d..5214dcd7fab5 100644 --- a/drivers/media/platform/nxp/imx-jpeg/Kconfig +++ b/drivers/media/platform/nxp/imx-jpeg/Kconfig @@ -3,7 +3,7 @@ config VIDEO_IMX8_JPEG tristate "IMX8 JPEG Encoder/Decoder" depends on V4L_MEM2MEM_DRIVERS depends on ARCH_MXC || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select V4L2_JPEG_HELPER diff --git a/drivers/media/platform/qcom/camss/Kconfig b/drivers/media/platform/qcom/camss/Kconfig index 56be91578706..4eda48cb1adf 100644 --- a/drivers/media/platform/qcom/camss/Kconfig +++ b/drivers/media/platform/qcom/camss/Kconfig @@ -1,7 +1,7 @@ config VIDEO_QCOM_CAMSS tristate "Qualcomm V4L2 Camera Subsystem driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/qcom/venus/Kconfig b/drivers/media/platform/qcom/venus/Kconfig index de0fe3f7be5f..bfd50e8f3421 100644 --- a/drivers/media/platform/qcom/venus/Kconfig +++ b/drivers/media/platform/qcom/venus/Kconfig @@ -1,7 +1,7 @@ config VIDEO_QCOM_VENUS tristate "Qualcomm Venus V4L2 encoder/decoder driver" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 && QCOM_SMEM + depends on VIDEO_DEV && QCOM_SMEM depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST select QCOM_MDT_LOADER if ARCH_QCOM select QCOM_SCM diff --git a/drivers/media/platform/renesas/Kconfig b/drivers/media/platform/renesas/Kconfig index bc174a028b10..9fd90672ea2d 100644 --- a/drivers/media/platform/renesas/Kconfig +++ b/drivers/media/platform/renesas/Kconfig @@ -4,10 +4,20 @@ comment "Renesas media platform drivers" # V4L drivers +config VIDEO_RENESAS_CEU + tristate "Renesas Capture Engine Unit (CEU) driver" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV + depends on ARCH_SHMOBILE || ARCH_R7S72100 || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + help + This is a v4l2 driver for the Renesas CEU Interface + config VIDEO_RCAR_ISP tristate "R-Car Image Signal Processor (ISP)" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && OF + depends on VIDEO_DEV && OF depends on ARCH_RENESAS || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -21,16 +31,6 @@ config VIDEO_RCAR_ISP To compile this driver as a module, choose M here: the module will be called rcar-isp. -config VIDEO_RENESAS_CEU - tristate "Renesas Capture Engine Unit (CEU) driver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 - depends on ARCH_SHMOBILE || ARCH_R7S72100 || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - select V4L2_FWNODE - help - This is a v4l2 driver for the Renesas CEU Interface - config VIDEO_SH_VOU tristate "SuperH VOU video output driver" depends on V4L_PLATFORM_DRIVERS @@ -61,7 +61,7 @@ config VIDEO_RENESAS_FCP config VIDEO_RENESAS_FDP1 tristate "Renesas Fine Display Processor" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_RENESAS || COMPILE_TEST depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP select VIDEOBUF2_DMA_CONTIG @@ -76,7 +76,7 @@ config VIDEO_RENESAS_FDP1 config VIDEO_RENESAS_JPU tristate "Renesas JPEG Processing Unit" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV @@ -89,7 +89,7 @@ config VIDEO_RENESAS_JPU config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_RENESAS || COMPILE_TEST depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP select MEDIA_CONTROLLER @@ -107,7 +107,7 @@ config VIDEO_RENESAS_VSP1 config VIDEO_RCAR_DRIF tristate "Renesas Digital Radio Interface (DRIF)" depends on SDR_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_VMALLOC select V4L2_ASYNC diff --git a/drivers/media/platform/renesas/rcar-vin/Kconfig b/drivers/media/platform/renesas/rcar-vin/Kconfig index 34b7ea6f1246..de55fe63d84c 100644 --- a/drivers/media/platform/renesas/rcar-vin/Kconfig +++ b/drivers/media/platform/renesas/rcar-vin/Kconfig @@ -2,7 +2,7 @@ config VIDEO_RCAR_CSI2 tristate "R-Car MIPI CSI-2 Receiver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && OF + depends on VIDEO_DEV && OF depends on ARCH_RENESAS || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API @@ -18,7 +18,7 @@ config VIDEO_RCAR_CSI2 config VIDEO_RCAR_VIN tristate "R-Car Video Input (VIN) Driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && OF + depends on VIDEO_DEV && OF depends on ARCH_RENESAS || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/rockchip/rga/Kconfig b/drivers/media/platform/rockchip/rga/Kconfig index 0106cc8a93a7..727a0f6ea466 100644 --- a/drivers/media/platform/rockchip/rga/Kconfig +++ b/drivers/media/platform/rockchip/rga/Kconfig @@ -1,7 +1,7 @@ config VIDEO_ROCKCHIP_RGA tristate "Rockchip Raster 2d Graphic Acceleration Unit" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_ROCKCHIP || COMPILE_TEST select VIDEOBUF2_DMA_SG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/rockchip/rkisp1/Kconfig b/drivers/media/platform/rockchip/rkisp1/Kconfig index c2e464317929..dabd7e42c193 100644 --- a/drivers/media/platform/rockchip/rkisp1/Kconfig +++ b/drivers/media/platform/rockchip/rkisp1/Kconfig @@ -2,7 +2,7 @@ config VIDEO_ROCKCHIP_ISP1 tristate "Rockchip Image Signal Processing v1 Unit driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && OF + depends on VIDEO_DEV && OF depends on ARCH_ROCKCHIP || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/samsung/exynos-gsc/Kconfig b/drivers/media/platform/samsung/exynos-gsc/Kconfig index f9bdffe915b4..7244d63c9646 100644 --- a/drivers/media/platform/samsung/exynos-gsc/Kconfig +++ b/drivers/media/platform/samsung/exynos-gsc/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC tristate "Samsung Exynos G-Scaler driver" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/samsung/exynos4-is/Kconfig b/drivers/media/platform/samsung/exynos4-is/Kconfig index 868bb86c7699..da33faa7132e 100644 --- a/drivers/media/platform/samsung/exynos4-is/Kconfig +++ b/drivers/media/platform/samsung/exynos4-is/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SAMSUNG_EXYNOS4_IS tristate "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && OF && COMMON_CLK + depends on VIDEO_DEV && OF && COMMON_CLK depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/samsung/s3c-camif/Kconfig b/drivers/media/platform/samsung/s3c-camif/Kconfig index e8ef9e06dc1b..8cb8d1ac3edc 100644 --- a/drivers/media/platform/samsung/s3c-camif/Kconfig +++ b/drivers/media/platform/samsung/s3c-camif/Kconfig @@ -2,7 +2,7 @@ config VIDEO_S3C_CAMIF tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && I2C && PM + depends on VIDEO_DEV && I2C && PM depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/samsung/s5p-g2d/Kconfig b/drivers/media/platform/samsung/s5p-g2d/Kconfig index 9bc9d90a666a..28ab88fc2d7c 100644 --- a/drivers/media/platform/samsung/s5p-g2d/Kconfig +++ b/drivers/media/platform/samsung/s5p-g2d/Kconfig @@ -1,7 +1,7 @@ config VIDEO_SAMSUNG_S5P_G2D tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/samsung/s5p-jpeg/Kconfig b/drivers/media/platform/samsung/s5p-jpeg/Kconfig index e522860d2b15..11f6e99dec39 100644 --- a/drivers/media/platform/samsung/s5p-jpeg/Kconfig +++ b/drivers/media/platform/samsung/s5p-jpeg/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SAMSUNG_S5P_JPEG tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/samsung/s5p-mfc/Kconfig b/drivers/media/platform/samsung/s5p-mfc/Kconfig index 34b52b0de304..7ee3b0c8d98b 100644 --- a/drivers/media/platform/samsung/s5p-mfc/Kconfig +++ b/drivers/media/platform/samsung/s5p-mfc/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SAMSUNG_S5P_MFC tristate "Samsung S5P MFC Video Codec" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG help diff --git a/drivers/media/platform/st/sti/bdisp/Kconfig b/drivers/media/platform/st/sti/bdisp/Kconfig index e583fb924f52..496f8aedf0a4 100644 --- a/drivers/media/platform/st/sti/bdisp/Kconfig +++ b/drivers/media/platform/st/sti/bdisp/Kconfig @@ -2,7 +2,7 @@ config VIDEO_STI_BDISP tristate "STMicroelectronics BDISP 2D blitter driver" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_STI || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/st/sti/delta/Kconfig b/drivers/media/platform/st/sti/delta/Kconfig index 0bbc7edce208..efa936b1cc8a 100644 --- a/drivers/media/platform/st/sti/delta/Kconfig +++ b/drivers/media/platform/st/sti/delta/Kconfig @@ -2,7 +2,7 @@ config VIDEO_STI_DELTA tristate "STMicroelectronics DELTA multi-format video decoder V4L2 driver" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_STI || COMPILE_TEST help This V4L2 driver enables DELTA multi-format video decoder diff --git a/drivers/media/platform/st/sti/hva/Kconfig b/drivers/media/platform/st/sti/hva/Kconfig index 5651667bcc54..46d6f82f648e 100644 --- a/drivers/media/platform/st/sti/hva/Kconfig +++ b/drivers/media/platform/st/sti/hva/Kconfig @@ -2,7 +2,7 @@ config VIDEO_STI_HVA tristate "STMicroelectronics HVA multi-format video encoder V4L2 driver" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_STI || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/st/stm32/Kconfig b/drivers/media/platform/st/stm32/Kconfig index 60b87e403c7c..b22dd4753496 100644 --- a/drivers/media/platform/st/stm32/Kconfig +++ b/drivers/media/platform/st/stm32/Kconfig @@ -4,7 +4,7 @@ config VIDEO_STM32_DCMI tristate "STM32 Digital Camera Memory Interface (DCMI) support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && OF + depends on VIDEO_DEV && OF depends on ARCH_STM32 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select MEDIA_CONTROLLER @@ -20,7 +20,7 @@ config VIDEO_STM32_DCMI config VIDEO_STM32_DMA2D tristate "STM32 Chrom-Art Accelerator (DMA2D)" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_STM32 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/media/platform/sunxi/sun4i-csi/Kconfig b/drivers/media/platform/sunxi/sun4i-csi/Kconfig index 43ad2dd7da5d..7960e6836f41 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun4i-csi/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SUN4I_CSI tristate "Allwinner A10 CMOS Sensor Interface Support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && COMMON_CLK && HAS_DMA + depends on VIDEO_DEV && COMMON_CLK && HAS_DMA depends on ARCH_SUNXI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index 6d9cf1963c41..0345901617d4 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SUN6I_CSI tristate "Allwinner V3s Camera Sensor Interface driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && COMMON_CLK && HAS_DMA + depends on VIDEO_DEV && COMMON_CLK && HAS_DMA depends on ARCH_SUNXI || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/sunxi/sun8i-di/Kconfig b/drivers/media/platform/sunxi/sun8i-di/Kconfig index 8d762e664d45..ff71e06ee2df 100644 --- a/drivers/media/platform/sunxi/sun8i-di/Kconfig +++ b/drivers/media/platform/sunxi/sun8i-di/Kconfig @@ -2,7 +2,7 @@ config VIDEO_SUN8I_DEINTERLACE tristate "Allwinner Deinterlace driver" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST depends on COMMON_CLK && OF depends on PM diff --git a/drivers/media/platform/sunxi/sun8i-rotate/Kconfig b/drivers/media/platform/sunxi/sun8i-rotate/Kconfig index 64a8ea76e917..cfba29072d75 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/Kconfig +++ b/drivers/media/platform/sunxi/sun8i-rotate/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SUN8I_ROTATE tristate "Allwinner DE2 rotation driver" depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_SUNXI || COMPILE_TEST depends on COMMON_CLK && OF depends on PM diff --git a/drivers/media/platform/ti/am437x/Kconfig b/drivers/media/platform/ti/am437x/Kconfig index 619cefca7590..2e24fff7e625 100644 --- a/drivers/media/platform/ti/am437x/Kconfig +++ b/drivers/media/platform/ti/am437x/Kconfig @@ -2,7 +2,7 @@ config VIDEO_AM437X_VPFE tristate "TI AM437x VPFE video capture driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on SOC_AM43XX || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/ti/davinci/Kconfig b/drivers/media/platform/ti/davinci/Kconfig index 7e5f92b0082a..c61e697aeb12 100644 --- a/drivers/media/platform/ti/davinci/Kconfig +++ b/drivers/media/platform/ti/davinci/Kconfig @@ -2,7 +2,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY tristate "TI DaVinci VPIF V4L2-Display driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST depends on I2C select VIDEOBUF2_DMA_CONTIG @@ -19,7 +19,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY config VIDEO_DAVINCI_VPIF_CAPTURE tristate "TI DaVinci VPIF video capture driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST depends on I2C select VIDEOBUF2_DMA_CONTIG @@ -35,7 +35,7 @@ config VIDEO_DAVINCI_VPIF_CAPTURE config VIDEO_DM6446_CCDC tristate "TI DM6446 CCDC video capture driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST depends on I2C select VIDEOBUF_DMA_CONTIG @@ -52,7 +52,7 @@ config VIDEO_DM6446_CCDC config VIDEO_DM355_CCDC tristate "TI DM355 CCDC video capture driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST depends on I2C select VIDEOBUF_DMA_CONTIG @@ -69,7 +69,7 @@ config VIDEO_DM355_CCDC config VIDEO_DM365_ISIF tristate "TI DM365 ISIF video capture driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST depends on I2C select VIDEOBUF_DMA_CONTIG @@ -84,7 +84,7 @@ config VIDEO_DM365_ISIF config VIDEO_DAVINCI_VPBE_DISPLAY tristate "TI DaVinci VPBE V4L2-Display driver" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on ARCH_DAVINCI || COMPILE_TEST depends on I2C select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/platform/ti/omap/Kconfig b/drivers/media/platform/ti/omap/Kconfig index 789d5e5686c7..a9dbe1097775 100644 --- a/drivers/media/platform/ti/omap/Kconfig +++ b/drivers/media/platform/ti/omap/Kconfig @@ -10,7 +10,7 @@ config VIDEO_OMAP2_VOUT depends on MMU depends on FB_OMAP2 || (COMPILE_TEST && FB_OMAP2=n) depends on ARCH_OMAP2 || ARCH_OMAP3 || COMPILE_TEST - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_DMA_CONTIG select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 help diff --git a/drivers/media/platform/ti/omap3isp/Kconfig b/drivers/media/platform/ti/omap3isp/Kconfig index 85f0cf063153..f0a680938d5e 100644 --- a/drivers/media/platform/ti/omap3isp/Kconfig +++ b/drivers/media/platform/ti/omap3isp/Kconfig @@ -2,7 +2,7 @@ config VIDEO_OMAP3 tristate "OMAP 3 Camera support" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on (ARCH_OMAP3 && OMAP_IOMMU) || COMPILE_TEST depends on COMMON_CLK && OF select ARM_DMA_USE_IOMMU if OMAP_IOMMU diff --git a/drivers/media/platform/via/Kconfig b/drivers/media/platform/via/Kconfig index 9080960a4a5b..8926eb0803b2 100644 --- a/drivers/media/platform/via/Kconfig +++ b/drivers/media/platform/via/Kconfig @@ -5,7 +5,7 @@ comment "VIA media platform drivers" config VIDEO_VIA_CAMERA tristate "VIAFB camera controller support" depends on V4L_PLATFORM_DRIVERS - depends on FB_VIA && VIDEO_V4L2 + depends on FB_VIA && VIDEO_DEV select VIDEOBUF2_DMA_SG select VIDEO_OV7670 help diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig index 6b38ec7876f6..93ef78bf62e6 100644 --- a/drivers/media/platform/xilinx/Kconfig +++ b/drivers/media/platform/xilinx/Kconfig @@ -5,7 +5,7 @@ comment "Xilinx media platform drivers" config VIDEO_XILINX tristate "Xilinx Video IP (EXPERIMENTAL)" depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_V4L2 && OF && HAS_DMA + depends on VIDEO_DEV && OF && HAS_DMA select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index d29e29645e04..58c10a2ed292 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -5,13 +5,13 @@ menuconfig RADIO_ADAPTERS bool "Radio Adapters" - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on MEDIA_RADIO_SUPPORT default y help Say Y here to enable selecting AM/FM radio adapters. -if RADIO_ADAPTERS && VIDEO_V4L2 +if RADIO_ADAPTERS config RADIO_TEA575X tristate @@ -20,13 +20,12 @@ source "drivers/media/radio/si470x/Kconfig" config RADIO_SI4713 tristate "Silicon Labs Si4713 FM Radio with RDS Transmitter support" - depends on VIDEO_V4L2 source "drivers/media/radio/si4713/Kconfig" config RADIO_SI476X tristate "Silicon Laboratories Si476x I2C FM Radio" - depends on I2C && VIDEO_V4L2 + depends on I2C depends on MFD_SI476X_CORE depends on SND_SOC select SND_SOC_SI476X @@ -43,7 +42,7 @@ config RADIO_SI476X config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" - depends on USB && VIDEO_V4L2 + depends on USB help Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and @@ -55,7 +54,7 @@ config USB_MR800 config USB_DSBR tristate "D-Link/GemTek USB FM radio support" - depends on USB && VIDEO_V4L2 + depends on USB help Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and @@ -67,7 +66,7 @@ config USB_DSBR config RADIO_MAXIRADIO tristate "Guillemot MAXI Radio FM 2000 radio" - depends on VIDEO_V4L2 && PCI + depends on PCI select RADIO_TEA575X help Choose Y here if you have this radio card. This card may also be @@ -118,7 +117,7 @@ config RADIO_SHARK2 config USB_KEENE tristate "Keene FM Transmitter USB support" - depends on USB && VIDEO_V4L2 + depends on USB help Say Y here if you want to connect this type of FM transmitter to your computer's USB port. @@ -128,7 +127,7 @@ config USB_KEENE config USB_RAREMONO tristate "Thanko's Raremono AM/FM/SW radio support" - depends on USB && VIDEO_V4L2 + depends on USB help The 'Thanko's Raremono' device contains the Si4734 chip from Silicon Labs Inc. It is one of the very few or perhaps the only consumer USB radio device @@ -142,7 +141,7 @@ config USB_RAREMONO config USB_MA901 tristate "Masterkit MA901 USB FM radio support" - depends on USB && VIDEO_V4L2 + depends on USB help Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and @@ -154,7 +153,7 @@ config USB_MA901 config RADIO_TEA5764 tristate "TEA5764 I2C FM radio support" - depends on I2C && VIDEO_V4L2 + depends on I2C help Say Y here if you want to use the TEA5764 FM chip found in EZX phones. This FM chip is present in EZX phones from Motorola, @@ -173,7 +172,7 @@ config RADIO_TEA5764_XTAL config RADIO_SAA7706H tristate "SAA7706H Car Radio DSP" - depends on I2C && VIDEO_V4L2 + depends on I2C help Say Y here if you want to use the SAA7706H Car radio Digital Signal Processor, found for instance on the Russellville development @@ -185,7 +184,7 @@ config RADIO_SAA7706H config RADIO_TEF6862 tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" - depends on I2C && VIDEO_V4L2 + depends on I2C help Say Y here if you want to use the TEF6862 Car Radio Enhanced Selectivity Tuner, found for instance on the Russellville development @@ -197,7 +196,7 @@ config RADIO_TEF6862 config RADIO_TIMBERDALE tristate "Enable the Timberdale radio driver" - depends on MFD_TIMBERDALE && VIDEO_V4L2 + depends on MFD_TIMBERDALE depends on I2C # for RADIO_SAA7706H select RADIO_TEF6862 select RADIO_SAA7706H @@ -208,7 +207,7 @@ config RADIO_TIMBERDALE config RADIO_WL1273 tristate "Texas Instruments WL1273 I2C FM Radio" - depends on I2C && VIDEO_V4L2 + depends on I2C select MFD_CORE select MFD_WL1273_CORE select FW_LOADER @@ -245,7 +244,6 @@ config RADIO_ISA config RADIO_CADET tristate "ADS Cadet AM/FM Tuner" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 help Choose Y here if you have one of these AM/FM radio cards, and then fill in the port address below. @@ -256,7 +254,6 @@ config RADIO_CADET config RADIO_RTRACK tristate "AIMSlab RadioTrack (aka RadioReveal) support" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 select RADIO_ISA help Choose Y here if you have one of these FM radio cards, and then fill @@ -288,7 +285,6 @@ config RADIO_RTRACK_PORT config RADIO_RTRACK2 tristate "AIMSlab RadioTrack II support" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 select RADIO_ISA help Choose Y here if you have this FM radio card, and then fill in the @@ -312,7 +308,6 @@ config RADIO_RTRACK2_PORT config RADIO_AZTECH tristate "Aztech/Packard Bell Radio" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 select RADIO_ISA help Choose Y here if you have one of these FM radio cards, and then fill @@ -333,7 +328,6 @@ config RADIO_AZTECH_PORT config RADIO_GEMTEK tristate "GemTek Radio card (or compatible) support" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 select RADIO_ISA help Choose Y here if you have this FM radio card, and then fill in the @@ -374,7 +368,7 @@ config RADIO_GEMTEK_PROBE config RADIO_MIROPCM20 tristate "miroSOUND PCM20 radio" depends on ISA || COMPILE_TEST - depends on ISA_DMA_API && VIDEO_V4L2 && SND + depends on ISA_DMA_API && SND select SND_ISA select SND_MIRO help @@ -389,7 +383,6 @@ config RADIO_MIROPCM20 config RADIO_SF16FMI tristate "SF16-FMI/SF16-FMP/SF16-FMD Radio" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 help Choose Y here if you have one of these FM radio cards. @@ -399,7 +392,6 @@ config RADIO_SF16FMI config RADIO_SF16FMR2 tristate "SF16-FMR2/SF16-FMD2 Radio" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 select RADIO_TEA575X help Choose Y here if you have one of these FM radio cards. @@ -410,7 +402,6 @@ config RADIO_SF16FMR2 config RADIO_TERRATEC tristate "TerraTec ActiveRadio ISA Standalone" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 select RADIO_ISA help Choose Y here if you have this FM radio card. @@ -425,7 +416,6 @@ config RADIO_TERRATEC config RADIO_TRUST tristate "Trust FM radio card" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 select RADIO_ISA help This is a driver for the Trust FM radio cards. Say Y if you have @@ -449,7 +439,6 @@ config RADIO_TRUST_PORT config RADIO_TYPHOON tristate "Typhoon Radio (a.k.a. EcoRadio)" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 select RADIO_ISA help Choose Y here if you have one of these FM radio cards, and then fill @@ -484,7 +473,6 @@ config RADIO_TYPHOON_MUTEFREQ config RADIO_ZOLTRIX tristate "Zoltrix Radio" depends on ISA || COMPILE_TEST - depends on VIDEO_V4L2 select RADIO_ISA help Choose Y here if you have one of these FM radio cards, and then fill diff --git a/drivers/media/radio/si470x/Kconfig b/drivers/media/radio/si470x/Kconfig index 7161bd6cd13c..9f7d35b04a13 100644 --- a/drivers/media/radio/si470x/Kconfig +++ b/drivers/media/radio/si470x/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config RADIO_SI470X tristate "Silicon Labs Si470x FM Radio Receiver support" - depends on VIDEO_V4L2 + depends on VIDEO_DEV help This is a driver for devices with the Silicon Labs SI470x chip (either via USB or I2C buses). diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig index d5ae3388d3db..3e7713872e3f 100644 --- a/drivers/media/radio/wl128x/Kconfig +++ b/drivers/media/radio/wl128x/Kconfig @@ -4,7 +4,7 @@ # config RADIO_WL128X tristate "Texas Instruments WL128x FM Radio" - depends on VIDEO_V4L2 && RFKILL && TTY && TI_ST + depends on VIDEO_DEV && RFKILL && TTY && TI_ST depends on GPIOLIB || COMPILE_TEST help Choose Y here if you have this FM radio chip. diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index 857ef4ace6e9..01e4e6cce027 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -if VIDEO_V4L2 +if VIDEO_DEV comment "SPI I2C drivers auto-selected by 'Autoselect ancillary drivers'" depends on MEDIA_HIDE_ANCILLARY_SUBDRV && SPI @@ -9,7 +9,7 @@ menu "SPI helper chips" config VIDEO_GS1662 tristate "Gennum Serializers video" - depends on SPI && VIDEO_V4L2 + depends on SPI && VIDEO_DEV select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API help diff --git a/drivers/media/test-drivers/Kconfig b/drivers/media/test-drivers/Kconfig index e27d6602545d..d663d822ec75 100644 --- a/drivers/media/test-drivers/Kconfig +++ b/drivers/media/test-drivers/Kconfig @@ -12,7 +12,7 @@ source "drivers/media/test-drivers/vivid/Kconfig" config VIDEO_VIM2M tristate "Virtual Memory-to-Memory Driver" - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV select MEDIA_CONTROLLER diff --git a/drivers/media/test-drivers/vicodec/Kconfig b/drivers/media/test-drivers/vicodec/Kconfig index d77c67810c73..a7a828eec2a4 100644 --- a/drivers/media/test-drivers/vicodec/Kconfig +++ b/drivers/media/test-drivers/vicodec/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_VICODEC tristate "Virtual Codec Driver" - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV select MEDIA_CONTROLLER diff --git a/drivers/media/test-drivers/vimc/Kconfig b/drivers/media/test-drivers/vimc/Kconfig index ea37a102dec8..0d5169819cac 100644 --- a/drivers/media/test-drivers/vimc/Kconfig +++ b/drivers/media/test-drivers/vimc/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_VIMC tristate "Virtual Media Controller Driver (VIMC)" - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV select FONT_SUPPORT select FONT_8x16 select MEDIA_CONTROLLER diff --git a/drivers/media/test-drivers/vivid/Kconfig b/drivers/media/test-drivers/vivid/Kconfig index c3abde2986b2..318799d317ba 100644 --- a/drivers/media/test-drivers/vivid/Kconfig +++ b/drivers/media/test-drivers/vivid/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_VIVID tristate "Virtual Video Test Driver" - depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FB + depends on VIDEO_DEV && !SPARC32 && !SPARC64 && FB depends on HAS_DMA select FONT_SUPPORT select FONT_8x16 diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 4605bb377574..81d1d56b9317 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -85,7 +85,7 @@ config MEDIA_TUNER_TEA5767 config MEDIA_TUNER_MSI001 tristate "Mirics MSi001" - depends on MEDIA_SUPPORT && SPI && VIDEO_V4L2 + depends on MEDIA_SUPPORT && SPI && VIDEO_DEV default m if !MEDIA_SUBDRV_AUTOSELECT help Mirics MSi001 silicon tuner driver. @@ -223,7 +223,7 @@ config MEDIA_TUNER_TDA18212 config MEDIA_TUNER_E4000 tristate "Elonics E4000 silicon tuner" - depends on MEDIA_SUPPORT && I2C && VIDEO_V4L2 + depends on MEDIA_SUPPORT && I2C && VIDEO_DEV select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help @@ -231,7 +231,7 @@ config MEDIA_TUNER_E4000 config MEDIA_TUNER_FC2580 tristate "FCI FC2580 silicon tuner" - depends on MEDIA_SUPPORT && I2C && VIDEO_V4L2 + depends on MEDIA_SUPPORT && I2C && VIDEO_DEV select REGMAP_I2C default m if !MEDIA_SUBDRV_AUTOSELECT help diff --git a/drivers/media/tuners/e4000.c b/drivers/media/tuners/e4000.c index 3f1f9af92bc9..a3a8d051dc6c 100644 --- a/drivers/media/tuners/e4000.c +++ b/drivers/media/tuners/e4000.c @@ -257,7 +257,7 @@ err: /* * V4L2 API */ -#if IS_ENABLED(CONFIG_VIDEO_V4L2) +#if IS_ENABLED(CONFIG_VIDEO_DEV) static const struct v4l2_frequency_band bands[] = { { .type = V4L2_TUNER_RF, @@ -654,7 +654,7 @@ static int e4000_probe(struct i2c_client *client, if (ret) goto err_kfree; -#if IS_ENABLED(CONFIG_VIDEO_V4L2) +#if IS_ENABLED(CONFIG_VIDEO_DEV) /* Register controls */ v4l2_ctrl_handler_init(&dev->hdl, 9); dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &e4000_ctrl_ops, @@ -713,7 +713,7 @@ static int e4000_remove(struct i2c_client *client) dev_dbg(&client->dev, "\n"); -#if IS_ENABLED(CONFIG_VIDEO_V4L2) +#if IS_ENABLED(CONFIG_VIDEO_DEV) v4l2_ctrl_handler_free(&dev->hdl); #endif kfree(dev); diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c index 7639a305048f..1b5961bdf2d5 100644 --- a/drivers/media/tuners/fc2580.c +++ b/drivers/media/tuners/fc2580.c @@ -357,7 +357,7 @@ static const struct dvb_tuner_ops fc2580_dvb_tuner_ops = { /* * V4L2 API */ -#if IS_ENABLED(CONFIG_VIDEO_V4L2) +#if IS_ENABLED(CONFIG_VIDEO_DEV) static const struct v4l2_frequency_band bands[] = { { .type = V4L2_TUNER_RF, @@ -552,7 +552,7 @@ static int fc2580_probe(struct i2c_client *client, goto err_kfree; } -#if IS_ENABLED(CONFIG_VIDEO_V4L2) +#if IS_ENABLED(CONFIG_VIDEO_DEV) /* Register controls */ v4l2_ctrl_handler_init(&dev->hdl, 2); dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &fc2580_ctrl_ops, @@ -594,7 +594,7 @@ static int fc2580_remove(struct i2c_client *client) dev_dbg(&client->dev, "\n"); -#if IS_ENABLED(CONFIG_VIDEO_V4L2) +#if IS_ENABLED(CONFIG_VIDEO_DEV) v4l2_ctrl_handler_free(&dev->hdl); #endif kfree(dev); diff --git a/drivers/media/usb/airspy/Kconfig b/drivers/media/usb/airspy/Kconfig index 458345217f78..0662d8701c44 100644 --- a/drivers/media/usb/airspy/Kconfig +++ b/drivers/media/usb/airspy/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_AIRSPY tristate "AirSpy" - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_VMALLOC help This is a video4linux2 driver for AirSpy SDR device. diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 05cc6c48c26f..31799b6ff91f 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -2,12 +2,12 @@ config VIDEO_AU0828 tristate "Auvitek AU0828 support" - depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 + depends on I2C && INPUT && DVB_CORE && USB && VIDEO_DEV select MEDIA_CONTROLLER select MEDIA_CONTROLLER_DVB select I2C_ALGOBIT select VIDEO_TVEEPROM - select VIDEOBUF2_VMALLOC if VIDEO_V4L2 + select VIDEOBUF2_VMALLOC if VIDEO_DEV select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT @@ -22,7 +22,7 @@ config VIDEO_AU0828 config VIDEO_AU0828_V4L2 bool "Auvitek AU0828 v4l2 analog video support" depends on VIDEO_AU0828 - depends on VIDEO_V4L2=y || VIDEO_V4L2=VIDEO_AU0828 + depends on VIDEO_DEV=y || VIDEO_DEV=VIDEO_AU0828 select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TUNER default y diff --git a/drivers/media/usb/cpia2/Kconfig b/drivers/media/usb/cpia2/Kconfig index e2c18ab0262b..da2c6862b4a2 100644 --- a/drivers/media/usb/cpia2/Kconfig +++ b/drivers/media/usb/cpia2/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_CPIA2 tristate "CPiA2 Video For Linux" - depends on VIDEO_DEV && USB && VIDEO_V4L2 + depends on USB && VIDEO_DEV help This is the video4linux driver for cameras based on Vision's CPiA2 (Colour Processor Interface ASIC), such as the Digital Blue QX5 diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 60ca8b9d070b..a4600a97d1fd 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -40,7 +40,7 @@ config DVB_USB_AF9035 select MEDIA_TUNER_FC0011 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_FC2580 if (MEDIA_SUBDRV_AUTOSELECT && VIDEO_V4L2) + select MEDIA_TUNER_FC2580 if (MEDIA_SUBDRV_AUTOSELECT && VIDEO_DEV) select MEDIA_TUNER_IT913X if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Afatech AF9035 based DVB USB receiver. @@ -139,12 +139,12 @@ config DVB_USB_RTL28XXU select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT select DVB_RTL2830 select DVB_RTL2832 - select DVB_RTL2832_SDR if (MEDIA_SUBDRV_AUTOSELECT && MEDIA_SDR_SUPPORT && VIDEO_V4L2) + select DVB_RTL2832_SDR if (MEDIA_SUBDRV_AUTOSELECT && MEDIA_SDR_SUPPORT && VIDEO_DEV) select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_E4000 if (MEDIA_SUBDRV_AUTOSELECT && VIDEO_V4L2) + select MEDIA_TUNER_E4000 if (MEDIA_SUBDRV_AUTOSELECT && VIDEO_DEV) select MEDIA_TUNER_FC0012 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_FC2580 if (MEDIA_SUBDRV_AUTOSELECT && VIDEO_V4L2) + select MEDIA_TUNER_FC2580 if (MEDIA_SUBDRV_AUTOSELECT && VIDEO_DEV) select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index 7498110142e4..6df96c2bf569 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -150,8 +150,8 @@ config DVB_USB_CXUSB config DVB_USB_CXUSB_ANALOG bool "Analog support for the Conexant USB2.0 hybrid reference design" - depends on DVB_USB_CXUSB && VIDEO_V4L2 - depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_USB_CXUSB + depends on DVB_USB_CXUSB && VIDEO_DEV + depends on VIDEO_DEV=y || VIDEO_DEV=DVB_USB_CXUSB select VIDEO_CX25840 select VIDEOBUF2_VMALLOC help diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index dca4e16ed133..2b106a7fcf4c 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only menuconfig USB_GSPCA tristate "GSPCA based webcams" - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on INPUT || INPUT=n select VIDEOBUF2_VMALLOC help @@ -17,7 +17,7 @@ menuconfig USB_GSPCA module will be called gspca_main. -if USB_GSPCA && VIDEO_V4L2 +if USB_GSPCA && VIDEO_DEV source "drivers/media/usb/gspca/m5602/Kconfig" source "drivers/media/usb/gspca/stv06xx/Kconfig" @@ -25,7 +25,7 @@ source "drivers/media/usb/gspca/gl860/Kconfig" config USB_GSPCA_BENQ tristate "Benq USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for the Benq DC E300 camera. @@ -34,7 +34,7 @@ config USB_GSPCA_BENQ config USB_GSPCA_CONEX tristate "Conexant Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the Conexant chip. @@ -43,7 +43,7 @@ config USB_GSPCA_CONEX config USB_GSPCA_CPIA1 tristate "cpia CPiA (version 1) Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for USB cameras based on the cpia CPiA chip. Note that you need at least version 0.6.4 of libv4l for @@ -54,7 +54,7 @@ config USB_GSPCA_CPIA1 config USB_GSPCA_DTCS033 tristate "DTCS033 (Scopium) USB Astro-Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for the Scopium camera for planetary astrophotography. @@ -64,7 +64,7 @@ config USB_GSPCA_DTCS033 config USB_GSPCA_ETOMS tristate "Etoms USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the Etoms chip. @@ -73,7 +73,7 @@ config USB_GSPCA_ETOMS config USB_GSPCA_FINEPIX tristate "Fujifilm FinePix USB V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the FinePix chip. @@ -82,7 +82,7 @@ config USB_GSPCA_FINEPIX config USB_GSPCA_JEILINJ tristate "Jeilin JPEG USB V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on this Jeilin chip. @@ -91,7 +91,7 @@ config USB_GSPCA_JEILINJ config USB_GSPCA_JL2005BCD tristate "JL2005B/C/D USB V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based the JL2005B, JL2005C, or JL2005D chip. @@ -101,7 +101,7 @@ config USB_GSPCA_JL2005BCD config USB_GSPCA_KINECT tristate "Kinect sensor device USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for the Microsoft Kinect sensor device. @@ -110,7 +110,7 @@ config USB_GSPCA_KINECT config USB_GSPCA_KONICA tristate "Konica USB Camera V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the Konica chip. @@ -119,7 +119,7 @@ config USB_GSPCA_KONICA config USB_GSPCA_MARS tristate "Mars USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the Mars chip. @@ -128,7 +128,7 @@ config USB_GSPCA_MARS config USB_GSPCA_MR97310A tristate "Mars-Semi MR97310A USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the MR97310A chip. @@ -137,7 +137,7 @@ config USB_GSPCA_MR97310A config USB_GSPCA_NW80X tristate "Divio based (NW80x) USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the NW80x chips. @@ -146,7 +146,7 @@ config USB_GSPCA_NW80X config USB_GSPCA_OV519 tristate "OV51x / OVFX2 / W996xCF USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on one of these: OV511(+), OV518(+), OV519, OVFX2, W9967CF, W9968CF @@ -156,7 +156,7 @@ config USB_GSPCA_OV519 config USB_GSPCA_OV534 tristate "OV534 OV772x USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the OV534 chip and sensor OV772x (e.g. Sony Playstation EYE) @@ -166,7 +166,7 @@ config USB_GSPCA_OV534 config USB_GSPCA_OV534_9 tristate "OV534 OV965x USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the OV534 chip and sensor OV965x (e.g. Hercules Dualpix) @@ -176,7 +176,7 @@ config USB_GSPCA_OV534_9 config USB_GSPCA_PAC207 tristate "Pixart PAC207 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the PAC207 chip. @@ -185,7 +185,7 @@ config USB_GSPCA_PAC207 config USB_GSPCA_PAC7302 tristate "Pixart PAC7302 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the PAC7302 chip. @@ -194,7 +194,7 @@ config USB_GSPCA_PAC7302 config USB_GSPCA_PAC7311 tristate "Pixart PAC7311 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the PAC7311 chip. @@ -203,7 +203,7 @@ config USB_GSPCA_PAC7311 config USB_GSPCA_SE401 tristate "SE401 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the Endpoints (formerly known as AOX) se401 chip. @@ -213,7 +213,7 @@ config USB_GSPCA_SE401 config USB_GSPCA_SN9C2028 tristate "SONIX Dual-Mode USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want streaming support for Sonix SN9C2028 cameras. These are supported as stillcams in libgphoto2/camlibs/sonix. @@ -223,7 +223,7 @@ config USB_GSPCA_SN9C2028 config USB_GSPCA_SN9C20X tristate "SN9C20X USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the sn9c20x chips (SN9C201 and SN9C202). @@ -233,7 +233,7 @@ config USB_GSPCA_SN9C20X config USB_GSPCA_SONIXB tristate "SONIX Bayer USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the Sonix chips with Bayer format (SN9C101, SN9C102 and SN9C103). @@ -243,7 +243,7 @@ config USB_GSPCA_SONIXB config USB_GSPCA_SONIXJ tristate "SONIX JPEG USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the Sonix chips with JPEG format (SN9C102P, SN9C105 and >= SN9C110). @@ -253,7 +253,7 @@ config USB_GSPCA_SONIXJ config USB_GSPCA_SPCA500 tristate "SPCA500 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SPCA500 chip. @@ -262,7 +262,7 @@ config USB_GSPCA_SPCA500 config USB_GSPCA_SPCA501 tristate "SPCA501 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SPCA501 chip. @@ -271,7 +271,7 @@ config USB_GSPCA_SPCA501 config USB_GSPCA_SPCA505 tristate "SPCA505 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SPCA505 chip. @@ -280,7 +280,7 @@ config USB_GSPCA_SPCA505 config USB_GSPCA_SPCA506 tristate "SPCA506 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SPCA506 chip. @@ -289,7 +289,7 @@ config USB_GSPCA_SPCA506 config USB_GSPCA_SPCA508 tristate "SPCA508 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SPCA508 chip. @@ -298,7 +298,7 @@ config USB_GSPCA_SPCA508 config USB_GSPCA_SPCA561 tristate "SPCA561 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SPCA561 chip. @@ -307,7 +307,7 @@ config USB_GSPCA_SPCA561 config USB_GSPCA_SPCA1528 tristate "SPCA1528 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SPCA1528 chip. @@ -316,7 +316,7 @@ config USB_GSPCA_SPCA1528 config USB_GSPCA_SQ905 tristate "SQ Technologies SQ905 based USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SQ905 chip. @@ -325,7 +325,7 @@ config USB_GSPCA_SQ905 config USB_GSPCA_SQ905C tristate "SQ Technologies SQ905C based USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SQ905C chip. @@ -334,7 +334,7 @@ config USB_GSPCA_SQ905C config USB_GSPCA_SQ930X tristate "SQ Technologies SQ930X based USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the SQ930X chip. @@ -343,7 +343,7 @@ config USB_GSPCA_SQ930X config USB_GSPCA_STK014 tristate "Syntek DV4000 (STK014) USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the STK014 chip. @@ -352,7 +352,7 @@ config USB_GSPCA_STK014 config USB_GSPCA_STK1135 tristate "Syntek STK1135 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the STK1135 chip. @@ -361,7 +361,7 @@ config USB_GSPCA_STK1135 config USB_GSPCA_STV0680 tristate "STV0680 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the STV0680 chip. @@ -370,7 +370,7 @@ config USB_GSPCA_STV0680 config USB_GSPCA_SUNPLUS tristate "SUNPLUS USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the Sunplus SPCA504(abc) SPCA533 SPCA536 chips. @@ -380,7 +380,7 @@ config USB_GSPCA_SUNPLUS config USB_GSPCA_T613 tristate "T613 (JPEG Compliance) USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the T613 chip. @@ -389,7 +389,7 @@ config USB_GSPCA_T613 config USB_GSPCA_TOPRO tristate "TOPRO USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the TP6800 and TP6810 Topro chips. @@ -399,7 +399,7 @@ config USB_GSPCA_TOPRO config USB_GSPCA_TOUPTEK tristate "Touptek USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the ToupTek UCMOS / AmScope MU series camera. @@ -409,7 +409,7 @@ config USB_GSPCA_TOUPTEK config USB_GSPCA_TV8532 tristate "TV8532 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the TV8531 chip. @@ -418,7 +418,7 @@ config USB_GSPCA_TV8532 config USB_GSPCA_VC032X tristate "VC032X USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the VC032X chip. @@ -427,7 +427,7 @@ config USB_GSPCA_VC032X config USB_GSPCA_VICAM tristate "ViCam USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for the 3com homeconnect camera (vicam). @@ -437,7 +437,7 @@ config USB_GSPCA_VICAM config USB_GSPCA_XIRLINK_CIT tristate "Xirlink C-It USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for Xirlink C-It bases cameras. @@ -446,7 +446,7 @@ config USB_GSPCA_XIRLINK_CIT config USB_GSPCA_ZC3XX tristate "ZC3XX USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the ZC3XX chip. diff --git a/drivers/media/usb/gspca/gl860/Kconfig b/drivers/media/usb/gspca/gl860/Kconfig index 2dfd2704c915..e5a35ca72b60 100644 --- a/drivers/media/usb/gspca/gl860/Kconfig +++ b/drivers/media/usb/gspca/gl860/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_GL860 tristate "GL860 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the GL860 chip. diff --git a/drivers/media/usb/gspca/m5602/Kconfig b/drivers/media/usb/gspca/m5602/Kconfig index 0a250652d717..d616408b67d9 100644 --- a/drivers/media/usb/gspca/m5602/Kconfig +++ b/drivers/media/usb/gspca/m5602/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_M5602 tristate "ALi USB m5602 Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA + depends on VIDEO_DEV && USB_GSPCA help Say Y here if you want support for cameras based on the ALi m5602 connected to various image sensors. diff --git a/drivers/media/usb/hackrf/Kconfig b/drivers/media/usb/hackrf/Kconfig index 2267cebfdecb..1cf9b4d3a514 100644 --- a/drivers/media/usb/hackrf/Kconfig +++ b/drivers/media/usb/hackrf/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_HACKRF tristate "HackRF" - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_VMALLOC help This is a video4linux2 driver for HackRF SDR device. diff --git a/drivers/media/usb/hdpvr/Kconfig b/drivers/media/usb/hdpvr/Kconfig index 617400b27314..ee45a89aa607 100644 --- a/drivers/media/usb/hdpvr/Kconfig +++ b/drivers/media/usb/hdpvr/Kconfig @@ -2,7 +2,7 @@ config VIDEO_HDPVR tristate "Hauppauge HD PVR support" - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV help This is a video4linux driver for Hauppauge's HD PVR USB device. diff --git a/drivers/media/usb/msi2500/Kconfig b/drivers/media/usb/msi2500/Kconfig index b403603bcc81..c2ded6482a5b 100644 --- a/drivers/media/usb/msi2500/Kconfig +++ b/drivers/media/usb/msi2500/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_MSI2500 tristate "Mirics MSi2500" - depends on VIDEO_V4L2 && SPI + depends on VIDEO_DEV && SPI select VIDEOBUF2_VMALLOC select MEDIA_TUNER_MSI001 diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index e6a4f730591b..f2b64e49c5a2 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X diff --git a/drivers/media/usb/pwc/Kconfig b/drivers/media/usb/pwc/Kconfig index 7cebf6314a67..2078bd5ecf41 100644 --- a/drivers/media/usb/pwc/Kconfig +++ b/drivers/media/usb/pwc/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_PWC tristate "USB Philips Cameras" - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_VMALLOC help Say Y or M here if you want to use one of these Philips & OEM diff --git a/drivers/media/usb/s2255/Kconfig b/drivers/media/usb/s2255/Kconfig index e4a0c914d9c3..889593b21889 100644 --- a/drivers/media/usb/s2255/Kconfig +++ b/drivers/media/usb/s2255/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_S2255 tristate "USB Sensoray 2255 video capture device" - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_VMALLOC help Say Y here if you want support for the Sensoray 2255 USB device. diff --git a/drivers/media/usb/stkwebcam/Kconfig b/drivers/media/usb/stkwebcam/Kconfig index 775a5151539c..d94d023f1aa0 100644 --- a/drivers/media/usb/stkwebcam/Kconfig +++ b/drivers/media/usb/stkwebcam/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_STKWEBCAM tristate "USB Syntek DC1125 Camera support" - depends on VIDEO_V4L2 + depends on VIDEO_DEV help Say Y here if you want to use this type of camera. Supported devices are typically found in some Asus laptops, diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig index 84799c7203d3..578a0e693f8b 100644 --- a/drivers/media/usb/usbtv/Kconfig +++ b/drivers/media/usb/usbtv/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_USBTV tristate "USBTV007 video capture support" - depends on VIDEO_V4L2 && SND + depends on VIDEO_DEV && SND select SND_PCM select VIDEOBUF2_VMALLOC diff --git a/drivers/media/usb/uvc/Kconfig b/drivers/media/usb/uvc/Kconfig index 4c2f4a3216f2..ca51ee8e45f3 100644 --- a/drivers/media/usb/uvc/Kconfig +++ b/drivers/media/usb/uvc/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_VIDEO_CLASS tristate "USB Video Class (UVC)" - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF2_VMALLOC help Support for the USB Video Class (UVC). Currently only video diff --git a/drivers/media/usb/zr364xx/Kconfig b/drivers/media/usb/zr364xx/Kconfig index 49b4257487bb..a9fb02566c4b 100644 --- a/drivers/media/usb/zr364xx/Kconfig +++ b/drivers/media/usb/zr364xx/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config USB_ZR364XX tristate "USB ZR364XX Camera support" - depends on VIDEO_V4L2 + depends on VIDEO_DEV select VIDEOBUF_GEN select VIDEOBUF_VMALLOC help diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 6ee75c6c820e..1be9a2cc947a 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -3,17 +3,9 @@ # Generic video config states # -# Enable the V4L2 core and API -config VIDEO_V4L2 - tristate - depends on (I2C || I2C=n) && VIDEO_DEV - select RATIONAL - select VIDEOBUF2_V4L2 if VIDEOBUF2_CORE - default (I2C || I2C=n) && VIDEO_DEV - config VIDEO_V4L2_I2C bool - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV default y config VIDEO_V4L2_SUBDEV_API @@ -64,7 +56,7 @@ config V4L2_MEM2MEM_DEV # Used by LED subsystem flash drivers config V4L2_FLASH_LED_CLASS tristate "V4L2 flash API for LED flash class devices" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_DEV && VIDEO_V4L2_SUBDEV_API depends on LEDS_CLASS_FLASH select V4L2_ASYNC help diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index 1ec7e9cae1fa..41d91bd10cf2 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -38,4 +38,4 @@ obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o -obj-$(CONFIG_VIDEO_V4L2) += v4l2-dv-timings.o videodev.o +obj-$(CONFIG_VIDEO_DEV) += v4l2-dv-timings.o videodev.o diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig index aeed5803dfb1..2c8d7fdcc5f7 100644 --- a/drivers/staging/media/atomisp/Kconfig +++ b/drivers/staging/media/atomisp/Kconfig @@ -11,7 +11,7 @@ menuconfig INTEL_ATOMISP config VIDEO_ATOMISP tristate "Intel Atom Image Signal Processor Driver" - depends on VIDEO_V4L2 && INTEL_ATOMISP + depends on VIDEO_DEV && INTEL_ATOMISP depends on PMIC_OPREGION select IOSF_MBI select VIDEOBUF_VMALLOC diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index a772b833a85f..e726101b24e4 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -6,7 +6,7 @@ config VIDEO_ATOMISP_OV2722 tristate "OVT ov2722 sensor support" depends on ACPI - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor-level driver for the OVT OV2722 raw camera. @@ -18,7 +18,7 @@ config VIDEO_ATOMISP_OV2722 config VIDEO_ATOMISP_GC2235 tristate "Galaxy gc2235 sensor support" depends on ACPI - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor-level driver for the OVT GC2235 raw camera. @@ -40,7 +40,7 @@ config VIDEO_ATOMISP_MSRLIST_HELPER config VIDEO_ATOMISP_MT9M114 tristate "Aptina mt9m114 sensor support" depends on ACPI - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor-level driver for the Micron mt9m114 1.3 Mpixel camera. @@ -52,7 +52,7 @@ config VIDEO_ATOMISP_MT9M114 config VIDEO_ATOMISP_GC0310 tristate "GC0310 sensor support" depends on ACPI - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor-level driver for the Galaxycore GC0310 0.3MP sensor. @@ -60,7 +60,7 @@ config VIDEO_ATOMISP_GC0310 config VIDEO_ATOMISP_OV2680 tristate "Omnivision OV2680 sensor support" depends on ACPI - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor-level driver for the Omnivision OV2680 raw camera. @@ -72,7 +72,7 @@ config VIDEO_ATOMISP_OV2680 config VIDEO_ATOMISP_OV5693 tristate "Omnivision ov5693 sensor support" depends on ACPI - depends on I2C && VIDEO_V4L2 + depends on I2C && VIDEO_DEV help This is a Video4Linux2 sensor-level driver for the Micron ov5693 5 Mpixel camera. @@ -88,7 +88,7 @@ config VIDEO_ATOMISP_OV5693 config VIDEO_ATOMISP_LM3554 tristate "LM3554 flash light driver" depends on ACPI - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C help This is a Video4Linux2 sub-dev driver for the LM3554 flash light driver. diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig index 3c5d833322c8..0172a6822ec2 100644 --- a/drivers/staging/media/hantro/Kconfig +++ b/drivers/staging/media/hantro/Kconfig @@ -2,7 +2,7 @@ config VIDEO_HANTRO tristate "Hantro VPU driver" depends on ARCH_MXC || ARCH_ROCKCHIP || ARCH_AT91 || ARCH_SUNXI || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV select MEDIA_CONTROLLER select MEDIA_CONTROLLER_REQUEST_API select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig index c3bf433ba3e3..0bacac302d7e 100644 --- a/drivers/staging/media/imx/Kconfig +++ b/drivers/staging/media/imx/Kconfig @@ -4,7 +4,7 @@ config VIDEO_IMX_MEDIA depends on ARCH_MXC || COMPILE_TEST depends on HAS_DMA depends on VIDEO_DEV - depends on VIDEO_V4L2 + depends on VIDEO_DEV select MEDIA_CONTROLLER select V4L2_FWNODE select V4L2_MEM2MEM_DEV diff --git a/drivers/staging/media/ipu3/Kconfig b/drivers/staging/media/ipu3/Kconfig index 3e9640523e50..114a1d8e7cc8 100644 --- a/drivers/staging/media/ipu3/Kconfig +++ b/drivers/staging/media/ipu3/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 config VIDEO_IPU3_IMGU tristate "Intel ipu3-imgu driver" - depends on PCI && VIDEO_V4L2 + depends on PCI && VIDEO_DEV depends on X86 select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/staging/media/max96712/Kconfig b/drivers/staging/media/max96712/Kconfig index acde14fd5c4d..117fadf81bd0 100644 --- a/drivers/staging/media/max96712/Kconfig +++ b/drivers/staging/media/max96712/Kconfig @@ -3,7 +3,7 @@ config VIDEO_MAX96712 tristate "Maxim MAX96712 Quad GMSL2 Deserializer support" depends on I2C depends on OF_GPIO - depends on VIDEO_V4L2 + depends on VIDEO_DEV select V4L2_FWNODE select VIDEO_V4L2_SUBDEV_API select MEDIA_CONTROLLER diff --git a/drivers/staging/media/meson/vdec/Kconfig b/drivers/staging/media/meson/vdec/Kconfig index 9e1450193392..19ffea987b89 100644 --- a/drivers/staging/media/meson/vdec/Kconfig +++ b/drivers/staging/media/meson/vdec/Kconfig @@ -2,7 +2,7 @@ config VIDEO_MESON_VDEC tristate "Amlogic video decoder driver" - depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on VIDEO_DEV && HAS_DMA depends on ARCH_MESON || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index 6c254907a27b..6d1f55b09132 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -2,7 +2,7 @@ config VIDEO_OMAP4 tristate "OMAP 4 Camera support" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_DEV && I2C depends on ARCH_OMAP4 || COMPILE_TEST select MEDIA_CONTROLLER select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/staging/media/rkvdec/Kconfig b/drivers/staging/media/rkvdec/Kconfig index dc7292f346fa..e963d60cc6ad 100644 --- a/drivers/staging/media/rkvdec/Kconfig +++ b/drivers/staging/media/rkvdec/Kconfig @@ -2,7 +2,7 @@ config VIDEO_ROCKCHIP_VDEC tristate "Rockchip Video Decoder driver" depends on ARCH_ROCKCHIP || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV select MEDIA_CONTROLLER select MEDIA_CONTROLLER_REQUEST_API select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/staging/media/sunxi/cedrus/Kconfig b/drivers/staging/media/sunxi/cedrus/Kconfig index da369950bbf2..21c13f9b6e33 100644 --- a/drivers/staging/media/sunxi/cedrus/Kconfig +++ b/drivers/staging/media/sunxi/cedrus/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 config VIDEO_SUNXI_CEDRUS tristate "Allwinner Cedrus VPU driver" - depends on VIDEO_DEV && VIDEO_V4L2 + depends on VIDEO_DEV depends on HAS_DMA depends on OF select MEDIA_CONTROLLER diff --git a/drivers/staging/media/tegra-video/Kconfig b/drivers/staging/media/tegra-video/Kconfig index 1f35da4b134e..df1b2cff2417 100644 --- a/drivers/staging/media/tegra-video/Kconfig +++ b/drivers/staging/media/tegra-video/Kconfig @@ -2,7 +2,7 @@ config VIDEO_TEGRA tristate "NVIDIA Tegra VI driver" depends on TEGRA_HOST1X - depends on VIDEO_V4L2 + depends on VIDEO_DEV select MEDIA_CONTROLLER select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE diff --git a/drivers/staging/media/zoran/Kconfig b/drivers/staging/media/zoran/Kconfig index faef008b8554..3fb3e27e04a8 100644 --- a/drivers/staging/media/zoran/Kconfig +++ b/drivers/staging/media/zoran/Kconfig @@ -1,6 +1,6 @@ config VIDEO_ZORAN tristate "Zoran ZR36057/36067 Video For Linux (Deprecated)" - depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 + depends on PCI && I2C_ALGOBIT && VIDEO_DEV depends on !ALPHA depends on DEBUG_FS select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/staging/most/video/Kconfig b/drivers/staging/most/video/Kconfig index e0964ca5e7b3..e16cc5e104b7 100644 --- a/drivers/staging/most/video/Kconfig +++ b/drivers/staging/most/video/Kconfig @@ -5,7 +5,7 @@ config MOST_VIDEO tristate "Video" - depends on VIDEO_V4L2 + depends on VIDEO_DEV help Say Y here if you want to commumicate via Video 4 Linux. diff --git a/drivers/staging/vc04_services/bcm2835-camera/Kconfig b/drivers/staging/vc04_services/bcm2835-camera/Kconfig index d0653d1ed3c7..dcda565f9b38 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/Kconfig +++ b/drivers/staging/vc04_services/bcm2835-camera/Kconfig @@ -2,7 +2,7 @@ config VIDEO_BCM2835 tristate "BCM2835 Camera" depends on MEDIA_SUPPORT - depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST) + depends on VIDEO_DEV && (ARCH_BCM2835 || COMPILE_TEST) select BCM2835_VCHIQ select BCM2835_VCHIQ_MMAL select VIDEOBUF2_VMALLOC diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index dd58094f0b85..4fa2ddf322b4 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -448,7 +448,7 @@ config USB_CONFIGFS_F_HID config USB_CONFIGFS_F_UVC bool "USB Webcam function" depends on USB_CONFIGFS - depends on VIDEO_V4L2 + depends on VIDEO_DEV depends on VIDEO_DEV select VIDEOBUF2_DMA_SG select VIDEOBUF2_VMALLOC diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index de6668e58481..0a7b382fbe27 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -500,7 +500,7 @@ endif # or video class gadget drivers), or specific hardware, here. config USB_G_WEBCAM tristate "USB Webcam Gadget" - depends on VIDEO_V4L2 + depends on VIDEO_DEV select USB_LIBCOMPOSITE select VIDEOBUF2_DMA_SG select VIDEOBUF2_VMALLOC diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 41ce12597177..a55836225401 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -559,7 +559,7 @@ config SND_ES1968_RADIO bool "Enable TEA5757 radio tuner support for es1968" depends on SND_ES1968 depends on MEDIA_RADIO_SUPPORT - depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_ES1968 + depends on VIDEO_DEV=y || VIDEO_DEV=SND_ES1968 select RADIO_ADAPTERS select RADIO_TEA575X @@ -583,7 +583,7 @@ config SND_FM801_TEA575X_BOOL bool "ForteMedia FM801 + TEA5757 tuner" depends on SND_FM801 depends on MEDIA_RADIO_SUPPORT - depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801 + depends on VIDEO_DEV=y || VIDEO_DEV=SND_FM801 select RADIO_ADAPTERS select RADIO_TEA575X help -- cgit v1.2.3 From fc0b582c858ed73f94c8f3375c203ea46f1f7402 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 14 Mar 2022 18:11:38 +0100 Subject: media: atomisp: fix bad usage at error handling logic As warned by sparse: atomisp: drivers/staging/media/atomisp/pci/atomisp_acc.c:508 atomisp_acc_load_extensions() warn: iterator used outside loop: 'acc_fw' The acc_fw interactor is used outside the loop, at the error handling logic. On most cases, this is actually safe there, but, if atomisp_css_set_acc_parameters() has an error, an attempt to use it will pick an invalid value for acc_fw. Reported-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp_acc.c | 28 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'drivers/staging') diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.c b/drivers/staging/media/atomisp/pci/atomisp_acc.c index 9a1751895ab0..28cb271663c4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_acc.c +++ b/drivers/staging/media/atomisp/pci/atomisp_acc.c @@ -439,6 +439,18 @@ int atomisp_acc_s_mapped_arg(struct atomisp_sub_device *asd, return 0; } +static void atomisp_acc_unload_some_extensions(struct atomisp_sub_device *asd, + int i, + struct atomisp_acc_fw *acc_fw) +{ + while (--i >= 0) { + if (acc_fw->flags & acc_flag_to_pipe[i].flag) { + atomisp_css_unload_acc_extension(asd, acc_fw->fw, + acc_flag_to_pipe[i].pipe_id); + } + } +} + /* * Appends the loaded acceleration binary extensions to the * current ISP mode. Must be called just before sh_css_start(). @@ -479,16 +491,20 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) acc_fw->fw, acc_flag_to_pipe[i].pipe_id, acc_fw->type); - if (ret) + if (ret) { + atomisp_acc_unload_some_extensions(asd, i, acc_fw); goto error; + } ext_loaded = true; } } ret = atomisp_css_set_acc_parameters(acc_fw); - if (ret < 0) + if (ret < 0) { + atomisp_acc_unload_some_extensions(asd, i, acc_fw); goto error; + } } if (!ext_loaded) @@ -497,6 +513,7 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) ret = atomisp_css_update_stream(asd); if (ret) { dev_err(isp->dev, "%s: update stream failed.\n", __func__); + atomisp_acc_unload_extensions(asd); goto error; } @@ -504,13 +521,6 @@ int atomisp_acc_load_extensions(struct atomisp_sub_device *asd) return 0; error: - while (--i >= 0) { - if (acc_fw->flags & acc_flag_to_pipe[i].flag) { - atomisp_css_unload_acc_extension(asd, acc_fw->fw, - acc_flag_to_pipe[i].pipe_id); - } - } - list_for_each_entry_continue_reverse(acc_fw, &asd->acc.fw, list) { if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT && acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER) -- cgit v1.2.3