diff options
Diffstat (limited to 'drivers/media/platform')
92 files changed, 3418 insertions, 3186 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 614fbef08ddc..c7a1cf8a1b01 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -31,8 +31,6 @@ source "drivers/media/platform/davinci/Kconfig" source "drivers/media/platform/omap/Kconfig" -source "drivers/media/platform/blackfin/Kconfig" - config VIDEO_SH_VOU tristate "SuperH VOU video output driver" depends on MEDIA_CAMERA_SUPPORT @@ -54,26 +52,6 @@ config VIDEO_VIU Say Y here if you want to enable VIU device on MPC5121e Rev2+. In doubt, say N. -config VIDEO_M32R_AR - tristate "AR devices" - depends on VIDEO_V4L2 - depends on M32R || COMPILE_TEST - ---help--- - This is a video4linux driver for the Renesas AR (Artificial Retina) - camera module. - -config VIDEO_M32R_AR_M64278 - tristate "AR device with color module M64278(VGA)" - depends on PLAT_M32700UT - select VIDEO_M32R_AR - ---help--- - This is a video4linux driver for the Renesas AR (Artificial - Retina) with M64278E-800 camera module. - This module supports VGA(640x480 pixels) resolutions. - - To compile this driver as a module, choose M here: the - module will be called arv. - config VIDEO_MUX tristate "Video Multiplexer" select MULTIPLEXER @@ -144,6 +122,15 @@ config VIDEO_STM32_DCMI To compile this driver as a module, choose M here: the module will be called stm32-dcmi. +config VIDEO_RENESAS_CEU + tristate "Renesas Capture Engine Unit (CEU) driver" + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + 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 + source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/am437x/Kconfig" @@ -582,7 +569,7 @@ config CEC_GPIO config VIDEO_SAMSUNG_S5P_CEC tristate "Samsung S5P CEC driver" - depends on PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST + depends on ARCH_EXYNOS || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER ---help--- diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 7f3080437be6..932515df4477 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -3,8 +3,6 @@ # Makefile for the video capture/playback device drivers. # -obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o - obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/ obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ @@ -53,8 +51,6 @@ obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC) += tegra-cec/ obj-y += stm32/ -obj-y += blackfin/ - obj-y += davinci/ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o @@ -62,6 +58,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o obj-$(CONFIG_SOC_CAMERA) += soc_camera/ obj-$(CONFIG_VIDEO_RCAR_DRIF) += rcar_drif.o +obj-$(CONFIG_VIDEO_RENESAS_CEU) += renesas-ceu.o obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o diff --git a/drivers/media/platform/arv.c b/drivers/media/platform/arv.c deleted file mode 100644 index 1e865fea803c..000000000000 --- a/drivers/media/platform/arv.c +++ /dev/null @@ -1,884 +0,0 @@ -/* - * Colour AR M64278(VGA) driver for Video4Linux - * - * Copyright (C) 2003 Takeo Takahashi <takahashi.takeo@renesas.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Some code is taken from AR driver sample program for M3T-M32700UT. - * - * AR driver sample (M32R SDK): - * Copyright (c) 2003 RENESAS TECHNOROGY CORPORATION - * AND RENESAS SOLUTIONS CORPORATION - * All Rights Reserved. - * - * 2003-09-01: Support w3cam by Takeo Takahashi - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include <linux/videodev2.h> -#include <media/v4l2-common.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-fh.h> -#include <linux/mutex.h> - -#include <linux/uaccess.h> -#include <asm/m32r.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/byteorder.h> - -#if 0 -#define DEBUG(n, args...) printk(KERN_INFO args) -#define CHECK_LOST 1 -#else -#define DEBUG(n, args...) -#define CHECK_LOST 0 -#endif - -/* - * USE_INT is always 0, interrupt mode is not available - * on linux due to lack of speed - */ -#define USE_INT 0 /* Don't modify */ - -#define VERSION "0.0.5" - -#define ar_inl(addr) inl((unsigned long)(addr)) -#define ar_outl(val, addr) outl((unsigned long)(val), (unsigned long)(addr)) - -extern struct cpuinfo_m32r boot_cpu_data; - -/* - * CCD pixel size - * Note that M32700UT does not support CIF mode, but QVGA is - * supported by M32700UT hardware using VGA mode of AR LSI. - * - * Supported: VGA (Normal mode, Interlace mode) - * QVGA (Always Interlace mode of VGA) - * - */ -#define AR_WIDTH_VGA 640 -#define AR_HEIGHT_VGA 480 -#define AR_WIDTH_QVGA 320 -#define AR_HEIGHT_QVGA 240 -#define MIN_AR_WIDTH AR_WIDTH_QVGA -#define MIN_AR_HEIGHT AR_HEIGHT_QVGA -#define MAX_AR_WIDTH AR_WIDTH_VGA -#define MAX_AR_HEIGHT AR_HEIGHT_VGA - -/* bits & bytes per pixel */ -#define AR_BITS_PER_PIXEL 16 -#define AR_BYTES_PER_PIXEL (AR_BITS_PER_PIXEL / 8) - -/* line buffer size */ -#define AR_LINE_BYTES_VGA (AR_WIDTH_VGA * AR_BYTES_PER_PIXEL) -#define AR_LINE_BYTES_QVGA (AR_WIDTH_QVGA * AR_BYTES_PER_PIXEL) -#define MAX_AR_LINE_BYTES AR_LINE_BYTES_VGA - -/* frame size & type */ -#define AR_FRAME_BYTES_VGA \ - (AR_WIDTH_VGA * AR_HEIGHT_VGA * AR_BYTES_PER_PIXEL) -#define AR_FRAME_BYTES_QVGA \ - (AR_WIDTH_QVGA * AR_HEIGHT_QVGA * AR_BYTES_PER_PIXEL) -#define MAX_AR_FRAME_BYTES \ - (MAX_AR_WIDTH * MAX_AR_HEIGHT * AR_BYTES_PER_PIXEL) - -#define AR_MAX_FRAME 15 - -/* capture size */ -#define AR_SIZE_VGA 0 -#define AR_SIZE_QVGA 1 - -/* capture mode */ -#define AR_MODE_INTERLACE 0 -#define AR_MODE_NORMAL 1 - -struct ar { - struct v4l2_device v4l2_dev; - struct video_device vdev; - int start_capture; /* duaring capture in INT. mode. */ -#if USE_INT - unsigned char *line_buff; /* DMA line buffer */ -#endif - unsigned char *frame[MAX_AR_HEIGHT]; /* frame data */ - short size; /* capture size */ - short mode; /* capture mode */ - int width, height; - int frame_bytes, line_bytes; - wait_queue_head_t wait; - struct mutex lock; -}; - -static struct ar ardev; - -static int video_nr = -1; /* video device number (first free) */ -static unsigned char yuv[MAX_AR_FRAME_BYTES]; - -/* module parameters */ -/* default frequency */ -#define DEFAULT_FREQ 50 /* 50 or 75 (MHz) is available as BCLK */ -static int freq = DEFAULT_FREQ; /* BCLK: available 50 or 70 (MHz) */ -static int vga; /* default mode(0:QVGA mode, other:VGA mode) */ -static int vga_interlace; /* 0 is normal mode for, else interlace mode */ -module_param(freq, int, 0); -module_param(vga, int, 0); -module_param(vga_interlace, int, 0); - -static void wait_for_vsync(void) -{ - while (ar_inl(ARVCR0) & ARVCR0_VDS) /* wait for VSYNC */ - cpu_relax(); - while (!(ar_inl(ARVCR0) & ARVCR0_VDS)) /* wait for VSYNC */ - cpu_relax(); -} - -static void wait_acknowledge(void) -{ - int i; - - for (i = 0; i < 1000; i++) - cpu_relax(); - while (ar_inl(PLDI2CSTS) & PLDI2CSTS_NOACK) - cpu_relax(); -} - -/******************************************************************* - * I2C functions - *******************************************************************/ -static void iic(int n, unsigned long addr, unsigned long data1, unsigned long data2, - unsigned long data3) -{ - int i; - - /* Slave Address */ - ar_outl(addr, PLDI2CDATA); - wait_for_vsync(); - - /* Start */ - ar_outl(1, PLDI2CCND); - wait_acknowledge(); - - /* Transfer data 1 */ - ar_outl(data1, PLDI2CDATA); - wait_for_vsync(); - ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN); - wait_acknowledge(); - - /* Transfer data 2 */ - ar_outl(data2, PLDI2CDATA); - wait_for_vsync(); - ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN); - wait_acknowledge(); - - if (n == 3) { - /* Transfer data 3 */ - ar_outl(data3, PLDI2CDATA); - wait_for_vsync(); - ar_outl(PLDI2CSTEN_STEN, PLDI2CSTEN); - wait_acknowledge(); - } - - /* Stop */ - for (i = 0; i < 100; i++) - cpu_relax(); - ar_outl(2, PLDI2CCND); - ar_outl(2, PLDI2CCND); - - while (ar_inl(PLDI2CSTS) & PLDI2CSTS_BB) - cpu_relax(); -} - - -static void init_iic(void) -{ - DEBUG(1, "init_iic:\n"); - - /* - * ICU Setting (iic) - */ - /* I2C Setting */ - ar_outl(0x0, PLDI2CCR); /* I2CCR Disable */ - ar_outl(0x0300, PLDI2CMOD); /* I2CMOD ACK/8b-data/7b-addr/auto */ - ar_outl(0x1, PLDI2CACK); /* I2CACK ACK */ - - /* I2C CLK */ - /* 50MH-100k */ - if (freq == 75) - ar_outl(369, PLDI2CFREQ); /* BCLK = 75MHz */ - else if (freq == 50) - ar_outl(244, PLDI2CFREQ); /* BCLK = 50MHz */ - else - ar_outl(244, PLDI2CFREQ); /* default: BCLK = 50MHz */ - ar_outl(0x1, PLDI2CCR); /* I2CCR Enable */ -} - -/************************************************************************** - * - * Video4Linux Interface functions - * - **************************************************************************/ - -static inline void disable_dma(void) -{ - ar_outl(0x8000, M32R_DMAEN_PORTL); /* disable DMA0 */ -} - -static inline void enable_dma(void) -{ - ar_outl(0x8080, M32R_DMAEN_PORTL); /* enable DMA0 */ -} - -static inline void clear_dma_status(void) -{ - ar_outl(0x8000, M32R_DMAEDET_PORTL); /* clear status */ -} - -static void wait_for_vertical_sync(struct ar *ar, int exp_line) -{ -#if CHECK_LOST - int tmout = 10000; /* FIXME */ - int l; - - /* - * check HCOUNT because we cannot check vertical sync. - */ - for (; tmout >= 0; tmout--) { - l = ar_inl(ARVHCOUNT); - if (l == exp_line) - break; - } - if (tmout < 0) - v4l2_err(&ar->v4l2_dev, "lost %d -> %d\n", exp_line, l); -#else - while (ar_inl(ARVHCOUNT) != exp_line) - cpu_relax(); -#endif -} - -static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos) -{ - struct ar *ar = video_drvdata(file); - long ret = ar->frame_bytes; /* return read bytes */ - unsigned long arvcr1 = 0; - unsigned long flags; - unsigned char *p; - int h, w; - unsigned char *py, *pu, *pv; -#if !USE_INT - int l; -#endif - - DEBUG(1, "ar_read()\n"); - - if (ar->size == AR_SIZE_QVGA) - arvcr1 |= ARVCR1_QVGA; - if (ar->mode == AR_MODE_NORMAL) - arvcr1 |= ARVCR1_NORMAL; - - mutex_lock(&ar->lock); - -#if USE_INT - local_irq_save(flags); - disable_dma(); - ar_outl(0xa1871300, M32R_DMA0CR0_PORTL); - ar_outl(0x01000000, M32R_DMA0CR1_PORTL); - - /* set AR FIFO address as source(BSEL5) */ - ar_outl(ARDATA32, M32R_DMA0CSA_PORTL); - ar_outl(ARDATA32, M32R_DMA0RSA_PORTL); - ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); /* destination addr. */ - ar_outl(ar->line_buff, M32R_DMA0RDA_PORTL); /* reload address */ - ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL); /* byte count (bytes) */ - ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL); /* reload count (bytes) */ - - /* - * Okay, kick AR LSI to invoke an interrupt - */ - ar->start_capture = -1; - ar_outl(arvcr1 | ARVCR1_HIEN, ARVCR1); - local_irq_restore(flags); - /* .... AR interrupts .... */ - wait_event_interruptible(ar->wait, ar->start_capture == 0); - if (signal_pending(current)) { - printk(KERN_ERR "arv: interrupted while get frame data.\n"); - ret = -EINTR; - goto out_up; - } -#else /* ! USE_INT */ - /* polling */ - ar_outl(arvcr1, ARVCR1); - disable_dma(); - ar_outl(0x8000, M32R_DMAEDET_PORTL); - ar_outl(0xa0861300, M32R_DMA0CR0_PORTL); - ar_outl(0x01000000, M32R_DMA0CR1_PORTL); - ar_outl(ARDATA32, M32R_DMA0CSA_PORTL); - ar_outl(ARDATA32, M32R_DMA0RSA_PORTL); - ar_outl(ar->line_bytes, M32R_DMA0CBCUT_PORTL); - ar_outl(ar->line_bytes, M32R_DMA0RBCUT_PORTL); - - local_irq_save(flags); - while (ar_inl(ARVHCOUNT) != 0) /* wait for 0 */ - cpu_relax(); - if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) { - for (h = 0; h < ar->height; h++) { - wait_for_vertical_sync(ar, h); - if (h < (AR_HEIGHT_VGA/2)) - l = h << 1; - else - l = (((h - (AR_HEIGHT_VGA/2)) << 1) + 1); - ar_outl(virt_to_phys(ar->frame[l]), M32R_DMA0CDA_PORTL); - enable_dma(); - while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000)) - cpu_relax(); - disable_dma(); - clear_dma_status(); - ar_outl(0xa0861300, M32R_DMA0CR0_PORTL); - } - } else { - for (h = 0; h < ar->height; h++) { - wait_for_vertical_sync(ar, h); - ar_outl(virt_to_phys(ar->frame[h]), M32R_DMA0CDA_PORTL); - enable_dma(); - while (!(ar_inl(M32R_DMAEDET_PORTL) & 0x8000)) - cpu_relax(); - disable_dma(); - clear_dma_status(); - ar_outl(0xa0861300, M32R_DMA0CR0_PORTL); - } - } - local_irq_restore(flags); -#endif /* ! USE_INT */ - - /* - * convert YUV422 to YUV422P - * +--------------------+ - * | Y0,Y1,... | - * | ..............Yn | - * +--------------------+ - * | U0,U1,........Un | - * +--------------------+ - * | V0,V1,........Vn | - * +--------------------+ - */ - py = yuv; - pu = py + (ar->frame_bytes / 2); - pv = pu + (ar->frame_bytes / 4); - for (h = 0; h < ar->height; h++) { - p = ar->frame[h]; - for (w = 0; w < ar->line_bytes; w += 4) { - *py++ = *p++; - *pu++ = *p++; - *py++ = *p++; - *pv++ = *p++; - } - } - if (copy_to_user(buf, yuv, ar->frame_bytes)) { - v4l2_err(&ar->v4l2_dev, "failed while copy_to_user yuv.\n"); - ret = -EFAULT; - goto out_up; - } - DEBUG(1, "ret = %d\n", ret); -out_up: - mutex_unlock(&ar->lock); - return ret; -} - -static int ar_querycap(struct file *file, void *priv, - struct v4l2_capability *vcap) -{ - struct ar *ar = video_drvdata(file); - - strlcpy(vcap->driver, ar->vdev.name, sizeof(vcap->driver)); - strlcpy(vcap->card, "Colour AR VGA", sizeof(vcap->card)); - strlcpy(vcap->bus_info, "Platform", sizeof(vcap->bus_info)); - vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; - vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int ar_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - if (vin->index > 0) - return -EINVAL; - strlcpy(vin->name, "Camera", sizeof(vin->name)); - vin->type = V4L2_INPUT_TYPE_CAMERA; - vin->audioset = 0; - vin->tuner = 0; - vin->std = V4L2_STD_ALL; - vin->status = 0; - return 0; -} - -static int ar_g_input(struct file *file, void *fh, unsigned int *inp) -{ - *inp = 0; - return 0; -} - -static int ar_s_input(struct file *file, void *fh, unsigned int inp) -{ - return inp ? -EINVAL : 0; -} - -static int ar_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ar *ar = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - pix->width = ar->width; - pix->height = ar->height; - pix->pixelformat = V4L2_PIX_FMT_YUV422P; - pix->field = (ar->mode == AR_MODE_NORMAL) ? V4L2_FIELD_NONE : V4L2_FIELD_INTERLACED; - pix->bytesperline = ar->width; - pix->sizeimage = 2 * ar->width * ar->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int ar_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ar *ar = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - - if (pix->height <= AR_HEIGHT_QVGA || pix->width <= AR_WIDTH_QVGA) { - pix->height = AR_HEIGHT_QVGA; - pix->width = AR_WIDTH_QVGA; - pix->field = V4L2_FIELD_INTERLACED; - } else { - pix->height = AR_HEIGHT_VGA; - pix->width = AR_WIDTH_VGA; - pix->field = vga_interlace ? V4L2_FIELD_INTERLACED : V4L2_FIELD_NONE; - } - pix->pixelformat = V4L2_PIX_FMT_YUV422P; - pix->bytesperline = ar->width; - pix->sizeimage = 2 * ar->width * ar->height; - /* Just a guess */ - pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} - -static int ar_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct ar *ar = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int ret = ar_try_fmt_vid_cap(file, fh, fmt); - - if (ret) - return ret; - mutex_lock(&ar->lock); - ar->width = pix->width; - ar->height = pix->height; - if (ar->width == AR_WIDTH_VGA) { - ar->size = AR_SIZE_VGA; - ar->frame_bytes = AR_FRAME_BYTES_VGA; - ar->line_bytes = AR_LINE_BYTES_VGA; - if (vga_interlace) - ar->mode = AR_MODE_INTERLACE; - else - ar->mode = AR_MODE_NORMAL; - } else { - ar->size = AR_SIZE_QVGA; - ar->frame_bytes = AR_FRAME_BYTES_QVGA; - ar->line_bytes = AR_LINE_BYTES_QVGA; - ar->mode = AR_MODE_INTERLACE; - } - /* Ok we figured out what to use from our wide choice */ - mutex_unlock(&ar->lock); - return 0; -} - -static int ar_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) -{ - static struct v4l2_fmtdesc formats[] = { - { 0, 0, 0, - "YUV 4:2:2 Planar", V4L2_PIX_FMT_YUV422P, - { 0, 0, 0, 0 } - }, - }; - enum v4l2_buf_type type = fmt->type; - - if (fmt->index > 0) - return -EINVAL; - - *fmt = formats[fmt->index]; - fmt->type = type; - return 0; -} - -#if USE_INT -/* - * Interrupt handler - */ -static void ar_interrupt(int irq, void *dev) -{ - struct ar *ar = dev; - unsigned int line_count; - unsigned int line_number; - unsigned int arvcr1; - - line_count = ar_inl(ARVHCOUNT); /* line number */ - if (ar->mode == AR_MODE_INTERLACE && ar->size == AR_SIZE_VGA) { - /* operations for interlace mode */ - if (line_count < (AR_HEIGHT_VGA / 2)) /* even line */ - line_number = (line_count << 1); - else /* odd line */ - line_number = - (((line_count - (AR_HEIGHT_VGA / 2)) << 1) + 1); - } else { - line_number = line_count; - } - - if (line_number == 0) { - /* - * It is an interrupt for line 0. - * we have to start capture. - */ - disable_dma(); -#if 0 - ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); /* needless? */ -#endif - memcpy(ar->frame[0], ar->line_buff, ar->line_bytes); -#if 0 - ar_outl(0xa1861300, M32R_DMA0CR0_PORTL); -#endif - enable_dma(); - ar->start_capture = 1; /* during capture */ - return; - } - - if (ar->start_capture == 1 && line_number <= (ar->height - 1)) { - disable_dma(); - memcpy(ar->frame[line_number], ar->line_buff, ar->line_bytes); - - /* - * if captured all line of a frame, disable AR interrupt - * and wake a process up. - */ - if (line_number == (ar->height - 1)) { /* end of line */ - - ar->start_capture = 0; - - /* disable AR interrupt request */ - arvcr1 = ar_inl(ARVCR1); - arvcr1 &= ~ARVCR1_HIEN; /* clear int. flag */ - ar_outl(arvcr1, ARVCR1); /* disable */ - wake_up_interruptible(&ar->wait); - } else { -#if 0 - ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); - ar_outl(0xa1861300, M32R_DMA0CR0_PORTL); -#endif - enable_dma(); - } - } -} -#endif - -/* - * ar_initialize() - * ar_initialize() is called by video_register_device() and - * initializes AR LSI and peripherals. - * - * -1 is returned in all failures. - * 0 is returned in success. - * - */ -static int ar_initialize(struct ar *ar) -{ - unsigned long cr = 0; - int i, found = 0; - - DEBUG(1, "ar_initialize:\n"); - - /* - * initialize AR LSI - */ - ar_outl(0, ARVCR0); /* assert reset of AR LSI */ - for (i = 0; i < 0x18; i++) /* wait for over 10 cycles @ 27MHz */ - cpu_relax(); - ar_outl(ARVCR0_RST, ARVCR0); /* negate reset of AR LSI (enable) */ - for (i = 0; i < 0x40d; i++) /* wait for over 420 cycles @ 27MHz */ - cpu_relax(); - - /* AR uses INT3 of CPU as interrupt pin. */ - ar_outl(ARINTSEL_INT3, ARINTSEL); - - if (ar->size == AR_SIZE_QVGA) - cr |= ARVCR1_QVGA; - if (ar->mode == AR_MODE_NORMAL) - cr |= ARVCR1_NORMAL; - ar_outl(cr, ARVCR1); - - /* - * Initialize IIC so that CPU can communicate with AR LSI, - * and send boot commands to AR LSI. - */ - init_iic(); - - for (i = 0; i < 0x100000; i++) { /* > 0xa1d10, 56ms */ - if ((ar_inl(ARVCR0) & ARVCR0_VDS)) { /* VSYNC */ - found = 1; - break; - } - } - - if (found == 0) - return -ENODEV; - - v4l2_info(&ar->v4l2_dev, "Initializing "); - - iic(2, 0x78, 0x11, 0x01, 0x00); /* start */ - iic(3, 0x78, 0x12, 0x00, 0x06); - iic(3, 0x78, 0x12, 0x12, 0x30); - iic(3, 0x78, 0x12, 0x15, 0x58); - iic(3, 0x78, 0x12, 0x17, 0x30); - printk(KERN_CONT "."); - iic(3, 0x78, 0x12, 0x1a, 0x97); - iic(3, 0x78, 0x12, 0x1b, 0xff); - iic(3, 0x78, 0x12, 0x1c, 0xff); - iic(3, 0x78, 0x12, 0x26, 0x10); - iic(3, 0x78, 0x12, 0x27, 0x00); - printk(KERN_CONT "."); - iic(2, 0x78, 0x34, 0x02, 0x00); - iic(2, 0x78, 0x7a, 0x10, 0x00); - iic(2, 0x78, 0x80, 0x39, 0x00); - iic(2, 0x78, 0x81, 0xe6, 0x00); - iic(2, 0x78, 0x8d, 0x00, 0x00); - printk(KERN_CONT "."); - iic(2, 0x78, 0x8e, 0x0c, 0x00); - iic(2, 0x78, 0x8f, 0x00, 0x00); -#if 0 - iic(2, 0x78, 0x90, 0x00, 0x00); /* AWB on=1 off=0 */ -#endif - iic(2, 0x78, 0x93, 0x01, 0x00); - iic(2, 0x78, 0x94, 0xcd, 0x00); - iic(2, 0x78, 0x95, 0x00, 0x00); - printk(KERN_CONT "."); - iic(2, 0x78, 0x96, 0xa0, 0x00); - iic(2, 0x78, 0x97, 0x00, 0x00); - iic(2, 0x78, 0x98, 0x60, 0x00); - iic(2, 0x78, 0x99, 0x01, 0x00); - iic(2, 0x78, 0x9a, 0x19, 0x00); - printk(KERN_CONT "."); - iic(2, 0x78, 0x9b, 0x02, 0x00); - iic(2, 0x78, 0x9c, 0xe8, 0x00); - iic(2, 0x78, 0x9d, 0x02, 0x00); - iic(2, 0x78, 0x9e, 0x2e, 0x00); - iic(2, 0x78, 0xb8, 0x78, 0x00); - iic(2, 0x78, 0xba, 0x05, 0x00); -#if 0 - iic(2, 0x78, 0x83, 0x8c, 0x00); /* brightness */ -#endif - printk(KERN_CONT "."); - - /* color correction */ - iic(3, 0x78, 0x49, 0x00, 0x95); /* a */ - iic(3, 0x78, 0x49, 0x01, 0x96); /* b */ - iic(3, 0x78, 0x49, 0x03, 0x85); /* c */ - iic(3, 0x78, 0x49, 0x04, 0x97); /* d */ - iic(3, 0x78, 0x49, 0x02, 0x7e); /* e(Lo) */ - iic(3, 0x78, 0x49, 0x05, 0xa4); /* f(Lo) */ - iic(3, 0x78, 0x49, 0x06, 0x04); /* e(Hi) */ - iic(3, 0x78, 0x49, 0x07, 0x04); /* e(Hi) */ - iic(2, 0x78, 0x48, 0x01, 0x00); /* on=1 off=0 */ - - printk(KERN_CONT "."); - iic(2, 0x78, 0x11, 0x00, 0x00); /* end */ - printk(KERN_CONT " done\n"); - return 0; -} - - -/**************************************************************************** - * - * Video4Linux Module functions - * - ****************************************************************************/ - -static const struct v4l2_file_operations ar_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = v4l2_fh_release, - .read = ar_read, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops ar_ioctl_ops = { - .vidioc_querycap = ar_querycap, - .vidioc_g_input = ar_g_input, - .vidioc_s_input = ar_s_input, - .vidioc_enum_input = ar_enum_input, - .vidioc_enum_fmt_vid_cap = ar_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = ar_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = ar_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = ar_try_fmt_vid_cap, -}; - -#define ALIGN4(x) ((((int)(x)) & 0x3) == 0) - -static int __init ar_init(void) -{ - struct ar *ar; - struct v4l2_device *v4l2_dev; - int ret; - int i; - - ar = &ardev; - v4l2_dev = &ar->v4l2_dev; - strlcpy(v4l2_dev->name, "arv", sizeof(v4l2_dev->name)); - v4l2_info(v4l2_dev, "Colour AR VGA driver %s\n", VERSION); - - ret = v4l2_device_register(NULL, v4l2_dev); - if (ret < 0) { - v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); - return ret; - } - ret = -EIO; - -#if USE_INT - /* allocate a DMA buffer for 1 line. */ - ar->line_buff = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL | GFP_DMA); - if (ar->line_buff == NULL || !ALIGN4(ar->line_buff)) { - v4l2_err(v4l2_dev, "buffer allocation failed for DMA.\n"); - ret = -ENOMEM; - goto out_end; - } -#endif - /* allocate buffers for a frame */ - for (i = 0; i < MAX_AR_HEIGHT; i++) { - ar->frame[i] = kmalloc(MAX_AR_LINE_BYTES, GFP_KERNEL); - if (ar->frame[i] == NULL || !ALIGN4(ar->frame[i])) { - v4l2_err(v4l2_dev, "buffer allocation failed for frame.\n"); - ret = -ENOMEM; - goto out_line_buff; - } - } - - strlcpy(ar->vdev.name, "Colour AR VGA", sizeof(ar->vdev.name)); - ar->vdev.v4l2_dev = v4l2_dev; - ar->vdev.fops = &ar_fops; - ar->vdev.ioctl_ops = &ar_ioctl_ops; - ar->vdev.release = video_device_release_empty; - video_set_drvdata(&ar->vdev, ar); - - if (vga) { - ar->width = AR_WIDTH_VGA; - ar->height = AR_HEIGHT_VGA; - ar->size = AR_SIZE_VGA; - ar->frame_bytes = AR_FRAME_BYTES_VGA; - ar->line_bytes = AR_LINE_BYTES_VGA; - if (vga_interlace) - ar->mode = AR_MODE_INTERLACE; - else - ar->mode = AR_MODE_NORMAL; - } else { - ar->width = AR_WIDTH_QVGA; - ar->height = AR_HEIGHT_QVGA; - ar->size = AR_SIZE_QVGA; - ar->frame_bytes = AR_FRAME_BYTES_QVGA; - ar->line_bytes = AR_LINE_BYTES_QVGA; - ar->mode = AR_MODE_INTERLACE; - } - mutex_init(&ar->lock); - init_waitqueue_head(&ar->wait); - -#if USE_INT - if (request_irq(M32R_IRQ_INT3, ar_interrupt, 0, "arv", ar)) { - v4l2_err("request_irq(%d) failed.\n", M32R_IRQ_INT3); - ret = -EIO; - goto out_irq; - } -#endif - - if (ar_initialize(ar) != 0) { - v4l2_err(v4l2_dev, "M64278 not found.\n"); - ret = -ENODEV; - goto out_dev; - } - - /* - * ok, we can initialize h/w according to parameters, - * so register video device as a frame grabber type. - * device is named "video[0-64]". - * video_register_device() initializes h/w using ar_initialize(). - */ - if (video_register_device(&ar->vdev, VFL_TYPE_GRABBER, video_nr) != 0) { - /* return -1, -ENFILE(full) or others */ - v4l2_err(v4l2_dev, "register video (Colour AR) failed.\n"); - ret = -ENODEV; - goto out_dev; - } - - v4l2_info(v4l2_dev, "%s: Found M64278 VGA (IRQ %d, Freq %dMHz).\n", - video_device_node_name(&ar->vdev), M32R_IRQ_INT3, freq); - - return 0; - -out_dev: -#if USE_INT - free_irq(M32R_IRQ_INT3, ar); - -out_irq: -#endif - for (i = 0; i < MAX_AR_HEIGHT; i++) - kfree(ar->frame[i]); - -out_line_buff: -#if USE_INT - kfree(ar->line_buff); - -out_end: -#endif - v4l2_device_unregister(&ar->v4l2_dev); - return ret; -} - - -static int __init ar_init_module(void) -{ - freq = (boot_cpu_data.bus_clock / 1000000); - printk(KERN_INFO "arv: Bus clock %d\n", freq); - if (freq != 50 && freq != 75) - freq = DEFAULT_FREQ; - return ar_init(); -} - -static void __exit ar_cleanup_module(void) -{ - struct ar *ar; - int i; - - ar = &ardev; - video_unregister_device(&ar->vdev); -#if USE_INT - free_irq(M32R_IRQ_INT3, ar); -#endif - for (i = 0; i < MAX_AR_HEIGHT; i++) - kfree(ar->frame[i]); -#if USE_INT - kfree(ar->line_buff); -#endif - v4l2_device_unregister(&ar->v4l2_dev); -} - -module_init(ar_init_module); -module_exit(ar_cleanup_module); - -MODULE_AUTHOR("Takeo Takahashi <takahashi.takeo@renesas.com>"); -MODULE_DESCRIPTION("Colour AR M64278(VGA) for Video4Linux"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(VERSION); diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 34676409ca08..d89e14524d42 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -335,7 +335,7 @@ static struct isc_format formats_list[] = { }, }; -struct fmt_config fmt_configs_list[] = { +static struct fmt_config fmt_configs_list[] = { { .fourcc = V4L2_PIX_FMT_SBGGR8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, @@ -1417,20 +1417,14 @@ static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct isc_device *isc = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return v4l2_subdev_call(isc->current_subdev->sd, video, g_parm, a); + return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a); } static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct isc_device *isc = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - return v4l2_subdev_call(isc->current_subdev->sd, video, s_parm, a); + return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a); } static int isc_enum_framesizes(struct file *file, void *fh, diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 9958918e2449..e5be21a31640 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -689,22 +689,14 @@ static int isi_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct atmel_isi *isi = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - a->parm.capture.readbuffers = 2; - return v4l2_subdev_call(isi->entity.subdev, video, g_parm, a); + return v4l2_g_parm_cap(video_devdata(file), isi->entity.subdev, a); } static int isi_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) { struct atmel_isi *isi = video_drvdata(file); - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - a->parm.capture.readbuffers = 2; - return v4l2_subdev_call(isi->entity.subdev, video, s_parm, a); + return v4l2_s_parm_cap(video_devdata(file), isi->entity.subdev, a); } static int isi_enum_framesizes(struct file *file, void *fh, diff --git a/drivers/media/platform/blackfin/Kconfig b/drivers/media/platform/blackfin/Kconfig deleted file mode 100644 index 68fa90151b8f..000000000000 --- a/drivers/media/platform/blackfin/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config VIDEO_BLACKFIN_CAPTURE - tristate "Blackfin Video Capture Driver" - depends on VIDEO_V4L2 && BLACKFIN && I2C - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - help - V4L2 bridge driver for Blackfin video capture device. - Choose PPI or EPPI as its interface. - - To compile this driver as a module, choose M here: the - module will be called bfin_capture. - -config VIDEO_BLACKFIN_PPI - tristate - depends on VIDEO_BLACKFIN_CAPTURE - default VIDEO_BLACKFIN_CAPTURE diff --git a/drivers/media/platform/blackfin/Makefile b/drivers/media/platform/blackfin/Makefile deleted file mode 100644 index 30421bc23080..000000000000 --- a/drivers/media/platform/blackfin/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_VIDEO_BLACKFIN_CAPTURE) += bfin_capture.o -obj-$(CONFIG_VIDEO_BLACKFIN_PPI) += ppi.o diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c deleted file mode 100644 index 41f179117fb0..000000000000 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ /dev/null @@ -1,989 +0,0 @@ -/* - * Analog Devices video capture driver - * - * Copyright (c) 2011 Analog Devices Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/i2c.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/time.h> -#include <linux/types.h> - -#include <media/v4l2-common.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-device.h> -#include <media/v4l2-ioctl.h> -#include <media/videobuf2-dma-contig.h> - -#include <asm/dma.h> - -#include <media/blackfin/bfin_capture.h> -#include <media/blackfin/ppi.h> - -#define CAPTURE_DRV_NAME "bfin_capture" - -struct bcap_format { - char *desc; - u32 pixelformat; - u32 mbus_code; - int bpp; /* bits per pixel */ - int dlen; /* data length for ppi in bits */ -}; - -struct bcap_buffer { - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -struct bcap_device { - /* capture device instance */ - struct v4l2_device v4l2_dev; - /* v4l2 control handler */ - struct v4l2_ctrl_handler ctrl_handler; - /* device node data */ - struct video_device video_dev; - /* sub device instance */ - struct v4l2_subdev *sd; - /* capture config */ - struct bfin_capture_config *cfg; - /* ppi interface */ - struct ppi_if *ppi; - /* current input */ - unsigned int cur_input; - /* current selected standard */ - v4l2_std_id std; - /* current selected dv_timings */ - struct v4l2_dv_timings dv_timings; - /* used to store pixel format */ - struct v4l2_pix_format fmt; - /* bits per pixel*/ - int bpp; - /* data length for ppi in bits */ - int dlen; - /* used to store sensor supported format */ - struct bcap_format *sensor_formats; - /* number of sensor formats array */ - int num_sensor_formats; - /* pointing to current video buffer */ - struct bcap_buffer *cur_frm; - /* buffer queue used in videobuf2 */ - struct vb2_queue buffer_queue; - /* queue of filled frames */ - struct list_head dma_queue; - /* used in videobuf2 callback */ - spinlock_t lock; - /* used to access capture device */ - struct mutex mutex; - /* used to wait ppi to complete one transfer */ - struct completion comp; - /* prepare to stop */ - bool stop; - /* vb2 buffer sequence counter */ - unsigned sequence; -}; - -static const struct bcap_format bcap_formats[] = { - { - .desc = "YCbCr 4:2:2 Interleaved UYVY", - .pixelformat = V4L2_PIX_FMT_UYVY, - .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, - .bpp = 16, - .dlen = 8, - }, - { - .desc = "YCbCr 4:2:2 Interleaved YUYV", - .pixelformat = V4L2_PIX_FMT_YUYV, - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .bpp = 16, - .dlen = 8, - }, - { - .desc = "YCbCr 4:2:2 Interleaved UYVY", - .pixelformat = V4L2_PIX_FMT_UYVY, - .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16, - .bpp = 16, - .dlen = 16, - }, - { - .desc = "RGB 565", - .pixelformat = V4L2_PIX_FMT_RGB565, - .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .bpp = 16, - .dlen = 8, - }, - { - .desc = "RGB 444", - .pixelformat = V4L2_PIX_FMT_RGB444, - .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, - .bpp = 16, - .dlen = 8, - }, - -}; -#define BCAP_MAX_FMTS ARRAY_SIZE(bcap_formats) - -static irqreturn_t bcap_isr(int irq, void *dev_id); - -static struct bcap_buffer *to_bcap_vb(struct vb2_v4l2_buffer *vb) -{ - return container_of(vb, struct bcap_buffer, vb); -} - -static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) -{ - struct v4l2_subdev_mbus_code_enum code = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct bcap_format *sf; - unsigned int num_formats = 0; - int i, j; - - while (!v4l2_subdev_call(bcap_dev->sd, pad, - enum_mbus_code, NULL, &code)) { - num_formats++; - code.index++; - } - if (!num_formats) - return -ENXIO; - - sf = kcalloc(num_formats, sizeof(*sf), GFP_KERNEL); - if (!sf) - return -ENOMEM; - - for (i = 0; i < num_formats; i++) { - code.index = i; - v4l2_subdev_call(bcap_dev->sd, pad, - enum_mbus_code, NULL, &code); - for (j = 0; j < BCAP_MAX_FMTS; j++) - if (code.code == bcap_formats[j].mbus_code) - break; - if (j == BCAP_MAX_FMTS) { - /* we don't allow this sensor working with our bridge */ - kfree(sf); - return -EINVAL; - } - sf[i] = bcap_formats[j]; - } - bcap_dev->sensor_formats = sf; - bcap_dev->num_sensor_formats = num_formats; - return 0; -} - -static void bcap_free_sensor_formats(struct bcap_device *bcap_dev) -{ - bcap_dev->num_sensor_formats = 0; - kfree(bcap_dev->sensor_formats); - bcap_dev->sensor_formats = NULL; -} - -static int bcap_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); - - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2; - - if (*nplanes) - return sizes[0] < bcap_dev->fmt.sizeimage ? -EINVAL : 0; - - *nplanes = 1; - sizes[0] = bcap_dev->fmt.sizeimage; - - return 0; -} - -static int bcap_buffer_prepare(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = bcap_dev->fmt.sizeimage; - - if (vb2_plane_size(vb, 0) < size) { - v4l2_err(&bcap_dev->v4l2_dev, "buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, 0, size); - - vbuf->field = bcap_dev->fmt.field; - - return 0; -} - -static void bcap_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); - struct bcap_buffer *buf = to_bcap_vb(vbuf); - unsigned long flags; - - spin_lock_irqsave(&bcap_dev->lock, flags); - list_add_tail(&buf->list, &bcap_dev->dma_queue); - spin_unlock_irqrestore(&bcap_dev->lock, flags); -} - -static void bcap_buffer_cleanup(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct bcap_device *bcap_dev = vb2_get_drv_priv(vb->vb2_queue); - struct bcap_buffer *buf = to_bcap_vb(vbuf); - unsigned long flags; - - spin_lock_irqsave(&bcap_dev->lock, flags); - list_del_init(&buf->list); - spin_unlock_irqrestore(&bcap_dev->lock, flags); -} - -static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); - struct ppi_if *ppi = bcap_dev->ppi; - struct bcap_buffer *buf, *tmp; - struct ppi_params params; - dma_addr_t addr; - int ret; - - /* enable streamon on the sub device */ - ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 1); - if (ret && (ret != -ENOIOCTLCMD)) { - v4l2_err(&bcap_dev->v4l2_dev, "stream on failed in subdev\n"); - goto err; - } - - /* set ppi params */ - params.width = bcap_dev->fmt.width; - params.height = bcap_dev->fmt.height; - params.bpp = bcap_dev->bpp; - params.dlen = bcap_dev->dlen; - params.ppi_control = bcap_dev->cfg->ppi_control; - params.int_mask = bcap_dev->cfg->int_mask; - if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities - & V4L2_IN_CAP_DV_TIMINGS) { - struct v4l2_bt_timings *bt = &bcap_dev->dv_timings.bt; - - params.hdelay = bt->hsync + bt->hbackporch; - params.vdelay = bt->vsync + bt->vbackporch; - params.line = V4L2_DV_BT_FRAME_WIDTH(bt); - params.frame = V4L2_DV_BT_FRAME_HEIGHT(bt); - } else if (bcap_dev->cfg->inputs[bcap_dev->cur_input].capabilities - & V4L2_IN_CAP_STD) { - params.hdelay = 0; - params.vdelay = 0; - if (bcap_dev->std & V4L2_STD_525_60) { - params.line = 858; - params.frame = 525; - } else { - params.line = 864; - params.frame = 625; - } - } else { - params.hdelay = 0; - params.vdelay = 0; - params.line = params.width + bcap_dev->cfg->blank_pixels; - params.frame = params.height; - } - ret = ppi->ops->set_params(ppi, ¶ms); - if (ret < 0) { - v4l2_err(&bcap_dev->v4l2_dev, - "Error in setting ppi params\n"); - goto err; - } - - /* attach ppi DMA irq handler */ - ret = ppi->ops->attach_irq(ppi, bcap_isr); - if (ret < 0) { - v4l2_err(&bcap_dev->v4l2_dev, - "Error in attaching interrupt handler\n"); - goto err; - } - - bcap_dev->sequence = 0; - - reinit_completion(&bcap_dev->comp); - bcap_dev->stop = false; - - /* get the next frame from the dma queue */ - bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, - struct bcap_buffer, list); - /* remove buffer from the dma queue */ - list_del_init(&bcap_dev->cur_frm->list); - addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb.vb2_buf, - 0); - /* update DMA address */ - ppi->ops->update_addr(ppi, (unsigned long)addr); - /* enable ppi */ - ppi->ops->start(ppi); - - return 0; - -err: - list_for_each_entry_safe(buf, tmp, &bcap_dev->dma_queue, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); - } - - return ret; -} - -static void bcap_stop_streaming(struct vb2_queue *vq) -{ - struct bcap_device *bcap_dev = vb2_get_drv_priv(vq); - struct ppi_if *ppi = bcap_dev->ppi; - int ret; - - bcap_dev->stop = true; - wait_for_completion(&bcap_dev->comp); - ppi->ops->stop(ppi); - ppi->ops->detach_irq(ppi); - ret = v4l2_subdev_call(bcap_dev->sd, video, s_stream, 0); - if (ret && (ret != -ENOIOCTLCMD)) - v4l2_err(&bcap_dev->v4l2_dev, - "stream off failed in subdev\n"); - - /* release all active buffers */ - if (bcap_dev->cur_frm) - vb2_buffer_done(&bcap_dev->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - - while (!list_empty(&bcap_dev->dma_queue)) { - bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, - struct bcap_buffer, list); - list_del_init(&bcap_dev->cur_frm->list); - vb2_buffer_done(&bcap_dev->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - } -} - -static const struct vb2_ops bcap_video_qops = { - .queue_setup = bcap_queue_setup, - .buf_prepare = bcap_buffer_prepare, - .buf_cleanup = bcap_buffer_cleanup, - .buf_queue = bcap_buffer_queue, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .start_streaming = bcap_start_streaming, - .stop_streaming = bcap_stop_streaming, -}; - -static irqreturn_t bcap_isr(int irq, void *dev_id) -{ - struct ppi_if *ppi = dev_id; - struct bcap_device *bcap_dev = ppi->priv; - struct vb2_v4l2_buffer *vbuf = &bcap_dev->cur_frm->vb; - struct vb2_buffer *vb = &vbuf->vb2_buf; - dma_addr_t addr; - - spin_lock(&bcap_dev->lock); - - if (!list_empty(&bcap_dev->dma_queue)) { - vb->timestamp = ktime_get_ns(); - if (ppi->err) { - vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); - ppi->err = false; - } else { - vbuf->sequence = bcap_dev->sequence++; - vb2_buffer_done(vb, VB2_BUF_STATE_DONE); - } - bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next, - struct bcap_buffer, list); - list_del_init(&bcap_dev->cur_frm->list); - } else { - /* clear error flag, we will get a new frame */ - if (ppi->err) - ppi->err = false; - } - - ppi->ops->stop(ppi); - - if (bcap_dev->stop) { - complete(&bcap_dev->comp); - } else { - addr = vb2_dma_contig_plane_dma_addr( - &bcap_dev->cur_frm->vb.vb2_buf, 0); - ppi->ops->update_addr(ppi, (unsigned long)addr); - ppi->ops->start(ppi); - } - - spin_unlock(&bcap_dev->lock); - - return IRQ_HANDLED; -} - -static int bcap_querystd(struct file *file, void *priv, v4l2_std_id *std) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_input input; - - input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; - if (!(input.capabilities & V4L2_IN_CAP_STD)) - return -ENODATA; - - return v4l2_subdev_call(bcap_dev->sd, video, querystd, std); -} - -static int bcap_g_std(struct file *file, void *priv, v4l2_std_id *std) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_input input; - - input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; - if (!(input.capabilities & V4L2_IN_CAP_STD)) - return -ENODATA; - - *std = bcap_dev->std; - return 0; -} - -static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_input input; - int ret; - - input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; - if (!(input.capabilities & V4L2_IN_CAP_STD)) - return -ENODATA; - - if (vb2_is_busy(&bcap_dev->buffer_queue)) - return -EBUSY; - - ret = v4l2_subdev_call(bcap_dev->sd, video, s_std, std); - if (ret < 0) - return ret; - - bcap_dev->std = std; - return 0; -} - -static int bcap_enum_dv_timings(struct file *file, void *priv, - struct v4l2_enum_dv_timings *timings) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_input input; - - input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; - if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) - return -ENODATA; - - timings->pad = 0; - - return v4l2_subdev_call(bcap_dev->sd, pad, - enum_dv_timings, timings); -} - -static int bcap_query_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_input input; - - input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; - if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) - return -ENODATA; - - return v4l2_subdev_call(bcap_dev->sd, video, - query_dv_timings, timings); -} - -static int bcap_g_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_input input; - - input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; - if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) - return -ENODATA; - - *timings = bcap_dev->dv_timings; - return 0; -} - -static int bcap_s_dv_timings(struct file *file, void *priv, - struct v4l2_dv_timings *timings) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_input input; - int ret; - - input = bcap_dev->cfg->inputs[bcap_dev->cur_input]; - if (!(input.capabilities & V4L2_IN_CAP_DV_TIMINGS)) - return -ENODATA; - - if (vb2_is_busy(&bcap_dev->buffer_queue)) - return -EBUSY; - - ret = v4l2_subdev_call(bcap_dev->sd, video, s_dv_timings, timings); - if (ret < 0) - return ret; - - bcap_dev->dv_timings = *timings; - return 0; -} - -static int bcap_enum_input(struct file *file, void *priv, - struct v4l2_input *input) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct bfin_capture_config *config = bcap_dev->cfg; - int ret; - u32 status; - - if (input->index >= config->num_inputs) - return -EINVAL; - - *input = config->inputs[input->index]; - /* get input status */ - ret = v4l2_subdev_call(bcap_dev->sd, video, g_input_status, &status); - if (!ret) - input->status = status; - return 0; -} - -static int bcap_g_input(struct file *file, void *priv, unsigned int *index) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - - *index = bcap_dev->cur_input; - return 0; -} - -static int bcap_s_input(struct file *file, void *priv, unsigned int index) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct bfin_capture_config *config = bcap_dev->cfg; - struct bcap_route *route; - int ret; - - if (vb2_is_busy(&bcap_dev->buffer_queue)) - return -EBUSY; - - if (index >= config->num_inputs) - return -EINVAL; - - route = &config->routes[index]; - ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing, - route->input, route->output, 0); - if ((ret < 0) && (ret != -ENOIOCTLCMD)) { - v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n"); - return ret; - } - bcap_dev->cur_input = index; - /* if this route has specific config, update ppi control */ - if (route->ppi_control) - config->ppi_control = route->ppi_control; - return 0; -} - -static int bcap_try_format(struct bcap_device *bcap, - struct v4l2_pix_format *pixfmt, - struct bcap_format *bcap_fmt) -{ - struct bcap_format *sf = bcap->sensor_formats; - struct bcap_format *fmt = NULL; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_TRY, - }; - int ret, i; - - for (i = 0; i < bcap->num_sensor_formats; i++) { - fmt = &sf[i]; - if (pixfmt->pixelformat == fmt->pixelformat) - break; - } - if (i == bcap->num_sensor_formats) - fmt = &sf[0]; - - v4l2_fill_mbus_format(&format.format, pixfmt, fmt->mbus_code); - ret = v4l2_subdev_call(bcap->sd, pad, set_fmt, &pad_cfg, - &format); - if (ret < 0) - return ret; - v4l2_fill_pix_format(pixfmt, &format.format); - if (bcap_fmt) { - for (i = 0; i < bcap->num_sensor_formats; i++) { - fmt = &sf[i]; - if (format.format.code == fmt->mbus_code) - break; - } - *bcap_fmt = *fmt; - } - pixfmt->bytesperline = pixfmt->width * fmt->bpp / 8; - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - return 0; -} - -static int bcap_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmt) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct bcap_format *sf = bcap_dev->sensor_formats; - - if (fmt->index >= bcap_dev->num_sensor_formats) - return -EINVAL; - - fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strlcpy(fmt->description, - sf[fmt->index].desc, - sizeof(fmt->description)); - fmt->pixelformat = sf[fmt->index].pixelformat; - return 0; -} - -static int bcap_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - return bcap_try_format(bcap_dev, pixfmt, NULL); -} - -static int bcap_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - - fmt->fmt.pix = bcap_dev->fmt; - return 0; -} - -static int bcap_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct bcap_format bcap_fmt; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - int ret; - - if (vb2_is_busy(&bcap_dev->buffer_queue)) - return -EBUSY; - - /* see if format works */ - ret = bcap_try_format(bcap_dev, pixfmt, &bcap_fmt); - if (ret < 0) - return ret; - - v4l2_fill_mbus_format(&format.format, pixfmt, bcap_fmt.mbus_code); - ret = v4l2_subdev_call(bcap_dev->sd, pad, set_fmt, NULL, &format); - if (ret < 0) - return ret; - bcap_dev->fmt = *pixfmt; - bcap_dev->bpp = bcap_fmt.bpp; - bcap_dev->dlen = bcap_fmt.dlen; - return 0; -} - -static int bcap_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); - strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info)); - strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card)); - return 0; -} - -static int bcap_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return v4l2_subdev_call(bcap_dev->sd, video, g_parm, a); -} - -static int bcap_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *a) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - - if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - return v4l2_subdev_call(bcap_dev->sd, video, s_parm, a); -} - -static int bcap_log_status(struct file *file, void *priv) -{ - struct bcap_device *bcap_dev = video_drvdata(file); - /* status for sub devices */ - v4l2_device_call_all(&bcap_dev->v4l2_dev, 0, core, log_status); - return 0; -} - -static const struct v4l2_ioctl_ops bcap_ioctl_ops = { - .vidioc_querycap = bcap_querycap, - .vidioc_g_fmt_vid_cap = bcap_g_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = bcap_enum_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = bcap_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = bcap_try_fmt_vid_cap, - .vidioc_enum_input = bcap_enum_input, - .vidioc_g_input = bcap_g_input, - .vidioc_s_input = bcap_s_input, - .vidioc_querystd = bcap_querystd, - .vidioc_s_std = bcap_s_std, - .vidioc_g_std = bcap_g_std, - .vidioc_s_dv_timings = bcap_s_dv_timings, - .vidioc_g_dv_timings = bcap_g_dv_timings, - .vidioc_query_dv_timings = bcap_query_dv_timings, - .vidioc_enum_dv_timings = bcap_enum_dv_timings, - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_g_parm = bcap_g_parm, - .vidioc_s_parm = bcap_s_parm, - .vidioc_log_status = bcap_log_status, -}; - -static const struct v4l2_file_operations bcap_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .unlocked_ioctl = video_ioctl2, - .mmap = vb2_fop_mmap, -#ifndef CONFIG_MMU - .get_unmapped_area = vb2_fop_get_unmapped_area, -#endif - .poll = vb2_fop_poll -}; - -static int bcap_probe(struct platform_device *pdev) -{ - struct bcap_device *bcap_dev; - struct video_device *vfd; - struct i2c_adapter *i2c_adap; - struct bfin_capture_config *config; - struct vb2_queue *q; - struct bcap_route *route; - int ret; - - config = pdev->dev.platform_data; - if (!config || !config->num_inputs) { - v4l2_err(pdev->dev.driver, "Unable to get board config\n"); - return -ENODEV; - } - - bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL); - if (!bcap_dev) - return -ENOMEM; - - bcap_dev->cfg = config; - - bcap_dev->ppi = ppi_create_instance(pdev, config->ppi_info); - if (!bcap_dev->ppi) { - v4l2_err(pdev->dev.driver, "Unable to create ppi\n"); - ret = -ENODEV; - goto err_free_dev; - } - bcap_dev->ppi->priv = bcap_dev; - - vfd = &bcap_dev->video_dev; - /* initialize field of video device */ - vfd->release = video_device_release_empty; - vfd->fops = &bcap_fops; - vfd->ioctl_ops = &bcap_ioctl_ops; - vfd->tvnorms = 0; - vfd->v4l2_dev = &bcap_dev->v4l2_dev; - strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name)); - - ret = v4l2_device_register(&pdev->dev, &bcap_dev->v4l2_dev); - if (ret) { - v4l2_err(pdev->dev.driver, - "Unable to register v4l2 device\n"); - goto err_free_ppi; - } - v4l2_info(&bcap_dev->v4l2_dev, "v4l2 device registered\n"); - - bcap_dev->v4l2_dev.ctrl_handler = &bcap_dev->ctrl_handler; - ret = v4l2_ctrl_handler_init(&bcap_dev->ctrl_handler, 0); - if (ret) { - v4l2_err(&bcap_dev->v4l2_dev, - "Unable to init control handler\n"); - goto err_unreg_v4l2; - } - - spin_lock_init(&bcap_dev->lock); - /* initialize queue */ - q = &bcap_dev->buffer_queue; - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF; - q->drv_priv = bcap_dev; - q->buf_struct_size = sizeof(struct bcap_buffer); - q->ops = &bcap_video_qops; - q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &bcap_dev->mutex; - q->min_buffers_needed = 1; - q->dev = &pdev->dev; - - ret = vb2_queue_init(q); - if (ret) - goto err_free_handler; - - mutex_init(&bcap_dev->mutex); - init_completion(&bcap_dev->comp); - - /* init video dma queues */ - INIT_LIST_HEAD(&bcap_dev->dma_queue); - - vfd->lock = &bcap_dev->mutex; - vfd->queue = q; - - /* register video device */ - ret = video_register_device(&bcap_dev->video_dev, VFL_TYPE_GRABBER, -1); - if (ret) { - v4l2_err(&bcap_dev->v4l2_dev, - "Unable to register video device\n"); - goto err_free_handler; - } - video_set_drvdata(&bcap_dev->video_dev, bcap_dev); - v4l2_info(&bcap_dev->v4l2_dev, "video device registered as: %s\n", - video_device_node_name(vfd)); - - /* load up the subdevice */ - i2c_adap = i2c_get_adapter(config->i2c_adapter_id); - if (!i2c_adap) { - v4l2_err(&bcap_dev->v4l2_dev, - "Unable to find i2c adapter\n"); - ret = -ENODEV; - goto err_unreg_vdev; - - } - bcap_dev->sd = v4l2_i2c_new_subdev_board(&bcap_dev->v4l2_dev, - i2c_adap, - &config->board_info, - NULL); - if (bcap_dev->sd) { - int i; - - /* update tvnorms from the sub devices */ - for (i = 0; i < config->num_inputs; i++) - vfd->tvnorms |= config->inputs[i].std; - } else { - v4l2_err(&bcap_dev->v4l2_dev, - "Unable to register sub device\n"); - ret = -ENODEV; - goto err_unreg_vdev; - } - - v4l2_info(&bcap_dev->v4l2_dev, "v4l2 sub device registered\n"); - - /* - * explicitly set input, otherwise some boards - * may not work at the state as we expected - */ - route = &config->routes[0]; - ret = v4l2_subdev_call(bcap_dev->sd, video, s_routing, - route->input, route->output, 0); - if ((ret < 0) && (ret != -ENOIOCTLCMD)) { - v4l2_err(&bcap_dev->v4l2_dev, "Failed to set input\n"); - goto err_unreg_vdev; - } - bcap_dev->cur_input = 0; - /* if this route has specific config, update ppi control */ - if (route->ppi_control) - config->ppi_control = route->ppi_control; - - /* now we can probe the default state */ - if (config->inputs[0].capabilities & V4L2_IN_CAP_STD) { - v4l2_std_id std; - ret = v4l2_subdev_call(bcap_dev->sd, video, g_std, &std); - if (ret) { - v4l2_err(&bcap_dev->v4l2_dev, - "Unable to get std\n"); - goto err_unreg_vdev; - } - bcap_dev->std = std; - } - if (config->inputs[0].capabilities & V4L2_IN_CAP_DV_TIMINGS) { - struct v4l2_dv_timings dv_timings; - ret = v4l2_subdev_call(bcap_dev->sd, video, - g_dv_timings, &dv_timings); - if (ret) { - v4l2_err(&bcap_dev->v4l2_dev, - "Unable to get dv timings\n"); - goto err_unreg_vdev; - } - bcap_dev->dv_timings = dv_timings; - } - ret = bcap_init_sensor_formats(bcap_dev); - if (ret) { - v4l2_err(&bcap_dev->v4l2_dev, - "Unable to create sensor formats table\n"); - goto err_unreg_vdev; - } - return 0; -err_unreg_vdev: - video_unregister_device(&bcap_dev->video_dev); -err_free_handler: - v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); -err_unreg_v4l2: - v4l2_device_unregister(&bcap_dev->v4l2_dev); -err_free_ppi: - ppi_delete_instance(bcap_dev->ppi); -err_free_dev: - kfree(bcap_dev); - return ret; -} - -static int bcap_remove(struct platform_device *pdev) -{ - struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); - struct bcap_device *bcap_dev = container_of(v4l2_dev, - struct bcap_device, v4l2_dev); - - bcap_free_sensor_formats(bcap_dev); - video_unregister_device(&bcap_dev->video_dev); - v4l2_ctrl_handler_free(&bcap_dev->ctrl_handler); - v4l2_device_unregister(v4l2_dev); - ppi_delete_instance(bcap_dev->ppi); - kfree(bcap_dev); - return 0; -} - -static struct platform_driver bcap_driver = { - .driver = { - .name = CAPTURE_DRV_NAME, - }, - .probe = bcap_probe, - .remove = bcap_remove, -}; -module_platform_driver(bcap_driver); - -MODULE_DESCRIPTION("Analog Devices blackfin video capture driver"); -MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/blackfin/ppi.c b/drivers/media/platform/blackfin/ppi.c deleted file mode 100644 index d3dc765c1609..000000000000 --- a/drivers/media/platform/blackfin/ppi.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * ppi.c Analog Devices Parallel Peripheral Interface driver - * - * Copyright (c) 2011 Analog Devices Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/platform_device.h> - -#include <asm/bfin_ppi.h> -#include <asm/blackfin.h> -#include <asm/cacheflush.h> -#include <asm/dma.h> -#include <asm/portmux.h> - -#include <media/blackfin/ppi.h> - -static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler); -static void ppi_detach_irq(struct ppi_if *ppi); -static int ppi_start(struct ppi_if *ppi); -static int ppi_stop(struct ppi_if *ppi); -static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params); -static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr); - -static const struct ppi_ops ppi_ops = { - .attach_irq = ppi_attach_irq, - .detach_irq = ppi_detach_irq, - .start = ppi_start, - .stop = ppi_stop, - .set_params = ppi_set_params, - .update_addr = ppi_update_addr, -}; - -static irqreturn_t ppi_irq_err(int irq, void *dev_id) -{ - struct ppi_if *ppi = dev_id; - const struct ppi_info *info = ppi->info; - - switch (info->type) { - case PPI_TYPE_PPI: - { - struct bfin_ppi_regs *reg = info->base; - unsigned short status; - - /* register on bf561 is cleared when read - * others are W1C - */ - status = bfin_read16(®->status); - if (status & 0x3000) - ppi->err = true; - bfin_write16(®->status, 0xff00); - break; - } - case PPI_TYPE_EPPI: - { - struct bfin_eppi_regs *reg = info->base; - unsigned short status; - - status = bfin_read16(®->status); - if (status & 0x2) - ppi->err = true; - bfin_write16(®->status, 0xffff); - break; - } - case PPI_TYPE_EPPI3: - { - struct bfin_eppi3_regs *reg = info->base; - unsigned long stat; - - stat = bfin_read32(®->stat); - if (stat & 0x2) - ppi->err = true; - bfin_write32(®->stat, 0xc0ff); - break; - } - default: - break; - } - - return IRQ_HANDLED; -} - -static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler) -{ - const struct ppi_info *info = ppi->info; - int ret; - - ret = request_dma(info->dma_ch, "PPI_DMA"); - - if (ret) { - pr_err("Unable to allocate DMA channel for PPI\n"); - return ret; - } - set_dma_callback(info->dma_ch, handler, ppi); - - if (ppi->err_int) { - ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi); - if (ret) { - pr_err("Unable to allocate IRQ for PPI\n"); - free_dma(info->dma_ch); - } - } - return ret; -} - -static void ppi_detach_irq(struct ppi_if *ppi) -{ - const struct ppi_info *info = ppi->info; - - if (ppi->err_int) - free_irq(info->irq_err, ppi); - free_dma(info->dma_ch); -} - -static int ppi_start(struct ppi_if *ppi) -{ - const struct ppi_info *info = ppi->info; - - /* enable DMA */ - enable_dma(info->dma_ch); - - /* enable PPI */ - ppi->ppi_control |= PORT_EN; - switch (info->type) { - case PPI_TYPE_PPI: - { - struct bfin_ppi_regs *reg = info->base; - bfin_write16(®->control, ppi->ppi_control); - break; - } - case PPI_TYPE_EPPI: - { - struct bfin_eppi_regs *reg = info->base; - bfin_write32(®->control, ppi->ppi_control); - break; - } - case PPI_TYPE_EPPI3: - { - struct bfin_eppi3_regs *reg = info->base; - bfin_write32(®->ctl, ppi->ppi_control); - break; - } - default: - return -EINVAL; - } - - SSYNC(); - return 0; -} - -static int ppi_stop(struct ppi_if *ppi) -{ - const struct ppi_info *info = ppi->info; - - /* disable PPI */ - ppi->ppi_control &= ~PORT_EN; - switch (info->type) { - case PPI_TYPE_PPI: - { - struct bfin_ppi_regs *reg = info->base; - bfin_write16(®->control, ppi->ppi_control); - break; - } - case PPI_TYPE_EPPI: - { - struct bfin_eppi_regs *reg = info->base; - bfin_write32(®->control, ppi->ppi_control); - break; - } - case PPI_TYPE_EPPI3: - { - struct bfin_eppi3_regs *reg = info->base; - bfin_write32(®->ctl, ppi->ppi_control); - break; - } - default: - return -EINVAL; - } - - /* disable DMA */ - clear_dma_irqstat(info->dma_ch); - disable_dma(info->dma_ch); - - SSYNC(); - return 0; -} - -static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) -{ - const struct ppi_info *info = ppi->info; - int dma32 = 0; - int dma_config, bytes_per_line; - int hcount, hdelay, samples_per_line; - -#ifdef CONFIG_PINCTRL - static const char * const pin_state[] = {"8bit", "16bit", "24bit"}; - struct pinctrl *pctrl; - struct pinctrl_state *pstate; - - if (params->dlen > 24 || params->dlen <= 0) - return -EINVAL; - pctrl = devm_pinctrl_get(ppi->dev); - if (IS_ERR(pctrl)) - return PTR_ERR(pctrl); - pstate = pinctrl_lookup_state(pctrl, - pin_state[(params->dlen + 7) / 8 - 1]); - if (pinctrl_select_state(pctrl, pstate)) - return -EINVAL; -#endif - - bytes_per_line = params->width * params->bpp / 8; - /* convert parameters unit from pixels to samples */ - hcount = params->width * params->bpp / params->dlen; - hdelay = params->hdelay * params->bpp / params->dlen; - samples_per_line = params->line * params->bpp / params->dlen; - if (params->int_mask == 0xFFFFFFFF) - ppi->err_int = false; - else - ppi->err_int = true; - - dma_config = (DMA_FLOW_STOP | RESTART | DMA2D | DI_EN_Y); - ppi->ppi_control = params->ppi_control & ~PORT_EN; - if (!(ppi->ppi_control & PORT_DIR)) - dma_config |= WNR; - switch (info->type) { - case PPI_TYPE_PPI: - { - struct bfin_ppi_regs *reg = info->base; - - if (params->ppi_control & DMA32) - dma32 = 1; - - bfin_write16(®->control, ppi->ppi_control); - bfin_write16(®->count, samples_per_line - 1); - bfin_write16(®->frame, params->frame); - break; - } - case PPI_TYPE_EPPI: - { - struct bfin_eppi_regs *reg = info->base; - - if ((params->ppi_control & PACK_EN) - || (params->ppi_control & 0x38000) > DLEN_16) - dma32 = 1; - - bfin_write32(®->control, ppi->ppi_control); - bfin_write16(®->line, samples_per_line); - bfin_write16(®->frame, params->frame); - bfin_write16(®->hdelay, hdelay); - bfin_write16(®->vdelay, params->vdelay); - bfin_write16(®->hcount, hcount); - bfin_write16(®->vcount, params->height); - break; - } - case PPI_TYPE_EPPI3: - { - struct bfin_eppi3_regs *reg = info->base; - - if ((params->ppi_control & PACK_EN) - || (params->ppi_control & 0x70000) > DLEN_16) - dma32 = 1; - - bfin_write32(®->ctl, ppi->ppi_control); - bfin_write32(®->line, samples_per_line); - bfin_write32(®->frame, params->frame); - bfin_write32(®->hdly, hdelay); - bfin_write32(®->vdly, params->vdelay); - bfin_write32(®->hcnt, hcount); - bfin_write32(®->vcnt, params->height); - if (params->int_mask) - bfin_write32(®->imsk, params->int_mask & 0xFF); - if (ppi->ppi_control & PORT_DIR) { - u32 hsync_width, vsync_width, vsync_period; - - hsync_width = params->hsync - * params->bpp / params->dlen; - vsync_width = params->vsync * samples_per_line; - vsync_period = samples_per_line * params->frame; - bfin_write32(®->fs1_wlhb, hsync_width); - bfin_write32(®->fs1_paspl, samples_per_line); - bfin_write32(®->fs2_wlvb, vsync_width); - bfin_write32(®->fs2_palpf, vsync_period); - } - break; - } - default: - return -EINVAL; - } - - if (dma32) { - dma_config |= WDSIZE_32 | PSIZE_32; - set_dma_x_count(info->dma_ch, bytes_per_line >> 2); - set_dma_x_modify(info->dma_ch, 4); - set_dma_y_modify(info->dma_ch, 4); - } else { - dma_config |= WDSIZE_16 | PSIZE_16; - set_dma_x_count(info->dma_ch, bytes_per_line >> 1); - set_dma_x_modify(info->dma_ch, 2); - set_dma_y_modify(info->dma_ch, 2); - } - set_dma_y_count(info->dma_ch, params->height); - set_dma_config(info->dma_ch, dma_config); - - SSYNC(); - return 0; -} - -static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr) -{ - set_dma_start_addr(ppi->info->dma_ch, addr); -} - -struct ppi_if *ppi_create_instance(struct platform_device *pdev, - const struct ppi_info *info) -{ - struct ppi_if *ppi; - - if (!info || !info->pin_req) - return NULL; - -#ifndef CONFIG_PINCTRL - if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) { - dev_err(&pdev->dev, "request peripheral failed\n"); - return NULL; - } -#endif - - ppi = kzalloc(sizeof(*ppi), GFP_KERNEL); - if (!ppi) { - peripheral_free_list(info->pin_req); - return NULL; - } - ppi->ops = &ppi_ops; - ppi->info = info; - ppi->dev = &pdev->dev; - - pr_info("ppi probe success\n"); - return ppi; -} -EXPORT_SYMBOL(ppi_create_instance); - -void ppi_delete_instance(struct ppi_if *ppi) -{ - peripheral_free_list(ppi->info->pin_req); - kfree(ppi); -} -EXPORT_SYMBOL(ppi_delete_instance); - -MODULE_DESCRIPTION("Analog Devices PPI driver"); -MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c index 5debdf08fbe7..f1f28cf5c751 100644 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -1,18 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 9fe113cb901f..68ed2a564ad1 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -68,8 +68,9 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd) { struct coda_dev *dev = ctx->dev; - if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541 || + dev->devtype->product == CODA_960) { /* Restore context related registers to CODA */ coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM); @@ -506,7 +507,8 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx, goto err; } - if (!ctx->psbuf.vaddr && dev->devtype->product == CODA_7541) { + if (!ctx->psbuf.vaddr && (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541)) { ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf"); if (ret < 0) @@ -594,6 +596,7 @@ static void coda_setup_iram(struct coda_ctx *ctx) int dbk_bits; int bit_bits; int ip_bits; + int me_bits; memset(iram_info, 0, sizeof(*iram_info)); iram_info->next_paddr = dev->iram.paddr; @@ -603,15 +606,23 @@ static void coda_setup_iram(struct coda_ctx *ctx) return; switch (dev->devtype->product) { + case CODA_HX4: + dbk_bits = CODA7_USE_HOST_DBK_ENABLE; + bit_bits = CODA7_USE_HOST_BIT_ENABLE; + ip_bits = CODA7_USE_HOST_IP_ENABLE; + me_bits = CODA7_USE_HOST_ME_ENABLE; + break; case CODA_7541: dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE; bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + me_bits = CODA7_USE_HOST_ME_ENABLE | CODA7_USE_ME_ENABLE; break; case CODA_960: dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE; bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE; ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE; + me_bits = 0; break; default: /* CODA_DX6 */ return; @@ -626,7 +637,8 @@ static void coda_setup_iram(struct coda_ctx *ctx) w64 = mb_width * 64; /* Prioritize in case IRAM is too small for everything */ - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { iram_info->search_ram_size = round_up(mb_width * 16 * 36 + 2048, 1024); iram_info->search_ram_paddr = coda_iram_alloc(iram_info, @@ -635,8 +647,7 @@ static void coda_setup_iram(struct coda_ctx *ctx) pr_err("IRAM is smaller than the search ram size\n"); goto out; } - iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE | - CODA7_USE_ME_ENABLE; + iram_info->axi_sram_use |= me_bits; } /* Only H.264BP and H.263P3 are considered */ @@ -688,7 +699,8 @@ out: v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "IRAM smaller than needed\n"); - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { /* TODO - Enabling these causes picture errors on CODA7541 */ if (ctx->inst_type == CODA_INST_DECODER) { /* fw 1.4.50 */ @@ -706,6 +718,7 @@ out: static u32 coda_supported_firmwares[] = { CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5), + CODA_FIRMWARE_VERNUM(CODA_HX4, 1, 4, 50), CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50), CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5), CODA_FIRMWARE_VERNUM(CODA_960, 2, 3, 10), @@ -890,6 +903,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) case CODA_960: coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN); /* fallthrough */ + case CODA_HX4: case CODA_7541: coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN | CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL); @@ -919,6 +933,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET; break; + case CODA_HX4: case CODA_7541: if (dst_fourcc == V4L2_PIX_FMT_H264) { value = (round_up(q_data_src->width, 16) & @@ -1086,6 +1101,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) value = FMO_SLICE_SAVE_BUF_SIZE << 7; coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO); break; + case CODA_HX4: case CODA_7541: coda_write(dev, ctx->iram_info.search_ram_paddr, CODA7_CMD_ENC_SEQ_SEARCH_BASE); @@ -1131,7 +1147,8 @@ static int coda_start_encoding(struct coda_ctx *ctx) coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM); coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE); - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { coda_write(dev, q_data_src->bytesperline, CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE); } @@ -1570,7 +1587,8 @@ static bool coda_reorder_enable(struct coda_ctx *ctx) struct coda_dev *dev = ctx->dev; int profile, level; - if (dev->devtype->product != CODA_7541 && + if (dev->devtype->product != CODA_HX4 && + dev->devtype->product != CODA_7541 && dev->devtype->product != CODA_960) return false; @@ -1664,7 +1682,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) CODA_CMD_DEC_SEQ_MP4_ASP_CLASS); } if (src_fourcc == V4L2_PIX_FMT_H264) { - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { coda_write(dev, ctx->psbuf.paddr, CODA_CMD_DEC_SEQ_PS_BB_START); coda_write(dev, (CODA7_PS_BUF_SIZE / 1024), @@ -1791,7 +1810,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) CODA_CMD_SET_FRAME_SLICE_BB_SIZE); } - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { int max_mb_x = 1920 / 16; int max_mb_y = 1088 / 16; int max_mb_num = max_mb_x * max_mb_y; @@ -1909,6 +1929,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) switch (dev->devtype->product) { case CODA_DX6: /* TBD */ + case CODA_HX4: case CODA_7541: coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION); break; @@ -2049,7 +2070,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "errors in %d macroblocks\n", err_mb); - if (dev->devtype->product == CODA_7541) { + if (dev->devtype->product == CODA_HX4 || + dev->devtype->product == CODA_7541) { val = coda_read(dev, CODA_RET_DEC_PIC_OPTION); if (val == 0) { /* not enough bitstream data */ diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index e8a7554a61d2..04e35d70ce2e 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -128,7 +128,8 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, /* * Arrays of codecs supported by each given version of Coda: * i.MX27 -> codadx6 - * i.MX5x -> coda7 + * i.MX51 -> codahx4 + * i.MX53 -> coda7 * i.MX6 -> coda960 * Use V4L2_PIX_FMT_YUV420 as placeholder for all supported YUV 4:2:0 variants */ @@ -137,6 +138,13 @@ static const struct coda_codec codadx6_codecs[] = { CODA_CODEC(CODADX6_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 720, 576), }; +static const struct coda_codec codahx4_codecs[] = { + CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 720, 576), + CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088), + CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1280, 720), +}; + static const struct coda_codec coda7_codecs[] = { CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720), CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720), @@ -234,6 +242,11 @@ static const struct coda_video_device *codadx6_video_devices[] = { &coda_bit_encoder, }; +static const struct coda_video_device *codahx4_video_devices[] = { + &coda_bit_encoder, + &coda_bit_decoder, +}; + static const struct coda_video_device *coda7_video_devices[] = { &coda_bit_jpeg_encoder, &coda_bit_jpeg_decoder, @@ -332,6 +345,8 @@ const char *coda_product_name(int product) switch (product) { case CODA_DX6: return "CodaDx6"; + case CODA_HX4: + return "CodaHx4"; case CODA_7541: return "CODA7541"; case CODA_960: @@ -1775,7 +1790,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE); - if (ctx->dev->devtype->product == CODA_7541) { + if (ctx->dev->devtype->product == CODA_HX4 || + ctx->dev->devtype->product == CODA_7541) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_MPEG_VIDEO_H264_LEVEL_3_1, @@ -1803,7 +1819,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, 0x0, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE); - if (ctx->dev->devtype->product == CODA_7541 || + if (ctx->dev->devtype->product == CODA_HX4 || + ctx->dev->devtype->product == CODA_7541 || ctx->dev->devtype->product == CODA_960) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, @@ -2004,6 +2021,7 @@ static int coda_open(struct file *file) if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER) ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB; /* fallthrough */ + case CODA_HX4: case CODA_7541: ctx->reg_idx = 0; break; @@ -2182,7 +2200,8 @@ static int coda_hw_init(struct coda_dev *dev) /* Tell the BIT where to find everything it needs */ if (dev->devtype->product == CODA_960 || - dev->devtype->product == CODA_7541) { + dev->devtype->product == CODA_7541 || + dev->devtype->product == CODA_HX4) { coda_write(dev, dev->tempbuf.paddr, CODA_REG_BIT_TEMP_BUF_ADDR); coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); @@ -2387,6 +2406,7 @@ put_pm: enum coda_platform { CODA_IMX27, + CODA_IMX51, CODA_IMX53, CODA_IMX6Q, CODA_IMX6DL, @@ -2407,6 +2427,21 @@ static const struct coda_devtype coda_devdata[] = { .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024, .iram_size = 0xb000, }, + [CODA_IMX51] = { + .firmware = { + "vpu_fw_imx51.bin", + "vpu/vpu_fw_imx51.bin", + "v4l-codahx4-imx51.bin" + }, + .product = CODA_HX4, + .codecs = codahx4_codecs, + .num_codecs = ARRAY_SIZE(codahx4_codecs), + .vdevs = codahx4_video_devices, + .num_vdevs = ARRAY_SIZE(codahx4_video_devices), + .workbuf_size = 128 * 1024, + .tempbuf_size = 304 * 1024, + .iram_size = 0x14000, + }, [CODA_IMX53] = { .firmware = { "vpu_fw_imx53.bin", @@ -2463,6 +2498,7 @@ MODULE_DEVICE_TABLE(platform, coda_platform_ids); #ifdef CONFIG_OF static const struct of_device_id coda_dt_ids[] = { { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] }, + { .compatible = "fsl,imx51-vpu", .data = &coda_devdata[CODA_IMX51] }, { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] }, { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] }, { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] }, diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index c5f504d8cf67..c70cfab2433f 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -28,7 +28,7 @@ #include "coda_regs.h" -#define CODA_MAX_FRAMEBUFFERS 17 +#define CODA_MAX_FRAMEBUFFERS 19 #define FMO_SLICE_SAVE_BUF_SIZE (32) enum { @@ -43,6 +43,7 @@ enum coda_inst_type { enum coda_product { CODA_DX6 = 0xf001, + CODA_HX4 = 0xf00a, CODA_7541 = 0xf012, CODA_960 = 0xf020, }; diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index b73886519f4f..19cf6853411e 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -116,7 +116,7 @@ struct vpss_hw_ops { struct vpss_oper_config { __iomem void *vpss_regs_base0; __iomem void *vpss_regs_base1; - resource_size_t *vpss_regs_base2; + __iomem void *vpss_regs_base2; enum vpss_platform_type platform; spinlock_t vpss_lock; struct vpss_hw_ops hw_ops; diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index ed9302caa004..a3cdac188190 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -670,10 +670,13 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, return; } if (target == V4L2_SEL_TGT_COMPOSE) { + u32 tmp_min_h = ffs(sink->width) - 3; + u32 tmp_min_v = ffs(sink->height) - 1; + if (ctx->rotation != 90 && ctx->rotation != 270) align_h = 1; - max_sc_h = min(SCALER_MAX_HRATIO, 1 << (ffs(sink->width) - 3)); - max_sc_v = min(SCALER_MAX_VRATIO, 1 << (ffs(sink->height) - 1)); + max_sc_h = min(SCALER_MAX_HRATIO, 1 << tmp_min_h); + max_sc_v = min(SCALER_MAX_VRATIO, 1 << tmp_min_v); min_sz = var->min_out_pixsize; } else { u32 depth = fimc_get_format_depth(sink->fmt); diff --git a/drivers/media/platform/exynos4-is/fimc-is-regs.c b/drivers/media/platform/exynos4-is/fimc-is-regs.c index cfe4406a83ff..e0e291066037 100644 --- a/drivers/media/platform/exynos4-is/fimc-is-regs.c +++ b/drivers/media/platform/exynos4-is/fimc-is-regs.c @@ -159,7 +159,7 @@ void fimc_is_hw_load_setfile(struct fimc_is *is) int fimc_is_hw_change_mode(struct fimc_is *is) { - const u8 cmd[] = { + static const u8 cmd[] = { HIC_PREVIEW_STILL, HIC_PREVIEW_VIDEO, HIC_CAPTURE_STILL, HIC_CAPTURE_VIDEO, }; diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 7b7250b1cff8..80670eeee142 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1443,24 +1443,24 @@ static int mcam_vidioc_s_input(struct file *filp, void *priv, unsigned int i) * the level which controls the number of read buffers. */ static int mcam_vidioc_g_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) + struct v4l2_streamparm *a) { struct mcam_camera *cam = video_drvdata(filp); int ret; - ret = sensor_call(cam, video, g_parm, parms); - parms->parm.capture.readbuffers = n_dma_bufs; + ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, a); + a->parm.capture.readbuffers = n_dma_bufs; return ret; } static int mcam_vidioc_s_parm(struct file *filp, void *priv, - struct v4l2_streamparm *parms) + struct v4l2_streamparm *a) { struct mcam_camera *cam = video_drvdata(filp); int ret; - ret = sensor_call(cam, video, s_parm, parms); - parms->parm.capture.readbuffers = n_dma_bufs; + ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, a); + a->parm.capture.readbuffers = n_dma_bufs; return ret; } diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index 226f90886484..af17aaa21f58 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -1081,11 +1081,11 @@ static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg) jpeg->clk_jdec = devm_clk_get(jpeg->dev, "jpgdec"); if (IS_ERR(jpeg->clk_jdec)) - return -EINVAL; + return PTR_ERR(jpeg->clk_jdec); jpeg->clk_jdec_smi = devm_clk_get(jpeg->dev, "jpgdec-smi"); if (IS_ERR(jpeg->clk_jdec_smi)) - return -EINVAL; + return PTR_ERR(jpeg->clk_jdec_smi); return 0; } diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 843510979ad8..86f0a7134365 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -1224,6 +1224,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) ctx->dpb_size = dpbsize; ctx->state = MTK_STATE_HEADER; mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size); + + mtk_vdec_queue_res_chg_event(ctx); } static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index 123c2b26a933..1d8508237220 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -236,7 +236,6 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, struct dma_async_tx_descriptor *tx; enum dma_ctrl_flags flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; struct dma_chan *chan = vout->vrfb_dma_tx.chan; - struct dma_device *dmadev = chan->device; struct dma_interleaved_template *xt = vout->vrfb_dma_tx.xt; dma_cookie_t cookie; enum dma_status status; @@ -271,7 +270,7 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout, xt->dst_sgl = true; xt->dst_inc = true; - tx = dmadev->device_prep_interleaved_dma(chan, xt, flags); + tx = dmaengine_prep_interleaved_dma(chan, xt, flags); if (tx == NULL) { pr_err("%s: DMA interleaved prep error\n", __func__); return -EINVAL; diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 521d4b36c090..c4a577848dd7 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -76,7 +76,7 @@ int venus_boot(struct device *dev, const char *fwname) } ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID, mem_va, mem_phys, - mem_size); + mem_size, NULL); release_firmware(mdt); diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index 1baf78d3c02d..bca894a00c07 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -106,8 +106,8 @@ int hfi_core_deinit(struct venus_core *core, bool blocking) if (!empty) { mutex_unlock(&core->lock); - wait_on_atomic_t(&core->insts_count, atomic_t_wait, - TASK_UNINTERRUPTIBLE); + wait_var_event(&core->insts_count, + !atomic_read(&core->insts_count)); mutex_lock(&core->lock); } @@ -229,8 +229,8 @@ void hfi_session_destroy(struct venus_inst *inst) mutex_lock(&core->lock); list_del_init(&inst->list); - atomic_dec(&core->insts_count); - wake_up_atomic_t(&core->insts_count); + if (atomic_dec_and_test(&core->insts_count)) + wake_up_var(&core->insts_count); mutex_unlock(&core->lock); } EXPORT_SYMBOL_GPL(hfi_session_destroy); diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index a681ae5381d6..90c93d9603dc 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -659,10 +659,10 @@ static u32 init_done_read_prop(struct venus_core *core, struct venus_inst *inst, prop->buffer_type == HFI_BUFFER_OUTPUT2) { switch (prop->data[i]) { case HFI_BUFFER_MODE_STATIC: - inst->cap_bufs_mode_static = 1; + inst->cap_bufs_mode_static = true; break; case HFI_BUFFER_MODE_DYNAMIC: - inst->cap_bufs_mode_dynamic = 1; + inst->cap_bufs_mode_dynamic = true; break; default: break; diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index c9e9576bb08a..49bbd1861d3a 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -135,20 +135,21 @@ find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) return NULL; for (i = 0; i < size; i++) { + bool valid; + if (fmt[i].type != type) continue; - if (k == index) + valid = type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE || + venus_helper_check_codec(inst, fmt[i].pixfmt); + if (k == index && valid) break; - k++; + if (valid) + k++; } if (i == size) return NULL; - if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - !venus_helper_check_codec(inst, fmt[i].pixfmt)) - return NULL; - return &fmt[i]; } diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index e3a10a852cad..6b2ce479584e 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -120,20 +120,21 @@ find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) return NULL; for (i = 0; i < size; i++) { + bool valid; + if (fmt[i].type != type) continue; - if (k == index) + valid = type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || + venus_helper_check_codec(inst, fmt[i].pixfmt); + if (k == index && valid) break; - k++; + if (valid) + k++; } if (i == size) return NULL; - if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && - !venus_helper_check_codec(inst, fmt[i].pixfmt)) - return NULL; - return &fmt[i]; } diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 23fdff7a7370..4a40e6ad1be7 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -168,12 +168,8 @@ static int rvin_setup(struct rvin_dev *vin) break; case V4L2_FIELD_ALTERNATE: case V4L2_FIELD_NONE: - if (vin->continuous) { - vnmc = VNMC_IM_ODD_EVEN; - progressive = true; - } else { - vnmc = VNMC_IM_ODD; - } + vnmc = VNMC_IM_ODD_EVEN; + progressive = true; break; default: vnmc = VNMC_IM_ODD; @@ -298,14 +294,6 @@ static bool rvin_capture_active(struct rvin_dev *vin) return rvin_read(vin, VNMS_REG) & VNMS_CA; } -static int rvin_get_active_slot(struct rvin_dev *vin, u32 vnms) -{ - if (vin->continuous) - return (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; - - return 0; -} - static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms) { if (vin->format.field == V4L2_FIELD_ALTERNATE) { @@ -344,76 +332,47 @@ static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr) rvin_write(vin, offset, VNMB_REG(slot)); } -/* Moves a buffer from the queue to the HW slots */ -static bool rvin_fill_hw_slot(struct rvin_dev *vin, int slot) +/* + * Moves a buffer from the queue to the HW slot. If no buffer is + * available use the scratch buffer. The scratch buffer is never + * returned to userspace, its only function is to enable the capture + * loop to keep running. + */ +static void rvin_fill_hw_slot(struct rvin_dev *vin, int slot) { struct rvin_buffer *buf; struct vb2_v4l2_buffer *vbuf; - dma_addr_t phys_addr_top; - - if (vin->queue_buf[slot] != NULL) - return true; + dma_addr_t phys_addr; - if (list_empty(&vin->buf_list)) - return false; + /* A already populated slot shall never be overwritten. */ + if (WARN_ON(vin->queue_buf[slot] != NULL)) + return; vin_dbg(vin, "Filling HW slot: %d\n", slot); - /* Keep track of buffer we give to HW */ - buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); - vbuf = &buf->vb; - list_del_init(to_buf_list(vbuf)); - vin->queue_buf[slot] = vbuf; - - /* Setup DMA */ - phys_addr_top = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); - rvin_set_slot_addr(vin, slot, phys_addr_top); - - return true; -} - -static bool rvin_fill_hw(struct rvin_dev *vin) -{ - int slot, limit; - - limit = vin->continuous ? HW_BUFFER_NUM : 1; - - for (slot = 0; slot < limit; slot++) - if (!rvin_fill_hw_slot(vin, slot)) - return false; - return true; -} - -static void rvin_capture_on(struct rvin_dev *vin) -{ - vin_dbg(vin, "Capture on in %s mode\n", - vin->continuous ? "continuous" : "single"); + if (list_empty(&vin->buf_list)) { + vin->queue_buf[slot] = NULL; + phys_addr = vin->scratch_phys; + } else { + /* Keep track of buffer we give to HW */ + buf = list_entry(vin->buf_list.next, struct rvin_buffer, list); + vbuf = &buf->vb; + list_del_init(to_buf_list(vbuf)); + vin->queue_buf[slot] = vbuf; + + /* Setup DMA */ + phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0); + } - if (vin->continuous) - /* Continuous Frame Capture Mode */ - rvin_write(vin, VNFC_C_FRAME, VNFC_REG); - else - /* Single Frame Capture Mode */ - rvin_write(vin, VNFC_S_FRAME, VNFC_REG); + rvin_set_slot_addr(vin, slot, phys_addr); } static int rvin_capture_start(struct rvin_dev *vin) { - struct rvin_buffer *buf, *node; - int bufs, ret; - - /* Count number of free buffers */ - bufs = 0; - list_for_each_entry_safe(buf, node, &vin->buf_list, list) - bufs++; + int slot, ret; - /* Continuous capture requires more buffers then there are HW slots */ - vin->continuous = bufs > HW_BUFFER_NUM; - - if (!rvin_fill_hw(vin)) { - vin_err(vin, "HW not ready to start, not enough buffers available\n"); - return -EINVAL; - } + for (slot = 0; slot < HW_BUFFER_NUM; slot++) + rvin_fill_hw_slot(vin, slot); rvin_crop_scale_comp(vin); @@ -421,7 +380,10 @@ static int rvin_capture_start(struct rvin_dev *vin) if (ret) return ret; - rvin_capture_on(vin); + vin_dbg(vin, "Starting to capture\n"); + + /* Continuous Frame Capture Mode */ + rvin_write(vin, VNFC_C_FRAME, VNFC_REG); vin->state = RUNNING; @@ -904,7 +866,7 @@ static irqreturn_t rvin_irq(int irq, void *data) struct rvin_dev *vin = data; u32 int_status, vnms; int slot; - unsigned int i, sequence, handled = 0; + unsigned int handled = 0; unsigned long flags; spin_lock_irqsave(&vin->qlock, flags); @@ -930,65 +892,25 @@ static irqreturn_t rvin_irq(int irq, void *data) /* Prepare for capture and update state */ vnms = rvin_read(vin, VNMS_REG); - slot = rvin_get_active_slot(vin, vnms); - sequence = vin->sequence++; - - vin_dbg(vin, "IRQ %02d: %d\tbuf0: %c buf1: %c buf2: %c\tmore: %d\n", - sequence, slot, - slot == 0 ? 'x' : vin->queue_buf[0] != NULL ? '1' : '0', - slot == 1 ? 'x' : vin->queue_buf[1] != NULL ? '1' : '0', - slot == 2 ? 'x' : vin->queue_buf[2] != NULL ? '1' : '0', - !list_empty(&vin->buf_list)); - - /* HW have written to a slot that is not prepared we are in trouble */ - if (WARN_ON((vin->queue_buf[slot] == NULL))) - goto done; + slot = (vnms & VNMS_FBS_MASK) >> VNMS_FBS_SHIFT; /* Capture frame */ - vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms); - vin->queue_buf[slot]->sequence = sequence; - vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); - vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, VB2_BUF_STATE_DONE); - vin->queue_buf[slot] = NULL; - - /* Prepare for next frame */ - if (!rvin_fill_hw(vin)) { - - /* - * Can't supply HW with new buffers fast enough. Halt - * capture until more buffers are available. - */ - vin->state = STALLED; - - /* - * The continuous capturing requires an explicit stop - * operation when there is no buffer to be set into - * the VnMBm registers. - */ - if (vin->continuous) { - rvin_capture_stop(vin); - vin_dbg(vin, "IRQ %02d: hw not ready stop\n", sequence); - - /* Maybe we can continue in single capture mode */ - for (i = 0; i < HW_BUFFER_NUM; i++) { - if (vin->queue_buf[i]) { - list_add(to_buf_list(vin->queue_buf[i]), - &vin->buf_list); - vin->queue_buf[i] = NULL; - } - } - - if (!list_empty(&vin->buf_list)) - rvin_capture_start(vin); - } + if (vin->queue_buf[slot]) { + vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms); + vin->queue_buf[slot]->sequence = vin->sequence; + vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns(); + vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf, + VB2_BUF_STATE_DONE); + vin->queue_buf[slot] = NULL; } else { - /* - * The single capturing requires an explicit capture - * operation to fetch the next frame. - */ - if (!vin->continuous) - rvin_capture_on(vin); + /* Scratch buffer was used, dropping frame. */ + vin_dbg(vin, "Dropping frame %u\n", vin->sequence); } + + vin->sequence++; + + /* Prepare for next frame */ + rvin_fill_hw_slot(vin, slot); done: spin_unlock_irqrestore(&vin->qlock, flags); @@ -1059,13 +981,6 @@ static void rvin_buffer_queue(struct vb2_buffer *vb) list_add_tail(to_buf_list(vbuf), &vin->buf_list); - /* - * If capture is stalled add buffer to HW and restart - * capturing if HW is ready to continue. - */ - if (vin->state == STALLED) - rvin_capture_start(vin); - spin_unlock_irqrestore(&vin->qlock, flags); } @@ -1076,6 +991,17 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) unsigned long flags; int ret; + /* Allocate scratch buffer. */ + vin->scratch = dma_alloc_coherent(vin->dev, vin->format.sizeimage, + &vin->scratch_phys, GFP_KERNEL); + if (!vin->scratch) { + spin_lock_irqsave(&vin->qlock, flags); + return_all_buffers(vin, VB2_BUF_STATE_QUEUED); + spin_unlock_irqrestore(&vin->qlock, flags); + vin_err(vin, "Failed to allocate scratch buffer\n"); + return -ENOMEM; + } + sd = vin_to_source(vin); v4l2_subdev_call(sd, video, s_stream, 1); @@ -1091,6 +1017,10 @@ static int rvin_start_streaming(struct vb2_queue *vq, unsigned int count) spin_unlock_irqrestore(&vin->qlock, flags); + if (ret) + dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, + vin->scratch_phys); + return ret; } @@ -1141,6 +1071,10 @@ static void rvin_stop_streaming(struct vb2_queue *vq) /* disable interrupts */ rvin_disable_interrupts(vin); + + /* Free scratch buffer. */ + dma_free_coherent(vin->dev, vin->format.sizeimage, vin->scratch, + vin->scratch_phys); } static const struct vb2_ops rvin_qops = { @@ -1189,7 +1123,7 @@ int rvin_dma_probe(struct rvin_dev *vin, int irq) q->ops = &rvin_qops; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 1; + q->min_buffers_needed = 4; q->dev = vin->dev; ret = vb2_queue_init(q); diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 5382078143fb..95897127cc41 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -38,13 +38,11 @@ enum chip_id { /** * STOPPED - No operation in progress * RUNNING - Operation in progress have buffers - * STALLED - No operation in progress have no buffers * STOPPING - Stopping operation */ enum rvin_dma_state { STOPPED = 0, RUNNING, - STALLED, STOPPING, }; @@ -102,12 +100,13 @@ struct rvin_graph_entity { * * @lock: protects @queue * @queue: vb2 buffers queue + * @scratch: cpu address for scratch buffer + * @scratch_phys: physical address of the scratch buffer * - * @qlock: protects @queue_buf, @buf_list, @continuous, @sequence + * @qlock: protects @queue_buf, @buf_list, @sequence * @state * @queue_buf: Keeps track of buffers given to HW slot * @buf_list: list of queued buffers - * @continuous: tracks if active operation is continuous or single mode * @sequence: V4L2 buffers sequence number * @state: keeps track of operation state * @@ -130,11 +129,12 @@ struct rvin_dev { struct mutex lock; struct vb2_queue queue; + void *scratch; + dma_addr_t scratch_phys; spinlock_t qlock; struct vb2_v4l2_buffer *queue_buf[HW_BUFFER_NUM]; struct list_head buf_list; - bool continuous; unsigned int sequence; enum rvin_dma_state state; diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index b2e080ef5391..dc7e280c91b4 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -274,7 +274,7 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr) { struct dma_slave_config dma_cfg; unsigned int i; - int ret = -ENODEV; + int ret; for_each_rcar_drif_channel(i, &sdr->cur_ch_mask) { struct rcar_drif *ch = sdr->ch[i]; @@ -282,6 +282,7 @@ static int rcar_drif_alloc_dmachannels(struct rcar_drif_sdr *sdr) ch->dmach = dma_request_slave_channel(&ch->pdev->dev, "rx"); if (!ch->dmach) { rdrif_err(sdr, "ch%u: dma channel req failed\n", i); + ret = -ENODEV; goto dmach_error; } diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c new file mode 100644 index 000000000000..6599dba5ab84 --- /dev/null +++ b/drivers/media/platform/renesas-ceu.c @@ -0,0 +1,1677 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 Driver for Renesas Capture Engine Unit (CEU) interface + * Copyright (C) 2017-2018 Jacopo Mondi <jacopo+renesas@jmondi.org> + * + * Based on soc-camera driver "soc_camera/sh_mobile_ceu_camera.c" + * Copyright (C) 2008 Magnus Damm + * + * Based on V4L2 Driver for PXA camera host - "pxa_camera.c", + * Copyright (C) 2006, Sascha Hauer, Pengutronix + * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_graph.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/time.h> +#include <linux/videodev2.h> + +#include <media/v4l2-async.h> +#include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-event.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-image-sizes.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-mediabus.h> +#include <media/videobuf2-dma-contig.h> + +#include <media/drv-intf/renesas-ceu.h> + +#define DRIVER_NAME "renesas-ceu" + +/* CEU registers offsets and masks. */ +#define CEU_CAPSR 0x00 /* Capture start register */ +#define CEU_CAPCR 0x04 /* Capture control register */ +#define CEU_CAMCR 0x08 /* Capture interface control register */ +#define CEU_CAMOR 0x10 /* Capture interface offset register */ +#define CEU_CAPWR 0x14 /* Capture interface width register */ +#define CEU_CAIFR 0x18 /* Capture interface input format register */ +#define CEU_CRCNTR 0x28 /* CEU register control register */ +#define CEU_CRCMPR 0x2c /* CEU register forcible control register */ +#define CEU_CFLCR 0x30 /* Capture filter control register */ +#define CEU_CFSZR 0x34 /* Capture filter size clip register */ +#define CEU_CDWDR 0x38 /* Capture destination width register */ +#define CEU_CDAYR 0x3c /* Capture data address Y register */ +#define CEU_CDACR 0x40 /* Capture data address C register */ +#define CEU_CFWCR 0x5c /* Firewall operation control register */ +#define CEU_CDOCR 0x64 /* Capture data output control register */ +#define CEU_CEIER 0x70 /* Capture event interrupt enable register */ +#define CEU_CETCR 0x74 /* Capture event flag clear register */ +#define CEU_CSTSR 0x7c /* Capture status register */ +#define CEU_CSRTR 0x80 /* Capture software reset register */ + +/* Data synchronous fetch mode. */ +#define CEU_CAMCR_JPEG BIT(4) + +/* Input components ordering: CEU_CAMCR.DTARY field. */ +#define CEU_CAMCR_DTARY_8_UYVY (0x00 << 8) +#define CEU_CAMCR_DTARY_8_VYUY (0x01 << 8) +#define CEU_CAMCR_DTARY_8_YUYV (0x02 << 8) +#define CEU_CAMCR_DTARY_8_YVYU (0x03 << 8) +/* TODO: input components ordering for 16 bits input. */ + +/* Bus transfer MTU. */ +#define CEU_CAPCR_BUS_WIDTH256 (0x3 << 20) + +/* Bus width configuration. */ +#define CEU_CAMCR_DTIF_16BITS BIT(12) + +/* No downsampling to planar YUV420 in image fetch mode. */ +#define CEU_CDOCR_NO_DOWSAMPLE BIT(4) + +/* Swap all input data in 8-bit, 16-bits and 32-bits units (Figure 46.45). */ +#define CEU_CDOCR_SWAP_ENDIANNESS (7) + +/* Capture reset and enable bits. */ +#define CEU_CAPSR_CPKIL BIT(16) +#define CEU_CAPSR_CE BIT(0) + +/* CEU operating flag bit. */ +#define CEU_CAPCR_CTNCP BIT(16) +#define CEU_CSTRST_CPTON BIT(0) + +/* Platform specific IRQ source flags. */ +#define CEU_CETCR_ALL_IRQS_RZ 0x397f313 +#define CEU_CETCR_ALL_IRQS_SH4 0x3d7f313 + +/* Prohibited register access interrupt bit. */ +#define CEU_CETCR_IGRW BIT(4) +/* One-frame capture end interrupt. */ +#define CEU_CEIER_CPE BIT(0) +/* VBP error. */ +#define CEU_CEIER_VBP BIT(20) +#define CEU_CEIER_MASK (CEU_CEIER_CPE | CEU_CEIER_VBP) + +#define CEU_MAX_WIDTH 2560 +#define CEU_MAX_HEIGHT 1920 +#define CEU_MAX_BPL 8188 +#define CEU_W_MAX(w) ((w) < CEU_MAX_WIDTH ? (w) : CEU_MAX_WIDTH) +#define CEU_H_MAX(h) ((h) < CEU_MAX_HEIGHT ? (h) : CEU_MAX_HEIGHT) + +/* + * ceu_bus_fmt - describe a 8-bits yuyv format the sensor can produce + * + * @mbus_code: bus format code + * @fmt_order: CEU_CAMCR.DTARY ordering of input components (Y, Cb, Cr) + * @fmt_order_swap: swapped CEU_CAMCR.DTARY ordering of input components + * (Y, Cr, Cb) + * @swapped: does Cr appear before Cb? + * @bps: number of bits sent over bus for each sample + * @bpp: number of bits per pixels unit + */ +struct ceu_mbus_fmt { + u32 mbus_code; + u32 fmt_order; + u32 fmt_order_swap; + bool swapped; + u8 bps; + u8 bpp; +}; + +/* + * ceu_buffer - Link vb2 buffer to the list of available buffers. + */ +struct ceu_buffer { + struct vb2_v4l2_buffer vb; + struct list_head queue; +}; + +static inline struct ceu_buffer *vb2_to_ceu(struct vb2_v4l2_buffer *vbuf) +{ + return container_of(vbuf, struct ceu_buffer, vb); +} + +/* + * ceu_subdev - Wraps v4l2 sub-device and provides async subdevice. + */ +struct ceu_subdev { + struct v4l2_subdev *v4l2_sd; + struct v4l2_async_subdev asd; + + /* per-subdevice mbus configuration options */ + unsigned int mbus_flags; + struct ceu_mbus_fmt mbus_fmt; +}; + +static struct ceu_subdev *to_ceu_subdev(struct v4l2_async_subdev *asd) +{ + return container_of(asd, struct ceu_subdev, asd); +} + +/* + * ceu_device - CEU device instance + */ +struct ceu_device { + struct device *dev; + struct video_device vdev; + struct v4l2_device v4l2_dev; + + /* subdevices descriptors */ + struct ceu_subdev *subdevs; + /* the subdevice currently in use */ + struct ceu_subdev *sd; + unsigned int sd_index; + unsigned int num_sd; + + /* platform specific mask with all IRQ sources flagged */ + u32 irq_mask; + + /* currently configured field and pixel format */ + enum v4l2_field field; + struct v4l2_pix_format_mplane v4l2_pix; + + /* async subdev notification helpers */ + struct v4l2_async_notifier notifier; + /* pointers to "struct ceu_subdevice -> asd" */ + struct v4l2_async_subdev **asds; + + /* vb2 queue, capture buffer list and active buffer pointer */ + struct vb2_queue vb2_vq; + struct list_head capture; + struct vb2_v4l2_buffer *active; + unsigned int sequence; + + /* mlock - lock access to interface reset and vb2 queue */ + struct mutex mlock; + + /* lock - lock access to capture buffer queue and active buffer */ + spinlock_t lock; + + /* base - CEU memory base address */ + void __iomem *base; +}; + +static inline struct ceu_device *v4l2_to_ceu(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct ceu_device, v4l2_dev); +} + +/* --- CEU memory output formats --- */ + +/* + * ceu_fmt - describe a memory output format supported by CEU interface. + * + * @fourcc: memory layout fourcc format code + * @bpp: number of bits for each pixel stored in memory + */ +struct ceu_fmt { + u32 fourcc; + u32 bpp; +}; + +/* + * ceu_format_list - List of supported memory output formats + * + * If sensor provides any YUYV bus format, all the following planar memory + * formats are available thanks to CEU re-ordering and sub-sampling + * capabilities. + */ +static const struct ceu_fmt ceu_fmt_list[] = { + { + .fourcc = V4L2_PIX_FMT_NV16, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_NV61, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .bpp = 12, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .bpp = 12, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .bpp = 16, + }, +}; + +static const struct ceu_fmt *get_ceu_fmt_from_fourcc(unsigned int fourcc) +{ + const struct ceu_fmt *fmt = &ceu_fmt_list[0]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ceu_fmt_list); i++, fmt++) + if (fmt->fourcc == fourcc) + return fmt; + + return NULL; +} + +static bool ceu_fmt_mplane(struct v4l2_pix_format_mplane *pix) +{ + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + return false; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + return true; + default: + return false; + } +} + +/* --- CEU HW operations --- */ + +static void ceu_write(struct ceu_device *priv, unsigned int reg_offs, u32 data) +{ + iowrite32(data, priv->base + reg_offs); +} + +static u32 ceu_read(struct ceu_device *priv, unsigned int reg_offs) +{ + return ioread32(priv->base + reg_offs); +} + +/* + * ceu_soft_reset() - Software reset the CEU interface. + * @ceu_device: CEU device. + * + * Returns 0 for success, -EIO for error. + */ +static int ceu_soft_reset(struct ceu_device *ceudev) +{ + unsigned int i; + + ceu_write(ceudev, CEU_CAPSR, CEU_CAPSR_CPKIL); + + for (i = 0; i < 100; i++) { + if (!(ceu_read(ceudev, CEU_CSTSR) & CEU_CSTRST_CPTON)) + break; + udelay(1); + } + + if (i == 100) { + dev_err(ceudev->dev, "soft reset time out\n"); + return -EIO; + } + + for (i = 0; i < 100; i++) { + if (!(ceu_read(ceudev, CEU_CAPSR) & CEU_CAPSR_CPKIL)) + return 0; + udelay(1); + } + + /* If we get here, CEU has not reset properly. */ + return -EIO; +} + +/* --- CEU Capture Operations --- */ + +/* + * ceu_hw_config() - Configure CEU interface registers. + */ +static int ceu_hw_config(struct ceu_device *ceudev) +{ + u32 camcr, cdocr, cfzsr, cdwdr, capwr; + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + struct ceu_subdev *ceu_sd = ceudev->sd; + struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt; + unsigned int mbus_flags = ceu_sd->mbus_flags; + + /* Start configuring CEU registers */ + ceu_write(ceudev, CEU_CAIFR, 0); + ceu_write(ceudev, CEU_CFWCR, 0); + ceu_write(ceudev, CEU_CRCNTR, 0); + ceu_write(ceudev, CEU_CRCMPR, 0); + + /* Set the frame capture period for both image capture and data sync. */ + capwr = (pix->height << 16) | pix->width * mbus_fmt->bpp / 8; + + /* + * Swap input data endianness by default. + * In data fetch mode bytes are received in chunks of 8 bytes. + * D0, D1, D2, D3, D4, D5, D6, D7 (D0 received first) + * The data is however by default written to memory in reverse order: + * D7, D6, D5, D4, D3, D2, D1, D0 (D7 written to lowest byte) + * + * Use CEU_CDOCR[2:0] to swap data ordering. + */ + cdocr = CEU_CDOCR_SWAP_ENDIANNESS; + + /* + * Configure CAMCR and CDOCR: + * match input components ordering with memory output format and + * handle downsampling to YUV420. + * + * If the memory output planar format is 'swapped' (Cr before Cb) and + * input format is not, use the swapped version of CAMCR.DTARY. + * + * If the memory output planar format is not 'swapped' (Cb before Cr) + * and input format is, use the swapped version of CAMCR.DTARY. + * + * CEU by default downsample to planar YUV420 (CDCOR[4] = 0). + * If output is planar YUV422 set CDOCR[4] = 1 + * + * No downsample for data fetch sync mode. + */ + switch (pix->pixelformat) { + /* Data fetch sync mode */ + case V4L2_PIX_FMT_YUYV: + /* TODO: handle YUYV permutations through DTARY bits. */ + camcr = CEU_CAMCR_JPEG; + cdocr |= CEU_CDOCR_NO_DOWSAMPLE; + cfzsr = (pix->height << 16) | pix->width; + cdwdr = pix->plane_fmt[0].bytesperline; + break; + + /* Non-swapped planar image capture mode. */ + case V4L2_PIX_FMT_NV16: + cdocr |= CEU_CDOCR_NO_DOWSAMPLE; + /* fall-through */ + case V4L2_PIX_FMT_NV12: + if (mbus_fmt->swapped) + camcr = mbus_fmt->fmt_order_swap; + else + camcr = mbus_fmt->fmt_order; + + cfzsr = (pix->height << 16) | pix->width; + cdwdr = pix->width; + break; + + /* Swapped planar image capture mode. */ + case V4L2_PIX_FMT_NV61: + cdocr |= CEU_CDOCR_NO_DOWSAMPLE; + /* fall-through */ + case V4L2_PIX_FMT_NV21: + if (mbus_fmt->swapped) + camcr = mbus_fmt->fmt_order; + else + camcr = mbus_fmt->fmt_order_swap; + + cfzsr = (pix->height << 16) | pix->width; + cdwdr = pix->width; + break; + + default: + return -EINVAL; + } + + camcr |= mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? 1 << 1 : 0; + camcr |= mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? 1 << 0 : 0; + + /* TODO: handle 16 bit bus width with DTIF bit in CAMCR */ + ceu_write(ceudev, CEU_CAMCR, camcr); + ceu_write(ceudev, CEU_CDOCR, cdocr); + ceu_write(ceudev, CEU_CAPCR, CEU_CAPCR_BUS_WIDTH256); + + /* + * TODO: make CAMOR offsets configurable. + * CAMOR wants to know the number of blanks between a VS/HS signal + * and valid data. This value should actually come from the sensor... + */ + ceu_write(ceudev, CEU_CAMOR, 0); + + /* TODO: 16 bit bus width require re-calculation of cdwdr and cfzsr */ + ceu_write(ceudev, CEU_CAPWR, capwr); + ceu_write(ceudev, CEU_CFSZR, cfzsr); + ceu_write(ceudev, CEU_CDWDR, cdwdr); + + return 0; +} + +/* + * ceu_capture() - Trigger start of a capture sequence. + * + * Program the CEU DMA registers with addresses where to transfer image data. + */ +static int ceu_capture(struct ceu_device *ceudev) +{ + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + dma_addr_t phys_addr_top; + + phys_addr_top = + vb2_dma_contig_plane_dma_addr(&ceudev->active->vb2_buf, 0); + ceu_write(ceudev, CEU_CDAYR, phys_addr_top); + + /* Ignore CbCr plane for non multi-planar image formats. */ + if (ceu_fmt_mplane(pix)) { + phys_addr_top = + vb2_dma_contig_plane_dma_addr(&ceudev->active->vb2_buf, + 1); + ceu_write(ceudev, CEU_CDACR, phys_addr_top); + } + + /* + * Trigger new capture start: once for each frame, as we work in + * one-frame capture mode. + */ + ceu_write(ceudev, CEU_CAPSR, CEU_CAPSR_CE); + + return 0; +} + +static irqreturn_t ceu_irq(int irq, void *data) +{ + struct ceu_device *ceudev = data; + struct vb2_v4l2_buffer *vbuf; + struct ceu_buffer *buf; + u32 status; + + /* Clean interrupt status. */ + status = ceu_read(ceudev, CEU_CETCR); + ceu_write(ceudev, CEU_CETCR, ~ceudev->irq_mask); + + /* Unexpected interrupt. */ + if (!(status & CEU_CEIER_MASK)) + return IRQ_NONE; + + spin_lock(&ceudev->lock); + + /* Stale interrupt from a released buffer, ignore it. */ + vbuf = ceudev->active; + if (!vbuf) { + spin_unlock(&ceudev->lock); + return IRQ_HANDLED; + } + + /* + * When a VBP interrupt occurs, no capture end interrupt will occur + * and the image of that frame is not captured correctly. + */ + if (status & CEU_CEIER_VBP) { + dev_err(ceudev->dev, "VBP interrupt: abort capture\n"); + goto error_irq_out; + } + + /* Prepare to return the 'previous' buffer. */ + vbuf->vb2_buf.timestamp = ktime_get_ns(); + vbuf->sequence = ceudev->sequence++; + vbuf->field = ceudev->field; + + /* Prepare a new 'active' buffer and trigger a new capture. */ + if (!list_empty(&ceudev->capture)) { + buf = list_first_entry(&ceudev->capture, struct ceu_buffer, + queue); + list_del(&buf->queue); + ceudev->active = &buf->vb; + + ceu_capture(ceudev); + } + + /* Return the 'previous' buffer. */ + vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); + + spin_unlock(&ceudev->lock); + + return IRQ_HANDLED; + +error_irq_out: + /* Return the 'previous' buffer and all queued ones. */ + vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_ERROR); + + list_for_each_entry(buf, &ceudev->capture, queue) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + + spin_unlock(&ceudev->lock); + + return IRQ_HANDLED; +} + +/* --- CEU Videobuf2 operations --- */ + +static void ceu_update_plane_sizes(struct v4l2_plane_pix_format *plane, + unsigned int bpl, unsigned int szimage) +{ + memset(plane, 0, sizeof(*plane)); + + plane->sizeimage = szimage; + if (plane->bytesperline < bpl || plane->bytesperline > CEU_MAX_BPL) + plane->bytesperline = bpl; +} + +/* + * ceu_calc_plane_sizes() - Fill per-plane 'struct v4l2_plane_pix_format' + * information according to the currently configured + * pixel format. + * @ceu_device: CEU device. + * @ceu_fmt: Active image format. + * @pix: Pixel format information (store line width and image sizes) + */ +static void ceu_calc_plane_sizes(struct ceu_device *ceudev, + const struct ceu_fmt *ceu_fmt, + struct v4l2_pix_format_mplane *pix) +{ + unsigned int bpl, szimage; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + pix->num_planes = 1; + bpl = pix->width * ceu_fmt->bpp / 8; + szimage = pix->height * bpl; + ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage); + break; + + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + pix->num_planes = 2; + bpl = pix->width; + szimage = pix->height * pix->width; + ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage); + ceu_update_plane_sizes(&pix->plane_fmt[1], bpl, szimage / 2); + break; + + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + default: + pix->num_planes = 2; + bpl = pix->width; + szimage = pix->height * pix->width; + ceu_update_plane_sizes(&pix->plane_fmt[0], bpl, szimage); + ceu_update_plane_sizes(&pix->plane_fmt[1], bpl, szimage); + break; + } +} + +/* + * ceu_vb2_setup() - is called to check whether the driver can accept the + * requested number of buffers and to fill in plane sizes + * for the current frame format, if required. + */ +static int ceu_vb2_setup(struct vb2_queue *vq, unsigned int *count, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vq); + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + unsigned int i; + + /* num_planes is set: just check plane sizes. */ + if (*num_planes) { + for (i = 0; i < pix->num_planes; i++) + if (sizes[i] < pix->plane_fmt[i].sizeimage) + return -EINVAL; + + return 0; + } + + /* num_planes not set: called from REQBUFS, just set plane sizes. */ + *num_planes = pix->num_planes; + for (i = 0; i < pix->num_planes; i++) + sizes[i] = pix->plane_fmt[i].sizeimage; + + return 0; +} + +static void ceu_vb2_queue(struct vb2_buffer *vb) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct ceu_buffer *buf = vb2_to_ceu(vbuf); + unsigned long irqflags; + + spin_lock_irqsave(&ceudev->lock, irqflags); + list_add_tail(&buf->queue, &ceudev->capture); + spin_unlock_irqrestore(&ceudev->lock, irqflags); +} + +static int ceu_vb2_prepare(struct vb2_buffer *vb) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_pix_format_mplane *pix = &ceudev->v4l2_pix; + unsigned int i; + + for (i = 0; i < pix->num_planes; i++) { + if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) { + dev_err(ceudev->dev, + "Plane size too small (%lu < %u)\n", + vb2_plane_size(vb, i), + pix->plane_fmt[i].sizeimage); + return -EINVAL; + } + + vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage); + } + + return 0; +} + +static int ceu_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vq); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + struct ceu_buffer *buf; + unsigned long irqflags; + int ret; + + /* Program the CEU interface according to the CEU image format. */ + ret = ceu_hw_config(ceudev); + if (ret) + goto error_return_bufs; + + ret = v4l2_subdev_call(v4l2_sd, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) { + dev_dbg(ceudev->dev, + "Subdevice failed to start streaming: %d\n", ret); + goto error_return_bufs; + } + + spin_lock_irqsave(&ceudev->lock, irqflags); + ceudev->sequence = 0; + + /* Grab the first available buffer and trigger the first capture. */ + buf = list_first_entry(&ceudev->capture, struct ceu_buffer, + queue); + if (!buf) { + spin_unlock_irqrestore(&ceudev->lock, irqflags); + dev_dbg(ceudev->dev, + "No buffer available for capture.\n"); + goto error_stop_sensor; + } + + list_del(&buf->queue); + ceudev->active = &buf->vb; + + /* Clean and program interrupts for first capture. */ + ceu_write(ceudev, CEU_CETCR, ~ceudev->irq_mask); + ceu_write(ceudev, CEU_CEIER, CEU_CEIER_MASK); + + ceu_capture(ceudev); + + spin_unlock_irqrestore(&ceudev->lock, irqflags); + + return 0; + +error_stop_sensor: + v4l2_subdev_call(v4l2_sd, video, s_stream, 0); + +error_return_bufs: + spin_lock_irqsave(&ceudev->lock, irqflags); + list_for_each_entry(buf, &ceudev->capture, queue) + vb2_buffer_done(&ceudev->active->vb2_buf, + VB2_BUF_STATE_QUEUED); + ceudev->active = NULL; + spin_unlock_irqrestore(&ceudev->lock, irqflags); + + return ret; +} + +static void ceu_stop_streaming(struct vb2_queue *vq) +{ + struct ceu_device *ceudev = vb2_get_drv_priv(vq); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + struct ceu_buffer *buf; + unsigned long irqflags; + + /* Clean and disable interrupt sources. */ + ceu_write(ceudev, CEU_CETCR, + ceu_read(ceudev, CEU_CETCR) & ceudev->irq_mask); + ceu_write(ceudev, CEU_CEIER, CEU_CEIER_MASK); + + v4l2_subdev_call(v4l2_sd, video, s_stream, 0); + + spin_lock_irqsave(&ceudev->lock, irqflags); + if (ceudev->active) { + vb2_buffer_done(&ceudev->active->vb2_buf, + VB2_BUF_STATE_ERROR); + ceudev->active = NULL; + } + + /* Release all queued buffers. */ + list_for_each_entry(buf, &ceudev->capture, queue) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + INIT_LIST_HEAD(&ceudev->capture); + + spin_unlock_irqrestore(&ceudev->lock, irqflags); + + ceu_soft_reset(ceudev); +} + +static const struct vb2_ops ceu_vb2_ops = { + .queue_setup = ceu_vb2_setup, + .buf_queue = ceu_vb2_queue, + .buf_prepare = ceu_vb2_prepare, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = ceu_start_streaming, + .stop_streaming = ceu_stop_streaming, +}; + +/* --- CEU image formats handling --- */ + +/* + * ceu_try_fmt() - test format on CEU and sensor + * @ceudev: The CEU device. + * @v4l2_fmt: format to test. + * + * Returns 0 for success, < 0 for errors. + */ +static int ceu_try_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt) +{ + struct ceu_subdev *ceu_sd = ceudev->sd; + struct v4l2_pix_format_mplane *pix = &v4l2_fmt->fmt.pix_mp; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + struct v4l2_subdev_pad_config pad_cfg; + const struct ceu_fmt *ceu_fmt; + int ret; + + struct v4l2_subdev_format sd_format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + break; + + default: + pix->pixelformat = V4L2_PIX_FMT_NV16; + break; + } + + ceu_fmt = get_ceu_fmt_from_fourcc(pix->pixelformat); + + /* CFSZR requires height and width to be 4-pixel aligned. */ + v4l_bound_align_image(&pix->width, 2, CEU_MAX_WIDTH, 4, + &pix->height, 4, CEU_MAX_HEIGHT, 4, 0); + + /* + * Set format on sensor sub device: bus format used to produce memory + * format is selected at initialization time. + */ + v4l2_fill_mbus_format_mplane(&sd_format.format, pix); + ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, &pad_cfg, &sd_format); + if (ret) + return ret; + + /* Apply size returned by sensor as the CEU can't scale. */ + v4l2_fill_pix_format_mplane(pix, &sd_format.format); + + /* Calculate per-plane sizes based on image format. */ + ceu_calc_plane_sizes(ceudev, ceu_fmt, pix); + + return 0; +} + +/* + * ceu_set_fmt() - Apply the supplied format to both sensor and CEU + */ +static int ceu_set_fmt(struct ceu_device *ceudev, struct v4l2_format *v4l2_fmt) +{ + struct ceu_subdev *ceu_sd = ceudev->sd; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + int ret; + + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + ret = ceu_try_fmt(ceudev, v4l2_fmt); + if (ret) + return ret; + + v4l2_fill_mbus_format_mplane(&format.format, &v4l2_fmt->fmt.pix_mp); + ret = v4l2_subdev_call(v4l2_sd, pad, set_fmt, NULL, &format); + if (ret) + return ret; + + ceudev->v4l2_pix = v4l2_fmt->fmt.pix_mp; + ceudev->field = V4L2_FIELD_NONE; + + return 0; +} + +/* + * ceu_set_default_fmt() - Apply default NV16 memory output format with VGA + * sizes. + */ +static int ceu_set_default_fmt(struct ceu_device *ceudev) +{ + int ret; + + struct v4l2_format v4l2_fmt = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .fmt.pix_mp = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .field = V4L2_FIELD_NONE, + .pixelformat = V4L2_PIX_FMT_NV16, + .num_planes = 2, + .plane_fmt = { + [0] = { + .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, + .bytesperline = VGA_WIDTH * 2, + }, + [1] = { + .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2, + .bytesperline = VGA_WIDTH * 2, + }, + }, + }, + }; + + ret = ceu_try_fmt(ceudev, &v4l2_fmt); + if (ret) + return ret; + + ceudev->v4l2_pix = v4l2_fmt.fmt.pix_mp; + ceudev->field = V4L2_FIELD_NONE; + + return 0; +} + +/* + * ceu_init_mbus_fmt() - Query sensor for supported formats and initialize + * CEU media bus format used to produce memory formats. + * + * Find out if sensor can produce a permutation of 8-bits YUYV bus format. + * From a single 8-bits YUYV bus format the CEU can produce several memory + * output formats: + * - NV[12|21|16|61] through image fetch mode; + * - YUYV422 if sensor provides YUYV422 + * + * TODO: Other YUYV422 permutations through data fetch sync mode and DTARY + * TODO: Binary data (eg. JPEG) and raw formats through data fetch sync mode + */ +static int ceu_init_mbus_fmt(struct ceu_device *ceudev) +{ + struct ceu_subdev *ceu_sd = ceudev->sd; + struct ceu_mbus_fmt *mbus_fmt = &ceu_sd->mbus_fmt; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + bool yuyv_bus_fmt = false; + + struct v4l2_subdev_mbus_code_enum sd_mbus_fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = 0, + }; + + /* Find out if sensor can produce any permutation of 8-bits YUYV422. */ + while (!yuyv_bus_fmt && + !v4l2_subdev_call(v4l2_sd, pad, enum_mbus_code, + NULL, &sd_mbus_fmt)) { + switch (sd_mbus_fmt.code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + yuyv_bus_fmt = true; + break; + default: + /* + * Only support 8-bits YUYV bus formats at the moment; + * + * TODO: add support for binary formats (data sync + * fetch mode). + */ + break; + } + + sd_mbus_fmt.index++; + } + + if (!yuyv_bus_fmt) + return -ENXIO; + + /* + * Save the first encountered YUYV format as "mbus_fmt" and use it + * to output all planar YUV422 and YUV420 (NV*) formats to memory as + * well as for data synch fetch mode (YUYV - YVYU etc. ). + */ + mbus_fmt->mbus_code = sd_mbus_fmt.code; + mbus_fmt->bps = 8; + + /* Annotate the selected bus format components ordering. */ + switch (sd_mbus_fmt.code) { + case MEDIA_BUS_FMT_YUYV8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YUYV; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YVYU; + mbus_fmt->swapped = false; + mbus_fmt->bpp = 16; + break; + + case MEDIA_BUS_FMT_YVYU8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_YVYU; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_YUYV; + mbus_fmt->swapped = true; + mbus_fmt->bpp = 16; + break; + + case MEDIA_BUS_FMT_UYVY8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_UYVY; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_VYUY; + mbus_fmt->swapped = false; + mbus_fmt->bpp = 16; + break; + + case MEDIA_BUS_FMT_VYUY8_2X8: + mbus_fmt->fmt_order = CEU_CAMCR_DTARY_8_VYUY; + mbus_fmt->fmt_order_swap = CEU_CAMCR_DTARY_8_UYVY; + mbus_fmt->swapped = true; + mbus_fmt->bpp = 16; + break; + } + + return 0; +} + +/* --- Runtime PM Handlers --- */ + +/* + * ceu_runtime_resume() - soft-reset the interface and turn sensor power on. + */ +static int __maybe_unused ceu_runtime_resume(struct device *dev) +{ + struct ceu_device *ceudev = dev_get_drvdata(dev); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + + v4l2_subdev_call(v4l2_sd, core, s_power, 1); + + ceu_soft_reset(ceudev); + + return 0; +} + +/* + * ceu_runtime_suspend() - disable capture and interrupts and soft-reset. + * Turn sensor power off. + */ +static int __maybe_unused ceu_runtime_suspend(struct device *dev) +{ + struct ceu_device *ceudev = dev_get_drvdata(dev); + struct v4l2_subdev *v4l2_sd = ceudev->sd->v4l2_sd; + + v4l2_subdev_call(v4l2_sd, core, s_power, 0); + + ceu_write(ceudev, CEU_CEIER, 0); + ceu_soft_reset(ceudev); + + return 0; +} + +/* --- File Operations --- */ + +static int ceu_open(struct file *file) +{ + struct ceu_device *ceudev = video_drvdata(file); + int ret; + + ret = v4l2_fh_open(file); + if (ret) + return ret; + + mutex_lock(&ceudev->mlock); + /* Causes soft-reset and sensor power on on first open */ + pm_runtime_get_sync(ceudev->dev); + mutex_unlock(&ceudev->mlock); + + return 0; +} + +static int ceu_release(struct file *file) +{ + struct ceu_device *ceudev = video_drvdata(file); + + vb2_fop_release(file); + + mutex_lock(&ceudev->mlock); + /* Causes soft-reset and sensor power down on last close */ + pm_runtime_put(ceudev->dev); + mutex_unlock(&ceudev->mlock); + + return 0; +} + +static const struct v4l2_file_operations ceu_fops = { + .owner = THIS_MODULE, + .open = ceu_open, + .release = ceu_release, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +/* --- Video Device IOCTLs --- */ + +static int ceu_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct ceu_device *ceudev = video_drvdata(file); + + strlcpy(cap->card, "Renesas CEU", sizeof(cap->card)); + strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:renesas-ceu-%s", dev_name(ceudev->dev)); + + return 0; +} + +static int ceu_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct ceu_fmt *fmt; + + if (f->index >= ARRAY_SIZE(ceu_fmt_list)) + return -EINVAL; + + fmt = &ceu_fmt_list[f->index]; + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int ceu_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ceu_device *ceudev = video_drvdata(file); + + return ceu_try_fmt(ceudev, f); +} + +static int ceu_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ceu_device *ceudev = video_drvdata(file); + + if (vb2_is_streaming(&ceudev->vb2_vq)) + return -EBUSY; + + return ceu_set_fmt(ceudev, f); +} + +static int ceu_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct ceu_device *ceudev = video_drvdata(file); + + f->fmt.pix_mp = ceudev->v4l2_pix; + + return 0; +} + +static int ceu_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceusd; + + if (inp->index >= ceudev->num_sd) + return -EINVAL; + + ceusd = &ceudev->subdevs[inp->index]; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->std = 0; + snprintf(inp->name, sizeof(inp->name), "Camera%u: %s", + inp->index, ceusd->v4l2_sd->name); + + return 0; +} + +static int ceu_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct ceu_device *ceudev = video_drvdata(file); + + *i = ceudev->sd_index; + + return 0; +} + +static int ceu_s_input(struct file *file, void *priv, unsigned int i) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceu_sd_old; + int ret; + + if (i >= ceudev->num_sd) + return -EINVAL; + + if (vb2_is_streaming(&ceudev->vb2_vq)) + return -EBUSY; + + if (i == ceudev->sd_index) + return 0; + + ceu_sd_old = ceudev->sd; + ceudev->sd = &ceudev->subdevs[i]; + + /* + * Make sure we can generate output image formats and apply + * default one. + */ + ret = ceu_init_mbus_fmt(ceudev); + if (ret) { + ceudev->sd = ceu_sd_old; + return -EINVAL; + } + + ret = ceu_set_default_fmt(ceudev); + if (ret) { + ceudev->sd = ceu_sd_old; + return -EINVAL; + } + + /* Now that we're sure we can use the sensor, power off the old one. */ + v4l2_subdev_call(ceu_sd_old->v4l2_sd, core, s_power, 0); + v4l2_subdev_call(ceudev->sd->v4l2_sd, core, s_power, 1); + + ceudev->sd_index = i; + + return 0; +} + +static int ceu_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct ceu_device *ceudev = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), ceudev->sd->v4l2_sd, a); +} + +static int ceu_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct ceu_device *ceudev = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), ceudev->sd->v4l2_sd, a); +} + +static int ceu_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceu_sd = ceudev->sd; + const struct ceu_fmt *ceu_fmt; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + int ret; + + struct v4l2_subdev_frame_size_enum fse = { + .code = ceu_sd->mbus_fmt.mbus_code, + .index = fsize->index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + /* Just check if user supplied pixel format is supported. */ + ceu_fmt = get_ceu_fmt_from_fourcc(fsize->pixel_format); + if (!ceu_fmt) + return -EINVAL; + + ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_size, + NULL, &fse); + if (ret) + return ret; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = CEU_W_MAX(fse.max_width); + fsize->discrete.height = CEU_H_MAX(fse.max_height); + + return 0; +} + +static int ceu_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct ceu_device *ceudev = video_drvdata(file); + struct ceu_subdev *ceu_sd = ceudev->sd; + const struct ceu_fmt *ceu_fmt; + struct v4l2_subdev *v4l2_sd = ceu_sd->v4l2_sd; + int ret; + + struct v4l2_subdev_frame_interval_enum fie = { + .code = ceu_sd->mbus_fmt.mbus_code, + .index = fival->index, + .width = fival->width, + .height = fival->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + /* Just check if user supplied pixel format is supported. */ + ceu_fmt = get_ceu_fmt_from_fourcc(fival->pixel_format); + if (!ceu_fmt) + return -EINVAL; + + ret = v4l2_subdev_call(v4l2_sd, pad, enum_frame_interval, NULL, + &fie); + if (ret) + return ret; + + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = fie.interval; + + return 0; +} + +static const struct v4l2_ioctl_ops ceu_ioctl_ops = { + .vidioc_querycap = ceu_querycap, + + .vidioc_enum_fmt_vid_cap_mplane = ceu_enum_fmt_vid_cap, + .vidioc_try_fmt_vid_cap_mplane = ceu_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap_mplane = ceu_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap_mplane = ceu_g_fmt_vid_cap, + + .vidioc_enum_input = ceu_enum_input, + .vidioc_g_input = ceu_g_input, + .vidioc_s_input = ceu_s_input, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_g_parm = ceu_g_parm, + .vidioc_s_parm = ceu_s_parm, + .vidioc_enum_framesizes = ceu_enum_framesizes, + .vidioc_enum_frameintervals = ceu_enum_frameintervals, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * ceu_vdev_release() - release CEU video device memory when last reference + * to this driver is closed + */ +static void ceu_vdev_release(struct video_device *vdev) +{ + struct ceu_device *ceudev = video_get_drvdata(vdev); + + kfree(ceudev); +} + +static int ceu_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *v4l2_sd, + struct v4l2_async_subdev *asd) +{ + struct v4l2_device *v4l2_dev = notifier->v4l2_dev; + struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev); + struct ceu_subdev *ceu_sd = to_ceu_subdev(asd); + + ceu_sd->v4l2_sd = v4l2_sd; + ceudev->num_sd++; + + return 0; +} + +static int ceu_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct v4l2_device *v4l2_dev = notifier->v4l2_dev; + struct ceu_device *ceudev = v4l2_to_ceu(v4l2_dev); + struct video_device *vdev = &ceudev->vdev; + struct vb2_queue *q = &ceudev->vb2_vq; + struct v4l2_subdev *v4l2_sd; + int ret; + + /* Initialize vb2 queue. */ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->drv_priv = ceudev; + q->ops = &ceu_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct ceu_buffer); + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + q->lock = &ceudev->mlock; + q->dev = ceudev->v4l2_dev.dev; + + ret = vb2_queue_init(q); + if (ret) + return ret; + + /* + * Make sure at least one sensor is primary and use it to initialize + * ceu formats. + */ + if (!ceudev->sd) { + ceudev->sd = &ceudev->subdevs[0]; + ceudev->sd_index = 0; + } + + v4l2_sd = ceudev->sd->v4l2_sd; + + ret = ceu_init_mbus_fmt(ceudev); + if (ret) + return ret; + + ret = ceu_set_default_fmt(ceudev); + if (ret) + return ret; + + /* Register the video device. */ + strncpy(vdev->name, DRIVER_NAME, strlen(DRIVER_NAME)); + vdev->v4l2_dev = v4l2_dev; + vdev->lock = &ceudev->mlock; + vdev->queue = &ceudev->vb2_vq; + vdev->ctrl_handler = v4l2_sd->ctrl_handler; + vdev->fops = &ceu_fops; + vdev->ioctl_ops = &ceu_ioctl_ops; + vdev->release = ceu_vdev_release; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_STREAMING; + video_set_drvdata(vdev, ceudev); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + v4l2_err(vdev->v4l2_dev, + "video_register_device failed: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct v4l2_async_notifier_operations ceu_notify_ops = { + .bound = ceu_notify_bound, + .complete = ceu_notify_complete, +}; + +/* + * ceu_init_async_subdevs() - Initialize CEU subdevices and async_subdevs in + * ceu device. Both DT and platform data parsing use + * this routine. + * + * Returns 0 for success, -ENOMEM for failure. + */ +static int ceu_init_async_subdevs(struct ceu_device *ceudev, unsigned int n_sd) +{ + /* Reserve memory for 'n_sd' ceu_subdev descriptors. */ + ceudev->subdevs = devm_kcalloc(ceudev->dev, n_sd, + sizeof(*ceudev->subdevs), GFP_KERNEL); + if (!ceudev->subdevs) + return -ENOMEM; + + /* + * Reserve memory for 'n_sd' pointers to async_subdevices. + * ceudev->asds members will point to &ceu_subdev.asd + */ + ceudev->asds = devm_kcalloc(ceudev->dev, n_sd, + sizeof(*ceudev->asds), GFP_KERNEL); + if (!ceudev->asds) + return -ENOMEM; + + ceudev->sd = NULL; + ceudev->sd_index = 0; + ceudev->num_sd = 0; + + return 0; +} + +/* + * ceu_parse_platform_data() - Initialize async_subdevices using platform + * device provided data. + */ +static int ceu_parse_platform_data(struct ceu_device *ceudev, + const struct ceu_platform_data *pdata) +{ + const struct ceu_async_subdev *async_sd; + struct ceu_subdev *ceu_sd; + unsigned int i; + int ret; + + if (pdata->num_subdevs == 0) + return -ENODEV; + + ret = ceu_init_async_subdevs(ceudev, pdata->num_subdevs); + if (ret) + return ret; + + for (i = 0; i < pdata->num_subdevs; i++) { + /* Setup the ceu subdevice and the async subdevice. */ + async_sd = &pdata->subdevs[i]; + ceu_sd = &ceudev->subdevs[i]; + + INIT_LIST_HEAD(&ceu_sd->asd.list); + + ceu_sd->mbus_flags = async_sd->flags; + ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_I2C; + ceu_sd->asd.match.i2c.adapter_id = async_sd->i2c_adapter_id; + ceu_sd->asd.match.i2c.address = async_sd->i2c_address; + + ceudev->asds[i] = &ceu_sd->asd; + } + + return pdata->num_subdevs; +} + +/* + * ceu_parse_dt() - Initialize async_subdevs parsing device tree graph. + */ +static int ceu_parse_dt(struct ceu_device *ceudev) +{ + struct device_node *of = ceudev->dev->of_node; + struct v4l2_fwnode_endpoint fw_ep; + struct ceu_subdev *ceu_sd; + struct device_node *ep; + unsigned int i; + int num_ep; + int ret; + + num_ep = of_graph_get_endpoint_count(of); + if (!num_ep) + return -ENODEV; + + ret = ceu_init_async_subdevs(ceudev, num_ep); + if (ret) + return ret; + + for (i = 0; i < num_ep; i++) { + ep = of_graph_get_endpoint_by_regs(of, 0, i); + if (!ep) { + dev_err(ceudev->dev, + "No subdevice connected on endpoint %u.\n", i); + ret = -ENODEV; + goto error_put_node; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &fw_ep); + if (ret) { + dev_err(ceudev->dev, + "Unable to parse endpoint #%u.\n", i); + goto error_put_node; + } + + if (fw_ep.bus_type != V4L2_MBUS_PARALLEL) { + dev_err(ceudev->dev, + "Only parallel input supported.\n"); + ret = -EINVAL; + goto error_put_node; + } + + /* Setup the ceu subdevice and the async subdevice. */ + ceu_sd = &ceudev->subdevs[i]; + INIT_LIST_HEAD(&ceu_sd->asd.list); + + ceu_sd->mbus_flags = fw_ep.bus.parallel.flags; + ceu_sd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + ceu_sd->asd.match.fwnode = + fwnode_graph_get_remote_port_parent( + of_fwnode_handle(ep)); + + ceudev->asds[i] = &ceu_sd->asd; + of_node_put(ep); + } + + return num_ep; + +error_put_node: + of_node_put(ep); + return ret; +} + +/* + * struct ceu_data - Platform specific CEU data + * @irq_mask: CETCR mask with all interrupt sources enabled. The mask differs + * between SH4 and RZ platforms. + */ +struct ceu_data { + u32 irq_mask; +}; + +static const struct ceu_data ceu_data_rz = { + .irq_mask = CEU_CETCR_ALL_IRQS_RZ, +}; + +static const struct ceu_data ceu_data_sh4 = { + .irq_mask = CEU_CETCR_ALL_IRQS_SH4, +}; + +#if IS_ENABLED(CONFIG_OF) +static const struct of_device_id ceu_of_match[] = { + { .compatible = "renesas,r7s72100-ceu", .data = &ceu_data_rz }, + { } +}; +MODULE_DEVICE_TABLE(of, ceu_of_match); +#endif + +static int ceu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct ceu_data *ceu_data; + struct ceu_device *ceudev; + struct resource *res; + unsigned int irq; + int num_subdevs; + int ret; + + ceudev = kzalloc(sizeof(*ceudev), GFP_KERNEL); + if (!ceudev) + return -ENOMEM; + + platform_set_drvdata(pdev, ceudev); + ceudev->dev = dev; + + INIT_LIST_HEAD(&ceudev->capture); + spin_lock_init(&ceudev->lock); + mutex_init(&ceudev->mlock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ceudev->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ceudev->base)) { + ret = PTR_ERR(ceudev->base); + goto error_free_ceudev; + } + + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "Failed to get irq: %d\n", ret); + goto error_free_ceudev; + } + irq = ret; + + ret = devm_request_irq(dev, irq, ceu_irq, + 0, dev_name(dev), ceudev); + if (ret) { + dev_err(&pdev->dev, "Unable to request CEU interrupt.\n"); + goto error_free_ceudev; + } + + pm_runtime_enable(dev); + + ret = v4l2_device_register(dev, &ceudev->v4l2_dev); + if (ret) + goto error_pm_disable; + + if (IS_ENABLED(CONFIG_OF) && dev->of_node) { + ceu_data = of_match_device(ceu_of_match, dev)->data; + num_subdevs = ceu_parse_dt(ceudev); + } else if (dev->platform_data) { + /* Assume SH4 if booting with platform data. */ + ceu_data = &ceu_data_sh4; + num_subdevs = ceu_parse_platform_data(ceudev, + dev->platform_data); + } else { + num_subdevs = -EINVAL; + } + + if (num_subdevs < 0) { + ret = num_subdevs; + goto error_v4l2_unregister; + } + ceudev->irq_mask = ceu_data->irq_mask; + + ceudev->notifier.v4l2_dev = &ceudev->v4l2_dev; + ceudev->notifier.subdevs = ceudev->asds; + ceudev->notifier.num_subdevs = num_subdevs; + ceudev->notifier.ops = &ceu_notify_ops; + ret = v4l2_async_notifier_register(&ceudev->v4l2_dev, + &ceudev->notifier); + if (ret) + goto error_v4l2_unregister; + + dev_info(dev, "Renesas Capture Engine Unit %s\n", dev_name(dev)); + + return 0; + +error_v4l2_unregister: + v4l2_device_unregister(&ceudev->v4l2_dev); +error_pm_disable: + pm_runtime_disable(dev); +error_free_ceudev: + kfree(ceudev); + + return ret; +} + +static int ceu_remove(struct platform_device *pdev) +{ + struct ceu_device *ceudev = platform_get_drvdata(pdev); + + pm_runtime_disable(ceudev->dev); + + v4l2_async_notifier_unregister(&ceudev->notifier); + + v4l2_device_unregister(&ceudev->v4l2_dev); + + video_unregister_device(&ceudev->vdev); + + return 0; +} + +static const struct dev_pm_ops ceu_pm_ops = { + SET_RUNTIME_PM_OPS(ceu_runtime_suspend, + ceu_runtime_resume, + NULL) +}; + +static struct platform_driver ceu_driver = { + .driver = { + .name = DRIVER_NAME, + .pm = &ceu_pm_ops, + .of_match_table = of_match_ptr(ceu_of_match), + }, + .probe = ceu_probe, + .remove = ceu_remove, +}; + +module_platform_driver(ceu_driver); + +MODULE_DESCRIPTION("Renesas CEU camera driver"); +MODULE_AUTHOR("Jacopo Mondi <jacopo+renesas@jmondi.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c index 49cacc7a48d1..fa1ba98c96dc 100644 --- a/drivers/media/platform/rockchip/rga/rga-buf.c +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -140,7 +140,8 @@ void rga_buf_map(struct vb2_buffer *vb) address = sg_phys(sgl); for (p = 0; p < len; p++) { - dma_addr_t phys = address + (p << PAGE_SHIFT); + dma_addr_t phys = address + + ((dma_addr_t)p << PAGE_SHIFT); pages[mapped_size + p] = phys; } diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 89296de9cf4a..d508a8ba6f89 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -207,7 +207,7 @@ static int rga_setup_ctrls(struct rga_ctx *ctx) return 0; } -struct rga_fmt formats[] = { +static struct rga_fmt formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB32, .color_swap = RGA_COLOR_RB_SWAP, diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c index 437395a61065..9ab8e7ee2e1e 100644 --- a/drivers/media/platform/s3c-camif/camif-capture.c +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -1256,16 +1256,17 @@ static void __camif_subdev_try_format(struct camif_dev *camif, { const struct s3c_camif_variant *variant = camif->variant; const struct vp_pix_limits *pix_lim; - int i = ARRAY_SIZE(camif_mbus_formats); + unsigned int i; /* FIXME: constraints against codec or preview path ? */ pix_lim = &variant->vp_pix_limits[VP_CODEC]; - while (i-- >= 0) + for (i = 0; i < ARRAY_SIZE(camif_mbus_formats); i++) if (camif_mbus_formats[i] == mf->code) break; - mf->code = camif_mbus_formats[i]; + if (i == ARRAY_SIZE(camif_mbus_formats)) + mf->code = camif_mbus_formats[0]; if (pad == CAMIF_SD_PAD_SINK) { v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH, diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h new file mode 100644 index 000000000000..fadd9139b489 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Register definition file for Samsung MFC V10.x Interface (FIMV) driver + * + */ + +#ifndef _REGS_MFC_V10_H +#define _REGS_MFC_V10_H + +#include <linux/sizes.h> +#include "regs-mfc-v8.h" + +/* MFCv10 register definitions*/ +#define S5P_FIMV_MFC_CLOCK_OFF_V10 0x7120 +#define S5P_FIMV_MFC_STATE_V10 0x7124 +#define S5P_FIMV_D_STATIC_BUFFER_ADDR_V10 0xF570 +#define S5P_FIMV_D_STATIC_BUFFER_SIZE_V10 0xF574 +#define S5P_FIMV_E_NUM_T_LAYER_V10 0xFBAC +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10 0xFBB0 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER1_V10 0xFBB4 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER2_V10 0xFBB8 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER3_V10 0xFBBC +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER4_V10 0xFBC0 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER5_V10 0xFBC4 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER6_V10 0xFBC8 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10 0xFD18 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER1_V10 0xFD1C +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER2_V10 0xFD20 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER3_V10 0xFD24 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER4_V10 0xFD28 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER5_V10 0xFD2C +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER6_V10 0xFD30 +#define S5P_FIMV_E_HEVC_OPTIONS_V10 0xFDD4 +#define S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10 0xFDD8 +#define S5P_FIMV_E_HEVC_CHROMA_QP_OFFSET_V10 0xFDDC +#define S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10 0xFDE0 +#define S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10 0xFDE4 +#define S5P_FIMV_E_HEVC_NAL_CONTROL_V10 0xFDE8 + +/* MFCv10 Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V10 (30 * SZ_1K) +#define MFC_H264_DEC_CTX_BUF_SIZE_V10 (2 * SZ_1M) +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V10 (20 * SZ_1K) +#define MFC_H264_ENC_CTX_BUF_SIZE_V10 (100 * SZ_1K) +#define MFC_HEVC_ENC_CTX_BUF_SIZE_V10 (30 * SZ_1K) +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V10 (15 * SZ_1K) + +/* MFCv10 variant defines */ +#define MAX_FW_SIZE_V10 (SZ_1M) +#define MAX_CPB_SIZE_V10 (3 * SZ_1M) +#define MFC_VERSION_V10 0xA0 +#define MFC_NUM_PORTS_V10 1 + +/* MFCv10 codec defines*/ +#define S5P_FIMV_CODEC_HEVC_DEC 17 +#define S5P_FIMV_CODEC_VP9_DEC 18 +#define S5P_FIMV_CODEC_HEVC_ENC 26 + +/* Decoder buffer size for MFC v10 */ +#define DEC_VP9_STATIC_BUFFER_SIZE 20480 + +/* Encoder buffer size for MFC v10.0 */ +#define ENC_V100_BASE_SIZE(x, y) \ + (((x + 3) * (y + 3) * 8) \ + + ((y * 64) + 1280) * DIV_ROUND_UP(x, 8)) + +#define ENC_V100_H264_ME_SIZE(x, y) \ + (ENC_V100_BASE_SIZE(x, y) \ + + (DIV_ROUND_UP(x * y, 64) * 32)) + +#define ENC_V100_MPEG4_ME_SIZE(x, y) \ + (ENC_V100_BASE_SIZE(x, y) \ + + (DIV_ROUND_UP(x * y, 128) * 16)) + +#define ENC_V100_VP8_ME_SIZE(x, y) \ + ENC_V100_BASE_SIZE(x, y) + +#define ENC_V100_HEVC_ME_SIZE(x, y) \ + (((x + 3) * (y + 3) * 32) \ + + ((y * 128) + 1280) * DIV_ROUND_UP(x, 4)) + +#endif /*_REGS_MFC_V10_H*/ + diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h index 75f5f7511d72..bd639ae71023 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h @@ -17,6 +17,7 @@ /* Additional registers for v8 */ #define S5P_FIMV_D_MVC_NUM_VIEWS_V8 0xf104 +#define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8 0xf108 #define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8 0xf144 #define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8 0xf148 #define S5P_FIMV_D_MV_BUFFER_SIZE_V8 0xf150 @@ -84,6 +85,7 @@ #define S5P_FIMV_E_VBV_BUFFER_SIZE_V8 0xf78c #define S5P_FIMV_E_VBV_INIT_DELAY_V8 0xf790 +#define S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8 0xf894 #define S5P_FIMV_E_ASPECT_RATIO_V8 0xfb4c #define S5P_FIMV_E_EXTENDED_SAR_V8 0xfb50 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index d5b94fc0040e..a80251ed3143 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -526,6 +526,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, dev); ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, dev); + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + get_min_scratch_buf_size, dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; else @@ -1607,6 +1609,29 @@ static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { .num_clocks = 3, }; +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V10, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V10, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V10, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V10, + .hevc_enc_ctx = MFC_HEVC_ENC_CTX_BUF_SIZE_V10, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V10, +}; + +static struct s5p_mfc_buf_size buf_size_v10 = { + .fw = MAX_FW_SIZE_V10, + .cpb = MAX_CPB_SIZE_V10, + .priv = &mfc_buf_size_v10, +}; + +static struct s5p_mfc_variant mfc_drvdata_v10 = { + .version = MFC_VERSION_V10, + .version_bit = MFC_V10_BIT, + .port_num = MFC_NUM_PORTS_V10, + .buf_size = &buf_size_v10, + .fw_name[0] = "s5p-mfc-v10.fw", +}; + static const struct of_device_id exynos_mfc_match[] = { { .compatible = "samsung,mfc-v5", @@ -1623,6 +1648,9 @@ static const struct of_device_id exynos_mfc_match[] = { }, { .compatible = "samsung,exynos5433-mfc", .data = &mfc_drvdata_v8_5433, + }, { + .compatible = "samsung,mfc-v10", + .data = &mfc_drvdata_v10, }, {}, }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c index b1b149151d2d..7521fceb68f1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c @@ -101,6 +101,12 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VP8_DEC: codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; break; + case S5P_MFC_CODEC_HEVC_DEC: + codec_type = S5P_FIMV_CODEC_HEVC_DEC; + break; + case S5P_MFC_CODEC_VP9_DEC: + codec_type = S5P_FIMV_CODEC_VP9_DEC; + break; case S5P_MFC_CODEC_H264_ENC: codec_type = S5P_FIMV_CODEC_H264_ENC_V6; break; @@ -116,6 +122,9 @@ static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VP8_ENC: codec_type = S5P_FIMV_CODEC_VP8_ENC_V7; break; + case S5P_MFC_CODEC_HEVC_ENC: + codec_type = S5P_FIMV_CODEC_HEVC_ENC; + break; default: codec_type = S5P_FIMV_CODEC_NONE_V6; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 76119a8cc477..20442a9b9f7a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -23,7 +23,7 @@ #include <media/v4l2-ioctl.h> #include <media/videobuf2-v4l2.h> #include "regs-mfc.h" -#include "regs-mfc-v8.h" +#include "regs-mfc-v10.h" #define S5P_MFC_NAME "s5p-mfc" @@ -61,7 +61,7 @@ #define MFC_ENC_CAP_PLANE_COUNT 1 #define MFC_ENC_OUT_PLANE_COUNT 2 #define STUFF_BYTE 4 -#define MFC_MAX_CTRLS 77 +#define MFC_MAX_CTRLS 128 #define S5P_MFC_CODEC_NONE -1 #define S5P_MFC_CODEC_H264_DEC 0 @@ -72,12 +72,15 @@ #define S5P_MFC_CODEC_H263_DEC 5 #define S5P_MFC_CODEC_VC1RCV_DEC 6 #define S5P_MFC_CODEC_VP8_DEC 7 +#define S5P_MFC_CODEC_HEVC_DEC 17 +#define S5P_MFC_CODEC_VP9_DEC 18 #define S5P_MFC_CODEC_H264_ENC 20 #define S5P_MFC_CODEC_H264_MVC_ENC 21 #define S5P_MFC_CODEC_MPEG4_ENC 22 #define S5P_MFC_CODEC_H263_ENC 23 #define S5P_MFC_CODEC_VP8_ENC 24 +#define S5P_MFC_CODEC_HEVC_ENC 26 #define S5P_MFC_R2H_CMD_EMPTY 0 #define S5P_MFC_R2H_CMD_SYS_INIT_RET 1 @@ -213,6 +216,7 @@ struct s5p_mfc_buf_size_v6 { unsigned int h264_dec_ctx; unsigned int other_dec_ctx; unsigned int h264_enc_ctx; + unsigned int hevc_enc_ctx; unsigned int other_enc_ctx; }; @@ -430,6 +434,55 @@ struct s5p_mfc_vp8_enc_params { u8 profile; }; +struct s5p_mfc_hevc_enc_params { + enum v4l2_mpeg_video_hevc_profile profile; + int level; + enum v4l2_mpeg_video_h264_level level_v4l2; + u8 tier; + u32 rc_framerate; + u8 rc_min_qp; + u8 rc_max_qp; + u8 rc_lcu_dark; + u8 rc_lcu_smooth; + u8 rc_lcu_static; + u8 rc_lcu_activity; + u8 rc_frame_qp; + u8 rc_p_frame_qp; + u8 rc_b_frame_qp; + u8 max_partition_depth; + u8 num_refs_for_p; + u8 refreshtype; + u16 refreshperiod; + s32 lf_beta_offset_div2; + s32 lf_tc_offset_div2; + u8 loopfilter; + u8 loopfilter_disable; + u8 loopfilter_across; + u8 nal_control_length_filed; + u8 nal_control_user_ref; + u8 nal_control_store_ref; + u8 const_intra_period_enable; + u8 lossless_cu_enable; + u8 wavefront_enable; + u8 enable_ltr; + u8 hier_qp_enable; + enum v4l2_mpeg_video_hevc_hier_coding_type hier_qp_type; + u8 num_hier_layer; + u8 hier_qp_layer[7]; + u32 hier_bit_layer[7]; + u8 sign_data_hiding; + u8 general_pb_enable; + u8 temporal_id_enable; + u8 strong_intra_smooth; + u8 intra_pu_split_disable; + u8 tmv_prediction_disable; + u8 max_num_merge_mv; + u8 eco_mode_enable; + u8 encoding_nostartcode_enable; + u8 size_of_length_field; + u8 prepend_sps_pps_to_idr; +}; + /** * struct s5p_mfc_enc_params - general encoding parameters */ @@ -467,6 +520,7 @@ struct s5p_mfc_enc_params { struct s5p_mfc_h264_enc_params h264; struct s5p_mfc_mpeg4_enc_params mpeg4; struct s5p_mfc_vp8_enc_params vp8; + struct s5p_mfc_hevc_enc_params hevc; } codec; }; @@ -714,12 +768,20 @@ void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); #define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0) #define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0) #define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0) -#define IS_MFCV8(dev) (dev->variant->version >= 0x80 ? 1 : 0) +#define IS_MFCV8_PLUS(dev) (dev->variant->version >= 0x80 ? 1 : 0) +#define IS_MFCV10(dev) (dev->variant->version >= 0xA0 ? 1 : 0) +#define FW_HAS_E_MIN_SCRATCH_BUF(dev) (IS_MFCV10(dev)) #define MFC_V5_BIT BIT(0) #define MFC_V6_BIT BIT(1) #define MFC_V7_BIT BIT(2) #define MFC_V8_BIT BIT(3) +#define MFC_V10_BIT BIT(5) +#define MFC_V5PLUS_BITS (MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | \ + MFC_V8_BIT | MFC_V10_BIT) +#define MFC_V6PLUS_BITS (MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT | \ + MFC_V10_BIT) +#define MFC_V7PLUS_BITS (MFC_V7_BIT | MFC_V8_BIT | MFC_V10_BIT) #endif /* S5P_MFC_COMMON_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index f95cd76af537..ee7b15b335e0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -62,7 +62,7 @@ int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) if (!dev->variant->fw_name[i]) continue; err = request_firmware((const struct firmware **)&fw_blob, - dev->variant->fw_name[i], dev->v4l2_dev.dev); + dev->variant->fw_name[i], &dev->plat_dev->dev); if (!err) { dev->fw_ver = (enum s5p_mfc_fw_ver) i; break; @@ -239,6 +239,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } else mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + + if (IS_MFCV10(dev)) + mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10); + mfc_debug(2, "Will now wait for completion of firmware transfer\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware\n"); @@ -399,7 +403,7 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) s5p_mfc_clear_cmds(dev); s5p_mfc_clean_dev_int_flags(dev); /* 3. Send MFC wakeup command and wait for completion*/ - if (IS_MFCV8(dev)) + if (IS_MFCV8_PLUS(dev)) ret = s5p_mfc_v8_wait_wakeup(dev); else ret = s5p_mfc_wait_wakeup(dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 8937b0af7cb3..5cf4d9921264 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -54,7 +54,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "4:2:0 2 Planes Y/CrCb", @@ -62,7 +62,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "H264 Encoded Stream", @@ -70,8 +70,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H264_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "H264/MVC Encoded Stream", @@ -79,7 +78,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "H263 Encoded Stream", @@ -87,8 +86,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H263_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG1 Encoded Stream", @@ -96,8 +94,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG2 Encoded Stream", @@ -105,8 +102,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG4 Encoded Stream", @@ -114,8 +110,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "XviD Encoded Stream", @@ -123,8 +118,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VC1 Encoded Stream", @@ -132,8 +126,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VC1_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VC1 RCV Encoded Stream", @@ -141,8 +134,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VP8 Encoded Stream", @@ -150,7 +142,21 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VP8_DEC, .type = MFC_FMT_DEC, .num_planes = 1, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .codec_mode = S5P_FIMV_CODEC_HEVC_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V10_BIT, + }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .codec_mode = S5P_FIMV_CODEC_VP9_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V10_BIT, }, }; @@ -1177,7 +1183,7 @@ void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) struct v4l2_format f; f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; ctx->src_fmt = find_format(&f, MFC_FMT_DEC); - if (IS_MFCV8(ctx->dev)) + if (IS_MFCV8_PLUS(ctx->dev)) f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; else if (IS_MFCV6_PLUS(ctx->dev)) f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 0d5d465561be..5c0462ca9993 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -57,8 +57,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "4:2:0 2 Planes Y/CrCb", @@ -66,7 +65,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_NONE, .type = MFC_FMT_RAW, .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V6PLUS_BITS, }, { .name = "H264 Encoded Stream", @@ -74,8 +73,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H264_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "MPEG4 Encoded Stream", @@ -83,8 +81,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "H263 Encoded Stream", @@ -92,8 +89,7 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_H263_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | - MFC_V8_BIT, + .versions = MFC_V5PLUS_BITS, }, { .name = "VP8 Encoded Stream", @@ -101,7 +97,14 @@ static struct s5p_mfc_fmt formats[] = { .codec_mode = S5P_MFC_CODEC_VP8_ENC, .type = MFC_FMT_ENC, .num_planes = 1, - .versions = MFC_V7_BIT | MFC_V8_BIT, + .versions = MFC_V7PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .codec_mode = S5P_FIMV_CODEC_HEVC_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + .versions = MFC_V10_BIT, }, }; @@ -697,6 +700,368 @@ static struct mfc_control controls[] = { .default_value = 0, }, { + .id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HEVC I Frame QP Value", + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HEVC P Frame QP Value", + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .maximum = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TIER, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 2, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, + .maximum = V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + .maximum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + .maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + .maximum = V4L2_MPEG_VIDEO_HEVC_SIZE_4, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Minimum number of output bufs", @@ -817,6 +1182,11 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) get_enc_dpb_count, dev); if (ctx->pb_count < enc_pb_count) ctx->pb_count = enc_pb_count; + if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) { + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + get_e_min_scratch_buf_size, dev); + ctx->bank1.size += ctx->scratch_buf_size; + } ctx->state = MFCINST_HEAD_PRODUCED; } @@ -850,7 +1220,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; struct s5p_mfc_buf *mb_entry; - unsigned long enc_y_addr, enc_c_addr; + unsigned long enc_y_addr = 0, enc_c_addr = 0; unsigned long mb_y_addr, mb_c_addr; int slice_type; unsigned int strm_size; @@ -1358,6 +1728,26 @@ static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl) return t[lvl]; } +static inline int hevc_level(enum v4l2_mpeg_video_hevc_level lvl) +{ + static unsigned int t[] = { + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_1 */ 10, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2 */ 20, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 */ 21, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3 */ 30, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 */ 31, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4 */ 40, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 */ 41, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5 */ 50, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 */ 51, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 */ 52, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6 */ 60, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 */ 61, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 */ 62, + }; + return t[lvl]; +} + static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar) { static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = { @@ -1383,6 +1773,42 @@ static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar) return t[sar]; } +/* + * Update range of all HEVC quantization parameter controls that depend on the + * V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP controls. + */ +static void __enc_update_hevc_qp_ctrls_range(struct s5p_mfc_ctx *ctx, + int min, int max) +{ + static const int __hevc_qp_ctrls[] = { + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, + }; + struct v4l2_ctrl *ctrl = NULL; + int i, j; + + for (i = 0; i < ARRAY_SIZE(__hevc_qp_ctrls); i++) { + for (j = 0; j < ARRAY_SIZE(ctx->ctrls); j++) { + if (ctx->ctrls[j]->id == __hevc_qp_ctrls[i]) { + ctrl = ctx->ctrls[j]; + break; + } + } + if (WARN_ON(!ctrl)) + break; + + __v4l2_ctrl_modify_range(ctrl, min, max, ctrl->step, min); + } +} + static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) { struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); @@ -1634,6 +2060,157 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_VPX_PROFILE: p->codec.vp8.profile = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + p->codec.hevc.rc_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: + p->codec.hevc.rc_p_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: + p->codec.hevc.rc_b_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: + p->codec.hevc.rc_framerate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + p->codec.hevc.rc_min_qp = ctrl->val; + __enc_update_hevc_qp_ctrls_range(ctx, ctrl->val, + p->codec.hevc.rc_max_qp); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + p->codec.hevc.rc_max_qp = ctrl->val; + __enc_update_hevc_qp_ctrls_range(ctx, p->codec.hevc.rc_min_qp, + ctrl->val); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + p->codec.hevc.level_v4l2 = ctrl->val; + p->codec.hevc.level = hevc_level(ctrl->val); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + p->codec.hevc.profile = + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + p->codec.hevc.profile = + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; + break; + default: + ret = -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + p->codec.hevc.tier = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: + p->codec.hevc.max_partition_depth = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: + p->codec.hevc.num_refs_for_p = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + p->codec.hevc.refreshtype = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: + p->codec.hevc.const_intra_period_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: + p->codec.hevc.lossless_cu_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: + p->codec.hevc.wavefront_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + p->codec.hevc.loopfilter = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: + p->codec.hevc.hier_qp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + p->codec.hevc.hier_qp_type = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: + p->codec.hevc.num_hier_layer = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: + p->codec.hevc.hier_qp_layer[0] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: + p->codec.hevc.hier_qp_layer[1] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: + p->codec.hevc.hier_qp_layer[2] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: + p->codec.hevc.hier_qp_layer[3] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: + p->codec.hevc.hier_qp_layer[4] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: + p->codec.hevc.hier_qp_layer[5] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: + p->codec.hevc.hier_qp_layer[6] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: + p->codec.hevc.hier_bit_layer[0] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: + p->codec.hevc.hier_bit_layer[1] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: + p->codec.hevc.hier_bit_layer[2] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: + p->codec.hevc.hier_bit_layer[3] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: + p->codec.hevc.hier_bit_layer[4] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: + p->codec.hevc.hier_bit_layer[5] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: + p->codec.hevc.hier_bit_layer[6] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: + p->codec.hevc.general_pb_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: + p->codec.hevc.temporal_id_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: + p->codec.hevc.strong_intra_smooth = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: + p->codec.hevc.intra_pu_split_disable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: + p->codec.hevc.tmv_prediction_disable = !ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: + p->codec.hevc.max_num_merge_mv = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: + p->codec.hevc.encoding_nostartcode_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: + p->codec.hevc.refreshperiod = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: + p->codec.hevc.lf_beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: + p->codec.hevc.lf_tc_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + p->codec.hevc.size_of_length_field = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + p->codec.hevc.prepend_sps_pps_to_idr = ctrl->val; + break; default: v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", ctrl->id, ctrl->val); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h index 16d553fcff08..8c295f0f9740 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h @@ -169,6 +169,9 @@ struct s5p_mfc_regs { void __iomem *d_decoded_third_addr;/* only v7 */ void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */ void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */ + void __iomem *d_min_scratch_buffer_size; /* v10 */ + void __iomem *d_static_buffer_addr; /* v10 */ + void __iomem *d_static_buffer_size; /* v10 */ /* encoder registers */ void __iomem *e_frame_width; @@ -268,6 +271,15 @@ struct s5p_mfc_regs { void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */ void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ + void __iomem *e_min_scratch_buffer_size; /* v10 */ + void __iomem *e_num_t_layer; /* v10 */ + void __iomem *e_hier_qp_layer0; /* v10 */ + void __iomem *e_hier_bit_rate_layer0; /* v10 */ + void __iomem *e_hevc_options; /* v10 */ + void __iomem *e_hevc_refresh_period; /* v10 */ + void __iomem *e_hevc_lf_beta_offset_div2; /* v10 */ + void __iomem *e_hevc_lf_tc_offset_div2; /* v10 */ + void __iomem *e_hevc_nal_control; /* v10 */ }; struct s5p_mfc_hw_ops { @@ -311,6 +323,8 @@ struct s5p_mfc_hw_ops { unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx); unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx); unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx); + int (*get_min_scratch_buf_size)(struct s5p_mfc_dev *dev); + int (*get_e_min_scratch_buf_size)(struct s5p_mfc_dev *dev); }; void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 88dbb9c341ec..7c629be43205 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -64,6 +64,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; unsigned int mb_width, mb_height; + unsigned int lcu_width = 0, lcu_height = 0; int ret; mb_width = MB_WIDTH(ctx->img_width); @@ -74,7 +75,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->luma_size, ctx->chroma_size, ctx->mv_size); mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); } else if (ctx->type == MFCINST_ENCODER) { - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) { + ctx->tmv_buffer_size = 0; + } else if (IS_MFCV8_PLUS(dev)) ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V8(mb_width, mb_height), S5P_FIMV_TMV_BUFFER_ALIGN_V6); @@ -82,14 +85,37 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), S5P_FIMV_TMV_BUFFER_ALIGN_V6); - - ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * - S5P_FIMV_LUMA_MB_TO_PIXEL_V6, - S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); - ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * - S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, - S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) { + lcu_width = S5P_MFC_LCU_WIDTH(ctx->img_width); + lcu_height = S5P_MFC_LCU_HEIGHT(ctx->img_height); + if (ctx->codec_mode != S5P_FIMV_CODEC_HEVC_ENC) { + ctx->luma_dpb_size = + ALIGN((mb_width * 16), 64) + * ALIGN((mb_height * 16), 32) + + 64; + ctx->chroma_dpb_size = + ALIGN((mb_width * 16), 64) + * (mb_height * 8) + + 64; + } else { + ctx->luma_dpb_size = + ALIGN((lcu_width * 32), 64) + * ALIGN((lcu_height * 32), 32) + + 64; + ctx->chroma_dpb_size = + ALIGN((lcu_width * 32), 64) + * (lcu_height * 16) + + 64; + } + } else { + ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_LUMA_MB_TO_PIXEL_V6, + S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); + ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, + S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); + } + if (IS_MFCV8_PLUS(dev)) ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V8( ctx->img_width, ctx->img_height, mb_width, mb_height), @@ -110,7 +136,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_DEC: case S5P_MFC_CODEC_H264_MVC_DEC: - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8( mb_width, @@ -127,7 +155,9 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) (ctx->mv_count * ctx->mv_size); break; case S5P_MFC_CODEC_MPEG4_DEC: - if (IS_MFCV7_PLUS(dev)) { + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV7_PLUS(dev)) { ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7( mb_width, @@ -145,10 +175,14 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) break; case S5P_MFC_CODEC_VC1RCV_DEC: case S5P_MFC_CODEC_VC1_DEC: - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( - mb_width, - mb_height); + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size; @@ -158,16 +192,21 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank2.size = 0; break; case S5P_MFC_CODEC_H263_DEC: - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( - mb_width, - mb_height); + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( + mb_width, + mb_height); ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size; break; case S5P_MFC_CODEC_VP8_DEC: - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8( mb_width, @@ -181,8 +220,24 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = ctx->scratch_buf_size; break; + case S5P_MFC_CODEC_HEVC_DEC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->bank1.size = + ctx->scratch_buf_size + + (ctx->mv_count * ctx->mv_size); + break; + case S5P_MFC_CODEC_VP9_DEC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->bank1.size = + ctx->scratch_buf_size + + DEC_VP9_STATIC_BUFFER_SIZE; + break; case S5P_MFC_CODEC_H264_ENC: - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_H264_ME_SIZE(mb_width, mb_height), 16); + } else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8( mb_width, @@ -202,10 +257,16 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) break; case S5P_MFC_CODEC_MPEG4_ENC: case S5P_MFC_CODEC_H263_ENC: - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( - mb_width, - mb_height); + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width, + mb_height), 16); + } else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( + mb_width, + mb_height); ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); ctx->bank1.size = @@ -215,7 +276,12 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->bank2.size = 0; break; case S5P_MFC_CODEC_VP8_ENC: - if (IS_MFCV8(dev)) + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height), + 16); + } else if (IS_MFCV8_PLUS(dev)) ctx->scratch_buf_size = S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8( mb_width, @@ -233,6 +299,17 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) ctx->chroma_dpb_size + ctx->me_buffer_size)); ctx->bank2.size = 0; break; + case S5P_MFC_CODEC_HEVC_ENC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 16); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256); + ctx->bank1.size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->pb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2.size = 0; + break; default: break; } @@ -267,6 +344,7 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) switch (ctx->codec_mode) { case S5P_MFC_CODEC_H264_DEC: case S5P_MFC_CODEC_H264_MVC_DEC: + case S5P_MFC_CODEC_HEVC_DEC: ctx->ctx.size = buf_size->h264_dec_ctx; break; case S5P_MFC_CODEC_MPEG4_DEC: @@ -275,11 +353,15 @@ static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) case S5P_MFC_CODEC_VC1_DEC: case S5P_MFC_CODEC_MPEG2_DEC: case S5P_MFC_CODEC_VP8_DEC: + case S5P_MFC_CODEC_VP9_DEC: ctx->ctx.size = buf_size->other_dec_ctx; break; case S5P_MFC_CODEC_H264_ENC: ctx->ctx.size = buf_size->h264_enc_ctx; break; + case S5P_MFC_CODEC_HEVC_ENC: + ctx->ctx.size = buf_size->hevc_enc_ctx; + break; case S5P_MFC_CODEC_MPEG4_ENC: case S5P_MFC_CODEC_H263_ENC: case S5P_MFC_CODEC_VP8_ENC: @@ -356,6 +438,7 @@ static int calc_plane(int width, int height) static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) { + struct s5p_mfc_dev *dev = ctx->dev; ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n" @@ -364,7 +447,7 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height); ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1)); - if (IS_MFCV8(ctx->dev)) { + if (IS_MFCV8_PLUS(ctx->dev)) { /* MFCv8 needs additional 64 bytes for luma,chroma dpb*/ ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; @@ -372,9 +455,17 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { - ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, + if (IS_MFCV10(dev)) { + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V10(ctx->img_width, + ctx->img_height); + } else { + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, + ctx->img_height); + } + } else if (ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { + ctx->mv_size = s5p_mfc_dec_hevc_mv_size(ctx->img_width, ctx->img_height); - ctx->mv_size = ALIGN(ctx->mv_size, 16); + ctx->mv_size = ALIGN(ctx->mv_size, 32); } else { ctx->mv_size = 0; } @@ -445,7 +536,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) writel(buf_addr1, mfc_regs->d_scratch_buffer_addr); writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size); - if (IS_MFCV8(dev)) { + if (IS_MFCV8_PLUS(dev)) { writel(ctx->img_width, mfc_regs->d_first_plane_dpb_stride_size); writel(ctx->img_width, @@ -456,7 +547,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) buf_size1 -= ctx->scratch_buf_size; if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){ + ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_HEVC_DEC) { writel(ctx->mv_size, mfc_regs->d_mv_buffer_size); writel(ctx->mv_count, mfc_regs->d_num_mv); } @@ -479,7 +571,8 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_regs->d_second_plane_dpb + i * 4); } if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || - ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC || + ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { for (i = 0; i < ctx->mv_count; i++) { /* To test alignment */ align_gap = buf_addr1; @@ -494,6 +587,13 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) buf_size1 -= frame_size_mv; } } + if (ctx->codec_mode == S5P_FIMV_CODEC_VP9_DEC) { + writel(buf_addr1, mfc_regs->d_static_buffer_addr); + writel(DEC_VP9_STATIC_BUFFER_SIZE, + mfc_regs->d_static_buffer_size); + buf_addr1 += DEC_VP9_STATIC_BUFFER_SIZE; + buf_size1 -= DEC_VP9_STATIC_BUFFER_SIZE; + } mfc_debug(2, "Buf1: %zx, buf_size1: %d (frames %d)\n", buf_addr1, buf_size1, ctx->total_dpb_count); @@ -571,15 +671,34 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); - for (i = 0; i < ctx->pb_count; i++) { - writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); - buf_addr1 += ctx->luma_dpb_size; - writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); - buf_addr1 += ctx->chroma_dpb_size; - writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); - buf_addr1 += ctx->me_buffer_size; - buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + - ctx->me_buffer_size); + if (IS_MFCV10(dev)) { + /* start address of per buffer is aligned */ + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + buf_size1 -= ctx->luma_dpb_size; + } + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + buf_size1 -= ctx->chroma_dpb_size; + } + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= ctx->me_buffer_size; + } + } else { + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + + ctx->me_buffer_size); + } } writel(buf_addr1, mfc_regs->e_scratch_buffer_addr); @@ -1321,6 +1440,162 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) return 0; } +static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_hevc_enc_params *p_hevc = &p->codec.hevc; + unsigned int reg = 0; + int i; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = readl(mfc_regs->e_gop_config); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + writel(reg, mfc_regs->e_gop_config); + + /* UHD encoding case */ + if ((ctx->img_width == 3840) && (ctx->img_height == 2160)) { + p_hevc->level = 51; + p_hevc->tier = 0; + /* this tier can be changed */ + } + + /* tier & level */ + reg = 0; + /* profile */ + reg |= p_hevc->profile & 0x3; + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_hevc->level << 8); + /* tier - 0 ~ 1 */ + reg |= (p_hevc->tier << 16); + writel(reg, mfc_regs->e_picture_profile); + + switch (p_hevc->loopfilter) { + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: + p_hevc->loopfilter_disable = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: + p_hevc->loopfilter_disable = 0; + p_hevc->loopfilter_across = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + p_hevc->loopfilter_disable = 0; + p_hevc->loopfilter_across = 0; + break; + } + + /* max partition depth */ + reg = 0; + reg |= (p_hevc->max_partition_depth & 0x1); + reg |= (p_hevc->num_refs_for_p-1) << 2; + reg |= (p_hevc->refreshtype & 0x3) << 3; + reg |= (p_hevc->const_intra_period_enable & 0x1) << 5; + reg |= (p_hevc->lossless_cu_enable & 0x1) << 6; + reg |= (p_hevc->wavefront_enable & 0x1) << 7; + reg |= (p_hevc->loopfilter_disable & 0x1) << 8; + reg |= (p_hevc->loopfilter_across & 0x1) << 9; + reg |= (p_hevc->enable_ltr & 0x1) << 10; + reg |= (p_hevc->hier_qp_enable & 0x1) << 11; + reg |= (p_hevc->general_pb_enable & 0x1) << 13; + reg |= (p_hevc->temporal_id_enable & 0x1) << 14; + reg |= (p_hevc->strong_intra_smooth & 0x1) << 15; + reg |= (p_hevc->intra_pu_split_disable & 0x1) << 16; + reg |= (p_hevc->tmv_prediction_disable & 0x1) << 17; + reg |= (p_hevc->max_num_merge_mv & 0x7) << 18; + reg |= (p_hevc->encoding_nostartcode_enable & 0x1) << 23; + reg |= (p_hevc->prepend_sps_pps_to_idr << 26); + + writel(reg, mfc_regs->e_hevc_options); + /* refresh period */ + if (p_hevc->refreshtype) { + reg = 0; + reg |= (p_hevc->refreshperiod & 0xFFFF); + writel(reg, mfc_regs->e_hevc_refresh_period); + } + /* loop filter setting */ + if (!(p_hevc->loopfilter_disable & 0x1)) { + reg = 0; + reg |= (p_hevc->lf_beta_offset_div2); + writel(reg, mfc_regs->e_hevc_lf_beta_offset_div2); + reg = 0; + reg |= (p_hevc->lf_tc_offset_div2); + writel(reg, mfc_regs->e_hevc_lf_tc_offset_div2); + } + /* hier qp enable */ + if (p_hevc->num_hier_layer) { + reg = 0; + reg |= (p_hevc->hier_qp_type & 0x1) << 0x3; + reg |= p_hevc->num_hier_layer & 0x7; + writel(reg, mfc_regs->e_num_t_layer); + /* QP value for each layer */ + if (p_hevc->hier_qp_enable) { + for (i = 0; i < 7; i++) + writel(p_hevc->hier_qp_layer[i], + mfc_regs->e_hier_qp_layer0 + i * 4); + } + if (p->rc_frame) { + for (i = 0; i < 7; i++) + writel(p_hevc->hier_bit_layer[i], + mfc_regs->e_hier_bit_rate_layer0 + + i * 4); + } + } + + /* rate control config. */ + reg = readl(mfc_regs->e_rc_config); + /* macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= (p->rc_mb << 8); + writel(reg, mfc_regs->e_rc_config); + /* frame QP */ + reg &= ~(0xFF); + reg |= p_hevc->rc_frame_qp; + writel(reg, mfc_regs->e_rc_config); + + /* frame rate */ + if (p->rc_frame) { + reg = 0; + reg &= ~(0xFFFF << 16); + reg |= ((p_hevc->rc_framerate) << 16); + reg &= ~(0xFFFF); + reg |= FRAME_DELTA_DEFAULT; + writel(reg, mfc_regs->e_rc_frame_rate); + } + + /* max & min value of QP */ + reg = 0; + /* max QP */ + reg &= ~(0xFF << 8); + reg |= (p_hevc->rc_max_qp << 8); + /* min QP */ + reg &= ~(0xFF); + reg |= p_hevc->rc_min_qp; + writel(reg, mfc_regs->e_rc_qp_bound); + + writel(0x0, mfc_regs->e_fixed_picture_qp); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg &= ~(0xFF << 16); + reg |= (p_hevc->rc_b_frame_qp << 16); + reg &= ~(0xFF << 8); + reg |= (p_hevc->rc_p_frame_qp << 8); + reg &= ~(0xFF); + reg |= p_hevc->rc_frame_qp; + writel(reg, mfc_regs->e_fixed_picture_qp); + } + mfc_debug_leave(); + + return 0; +} + /* Initialize decoding */ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) { @@ -1440,6 +1715,8 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) s5p_mfc_set_enc_params_h263(ctx); else if (ctx->codec_mode == S5P_MFC_CODEC_VP8_ENC) s5p_mfc_set_enc_params_vp8(ctx); + else if (ctx->codec_mode == S5P_FIMV_CODEC_HEVC_ENC) + s5p_mfc_set_enc_params_hevc(ctx); else { mfc_err("Unknown codec for encoding (%x).\n", ctx->codec_mode); @@ -1895,6 +2172,16 @@ static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) return readl(dev->mfc_regs->d_min_num_mv); } +static int s5p_mfc_get_min_scratch_buf_size(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_min_scratch_buffer_size); +} + +static int s5p_mfc_get_e_min_scratch_buf_size(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->e_min_scratch_buffer_size); +} + static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) { return readl(dev->mfc_regs->ret_instance_id); @@ -2109,7 +2396,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7); R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7); - if (!IS_MFCV8(dev)) + if (!IS_MFCV8_PLUS(dev)) goto done; /* Initialize registers used in MFC v8 only. @@ -2153,6 +2440,7 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8); R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V8); R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V8); + R(d_min_scratch_buffer_size, S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8); /* encoder registers */ R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V8); @@ -2168,6 +2456,29 @@ const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V8); R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V8); R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V8); + R(e_min_scratch_buffer_size, S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8); + + if (!IS_MFCV10(dev)) + goto done; + + /* Initialize registers used in MFC v10 only. + * Also, over-write the registers which have + * a different offset for MFC v10. + */ + + /* decoder registers */ + R(d_static_buffer_addr, S5P_FIMV_D_STATIC_BUFFER_ADDR_V10); + R(d_static_buffer_size, S5P_FIMV_D_STATIC_BUFFER_SIZE_V10); + + /* encoder registers */ + R(e_num_t_layer, S5P_FIMV_E_NUM_T_LAYER_V10); + R(e_hier_qp_layer0, S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10); + R(e_hier_bit_rate_layer0, S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10); + R(e_hevc_options, S5P_FIMV_E_HEVC_OPTIONS_V10); + R(e_hevc_refresh_period, S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10); + R(e_hevc_lf_beta_offset_div2, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10); + R(e_hevc_lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10); + R(e_hevc_nal_control, S5P_FIMV_E_HEVC_NAL_CONTROL_V10); done: return &mfc_regs; @@ -2216,6 +2527,8 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, .get_crop_info_v = s5p_mfc_get_crop_info_v_v6, + .get_min_scratch_buf_size = s5p_mfc_get_min_scratch_buf_size, + .get_e_min_scratch_buf_size = s5p_mfc_get_e_min_scratch_buf_size, }; struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h index 80558484bb40..f013b291ae5b 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h @@ -24,6 +24,13 @@ #define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16) #define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \ (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) +#define S5P_MFC_DEC_MV_SIZE_V10(x, y) (MB_WIDTH(x) * \ + (((MB_HEIGHT(y)+1)/2)*2) * 64 + 512) +#define S5P_MFC_LCU_WIDTH(x_size) DIV_ROUND_UP(x_size, 32) +#define S5P_MFC_LCU_HEIGHT(y_size) DIV_ROUND_UP(y_size, 32) + +#define s5p_mfc_dec_hevc_mv_size(x, y) \ + (DIV_ROUND_UP(x, 64) * DIV_ROUND_UP(y, 64) * 256 + 512) /* Definition */ #define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) @@ -39,6 +46,14 @@ #define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1) #define FRAME_DELTA_H264_H263 1 #define TIGHT_CBR_MAX 10 +#define ENC_HEVC_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_HEVC_QP_INDEX_MIN -12 +#define ENC_HEVC_QP_INDEX_MAX 12 +#define ENC_HEVC_LOOP_FILTER_MIN -12 +#define ENC_HEVC_LOOP_FILTER_MAX 12 +#define ENC_HEVC_LEVEL_MAX 62 + +#define FRAME_DELTA_DEFAULT 1 struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev); diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 976ea0bb5b6c..1a0cde017fdf 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -520,8 +520,8 @@ static void sh_veu_colour_offset(struct sh_veu_dev *veu, struct sh_veu_vfmt *vfm /* dst_left and dst_top validity will be verified in CROP / COMPOSE */ unsigned int left = vfmt->frame.left & ~0x03; unsigned int top = vfmt->frame.top; - dma_addr_t offset = ((left * veu->vfmt_out.fmt->depth) >> 3) + - top * veu->vfmt_out.bytesperline; + dma_addr_t offset = (dma_addr_t)top * veu->vfmt_out.bytesperline + + (((dma_addr_t)left * veu->vfmt_out.fmt->depth) >> 3); unsigned int y_line; vfmt->offset_y = offset; diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index c86dd2fdab84..69f0d8e80bd8 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -787,7 +787,7 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); int err; - dev_dbg(icd->pdev, "mmap called, vma=0x%08lx\n", (unsigned long)vma); + dev_dbg(icd->pdev, "mmap called, vma=%p\n", vma); if (icd->streamer != file) return -EBUSY; @@ -1788,17 +1788,19 @@ static int default_s_selection(struct soc_camera_device *icd, } static int default_g_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *parm) + struct v4l2_streamparm *a) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, g_parm, parm); + + return v4l2_g_parm_cap(icd->vdev, sd, a); } static int default_s_parm(struct soc_camera_device *icd, - struct v4l2_streamparm *parm) + struct v4l2_streamparm *a) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - return v4l2_subdev_call(sd, video, s_parm, parm); + + return v4l2_s_parm_cap(icd->vdev, sd, a); } static int default_enum_framesizes(struct soc_camera_device *icd, diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c index 0e5aa17bdd40..7c496bc1cf38 100644 --- a/drivers/media/platform/stm32/stm32-cec.c +++ b/drivers/media/platform/stm32/stm32-cec.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * STM32 CEC driver * Copyright (C) STMicroelectronics SA 2017 * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. */ #include <linux/clk.h> diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 9460b3080dca..2e1933d872ee 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for STM32 Digital Camera Memory Interface * @@ -5,7 +6,6 @@ * Authors: Yannick Fertre <yannick.fertre@st.com> * Hugues Fruchet <hugues.fruchet@st.com> * for STMicroelectronics. - * License terms: GNU General Public License (GPL), version 2 * * This driver is based on atmel_isi.c * @@ -93,6 +93,11 @@ enum state { #define MIN_HEIGHT 16U #define MAX_HEIGHT 2048U +#define MIN_JPEG_WIDTH 16U +#define MAX_JPEG_WIDTH 2592U +#define MIN_JPEG_HEIGHT 16U +#define MAX_JPEG_HEIGHT 2592U + #define TIMEOUT_MS 1000 struct dcmi_graph_entity { @@ -160,6 +165,7 @@ struct stm32_dcmi { dma_cookie_t dma_cookie; u32 misr; int errors_count; + int overrun_count; int buffers_count; }; @@ -190,14 +196,67 @@ static inline void reg_clear(void __iomem *base, u32 reg, u32 mask) static int dcmi_start_capture(struct stm32_dcmi *dcmi); +static void dcmi_buffer_done(struct stm32_dcmi *dcmi, + struct dcmi_buf *buf, + size_t bytesused, + int err) +{ + struct vb2_v4l2_buffer *vbuf; + + if (!buf) + return; + + vbuf = &buf->vb; + + vbuf->sequence = dcmi->sequence++; + vbuf->field = V4L2_FIELD_NONE; + vbuf->vb2_buf.timestamp = ktime_get_ns(); + vb2_set_plane_payload(&vbuf->vb2_buf, 0, bytesused); + vb2_buffer_done(&vbuf->vb2_buf, + err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dev_dbg(dcmi->dev, "buffer[%d] done seq=%d, bytesused=%zu\n", + vbuf->vb2_buf.index, vbuf->sequence, bytesused); + + dcmi->buffers_count++; + dcmi->active = NULL; +} + +static int dcmi_restart_capture(struct stm32_dcmi *dcmi) +{ + spin_lock_irq(&dcmi->irqlock); + + if (dcmi->state != RUNNING) { + spin_unlock_irq(&dcmi->irqlock); + return -EINVAL; + } + + /* Restart a new DMA transfer with next buffer */ + if (list_empty(&dcmi->buffers)) { + dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer\n", + __func__); + dcmi->errors_count++; + dcmi->active = NULL; + + spin_unlock_irq(&dcmi->irqlock); + return -EINVAL; + } + + dcmi->active = list_entry(dcmi->buffers.next, + struct dcmi_buf, list); + list_del_init(&dcmi->active->list); + + spin_unlock_irq(&dcmi->irqlock); + + return dcmi_start_capture(dcmi); +} + static void dcmi_dma_callback(void *param) { struct stm32_dcmi *dcmi = (struct stm32_dcmi *)param; struct dma_chan *chan = dcmi->dma_chan; struct dma_tx_state state; enum dma_status status; - - spin_lock(&dcmi->irqlock); + struct dcmi_buf *buf = dcmi->active; /* Check DMA status */ status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state); @@ -215,58 +274,18 @@ static void dcmi_dma_callback(void *param) case DMA_COMPLETE: dev_dbg(dcmi->dev, "%s: Received DMA_COMPLETE\n", __func__); - if (dcmi->active) { - struct dcmi_buf *buf = dcmi->active; - struct vb2_v4l2_buffer *vbuf = &dcmi->active->vb; - - vbuf->sequence = dcmi->sequence++; - vbuf->field = V4L2_FIELD_NONE; - vbuf->vb2_buf.timestamp = ktime_get_ns(); - vb2_set_plane_payload(&vbuf->vb2_buf, 0, buf->size); - vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); - dev_dbg(dcmi->dev, "buffer[%d] done seq=%d\n", - vbuf->vb2_buf.index, vbuf->sequence); - - dcmi->buffers_count++; - dcmi->active = NULL; - } - - /* Restart a new DMA transfer with next buffer */ - if (dcmi->state == RUNNING) { - if (list_empty(&dcmi->buffers)) { - dev_err(dcmi->dev, "%s: No more buffer queued, cannot capture buffer", - __func__); - dcmi->errors_count++; - dcmi->active = NULL; - - spin_unlock(&dcmi->irqlock); - return; - } - - dcmi->active = list_entry(dcmi->buffers.next, - struct dcmi_buf, list); - - list_del_init(&dcmi->active->list); - - if (dcmi_start_capture(dcmi)) { - dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete", - __func__); - - spin_unlock(&dcmi->irqlock); - return; - } - - /* Enable capture */ - reg_set(dcmi->regs, DCMI_CR, CR_CAPTURE); - } + /* Return buffer to V4L2 */ + dcmi_buffer_done(dcmi, buf, buf->size, 0); + /* Restart capture */ + if (dcmi_restart_capture(dcmi)) + dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n", + __func__); break; default: dev_err(dcmi->dev, "%s: Received unknown status\n", __func__); break; } - - spin_unlock(&dcmi->irqlock); } static int dcmi_start_dma(struct stm32_dcmi *dcmi, @@ -359,11 +378,57 @@ static void dcmi_set_crop(struct stm32_dcmi *dcmi) reg_set(dcmi->regs, DCMI_CR, CR_CROP); } +static void dcmi_process_jpeg(struct stm32_dcmi *dcmi) +{ + struct dma_tx_state state; + enum dma_status status; + struct dma_chan *chan = dcmi->dma_chan; + struct dcmi_buf *buf = dcmi->active; + + if (!buf) + return; + + /* + * Because of variable JPEG buffer size sent by sensor, + * DMA transfer never completes due to transfer size + * never reached. + * In order to ensure that all the JPEG data are transferred + * in active buffer memory, DMA is drained. + * Then DMA tx status gives the amount of data transferred + * to memory, which is then returned to V4L2 through the active + * buffer payload. + */ + + /* Drain DMA */ + dmaengine_synchronize(chan); + + /* Get DMA residue to get JPEG size */ + status = dmaengine_tx_status(chan, dcmi->dma_cookie, &state); + if (status != DMA_ERROR && state.residue < buf->size) { + /* Return JPEG buffer to V4L2 with received JPEG buffer size */ + dcmi_buffer_done(dcmi, buf, buf->size - state.residue, 0); + } else { + dcmi->errors_count++; + dev_err(dcmi->dev, "%s: Cannot get JPEG size from DMA\n", + __func__); + /* Return JPEG buffer to V4L2 in ERROR state */ + dcmi_buffer_done(dcmi, buf, 0, -EIO); + } + + /* Abort DMA operation */ + dmaengine_terminate_all(dcmi->dma_chan); + + /* Restart capture */ + if (dcmi_restart_capture(dcmi)) + dev_err(dcmi->dev, "%s: Cannot restart capture on JPEG received\n", + __func__); +} + static irqreturn_t dcmi_irq_thread(int irq, void *arg) { struct stm32_dcmi *dcmi = arg; - spin_lock(&dcmi->irqlock); + spin_lock_irq(&dcmi->irqlock); /* Stop capture is required */ if (dcmi->state == STOPPING) { @@ -373,50 +438,41 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) complete(&dcmi->complete); - spin_unlock(&dcmi->irqlock); + spin_unlock_irq(&dcmi->irqlock); return IRQ_HANDLED; } if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) { - /* - * An overflow or an error has been detected, - * stop current DMA transfert & restart it - */ - dev_warn(dcmi->dev, "%s: Overflow or error detected\n", - __func__); - dcmi->errors_count++; - dmaengine_terminate_all(dcmi->dma_chan); - - reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR); - - dev_dbg(dcmi->dev, "Restarting capture after DCMI error\n"); - - if (dcmi_start_capture(dcmi)) { - dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n", - __func__); + if (dcmi->misr & IT_OVR) + dcmi->overrun_count++; + } - spin_unlock(&dcmi->irqlock); - return IRQ_HANDLED; - } + if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG && + dcmi->misr & IT_FRAME) { + /* JPEG received */ + spin_unlock_irq(&dcmi->irqlock); + dcmi_process_jpeg(dcmi); + return IRQ_HANDLED; } - spin_unlock(&dcmi->irqlock); + spin_unlock_irq(&dcmi->irqlock); return IRQ_HANDLED; } static irqreturn_t dcmi_irq_callback(int irq, void *arg) { struct stm32_dcmi *dcmi = arg; + unsigned long flags; - spin_lock(&dcmi->irqlock); + spin_lock_irqsave(&dcmi->irqlock, flags); dcmi->misr = reg_read(dcmi->regs, DCMI_MIS); /* Clear interrupt */ reg_set(dcmi->regs, DCMI_ICR, IT_FRAME | IT_OVR | IT_ERR); - spin_unlock(&dcmi->irqlock); + spin_unlock_irqrestore(&dcmi->irqlock, flags); return IRQ_WAKE_THREAD; } @@ -483,7 +539,7 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb) vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); - dev_dbg(dcmi->dev, "buffer[%d] phy=0x%pad size=%zu\n", + dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n", vb->index, &buf->paddr, buf->size); } @@ -495,29 +551,24 @@ static void dcmi_buf_queue(struct vb2_buffer *vb) struct stm32_dcmi *dcmi = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb); - unsigned long flags = 0; - spin_lock_irqsave(&dcmi->irqlock, flags); + spin_lock_irq(&dcmi->irqlock); - if ((dcmi->state == RUNNING) && (!dcmi->active)) { + if (dcmi->state == RUNNING && !dcmi->active) { dcmi->active = buf; dev_dbg(dcmi->dev, "Starting capture on buffer[%d] queued\n", buf->vb.vb2_buf.index); - if (dcmi_start_capture(dcmi)) { + spin_unlock_irq(&dcmi->irqlock); + if (dcmi_start_capture(dcmi)) dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n", __func__); - - spin_unlock_irqrestore(&dcmi->irqlock, flags); - return; - } } else { /* Enqueue to video buffers list */ list_add_tail(&buf->list, &dcmi->buffers); + spin_unlock_irq(&dcmi->irqlock); } - - spin_unlock_irqrestore(&dcmi->irqlock, flags); } static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) @@ -529,7 +580,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) ret = clk_enable(dcmi->mclk); if (ret) { - dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock", + dev_err(dcmi->dev, "%s: Failed to start streaming, cannot enable clock\n", __func__); goto err_release_buffers; } @@ -578,6 +629,10 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) if (dcmi->do_crop) dcmi_set_crop(dcmi); + /* Enable jpeg capture */ + if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG) + reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */ + /* Enable dcmi */ reg_set(dcmi->regs, DCMI_CR, CR_ENABLE); @@ -585,6 +640,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) dcmi->sequence = 0; dcmi->errors_count = 0; + dcmi->overrun_count = 0; dcmi->buffers_count = 0; dcmi->active = NULL; @@ -603,20 +659,17 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) dev_dbg(dcmi->dev, "Start streaming, starting capture\n"); + spin_unlock_irq(&dcmi->irqlock); ret = dcmi_start_capture(dcmi); if (ret) { - dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture", + dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n", __func__); - - spin_unlock_irq(&dcmi->irqlock); goto err_subdev_streamoff; } /* Enable interruptions */ reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR); - spin_unlock_irq(&dcmi->irqlock); - return 0; err_subdev_streamoff: @@ -656,9 +709,12 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) /* Disable stream on the sub device */ ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0); if (ret && ret != -ENOIOCTLCMD) - dev_err(dcmi->dev, "stream off failed in subdev\n"); + dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n", + __func__, ret); + spin_lock_irq(&dcmi->irqlock); dcmi->state = STOPPING; + spin_unlock_irq(&dcmi->irqlock); timeout = wait_for_completion_interruptible_timeout(&dcmi->complete, time_ms); @@ -672,7 +728,8 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) reg_clear(dcmi->regs, DCMI_CR, CR_ENABLE); if (!timeout) { - dev_err(dcmi->dev, "Timeout during stop streaming\n"); + dev_err(dcmi->dev, "%s: Timeout during stop streaming\n", + __func__); dcmi->state = STOPPED; } @@ -694,8 +751,13 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) clk_disable(dcmi->mclk); - dev_dbg(dcmi->dev, "Stop streaming, errors=%d buffers=%d\n", - dcmi->errors_count, dcmi->buffers_count); + if (dcmi->errors_count) + dev_warn(dcmi->dev, "Some errors found while streaming: errors=%d (overrun=%d), buffers=%d\n", + dcmi->errors_count, dcmi->overrun_count, + dcmi->buffers_count); + dev_dbg(dcmi->dev, "Stop streaming, errors=%d (overrun=%d), buffers=%d\n", + dcmi->errors_count, dcmi->overrun_count, + dcmi->buffers_count); } static const struct vb2_ops dcmi_video_qops = { @@ -749,7 +811,7 @@ static void __find_outer_frame_size(struct stm32_dcmi *dcmi, int h_err = (fsize->height - pix->height); int err = w_err + h_err; - if ((w_err >= 0) && (h_err >= 0) && (err < min_err)) { + if (w_err >= 0 && h_err >= 0 && err < min_err) { min_err = err; match = fsize; } @@ -771,6 +833,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; + bool do_crop; int ret; sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); @@ -780,10 +843,19 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, } /* Limit to hardware capabilities */ - pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); - pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); + if (pix->pixelformat == V4L2_PIX_FMT_JPEG) { + pix->width = clamp(pix->width, MIN_JPEG_WIDTH, MAX_JPEG_WIDTH); + pix->height = + clamp(pix->height, MIN_JPEG_HEIGHT, MAX_JPEG_HEIGHT); + } else { + pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); + pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); + } - if (dcmi->do_crop && dcmi->num_of_sd_framesizes) { + /* No crop if JPEG is requested */ + do_crop = dcmi->do_crop && (pix->pixelformat != V4L2_PIX_FMT_JPEG); + + if (do_crop && dcmi->num_of_sd_framesizes) { struct dcmi_framesize outer_sd_fsize; /* * If crop is requested and sensor have discrete frame sizes, @@ -807,7 +879,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, sd_fsize.width = pix->width; sd_fsize.height = pix->height; - if (dcmi->do_crop) { + if (do_crop) { struct v4l2_rect c = dcmi->crop; struct v4l2_rect max_rect; @@ -862,6 +934,10 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) if (ret) return ret; + /* Disable crop if JPEG is requested */ + if (pix->pixelformat == V4L2_PIX_FMT_JPEG) + dcmi->do_crop = false; + /* pix to mbus format */ v4l2_fill_mbus_format(mf, pix, sd_format->mbus_code); @@ -1084,10 +1160,10 @@ static int dcmi_s_selection(struct file *file, void *priv, r.top = clamp_t(s32, r.top, 0, pix.height - r.height); r.left = clamp_t(s32, r.left, 0, pix.width - r.width); - if (!((r.top == dcmi->sd_bounds.top) && - (r.left == dcmi->sd_bounds.left) && - (r.width == dcmi->sd_bounds.width) && - (r.height == dcmi->sd_bounds.height))) { + if (!(r.top == dcmi->sd_bounds.top && + r.left == dcmi->sd_bounds.left && + r.width == dcmi->sd_bounds.width && + r.height == dcmi->sd_bounds.height)) { /* Crop if request is different than sensor resolution */ dcmi->do_crop = true; dcmi->crop = r; @@ -1167,6 +1243,22 @@ static int dcmi_enum_framesizes(struct file *file, void *fh, return 0; } +static int dcmi_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct stm32_dcmi *dcmi = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.subdev, p); +} + +static int dcmi_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *p) +{ + struct stm32_dcmi *dcmi = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.subdev, p); +} + static int dcmi_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival) { @@ -1269,6 +1361,9 @@ static const struct v4l2_ioctl_ops dcmi_ioctl_ops = { .vidioc_g_input = dcmi_g_input, .vidioc_s_input = dcmi_s_input, + .vidioc_g_parm = dcmi_g_parm, + .vidioc_s_parm = dcmi_s_parm, + .vidioc_enum_framesizes = dcmi_enum_framesizes, .vidioc_enum_frameintervals = dcmi_enum_frameintervals, @@ -1334,6 +1429,10 @@ static const struct dcmi_format dcmi_formats[] = { .fourcc = V4L2_PIX_FMT_UYVY, .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .bpp = 2, + }, { + .fourcc = V4L2_PIX_FMT_JPEG, + .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, + .bpp = 1, }, }; diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c index 92f93a880015..aba488cd0e64 100644 --- a/drivers/media/platform/tegra-cec/tegra_cec.c +++ b/drivers/media/platform/tegra-cec/tegra_cec.c @@ -172,16 +172,13 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data) } } - if (status & (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN | - TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED | - TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED | - TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)) { + if (status & TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED) { cec_write(cec, TEGRA_CEC_INT_STAT, - (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN | - TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED | - TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED | - TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)); - } else if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) { + TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED); + cec->rx_done = false; + cec->rx_buf_cnt = 0; + } + if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) { u32 v; cec_write(cec, TEGRA_CEC_INT_STAT, @@ -255,7 +252,7 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable) TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED | TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED | TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | - TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN); + TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED); cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE); return 0; diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index f77be9302120..e9a02639554b 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -1112,7 +1112,7 @@ static int viacam_g_parm(struct file *filp, void *priv, int ret; mutex_lock(&cam->lock); - ret = sensor_call(cam, video, g_parm, parm); + ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, parm); mutex_unlock(&cam->lock); parm->parm.capture.readbuffers = cam->n_cap_bufs; return ret; @@ -1125,7 +1125,7 @@ static int viacam_s_parm(struct file *filp, void *priv, int ret; mutex_lock(&cam->lock); - ret = sensor_call(cam, video, s_parm, parm); + ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, parm); mutex_unlock(&cam->lock); parm->parm.capture.readbuffers = cam->n_cap_bufs; return ret; diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index 9d63c84a9876..617415c224fe 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -434,7 +434,9 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, v4l2_set_subdevdata(sd, ved); /* Expose this subdev to user space */ - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + if (sd->ctrl_handler) + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; /* Initialize the media entity */ ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads); diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 4d663e89d33f..6e10b63ba9ec 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -533,7 +533,7 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master, /* Initialize ved and sd */ ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, pdata->entity_name, - MEDIA_ENT_F_ATV_DECODER, 2, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, &vimc_deb_ops); diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index e1602e0bc230..e583ec7a91da 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -395,7 +395,7 @@ static int vimc_sca_comp_bind(struct device *comp, struct device *master, /* Initialize ved and sd */ ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, pdata->entity_name, - MEDIA_ENT_F_ATV_DECODER, 2, + MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, &vimc_sca_ops); diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 457e211514c6..605e2a2d5dd5 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -23,6 +23,7 @@ #include <linux/v4l2-mediabus.h> #include <linux/vmalloc.h> #include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> #include <media/v4l2-subdev.h> #include <media/tpg/v4l2-tpg.h> @@ -284,11 +285,18 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) return 0; } +static struct v4l2_subdev_core_ops vimc_sen_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + static const struct v4l2_subdev_video_ops vimc_sen_video_ops = { .s_stream = vimc_sen_s_stream, }; static const struct v4l2_subdev_ops vimc_sen_ops = { + .core = &vimc_sen_core_ops, .pad = &vimc_sen_pad_ops, .video = &vimc_sen_video_ops, }; @@ -378,7 +386,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master, /* Initialize ved and sd */ ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, pdata->entity_name, - MEDIA_ENT_F_ATV_DECODER, 1, + MEDIA_ENT_F_CAM_SENSOR, 1, (const unsigned long[1]) {MEDIA_PAD_FL_SOURCE}, &vimc_sen_ops); if (ret) diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index b55d278d38a7..71105fa4c5f9 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-cec.c - A Virtual Video Test Driver, cec emulation * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <media/cec.h> @@ -82,11 +70,18 @@ static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, if (adap == NULL) return; - ts = ktime_sub_us(ts, (CEC_TIM_START_BIT_TOTAL + - len * 10 * CEC_TIM_DATA_BIT_TOTAL)); - cec_queue_pin_cec_event(adap, false, ts); + + /* + * Suffix ULL on constant 10 makes the expression + * CEC_TIM_START_BIT_TOTAL + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL + * to be evaluated using 64-bit unsigned arithmetic (u64), which + * is what ktime_sub_us expects as second argument. + */ + ts = ktime_sub_us(ts, CEC_TIM_START_BIT_TOTAL + + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL); + cec_queue_pin_cec_event(adap, false, false, ts); ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW); - cec_queue_pin_cec_event(adap, true, ts); + cec_queue_pin_cec_event(adap, true, false, ts); ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH); for (i = 0; i < 10 * len; i++) { @@ -101,12 +96,12 @@ static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, bit = cec_msg_is_broadcast(msg) ^ nacked; break; } - cec_queue_pin_cec_event(adap, false, ts); + cec_queue_pin_cec_event(adap, false, false, ts); if (bit) ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW); else ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW); - cec_queue_pin_cec_event(adap, true, ts); + cec_queue_pin_cec_event(adap, true, false, ts); if (bit) ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH); else diff --git a/drivers/media/platform/vivid/vivid-cec.h b/drivers/media/platform/vivid/vivid-cec.h index 3926b1422777..7524ed48a914 100644 --- a/drivers/media/platform/vivid/vivid-cec.h +++ b/drivers/media/platform/vivid/vivid-cec.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-cec.h - A Virtual Video Test Driver, cec emulation * * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifdef CONFIG_VIDEO_VIVID_CEC diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 9f036c5f51b0..82ec216f2ad8 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-core.c - A Virtual Video Test Driver, core initialization * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index c90e4a0ab94e..477c80a4d44c 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-core.h - core datastructures * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_CORE_H_ diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 3f9d354827af..6b0bfa091592 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-ctrls.c - control support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -1208,6 +1196,7 @@ static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl) v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls); v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls); + dev->radio_rx_dev.device_caps = dev->radio_rx_caps; break; case V4L2_CID_RDS_RECEPTION: dev->radio_rx_rds_enabled = ctrl->val; @@ -1282,6 +1271,7 @@ static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl) dev->radio_tx_caps &= ~V4L2_CAP_READWRITE; if (!dev->radio_tx_rds_controls) dev->radio_tx_caps |= V4L2_CAP_READWRITE; + dev->radio_tx_dev.device_caps = dev->radio_tx_caps; break; case V4L2_CID_RDS_TX_PTY: if (dev->radio_rx_rds_controls) diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h index 9bcca9d56359..6fad5f5d0054 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.h +++ b/drivers/media/platform/vivid/vivid-ctrls.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-ctrls.h - control support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_CTRLS_H_ diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index 6ca71aabb576..3fdb280c36ca 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-kthread-cap.h - video/vbi capture thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h index 5b92fc9a0d04..0f43015306d6 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.h +++ b/drivers/media/platform/vivid/vivid-kthread-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-kthread-cap.h - video/vbi capture thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_KTHREAD_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c index 98eed5889bc1..9981e7548019 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.c +++ b/drivers/media/platform/vivid/vivid-kthread-out.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-kthread-out.h - video/vbi output thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h index 2bf04a17b05d..d5bcf44bbaca 100644 --- a/drivers/media/platform/vivid/vivid-kthread-out.h +++ b/drivers/media/platform/vivid/vivid-kthread-out.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-kthread-out.h - video/vbi output thread support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_KTHREAD_OUT_H_ diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c index bdc380b14e0c..bbbc1b6938a5 100644 --- a/drivers/media/platform/vivid/vivid-osd.c +++ b/drivers/media/platform/vivid/vivid-osd.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-osd.c - osd support for testing overlays. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/module.h> diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h index 57c9daa5940a..f9ac1af25dd3 100644 --- a/drivers/media/platform/vivid/vivid-osd.h +++ b/drivers/media/platform/vivid/vivid-osd.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-osd.h - output overlay support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_OSD_H_ diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c index 78c1e920670a..7c8efe38ff5b 100644 --- a/drivers/media/platform/vivid/vivid-radio-common.c +++ b/drivers/media/platform/vivid/vivid-radio-common.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-radio-common.c - common radio rx/tx support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h index 92fe589141b7..30a9900e5b2b 100644 --- a/drivers/media/platform/vivid/vivid-radio-common.h +++ b/drivers/media/platform/vivid/vivid-radio-common.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-radio-common.h - common radio rx/tx support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RADIO_COMMON_H_ diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c index f834f7df8cf9..1f86d7d4f72f 100644 --- a/drivers/media/platform/vivid/vivid-radio-rx.c +++ b/drivers/media/platform/vivid/vivid-radio-rx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-radio-rx.c - radio receiver support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -259,7 +247,7 @@ int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) vt->rangehigh = FM_FREQ_RANGE_HIGH; sig_qual = dev->radio_rx_sig_qual; vt->signal = abs(sig_qual) > delta ? 0 : - 0xffff - (abs(sig_qual) * 0xffff) / delta; + 0xffff - ((unsigned)abs(sig_qual) * 0xffff) / delta; vt->afc = sig_qual > delta ? 0 : sig_qual; if (abs(sig_qual) > delta) vt->rxsubchans = 0; diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h index 2b33edb60942..c9c7849f6f99 100644 --- a/drivers/media/platform/vivid/vivid-radio-rx.h +++ b/drivers/media/platform/vivid/vivid-radio-rx.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-radio-rx.h - radio receiver support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RADIO_RX_H_ diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c index 308b13f85dc0..1a3749ba5e7e 100644 --- a/drivers/media/platform/vivid/vivid-radio-tx.c +++ b/drivers/media/platform/vivid/vivid-radio-tx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-radio-tx.c - radio transmitter support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h index 3c3343d70cbc..c2bf1e7e634a 100644 --- a/drivers/media/platform/vivid/vivid-radio-tx.h +++ b/drivers/media/platform/vivid/vivid-radio-tx.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-radio-tx.h - radio transmitter support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RADIO_TX_H_ diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c index 996e35e28d37..39ca9a56448c 100644 --- a/drivers/media/platform/vivid/vivid-rds-gen.c +++ b/drivers/media/platform/vivid/vivid-rds-gen.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-rds-gen.c - rds (radio data system) generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/kernel.h> diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h index e55e3b22b7ca..35ac5742302b 100644 --- a/drivers/media/platform/vivid/vivid-rds-gen.h +++ b/drivers/media/platform/vivid/vivid-rds-gen.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-rds-gen.h - rds (radio data system) generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_RDS_GEN_H_ diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index ebd7b9c4dd83..cfb7cb4d37a8 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-sdr-cap.c - software defined radio support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h index 43014b2733db..813c9248e5a7 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.h +++ b/drivers/media/platform/vivid/vivid-sdr-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-sdr-cap.h - software defined radio support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_SDR_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c index d66ef95dd2b5..92a852955173 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.c +++ b/drivers/media/platform/vivid/vivid-vbi-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vbi-cap.c - vbi capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h index 2d8ea0bac743..91d2de01381c 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.h +++ b/drivers/media/platform/vivid/vivid-vbi-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vbi-cap.h - vbi capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VBI_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c index 02c79d7cedab..acc98445a1fa 100644 --- a/drivers/media/platform/vivid/vivid-vbi-gen.c +++ b/drivers/media/platform/vivid/vivid-vbi-gen.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vbi-gen.c - vbi generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h index 8444abe905ea..2657a7f5571c 100644 --- a/drivers/media/platform/vivid/vivid-vbi-gen.h +++ b/drivers/media/platform/vivid/vivid-vbi-gen.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vbi-gen.h - vbi generator support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VBI_GEN_H_ diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c index d2989195cf03..69486c130a7e 100644 --- a/drivers/media/platform/vivid/vivid-vbi-out.c +++ b/drivers/media/platform/vivid/vivid-vbi-out.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vbi-out.c - vbi output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h index 6555ba9d2860..76584940cdaf 100644 --- a/drivers/media/platform/vivid/vivid-vbi-out.h +++ b/drivers/media/platform/vivid/vivid-vbi-out.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vbi-out.h - vbi output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VBI_OUT_H_ diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 0fbbcde19f0d..1599159f2574 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vid-cap.c - video capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -573,9 +561,9 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, mp->field = vivid_field_cap(dev, mp->field); if (vivid_is_webcam(dev)) { const struct v4l2_frmsize_discrete *sz = - v4l2_find_nearest_format(webcam_sizes, - VIVID_WEBCAM_SIZES, - mp->width, mp->height); + v4l2_find_nearest_size(webcam_sizes, + VIVID_WEBCAM_SIZES, width, + height, mp->width, mp->height); w = sz->width; h = sz->height; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h index 94079815dbc2..47d8b48820df 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.h +++ b/drivers/media/platform/vivid/vivid-vid-cap.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vid-cap.h - video capture support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VID_CAP_H_ diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index a651527d80db..e5914be0e12d 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vid-common.c - common video support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> @@ -874,7 +862,8 @@ int vidioc_g_edid(struct file *file, void *_fh, return -EINVAL; if (edid->start_block + edid->blocks > dev->edid_blocks) edid->blocks = dev->edid_blocks - edid->start_block; - cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); + if (adap) + cec_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128); return 0; } diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h index 4b6175eab8a2..29b6c0b40a1b 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.h +++ b/drivers/media/platform/vivid/vivid-vid-common.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vid-common.h - common video support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VID_COMMON_H_ diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 0b1b6218ede8..51fec66d8d45 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vivid-vid-out.c - video output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #include <linux/errno.h> diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h index dfa84db184ed..e87aacf843c5 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.h +++ b/drivers/media/platform/vivid/vivid-vid-out.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * vivid-vid-out.h - video output support functions. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. */ #ifndef _VIVID_VID_OUT_H_ diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c index 4257451f1bd8..0b86ed01e85d 100644 --- a/drivers/media/platform/vsp1/vsp1_dl.c +++ b/drivers/media/platform/vsp1/vsp1_dl.c @@ -509,7 +509,8 @@ static bool vsp1_dl_list_hw_update_pending(struct vsp1_dl_manager *dlm) return !!(vsp1_read(vsp1, VI6_DL_BODY_SIZE) & VI6_DL_BODY_SIZE_UPD); else - return !!(vsp1_read(vsp1, VI6_CMD(dlm->index) & VI6_CMD_UPDHDR)); + return !!(vsp1_read(vsp1, VI6_CMD(dlm->index)) + & VI6_CMD_UPDHDR); } static void vsp1_dl_list_hw_enqueue(struct vsp1_dl_list *dl) diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index 7ce69f23f50a..b8fee1834253 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -27,6 +27,7 @@ #include "vsp1_pipe.h" #include "vsp1_rwpf.h" +#define BRU_NAME(e) (e)->type == VSP1_ENTITY_BRU ? "BRU" : "BRS" /* ----------------------------------------------------------------------------- * Interrupt Handling @@ -88,7 +89,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, struct vsp1_entity *next; struct vsp1_dl_list *dl; struct v4l2_subdev_format format; - const char *bru_name; unsigned long flags; unsigned int i; int ret; @@ -99,7 +99,6 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, drm_pipe = &vsp1->drm->pipe[pipe_index]; pipe = &drm_pipe->pipe; bru = to_bru(&pipe->bru->subdev); - bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"; if (!cfg) { /* @@ -165,7 +164,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, bru_name, i); + format.format.code, BRU_NAME(pipe->bru), i); } format.pad = pipe->bru->source_pad; @@ -181,7 +180,7 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index, dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, bru_name, i); + format.format.code, BRU_NAME(pipe->bru), i); format.pad = RWPF_PAD_SINK; ret = v4l2_subdev_call(&pipe->output->entity.subdev, pad, set_fmt, NULL, @@ -473,9 +472,9 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, if (ret < 0) return ret; - dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on BRU pad %u\n", + dev_dbg(vsp1->dev, "%s: set format %ux%u (%x) on %s pad %u\n", __func__, format.format.width, format.format.height, - format.format.code, format.pad); + format.format.code, BRU_NAME(pipe->bru), format.pad); sel.pad = bru_input; sel.target = V4L2_SEL_TGT_COMPOSE; @@ -486,10 +485,9 @@ static int vsp1_du_setup_rpf_pipe(struct vsp1_device *vsp1, if (ret < 0) return ret; - dev_dbg(vsp1->dev, - "%s: set selection (%u,%u)/%ux%u on BRU pad %u\n", + dev_dbg(vsp1->dev, "%s: set selection (%u,%u)/%ux%u on %s pad %u\n", __func__, sel.r.left, sel.r.top, sel.r.width, sel.r.height, - sel.pad); + BRU_NAME(pipe->bru), sel.pad); return 0; } @@ -514,12 +512,9 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) struct vsp1_entity *entity; struct vsp1_entity *next; struct vsp1_dl_list *dl; - const char *bru_name; unsigned int i; int ret; - bru_name = pipe->bru->type == VSP1_ENTITY_BRU ? "BRU" : "BRS"; - /* Prepare the display list. */ dl = vsp1_dl_list_get(pipe->output->dlm); @@ -530,6 +525,15 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) struct vsp1_rwpf *rpf = vsp1->rpf[i]; unsigned int j; + /* + * Make sure we don't accept more inputs than the hardware can + * handle. This is a temporary fix to avoid display stall, we + * need to instead allocate the BRU or BRS to display pipelines + * dynamically based on the number of planes they each use. + */ + if (pipe->num_inputs >= pipe->bru->source_pad) + pipe->inputs[i] = NULL; + if (!pipe->inputs[i]) continue; @@ -561,7 +565,7 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index) rpf->entity.sink_pad = i; dev_dbg(vsp1->dev, "%s: connecting RPF.%u to %s:%u\n", - __func__, rpf->entity.index, bru_name, i); + __func__, rpf->entity.index, BRU_NAME(pipe->bru), i); ret = vsp1_du_setup_rpf_pipe(vsp1, pipe, rpf, i); if (ret < 0) diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c index e6fa16d7fda8..704920753998 100644 --- a/drivers/media/platform/vsp1/vsp1_lif.c +++ b/drivers/media/platform/vsp1/vsp1_lif.c @@ -155,6 +155,18 @@ static void lif_configure(struct vsp1_entity *entity, (obth << VI6_LIF_CTRL_OBTH_SHIFT) | (format->code == 0 ? VI6_LIF_CTRL_CFMT : 0) | VI6_LIF_CTRL_REQSEL | VI6_LIF_CTRL_LIF_EN); + + /* + * On R-Car V3M the LIF0 buffer attribute register has to be set to a + * non-default value to guarantee proper operation (otherwise artifacts + * may appear on the output). The value required by the manual is not + * explained but is likely a buffer size or threshold. + */ + if ((entity->vsp1->version & VI6_IP_VERSION_MASK) == + (VI6_IP_VERSION_MODEL_VSPD_V3 | VI6_IP_VERSION_SOC_V3M)) + vsp1_lif_write(lif, dl, VI6_LIF_LBA, + VI6_LIF_LBA_LBA0 | + (1536 << VI6_LIF_LBA_LBA1_SHIFT)); } static const struct vsp1_entity_operations lif_entity_ops = { diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 26c4ffad2f46..dae0c1901297 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -225,7 +225,7 @@ #define VI6_RPF_MULT_ALPHA_P_MMD_RATIO (1 << 8) #define VI6_RPF_MULT_ALPHA_P_MMD_IMAGE (2 << 8) #define VI6_RPF_MULT_ALPHA_P_MMD_BOTH (3 << 8) -#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff < 0) +#define VI6_RPF_MULT_ALPHA_RATIO_MASK (0xff << 0) #define VI6_RPF_MULT_ALPHA_RATIO_SHIFT 0 /* ----------------------------------------------------------------------------- @@ -693,6 +693,11 @@ #define VI6_LIF_CSBTH_LBTH_MASK (0x7ff << 0) #define VI6_LIF_CSBTH_LBTH_SHIFT 0 +#define VI6_LIF_LBA 0x3b0c +#define VI6_LIF_LBA_LBA0 (1 << 31) +#define VI6_LIF_LBA_LBA1_MASK (0xfff << 16) +#define VI6_LIF_LBA_LBA1_SHIFT 16 + /* ----------------------------------------------------------------------------- * Security Control Registers */ @@ -705,6 +710,7 @@ */ #define VI6_IP_VERSION 0x3f00 +#define VI6_IP_VERSION_MASK (0xffff << 0) #define VI6_IP_VERSION_MODEL_MASK (0xff << 8) #define VI6_IP_VERSION_MODEL_VSPS_H2 (0x09 << 8) #define VI6_IP_VERSION_MODEL_VSPR_H2 (0x0a << 8) diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c index f7f3b4b2c2de..8bd6b2f1af15 100644 --- a/drivers/media/platform/vsp1/vsp1_wpf.c +++ b/drivers/media/platform/vsp1/vsp1_wpf.c @@ -452,7 +452,7 @@ static void wpf_configure(struct vsp1_entity *entity, : VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index); } - if (pipe->bru || pipe->num_inputs > 1) + if (pipe->bru) srcrpf |= pipe->bru->type == VSP1_ENTITY_BRU ? VI6_WPF_SRCRPF_VIRACT_MST : VI6_WPF_SRCRPF_VIRACT2_MST; |