aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform')
-rw-r--r--drivers/media/platform/Kconfig90
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.c2
-rw-r--r--drivers/media/platform/aspeed-video.c33
-rw-r--r--drivers/media/platform/atmel/Kconfig2
-rw-r--r--drivers/media/platform/atmel/atmel-isc-regs.h21
-rw-r--r--drivers/media/platform/atmel/atmel-isc.c952
-rw-r--r--drivers/media/platform/coda/coda-bit.c3
-rw-r--r--drivers/media/platform/coda/coda-common.c130
-rw-r--r--drivers/media/platform/cros-ec-cec/cros-ec-cec.c1
-rw-r--r--drivers/media/platform/davinci/isif.c9
-rw-r--r--drivers/media/platform/davinci/vpbe.c2
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c2
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c3
-rw-r--r--drivers/media/platform/davinci/vpif_display.c4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c2
-rw-r--r--drivers/media/platform/imx-pxp.c4
-rw-r--r--drivers/media/platform/marvell-ccic/Kconfig4
-rw-r--r--drivers/media/platform/meson/Makefile1
-rw-r--r--drivers/media/platform/meson/ao-cec-g12a.c779
-rw-r--r--drivers/media/platform/meson/ao-cec.c16
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c75
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h16
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c10
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c4
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c4
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c27
-rw-r--r--drivers/media/platform/mtk-vpu/mtk_vpu.c2
-rw-r--r--drivers/media/platform/mx2_emmaprp.c4
-rw-r--r--drivers/media/platform/omap/Kconfig2
-rw-r--r--drivers/media/platform/omap/omap_vout.c15
-rw-r--r--drivers/media/platform/pxa_camera.c2
-rw-r--r--drivers/media/platform/qcom/venus/hfi_helper.h4
-rw-r--r--drivers/media/platform/rcar-vin/Kconfig3
-rw-r--r--drivers/media/platform/rcar-vin/rcar-core.c47
-rw-r--r--drivers/media/platform/rcar-vin/rcar-csi2.c184
-rw-r--r--drivers/media/platform/rcar-vin/rcar-dma.c2
-rw-r--r--drivers/media/platform/rcar_drif.c8
-rw-r--r--drivers/media/platform/rcar_fdp1.c28
-rw-r--r--drivers/media/platform/s5p-cec/s5p_cec.c16
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c6
-rw-r--r--drivers/media/platform/seco-cec/seco-cec.c1
-rw-r--r--drivers/media/platform/sh_veu.c6
-rw-r--r--drivers/media/platform/sti/c8sectpfe/Kconfig2
-rw-r--r--drivers/media/platform/sti/cec/stih-cec.c21
-rw-r--r--drivers/media/platform/sti/delta/delta-ipc.c6
-rw-r--r--drivers/media/platform/stm32/stm32-cec.c11
-rw-r--r--drivers/media/platform/stm32/stm32-dcmi.c60
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c4
-rw-r--r--drivers/media/platform/tegra-cec/tegra_cec.c16
-rw-r--r--drivers/media/platform/ti-vpe/cal.c12
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c6
-rw-r--r--drivers/media/platform/vicodec/codec-fwht.c121
-rw-r--r--drivers/media/platform/vicodec/codec-fwht.h12
-rw-r--r--drivers/media/platform/vicodec/codec-v4l2-fwht.c431
-rw-r--r--drivers/media/platform/vicodec/codec-v4l2-fwht.h7
-rw-r--r--drivers/media/platform/vicodec/vicodec-core.c762
-rw-r--r--drivers/media/platform/video-mux.c5
-rw-r--r--drivers/media/platform/vim2m.c69
-rw-r--r--drivers/media/platform/vimc/Kconfig2
-rw-r--r--drivers/media/platform/vimc/vimc-capture.c93
-rw-r--r--drivers/media/platform/vimc/vimc-common.c313
-rw-r--r--drivers/media/platform/vimc/vimc-common.h60
-rw-r--r--drivers/media/platform/vimc/vimc-core.c2
-rw-r--r--drivers/media/platform/vimc/vimc-debayer.c98
-rw-r--r--drivers/media/platform/vimc/vimc-scaler.c78
-rw-r--r--drivers/media/platform/vimc/vimc-sensor.c70
-rw-r--r--drivers/media/platform/vimc/vimc-streamer.c40
-rw-r--r--drivers/media/platform/vimc/vimc-streamer.h22
-rw-r--r--drivers/media/platform/vivid/Kconfig6
-rw-r--r--drivers/media/platform/vivid/vivid-core.c2
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c2
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c14
-rw-r--r--drivers/media/platform/vsp1/vsp1_brx.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_clu.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.c84
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.h6
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.c94
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c3
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.h7
-rw-r--r--drivers/media/platform/vsp1/vsp1_hgo.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_hgt.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_hsit.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_lut.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_pipe.c62
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h6
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h1
-rw-r--r--drivers/media/platform/vsp1/vsp1_sru.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_uif.c1
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c16
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c83
-rw-r--r--drivers/media/platform/xilinx/Kconfig6
97 files changed, 3390 insertions, 1868 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 4acbed189644..011c1c2fcf19 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -6,7 +6,7 @@ menuconfig V4L_PLATFORM_DRIVERS
bool "V4L platform devices"
depends on MEDIA_CAMERA_SUPPORT
default n
- ---help---
+ help
Say Y here to enable support for platform-specific V4L drivers.
if V4L_PLATFORM_DRIVERS
@@ -55,7 +55,7 @@ config VIDEO_VIU
depends on VIDEO_V4L2 && (PPC_MPC512x || COMPILE_TEST) && I2C
select VIDEOBUF_DMA_CONTIG
default y
- ---help---
+ help
Support for Freescale VIU video driver. This device captures
video data, or overlays video on DIU frame buffer.
@@ -80,13 +80,13 @@ config VIDEO_OMAP3
select VIDEOBUF2_DMA_CONTIG
select MFD_SYSCON
select V4L2_FWNODE
- ---help---
+ help
Driver for an OMAP 3 camera controller.
config VIDEO_OMAP3_DEBUG
bool "OMAP 3 Camera debug messages"
depends on VIDEO_OMAP3
- ---help---
+ help
Enable debug messages on OMAP 3 camera controller driver.
config VIDEO_PXA27x
@@ -96,7 +96,7 @@ config VIDEO_PXA27x
select VIDEOBUF2_DMA_SG
select SG_SPLIT
select V4L2_FWNODE
- ---help---
+ help
This is a v4l2 driver for the PXA27x Quick Capture Interface
config VIDEO_QCOM_CAMSS
@@ -112,7 +112,7 @@ config VIDEO_S3C_CAMIF
depends on PM
depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
- ---help---
+ help
This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera
host interface (CAMIF).
@@ -125,7 +125,7 @@ config VIDEO_STM32_DCMI
depends on ARCH_STM32 || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
- ---help---
+ help
This module makes the STM32 Digital Camera Memory Interface (DCMI)
available as a v4l2 device.
@@ -138,7 +138,7 @@ config VIDEO_RENESAS_CEU
depends on ARCH_SHMOBILE || ARCH_R7S72100 || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
- ---help---
+ help
This is a v4l2 driver for the Renesas CEU Interface
source "drivers/media/platform/exynos4-is/Kconfig"
@@ -155,7 +155,7 @@ config VIDEO_TI_CAL
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
default n
- ---help---
+ help
Support for the TI CAL (Camera Adaptation Layer) block
found on DRA72X SoC.
In TI Technical Reference Manual this module is referred as
@@ -168,7 +168,7 @@ menuconfig V4L_MEM2MEM_DRIVERS
depends on VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
default n
- ---help---
+ help
Say Y here to enable selecting drivers for V4L devices that
use system memory for both source and destination buffers, as opposed
to capture and output drivers, which use memory buffers for just
@@ -184,7 +184,7 @@ config VIDEO_CODA
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
select GENERIC_ALLOCATOR
- ---help---
+ help
Coda is a range of video codec IPs that supports
H.264, MPEG-4, and other video formats.
@@ -207,7 +207,7 @@ config VIDEO_MEDIATEK_JPEG
depends on ARCH_MEDIATEK || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
- ---help---
+ help
Mediatek jpeg codec driver provides HW capability to decode
JPEG format
@@ -218,7 +218,7 @@ config VIDEO_MEDIATEK_VPU
tristate "Mediatek Video Processor Unit"
depends on VIDEO_DEV && VIDEO_V4L2
depends on ARCH_MEDIATEK || COMPILE_TEST
- ---help---
+ help
This driver provides downloading VPU firmware and
communicating with VPU. This driver for hw video
codec embedded in Mediatek's MT8173 SOCs. It is able
@@ -236,7 +236,7 @@ config VIDEO_MEDIATEK_MDP
select V4L2_MEM2MEM_DEV
select VIDEO_MEDIATEK_VPU
default n
- ---help---
+ help
It is a v4l2 driver and present in Mediatek MT8173 SoCs.
The driver supports for scaling and color space conversion.
@@ -252,7 +252,7 @@ config VIDEO_MEDIATEK_VCODEC
select V4L2_MEM2MEM_DEV
select VIDEO_MEDIATEK_VPU
default n
- ---help---
+ help
Mediatek video codec driver provides HW capability to
encode and decode in a range of video formats
This driver rely on VPU driver to communicate with VPU.
@@ -276,7 +276,7 @@ config VIDEO_SAMSUNG_S5P_G2D
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
default n
- ---help---
+ help
This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D
2d graphics accelerator.
@@ -286,7 +286,7 @@ config VIDEO_SAMSUNG_S5P_JPEG
depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
- ---help---
+ help
This is a v4l2 driver for Samsung S5P, EXYNOS3250
and EXYNOS4 JPEG codec
@@ -407,7 +407,7 @@ config VIDEO_RENESAS_FDP1
depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
- ---help---
+ help
This is a V4L2 driver for the Renesas Fine Display Processor
providing colour space conversion, and de-interlacing features.
@@ -420,7 +420,7 @@ config VIDEO_RENESAS_JPU
depends on ARCH_RENESAS || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
- ---help---
+ help
This is a V4L2 driver for the Renesas JPEG Processing Unit.
To compile this driver as a module, choose M here: the module
@@ -430,7 +430,7 @@ config VIDEO_RENESAS_FCP
tristate "Renesas Frame Compression Processor"
depends on ARCH_RENESAS || COMPILE_TEST
depends on OF
- ---help---
+ help
This is a driver for the Renesas Frame Compression Processor (FCP).
The FCP is a companion module of video processing modules in the
Renesas R-Car Gen3 SoCs. It handles memory access for the codec,
@@ -446,7 +446,7 @@ config VIDEO_RENESAS_VSP1
depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_VMALLOC
- ---help---
+ help
This is a V4L2 driver for the Renesas VSP1 video processing engine.
To compile this driver as a module, choose M here: the module
@@ -459,7 +459,7 @@ config VIDEO_ROCKCHIP_RGA
select VIDEOBUF2_DMA_SG
select V4L2_MEM2MEM_DEV
default n
- ---help---
+ help
This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator.
Rockchip RGA is a separate 2D raster graphic acceleration unit.
It accelerates 2D graphics operations, such as point/line drawing,
@@ -477,14 +477,14 @@ config VIDEO_TI_VPE
select VIDEO_TI_SC
select VIDEO_TI_CSC
default n
- ---help---
+ help
Support for the TI VPE(Video Processing Engine) block
found on DRA7XX SoC.
config VIDEO_TI_VPE_DEBUG
bool "VPE debug messages"
depends on VIDEO_TI_VPE
- ---help---
+ help
Enable debug messages on VPE driver.
config VIDEO_QCOM_VENUS
@@ -495,7 +495,7 @@ config VIDEO_QCOM_VENUS
select QCOM_SCM if ARCH_QCOM
select VIDEOBUF2_DMA_SG
select V4L2_MEM2MEM_DEV
- ---help---
+ help
This is a V4L2 driver for Qualcomm Venus video accelerator
hardware. It accelerates encoding and decoding operations
on various Qualcomm SoCs.
@@ -530,7 +530,7 @@ config VIDEO_VIM2M
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
default n
- ---help---
+ help
This is a virtual test device for the memory-to-memory driver
framework.
@@ -542,7 +542,7 @@ menuconfig DVB_PLATFORM_DRIVERS
bool "DVB platform devices"
depends on MEDIA_DIGITAL_TV_SUPPORT
default n
- ---help---
+ help
Say Y here to enable support for platform-specific Digital TV drivers.
if DVB_PLATFORM_DRIVERS
@@ -562,7 +562,7 @@ config VIDEO_CROS_EC_CEC
select CEC_NOTIFIER
select CHROME_PLATFORMS
select CROS_EC_PROTO
- ---help---
+ help
If you say yes here you will get support for the
ChromeOS Embedded Controller's CEC.
The CEC bus is present in the HDMI connector and enables communication
@@ -573,18 +573,34 @@ config VIDEO_MESON_AO_CEC
depends on ARCH_MESON || COMPILE_TEST
select CEC_CORE
select CEC_NOTIFIER
- ---help---
+ help
This is a driver for Amlogic Meson SoCs AO CEC interface. It uses the
generic CEC framework interface.
CEC bus is present in the HDMI connector and enables communication
+config VIDEO_MESON_G12A_AO_CEC
+ tristate "Amlogic Meson G12A AO CEC driver"
+ depends on ARCH_MESON || COMPILE_TEST
+ depends on COMMON_CLK && OF
+ select REGMAP
+ select REGMAP_MMIO
+ select CEC_CORE
+ select CEC_NOTIFIER
+ ---help---
+ This is a driver for Amlogic Meson G12A SoCs AO CEC interface.
+ This driver if for the new AO-CEC module found in G12A SoCs,
+ usually named AO_CEC_B in documentation.
+ It uses the generic CEC framework interface.
+ CEC bus is present in the HDMI connector and enables communication
+ between compatible devices.
+
config CEC_GPIO
tristate "Generic GPIO-based CEC driver"
depends on PREEMPT || COMPILE_TEST
select CEC_CORE
select CEC_PIN
select GPIOLIB
- ---help---
+ help
This is a generic GPIO-based CEC driver.
The CEC bus is present in the HDMI connector and enables communication
between compatible devices.
@@ -594,7 +610,7 @@ config VIDEO_SAMSUNG_S5P_CEC
depends on ARCH_EXYNOS || COMPILE_TEST
select CEC_CORE
select CEC_NOTIFIER
- ---help---
+ help
This is a driver for Samsung S5P HDMI CEC interface. It uses the
generic CEC framework interface.
CEC bus is present in the HDMI connector and enables communication
@@ -605,7 +621,7 @@ config VIDEO_STI_HDMI_CEC
depends on ARCH_STI || COMPILE_TEST
select CEC_CORE
select CEC_NOTIFIER
- ---help---
+ help
This is a driver for STIH4xx HDMI CEC interface. It uses the
generic CEC framework interface.
CEC bus is present in the HDMI connector and enables communication
@@ -617,7 +633,7 @@ config VIDEO_STM32_HDMI_CEC
select REGMAP
select REGMAP_MMIO
select CEC_CORE
- ---help---
+ help
This is a driver for STM32 interface. It uses the
generic CEC framework interface.
CEC bus is present in the HDMI connector and enables communication
@@ -628,7 +644,7 @@ config VIDEO_TEGRA_HDMI_CEC
depends on ARCH_TEGRA || COMPILE_TEST
select CEC_CORE
select CEC_NOTIFIER
- ---help---
+ help
This is a driver for the Tegra HDMI CEC interface. It uses the
generic CEC framework interface.
The CEC bus is present in the HDMI connector and enables communication
@@ -649,7 +665,7 @@ config VIDEO_SECO_CEC
config VIDEO_SECO_RC
bool "SECO Boards IR RC5 support"
depends on VIDEO_SECO_CEC
- depends on RC_CORE
+ depends on RC_CORE=y || RC_CORE = VIDEO_SECO_CEC
help
If you say yes here you will get support for the
SECO Boards Consumer-IR in seco-cec driver.
@@ -662,7 +678,7 @@ menuconfig SDR_PLATFORM_DRIVERS
bool "SDR platform devices"
depends on MEDIA_SDR_SUPPORT
default n
- ---help---
+ help
Say Y here to enable support for platform-specific SDR Drivers.
if SDR_PLATFORM_DRIVERS
@@ -672,7 +688,7 @@ config VIDEO_RCAR_DRIF
depends on VIDEO_V4L2
depends on ARCH_RENESAS || COMPILE_TEST
select VIDEOBUF2_VMALLOC
- ---help---
+ help
Say Y if you want to enable R-Car Gen3 DRIF support. DRIF is Digital
Radio Interface that interfaces with an RF front end chip. It is a
receiver of digital data which uses DMA to transfer received data to
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
index 5c17624aaade..fe7b937eb5f2 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1540,7 +1540,7 @@ static int vpfe_enum_fmt(struct file *file, void *priv,
if (!fmt)
return -EINVAL;
- strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
f->type = vpfe->fmt.type;
diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
index 692e08ef38c0..8144fe36ad48 100644
--- a/drivers/media/platform/aspeed-video.c
+++ b/drivers/media/platform/aspeed-video.c
@@ -14,7 +14,6 @@
#include <linux/of_irq.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
-#include <linux/reset.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@@ -208,7 +207,6 @@ struct aspeed_video {
void __iomem *base;
struct clk *eclk;
struct clk *vclk;
- struct reset_control *rst;
struct device *dev;
struct v4l2_ctrl_handler ctrl_handler;
@@ -483,19 +481,10 @@ static void aspeed_video_enable_mode_detect(struct aspeed_video *video)
aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_MODE_DET);
}
-static void aspeed_video_reset(struct aspeed_video *video)
-{
- /* Reset the engine */
- reset_control_assert(video->rst);
-
- /* Don't usleep here; function may be called in interrupt context */
- udelay(100);
- reset_control_deassert(video->rst);
-}
-
static void aspeed_video_off(struct aspeed_video *video)
{
- aspeed_video_reset(video);
+ /* Disable interrupts */
+ aspeed_video_write(video, VE_INTERRUPT_CTRL, 0);
/* Turn off the relevant clocks */
clk_disable_unprepare(video->vclk);
@@ -507,8 +496,6 @@ static void aspeed_video_on(struct aspeed_video *video)
/* Turn on the relevant clocks */
clk_prepare_enable(video->eclk);
clk_prepare_enable(video->vclk);
-
- aspeed_video_reset(video);
}
static void aspeed_video_bufs_done(struct aspeed_video *video,
@@ -1464,7 +1451,9 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q)
* Need to force stop any DMA and try and get HW into a good
* state for future calls to start streaming again.
*/
- aspeed_video_reset(video);
+ aspeed_video_off(video);
+ aspeed_video_on(video);
+
aspeed_video_init_regs(video);
aspeed_video_get_resolution(video);
@@ -1619,17 +1608,7 @@ static int aspeed_video_init(struct aspeed_video *video)
return PTR_ERR(video->vclk);
}
- video->rst = devm_reset_control_get_exclusive(dev, NULL);
- if (IS_ERR(video->rst)) {
- dev_err(dev, "Unable to get VE reset\n");
- return PTR_ERR(video->rst);
- }
-
- rc = of_reserved_mem_device_init(dev);
- if (rc) {
- dev_err(dev, "Unable to reserve memory\n");
- return rc;
- }
+ of_reserved_mem_device_init(dev);
rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (rc) {
diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig
index a211ef20f77e..c3f6a47cdc0e 100644
--- a/drivers/media/platform/atmel/Kconfig
+++ b/drivers/media/platform/atmel/Kconfig
@@ -15,6 +15,6 @@ config VIDEO_ATMEL_ISI
depends on ARCH_AT91 || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
- ---help---
+ help
This module makes the ATMEL Image Sensor Interface available
as a v4l2 device.
diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h
index 2aadc19235ea..8f7f8efc71a7 100644
--- a/drivers/media/platform/atmel/atmel-isc-regs.h
+++ b/drivers/media/platform/atmel/atmel-isc-regs.h
@@ -24,6 +24,8 @@
#define ISC_PFE_CFG0_HPOL_LOW BIT(0)
#define ISC_PFE_CFG0_VPOL_LOW BIT(1)
#define ISC_PFE_CFG0_PPOL_LOW BIT(2)
+#define ISC_PFE_CFG0_CCIR656 BIT(9)
+#define ISC_PFE_CFG0_CCIR_CRC BIT(10)
#define ISC_PFE_CFG0_MODE_PROGRESSIVE (0x0 << 4)
#define ISC_PFE_CFG0_MODE_MASK GENMASK(6, 4)
@@ -35,6 +37,25 @@
#define ISC_PFG_CFG0_BPS_TWELVE (0x0 << 28)
#define ISC_PFE_CFG0_BPS_MASK GENMASK(30, 28)
+#define ISC_PFE_CFG0_COLEN BIT(12)
+#define ISC_PFE_CFG0_ROWEN BIT(13)
+
+/* ISC Parallel Front End Configuration 1 Register */
+#define ISC_PFE_CFG1 0x00000010
+
+#define ISC_PFE_CFG1_COLMIN(v) ((v))
+#define ISC_PFE_CFG1_COLMIN_MASK GENMASK(15, 0)
+#define ISC_PFE_CFG1_COLMAX(v) ((v) << 16)
+#define ISC_PFE_CFG1_COLMAX_MASK GENMASK(31, 16)
+
+/* ISC Parallel Front End Configuration 2 Register */
+#define ISC_PFE_CFG2 0x00000014
+
+#define ISC_PFE_CFG2_ROWMIN(v) ((v))
+#define ISC_PFE_CFG2_ROWMIN_MASK GENMASK(15, 0)
+#define ISC_PFE_CFG2_ROWMAX(v) ((v) << 16)
+#define ISC_PFE_CFG2_ROWMAX_MASK GENMASK(31, 16)
+
/* ISC Clock Enable Register */
#define ISC_CLKEN 0x00000018
diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c
index 50178968b8a6..94cb309fdb52 100644
--- a/drivers/media/platform/atmel/atmel-isc.c
+++ b/drivers/media/platform/atmel/atmel-isc.c
@@ -89,35 +89,25 @@ struct isc_subdev_entity {
struct list_head list;
};
-/* Indicate the format is generated by the sensor */
-#define FMT_FLAG_FROM_SENSOR BIT(0)
-/* Indicate the format is produced by ISC itself */
-#define FMT_FLAG_FROM_CONTROLLER BIT(1)
-/* Indicate a Raw Bayer format */
-#define FMT_FLAG_RAW_FORMAT BIT(2)
-
-#define FMT_FLAG_RAW_FROM_SENSOR (FMT_FLAG_FROM_SENSOR | \
- FMT_FLAG_RAW_FORMAT)
-
/*
* struct isc_format - ISC media bus format information
+ This structure represents the interface between the ISC
+ and the sensor. It's the input format received by
+ the ISC.
* @fourcc: Fourcc code for this format
* @mbus_code: V4L2 media bus format code.
- * flags: Indicate format from sensor or converted by controller
- * @bpp: Bits per pixel (when stored in memory)
- * (when transferred over a bus)
- * @sd_support: Subdev supports this format
- * @isc_support: ISC can convert raw format to this format
+ * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer.
+ this is either BGBG, RGRG, etc.
+ * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC
*/
struct isc_format {
u32 fourcc;
u32 mbus_code;
- u32 flags;
- u8 bpp;
+ u32 cfa_baycfg;
bool sd_support;
- bool isc_support;
+ u32 pfe_cfg0_bps;
};
/* Pipeline bitmap */
@@ -135,16 +125,31 @@ struct isc_format {
#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE)
+/*
+ * struct fmt_config - ISC format configuration and internal pipeline
+ This structure represents the internal configuration
+ of the ISC.
+ It also holds the format that ISC will present to v4l2.
+ * @sd_format: Pointer to an isc_format struct that holds the sensor
+ configuration.
+ * @fourcc: Fourcc code for this format.
+ * @bpp: Bytes per pixel in the current format.
+ * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging)
+ * @dcfg_imode: Configuration of the input of the DMA module
+ * @dctrl_dview: Configuration of the output of the DMA module
+ * @bits_pipeline: Configuration of the pipeline, which modules are enabled
+ */
struct fmt_config {
- u32 fourcc;
+ struct isc_format *sd_format;
- u32 pfe_cfg0_bps;
- u32 cfa_baycfg;
- u32 rlp_cfg_mode;
- u32 dcfg_imode;
- u32 dctrl_dview;
+ u32 fourcc;
+ u8 bpp;
- u32 bits_pipeline;
+ u32 rlp_cfg_mode;
+ u32 dcfg_imode;
+ u32 dctrl_dview;
+
+ u32 bits_pipeline;
};
#define HIST_ENTRIES 512
@@ -196,8 +201,9 @@ struct isc_device {
struct v4l2_format fmt;
struct isc_format **user_formats;
unsigned int num_user_formats;
- const struct isc_format *current_fmt;
- const struct isc_format *raw_fmt;
+
+ struct fmt_config config;
+ struct fmt_config try_config;
struct isc_ctrls ctrls;
struct work_struct awb_work;
@@ -210,319 +216,125 @@ struct isc_device {
struct list_head subdev_entities;
};
-static struct isc_format formats_list[] = {
- {
- .fourcc = V4L2_PIX_FMT_SBGGR8,
- .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 8,
- },
- {
- .fourcc = V4L2_PIX_FMT_SGBRG8,
- .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 8,
- },
- {
- .fourcc = V4L2_PIX_FMT_SGRBG8,
- .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 8,
- },
- {
- .fourcc = V4L2_PIX_FMT_SRGGB8,
- .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 8,
- },
- {
- .fourcc = V4L2_PIX_FMT_SBGGR10,
- .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 16,
- },
+/* This is a list of the formats that the ISC can *output* */
+static struct isc_format controller_formats[] = {
{
- .fourcc = V4L2_PIX_FMT_SGBRG10,
- .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 16,
- },
- {
- .fourcc = V4L2_PIX_FMT_SGRBG10,
- .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 16,
+ .fourcc = V4L2_PIX_FMT_ARGB444,
},
{
- .fourcc = V4L2_PIX_FMT_SRGGB10,
- .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 16,
+ .fourcc = V4L2_PIX_FMT_ARGB555,
},
{
- .fourcc = V4L2_PIX_FMT_SBGGR12,
- .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 16,
+ .fourcc = V4L2_PIX_FMT_RGB565,
},
{
- .fourcc = V4L2_PIX_FMT_SGBRG12,
- .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 16,
+ .fourcc = V4L2_PIX_FMT_ABGR32,
},
{
- .fourcc = V4L2_PIX_FMT_SGRBG12,
- .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 16,
+ .fourcc = V4L2_PIX_FMT_XBGR32,
},
{
- .fourcc = V4L2_PIX_FMT_SRGGB12,
- .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .flags = FMT_FLAG_RAW_FROM_SENSOR,
- .bpp = 16,
+ .fourcc = V4L2_PIX_FMT_YUV420,
},
{
- .fourcc = V4L2_PIX_FMT_YUV420,
- .mbus_code = 0x0,
- .flags = FMT_FLAG_FROM_CONTROLLER,
- .bpp = 12,
+ .fourcc = V4L2_PIX_FMT_YUYV,
},
{
.fourcc = V4L2_PIX_FMT_YUV422P,
- .mbus_code = 0x0,
- .flags = FMT_FLAG_FROM_CONTROLLER,
- .bpp = 16,
},
{
.fourcc = V4L2_PIX_FMT_GREY,
- .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
- .flags = FMT_FLAG_FROM_CONTROLLER |
- FMT_FLAG_FROM_SENSOR,
- .bpp = 8,
- },
- {
- .fourcc = V4L2_PIX_FMT_ARGB444,
- .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
- .flags = FMT_FLAG_FROM_CONTROLLER,
- .bpp = 16,
- },
- {
- .fourcc = V4L2_PIX_FMT_ARGB555,
- .mbus_code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
- .flags = FMT_FLAG_FROM_CONTROLLER,
- .bpp = 16,
- },
- {
- .fourcc = V4L2_PIX_FMT_RGB565,
- .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
- .flags = FMT_FLAG_FROM_CONTROLLER,
- .bpp = 16,
- },
- {
- .fourcc = V4L2_PIX_FMT_ARGB32,
- .mbus_code = MEDIA_BUS_FMT_ARGB8888_1X32,
- .flags = FMT_FLAG_FROM_CONTROLLER,
- .bpp = 32,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
- .flags = FMT_FLAG_FROM_CONTROLLER |
- FMT_FLAG_FROM_SENSOR,
- .bpp = 16,
},
};
-static struct fmt_config fmt_configs_list[] = {
+/* This is a list of formats that the ISC can receive as *input* */
+static struct isc_format formats_list[] = {
{
.fourcc = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
.pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
.cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
},
{
.fourcc = V4L2_PIX_FMT_SGBRG8,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
.pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
.cfa_baycfg = ISC_BAY_CFG_GBGB,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
},
{
.fourcc = V4L2_PIX_FMT_SGRBG8,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
.pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
.cfa_baycfg = ISC_BAY_CFG_GRGR,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
},
{
.fourcc = V4L2_PIX_FMT_SRGGB8,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
.pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
.cfa_baycfg = ISC_BAY_CFG_RGRG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
},
{
.fourcc = V4L2_PIX_FMT_SBGGR10,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
+ .cfa_baycfg = ISC_BAY_CFG_RGRG,
},
{
.fourcc = V4L2_PIX_FMT_SGBRG10,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
.cfa_baycfg = ISC_BAY_CFG_GBGB,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
},
{
.fourcc = V4L2_PIX_FMT_SGRBG10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
.cfa_baycfg = ISC_BAY_CFG_GRGR,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
},
{
.fourcc = V4L2_PIX_FMT_SRGGB10,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
.cfa_baycfg = ISC_BAY_CFG_RGRG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
},
{
.fourcc = V4L2_PIX_FMT_SBGGR12,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
.cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
},
{
.fourcc = V4L2_PIX_FMT_SGBRG12,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
.cfa_baycfg = ISC_BAY_CFG_GBGB,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0
},
{
.fourcc = V4L2_PIX_FMT_SGRBG12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
.cfa_baycfg = ISC_BAY_CFG_GRGR,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
},
{
.fourcc = V4L2_PIX_FMT_SRGGB12,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
.pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
.cfa_baycfg = ISC_BAY_CFG_RGRG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUV420,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC,
- .dcfg_imode = ISC_DCFG_IMODE_YC420P,
- .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR,
- .bits_pipeline = SUB420_ENABLE | SUB422_ENABLE |
- CBC_ENABLE | CSC_ENABLE |
- GAM_ENABLES |
- CFA_ENABLE | WB_ENABLE,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUV422P,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC,
- .dcfg_imode = ISC_DCFG_IMODE_YC422P,
- .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR,
- .bits_pipeline = SUB422_ENABLE |
- CBC_ENABLE | CSC_ENABLE |
- GAM_ENABLES |
- CFA_ENABLE | WB_ENABLE,
},
{
.fourcc = V4L2_PIX_FMT_GREY,
+ .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
.pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = CBC_ENABLE | CSC_ENABLE |
- GAM_ENABLES |
- CFA_ENABLE | WB_ENABLE,
- },
- {
- .fourcc = V4L2_PIX_FMT_ARGB444,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE,
},
{
- .fourcc = V4L2_PIX_FMT_ARGB555,
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE,
},
{
.fourcc = V4L2_PIX_FMT_RGB565,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED16,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE,
- },
- {
- .fourcc = V4L2_PIX_FMT_ARGB32,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED32,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
- .cfa_baycfg = ISC_BAY_CFG_BGBG,
- .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8,
- .dcfg_imode = ISC_DCFG_IMODE_PACKED8,
- .dctrl_dview = ISC_DCTRL_DVIEW_PACKED,
- .bits_pipeline = 0x0
},
};
@@ -571,6 +383,13 @@ static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 },
};
+#define ISC_IS_FORMAT_RAW(mbus_code) \
+ (((mbus_code) & 0xf000) == 0x3000)
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+
static unsigned int sensor_preferred = 1;
module_param(sensor_preferred, uint, 0644);
MODULE_PARM_DESC(sensor_preferred,
@@ -896,40 +715,51 @@ static int isc_buffer_prepare(struct vb2_buffer *vb)
return 0;
}
-static inline bool sensor_is_preferred(const struct isc_format *isc_fmt)
-{
- return (sensor_preferred && isc_fmt->sd_support) ||
- !isc_fmt->isc_support;
-}
-
-static struct fmt_config *get_fmt_config(u32 fourcc)
-{
- struct fmt_config *config;
- int i;
-
- config = &fmt_configs_list[0];
- for (i = 0; i < ARRAY_SIZE(fmt_configs_list); i++) {
- if (config->fourcc == fourcc)
- return config;
-
- config++;
- }
- return NULL;
-}
-
static void isc_start_dma(struct isc_device *isc)
{
struct regmap *regmap = isc->regmap;
- struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix;
- u32 sizeimage = pixfmt->sizeimage;
- struct fmt_config *config = get_fmt_config(isc->current_fmt->fourcc);
+ u32 sizeimage = isc->fmt.fmt.pix.sizeimage;
u32 dctrl_dview;
dma_addr_t addr0;
+ u32 h, w;
+
+ h = isc->fmt.fmt.pix.height;
+ w = isc->fmt.fmt.pix.width;
+
+ /*
+ * In case the sensor is not RAW, it will output a pixel (12-16 bits)
+ * with two samples on the ISC Data bus (which is 8-12)
+ * ISC will count each sample, so, we need to multiply these values
+ * by two, to get the real number of samples for the required pixels.
+ */
+ if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) {
+ h <<= 1;
+ w <<= 1;
+ }
+
+ /*
+ * We limit the column/row count that the ISC will output according
+ * to the configured resolution that we want.
+ * This will avoid the situation where the sensor is misconfigured,
+ * sending more data, and the ISC will just take it and DMA to memory,
+ * causing corruption.
+ */
+ regmap_write(regmap, ISC_PFE_CFG1,
+ (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) |
+ (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK));
+
+ regmap_write(regmap, ISC_PFE_CFG2,
+ (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) |
+ (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK));
+
+ regmap_update_bits(regmap, ISC_PFE_CFG0,
+ ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN,
+ ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN);
addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
regmap_write(regmap, ISC_DAD0, addr0);
- switch (pixfmt->pixelformat) {
+ switch (isc->config.fourcc) {
case V4L2_PIX_FMT_YUV420:
regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3);
regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6);
@@ -942,10 +772,7 @@ static void isc_start_dma(struct isc_device *isc)
break;
}
- if (sensor_is_preferred(isc->current_fmt))
- dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
- else
- dctrl_dview = config->dctrl_dview;
+ dctrl_dview = isc->config.dctrl_dview;
regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS);
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE);
@@ -955,7 +782,6 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
{
struct regmap *regmap = isc->regmap;
struct isc_ctrls *ctrls = &isc->ctrls;
- struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc);
u32 val, bay_cfg;
const u32 *gamma;
unsigned int i;
@@ -969,7 +795,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline)
if (!pipeline)
return;
- bay_cfg = config->cfa_baycfg;
+ bay_cfg = isc->config.sd_format->cfa_baycfg;
regmap_write(regmap, ISC_WB_CFG, bay_cfg);
regmap_write(regmap, ISC_WB_O_RGR, 0x0);
@@ -1011,24 +837,24 @@ static int isc_update_profile(struct isc_device *isc)
}
if (counter < 0) {
- v4l2_warn(&isc->v4l2_dev, "Time out to update profie\n");
+ v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n");
return -ETIMEDOUT;
}
return 0;
}
-static void isc_set_histogram(struct isc_device *isc)
+static void isc_set_histogram(struct isc_device *isc, bool enable)
{
struct regmap *regmap = isc->regmap;
struct isc_ctrls *ctrls = &isc->ctrls;
- struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc);
- if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) {
+ if (enable) {
regmap_write(regmap, ISC_HIS_CFG,
ISC_HIS_CFG_MODE_R |
- (config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT) |
- ISC_HIS_CFG_RAR);
+ (isc->config.sd_format->cfa_baycfg
+ << ISC_HIS_CFG_BAYSEL_SHIFT) |
+ ISC_HIS_CFG_RAR);
regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN);
regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE);
ctrls->hist_id = ISC_HIS_CFG_MODE_R;
@@ -1036,7 +862,7 @@ static void isc_set_histogram(struct isc_device *isc)
regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ);
ctrls->hist_stat = HIST_ENABLED;
- } else if (!ctrls->awb && (ctrls->hist_stat != HIST_DISABLED)) {
+ } else {
regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE);
regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS);
@@ -1044,58 +870,24 @@ static void isc_set_histogram(struct isc_device *isc)
}
}
-static inline void isc_get_param(const struct isc_format *fmt,
- u32 *rlp_mode, u32 *dcfg)
-{
- struct fmt_config *config = get_fmt_config(fmt->fourcc);
-
- *dcfg = ISC_DCFG_YMBSIZE_BEATS8;
-
- switch (fmt->fourcc) {
- case V4L2_PIX_FMT_SBGGR10:
- case V4L2_PIX_FMT_SGBRG10:
- case V4L2_PIX_FMT_SGRBG10:
- case V4L2_PIX_FMT_SRGGB10:
- case V4L2_PIX_FMT_SBGGR12:
- case V4L2_PIX_FMT_SGBRG12:
- case V4L2_PIX_FMT_SGRBG12:
- case V4L2_PIX_FMT_SRGGB12:
- *rlp_mode = config->rlp_cfg_mode;
- *dcfg |= config->dcfg_imode;
- break;
- default:
- *rlp_mode = ISC_RLP_CFG_MODE_DAT8;
- *dcfg |= ISC_DCFG_IMODE_PACKED8;
- break;
- }
-}
-
static int isc_configure(struct isc_device *isc)
{
struct regmap *regmap = isc->regmap;
- const struct isc_format *current_fmt = isc->current_fmt;
- struct fmt_config *curfmt_config = get_fmt_config(current_fmt->fourcc);
- struct fmt_config *rawfmt_config = get_fmt_config(isc->raw_fmt->fourcc);
- struct isc_subdev_entity *subdev = isc->current_subdev;
u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline;
+ struct isc_subdev_entity *subdev = isc->current_subdev;
- if (sensor_is_preferred(current_fmt)) {
- pfe_cfg0 = curfmt_config->pfe_cfg0_bps;
- pipeline = 0x0;
- isc_get_param(current_fmt, &rlp_mode, &dcfg);
- isc->ctrls.hist_stat = HIST_INIT;
- } else {
- pfe_cfg0 = rawfmt_config->pfe_cfg0_bps;
- pipeline = curfmt_config->bits_pipeline;
- rlp_mode = curfmt_config->rlp_cfg_mode;
- dcfg = curfmt_config->dcfg_imode |
+ pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps;
+ rlp_mode = isc->config.rlp_cfg_mode;
+ pipeline = isc->config.bits_pipeline;
+
+ dcfg = isc->config.dcfg_imode |
ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8;
- }
pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE;
mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
- ISC_PFE_CFG0_MODE_MASK;
+ ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC |
+ ISC_PFE_CFG0_CCIR656;
regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
@@ -1107,8 +899,15 @@ static int isc_configure(struct isc_device *isc)
/* Set the pipeline */
isc_set_pipeline(isc, pipeline);
- if (pipeline)
- isc_set_histogram(isc);
+ /*
+ * The current implemented histogram is available for RAW R, B, GB
+ * channels. We need to check if sensor is outputting RAW BAYER
+ */
+ if (isc->ctrls.awb &&
+ ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code))
+ isc_set_histogram(isc, true);
+ else
+ isc_set_histogram(isc, false);
/* Update profile */
return isc_update_profile(isc);
@@ -1125,7 +924,8 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
/* Enable stream on the sub device */
ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1);
if (ret && ret != -ENOIOCTLCMD) {
- v4l2_err(&isc->v4l2_dev, "stream on failed in subdev\n");
+ v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n",
+ ret);
goto err_start_stream;
}
@@ -1223,6 +1023,22 @@ static void isc_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
}
+static struct isc_format *find_format_by_fourcc(struct isc_device *isc,
+ unsigned int fourcc)
+{
+ unsigned int num_formats = isc->num_user_formats;
+ struct isc_format *fmt;
+ unsigned int i;
+
+ for (i = 0; i < num_formats; i++) {
+ fmt = isc->user_formats[i];
+ if (fmt->fourcc == fourcc)
+ return fmt;
+ }
+
+ return NULL;
+}
+
static const struct vb2_ops isc_vb2_ops = {
.queue_setup = isc_queue_setup,
.wait_prepare = vb2_ops_wait_prepare,
@@ -1249,15 +1065,31 @@ static int isc_querycap(struct file *file, void *priv,
static int isc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- struct isc_device *isc = video_drvdata(file);
u32 index = f->index;
+ u32 i, supported_index;
- if (index >= isc->num_user_formats)
- return -EINVAL;
+ if (index < ARRAY_SIZE(controller_formats)) {
+ f->pixelformat = controller_formats[index].fourcc;
+ return 0;
+ }
- f->pixelformat = isc->user_formats[index]->fourcc;
+ index -= ARRAY_SIZE(controller_formats);
- return 0;
+ i = 0;
+ supported_index = 0;
+
+ for (i = 0; i < ARRAY_SIZE(formats_list); i++) {
+ if (!ISC_IS_FORMAT_RAW(formats_list[i].mbus_code) ||
+ !formats_list[i].sd_support)
+ continue;
+ if (supported_index == index) {
+ f->pixelformat = formats_list[i].fourcc;
+ return 0;
+ }
+ supported_index++;
+ }
+
+ return -EINVAL;
}
static int isc_g_fmt_vid_cap(struct file *file, void *priv,
@@ -1270,26 +1102,238 @@ static int isc_g_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static struct isc_format *find_format_by_fourcc(struct isc_device *isc,
- unsigned int fourcc)
+/*
+ * Checks the current configured format, if ISC can output it,
+ * considering which type of format the ISC receives from the sensor
+ */
+static int isc_try_validate_formats(struct isc_device *isc)
{
- unsigned int num_formats = isc->num_user_formats;
- struct isc_format *fmt;
- unsigned int i;
+ int ret;
+ bool bayer = false, yuv = false, rgb = false, grey = false;
+
+ /* all formats supported by the RLP module are OK */
+ switch (isc->try_config.fourcc) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SGBRG12:
+ case V4L2_PIX_FMT_SGRBG12:
+ case V4L2_PIX_FMT_SRGGB12:
+ ret = 0;
+ bayer = true;
+ break;
- for (i = 0; i < num_formats; i++) {
- fmt = isc->user_formats[i];
- if (fmt->fourcc == fourcc)
- return fmt;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YUV422P:
+ case V4L2_PIX_FMT_YUYV:
+ ret = 0;
+ yuv = true;
+ break;
+
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ case V4L2_PIX_FMT_ARGB444:
+ case V4L2_PIX_FMT_ARGB555:
+ ret = 0;
+ rgb = true;
+ break;
+ case V4L2_PIX_FMT_GREY:
+ ret = 0;
+ grey = true;
+ break;
+ default:
+ /* any other different formats are not supported */
+ ret = -EINVAL;
}
- return NULL;
+ /* we cannot output RAW/Grey if we do not receive RAW */
+ if ((bayer || grey) &&
+ !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
+ return -EINVAL;
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n",
+ rgb, yuv, grey, bayer);
+
+ return ret;
+}
+
+/*
+ * Configures the RLP and DMA modules, depending on the output format
+ * configured for the ISC.
+ * If direct_dump == true, just dump raw data 8 bits.
+ */
+static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
+{
+ if (direct_dump) {
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ return 0;
+ }
+
+ switch (isc->try_config.fourcc) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 8;
+ break;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ break;
+ case V4L2_PIX_FMT_SBGGR12:
+ case V4L2_PIX_FMT_SGBRG12:
+ case V4L2_PIX_FMT_SGRBG12:
+ case V4L2_PIX_FMT_SRGGB12:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ break;
+ case V4L2_PIX_FMT_ARGB444:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ break;
+ case V4L2_PIX_FMT_ARGB555:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ break;
+ case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 32;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR;
+ isc->try_config.bpp = 12;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR;
+ isc->try_config.bpp = 16;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ break;
+ case V4L2_PIX_FMT_GREY:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * Configuring pipeline modules, depending on which format the ISC outputs
+ * and considering which format it has as input from the sensor.
+ */
+static int isc_try_configure_pipeline(struct isc_device *isc)
+{
+ switch (isc->try_config.fourcc) {
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_ARGB555:
+ case V4L2_PIX_FMT_ARGB444:
+ case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ /* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ WB_ENABLE | GAM_ENABLES;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ /* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
+ SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ /* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
+ SUB422_ENABLE | CBC_ENABLE;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ /* if sensor format is RAW, we convert inside ISC */
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
+ SUB422_ENABLE | CBC_ENABLE;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ case V4L2_PIX_FMT_GREY:
+ if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) {
+ /* if sensor format is RAW, we convert inside ISC */
+ isc->try_config.bits_pipeline = CFA_ENABLE |
+ CSC_ENABLE | WB_ENABLE | GAM_ENABLES |
+ CBC_ENABLE;
+ } else {
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ break;
+ default:
+ isc->try_config.bits_pipeline = 0x0;
+ }
+ return 0;
}
static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
- struct isc_format **current_fmt, u32 *code)
+ u32 *code)
{
- struct isc_format *isc_fmt;
+ int i;
+ struct isc_format *sd_fmt = NULL, *direct_fmt = NULL;
struct v4l2_pix_format *pixfmt = &f->fmt.pix;
struct v4l2_subdev_pad_config pad_cfg;
struct v4l2_subdev_format format = {
@@ -1297,48 +1341,119 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
};
u32 mbus_code;
int ret;
+ bool rlp_dma_direct_dump = false;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- isc_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat);
- if (!isc_fmt) {
- v4l2_warn(&isc->v4l2_dev, "Format 0x%x not found\n",
- pixfmt->pixelformat);
- isc_fmt = isc->user_formats[isc->num_user_formats - 1];
- pixfmt->pixelformat = isc_fmt->fourcc;
+ /* Step 1: find a RAW format that is supported */
+ for (i = 0; i < isc->num_user_formats; i++) {
+ if (ISC_IS_FORMAT_RAW(isc->user_formats[i]->mbus_code)) {
+ sd_fmt = isc->user_formats[i];
+ break;
+ }
+ }
+ /* Step 2: We can continue with this RAW format, or we can look
+ * for better: maybe sensor supports directly what we need.
+ */
+ direct_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat);
+
+ /* Step 3: We have both. We decide given the module parameter which
+ * one to use.
+ */
+ if (direct_fmt && sd_fmt && sensor_preferred)
+ sd_fmt = direct_fmt;
+
+ /* Step 4: we do not have RAW but we have a direct format. Use it. */
+ if (direct_fmt && !sd_fmt)
+ sd_fmt = direct_fmt;
+
+ /* Step 5: if we are using a direct format, we need to package
+ * everything as 8 bit data and just dump it
+ */
+ if (sd_fmt == direct_fmt)
+ rlp_dma_direct_dump = true;
+
+ /* Step 6: We have no format. This can happen if the userspace
+ * requests some weird/invalid format.
+ * In this case, default to whatever we have
+ */
+ if (!sd_fmt && !direct_fmt) {
+ sd_fmt = isc->user_formats[isc->num_user_formats - 1];
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "Sensor not supporting %.4s, using %.4s\n",
+ (char *)&pixfmt->pixelformat, (char *)&sd_fmt->fourcc);
+ }
+
+ if (!sd_fmt) {
+ ret = -EINVAL;
+ goto isc_try_fmt_err;
}
+ /* Step 7: Print out what we decided for debugging */
+ v4l2_dbg(1, debug, &isc->v4l2_dev,
+ "Preferring to have sensor using format %.4s\n",
+ (char *)&sd_fmt->fourcc);
+
+ /* Step 8: at this moment we decided which format the subdev will use */
+ isc->try_config.sd_format = sd_fmt;
+
/* Limit to Atmel ISC hardware capabilities */
if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH)
pixfmt->width = ISC_MAX_SUPPORT_WIDTH;
if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT)
pixfmt->height = ISC_MAX_SUPPORT_HEIGHT;
- if (sensor_is_preferred(isc_fmt))
- mbus_code = isc_fmt->mbus_code;
- else
- mbus_code = isc->raw_fmt->mbus_code;
+ /*
+ * The mbus format is the one the subdev outputs.
+ * The pixels will be transferred in this format Sensor -> ISC
+ */
+ mbus_code = sd_fmt->mbus_code;
+
+ /*
+ * Validate formats. If the required format is not OK, default to raw.
+ */
+
+ isc->try_config.fourcc = pixfmt->pixelformat;
+
+ if (isc_try_validate_formats(isc)) {
+ pixfmt->pixelformat = isc->try_config.fourcc = sd_fmt->fourcc;
+ /* Re-try to validate the new format */
+ ret = isc_try_validate_formats(isc);
+ if (ret)
+ goto isc_try_fmt_err;
+ }
+
+ ret = isc_try_configure_rlp_dma(isc, rlp_dma_direct_dump);
+ if (ret)
+ goto isc_try_fmt_err;
+
+ ret = isc_try_configure_pipeline(isc);
+ if (ret)
+ goto isc_try_fmt_err;
v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code);
ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt,
&pad_cfg, &format);
if (ret < 0)
- return ret;
+ goto isc_try_fmt_err;
v4l2_fill_pix_format(pixfmt, &format.format);
pixfmt->field = V4L2_FIELD_NONE;
- pixfmt->bytesperline = (pixfmt->width * isc_fmt->bpp) >> 3;
+ pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp) >> 3;
pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
- if (current_fmt)
- *current_fmt = isc_fmt;
-
if (code)
*code = mbus_code;
return 0;
+
+isc_try_fmt_err:
+ v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n");
+ memset(&isc->try_config, 0, sizeof(isc->try_config));
+
+ return ret;
}
static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
@@ -1346,11 +1461,10 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
- struct isc_format *current_fmt;
- u32 mbus_code;
+ u32 mbus_code = 0;
int ret;
- ret = isc_try_fmt(isc, f, &current_fmt, &mbus_code);
+ ret = isc_try_fmt(isc, f, &mbus_code);
if (ret)
return ret;
@@ -1361,7 +1475,10 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f)
return ret;
isc->fmt = *f;
- isc->current_fmt = current_fmt;
+ /* make the try configuration active */
+ isc->config = isc->try_config;
+
+ v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n");
return 0;
}
@@ -1382,7 +1499,7 @@ static int isc_try_fmt_vid_cap(struct file *file, void *priv,
{
struct isc_device *isc = video_drvdata(file);
- return isc_try_fmt(isc, f, NULL, NULL);
+ return isc_try_fmt(isc, f, NULL);
}
static int isc_enum_input(struct file *file, void *priv,
@@ -1431,27 +1548,31 @@ static int isc_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
struct isc_device *isc = video_drvdata(file);
- const struct isc_format *isc_fmt;
struct v4l2_subdev_frame_size_enum fse = {
.index = fsize->index,
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
- int ret;
+ int ret = -EINVAL;
+ int i;
- isc_fmt = find_format_by_fourcc(isc, fsize->pixel_format);
- if (!isc_fmt)
- return -EINVAL;
+ for (i = 0; i < isc->num_user_formats; i++)
+ if (isc->user_formats[i]->fourcc == fsize->pixel_format)
+ ret = 0;
- if (sensor_is_preferred(isc_fmt))
- fse.code = isc_fmt->mbus_code;
- else
- fse.code = isc->raw_fmt->mbus_code;
+ for (i = 0; i < ARRAY_SIZE(controller_formats); i++)
+ if (controller_formats[i].fourcc == fsize->pixel_format)
+ ret = 0;
+
+ if (ret)
+ return ret;
ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
NULL, &fse);
if (ret)
return ret;
+ fse.code = isc->config.sd_format->mbus_code;
+
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
fsize->discrete.width = fse.max_width;
fsize->discrete.height = fse.max_height;
@@ -1463,29 +1584,32 @@ static int isc_enum_frameintervals(struct file *file, void *fh,
struct v4l2_frmivalenum *fival)
{
struct isc_device *isc = video_drvdata(file);
- const struct isc_format *isc_fmt;
struct v4l2_subdev_frame_interval_enum fie = {
.index = fival->index,
.width = fival->width,
.height = fival->height,
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
- int ret;
+ int ret = -EINVAL;
+ int i;
- isc_fmt = find_format_by_fourcc(isc, fival->pixel_format);
- if (!isc_fmt)
- return -EINVAL;
+ for (i = 0; i < isc->num_user_formats; i++)
+ if (isc->user_formats[i]->fourcc == fival->pixel_format)
+ ret = 0;
- if (sensor_is_preferred(isc_fmt))
- fie.code = isc_fmt->mbus_code;
- else
- fie.code = isc->raw_fmt->mbus_code;
+ for (i = 0; i < ARRAY_SIZE(controller_formats); i++)
+ if (controller_formats[i].fourcc == fival->pixel_format)
+ ret = 0;
+
+ if (ret)
+ return ret;
ret = v4l2_subdev_call(isc->current_subdev->sd, pad,
enum_frame_interval, NULL, &fie);
if (ret)
return ret;
+ fie.code = isc->config.sd_format->mbus_code;
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fival->discrete = fie.interval;
@@ -1668,7 +1792,6 @@ static void isc_awb_work(struct work_struct *w)
struct isc_device *isc =
container_of(w, struct isc_device, awb_work);
struct regmap *regmap = isc->regmap;
- struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc);
struct isc_ctrls *ctrls = &isc->ctrls;
u32 hist_id = ctrls->hist_id;
u32 baysel;
@@ -1686,7 +1809,7 @@ static void isc_awb_work(struct work_struct *w)
}
ctrls->hist_id = hist_id;
- baysel = config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
+ baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT;
pm_runtime_get_sync(isc->dev);
@@ -1754,7 +1877,6 @@ static int isc_ctrl_init(struct isc_device *isc)
return 0;
}
-
static int isc_async_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
struct v4l2_async_subdev *asd)
@@ -1812,35 +1934,20 @@ static int isc_formats_init(struct isc_device *isc)
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
+ num_fmts = 0;
while (!v4l2_subdev_call(subdev, pad, enum_mbus_code,
NULL, &mbus_code)) {
mbus_code.index++;
fmt = find_format_by_code(mbus_code.code, &i);
- if ((!fmt) || (!(fmt->flags & FMT_FLAG_FROM_SENSOR)))
+ if (!fmt) {
+ v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n",
+ mbus_code.code);
continue;
+ }
fmt->sd_support = true;
-
- if (fmt->flags & FMT_FLAG_RAW_FORMAT)
- isc->raw_fmt = fmt;
- }
-
- fmt = &formats_list[0];
- for (i = 0; i < list_size; i++) {
- if (fmt->flags & FMT_FLAG_FROM_CONTROLLER)
- fmt->isc_support = true;
-
- fmt++;
- }
-
- fmt = &formats_list[0];
- num_fmts = 0;
- for (i = 0; i < list_size; i++) {
- if (fmt->isc_support || fmt->sd_support)
- num_fmts++;
-
- fmt++;
+ num_fmts++;
}
if (!num_fmts)
@@ -1855,9 +1962,8 @@ static int isc_formats_init(struct isc_device *isc)
fmt = &formats_list[0];
for (i = 0, j = 0; i < list_size; i++) {
- if (fmt->isc_support || fmt->sd_support)
+ if (fmt->sd_support)
isc->user_formats[j++] = fmt;
-
fmt++;
}
@@ -1877,13 +1983,11 @@ static int isc_set_default_fmt(struct isc_device *isc)
};
int ret;
- ret = isc_try_fmt(isc, &f, NULL, NULL);
+ ret = isc_try_fmt(isc, &f, NULL);
if (ret)
return ret;
- isc->current_fmt = isc->user_formats[0];
isc->fmt = f;
-
return 0;
}
@@ -1895,6 +1999,8 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
struct vb2_queue *q = &isc->vb2_vidq;
int ret;
+ INIT_WORK(&isc->awb_work, isc_awb_work);
+
ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev);
if (ret < 0) {
v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n");
@@ -1948,8 +2054,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
return ret;
}
- INIT_WORK(&isc->awb_work, isc_awb_work);
-
/* Register video device */
strscpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name));
vdev->release = video_device_release_empty;
@@ -2065,8 +2169,11 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc)
break;
}
- subdev_entity->asd = devm_kzalloc(dev,
- sizeof(*subdev_entity->asd), GFP_KERNEL);
+ /* asd will be freed by the subsystem once it's added to the
+ * notifier list
+ */
+ subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd),
+ GFP_KERNEL);
if (!subdev_entity->asd) {
of_node_put(rem);
ret = -ENOMEM;
@@ -2084,6 +2191,10 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc)
if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
+ if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
+ subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
+ ISC_PFE_CFG0_CCIR656;
+
subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
subdev_entity->asd->match.fwnode =
of_fwnode_handle(rem);
@@ -2210,6 +2321,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
subdev_entity->asd);
if (ret) {
fwnode_handle_put(subdev_entity->asd->match.fwnode);
+ kfree(subdev_entity->asd);
goto cleanup_subdev;
}
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index b4f396c2e72c..eaa86737fa04 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -2010,6 +2010,9 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
/* Clear decode success flag */
coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS);
+ /* Clear error return value */
+ coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB);
+
trace_coda_dec_pic_run(ctx, meta);
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index fa0b22fb7991..1d96cca61547 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -764,6 +764,7 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv,
{
struct coda_ctx *ctx = fh_to_ctx(priv);
struct coda_q_data *q_data_src;
+ const struct coda_codec *codec;
struct v4l2_rect r;
int ret;
@@ -784,6 +785,15 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv,
if (ctx->inst_type != CODA_INST_ENCODER)
return 0;
+ /* Setting the coded format determines the selected codec */
+ codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+ f->fmt.pix.pixelformat);
+ if (!codec) {
+ v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n");
+ return -EINVAL;
+ }
+ ctx->codec = codec;
+
ctx->colorspace = f->fmt.pix.colorspace;
ctx->xfer_func = f->fmt.pix.xfer_func;
ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
@@ -796,6 +806,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
struct coda_ctx *ctx = fh_to_ctx(priv);
+ const struct coda_codec *codec;
struct v4l2_format f_cap;
struct vb2_queue *dst_vq;
int ret;
@@ -808,14 +819,23 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv,
if (ret)
return ret;
- if (ctx->inst_type != CODA_INST_DECODER)
- return 0;
-
ctx->colorspace = f->fmt.pix.colorspace;
ctx->xfer_func = f->fmt.pix.xfer_func;
ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc;
ctx->quantization = f->fmt.pix.quantization;
+ if (ctx->inst_type != CODA_INST_DECODER)
+ return 0;
+
+ /* Setting the coded format determines the selected codec */
+ codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
+ V4L2_PIX_FMT_YUV420);
+ if (!codec) {
+ v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n");
+ return -EINVAL;
+ }
+ ctx->codec = codec;
+
dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
if (!dst_vq)
return -EINVAL;
@@ -980,6 +1000,11 @@ static int coda_s_selection(struct file *file, void *fh,
static int coda_try_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *ec)
{
+ struct coda_ctx *ctx = fh_to_ctx(fh);
+
+ if (ctx->inst_type != CODA_INST_ENCODER)
+ return -ENOTTY;
+
if (ec->cmd != V4L2_ENC_CMD_STOP)
return -EINVAL;
@@ -1000,10 +1025,6 @@ static int coda_encoder_cmd(struct file *file, void *fh,
if (ret < 0)
return ret;
- /* Ignore encoder stop command silently in decoder context */
- if (ctx->inst_type != CODA_INST_ENCODER)
- return 0;
-
/* Set the stream-end flag on this context */
ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
@@ -1021,6 +1042,11 @@ static int coda_encoder_cmd(struct file *file, void *fh,
static int coda_try_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dc)
{
+ struct coda_ctx *ctx = fh_to_ctx(fh);
+
+ if (ctx->inst_type != CODA_INST_DECODER)
+ return -ENOTTY;
+
if (dc->cmd != V4L2_DEC_CMD_STOP)
return -EINVAL;
@@ -1043,10 +1069,6 @@ static int coda_decoder_cmd(struct file *file, void *fh,
if (ret < 0)
return ret;
- /* Ignore decoder stop command silently in encoder context */
- if (ctx->inst_type != CODA_INST_DECODER)
- return 0;
-
/* Set the stream-end flag on this context */
coda_bit_stream_end_flag(ctx);
ctx->hold = false;
@@ -1055,6 +1077,42 @@ static int coda_decoder_cmd(struct file *file, void *fh,
return 0;
}
+static int coda_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct coda_ctx *ctx = fh_to_ctx(fh);
+ struct coda_q_data *q_data_dst;
+ const struct coda_codec *codec;
+
+ if (ctx->inst_type != CODA_INST_ENCODER)
+ return -ENOTTY;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ if (coda_format_normalize_yuv(fsize->pixel_format) ==
+ V4L2_PIX_FMT_YUV420) {
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ codec = coda_find_codec(ctx->dev, fsize->pixel_format,
+ q_data_dst->fourcc);
+ } else {
+ codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
+ fsize->pixel_format);
+ }
+ if (!codec)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = MIN_W;
+ fsize->stepwise.max_width = codec->max_w;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.min_height = MIN_H;
+ fsize->stepwise.max_height = codec->max_h;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
static int coda_enum_frameintervals(struct file *file, void *fh,
struct v4l2_frmivalenum *f)
{
@@ -1233,6 +1291,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
.vidioc_g_parm = coda_g_parm,
.vidioc_s_parm = coda_s_parm,
+ .vidioc_enum_framesizes = coda_enum_framesizes,
.vidioc_enum_frameintervals = coda_enum_frameintervals,
.vidioc_subscribe_event = coda_subscribe_event,
@@ -1442,6 +1501,9 @@ static int coda_queue_setup(struct vb2_queue *vq,
q_data = get_q_data(ctx, vq->type);
size = q_data->sizeimage;
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
+
*nplanes = 1;
sizes[0] = size;
@@ -1453,10 +1515,20 @@ static int coda_queue_setup(struct vb2_queue *vq,
static int coda_buf_prepare(struct vb2_buffer *vb)
{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct coda_q_data *q_data;
q_data = get_q_data(ctx, vb->vb2_queue->type);
+ if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ if (vbuf->field == V4L2_FIELD_ANY)
+ vbuf->field = V4L2_FIELD_NONE;
+ if (vbuf->field != V4L2_FIELD_NONE) {
+ v4l2_warn(&ctx->dev->v4l2_dev,
+ "%s field isn't supported\n", __func__);
+ return -EINVAL;
+ }
+ }
if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
v4l2_warn(&ctx->dev->v4l2_dev,
@@ -1680,14 +1752,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
ctx->gopcounter = ctx->params.gop_size - 1;
- ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
- q_data_dst->fourcc);
- if (!ctx->codec) {
- v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
- ret = -EINVAL;
- goto err;
- }
-
if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG)
ctx->params.gop_size = 1;
ctx->gopcounter = ctx->params.gop_size - 1;
@@ -2015,7 +2079,6 @@ static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx)
static void coda_decode_ctrls(struct coda_ctx *ctx)
{
- u64 mask;
u8 max;
ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
@@ -2029,27 +2092,14 @@ static void coda_decode_ctrls(struct coda_ctx *ctx)
ctx->h264_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
if (ctx->dev->devtype->product == CODA_HX4 ||
- ctx->dev->devtype->product == CODA_7541) {
+ ctx->dev->devtype->product == CODA_7541)
max = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
- mask = ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0));
- } else if (ctx->dev->devtype->product == CODA_960) {
+ else if (ctx->dev->devtype->product == CODA_960)
max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
- mask = ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1));
- } else {
+ else
return;
- }
ctx->h264_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
- &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, mask,
- max);
+ &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max);
if (ctx->h264_level_ctrl)
ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
}
@@ -2063,11 +2113,17 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
if (ctx->inst_type == CODA_INST_ENCODER) {
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+ 1, 1, 1, 1);
if (ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG)
coda_jpeg_encode_ctrls(ctx);
else
coda_encode_ctrls(ctx);
} else {
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+ 1, 1, 1, 1);
if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_H264)
coda_decode_ctrls(ctx);
}
diff --git a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c
index 7bc4d8a9af28..068df9888dbf 100644
--- a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c
+++ b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c
@@ -236,6 +236,7 @@ static int cros_ec_cec_get_notifier(struct device *dev,
return -EPROBE_DEFER;
*notify = cec_notifier_get_conn(d, m->conn);
+ put_device(d);
return 0;
}
}
diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c
index 47cecd10eb9f..2dee9af6d413 100644
--- a/drivers/media/platform/davinci/isif.c
+++ b/drivers/media/platform/davinci/isif.c
@@ -884,9 +884,7 @@ static int isif_set_hw_if_params(struct vpfe_hw_if_param *params)
static int isif_config_ycbcr(void)
{
struct isif_ycbcr_config *params = &isif_cfg.ycbcr;
- struct vpss_pg_frame_size frame_size;
u32 modeset = 0, ccdcfg = 0;
- struct vpss_sync_pol sync;
dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr...");
@@ -974,13 +972,6 @@ static int isif_config_ycbcr(void)
/* two fields are interleaved in memory */
regw(0x00000249, SDOFST);
- /* Setup test pattern if enabled */
- if (isif_cfg.bayer.config_params.test_pat_gen) {
- sync.ccdpg_hdpol = params->hd_pol;
- sync.ccdpg_vdpol = params->vd_pol;
- dm365_vpss_set_sync_pol(sync);
- dm365_vpss_set_pg_frame_size(frame_size);
- }
return 0;
}
diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c
index 8339163a5231..4e24f5d781f4 100644
--- a/drivers/media/platform/davinci/vpbe.c
+++ b/drivers/media/platform/davinci/vpbe.c
@@ -104,7 +104,7 @@ static int vpbe_enum_outputs(struct vpbe_device *vpbe_dev,
struct v4l2_output *output)
{
struct vpbe_config *cfg = vpbe_dev->cfg;
- int temp_index = output->index;
+ unsigned int temp_index = output->index;
if (temp_index >= cfg->num_outputs)
return -EINVAL;
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index 26dadbba930f..1e3a13830544 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -1759,7 +1759,7 @@ static int vpfe_probe(struct platform_device *pdev)
mutex_lock(&ccdc_lock);
- strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32);
+ strscpy(ccdc_cfg->name, vpfe_cfg->ccdc, sizeof(ccdc_cfg->name));
/* Get VINT0 irq resource */
res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res1) {
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 6216b7ac6875..b5aacb0fb96b 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -1254,7 +1254,8 @@ static int vpif_s_dv_timings(struct file *file, void *priv,
} else {
std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
}
- strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME);
+ strscpy(std_info->name, "Custom timings BT656/1120",
+ sizeof(std_info->name));
std_info->width = bt->width;
std_info->height = bt->height;
std_info->frm_fmt = bt->interlaced ? 0 : 1;
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index f4b4f2a1dfc0..a69897c68a50 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -987,8 +987,8 @@ static int vpif_s_dv_timings(struct file *file, void *priv,
} else {
std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
}
- strncpy(std_info->name, "Custom timings BT656/1120",
- VPIF_MAX_NAME);
+ strscpy(std_info->name, "Custom timings BT656/1120",
+ sizeof(std_info->name));
std_info->width = bt->width;
std_info->height = bt->height;
std_info->frm_fmt = bt->interlaced ? 0 : 1;
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 3e9fcf4f8a13..de4af0357a3c 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -742,7 +742,7 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv,
f->index);
if (!fmt)
return -EINVAL;
- strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
if (fmt->fourcc == MEDIA_BUS_FMT_JPEG_1X8)
f->flags |= V4L2_FMT_FLAG_COMPRESSED;
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index 61c8177409cf..1bea1ce4091e 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -252,7 +252,7 @@ static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv,
if (!fmt)
return -EINVAL;
- strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c
index 0bcfc5aa8f3d..8e7ef23b9a7e 100644
--- a/drivers/media/platform/imx-pxp.c
+++ b/drivers/media/platform/imx-pxp.c
@@ -1025,8 +1025,8 @@ static irqreturn_t pxp_irq_handler(int irq, void *dev_id)
static int pxp_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
- strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
+ strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
+ strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", MEM2MEM_NAME);
return 0;
diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig
index cf12e077203a..cd88e2eed749 100644
--- a/drivers/media/platform/marvell-ccic/Kconfig
+++ b/drivers/media/platform/marvell-ccic/Kconfig
@@ -5,7 +5,7 @@ config VIDEO_CAFE_CCIC
select VIDEOBUF2_VMALLOC
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_DMA_SG
- ---help---
+ help
This is a video4linux2 driver for the Marvell 88ALP01 integrated
CMOS camera controller. This is the controller found on first-
generation OLPC systems.
@@ -19,7 +19,7 @@ config VIDEO_MMP_CAMERA
select VIDEOBUF2_VMALLOC
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_DMA_SG
- ---help---
+ help
This is a Video4Linux2 driver for the integrated camera
controller found on Marvell Armada 610 application
processors (and likely beyond). This is the controller found
diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile
index 597beb8f34d1..f611c23c3718 100644
--- a/drivers/media/platform/meson/Makefile
+++ b/drivers/media/platform/meson/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o
+obj-$(CONFIG_VIDEO_MESON_G12A_AO_CEC) += ao-cec-g12a.o
diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c
new file mode 100644
index 000000000000..3620a1e310f5
--- /dev/null
+++ b/drivers/media/platform/meson/ao-cec-g12a.c
@@ -0,0 +1,779 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for Amlogic Meson AO CEC G12A Controller
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved
+ * Copyright (C) 2019 BayLibre, SAS
+ * Author: Neil Armstrong <narmstrong@baylibre.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <media/cec.h>
+#include <media/cec-notifier.h>
+#include <linux/clk-provider.h>
+
+/* CEC Registers */
+
+#define CECB_CLK_CNTL_REG0 0x00
+
+#define CECB_CLK_CNTL_N1 GENMASK(11, 0)
+#define CECB_CLK_CNTL_N2 GENMASK(23, 12)
+#define CECB_CLK_CNTL_DUAL_EN BIT(28)
+#define CECB_CLK_CNTL_OUTPUT_EN BIT(30)
+#define CECB_CLK_CNTL_INPUT_EN BIT(31)
+
+#define CECB_CLK_CNTL_REG1 0x04
+
+#define CECB_CLK_CNTL_M1 GENMASK(11, 0)
+#define CECB_CLK_CNTL_M2 GENMASK(23, 12)
+#define CECB_CLK_CNTL_BYPASS_EN BIT(24)
+
+/*
+ * [14:12] Filter_del. For glitch-filtering CEC line, ignore signal
+ * change pulse width < filter_del * T(filter_tick) * 3.
+ * [9:8] Filter_tick_sel: Select which periodical pulse for
+ * glitch-filtering CEC line signal.
+ * - 0=Use T(xtal)*3 = 125ns;
+ * - 1=Use once-per-1us pulse;
+ * - 2=Use once-per-10us pulse;
+ * - 3=Use once-per-100us pulse.
+ * [3] Sysclk_en. 0=Disable system clock; 1=Enable system clock.
+ * [2:1] cntl_clk
+ * - 0 = Disable clk (Power-off mode)
+ * - 1 = Enable gated clock (Normal mode)
+ * - 2 = Enable free-run clk (Debug mode)
+ * [0] SW_RESET 1=Apply reset; 0=No reset.
+ */
+#define CECB_GEN_CNTL_REG 0x08
+
+#define CECB_GEN_CNTL_RESET BIT(0)
+#define CECB_GEN_CNTL_CLK_DISABLE 0
+#define CECB_GEN_CNTL_CLK_ENABLE 1
+#define CECB_GEN_CNTL_CLK_ENABLE_DBG 2
+#define CECB_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1)
+#define CECB_GEN_CNTL_SYS_CLK_EN BIT(3)
+#define CECB_GEN_CNTL_FILTER_TICK_125NS 0
+#define CECB_GEN_CNTL_FILTER_TICK_1US 1
+#define CECB_GEN_CNTL_FILTER_TICK_10US 2
+#define CECB_GEN_CNTL_FILTER_TICK_100US 3
+#define CECB_GEN_CNTL_FILTER_TICK_SEL GENMASK(9, 8)
+#define CECB_GEN_CNTL_FILTER_DEL GENMASK(14, 12)
+
+/*
+ * [7:0] cec_reg_addr
+ * [15:8] cec_reg_wrdata
+ * [16] cec_reg_wr
+ * - 0 = Read
+ * - 1 = Write
+ * [31:24] cec_reg_rddata
+ */
+#define CECB_RW_REG 0x0c
+
+#define CECB_RW_ADDR GENMASK(7, 0)
+#define CECB_RW_WR_DATA GENMASK(15, 8)
+#define CECB_RW_WRITE_EN BIT(16)
+#define CECB_RW_BUS_BUSY BIT(23)
+#define CECB_RW_RD_DATA GENMASK(31, 24)
+
+/*
+ * [0] DONE Interrupt
+ * [1] End Of Message Interrupt
+ * [2] Not Acknowlegde Interrupt
+ * [3] Arbitration Loss Interrupt
+ * [4] Initiator Error Interrupt
+ * [5] Follower Error Interrupt
+ * [6] Wake-Up Interrupt
+ */
+#define CECB_INTR_MASKN_REG 0x10
+#define CECB_INTR_CLR_REG 0x14
+#define CECB_INTR_STAT_REG 0x18
+
+#define CECB_INTR_DONE BIT(0)
+#define CECB_INTR_EOM BIT(1)
+#define CECB_INTR_NACK BIT(2)
+#define CECB_INTR_ARB_LOSS BIT(3)
+#define CECB_INTR_INITIATOR_ERR BIT(4)
+#define CECB_INTR_FOLLOWER_ERR BIT(5)
+#define CECB_INTR_WAKE_UP BIT(6)
+
+/* CEC Commands */
+
+#define CECB_CTRL 0x00
+
+#define CECB_CTRL_SEND BIT(0)
+#define CECB_CTRL_TYPE GENMASK(2, 1)
+#define CECB_CTRL_TYPE_RETRY 0
+#define CECB_CTRL_TYPE_NEW 1
+#define CECB_CTRL_TYPE_NEXT 2
+
+#define CECB_CTRL2 0x01
+#define CECB_INTR_MASK 0x02
+#define CECB_LADD_LOW 0x05
+#define CECB_LADD_HIGH 0x06
+#define CECB_TX_CNT 0x07
+#define CECB_RX_CNT 0x08
+#define CECB_STAT0 0x09
+#define CECB_TX_DATA00 0x10
+#define CECB_TX_DATA01 0x11
+#define CECB_TX_DATA02 0x12
+#define CECB_TX_DATA03 0x13
+#define CECB_TX_DATA04 0x14
+#define CECB_TX_DATA05 0x15
+#define CECB_TX_DATA06 0x16
+#define CECB_TX_DATA07 0x17
+#define CECB_TX_DATA08 0x18
+#define CECB_TX_DATA09 0x19
+#define CECB_TX_DATA10 0x1A
+#define CECB_TX_DATA11 0x1B
+#define CECB_TX_DATA12 0x1C
+#define CECB_TX_DATA13 0x1D
+#define CECB_TX_DATA14 0x1E
+#define CECB_TX_DATA15 0x1F
+#define CECB_RX_DATA00 0x20
+#define CECB_RX_DATA01 0x21
+#define CECB_RX_DATA02 0x22
+#define CECB_RX_DATA03 0x23
+#define CECB_RX_DATA04 0x24
+#define CECB_RX_DATA05 0x25
+#define CECB_RX_DATA06 0x26
+#define CECB_RX_DATA07 0x27
+#define CECB_RX_DATA08 0x28
+#define CECB_RX_DATA09 0x29
+#define CECB_RX_DATA10 0x2A
+#define CECB_RX_DATA11 0x2B
+#define CECB_RX_DATA12 0x2C
+#define CECB_RX_DATA13 0x2D
+#define CECB_RX_DATA14 0x2E
+#define CECB_RX_DATA15 0x2F
+#define CECB_LOCK_BUF 0x30
+
+#define CECB_LOCK_BUF_EN BIT(0)
+
+#define CECB_WAKEUPCTRL 0x31
+
+struct meson_ao_cec_g12a_device {
+ struct platform_device *pdev;
+ struct regmap *regmap;
+ struct regmap *regmap_cec;
+ spinlock_t cec_reg_lock;
+ struct cec_notifier *notify;
+ struct cec_adapter *adap;
+ struct cec_msg rx_msg;
+ struct clk *oscin;
+ struct clk *core;
+};
+
+static const struct regmap_config meson_ao_cec_g12a_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = CECB_INTR_STAT_REG,
+};
+
+/*
+ * The AO-CECB embeds a dual/divider to generate a more precise
+ * 32,768KHz clock for CEC core clock.
+ * ______ ______
+ * | | | |
+ * ______ | Div1 |-| Cnt1 | ______
+ * | | /|______| |______|\ | |
+ * Xtal-->| Gate |---| ______ ______ X-X--| Gate |-->
+ * |______| | \| | | |/ | |______|
+ * | | Div2 |-| Cnt2 | |
+ * | |______| |______| |
+ * |_______________________|
+ *
+ * The dividing can be switched to single or dual, with a counter
+ * for each divider to set when the switching is done.
+ * The entire dividing mechanism can be also bypassed.
+ */
+
+struct meson_ao_cec_g12a_dualdiv_clk {
+ struct clk_hw hw;
+ struct regmap *regmap;
+};
+
+#define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw) \
+ container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw) \
+
+static unsigned long
+meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
+ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
+ unsigned long n1;
+ u32 reg0, reg1;
+
+ regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &reg0);
+ regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &reg1);
+
+ if (reg1 & CECB_CLK_CNTL_BYPASS_EN)
+ return parent_rate;
+
+ if (reg0 & CECB_CLK_CNTL_DUAL_EN) {
+ unsigned long n2, m1, m2, f1, f2, p1, p2;
+
+ n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
+ n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1;
+
+ m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
+ m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1;
+
+ f1 = DIV_ROUND_CLOSEST(parent_rate, n1);
+ f2 = DIV_ROUND_CLOSEST(parent_rate, n2);
+
+ p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2));
+ p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2));
+
+ return DIV_ROUND_UP(100000000, p1 + p2);
+ }
+
+ n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1;
+
+ return DIV_ROUND_CLOSEST(parent_rate, n1);
+}
+
+static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw)
+{
+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
+ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
+
+
+ /* Disable Input & Output */
+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
+ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
+ 0);
+
+ /* Set N1 & N2 */
+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
+ CECB_CLK_CNTL_N1,
+ FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1));
+
+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
+ CECB_CLK_CNTL_N2,
+ FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1));
+
+ /* Set M1 & M2 */
+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
+ CECB_CLK_CNTL_M1,
+ FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1));
+
+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
+ CECB_CLK_CNTL_M2,
+ FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1));
+
+ /* Enable Dual divisor */
+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
+ CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN);
+
+ /* Disable divisor bypass */
+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1,
+ CECB_CLK_CNTL_BYPASS_EN, 0);
+
+ /* Enable Input & Output */
+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
+ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
+ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN);
+
+ return 0;
+}
+
+static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw)
+{
+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
+ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
+
+ regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0,
+ CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN,
+ 0);
+}
+
+static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw)
+{
+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk =
+ hw_to_meson_ao_cec_g12a_dualdiv_clk(hw);
+ int val;
+
+ regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val);
+
+ return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN));
+}
+
+static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops = {
+ .recalc_rate = meson_ao_cec_g12a_dualdiv_clk_recalc_rate,
+ .is_enabled = meson_ao_cec_g12a_dualdiv_clk_is_enabled,
+ .enable = meson_ao_cec_g12a_dualdiv_clk_enable,
+ .disable = meson_ao_cec_g12a_dualdiv_clk_disable,
+};
+
+static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec)
+{
+ struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk;
+ struct device *dev = &ao_cec->pdev->dev;
+ struct clk_init_data init;
+ const char *parent_name;
+ struct clk *clk;
+ char *name;
+
+ dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL);
+ if (!dualdiv_clk)
+ return -ENOMEM;
+
+ name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev));
+ if (!name)
+ return -ENOMEM;
+
+ parent_name = __clk_get_name(ao_cec->oscin);
+
+ init.name = name;
+ init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+ dualdiv_clk->regmap = ao_cec->regmap;
+ dualdiv_clk->hw.init = &init;
+
+ clk = devm_clk_register(dev, &dualdiv_clk->hw);
+ kfree(name);
+ if (IS_ERR(clk)) {
+ dev_err(dev, "failed to register clock\n");
+ return PTR_ERR(clk);
+ }
+
+ ao_cec->core = clk;
+
+ return 0;
+}
+
+static int meson_ao_cec_g12a_read(void *context, unsigned int addr,
+ unsigned int *data)
+{
+ struct meson_ao_cec_g12a_device *ao_cec = context;
+ u32 reg = FIELD_PREP(CECB_RW_ADDR, addr);
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);
+
+ ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
+ if (ret)
+ goto read_out;
+
+ ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg,
+ !(reg & CECB_RW_BUS_BUSY),
+ 5, 1000);
+ if (ret)
+ goto read_out;
+
+ ret = regmap_read(ao_cec->regmap, CECB_RW_REG, &reg);
+
+ *data = FIELD_GET(CECB_RW_RD_DATA, reg);
+
+read_out:
+ spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);
+
+ return ret;
+}
+
+static int meson_ao_cec_g12a_write(void *context, unsigned int addr,
+ unsigned int data)
+{
+ struct meson_ao_cec_g12a_device *ao_cec = context;
+ unsigned long flags;
+ u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) |
+ FIELD_PREP(CECB_RW_WR_DATA, data) |
+ CECB_RW_WRITE_EN;
+ int ret = 0;
+
+ spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);
+
+ ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg);
+
+ spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);
+
+ return ret;
+}
+
+static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_read = meson_ao_cec_g12a_read,
+ .reg_write = meson_ao_cec_g12a_write,
+ .max_register = 0xffff,
+ .fast_io = true,
+};
+
+static inline void
+meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec,
+ bool enable)
+{
+ u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK |
+ CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR |
+ CECB_INTR_FOLLOWER_ERR;
+
+ regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG,
+ enable ? cfg : 0);
+}
+
+static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec)
+{
+ int i, ret = 0;
+ u32 val;
+
+ ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val);
+
+ ao_cec->rx_msg.len = val;
+ if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE)
+ ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE;
+
+ for (i = 0; i < ao_cec->rx_msg.len; i++) {
+ ret |= regmap_read(ao_cec->regmap_cec,
+ CECB_RX_DATA00 + i, &val);
+
+ ao_cec->rx_msg.msg[i] = val & 0xff;
+ }
+
+ ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0);
+ if (ret)
+ return;
+
+ cec_received_msg(ao_cec->adap, &ao_cec->rx_msg);
+}
+
+static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data)
+{
+ struct meson_ao_cec_g12a_device *ao_cec = data;
+ u32 stat;
+
+ regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
+ if (stat)
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_NONE;
+}
+
+static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data)
+{
+ struct meson_ao_cec_g12a_device *ao_cec = data;
+ u32 stat;
+
+ regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat);
+ regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat);
+
+ if (stat & CECB_INTR_DONE)
+ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK);
+
+ if (stat & CECB_INTR_EOM)
+ meson_ao_cec_g12a_irq_rx(ao_cec);
+
+ if (stat & CECB_INTR_NACK)
+ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK);
+
+ if (stat & CECB_INTR_ARB_LOSS) {
+ regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0);
+ regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL,
+ CECB_CTRL_SEND | CECB_CTRL_TYPE, 0);
+ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST);
+ }
+
+ /* Initiator reports an error on the CEC bus */
+ if (stat & CECB_INTR_INITIATOR_ERR)
+ cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR);
+
+ /* Follower reports a receive error, just reset RX buffer */
+ if (stat & CECB_INTR_FOLLOWER_ERR)
+ regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int
+meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr)
+{
+ struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
+ int ret = 0;
+
+ if (logical_addr == CEC_LOG_ADDR_INVALID) {
+ /* Assume this will allways succeed */
+ regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0);
+ regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0);
+
+ return 0;
+ } else if (logical_addr < 8) {
+ ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW,
+ BIT(logical_addr),
+ BIT(logical_addr));
+ } else {
+ ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH,
+ BIT(logical_addr - 8),
+ BIT(logical_addr - 8));
+ }
+
+ /* Always set Broadcast/Unregistered 15 address */
+ ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH,
+ BIT(CEC_LOG_ADDR_UNREGISTERED - 8),
+ BIT(CEC_LOG_ADDR_UNREGISTERED - 8));
+
+ return ret ? -EIO : 0;
+}
+
+static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts,
+ u32 signal_free_time, struct cec_msg *msg)
+{
+ struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
+ unsigned int type;
+ int ret = 0;
+ u32 val;
+ int i;
+
+ /* Check if RX is in progress */
+ ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val);
+ if (ret)
+ return ret;
+ if (val & CECB_LOCK_BUF_EN)
+ return -EBUSY;
+
+ /* Check if TX Busy */
+ ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val);
+ if (ret)
+ return ret;
+ if (val & CECB_CTRL_SEND)
+ return -EBUSY;
+
+ switch (signal_free_time) {
+ case CEC_SIGNAL_FREE_TIME_RETRY:
+ type = CECB_CTRL_TYPE_RETRY;
+ break;
+ case CEC_SIGNAL_FREE_TIME_NEXT_XFER:
+ type = CECB_CTRL_TYPE_NEXT;
+ break;
+ case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR:
+ default:
+ type = CECB_CTRL_TYPE_NEW;
+ break;
+ }
+
+ for (i = 0; i < msg->len; i++)
+ ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i,
+ msg->msg[i]);
+
+ ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len);
+ if (ret)
+ return -EIO;
+
+ ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL,
+ CECB_CTRL_SEND |
+ CECB_CTRL_TYPE,
+ CECB_CTRL_SEND |
+ FIELD_PREP(CECB_CTRL_TYPE, type));
+
+ return ret;
+}
+
+static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable)
+{
+ struct meson_ao_cec_g12a_device *ao_cec = adap->priv;
+
+ meson_ao_cec_g12a_irq_setup(ao_cec, false);
+
+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
+ CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET);
+
+ if (!enable)
+ return 0;
+
+ /* Setup Filter */
+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
+ CECB_GEN_CNTL_FILTER_TICK_SEL |
+ CECB_GEN_CNTL_FILTER_DEL,
+ FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL,
+ CECB_GEN_CNTL_FILTER_TICK_1US) |
+ FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7));
+
+ /* Enable System Clock */
+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
+ CECB_GEN_CNTL_SYS_CLK_EN,
+ CECB_GEN_CNTL_SYS_CLK_EN);
+
+ /* Enable gated clock (Normal mode). */
+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
+ CECB_GEN_CNTL_CLK_CTRL_MASK,
+ FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK,
+ CECB_GEN_CNTL_CLK_ENABLE));
+
+ /* Release Reset */
+ regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
+ CECB_GEN_CNTL_RESET, 0);
+
+ meson_ao_cec_g12a_irq_setup(ao_cec, true);
+
+ return 0;
+}
+
+static const struct cec_adap_ops meson_ao_cec_g12a_ops = {
+ .adap_enable = meson_ao_cec_g12a_adap_enable,
+ .adap_log_addr = meson_ao_cec_g12a_set_log_addr,
+ .adap_transmit = meson_ao_cec_g12a_transmit,
+};
+
+static int meson_ao_cec_g12a_probe(struct platform_device *pdev)
+{
+ struct meson_ao_cec_g12a_device *ao_cec;
+ struct device *hdmi_dev;
+ struct resource *res;
+ void __iomem *base;
+ int ret, irq;
+
+ hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev);
+ if (IS_ERR(hdmi_dev))
+ return PTR_ERR(hdmi_dev);
+
+ ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL);
+ if (!ao_cec)
+ return -ENOMEM;
+
+ spin_lock_init(&ao_cec->cec_reg_lock);
+ ao_cec->pdev = pdev;
+
+ ao_cec->notify = cec_notifier_get(hdmi_dev);
+ if (!ao_cec->notify)
+ return -ENOMEM;
+
+ ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec,
+ "meson_g12a_ao_cec",
+ CEC_CAP_DEFAULTS,
+ CEC_MAX_LOG_ADDRS);
+ if (IS_ERR(ao_cec->adap)) {
+ ret = PTR_ERR(ao_cec->adap);
+ goto out_probe_notify;
+ }
+
+ ao_cec->adap->owner = THIS_MODULE;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
+ goto out_probe_adapter;
+ }
+
+ ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &meson_ao_cec_g12a_regmap_conf);
+ if (IS_ERR(ao_cec->regmap)) {
+ ret = PTR_ERR(ao_cec->regmap);
+ goto out_probe_adapter;
+ }
+
+ ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec,
+ &meson_ao_cec_g12a_cec_regmap_conf);
+ if (IS_ERR(ao_cec->regmap_cec)) {
+ ret = PTR_ERR(ao_cec->regmap_cec);
+ goto out_probe_adapter;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_threaded_irq(&pdev->dev, irq,
+ meson_ao_cec_g12a_irq,
+ meson_ao_cec_g12a_irq_thread,
+ 0, NULL, ao_cec);
+ if (ret) {
+ dev_err(&pdev->dev, "irq request failed\n");
+ goto out_probe_adapter;
+ }
+
+ ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin");
+ if (IS_ERR(ao_cec->oscin)) {
+ dev_err(&pdev->dev, "oscin clock request failed\n");
+ ret = PTR_ERR(ao_cec->oscin);
+ goto out_probe_adapter;
+ }
+
+ ret = meson_ao_cec_g12a_setup_clk(ao_cec);
+ if (ret)
+ goto out_probe_adapter;
+
+ ret = clk_prepare_enable(ao_cec->core);
+ if (ret) {
+ dev_err(&pdev->dev, "core clock enable failed\n");
+ goto out_probe_adapter;
+ }
+
+ device_reset_optional(&pdev->dev);
+
+ platform_set_drvdata(pdev, ao_cec);
+
+ ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
+ if (ret < 0) {
+ cec_notifier_put(ao_cec->notify);
+ goto out_probe_core_clk;
+ }
+
+ /* Setup Hardware */
+ regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET);
+
+ cec_register_cec_notifier(ao_cec->adap, ao_cec->notify);
+
+ return 0;
+
+out_probe_core_clk:
+ clk_disable_unprepare(ao_cec->core);
+
+out_probe_adapter:
+ cec_delete_adapter(ao_cec->adap);
+
+out_probe_notify:
+ cec_notifier_put(ao_cec->notify);
+
+ dev_err(&pdev->dev, "CEC controller registration failed\n");
+
+ return ret;
+}
+
+static int meson_ao_cec_g12a_remove(struct platform_device *pdev)
+{
+ struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(ao_cec->core);
+
+ cec_unregister_adapter(ao_cec->adap);
+
+ cec_notifier_put(ao_cec->notify);
+
+ return 0;
+}
+
+static const struct of_device_id meson_ao_cec_g12a_of_match[] = {
+ { .compatible = "amlogic,meson-g12a-ao-cec", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match);
+
+static struct platform_driver meson_ao_cec_g12a_driver = {
+ .probe = meson_ao_cec_g12a_probe,
+ .remove = meson_ao_cec_g12a_remove,
+ .driver = {
+ .name = "meson-ao-cec-g12a",
+ .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match),
+ },
+};
+
+module_platform_driver(meson_ao_cec_g12a_driver);
+
+MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver");
+MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c
index cd4be38ab5ac..facf9b029e79 100644
--- a/drivers/media/platform/meson/ao-cec.c
+++ b/drivers/media/platform/meson/ao-cec.c
@@ -601,20 +601,14 @@ static const struct cec_adap_ops meson_ao_cec_ops = {
static int meson_ao_cec_probe(struct platform_device *pdev)
{
struct meson_ao_cec_device *ao_cec;
- struct platform_device *hdmi_dev;
- struct device_node *np;
+ struct device *hdmi_dev;
struct resource *res;
int ret, irq;
- np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0);
- if (!np) {
- dev_err(&pdev->dev, "Failed to find hdmi node\n");
- return -ENODEV;
- }
+ hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev);
- hdmi_dev = of_find_device_by_node(np);
- if (hdmi_dev == NULL)
- return -EPROBE_DEFER;
+ if (IS_ERR(hdmi_dev))
+ return PTR_ERR(hdmi_dev);
ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL);
if (!ao_cec)
@@ -622,7 +616,7 @@ static int meson_ao_cec_probe(struct platform_device *pdev)
spin_lock_init(&ao_cec->cec_reg_lock);
- ao_cec->notify = cec_notifier_get(&hdmi_dev->dev);
+ ao_cec->notify = cec_notifier_get(hdmi_dev);
if (!ao_cec->notify)
return -ENOMEM;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
index d022c65bb34c..851903867bc9 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
@@ -129,11 +129,9 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx)
mutex_lock(&ctx->lock);
if (dstbuf->used) {
vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0,
- ctx->picinfo.y_bs_sz);
+ ctx->picinfo.fb_sz[0]);
vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1,
- ctx->picinfo.c_bs_sz);
-
- dstbuf->ready_to_display = true;
+ ctx->picinfo.fb_sz[1]);
mtk_v4l2_debug(2,
"[%d]status=%x queue id=%d to done_list %d",
@@ -278,6 +276,27 @@ static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx)
clean_free_buffer(ctx);
}
+static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx,
+ unsigned int pixelformat)
+{
+ struct mtk_video_fmt *fmt;
+ struct mtk_q_data *dst_q_data;
+ unsigned int k;
+
+ dst_q_data = &ctx->q_data[MTK_Q_DATA_DST];
+ for (k = 0; k < NUM_FORMATS; k++) {
+ fmt = &mtk_video_formats[k];
+ if (fmt->fourcc == pixelformat) {
+ mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)",
+ dst_q_data->fmt.fourcc, pixelformat);
+ dst_q_data->fmt = fmt;
+ return;
+ }
+ }
+
+ mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat);
+}
+
static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx)
{
unsigned int dpbsize = 0;
@@ -299,6 +318,10 @@ static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx)
return -EINVAL;
}
+ if (ctx->last_decoded_picinfo.cap_fourcc != ctx->picinfo.cap_fourcc &&
+ ctx->picinfo.cap_fourcc != 0)
+ mtk_vdec_update_fmt(ctx, ctx->picinfo.cap_fourcc);
+
if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) ||
(ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h))
return 0;
@@ -352,11 +375,11 @@ static void mtk_vdec_worker(struct work_struct *work)
pfb = &dst_buf_info->frame_buffer;
pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
- pfb->base_y.size = ctx->picinfo.y_bs_sz + ctx->picinfo.y_len_sz;
+ pfb->base_y.size = ctx->picinfo.fb_sz[0];
pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1);
pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1);
- pfb->base_c.size = ctx->picinfo.c_bs_sz + ctx->picinfo.c_len_sz;
+ pfb->base_c.size = ctx->picinfo.fb_sz[1];
pfb->status = 0;
mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id);
@@ -388,7 +411,7 @@ static void mtk_vdec_worker(struct work_struct *work)
}
buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
- buf.size = (size_t)src_buf->planes[0].bytesused;
+ buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused;
if (!buf.va) {
v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
mtk_v4l2_err("[%d] id=%d src_addr is NULL!!",
@@ -976,14 +999,13 @@ static int vidioc_vdec_g_fmt(struct file *file, void *priv,
* So we just return picinfo yet, and update picinfo in
* stop_streaming hook function
*/
- q_data->sizeimage[0] = ctx->picinfo.y_bs_sz +
- ctx->picinfo.y_len_sz;
- q_data->sizeimage[1] = ctx->picinfo.c_bs_sz +
- ctx->picinfo.c_len_sz;
+ q_data->sizeimage[0] = ctx->picinfo.fb_sz[0];
+ q_data->sizeimage[1] = ctx->picinfo.fb_sz[1];
q_data->bytesperline[0] = ctx->last_decoded_picinfo.buf_w;
q_data->bytesperline[1] = ctx->last_decoded_picinfo.buf_w;
q_data->coded_width = ctx->picinfo.buf_w;
q_data->coded_height = ctx->picinfo.buf_h;
+ ctx->last_decoded_picinfo.cap_fourcc = q_data->fmt->fourcc;
/*
* Width and height are set to the dimensions
@@ -1103,10 +1125,11 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
struct mtk_vcodec_mem src_mem;
bool res_chg = false;
int ret = 0;
- unsigned int dpbsize = 1;
+ unsigned int dpbsize = 1, i = 0;
struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_v4l2_buffer *vb2_v4l2 = NULL;
struct mtk_video_dec_buf *buf = NULL;
+ struct mtk_q_data *dst_q_data;
mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p",
ctx->id, vb->vb2_queue->type,
@@ -1122,11 +1145,9 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
buf->queued_in_vb2 = true;
buf->queued_in_v4l2 = true;
- buf->ready_to_display = false;
} else {
buf->queued_in_vb2 = false;
buf->queued_in_v4l2 = true;
- buf->ready_to_display = false;
}
mutex_unlock(&ctx->lock);
return;
@@ -1155,10 +1176,10 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0);
src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
- src_mem.size = (size_t)src_buf->planes[0].bytesused;
+ src_mem.size = (size_t)src_buf->vb2_buf.planes[0].bytesused;
mtk_v4l2_debug(2,
"[%d] buf id=%d va=%p dma=%pad size=%zx",
- ctx->id, src_buf->index,
+ ctx->id, src_buf->vb2_buf.index,
src_mem.va, &src_mem.dma_addr,
src_mem.size);
@@ -1182,7 +1203,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
}
mtk_v4l2_debug(ret ? 0 : 1,
"[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d",
- ctx->id, src_buf->index,
+ ctx->id, src_buf->vb2_buf.index,
src_mem.size, ret, res_chg);
return;
}
@@ -1194,21 +1215,18 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
}
ctx->last_decoded_picinfo = ctx->picinfo;
- ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
- ctx->picinfo.y_bs_sz +
- ctx->picinfo.y_len_sz;
- ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] =
- ctx->picinfo.buf_w;
- ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] =
- ctx->picinfo.c_bs_sz +
- ctx->picinfo.c_len_sz;
- ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] = ctx->picinfo.buf_w;
+ dst_q_data = &ctx->q_data[MTK_Q_DATA_DST];
+ for (i = 0; i < dst_q_data->fmt->num_planes; i++) {
+ dst_q_data->sizeimage[i] = ctx->picinfo.fb_sz[i];
+ dst_q_data->bytesperline[i] = ctx->picinfo.buf_w;
+ }
+
mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x",
ctx->id,
ctx->picinfo.buf_w, ctx->picinfo.buf_h,
ctx->picinfo.pic_w, ctx->picinfo.pic_h,
- ctx->q_data[MTK_Q_DATA_DST].sizeimage[0],
- ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]);
+ dst_q_data->sizeimage[0],
+ dst_q_data->sizeimage[1]);
ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize);
if (dpbsize == 0)
@@ -1253,7 +1271,6 @@ static int vb2ops_vdec_buf_init(struct vb2_buffer *vb)
if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
buf->used = false;
- buf->ready_to_display = false;
buf->queued_in_v4l2 = false;
} else {
buf->lastframe = false;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
index dc4fc1df63c5..e4984edec4f8 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
@@ -45,7 +45,6 @@ struct vdec_fb {
* @list: link list
* @used: Capture buffer contain decoded frame data and keep in
* codec data structure
- * @ready_to_display: Capture buffer not display yet
* @queued_in_vb2: Capture buffer is queue in vb2
* @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2
* queue yet
@@ -60,7 +59,6 @@ struct mtk_video_dec_buf {
struct list_head list;
bool used;
- bool ready_to_display;
bool queued_in_vb2;
bool queued_in_v4l2;
bool lastframe;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index e7e2a108def9..662a84b822af 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -211,24 +211,20 @@ struct mtk_vcodec_pm {
* @pic_h: picture height
* @buf_w: picture buffer width (64 aligned up from pic_w)
* @buf_h: picture buffer heiht (64 aligned up from pic_h)
- * @y_bs_sz: Y bitstream size
- * @c_bs_sz: CbCr bitstream size
- * @y_len_sz: additional size required to store decompress information for y
- * plane
- * @c_len_sz: additional size required to store decompress information for cbcr
- * plane
+ * @fb_sz: bitstream size of each plane
* E.g. suppose picture size is 176x144,
* buffer size will be aligned to 176x160.
+ * @cap_fourcc: fourcc number(may changed when resolution change)
+ * @reserved: align struct to 64-bit in order to adjust 32-bit and 64-bit os.
*/
struct vdec_pic_info {
unsigned int pic_w;
unsigned int pic_h;
unsigned int buf_w;
unsigned int buf_h;
- unsigned int y_bs_sz;
- unsigned int c_bs_sz;
- unsigned int y_len_sz;
- unsigned int c_len_sz;
+ unsigned int fb_sz[VIDEO_MAX_PLANES];
+ unsigned int cap_fourcc;
+ unsigned int reserved;
};
/**
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
index c6b48b5925fb..50351adafc47 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -894,7 +894,7 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q)
if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) {
- dst_buf->planes[0].bytesused = 0;
+ dst_buf->vb2_buf.planes[0].bytesused = 0;
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
}
} else {
@@ -947,7 +947,7 @@ static int mtk_venc_encode_header(void *priv)
bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
- bs_buf.size = (size_t)dst_buf->planes[0].length;
+ bs_buf.size = (size_t)dst_buf->vb2_buf.planes[0].length;
mtk_v4l2_debug(1,
"[%d] buf id=%d va=0x%p dma_addr=0x%llx size=%zu",
@@ -976,7 +976,7 @@ static int mtk_venc_encode_header(void *priv)
}
ctx->state = MTK_STATE_HEADER;
- dst_buf->planes[0].bytesused = enc_result.bs_size;
+ dst_buf->vb2_buf.planes[0].bytesused = enc_result.bs_size;
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
return 0;
@@ -1107,12 +1107,12 @@ static void mtk_venc_worker(struct work_struct *work)
if (ret) {
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
- dst_buf->planes[0].bytesused = 0;
+ dst_buf->vb2_buf.planes[0].bytesused = 0;
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
mtk_v4l2_err("venc_if_encode failed=%d", ret);
} else {
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
- dst_buf->planes[0].bytesused = enc_result.bs_size;
+ dst_buf->vb2_buf.planes[0].bytesused = enc_result.bs_size;
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
mtk_v4l2_debug(2, "venc_if_encode bs size=%d",
enc_result.bs_size);
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
index 02c960c63ac0..cdbcd6909728 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
@@ -253,8 +253,8 @@ static void get_pic_info(struct vdec_h264_inst *inst,
*pic = inst->vsi->pic;
mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
- mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz,
- pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz);
+ mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
+ pic->fb_sz[0], pic->fb_sz[1]);
}
static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr)
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
index bac3723038de..ba79136421ef 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
@@ -294,8 +294,8 @@ static void get_pic_info(struct vdec_vp8_inst *inst, struct vdec_pic_info *pic)
mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
- mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz,
- pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz);
+ mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
+ pic->fb_sz[0], pic->fb_sz[1]);
}
static void vp8_dec_finish(struct vdec_vp8_inst *inst)
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
index bc8349bc2e80..939ea14bf6c5 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
@@ -481,15 +481,15 @@ static void vp9_swap_frm_bufs(struct vdec_vp9_inst *inst)
*/
if ((frm_to_show->fb != NULL) &&
(inst->cur_fb->base_y.size >=
- frm_to_show->fb->base_y.size)) {
+ frm_to_show->fb->base_y.size) &&
+ (inst->cur_fb->base_c.size >=
+ frm_to_show->fb->base_c.size)) {
memcpy((void *)inst->cur_fb->base_y.va,
(void *)frm_to_show->fb->base_y.va,
- vsi->buf_w *
- vsi->buf_h);
+ frm_to_show->fb->base_y.size);
memcpy((void *)inst->cur_fb->base_c.va,
(void *)frm_to_show->fb->base_c.va,
- vsi->buf_w *
- vsi->buf_h / 2);
+ frm_to_show->fb->base_c.size);
} else {
/* After resolution change case, current CAPTURE buffer
* may have less buffer size than frm_to_show buffer
@@ -702,10 +702,8 @@ static void init_all_fb_lists(struct vdec_vp9_inst *inst)
static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic)
{
- pic->y_bs_sz = inst->vsi->buf_sz_y_bs;
- pic->c_bs_sz = inst->vsi->buf_sz_c_bs;
- pic->y_len_sz = inst->vsi->buf_len_sz_y;
- pic->c_len_sz = inst->vsi->buf_len_sz_c;
+ pic->fb_sz[0] = inst->vsi->buf_sz_y_bs + inst->vsi->buf_len_sz_y;
+ pic->fb_sz[1] = inst->vsi->buf_sz_c_bs + inst->vsi->buf_len_sz_c;
pic->pic_w = inst->vsi->pic_w;
pic->pic_h = inst->vsi->pic_h;
@@ -714,8 +712,9 @@ static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic)
mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)",
pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h);
- mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz,
- pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz);
+ mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)",
+ pic->fb_sz[0],
+ pic->fb_sz[1]);
}
static void get_disp_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb)
@@ -895,7 +894,7 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
if (vsi->resolution_changed) {
if (!vp9_alloc_work_buf(inst)) {
- ret = -EINVAL;
+ ret = -EIO;
goto DECODE_ERROR;
}
}
@@ -924,14 +923,12 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs,
if (vsi->show_existing_frame && (vsi->frm_to_show_idx <
VP9_MAX_FRM_BUF_NUM)) {
- mtk_vcodec_err(inst,
+ mtk_vcodec_debug(inst,
"Skip Decode drv->new_fb_idx=%d, drv->frm_to_show_idx=%d",
vsi->new_fb_idx, vsi->frm_to_show_idx);
vp9_ref_cnt_fb(inst, &vsi->new_fb_idx,
vsi->frm_to_show_idx);
- ret = -EINVAL;
- goto DECODE_ERROR;
}
/* VPU assign the buffer pointer in its address space,
diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c
index b6602490a247..46c45f93c977 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.c
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c
@@ -614,7 +614,7 @@ static void vpu_init_ipi_handler(void *data, unsigned int len, void *priv)
struct vpu_run *run = (struct vpu_run *)data;
vpu->run.signaled = run->signaled;
- strncpy(vpu->run.fw_ver, run->fw_ver, VPU_FW_VER_LEN);
+ strscpy(vpu->run.fw_ver, run->fw_ver, sizeof(vpu->run.fw_ver));
vpu->run.dec_capability = run->dec_capability;
vpu->run.enc_capability = run->enc_capability;
wake_up_interruptible(&vpu->run.wq);
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index f60f499c596b..e100b30bb6f5 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -385,8 +385,8 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data)
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+ strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
+ strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index 4b5e55d41ad4..30ce2ba120a1 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -14,5 +14,5 @@ config VIDEO_OMAP2_VOUT
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select FRAME_VECTOR
default n
- ---help---
+ help
V4L2 Display driver support for OMAP2/3 based boards.
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 37f0d7146dfa..cb6a9e3946b6 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -1527,23 +1527,20 @@ static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
unsigned long size;
struct videobuf_buffer *vb;
- vb = q->bufs[b->index];
-
if (!vout->streaming)
return -EINVAL;
- if (file->f_flags & O_NONBLOCK)
- /* Call videobuf_dqbuf for non blocking mode */
- ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
- else
- /* Call videobuf_dqbuf for blocking mode */
- ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+ ret = videobuf_dqbuf(q, b, !!(file->f_flags & O_NONBLOCK));
+ if (ret)
+ return ret;
+
+ vb = q->bufs[b->index];
addr = (unsigned long) vout->buf_phy_addr[vb->i];
size = (unsigned long) vb->size;
dma_unmap_single(vout->vid_dev->v4l2_dev.dev, addr,
size, DMA_TO_DEVICE);
- return ret;
+ return 0;
}
static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index 4fe228752a43..a632f06d9fff 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -2350,7 +2350,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev,
pcdev->platform_flags |= PXA_CAMERA_PCLK_EN;
asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
- remote = of_graph_get_remote_port(np);
+ remote = of_graph_get_remote_port_parent(np);
if (remote)
asd->match.fwnode = of_fwnode_handle(remote);
else
diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h
index 15804ad7e65d..34ea503a9842 100644
--- a/drivers/media/platform/qcom/venus/hfi_helper.h
+++ b/drivers/media/platform/qcom/venus/hfi_helper.h
@@ -569,7 +569,7 @@ struct hfi_capability {
struct hfi_capabilities {
u32 num_capabilities;
- struct hfi_capability data[1];
+ struct hfi_capability *data;
};
#define HFI_DEBUG_MSG_LOW 0x01
@@ -726,7 +726,7 @@ struct hfi_profile_level {
struct hfi_profile_level_supported {
u32 profile_count;
- struct hfi_profile_level profile_level[1];
+ struct hfi_profile_level *profile_level;
};
struct hfi_quality_vs_speed {
diff --git a/drivers/media/platform/rcar-vin/Kconfig b/drivers/media/platform/rcar-vin/Kconfig
index e3eb8fee2536..240ac3f3c941 100644
--- a/drivers/media/platform/rcar-vin/Kconfig
+++ b/drivers/media/platform/rcar-vin/Kconfig
@@ -3,6 +3,7 @@ config VIDEO_RCAR_CSI2
tristate "R-Car MIPI CSI-2 Receiver"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF
depends on ARCH_RENESAS || COMPILE_TEST
+ select RESET_CONTROLLER
select V4L2_FWNODE
help
Support for Renesas R-Car MIPI CSI-2 receiver.
@@ -17,7 +18,7 @@ config VIDEO_RCAR_VIN
depends on ARCH_RENESAS || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
- ---help---
+ help
Support for Renesas R-Car Video Input (VIN) driver.
Supports R-Car Gen2 and Gen3 SoCs.
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 594d80434004..64f9cf790445 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -546,7 +546,9 @@ static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier,
vin_dbg(vin, "unbind parallel subdev %s\n", subdev->name);
+ mutex_lock(&vin->lock);
rvin_parallel_subdevice_detach(vin);
+ mutex_unlock(&vin->lock);
}
static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier,
@@ -556,7 +558,9 @@ static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier,
struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
int ret;
+ mutex_lock(&vin->lock);
ret = rvin_parallel_subdevice_attach(vin, subdev);
+ mutex_unlock(&vin->lock);
if (ret)
return ret;
@@ -664,6 +668,7 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
}
/* Create all media device links between VINs and CSI-2's. */
+ mutex_lock(&vin->group->lock);
for (route = vin->info->routes; route->mask; route++) {
struct media_pad *source_pad, *sink_pad;
struct media_entity *source, *sink;
@@ -699,6 +704,7 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
break;
}
}
+ mutex_unlock(&vin->group->lock);
return ret;
}
@@ -714,6 +720,8 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
if (vin->group->vin[i])
rvin_v4l2_unregister(vin->group->vin[i]);
+ mutex_lock(&vin->group->lock);
+
for (i = 0; i < RVIN_CSI_MAX; i++) {
if (vin->group->csi[i].fwnode != asd->match.fwnode)
continue;
@@ -721,6 +729,8 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i);
break;
}
+
+ mutex_unlock(&vin->group->lock);
}
static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
@@ -730,6 +740,8 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev);
unsigned int i;
+ mutex_lock(&vin->group->lock);
+
for (i = 0; i < RVIN_CSI_MAX; i++) {
if (vin->group->csi[i].fwnode != asd->match.fwnode)
continue;
@@ -738,6 +750,8 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
break;
}
+ mutex_unlock(&vin->group->lock);
+
return 0;
}
@@ -752,6 +766,7 @@ static int rvin_mc_parse_of_endpoint(struct device *dev,
struct v4l2_async_subdev *asd)
{
struct rvin_dev *vin = dev_get_drvdata(dev);
+ int ret = 0;
if (vep->base.port != 1 || vep->base.id >= RVIN_CSI_MAX)
return -EINVAL;
@@ -762,38 +777,48 @@ static int rvin_mc_parse_of_endpoint(struct device *dev,
return -ENOTCONN;
}
+ mutex_lock(&vin->group->lock);
+
if (vin->group->csi[vep->base.id].fwnode) {
vin_dbg(vin, "OF device %pOF already handled\n",
to_of_node(asd->match.fwnode));
- return -ENOTCONN;
+ ret = -ENOTCONN;
+ goto out;
}
vin->group->csi[vep->base.id].fwnode = asd->match.fwnode;
vin_dbg(vin, "Add group OF device %pOF to slot %u\n",
to_of_node(asd->match.fwnode), vep->base.id);
+out:
+ mutex_unlock(&vin->group->lock);
- return 0;
+ return ret;
}
static int rvin_mc_parse_of_graph(struct rvin_dev *vin)
{
- unsigned int count = 0;
+ unsigned int count = 0, vin_mask = 0;
unsigned int i;
int ret;
mutex_lock(&vin->group->lock);
/* If not all VIN's are registered don't register the notifier. */
- for (i = 0; i < RCAR_VIN_NUM; i++)
- if (vin->group->vin[i])
+ for (i = 0; i < RCAR_VIN_NUM; i++) {
+ if (vin->group->vin[i]) {
count++;
+ vin_mask |= BIT(i);
+ }
+ }
if (vin->group->count != count) {
mutex_unlock(&vin->group->lock);
return 0;
}
+ mutex_unlock(&vin->group->lock);
+
v4l2_async_notifier_init(&vin->group->notifier);
/*
@@ -802,21 +827,17 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin)
* will only be registered once with the group notifier.
*/
for (i = 0; i < RCAR_VIN_NUM; i++) {
- if (!vin->group->vin[i])
+ if (!(vin_mask & BIT(i)))
continue;
ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(
vin->group->vin[i]->dev, &vin->group->notifier,
sizeof(struct v4l2_async_subdev), 1,
rvin_mc_parse_of_endpoint);
- if (ret) {
- mutex_unlock(&vin->group->lock);
+ if (ret)
return ret;
- }
}
- mutex_unlock(&vin->group->lock);
-
if (list_empty(&vin->group->notifier.asd_list))
return 0;
@@ -1136,6 +1157,10 @@ static const struct rvin_info rcar_info_r8a77995 = {
static const struct of_device_id rvin_of_id_table[] = {
{
+ .compatible = "renesas,vin-r8a774a1",
+ .data = &rcar_info_r8a7796,
+ },
+ {
.compatible = "renesas,vin-r8a774c0",
.data = &rcar_info_r8a77990,
},
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index f64528d2be3c..8f097e514900 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -14,6 +14,7 @@
#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/reset.h>
#include <linux/sys_soc.h>
#include <media/v4l2-ctrls.h>
@@ -67,6 +68,7 @@ struct rcar_csi2;
/* Field Detection Control */
#define FLD_REG 0x1c
#define FLD_FLD_NUM(n) (((n) & 0xff) << 16)
+#define FLD_DET_SEL(n) (((n) & 0x3) << 4)
#define FLD_FLD_EN4 BIT(3)
#define FLD_FLD_EN3 BIT(2)
#define FLD_FLD_EN2 BIT(1)
@@ -83,6 +85,9 @@ struct rcar_csi2;
/* Interrupt Enable */
#define INTEN_REG 0x30
+#define INTEN_INT_AFIFO_OF BIT(27)
+#define INTEN_INT_ERRSOTHS BIT(4)
+#define INTEN_INT_ERRSOTSYNCHS BIT(3)
/* Interrupt Source Mask */
#define INTCLOSE_REG 0x34
@@ -350,6 +355,7 @@ struct rcar_csi2 {
struct device *dev;
void __iomem *base;
const struct rcar_csi2_info *info;
+ struct reset_control *rstc;
struct v4l2_subdev subdev;
struct media_pad pads[NR_OF_RCAR_CSI2_PAD];
@@ -387,11 +393,19 @@ static void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data)
iowrite32(data, priv->base + reg);
}
-static void rcsi2_reset(struct rcar_csi2 *priv)
+static void rcsi2_enter_standby(struct rcar_csi2 *priv)
{
- rcsi2_write(priv, SRST_REG, SRST_SRST);
+ rcsi2_write(priv, PHYCNT_REG, 0);
+ rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR);
+ reset_control_assert(priv->rstc);
usleep_range(100, 150);
- rcsi2_write(priv, SRST_REG, 0);
+ pm_runtime_put(priv->dev);
+}
+
+static void rcsi2_exit_standby(struct rcar_csi2 *priv)
+{
+ pm_runtime_get_sync(priv->dev);
+ reset_control_deassert(priv->rstc);
}
static int rcsi2_wait_phy_start(struct rcar_csi2 *priv)
@@ -462,10 +476,10 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
return mbps;
}
-static int rcsi2_start(struct rcar_csi2 *priv)
+static int rcsi2_start_receiver(struct rcar_csi2 *priv)
{
const struct rcar_csi2_format *format;
- u32 phycnt, vcdt = 0, vcdt2 = 0;
+ u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
unsigned int i;
int mbps, ret;
@@ -497,6 +511,16 @@ static int rcsi2_start(struct rcar_csi2 *priv)
vcdt2 |= vcdt_part << ((i % 2) * 16);
}
+ if (priv->mf.field == V4L2_FIELD_ALTERNATE) {
+ fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2
+ | FLD_FLD_EN;
+
+ if (priv->mf.height == 240)
+ fld |= FLD_FLD_NUM(0);
+ else
+ fld |= FLD_FLD_NUM(1);
+ }
+
phycnt = PHYCNT_ENABLECLK;
phycnt |= (1 << priv->lanes) - 1;
@@ -504,14 +528,15 @@ static int rcsi2_start(struct rcar_csi2 *priv)
if (mbps < 0)
return mbps;
+ /* Enable interrupts. */
+ rcsi2_write(priv, INTEN_REG, INTEN_INT_AFIFO_OF | INTEN_INT_ERRSOTHS
+ | INTEN_INT_ERRSOTSYNCHS);
+
/* Init */
rcsi2_write(priv, TREF_REG, TREF_TREF);
- rcsi2_reset(priv);
rcsi2_write(priv, PHTC_REG, 0);
/* Configure */
- rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 |
- FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN);
rcsi2_write(priv, VCDT_REG, vcdt);
if (vcdt2)
rcsi2_write(priv, VCDT2_REG, vcdt2);
@@ -542,6 +567,7 @@ static int rcsi2_start(struct rcar_csi2 *priv)
rcsi2_write(priv, PHYCNT_REG, phycnt);
rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN |
LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP);
+ rcsi2_write(priv, FLD_REG, fld);
rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ);
rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ);
@@ -564,19 +590,36 @@ static int rcsi2_start(struct rcar_csi2 *priv)
return 0;
}
-static void rcsi2_stop(struct rcar_csi2 *priv)
+static int rcsi2_start(struct rcar_csi2 *priv)
{
- rcsi2_write(priv, PHYCNT_REG, 0);
+ int ret;
- rcsi2_reset(priv);
+ rcsi2_exit_standby(priv);
- rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR);
+ ret = rcsi2_start_receiver(priv);
+ if (ret) {
+ rcsi2_enter_standby(priv);
+ return ret;
+ }
+
+ ret = v4l2_subdev_call(priv->remote, video, s_stream, 1);
+ if (ret) {
+ rcsi2_enter_standby(priv);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void rcsi2_stop(struct rcar_csi2 *priv)
+{
+ rcsi2_enter_standby(priv);
+ v4l2_subdev_call(priv->remote, video, s_stream, 0);
}
static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
{
struct rcar_csi2 *priv = sd_to_csi2(sd);
- struct v4l2_subdev *nextsd;
int ret = 0;
mutex_lock(&priv->lock);
@@ -586,27 +629,12 @@ static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
goto out;
}
- nextsd = priv->remote;
-
if (enable && priv->stream_count == 0) {
- pm_runtime_get_sync(priv->dev);
-
ret = rcsi2_start(priv);
- if (ret) {
- pm_runtime_put(priv->dev);
- goto out;
- }
-
- ret = v4l2_subdev_call(nextsd, video, s_stream, 1);
- if (ret) {
- rcsi2_stop(priv);
- pm_runtime_put(priv->dev);
+ if (ret)
goto out;
- }
} else if (!enable && priv->stream_count == 1) {
rcsi2_stop(priv);
- v4l2_subdev_call(nextsd, video, s_stream, 0);
- pm_runtime_put(priv->dev);
}
priv->stream_count += enable ? 1 : -1;
@@ -664,6 +692,43 @@ static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
.pad = &rcar_csi2_pad_ops,
};
+static irqreturn_t rcsi2_irq(int irq, void *data)
+{
+ struct rcar_csi2 *priv = data;
+ u32 status, err_status;
+
+ status = rcsi2_read(priv, INTSTATE_REG);
+ err_status = rcsi2_read(priv, INTERRSTATE_REG);
+
+ if (!status)
+ return IRQ_HANDLED;
+
+ rcsi2_write(priv, INTSTATE_REG, status);
+
+ if (!err_status)
+ return IRQ_HANDLED;
+
+ rcsi2_write(priv, INTERRSTATE_REG, err_status);
+
+ dev_info(priv->dev, "Transfer error, restarting CSI-2 receiver\n");
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t rcsi2_irq_thread(int irq, void *data)
+{
+ struct rcar_csi2 *priv = data;
+
+ mutex_lock(&priv->lock);
+ rcsi2_stop(priv);
+ usleep_range(1000, 2000);
+ if (rcsi2_start(priv))
+ dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n");
+ mutex_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
/* -----------------------------------------------------------------------------
* Async handling and registration of subdevices and links.
*/
@@ -854,7 +919,8 @@ static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps,
return rcsi2_phtw_write(priv, value->reg, code);
}
-static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps)
+static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
+ unsigned int mbps)
{
static const struct phtw_value step1[] = {
{ .data = 0xcc, .code = 0xe2 },
@@ -880,7 +946,7 @@ static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps)
if (ret)
return ret;
- if (mbps <= 250) {
+ if (mbps != 0 && mbps <= 250) {
ret = rcsi2_phtw_write(priv, 0x39, 0x05);
if (ret)
return ret;
@@ -894,6 +960,16 @@ static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps)
return rcsi2_phtw_write_array(priv, step2);
}
+static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps)
+{
+ return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps);
+}
+
+static int rcsi2_init_phtw_h3es2(struct rcar_csi2 *priv, unsigned int mbps)
+{
+ return __rcsi2_init_phtw_h3_v3h_m3n(priv, 0);
+}
+
static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps)
{
return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44);
@@ -902,11 +978,11 @@ static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps)
static int rcsi2_confirm_start_v3m_e3(struct rcar_csi2 *priv)
{
static const struct phtw_value step1[] = {
- { .data = 0xed, .code = 0x34 },
- { .data = 0xed, .code = 0x44 },
- { .data = 0xed, .code = 0x54 },
- { .data = 0xed, .code = 0x84 },
- { .data = 0xed, .code = 0x94 },
+ { .data = 0xee, .code = 0x34 },
+ { .data = 0xee, .code = 0x44 },
+ { .data = 0xee, .code = 0x54 },
+ { .data = 0xee, .code = 0x84 },
+ { .data = 0xee, .code = 0x94 },
{ /* sentinel */ },
};
@@ -925,7 +1001,7 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv,
struct platform_device *pdev)
{
struct resource *res;
- int irq;
+ int irq, ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(&pdev->dev, res);
@@ -936,6 +1012,16 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv,
if (irq < 0)
return irq;
+ ret = devm_request_threaded_irq(&pdev->dev, irq, rcsi2_irq,
+ rcsi2_irq_thread, IRQF_SHARED,
+ KBUILD_MODNAME, priv);
+ if (ret)
+ return ret;
+
+ priv->rstc = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->rstc))
+ return PTR_ERR(priv->rstc);
+
return 0;
}
@@ -952,6 +1038,14 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795es1 = {
.num_channels = 4,
};
+static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = {
+ .init_phtw = rcsi2_init_phtw_h3es2,
+ .hsfreqrange = hsfreqrange_h3_v3h_m3n,
+ .csi0clkfreqrange = 0x20,
+ .num_channels = 4,
+ .clear_ulps = true,
+};
+
static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
.hsfreqrange = hsfreqrange_m3w_h3es1,
.num_channels = 4,
@@ -986,6 +1080,10 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
static const struct of_device_id rcar_csi2_of_table[] = {
{
+ .compatible = "renesas,r8a774a1-csi2",
+ .data = &rcar_csi2_info_r8a7796,
+ },
+ {
.compatible = "renesas,r8a774c0-csi2",
.data = &rcar_csi2_info_r8a77990,
},
@@ -1017,11 +1115,15 @@ static const struct of_device_id rcar_csi2_of_table[] = {
};
MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
-static const struct soc_device_attribute r8a7795es1[] = {
+static const struct soc_device_attribute r8a7795[] = {
{
.soc_id = "r8a7795", .revision = "ES1.*",
.data = &rcar_csi2_info_r8a7795es1,
},
+ {
+ .soc_id = "r8a7795", .revision = "ES2.*",
+ .data = &rcar_csi2_info_r8a7795es2,
+ },
{ /* sentinel */ },
};
@@ -1039,10 +1141,10 @@ static int rcsi2_probe(struct platform_device *pdev)
priv->info = of_device_get_match_data(&pdev->dev);
/*
- * r8a7795 ES1.x behaves differently than the ES2.0+ but doesn't
- * have it's own compatible string.
+ * The different ES versions of r8a7795 (H3) behave differently but
+ * share the same compatible string.
*/
- attr = soc_device_match(r8a7795es1);
+ attr = soc_device_match(r8a7795);
if (attr)
priv->info = attr->data;
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index 2207a31d355e..91ab064404a1 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -486,7 +486,7 @@ static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs)
}
/* Use previous value if its XS value is closer */
- if (p_prev_set && p_set &&
+ if (p_prev_set &&
xs - p_prev_set->xs_value < p_set->xs_value - xs)
p_set = p_prev_set;
diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
index c417ff8f6fe5..608e5217ccd5 100644
--- a/drivers/media/platform/rcar_drif.c
+++ b/drivers/media/platform/rcar_drif.c
@@ -1405,11 +1405,9 @@ static int rcar_drif_probe(struct platform_device *pdev)
/* Register map */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ch->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(ch->base)) {
- ret = PTR_ERR(ch->base);
- dev_err(&pdev->dev, "ioremap failed (%d)\n", ret);
- return ret;
- }
+ if (IS_ERR(ch->base))
+ return PTR_ERR(ch->base);
+
ch->start = res->start;
platform_set_drvdata(pdev, ch);
diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c
index 6bda1eee9170..6a90bc4c476e 100644
--- a/drivers/media/platform/rcar_fdp1.c
+++ b/drivers/media/platform/rcar_fdp1.c
@@ -945,7 +945,7 @@ static void fdp1_configure_wpf(struct fdp1_ctx *ctx,
u32 rndctl;
pstride = q_data->format.plane_fmt[0].bytesperline
- << FD1_WPF_PSTRIDE_Y_SHIFT;
+ << FD1_WPF_PSTRIDE_Y_SHIFT;
if (q_data->format.num_planes > 1)
pstride |= q_data->format.plane_fmt[1].bytesperline
@@ -1139,8 +1139,8 @@ static int fdp1_m2m_job_ready(void *priv)
int dstbufs = 1;
dprintk(ctx->fdp1, "+ Src: %d : Dst: %d\n",
- v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx),
- v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx));
+ v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx),
+ v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx));
/* One output buffer is required for each field */
if (V4L2_FIELD_HAS_BOTH(src_q_data->format.field))
@@ -1278,7 +1278,7 @@ static void fdp1_m2m_device_run(void *priv)
fdp1_queue_field(ctx, fbuf);
dprintk(fdp1, "Queued Buffer [%d] last_field:%d\n",
- i, fbuf->last_field);
+ i, fbuf->last_field);
}
/* Queue as many jobs as our data provides for */
@@ -1337,7 +1337,7 @@ static void device_frame_end(struct fdp1_dev *fdp1,
fdp1_job_free(fdp1, job);
dprintk(fdp1, "curr_ctx->num_processed %d curr_ctx->translen %d\n",
- ctx->num_processed, ctx->translen);
+ ctx->num_processed, ctx->translen);
if (ctx->num_processed == ctx->translen ||
ctx->aborting) {
@@ -1362,7 +1362,7 @@ static int fdp1_vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, DRIVER_NAME, sizeof(cap->driver));
strscpy(cap->card, DRIVER_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
- "platform:%s", DRIVER_NAME);
+ "platform:%s", DRIVER_NAME);
return 0;
}
@@ -1993,13 +1993,13 @@ static void fdp1_stop_streaming(struct vb2_queue *q)
/* Free smsk_data */
if (ctx->smsk_cpu) {
dma_free_coherent(ctx->fdp1->dev, ctx->smsk_size,
- ctx->smsk_cpu, ctx->smsk_addr[0]);
+ ctx->smsk_cpu, ctx->smsk_addr[0]);
ctx->smsk_addr[0] = ctx->smsk_addr[1] = 0;
ctx->smsk_cpu = NULL;
}
WARN(!list_empty(&ctx->fields_queue),
- "Buffer queue not empty");
+ "Buffer queue not empty");
} else {
/* Empty Capture queues (Jobs) */
struct fdp1_job *job;
@@ -2021,10 +2021,10 @@ static void fdp1_stop_streaming(struct vb2_queue *q)
fdp1_field_complete(ctx, ctx->previous);
WARN(!list_empty(&ctx->fdp1->queued_job_list),
- "Queued Job List not empty");
+ "Queued Job List not empty");
WARN(!list_empty(&ctx->fdp1->hw_job_list),
- "HW Job list not empty");
+ "HW Job list not empty");
}
}
@@ -2110,7 +2110,7 @@ static int fdp1_open(struct file *file)
fdp1_ctrl_deint_menu);
ctrl = v4l2_ctrl_new_std(&ctx->hdl, &fdp1_ctrl_ops,
- V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 2, 1, 1);
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 2, 1, 1);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
@@ -2347,8 +2347,8 @@ static int fdp1_probe(struct platform_device *pdev)
goto release_m2m;
}
- v4l2_info(&fdp1->v4l2_dev,
- "Device registered as /dev/video%d\n", vfd->num);
+ v4l2_info(&fdp1->v4l2_dev, "Device registered as /dev/video%d\n",
+ vfd->num);
/* Power up the cells to read HW */
pm_runtime_enable(&pdev->dev);
@@ -2367,7 +2367,7 @@ static int fdp1_probe(struct platform_device *pdev)
break;
default:
dev_err(fdp1->dev, "FDP1 Unidentifiable (0x%08x)\n",
- hw_version);
+ hw_version);
}
/* Allow the hw to sleep until an open call puts it to use */
diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c
index 8837e2678bde..7f62f5ef0086 100644
--- a/drivers/media/platform/s5p-cec/s5p_cec.c
+++ b/drivers/media/platform/s5p-cec/s5p_cec.c
@@ -178,22 +178,16 @@ static const struct cec_adap_ops s5p_cec_adap_ops = {
static int s5p_cec_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np;
- struct platform_device *hdmi_dev;
+ struct device *hdmi_dev;
struct resource *res;
struct s5p_cec_dev *cec;
bool needs_hpd = of_property_read_bool(pdev->dev.of_node, "needs-hpd");
int ret;
- np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0);
+ hdmi_dev = cec_notifier_parse_hdmi_phandle(dev);
- if (!np) {
- dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n");
- return -ENODEV;
- }
- hdmi_dev = of_find_device_by_node(np);
- if (hdmi_dev == NULL)
- return -EPROBE_DEFER;
+ if (IS_ERR(hdmi_dev))
+ return PTR_ERR(hdmi_dev);
cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
if (!cec)
@@ -224,7 +218,7 @@ static int s5p_cec_probe(struct platform_device *pdev)
if (IS_ERR(cec->reg))
return PTR_ERR(cec->reg);
- cec->notifier = cec_notifier_get(&hdmi_dev->dev);
+ cec->notifier = cec_notifier_get(hdmi_dev);
if (cec->notifier == NULL)
return -ENOMEM;
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index 971c47165010..c8f394e1aff4 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -297,8 +297,8 @@ static int g2d_release(struct file *file)
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1);
- strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1);
+ strscpy(cap->driver, G2D_NAME, sizeof(cap->driver));
+ strscpy(cap->card, G2D_NAME, sizeof(cap->card));
cap->bus_info[0] = 0;
cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -312,7 +312,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
return -EINVAL;
fmt = &formats[f->index];
f->pixelformat = fmt->fourcc;
- strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ strscpy(f->description, fmt->name, sizeof(f->description));
return 0;
}
diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c
index a425a10540c1..e5080d6f5b2d 100644
--- a/drivers/media/platform/seco-cec/seco-cec.c
+++ b/drivers/media/platform/seco-cec/seco-cec.c
@@ -536,6 +536,7 @@ static int secocec_cec_get_notifier(struct cec_notifier **notify)
return -EPROBE_DEFER;
*notify = cec_notifier_get_conn(d, m->conn);
+ put_device(d);
return 0;
}
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index d277cc674349..5a9ba05c996e 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -493,9 +493,6 @@ static int sh_veu_try_fmt_vid_cap(struct file *file, void *priv,
const struct sh_veu_format *fmt;
fmt = sh_veu_find_fmt(f);
- if (!fmt)
- /* wrong buffer type */
- return -EINVAL;
return sh_veu_try_fmt(f, fmt);
}
@@ -506,9 +503,6 @@ static int sh_veu_try_fmt_vid_out(struct file *file, void *priv,
const struct sh_veu_format *fmt;
fmt = sh_veu_find_fmt(f);
- if (!fmt)
- /* wrong buffer type */
- return -EINVAL;
return sh_veu_try_fmt(f, fmt);
}
diff --git a/drivers/media/platform/sti/c8sectpfe/Kconfig b/drivers/media/platform/sti/c8sectpfe/Kconfig
index 7420a50572d3..93eaabfd5437 100644
--- a/drivers/media/platform/sti/c8sectpfe/Kconfig
+++ b/drivers/media/platform/sti/c8sectpfe/Kconfig
@@ -12,7 +12,7 @@ config DVB_C8SECTPFE
select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
- ---help---
+ help
This adds support for DVB front-end cards connected
to TS inputs of STiH407/410 SoC.
diff --git a/drivers/media/platform/sti/cec/stih-cec.c b/drivers/media/platform/sti/cec/stih-cec.c
index d34099f75990..fc37efe1d554 100644
--- a/drivers/media/platform/sti/cec/stih-cec.c
+++ b/drivers/media/platform/sti/cec/stih-cec.c
@@ -301,26 +301,19 @@ static int stih_cec_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct resource *res;
struct stih_cec *cec;
- struct device_node *np;
- struct platform_device *hdmi_dev;
+ struct device *hdmi_dev;
int ret;
+ hdmi_dev = cec_notifier_parse_hdmi_phandle(dev);
+
+ if (IS_ERR(hdmi_dev))
+ return PTR_ERR(hdmi_dev);
+
cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL);
if (!cec)
return -ENOMEM;
- np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0);
-
- if (!np) {
- dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n");
- return -ENODEV;
- }
-
- hdmi_dev = of_find_device_by_node(np);
- if (!hdmi_dev)
- return -EPROBE_DEFER;
-
- cec->notifier = cec_notifier_get(&hdmi_dev->dev);
+ cec->notifier = cec_notifier_get(hdmi_dev);
if (!cec->notifier)
return -ENOMEM;
diff --git a/drivers/media/platform/sti/delta/delta-ipc.c b/drivers/media/platform/sti/delta/delta-ipc.c
index a4603d573c34..186d88f02ecd 100644
--- a/drivers/media/platform/sti/delta/delta-ipc.c
+++ b/drivers/media/platform/sti/delta/delta-ipc.c
@@ -220,10 +220,8 @@ int delta_ipc_open(struct delta_ctx *pctx, const char *name,
err:
pctx->sys_errors++;
- if (ctx->ipc_buf) {
- hw_free(pctx, ctx->ipc_buf);
- ctx->ipc_buf = NULL;
- }
+ hw_free(pctx, ctx->ipc_buf);
+ ctx->ipc_buf = NULL;
return ret;
};
diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c
index 7c496bc1cf38..8a86b2cc22fa 100644
--- a/drivers/media/platform/stm32/stm32-cec.c
+++ b/drivers/media/platform/stm32/stm32-cec.c
@@ -56,6 +56,13 @@
#define ALL_TX_IT (TXEND | TXBR | TXACKE | TXERR | TXUDR | ARBLST)
#define ALL_RX_IT (RXEND | RXBR | RXACKE | RXOVR)
+/*
+ * 400 ms is the time it takes for one 16 byte message to be
+ * transferred and 5 is the maximum number of retries. Add
+ * another 100 ms as a margin.
+ */
+#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100)
+
struct stm32_cec {
struct cec_adapter *adap;
struct device *dev;
@@ -188,7 +195,11 @@ static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
{
struct stm32_cec *cec = adap->priv;
u32 oar = (1 << logical_addr) << 16;
+ u32 val;
+ /* Poll every 100µs the register CEC_CR to wait end of transmission */
+ regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM),
+ 100, CEC_XFER_TIMEOUT_MS * 1000);
regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0);
if (logical_addr == CEC_LOG_ADDR_INVALID)
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index 5fe5b38fa901..b9dad0accd1b 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -97,6 +97,8 @@ enum state {
#define TIMEOUT_MS 1000
+#define OVERRUN_ERROR_THRESHOLD 3
+
struct dcmi_graph_entity {
struct device_node *node;
@@ -164,6 +166,9 @@ struct stm32_dcmi {
int errors_count;
int overrun_count;
int buffers_count;
+
+ /* Ensure DMA operations atomicity */
+ struct mutex dma_lock;
};
static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n)
@@ -314,6 +319,13 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
return ret;
}
+ /*
+ * Avoid call of dmaengine_terminate_all() between
+ * dmaengine_prep_slave_single() and dmaengine_submit()
+ * by locking the whole DMA submission sequence
+ */
+ mutex_lock(&dcmi->dma_lock);
+
/* Prepare a DMA transaction */
desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr,
buf->size,
@@ -322,6 +334,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
if (!desc) {
dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n",
__func__, &buf->paddr, buf->size);
+ mutex_unlock(&dcmi->dma_lock);
return -EINVAL;
}
@@ -333,9 +346,12 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
dcmi->dma_cookie = dmaengine_submit(desc);
if (dma_submit_error(dcmi->dma_cookie)) {
dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__);
+ mutex_unlock(&dcmi->dma_lock);
return -ENXIO;
}
+ mutex_unlock(&dcmi->dma_lock);
+
dma_async_issue_pending(dcmi->dma_chan);
return 0;
@@ -432,11 +448,13 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
spin_lock_irq(&dcmi->irqlock);
- if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) {
- dcmi->errors_count++;
- if (dcmi->misr & IT_OVR)
- dcmi->overrun_count++;
+ if (dcmi->misr & IT_OVR) {
+ dcmi->overrun_count++;
+ if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD)
+ dcmi->errors_count++;
}
+ if (dcmi->misr & IT_ERR)
+ dcmi->errors_count++;
if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG &&
dcmi->misr & IT_FRAME) {
@@ -570,9 +588,9 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
int ret;
ret = pm_runtime_get_sync(dcmi->dev);
- if (ret) {
- dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync\n",
- __func__);
+ if (ret < 0) {
+ dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n",
+ __func__, ret);
goto err_release_buffers;
}
@@ -720,7 +738,9 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
spin_unlock_irq(&dcmi->irqlock);
/* Stop all pending DMA operations */
+ mutex_lock(&dcmi->dma_lock);
dmaengine_terminate_all(dcmi->dma_chan);
+ mutex_unlock(&dcmi->dma_lock);
pm_runtime_put(dcmi->dev);
@@ -811,6 +831,9 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat);
if (!sd_fmt) {
+ if (!dcmi->num_of_sd_formats)
+ return -ENODATA;
+
sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1];
pix->pixelformat = sd_fmt->fourcc;
}
@@ -989,6 +1012,9 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi,
sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat);
if (!sd_fmt) {
+ if (!dcmi->num_of_sd_formats)
+ return -ENODATA;
+
sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1];
pix->pixelformat = sd_fmt->fourcc;
}
@@ -1595,7 +1621,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
/* Parse the graph to extract a list of subdevice DT nodes. */
ret = dcmi_graph_parse(dcmi, dcmi->dev->of_node);
if (ret < 0) {
- dev_err(dcmi->dev, "Graph parsing failed\n");
+ dev_err(dcmi->dev, "Failed to parse graph\n");
return ret;
}
@@ -1604,6 +1630,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
ret = v4l2_async_notifier_add_subdev(&dcmi->notifier,
&dcmi->entity.asd);
if (ret) {
+ dev_err(dcmi->dev, "Failed to add subdev notifier\n");
of_node_put(dcmi->entity.node);
return ret;
}
@@ -1612,7 +1639,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier);
if (ret < 0) {
- dev_err(dcmi->dev, "Notifier registration failed\n");
+ dev_err(dcmi->dev, "Failed to register notifier\n");
v4l2_async_notifier_cleanup(&dcmi->notifier);
return ret;
}
@@ -1645,7 +1672,7 @@ static int dcmi_probe(struct platform_device *pdev)
dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(dcmi->rstc)) {
dev_err(&pdev->dev, "Could not get reset control\n");
- return -ENODEV;
+ return PTR_ERR(dcmi->rstc);
}
/* Get bus characteristics from devicetree */
@@ -1660,7 +1687,7 @@ static int dcmi_probe(struct platform_device *pdev)
of_node_put(np);
if (ret) {
dev_err(&pdev->dev, "Could not parse the endpoint\n");
- return -ENODEV;
+ return ret;
}
if (ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
@@ -1673,8 +1700,9 @@ static int dcmi_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
- dev_err(&pdev->dev, "Could not get irq\n");
- return -ENODEV;
+ if (irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Could not get irq\n");
+ return irq;
}
dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1694,12 +1722,13 @@ static int dcmi_probe(struct platform_device *pdev)
dev_name(&pdev->dev), dcmi);
if (ret) {
dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
- return -ENODEV;
+ return ret;
}
mclk = devm_clk_get(&pdev->dev, "mclk");
if (IS_ERR(mclk)) {
- dev_err(&pdev->dev, "Unable to get mclk\n");
+ if (PTR_ERR(mclk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get mclk\n");
return PTR_ERR(mclk);
}
@@ -1711,6 +1740,7 @@ static int dcmi_probe(struct platform_device *pdev)
spin_lock_init(&dcmi->irqlock);
mutex_init(&dcmi->lock);
+ mutex_init(&dcmi->dma_lock);
init_completion(&dcmi->complete);
INIT_LIST_HEAD(&dcmi->buffers);
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
index 1fd16861f111..f0dfe68486d1 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
@@ -412,7 +412,7 @@ static int vidioc_enum_input(struct file *file, void *fh,
if (inp->index != 0)
return -EINVAL;
- strlcpy(inp->name, "camera", sizeof(inp->name));
+ strscpy(inp->name, "camera", sizeof(inp->name));
inp->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
@@ -644,7 +644,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
}
/* Register video device */
- strlcpy(vdev->name, name, sizeof(vdev->name));
+ strscpy(vdev->name, name, sizeof(vdev->name));
vdev->release = video_device_release_empty;
vdev->fops = &sun6i_video_fops;
vdev->ioctl_ops = &sun6i_video_ioctl_ops;
diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c
index aba488cd0e64..447bdfbe5afe 100644
--- a/drivers/media/platform/tegra-cec/tegra_cec.c
+++ b/drivers/media/platform/tegra-cec/tegra_cec.c
@@ -327,21 +327,15 @@ static const struct cec_adap_ops tegra_cec_ops = {
static int tegra_cec_probe(struct platform_device *pdev)
{
- struct platform_device *hdmi_dev;
- struct device_node *np;
+ struct device *hdmi_dev;
struct tegra_cec *cec;
struct resource *res;
int ret = 0;
- np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0);
+ hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev);
- if (!np) {
- dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n");
- return -ENODEV;
- }
- hdmi_dev = of_find_device_by_node(np);
- if (hdmi_dev == NULL)
- return -EPROBE_DEFER;
+ if (IS_ERR(hdmi_dev))
+ return PTR_ERR(hdmi_dev);
cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL);
@@ -400,7 +394,7 @@ static int tegra_cec_probe(struct platform_device *pdev)
goto clk_error;
}
- cec->notifier = cec_notifier_get(&hdmi_dev->dev);
+ cec->notifier = cec_notifier_get(hdmi_dev);
if (!cec->notifier) {
ret = -ENOMEM;
goto clk_error;
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
index fc3c212b96e1..8d075683e448 100644
--- a/drivers/media/platform/ti-vpe/cal.c
+++ b/drivers/media/platform/ti-vpe/cal.c
@@ -1643,8 +1643,7 @@ of_get_next_endpoint(const struct device_node *parent,
static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
{
struct platform_device *pdev = ctx->dev->pdev;
- struct device_node *ep_node, *port, *remote_ep,
- *sensor_node, *parent;
+ struct device_node *ep_node, *port, *sensor_node, *parent;
struct v4l2_fwnode_endpoint *endpoint;
struct v4l2_async_subdev *asd;
u32 regval = 0;
@@ -1657,7 +1656,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
ep_node = NULL;
port = NULL;
- remote_ep = NULL;
sensor_node = NULL;
ret = -EINVAL;
@@ -1703,12 +1701,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
asd->match.fwnode = of_fwnode_handle(sensor_node);
- remote_ep = of_graph_get_remote_endpoint(ep_node);
- if (!remote_ep) {
- ctx_dbg(3, ctx, "can't get remote-endpoint\n");
- goto cleanup_exit;
- }
- v4l2_fwnode_endpoint_parse(of_fwnode_handle(remote_ep), endpoint);
+ v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint);
if (endpoint->bus_type != V4L2_MBUS_CSI2_DPHY) {
ctx_err(ctx, "Port:%d sub-device %pOFn is not a CSI2 device\n",
@@ -1759,7 +1752,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
sensor_node = NULL;
cleanup_exit:
- of_node_put(remote_ep);
of_node_put(sensor_node);
of_node_put(ep_node);
of_node_put(port);
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index 207e7e76c048..1e40eafec284 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -1491,8 +1491,8 @@ handled:
static int vpe_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1);
- strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1);
+ strscpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
VPE_MODULE_NAME);
cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
@@ -1519,7 +1519,7 @@ static int __enum_fmt(struct v4l2_fmtdesc *f, u32 type)
if (!fmt)
return -EINVAL;
- strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
diff --git a/drivers/media/platform/vicodec/codec-fwht.c b/drivers/media/platform/vicodec/codec-fwht.c
index d1d6085da9f1..31faf319e508 100644
--- a/drivers/media/platform/vicodec/codec-fwht.c
+++ b/drivers/media/platform/vicodec/codec-fwht.c
@@ -46,8 +46,12 @@ static const uint8_t zigzag[64] = {
63,
};
-
-static int rlc(const s16 *in, __be16 *output, int blocktype)
+/*
+ * noinline_for_stack to work around
+ * https://bugs.llvm.org/show_bug.cgi?id=38809
+ */
+static int noinline_for_stack
+rlc(const s16 *in, __be16 *output, int blocktype)
{
s16 block[8 * 8];
s16 *wp = block;
@@ -106,8 +110,8 @@ static int rlc(const s16 *in, __be16 *output, int blocktype)
* This function will worst-case increase rlc_in by 65*2 bytes:
* one s16 value for the header and 8 * 8 coefficients of type s16.
*/
-static u16 derlc(const __be16 **rlc_in, s16 *dwht_out,
- const __be16 *end_of_input)
+static noinline_for_stack u16
+derlc(const __be16 **rlc_in, s16 *dwht_out, const __be16 *end_of_input)
{
/* header */
const __be16 *input = *rlc_in;
@@ -240,8 +244,9 @@ static void dequantize_inter(s16 *coeff)
*coeff <<= *quant;
}
-static void fwht(const u8 *block, s16 *output_block, unsigned int stride,
- unsigned int input_step, bool intra)
+static void noinline_for_stack fwht(const u8 *block, s16 *output_block,
+ unsigned int stride,
+ unsigned int input_step, bool intra)
{
/* we'll need more than 8 bits for the transformed coefficients */
s32 workspace1[8], workspace2[8];
@@ -373,7 +378,8 @@ static void fwht(const u8 *block, s16 *output_block, unsigned int stride,
* Furthermore values can be negative... This is just a version that
* works with 16 signed data
*/
-static void fwht16(const s16 *block, s16 *output_block, int stride, int intra)
+static void noinline_for_stack
+fwht16(const s16 *block, s16 *output_block, int stride, int intra)
{
/* we'll need more than 8 bits for the transformed coefficients */
s32 workspace1[8], workspace2[8];
@@ -456,7 +462,8 @@ static void fwht16(const s16 *block, s16 *output_block, int stride, int intra)
}
}
-static void ifwht(const s16 *block, s16 *output_block, int intra)
+static noinline_for_stack void
+ifwht(const s16 *block, s16 *output_block, int intra)
{
/*
* we'll need more than 8 bits for the transformed coefficients
@@ -604,9 +611,9 @@ static int var_inter(const s16 *old, const s16 *new)
return ret;
}
-static int decide_blocktype(const u8 *cur, const u8 *reference,
- s16 *deltablock, unsigned int stride,
- unsigned int input_step)
+static noinline_for_stack int
+decide_blocktype(const u8 *cur, const u8 *reference, s16 *deltablock,
+ unsigned int stride, unsigned int input_step)
{
s16 tmp[64];
s16 old[64];
@@ -632,12 +639,13 @@ static int decide_blocktype(const u8 *cur, const u8 *reference,
return vari <= vard ? IBLOCK : PBLOCK;
}
-static void fill_decoder_block(u8 *dst, const s16 *input, int stride)
+static void fill_decoder_block(u8 *dst, const s16 *input, int stride,
+ unsigned int dst_step)
{
int i, j;
for (i = 0; i < 8; i++) {
- for (j = 0; j < 8; j++, input++, dst++) {
+ for (j = 0; j < 8; j++, input++, dst += dst_step) {
if (*input < 0)
*dst = 0;
else if (*input > 255)
@@ -645,17 +653,19 @@ static void fill_decoder_block(u8 *dst, const s16 *input, int stride)
else
*dst = *input;
}
- dst += stride - 8;
+ dst += stride - (8 * dst_step);
}
}
-static void add_deltas(s16 *deltas, const u8 *ref, int stride)
+static void add_deltas(s16 *deltas, const u8 *ref, int stride,
+ unsigned int ref_step)
{
int k, l;
for (k = 0; k < 8; k++) {
for (l = 0; l < 8; l++) {
- *deltas += *ref++;
+ *deltas += *ref;
+ ref += ref_step;
/*
* Due to quantizing, it might possible that the
* decoded coefficients are slightly out of range
@@ -666,7 +676,7 @@ static void add_deltas(s16 *deltas, const u8 *ref, int stride)
*deltas = 255;
deltas++;
}
- ref += stride - 8;
+ ref += stride - (8 * ref_step);
}
}
@@ -711,8 +721,8 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max,
ifwht(cf->de_coeffs, cf->de_fwht, blocktype);
if (blocktype == PBLOCK)
- add_deltas(cf->de_fwht, refp, 8);
- fill_decoder_block(refp, cf->de_fwht, 8);
+ add_deltas(cf->de_fwht, refp, 8, 1);
+ fill_decoder_block(refp, cf->de_fwht, 8, 1);
}
input += 8 * input_step;
@@ -821,23 +831,31 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm,
return encoding;
}
-static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref,
- u32 height, u32 width, u32 coded_width,
+static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco,
+ u32 height, u32 width, const u8 *ref, u32 ref_stride,
+ unsigned int ref_step, u8 *dst,
+ unsigned int dst_stride, unsigned int dst_step,
bool uncompressed, const __be16 *end_of_rlco_buf)
{
unsigned int copies = 0;
s16 copy[8 * 8];
u16 stat;
unsigned int i, j;
+ bool is_intra = !ref;
width = round_up(width, 8);
height = round_up(height, 8);
if (uncompressed) {
+ int i;
+
if (end_of_rlco_buf + 1 < *rlco + width * height / 2)
return false;
- memcpy(ref, *rlco, width * height);
- *rlco += width * height / 2;
+ for (i = 0; i < height; i++) {
+ memcpy(dst, *rlco, width);
+ dst += dst_stride;
+ *rlco += width / 2;
+ }
return true;
}
@@ -849,15 +867,17 @@ static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref,
*/
for (j = 0; j < height / 8; j++) {
for (i = 0; i < width / 8; i++) {
- u8 *refp = ref + j * 8 * coded_width + i * 8;
+ const u8 *refp = ref + j * 8 * ref_stride +
+ i * 8 * ref_step;
+ u8 *dstp = dst + j * 8 * dst_stride + i * 8 * dst_step;
if (copies) {
memcpy(cf->de_fwht, copy, sizeof(copy));
- if (stat & PFRAME_BIT)
+ if ((stat & PFRAME_BIT) && !is_intra)
add_deltas(cf->de_fwht, refp,
- coded_width);
- fill_decoder_block(refp, cf->de_fwht,
- coded_width);
+ ref_stride, ref_step);
+ fill_decoder_block(dstp, cf->de_fwht,
+ dst_stride, dst_step);
copies--;
continue;
}
@@ -865,35 +885,41 @@ static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref,
stat = derlc(rlco, cf->coeffs, end_of_rlco_buf);
if (stat & OVERFLOW_BIT)
return false;
- if (stat & PFRAME_BIT)
+ if ((stat & PFRAME_BIT) && !is_intra)
dequantize_inter(cf->coeffs);
else
dequantize_intra(cf->coeffs);
ifwht(cf->coeffs, cf->de_fwht,
- (stat & PFRAME_BIT) ? 0 : 1);
+ ((stat & PFRAME_BIT) && !is_intra) ? 0 : 1);
copies = (stat & DUPS_MASK) >> 1;
if (copies)
memcpy(copy, cf->de_fwht, sizeof(copy));
- if (stat & PFRAME_BIT)
- add_deltas(cf->de_fwht, refp, coded_width);
- fill_decoder_block(refp, cf->de_fwht, coded_width);
+ if ((stat & PFRAME_BIT) && !is_intra)
+ add_deltas(cf->de_fwht, refp,
+ ref_stride, ref_step);
+ fill_decoder_block(dstp, cf->de_fwht, dst_stride,
+ dst_step);
}
}
return true;
}
-bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
- u32 hdr_flags, unsigned int components_num,
- unsigned int width, unsigned int height,
- unsigned int coded_width)
+bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags,
+ unsigned int components_num, unsigned int width,
+ unsigned int height, const struct fwht_raw_frame *ref,
+ unsigned int ref_stride, unsigned int ref_chroma_stride,
+ struct fwht_raw_frame *dst, unsigned int dst_stride,
+ unsigned int dst_chroma_stride)
{
const __be16 *rlco = cf->rlc_data;
const __be16 *end_of_rlco_buf = cf->rlc_data +
(cf->size / sizeof(*rlco)) - 1;
- if (!decode_plane(cf, &rlco, ref->luma, height, width, coded_width,
+ if (!decode_plane(cf, &rlco, height, width, ref->luma, ref_stride,
+ ref->luma_alpha_step, dst->luma, dst_stride,
+ dst->luma_alpha_step,
hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED,
end_of_rlco_buf))
return false;
@@ -901,27 +927,30 @@ bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
if (components_num >= 3) {
u32 h = height;
u32 w = width;
- u32 c = coded_width;
if (!(hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT))
h /= 2;
- if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) {
+ if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH))
w /= 2;
- c /= 2;
- }
- if (!decode_plane(cf, &rlco, ref->cb, h, w, c,
+
+ if (!decode_plane(cf, &rlco, h, w, ref->cb, ref_chroma_stride,
+ ref->chroma_step, dst->cb, dst_chroma_stride,
+ dst->chroma_step,
hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED,
end_of_rlco_buf))
return false;
- if (!decode_plane(cf, &rlco, ref->cr, h, w, c,
+ if (!decode_plane(cf, &rlco, h, w, ref->cr, ref_chroma_stride,
+ ref->chroma_step, dst->cr, dst_chroma_stride,
+ dst->chroma_step,
hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED,
end_of_rlco_buf))
return false;
}
if (components_num == 4)
- if (!decode_plane(cf, &rlco, ref->alpha, height, width,
- coded_width,
+ if (!decode_plane(cf, &rlco, height, width, ref->alpha, ref_stride,
+ ref->luma_alpha_step, dst->alpha, dst_stride,
+ dst->luma_alpha_step,
hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED,
end_of_rlco_buf))
return false;
diff --git a/drivers/media/platform/vicodec/codec-fwht.h b/drivers/media/platform/vicodec/codec-fwht.h
index c410512d47c5..b6fec2b1cbca 100644
--- a/drivers/media/platform/vicodec/codec-fwht.h
+++ b/drivers/media/platform/vicodec/codec-fwht.h
@@ -124,6 +124,7 @@ struct fwht_raw_frame {
unsigned int luma_alpha_step;
unsigned int chroma_step;
unsigned int components_num;
+ u8 *buf;
u8 *luma, *cb, *cr, *alpha;
};
@@ -140,9 +141,10 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm,
bool is_intra, bool next_is_intra,
unsigned int width, unsigned int height,
unsigned int stride, unsigned int chroma_stride);
-bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
- u32 hdr_flags, unsigned int components_num,
- unsigned int width, unsigned int height,
- unsigned int coded_width);
-
+bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags,
+ unsigned int components_num, unsigned int width,
+ unsigned int height, const struct fwht_raw_frame *ref,
+ unsigned int ref_stride, unsigned int ref_chroma_stride,
+ struct fwht_raw_frame *dst, unsigned int dst_stride,
+ unsigned int dst_chroma_stride);
#endif
diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.c b/drivers/media/platform/vicodec/codec-v4l2-fwht.c
index 6573a471c5ca..01e7f09efc4e 100644
--- a/drivers/media/platform/vicodec/codec-v4l2-fwht.c
+++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.c
@@ -37,7 +37,19 @@ static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {
{ V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB},
};
-const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div,
+bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info,
+ u32 width_div, u32 height_div, u32 components_num,
+ u32 pixenc)
+{
+ if (info->width_div == width_div &&
+ info->height_div == height_div &&
+ (!pixenc || info->pixenc == pixenc) &&
+ info->components_num == components_num)
+ return true;
+ return false;
+}
+
+const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div,
u32 height_div,
u32 components_num,
u32 pixenc,
@@ -46,10 +58,10 @@ const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div,
unsigned int i;
for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) {
- if (v4l2_fwht_pixfmts[i].width_div == width_div &&
- v4l2_fwht_pixfmts[i].height_div == height_div &&
- (!pixenc || v4l2_fwht_pixfmts[i].pixenc == pixenc) &&
- v4l2_fwht_pixfmts[i].components_num == components_num) {
+ bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i],
+ width_div, height_div,
+ components_num, pixenc);
+ if (is_valid) {
if (start_idx == 0)
return v4l2_fwht_pixfmts + i;
start_idx--;
@@ -75,117 +87,141 @@ const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx)
return v4l2_fwht_pixfmts + idx;
}
-int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
+static int prepare_raw_frame(struct fwht_raw_frame *rf,
+ const struct v4l2_fwht_pixfmt_info *info, u8 *buf,
+ unsigned int size)
{
- unsigned int size = state->stride * state->coded_height;
- unsigned int chroma_stride = state->stride;
- const struct v4l2_fwht_pixfmt_info *info = state->info;
- struct fwht_cframe_hdr *p_hdr;
- struct fwht_cframe cf;
- struct fwht_raw_frame rf;
- u32 encoding;
- u32 flags = 0;
-
- if (!info)
- return -EINVAL;
-
- rf.luma = p_in;
- rf.width_div = info->width_div;
- rf.height_div = info->height_div;
- rf.luma_alpha_step = info->luma_alpha_step;
- rf.chroma_step = info->chroma_step;
- rf.alpha = NULL;
- rf.components_num = info->components_num;
+ rf->luma = buf;
+ rf->width_div = info->width_div;
+ rf->height_div = info->height_div;
+ rf->luma_alpha_step = info->luma_alpha_step;
+ rf->chroma_step = info->chroma_step;
+ rf->alpha = NULL;
+ rf->components_num = info->components_num;
+ /*
+ * The buffer is NULL if it is the reference
+ * frame of an I-frame in the stateless decoder
+ */
+ if (!buf) {
+ rf->luma = NULL;
+ rf->cb = NULL;
+ rf->cr = NULL;
+ rf->alpha = NULL;
+ return 0;
+ }
switch (info->id) {
case V4L2_PIX_FMT_GREY:
- rf.cb = NULL;
- rf.cr = NULL;
+ rf->cb = NULL;
+ rf->cr = NULL;
break;
case V4L2_PIX_FMT_YUV420:
- rf.cb = rf.luma + size;
- rf.cr = rf.cb + size / 4;
- chroma_stride /= 2;
+ rf->cb = rf->luma + size;
+ rf->cr = rf->cb + size / 4;
break;
case V4L2_PIX_FMT_YVU420:
- rf.cr = rf.luma + size;
- rf.cb = rf.cr + size / 4;
- chroma_stride /= 2;
+ rf->cr = rf->luma + size;
+ rf->cb = rf->cr + size / 4;
break;
case V4L2_PIX_FMT_YUV422P:
- rf.cb = rf.luma + size;
- rf.cr = rf.cb + size / 2;
- chroma_stride /= 2;
+ rf->cb = rf->luma + size;
+ rf->cr = rf->cb + size / 2;
break;
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV24:
- rf.cb = rf.luma + size;
- rf.cr = rf.cb + 1;
+ rf->cb = rf->luma + size;
+ rf->cr = rf->cb + 1;
break;
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_NV42:
- rf.cr = rf.luma + size;
- rf.cb = rf.cr + 1;
+ rf->cr = rf->luma + size;
+ rf->cb = rf->cr + 1;
break;
case V4L2_PIX_FMT_YUYV:
- rf.cb = rf.luma + 1;
- rf.cr = rf.cb + 2;
+ rf->cb = rf->luma + 1;
+ rf->cr = rf->cb + 2;
break;
case V4L2_PIX_FMT_YVYU:
- rf.cr = rf.luma + 1;
- rf.cb = rf.cr + 2;
+ rf->cr = rf->luma + 1;
+ rf->cb = rf->cr + 2;
break;
case V4L2_PIX_FMT_UYVY:
- rf.cb = rf.luma;
- rf.cr = rf.cb + 2;
- rf.luma++;
+ rf->cb = rf->luma;
+ rf->cr = rf->cb + 2;
+ rf->luma++;
break;
case V4L2_PIX_FMT_VYUY:
- rf.cr = rf.luma;
- rf.cb = rf.cr + 2;
- rf.luma++;
+ rf->cr = rf->luma;
+ rf->cb = rf->cr + 2;
+ rf->luma++;
break;
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_HSV24:
- rf.cr = rf.luma;
- rf.cb = rf.cr + 2;
- rf.luma++;
+ rf->cr = rf->luma;
+ rf->cb = rf->cr + 2;
+ rf->luma++;
break;
case V4L2_PIX_FMT_BGR24:
- rf.cb = rf.luma;
- rf.cr = rf.cb + 2;
- rf.luma++;
+ rf->cb = rf->luma;
+ rf->cr = rf->cb + 2;
+ rf->luma++;
break;
case V4L2_PIX_FMT_RGB32:
case V4L2_PIX_FMT_XRGB32:
case V4L2_PIX_FMT_HSV32:
- rf.cr = rf.luma + 1;
- rf.cb = rf.cr + 2;
- rf.luma += 2;
+ rf->cr = rf->luma + 1;
+ rf->cb = rf->cr + 2;
+ rf->luma += 2;
break;
case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_XBGR32:
- rf.cb = rf.luma;
- rf.cr = rf.cb + 2;
- rf.luma++;
+ rf->cb = rf->luma;
+ rf->cr = rf->cb + 2;
+ rf->luma++;
break;
case V4L2_PIX_FMT_ARGB32:
- rf.alpha = rf.luma;
- rf.cr = rf.luma + 1;
- rf.cb = rf.cr + 2;
- rf.luma += 2;
+ rf->alpha = rf->luma;
+ rf->cr = rf->luma + 1;
+ rf->cb = rf->cr + 2;
+ rf->luma += 2;
break;
case V4L2_PIX_FMT_ABGR32:
- rf.cb = rf.luma;
- rf.cr = rf.cb + 2;
- rf.luma++;
- rf.alpha = rf.cr + 1;
+ rf->cb = rf->luma;
+ rf->cr = rf->cb + 2;
+ rf->luma++;
+ rf->alpha = rf->cr + 1;
break;
default:
return -EINVAL;
}
+ return 0;
+}
+
+int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
+{
+ unsigned int size = state->stride * state->coded_height;
+ unsigned int chroma_stride = state->stride;
+ const struct v4l2_fwht_pixfmt_info *info = state->info;
+ struct fwht_cframe_hdr *p_hdr;
+ struct fwht_cframe cf;
+ struct fwht_raw_frame rf;
+ u32 encoding;
+ u32 flags = 0;
+
+ if (!info)
+ return -EINVAL;
+
+ if (prepare_raw_frame(&rf, info, p_in, size))
+ return -EINVAL;
+
+ if (info->planes_num == 3)
+ chroma_stride /= 2;
+
+ if (info->id == V4L2_PIX_FMT_NV24 ||
+ info->id == V4L2_PIX_FMT_NV42)
+ chroma_stride *= 2;
cf.i_frame_qp = state->i_frame_qp;
cf.p_frame_qp = state->p_frame_qp;
@@ -235,14 +271,17 @@ int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
{
- unsigned int i, j, k;
u32 flags;
struct fwht_cframe cf;
- u8 *p, *ref_p;
unsigned int components_num = 3;
unsigned int version;
const struct v4l2_fwht_pixfmt_info *info;
unsigned int hdr_width_div, hdr_height_div;
+ struct fwht_raw_frame dst_rf;
+ unsigned int dst_chroma_stride = state->stride;
+ unsigned int ref_chroma_stride = state->ref_stride;
+ unsigned int dst_size = state->stride * state->coded_height;
+ unsigned int ref_size;
if (!state->info)
return -EINVAL;
@@ -290,241 +329,29 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
hdr_height_div != info->height_div)
return -EINVAL;
- if (!fwht_decode_frame(&cf, &state->ref_frame, flags, components_num,
- state->visible_width, state->visible_height,
- state->coded_width))
+ if (prepare_raw_frame(&dst_rf, info, p_out, dst_size))
return -EINVAL;
+ if (info->planes_num == 3) {
+ dst_chroma_stride /= 2;
+ ref_chroma_stride /= 2;
+ }
+ if (info->id == V4L2_PIX_FMT_NV24 ||
+ info->id == V4L2_PIX_FMT_NV42) {
+ dst_chroma_stride *= 2;
+ ref_chroma_stride *= 2;
+ }
- /*
- * TODO - handle the case where the compressed stream encodes a
- * different format than the requested decoded format.
- */
- switch (state->info->id) {
- case V4L2_PIX_FMT_GREY:
- ref_p = state->ref_frame.luma;
- for (i = 0; i < state->coded_height; i++) {
- memcpy(p_out, ref_p, state->visible_width);
- p_out += state->stride;
- ref_p += state->coded_width;
- }
- break;
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YUV422P:
- ref_p = state->ref_frame.luma;
- for (i = 0; i < state->coded_height; i++) {
- memcpy(p_out, ref_p, state->visible_width);
- p_out += state->stride;
- ref_p += state->coded_width;
- }
- ref_p = state->ref_frame.cb;
- for (i = 0; i < state->coded_height / 2; i++) {
- memcpy(p_out, ref_p, state->visible_width / 2);
- p_out += state->stride / 2;
- ref_p += state->coded_width / 2;
- }
- ref_p = state->ref_frame.cr;
- for (i = 0; i < state->coded_height / 2; i++) {
- memcpy(p_out, ref_p, state->visible_width / 2);
- p_out += state->stride / 2;
- ref_p += state->coded_width / 2;
- }
- break;
- case V4L2_PIX_FMT_YVU420:
- ref_p = state->ref_frame.luma;
- for (i = 0; i < state->coded_height; i++) {
- memcpy(p_out, ref_p, state->visible_width);
- p_out += state->stride;
- ref_p += state->coded_width;
- }
-
- ref_p = state->ref_frame.cr;
- for (i = 0; i < state->coded_height / 2; i++) {
- memcpy(p_out, ref_p, state->visible_width / 2);
- p_out += state->stride / 2;
- ref_p += state->coded_width / 2;
- }
- ref_p = state->ref_frame.cb;
- for (i = 0; i < state->coded_height / 2; i++) {
- memcpy(p_out, ref_p, state->visible_width / 2);
- p_out += state->stride / 2;
- ref_p += state->coded_width / 2;
- }
- break;
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV24:
- ref_p = state->ref_frame.luma;
- for (i = 0; i < state->coded_height; i++) {
- memcpy(p_out, ref_p, state->visible_width);
- p_out += state->stride;
- ref_p += state->coded_width;
- }
+ ref_size = state->ref_stride * state->coded_height;
- k = 0;
- for (i = 0; i < state->coded_height / 2; i++) {
- for (j = 0, p = p_out; j < state->coded_width / 2; j++) {
- *p++ = state->ref_frame.cb[k];
- *p++ = state->ref_frame.cr[k];
- k++;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_NV21:
- case V4L2_PIX_FMT_NV61:
- case V4L2_PIX_FMT_NV42:
- ref_p = state->ref_frame.luma;
- for (i = 0; i < state->coded_height; i++) {
- memcpy(p_out, ref_p, state->visible_width);
- p_out += state->stride;
- ref_p += state->coded_width;
- }
+ if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf,
+ ref_size))
+ return -EINVAL;
- k = 0;
- for (i = 0; i < state->coded_height / 2; i++) {
- for (j = 0, p = p_out; j < state->coded_width / 2; j++) {
- *p++ = state->ref_frame.cr[k];
- *p++ = state->ref_frame.cb[k];
- k++;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_YUYV:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width / 2; j++) {
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cb[k / 2];
- *p++ = state->ref_frame.luma[k + 1];
- *p++ = state->ref_frame.cr[k / 2];
- k += 2;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_YVYU:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width / 2; j++) {
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cr[k / 2];
- *p++ = state->ref_frame.luma[k + 1];
- *p++ = state->ref_frame.cb[k / 2];
- k += 2;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_UYVY:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width / 2; j++) {
- *p++ = state->ref_frame.cb[k / 2];
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cr[k / 2];
- *p++ = state->ref_frame.luma[k + 1];
- k += 2;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_VYUY:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width / 2; j++) {
- *p++ = state->ref_frame.cr[k / 2];
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cb[k / 2];
- *p++ = state->ref_frame.luma[k + 1];
- k += 2;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_RGB24:
- case V4L2_PIX_FMT_HSV24:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width; j++) {
- *p++ = state->ref_frame.cr[k];
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cb[k];
- k++;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_BGR24:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width; j++) {
- *p++ = state->ref_frame.cb[k];
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cr[k];
- k++;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_RGB32:
- case V4L2_PIX_FMT_XRGB32:
- case V4L2_PIX_FMT_HSV32:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width; j++) {
- *p++ = 0;
- *p++ = state->ref_frame.cr[k];
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cb[k];
- k++;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_BGR32:
- case V4L2_PIX_FMT_XBGR32:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width; j++) {
- *p++ = state->ref_frame.cb[k];
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cr[k];
- *p++ = 0;
- k++;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_ARGB32:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width; j++) {
- *p++ = state->ref_frame.alpha[k];
- *p++ = state->ref_frame.cr[k];
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cb[k];
- k++;
- }
- p_out += state->stride;
- }
- break;
- case V4L2_PIX_FMT_ABGR32:
- k = 0;
- for (i = 0; i < state->coded_height; i++) {
- for (j = 0, p = p_out; j < state->coded_width; j++) {
- *p++ = state->ref_frame.cb[k];
- *p++ = state->ref_frame.luma[k];
- *p++ = state->ref_frame.cr[k];
- *p++ = state->ref_frame.alpha[k];
- k++;
- }
- p_out += state->stride;
- }
- break;
- default:
+ if (!fwht_decode_frame(&cf, flags, components_num,
+ state->visible_width, state->visible_height,
+ &state->ref_frame, state->ref_stride, ref_chroma_stride,
+ &dst_rf, state->stride, dst_chroma_stride))
return -EINVAL;
- }
return 0;
}
diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.h b/drivers/media/platform/vicodec/codec-v4l2-fwht.h
index aa6fa90a48be..1a0d2a9f931a 100644
--- a/drivers/media/platform/vicodec/codec-v4l2-fwht.h
+++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.h
@@ -30,6 +30,7 @@ struct v4l2_fwht_state {
unsigned int coded_width;
unsigned int coded_height;
unsigned int stride;
+ unsigned int ref_stride;
unsigned int gop_size;
unsigned int gop_cnt;
u16 i_frame_qp;
@@ -43,11 +44,15 @@ struct v4l2_fwht_state {
struct fwht_raw_frame ref_frame;
struct fwht_cframe_hdr header;
u8 *compressed_frame;
+ u64 ref_frame_ts;
};
const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat);
const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx);
-const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div,
+bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info,
+ u32 width_div, u32 height_div, u32 components_num,
+ u32 pixenc);
+const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div,
u32 height_div,
u32 components_num,
u32 pixenc,
diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c
index d7636fe9e174..bd01a9206aa6 100644
--- a/drivers/media/platform/vicodec/vicodec-core.c
+++ b/drivers/media/platform/vicodec/vicodec-core.c
@@ -64,6 +64,10 @@ static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = {
V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1
};
+static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = {
+ V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1
+};
+
static void vicodec_dev_release(struct device *dev)
{
}
@@ -89,27 +93,29 @@ enum {
V4L2_M2M_DST = 1,
};
+struct vicodec_dev_instance {
+ struct video_device vfd;
+ struct mutex mutex;
+ spinlock_t lock;
+ struct v4l2_m2m_dev *m2m_dev;
+};
+
struct vicodec_dev {
struct v4l2_device v4l2_dev;
- struct video_device enc_vfd;
- struct video_device dec_vfd;
+ struct vicodec_dev_instance stateful_enc;
+ struct vicodec_dev_instance stateful_dec;
+ struct vicodec_dev_instance stateless_dec;
#ifdef CONFIG_MEDIA_CONTROLLER
struct media_device mdev;
#endif
- struct mutex enc_mutex;
- struct mutex dec_mutex;
- spinlock_t enc_lock;
- spinlock_t dec_lock;
-
- struct v4l2_m2m_dev *enc_dev;
- struct v4l2_m2m_dev *dec_dev;
};
struct vicodec_ctx {
struct v4l2_fh fh;
struct vicodec_dev *dev;
bool is_enc;
+ bool is_stateless;
spinlock_t *lock;
struct v4l2_ctrl_handler hdl;
@@ -148,27 +154,149 @@ static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx,
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
return &ctx->q_data[V4L2_M2M_DST];
default:
- WARN_ON(1);
break;
}
return NULL;
}
+static void copy_cap_to_ref(const u8 *cap, const struct v4l2_fwht_pixfmt_info *info,
+ struct v4l2_fwht_state *state)
+{
+ int plane_idx;
+ u8 *p_ref = state->ref_frame.buf;
+ unsigned int cap_stride = state->stride;
+ unsigned int ref_stride = state->ref_stride;
+
+ for (plane_idx = 0; plane_idx < info->planes_num; plane_idx++) {
+ int i;
+ unsigned int h_div = (plane_idx == 1 || plane_idx == 2) ?
+ info->height_div : 1;
+ const u8 *row_cap = cap;
+ u8 *row_ref = p_ref;
+
+ if (info->planes_num == 3 && plane_idx == 1) {
+ cap_stride /= 2;
+ ref_stride /= 2;
+ }
+
+ if (plane_idx == 1 &&
+ (info->id == V4L2_PIX_FMT_NV24 ||
+ info->id == V4L2_PIX_FMT_NV42)) {
+ cap_stride *= 2;
+ ref_stride *= 2;
+ }
+
+ for (i = 0; i < state->visible_height / h_div; i++) {
+ memcpy(row_ref, row_cap, ref_stride);
+ row_ref += ref_stride;
+ row_cap += cap_stride;
+ }
+ cap += cap_stride * (state->coded_height / h_div);
+ p_ref += ref_stride * (state->coded_height / h_div);
+ }
+}
+
+static bool validate_by_version(unsigned int flags, unsigned int version)
+{
+ if (!version || version > FWHT_VERSION)
+ return false;
+
+ if (version >= 2) {
+ unsigned int components_num = 1 +
+ ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
+ FWHT_FL_COMPONENTS_NUM_OFFSET);
+ unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK;
+
+ if (components_num == 0 || components_num > 4 || !pixenc)
+ return false;
+ }
+ return true;
+}
+
+static bool validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params *params,
+ const struct v4l2_fwht_pixfmt_info *cur_info)
+{
+ unsigned int width_div =
+ (params->flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
+ unsigned int height_div =
+ (params->flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
+ unsigned int components_num = 3;
+ unsigned int pixenc = 0;
+
+ if (params->version < 3)
+ return false;
+
+ components_num = 1 + ((params->flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
+ FWHT_FL_COMPONENTS_NUM_OFFSET);
+ pixenc = (params->flags & FWHT_FL_PIXENC_MSK);
+ if (v4l2_fwht_validate_fmt(cur_info, width_div, height_div,
+ components_num, pixenc))
+ return true;
+ return false;
+}
+
+
+static void update_state_from_header(struct vicodec_ctx *ctx)
+{
+ const struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
+
+ ctx->state.visible_width = ntohl(p_hdr->width);
+ ctx->state.visible_height = ntohl(p_hdr->height);
+ ctx->state.colorspace = ntohl(p_hdr->colorspace);
+ ctx->state.xfer_func = ntohl(p_hdr->xfer_func);
+ ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc);
+ ctx->state.quantization = ntohl(p_hdr->quantization);
+}
+
static int device_process(struct vicodec_ctx *ctx,
struct vb2_v4l2_buffer *src_vb,
struct vb2_v4l2_buffer *dst_vb)
{
struct vicodec_dev *dev = ctx->dev;
- struct vicodec_q_data *q_dst;
struct v4l2_fwht_state *state = &ctx->state;
u8 *p_src, *p_dst;
- int ret;
+ int ret = 0;
- q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- if (ctx->is_enc)
+ if (ctx->is_enc || ctx->is_stateless)
p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0);
else
p_src = state->compressed_frame;
+
+ if (ctx->is_stateless) {
+ struct media_request *src_req = src_vb->vb2_buf.req_obj.req;
+
+ ret = v4l2_ctrl_request_setup(src_req, &ctx->hdl);
+ if (ret)
+ return ret;
+ update_state_from_header(ctx);
+
+ ctx->state.header.size =
+ htonl(vb2_get_plane_payload(&src_vb->vb2_buf, 0));
+ /*
+ * set the reference buffer from the reference timestamp
+ * only if this is a P-frame
+ */
+ if (!(ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME)) {
+ struct vb2_buffer *ref_vb2_buf;
+ int ref_buf_idx;
+ struct vb2_queue *vq_cap =
+ v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+ ref_buf_idx = vb2_find_timestamp(vq_cap,
+ ctx->state.ref_frame_ts, 0);
+ if (ref_buf_idx < 0)
+ return -EINVAL;
+
+ ref_vb2_buf = vq_cap->bufs[ref_buf_idx];
+ if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR)
+ ret = -EINVAL;
+ ctx->state.ref_frame.buf =
+ vb2_plane_vaddr(ref_vb2_buf, 0);
+ } else {
+ ctx->state.ref_frame.buf = NULL;
+ }
+ }
p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
if (!p_src || !p_dst) {
v4l2_err(&dev->v4l2_dev,
@@ -178,30 +306,31 @@ static int device_process(struct vicodec_ctx *ctx,
if (ctx->is_enc) {
struct vicodec_q_data *q_src;
+ int comp_sz_or_errcode;
q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
state->info = q_src->info;
- ret = v4l2_fwht_encode(state, p_src, p_dst);
- if (ret < 0)
- return ret;
- vb2_set_plane_payload(&dst_vb->vb2_buf, 0, ret);
+ comp_sz_or_errcode = v4l2_fwht_encode(state, p_src, p_dst);
+ if (comp_sz_or_errcode < 0)
+ return comp_sz_or_errcode;
+ vb2_set_plane_payload(&dst_vb->vb2_buf, 0, comp_sz_or_errcode);
} else {
+ struct vicodec_q_data *q_dst;
unsigned int comp_frame_size = ntohl(ctx->state.header.size);
+ q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
if (comp_frame_size > ctx->comp_max_size)
return -EINVAL;
state->info = q_dst->info;
ret = v4l2_fwht_decode(state, p_src, p_dst);
if (ret < 0)
return ret;
+ if (!ctx->is_stateless)
+ copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state);
+
vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage);
}
-
- dst_vb->sequence = q_dst->sequence++;
- dst_vb->flags &= ~V4L2_BUF_FLAG_LAST;
- v4l2_m2m_buf_copy_metadata(src_vb, dst_vb, !ctx->is_enc);
-
- return 0;
+ return ret;
}
/*
@@ -274,16 +403,26 @@ static void device_run(void *priv)
struct vicodec_ctx *ctx = priv;
struct vicodec_dev *dev = ctx->dev;
struct vb2_v4l2_buffer *src_buf, *dst_buf;
- struct vicodec_q_data *q_src;
+ struct vicodec_q_data *q_src, *q_dst;
u32 state;
+ struct media_request *src_req;
+
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ src_req = src_buf->vb2_buf.req_obj.req;
+
q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
state = VB2_BUF_STATE_DONE;
if (device_process(ctx, src_buf, dst_buf))
state = VB2_BUF_STATE_ERROR;
+ else
+ dst_buf->sequence = q_dst->sequence++;
+ dst_buf->flags &= ~V4L2_BUF_FLAG_LAST;
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc);
+
ctx->last_dst_buf = dst_buf;
spin_lock(ctx->lock);
@@ -291,7 +430,7 @@ static void device_run(void *priv)
dst_buf->flags |= V4L2_BUF_FLAG_LAST;
v4l2_event_queue_fh(&ctx->fh, &eos_event);
}
- if (ctx->is_enc) {
+ if (ctx->is_enc || ctx->is_stateless) {
src_buf->sequence = q_src->sequence++;
src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_buf_done(src_buf, state);
@@ -303,6 +442,9 @@ static void device_run(void *priv)
ctx->comp_has_next_frame = false;
}
v4l2_m2m_buf_done(dst_buf, state);
+ if (ctx->is_stateless && src_req)
+ v4l2_ctrl_request_complete(src_req, &ctx->hdl);
+
ctx->comp_size = 0;
ctx->header_size = 0;
ctx->comp_magic_cnt = 0;
@@ -310,9 +452,12 @@ static void device_run(void *priv)
spin_unlock(ctx->lock);
if (ctx->is_enc)
- v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx);
+ v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx);
+ else if (ctx->is_stateless)
+ v4l2_m2m_job_finish(dev->stateless_dec.m2m_dev,
+ ctx->fh.m2m_ctx);
else
- v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx);
+ v4l2_m2m_job_finish(dev->stateful_dec.m2m_dev, ctx->fh.m2m_ctx);
}
static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state)
@@ -344,7 +489,7 @@ info_from_header(const struct fwht_cframe_hdr *p_hdr)
FWHT_FL_COMPONENTS_NUM_OFFSET);
pixenc = (flags & FWHT_FL_PIXENC_MSK);
}
- return v4l2_fwht_default_fmt(width_div, height_div,
+ return v4l2_fwht_find_nth_fmt(width_div, height_div,
components_num, pixenc, 0);
}
@@ -356,21 +501,11 @@ static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr)
unsigned int version = ntohl(p_hdr->version);
unsigned int flags = ntohl(p_hdr->flags);
- if (!version || version > FWHT_VERSION)
- return false;
-
if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT)
return false;
- if (version >= 2) {
- unsigned int components_num = 1 +
- ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >>
- FWHT_FL_COMPONENTS_NUM_OFFSET);
- unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK;
-
- if (components_num == 0 || components_num > 4 || !pixenc)
- return false;
- }
+ if (!validate_by_version(flags, version))
+ return false;
info = info_from_header(p_hdr);
if (!info)
@@ -388,6 +523,12 @@ static void update_capture_data_from_header(struct vicodec_ctx *ctx)
unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
+ /*
+ * This function should not be used by a stateless codec since
+ * it changes values in q_data that are not request specific
+ */
+ WARN_ON(ctx->is_stateless);
+
q_dst->info = info;
q_dst->visible_width = ntohl(p_hdr->width);
q_dst->visible_height = ntohl(p_hdr->height);
@@ -440,7 +581,7 @@ static int job_ready(void *priv)
if (ctx->source_changed)
return 0;
- if (ctx->is_enc || ctx->comp_has_frame)
+ if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame)
return 1;
restart:
@@ -551,8 +692,8 @@ static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt)
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strncpy(cap->driver, VICODEC_NAME, sizeof(cap->driver) - 1);
- strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1);
+ strscpy(cap->driver, VICODEC_NAME, sizeof(cap->driver));
+ strscpy(cap->card, VICODEC_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", VICODEC_NAME);
return 0;
@@ -575,7 +716,7 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx,
if (!info || ctx->is_enc)
info = v4l2_fwht_get_pixfmt(f->index);
else
- info = v4l2_fwht_default_fmt(info->width_div,
+ info = v4l2_fwht_find_nth_fmt(info->width_div,
info->height_div,
info->components_num,
info->pixenc,
@@ -586,7 +727,8 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx,
} else {
if (f->index)
return -EINVAL;
- f->pixelformat = V4L2_PIX_FMT_FWHT;
+ f->pixelformat = ctx->is_stateless ?
+ V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT;
}
return 0;
}
@@ -688,13 +830,15 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
struct v4l2_pix_format_mplane *pix_mp;
struct v4l2_pix_format *pix;
struct v4l2_plane_pix_format *plane;
- const struct v4l2_fwht_pixfmt_info *info = &pixfmt_fwht;
+ const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ?
+ &pixfmt_stateless_fwht : &pixfmt_fwht;
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
pix = &f->fmt.pix;
- if (pix->pixelformat != V4L2_PIX_FMT_FWHT)
+ if (pix->pixelformat != V4L2_PIX_FMT_FWHT &&
+ pix->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS)
info = find_fmt(pix->pixelformat);
pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH);
@@ -715,7 +859,8 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
pix_mp = &f->fmt.pix_mp;
plane = pix_mp->plane_fmt;
- if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT)
+ if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT &&
+ pix_mp->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS)
info = find_fmt(pix_mp->pixelformat);
pix_mp->num_planes = 1;
@@ -792,8 +937,12 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
if (multiplanar)
return -EINVAL;
pix = &f->fmt.pix;
- pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
- find_fmt(pix->pixelformat)->id;
+ if (ctx->is_enc)
+ pix->pixelformat = find_fmt(pix->pixelformat)->id;
+ else if (ctx->is_stateless)
+ pix->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS;
+ else
+ pix->pixelformat = V4L2_PIX_FMT_FWHT;
if (!pix->colorspace)
pix->colorspace = V4L2_COLORSPACE_REC709;
break;
@@ -801,8 +950,12 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
if (!multiplanar)
return -EINVAL;
pix_mp = &f->fmt.pix_mp;
- pix_mp->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT :
- find_fmt(pix_mp->pixelformat)->id;
+ if (ctx->is_enc)
+ pix_mp->pixelformat = find_fmt(pix_mp->pixelformat)->id;
+ else if (ctx->is_stateless)
+ pix_mp->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS;
+ else
+ pix_mp->pixelformat = V4L2_PIX_FMT_FWHT;
if (!pix_mp->colorspace)
pix_mp->colorspace = V4L2_COLORSPACE_REC709;
break;
@@ -845,6 +998,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
q_data->info = &pixfmt_fwht;
+ else if (pix->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS)
+ q_data->info = &pixfmt_stateless_fwht;
else
q_data->info = find_fmt(pix->pixelformat);
q_data->coded_width = pix->width;
@@ -866,6 +1021,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f)
if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
q_data->info = &pixfmt_fwht;
+ else if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS)
+ q_data->info = &pixfmt_stateless_fwht;
else
q_data->info = find_fmt(pix_mp->pixelformat);
q_data->coded_width = pix_mp->width;
@@ -945,16 +1102,6 @@ static int vidioc_g_selection(struct file *file, void *priv,
{
struct vicodec_ctx *ctx = file2ctx(file);
struct vicodec_q_data *q_data;
- enum v4l2_buf_type valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- enum v4l2_buf_type valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-
- if (multiplanar) {
- valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- }
-
- if (s->type != valid_cap_type && s->type != valid_out_type)
- return -EINVAL;
q_data = get_q_data(ctx, s->type);
if (!q_data)
@@ -963,18 +1110,14 @@ static int vidioc_g_selection(struct file *file, void *priv,
* encoder supports only cropping on the OUTPUT buffer
* decoder supports only composing on the CAPTURE buffer
*/
- if ((ctx->is_enc && s->type == valid_out_type) ||
- (!ctx->is_enc && s->type == valid_cap_type)) {
+ if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
switch (s->target) {
- case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_CROP:
s->r.left = 0;
s->r.top = 0;
s->r.width = q_data->visible_width;
s->r.height = q_data->visible_height;
return 0;
- case V4L2_SEL_TGT_COMPOSE_DEFAULT:
- case V4L2_SEL_TGT_COMPOSE_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
s->r.left = 0;
@@ -983,6 +1126,22 @@ static int vidioc_g_selection(struct file *file, void *priv,
s->r.height = q_data->coded_height;
return 0;
}
+ } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = q_data->visible_width;
+ s->r.height = q_data->visible_height;
+ return 0;
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = q_data->coded_width;
+ s->r.height = q_data->coded_height;
+ return 0;
+ }
}
return -EINVAL;
}
@@ -992,12 +1151,8 @@ static int vidioc_s_selection(struct file *file, void *priv,
{
struct vicodec_ctx *ctx = file2ctx(file);
struct vicodec_q_data *q_data;
- enum v4l2_buf_type out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-
- if (multiplanar)
- out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- if (s->type != out_type)
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
q_data = get_q_data(ctx, s->type);
@@ -1092,6 +1247,8 @@ static int vicodec_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
switch (fsize->pixel_format) {
+ case V4L2_PIX_FMT_FWHT_STATELESS:
+ break;
case V4L2_PIX_FMT_FWHT:
break;
default:
@@ -1200,6 +1357,14 @@ static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
return 0;
}
+static int vicodec_buf_out_validate(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ vbuf->field = V4L2_FIELD_NONE;
+ return 0;
+}
+
static int vicodec_buf_prepare(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -1263,10 +1428,11 @@ static void vicodec_buf_queue(struct vb2_buffer *vb)
}
/*
- * source change event is relevant only for the decoder
+ * source change event is relevant only for the stateful decoder
* in the compressed stream
*/
- if (ctx->is_enc || !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
+ if (ctx->is_stateless || ctx->is_enc ||
+ !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) {
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
return;
}
@@ -1314,12 +1480,33 @@ static void vicodec_return_bufs(struct vb2_queue *q, u32 state)
vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
if (vbuf == NULL)
return;
+ v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req,
+ &ctx->hdl);
spin_lock(ctx->lock);
v4l2_m2m_buf_done(vbuf, state);
spin_unlock(ctx->lock);
}
}
+static unsigned int total_frame_size(struct vicodec_q_data *q_data)
+{
+ unsigned int size;
+ unsigned int chroma_div;
+
+ if (!q_data->info) {
+ WARN_ON(1);
+ return 0;
+ }
+ size = q_data->coded_width * q_data->coded_height;
+ chroma_div = q_data->info->width_div * q_data->info->height_div;
+
+ if (q_data->info->components_num == 4)
+ return 2 * size + 2 * (size / chroma_div);
+ else if (q_data->info->components_num == 3)
+ return size + 2 * (size / chroma_div);
+ return size;
+}
+
static int vicodec_start_streaming(struct vb2_queue *q,
unsigned int count)
{
@@ -1330,7 +1517,7 @@ static int vicodec_start_streaming(struct vb2_queue *q,
unsigned int size = q_data->coded_width * q_data->coded_height;
unsigned int chroma_div;
unsigned int total_planes_size;
- u8 *new_comp_frame;
+ u8 *new_comp_frame = NULL;
if (!info)
return -EINVAL;
@@ -1338,24 +1525,24 @@ static int vicodec_start_streaming(struct vb2_queue *q,
chroma_div = info->width_div * info->height_div;
q_data->sequence = 0;
- ctx->last_src_buf = NULL;
- ctx->last_dst_buf = NULL;
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ ctx->last_src_buf = NULL;
+ else
+ ctx->last_dst_buf = NULL;
+
state->gop_cnt = 0;
if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
(!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc))
return 0;
- if (info->id == V4L2_PIX_FMT_FWHT) {
+ if (info->id == V4L2_PIX_FMT_FWHT ||
+ info->id == V4L2_PIX_FMT_FWHT_STATELESS) {
vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED);
return -EINVAL;
}
- if (info->components_num == 4)
- total_planes_size = 2 * size + 2 * (size / chroma_div);
- else if (info->components_num == 3)
- total_planes_size = size + 2 * (size / chroma_div);
- else
- total_planes_size = size;
+ total_planes_size = total_frame_size(q_data);
+ ctx->comp_max_size = total_planes_size;
state->visible_width = q_data->visible_width;
state->visible_height = q_data->visible_height;
@@ -1364,8 +1551,14 @@ static int vicodec_start_streaming(struct vb2_queue *q,
state->stride = q_data->coded_width *
info->bytesperline_mult;
- state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL);
- ctx->comp_max_size = total_planes_size;
+ if (ctx->is_stateless) {
+ state->ref_stride = state->stride;
+ return 0;
+ }
+ state->ref_stride = q_data->coded_width * info->luma_alpha_step;
+
+ state->ref_frame.buf = kvmalloc(total_planes_size, GFP_KERNEL);
+ state->ref_frame.luma = state->ref_frame.buf;
new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL);
if (!state->ref_frame.luma || !new_comp_frame) {
@@ -1413,7 +1606,10 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) ||
(V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) {
- kvfree(ctx->state.ref_frame.luma);
+ if (!ctx->is_stateless)
+ kvfree(ctx->state.ref_frame.buf);
+ ctx->state.ref_frame.buf = NULL;
+ ctx->state.ref_frame.luma = NULL;
ctx->comp_max_size = 0;
ctx->source_changed = false;
}
@@ -1427,14 +1623,24 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
}
}
+static void vicodec_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl);
+}
+
+
static const struct vb2_ops vicodec_qops = {
- .queue_setup = vicodec_queue_setup,
- .buf_prepare = vicodec_buf_prepare,
- .buf_queue = vicodec_buf_queue,
- .start_streaming = vicodec_start_streaming,
- .stop_streaming = vicodec_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
+ .queue_setup = vicodec_queue_setup,
+ .buf_out_validate = vicodec_buf_out_validate,
+ .buf_prepare = vicodec_buf_prepare,
+ .buf_queue = vicodec_buf_queue,
+ .buf_request_complete = vicodec_buf_request_complete,
+ .start_streaming = vicodec_start_streaming,
+ .stop_streaming = vicodec_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
@@ -1452,9 +1658,14 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &vicodec_qops;
src_vq->mem_ops = &vb2_vmalloc_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex :
- &ctx->dev->dec_mutex;
-
+ if (ctx->is_enc)
+ src_vq->lock = &ctx->dev->stateful_enc.mutex;
+ else if (ctx->is_stateless)
+ src_vq->lock = &ctx->dev->stateless_dec.mutex;
+ else
+ src_vq->lock = &ctx->dev->stateful_dec.mutex;
+ src_vq->supports_requests = ctx->is_stateless;
+ src_vq->requires_requests = ctx->is_stateless;
ret = vb2_queue_init(src_vq);
if (ret)
return ret;
@@ -1473,53 +1684,86 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
return vb2_queue_init(dst_vq);
}
-#define VICODEC_CID_CUSTOM_BASE (V4L2_CID_MPEG_BASE | 0xf000)
-#define VICODEC_CID_I_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 0)
-#define VICODEC_CID_P_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 1)
+static int vicodec_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vicodec_ctx *ctx = container_of(ctrl->handler,
+ struct vicodec_ctx, hdl);
+ const struct v4l2_ctrl_fwht_params *params;
+ struct vicodec_q_data *q_dst = get_q_data(ctx,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS:
+ if (!q_dst->info)
+ return -EINVAL;
+ params = ctrl->p_new.p_fwht_params;
+ if (params->width > q_dst->coded_width ||
+ params->width < MIN_WIDTH ||
+ params->height > q_dst->coded_height ||
+ params->height < MIN_HEIGHT)
+ return -EINVAL;
+ if (!validate_by_version(params->flags, params->version))
+ return -EINVAL;
+ if (!validate_stateless_params_flags(params, q_dst->info))
+ return -EINVAL;
+ return 0;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static void update_header_from_stateless_params(struct vicodec_ctx *ctx,
+ const struct v4l2_ctrl_fwht_params *params)
+{
+ struct fwht_cframe_hdr *p_hdr = &ctx->state.header;
+
+ p_hdr->magic1 = FWHT_MAGIC1;
+ p_hdr->magic2 = FWHT_MAGIC2;
+ p_hdr->version = htonl(params->version);
+ p_hdr->width = htonl(params->width);
+ p_hdr->height = htonl(params->height);
+ p_hdr->flags = htonl(params->flags);
+ p_hdr->colorspace = htonl(params->colorspace);
+ p_hdr->xfer_func = htonl(params->xfer_func);
+ p_hdr->ycbcr_enc = htonl(params->ycbcr_enc);
+ p_hdr->quantization = htonl(params->quantization);
+}
static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct vicodec_ctx *ctx = container_of(ctrl->handler,
struct vicodec_ctx, hdl);
+ const struct v4l2_ctrl_fwht_params *params;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
ctx->state.gop_size = ctrl->val;
return 0;
- case VICODEC_CID_I_FRAME_QP:
+ case V4L2_CID_FWHT_I_FRAME_QP:
ctx->state.i_frame_qp = ctrl->val;
return 0;
- case VICODEC_CID_P_FRAME_QP:
+ case V4L2_CID_FWHT_P_FRAME_QP:
ctx->state.p_frame_qp = ctrl->val;
return 0;
+ case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS:
+ params = ctrl->p_new.p_fwht_params;
+ update_header_from_stateless_params(ctx, params);
+ ctx->state.ref_frame_ts = params->backward_ref_ts;
+ return 0;
}
return -EINVAL;
}
static const struct v4l2_ctrl_ops vicodec_ctrl_ops = {
.s_ctrl = vicodec_s_ctrl,
+ .try_ctrl = vicodec_try_ctrl,
};
-static const struct v4l2_ctrl_config vicodec_ctrl_i_frame = {
- .ops = &vicodec_ctrl_ops,
- .id = VICODEC_CID_I_FRAME_QP,
- .name = "FWHT I-Frame QP Value",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 1,
- .max = 31,
- .def = 20,
- .step = 1,
-};
-
-static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = {
- .ops = &vicodec_ctrl_ops,
- .id = VICODEC_CID_P_FRAME_QP,
- .name = "FWHT P-Frame QP Value",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 1,
- .max = 31,
- .def = 20,
- .step = 1,
+static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = {
+ .ops = &vicodec_ctrl_ops,
+ .id = V4L2_CID_MPEG_VIDEO_FWHT_PARAMS,
+ .elem_size = sizeof(struct v4l2_ctrl_fwht_params),
};
/*
@@ -1542,8 +1786,10 @@ static int vicodec_open(struct file *file)
goto open_unlock;
}
- if (vfd == &dev->enc_vfd)
+ if (vfd == &dev->stateful_enc.vfd)
ctx->is_enc = true;
+ else if (vfd == &dev->stateless_dec.vfd)
+ ctx->is_stateless = true;
v4l2_fh_init(&ctx->fh, video_devdata(file));
file->private_data = &ctx->fh;
@@ -1552,8 +1798,12 @@ static int vicodec_open(struct file *file)
v4l2_ctrl_handler_init(hdl, 4);
v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE,
1, 16, 1, 10);
- v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL);
- v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL);
+ v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP,
+ 1, 31, 1, 20);
+ v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP,
+ 1, 31, 1, 20);
+ if (ctx->is_stateless)
+ v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL);
if (hdl->error) {
rc = hdl->error;
v4l2_ctrl_handler_free(hdl);
@@ -1563,15 +1813,19 @@ static int vicodec_open(struct file *file)
ctx->fh.ctrl_handler = hdl;
v4l2_ctrl_handler_setup(hdl);
- ctx->q_data[V4L2_M2M_SRC].info =
- ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht;
+ if (ctx->is_enc)
+ ctx->q_data[V4L2_M2M_SRC].info = v4l2_fwht_get_pixfmt(0);
+ else if (ctx->is_stateless)
+ ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht;
+ else
+ ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_fwht;
ctx->q_data[V4L2_M2M_SRC].coded_width = 1280;
ctx->q_data[V4L2_M2M_SRC].coded_height = 720;
ctx->q_data[V4L2_M2M_SRC].visible_width = 1280;
ctx->q_data[V4L2_M2M_SRC].visible_height = 720;
size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult /
ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div;
- if (ctx->is_enc)
+ if (ctx->is_enc || ctx->is_stateless)
ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
else
ctx->q_data[V4L2_M2M_SRC].sizeimage =
@@ -1590,13 +1844,17 @@ static int vicodec_open(struct file *file)
ctx->state.colorspace = V4L2_COLORSPACE_REC709;
if (ctx->is_enc) {
- ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx,
- &queue_init);
- ctx->lock = &dev->enc_lock;
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_enc.m2m_dev,
+ ctx, &queue_init);
+ ctx->lock = &dev->stateful_enc.lock;
+ } else if (ctx->is_stateless) {
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateless_dec.m2m_dev,
+ ctx, &queue_init);
+ ctx->lock = &dev->stateless_dec.lock;
} else {
- ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->dec_dev, ctx,
- &queue_init);
- ctx->lock = &dev->dec_lock;
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_dec.m2m_dev,
+ ctx, &queue_init);
+ ctx->lock = &dev->stateful_dec.lock;
}
if (IS_ERR(ctx->fh.m2m_ctx)) {
@@ -1620,17 +1878,71 @@ static int vicodec_release(struct file *file)
struct video_device *vfd = video_devdata(file);
struct vicodec_ctx *ctx = file2ctx(file);
- v4l2_fh_del(&ctx->fh);
- v4l2_fh_exit(&ctx->fh);
- v4l2_ctrl_handler_free(&ctx->hdl);
mutex_lock(vfd->lock);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
mutex_unlock(vfd->lock);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_ctrl_handler_free(&ctx->hdl);
+ kvfree(ctx->state.compressed_frame);
kfree(ctx);
return 0;
}
+static int vicodec_request_validate(struct media_request *req)
+{
+ struct media_request_object *obj;
+ struct v4l2_ctrl_handler *parent_hdl, *hdl;
+ struct vicodec_ctx *ctx = NULL;
+ struct v4l2_ctrl *ctrl;
+ unsigned int count;
+
+ list_for_each_entry(obj, &req->objects, list) {
+ struct vb2_buffer *vb;
+
+ if (vb2_request_object_is_buffer(obj)) {
+ vb = container_of(obj, struct vb2_buffer, req_obj);
+ ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ break;
+ }
+ }
+
+ if (!ctx) {
+ pr_err("No buffer was provided with the request\n");
+ return -ENOENT;
+ }
+
+ count = vb2_request_buffer_cnt(req);
+ if (!count) {
+ v4l2_info(&ctx->dev->v4l2_dev,
+ "No buffer was provided with the request\n");
+ return -ENOENT;
+ } else if (count > 1) {
+ v4l2_info(&ctx->dev->v4l2_dev,
+ "More than one buffer was provided with the request\n");
+ return -EINVAL;
+ }
+
+ parent_hdl = &ctx->hdl;
+
+ hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl);
+ if (!hdl) {
+ v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control\n");
+ return -ENOENT;
+ }
+ ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl,
+ vicodec_ctrl_stateless_state.id);
+ if (!ctrl) {
+ v4l2_info(&ctx->dev->v4l2_dev,
+ "Missing required codec control\n");
+ return -ENOENT;
+ }
+
+ return vb2_request_validate(req);
+}
+
static const struct v4l2_file_operations vicodec_fops = {
.owner = THIS_MODULE,
.open = vicodec_open,
@@ -1649,24 +1961,67 @@ static const struct video_device vicodec_videodev = {
.release = video_device_release_empty,
};
+static const struct media_device_ops vicodec_m2m_media_ops = {
+ .req_validate = vicodec_request_validate,
+ .req_queue = v4l2_m2m_request_queue,
+};
+
static const struct v4l2_m2m_ops m2m_ops = {
.device_run = device_run,
.job_ready = job_ready,
};
+static int register_instance(struct vicodec_dev *dev,
+ struct vicodec_dev_instance *dev_instance,
+ const char *name, bool is_enc)
+{
+ struct video_device *vfd;
+ int ret;
+
+ spin_lock_init(&dev_instance->lock);
+ mutex_init(&dev_instance->mutex);
+ dev_instance->m2m_dev = v4l2_m2m_init(&m2m_ops);
+ if (IS_ERR(dev_instance->m2m_dev)) {
+ v4l2_err(&dev->v4l2_dev, "Failed to init vicodec enc device\n");
+ return PTR_ERR(dev_instance->m2m_dev);
+ }
+
+ dev_instance->vfd = vicodec_videodev;
+ vfd = &dev_instance->vfd;
+ vfd->lock = &dev_instance->mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ strscpy(vfd->name, name, sizeof(vfd->name));
+ vfd->device_caps = V4L2_CAP_STREAMING |
+ (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
+ if (is_enc) {
+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
+ } else {
+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
+ }
+ video_set_drvdata(vfd, dev);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev, "Failed to register video device '%s'\n", name);
+ v4l2_m2m_release(dev_instance->m2m_dev);
+ return ret;
+ }
+ v4l2_info(&dev->v4l2_dev, "Device '%s' registered as /dev/video%d\n",
+ name, vfd->num);
+ return 0;
+}
+
static int vicodec_probe(struct platform_device *pdev)
{
struct vicodec_dev *dev;
- struct video_device *vfd;
int ret;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- spin_lock_init(&dev->enc_lock);
- spin_lock_init(&dev->dec_lock);
-
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret)
return ret;
@@ -1677,103 +2032,74 @@ static int vicodec_probe(struct platform_device *pdev)
strscpy(dev->mdev.bus_info, "platform:vicodec",
sizeof(dev->mdev.bus_info));
media_device_init(&dev->mdev);
+ dev->mdev.ops = &vicodec_m2m_media_ops;
dev->v4l2_dev.mdev = &dev->mdev;
#endif
- mutex_init(&dev->enc_mutex);
- mutex_init(&dev->dec_mutex);
-
platform_set_drvdata(pdev, dev);
- dev->enc_dev = v4l2_m2m_init(&m2m_ops);
- if (IS_ERR(dev->enc_dev)) {
- v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
- ret = PTR_ERR(dev->enc_dev);
+ if (register_instance(dev, &dev->stateful_enc,
+ "stateful-encoder", true))
goto unreg_dev;
- }
- dev->dec_dev = v4l2_m2m_init(&m2m_ops);
- if (IS_ERR(dev->dec_dev)) {
- v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n");
- ret = PTR_ERR(dev->dec_dev);
- goto err_enc_m2m;
- }
+ if (register_instance(dev, &dev->stateful_dec,
+ "stateful-decoder", false))
+ goto unreg_sf_enc;
- dev->enc_vfd = vicodec_videodev;
- vfd = &dev->enc_vfd;
- vfd->lock = &dev->enc_mutex;
- vfd->v4l2_dev = &dev->v4l2_dev;
- strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name));
- vfd->device_caps = V4L2_CAP_STREAMING |
- (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
- v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
- video_set_drvdata(vfd, dev);
-
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
- if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
- goto err_dec_m2m;
- }
- v4l2_info(&dev->v4l2_dev,
- "Device registered as /dev/video%d\n", vfd->num);
+ if (register_instance(dev, &dev->stateless_dec,
+ "stateless-decoder", false))
+ goto unreg_sf_dec;
- dev->dec_vfd = vicodec_videodev;
- vfd = &dev->dec_vfd;
- vfd->lock = &dev->dec_mutex;
- vfd->v4l2_dev = &dev->v4l2_dev;
- vfd->device_caps = V4L2_CAP_STREAMING |
- (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M);
- strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name));
- v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
- v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
- video_set_drvdata(vfd, dev);
-
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ ret = v4l2_m2m_register_media_controller(dev->stateful_enc.m2m_dev,
+ &dev->stateful_enc.vfd,
+ MEDIA_ENT_F_PROC_VIDEO_ENCODER);
if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
- goto unreg_enc;
+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for enc\n");
+ goto unreg_m2m;
}
- v4l2_info(&dev->v4l2_dev,
- "Device registered as /dev/video%d\n", vfd->num);
-#ifdef CONFIG_MEDIA_CONTROLLER
- ret = v4l2_m2m_register_media_controller(dev->enc_dev,
- &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER);
+ ret = v4l2_m2m_register_media_controller(dev->stateful_dec.m2m_dev,
+ &dev->stateful_dec.vfd,
+ MEDIA_ENT_F_PROC_VIDEO_DECODER);
if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
- goto unreg_m2m;
+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for dec\n");
+ goto unreg_m2m_sf_enc_mc;
}
- ret = v4l2_m2m_register_media_controller(dev->dec_dev,
- &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER);
+ ret = v4l2_m2m_register_media_controller(dev->stateless_dec.m2m_dev,
+ &dev->stateless_dec.vfd,
+ MEDIA_ENT_F_PROC_VIDEO_DECODER);
if (ret) {
- v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
- goto unreg_m2m_enc_mc;
+ v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for stateless dec\n");
+ goto unreg_m2m_sf_dec_mc;
}
ret = media_device_register(&dev->mdev);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
- goto unreg_m2m_dec_mc;
+ goto unreg_m2m_sl_dec_mc;
}
#endif
return 0;
#ifdef CONFIG_MEDIA_CONTROLLER
-unreg_m2m_dec_mc:
- v4l2_m2m_unregister_media_controller(dev->dec_dev);
-unreg_m2m_enc_mc:
- v4l2_m2m_unregister_media_controller(dev->enc_dev);
+unreg_m2m_sl_dec_mc:
+ v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev);
+unreg_m2m_sf_dec_mc:
+ v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev);
+unreg_m2m_sf_enc_mc:
+ v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev);
unreg_m2m:
- video_unregister_device(&dev->dec_vfd);
+ video_unregister_device(&dev->stateless_dec.vfd);
+ v4l2_m2m_release(dev->stateless_dec.m2m_dev);
#endif
-unreg_enc:
- video_unregister_device(&dev->enc_vfd);
-err_dec_m2m:
- v4l2_m2m_release(dev->dec_dev);
-err_enc_m2m:
- v4l2_m2m_release(dev->enc_dev);
+unreg_sf_dec:
+ video_unregister_device(&dev->stateful_dec.vfd);
+ v4l2_m2m_release(dev->stateful_dec.m2m_dev);
+unreg_sf_enc:
+ video_unregister_device(&dev->stateful_enc.vfd);
+ v4l2_m2m_release(dev->stateful_enc.m2m_dev);
unreg_dev:
v4l2_device_unregister(&dev->v4l2_dev);
@@ -1788,15 +2114,17 @@ static int vicodec_remove(struct platform_device *pdev)
#ifdef CONFIG_MEDIA_CONTROLLER
media_device_unregister(&dev->mdev);
- v4l2_m2m_unregister_media_controller(dev->enc_dev);
- v4l2_m2m_unregister_media_controller(dev->dec_dev);
+ v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev);
+ v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev);
+ v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev);
media_device_cleanup(&dev->mdev);
#endif
- v4l2_m2m_release(dev->enc_dev);
- v4l2_m2m_release(dev->dec_dev);
- video_unregister_device(&dev->enc_vfd);
- video_unregister_device(&dev->dec_vfd);
+ v4l2_m2m_release(dev->stateful_enc.m2m_dev);
+ v4l2_m2m_release(dev->stateful_dec.m2m_dev);
+ video_unregister_device(&dev->stateful_enc.vfd);
+ video_unregister_device(&dev->stateful_dec.vfd);
+ video_unregister_device(&dev->stateless_dec.vfd);
v4l2_device_unregister(&dev->v4l2_dev);
return 0;
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index 0ba30756e1e4..d8cd5f5cb10d 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -419,9 +419,14 @@ static int video_mux_probe(struct platform_device *pdev)
vmux->active = -1;
vmux->pads = devm_kcalloc(dev, num_pads, sizeof(*vmux->pads),
GFP_KERNEL);
+ if (!vmux->pads)
+ return -ENOMEM;
+
vmux->format_mbus = devm_kcalloc(dev, num_pads,
sizeof(*vmux->format_mbus),
GFP_KERNEL);
+ if (!vmux->format_mbus)
+ return -ENOMEM;
for (i = 0; i < num_pads; i++) {
vmux->pads[i].flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index 34dcaca45d8b..243c82b5d537 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -302,7 +302,7 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in,
switch (in->fourcc) {
case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */
for (i = 0; i < 2; i++) {
- u16 pix = *(u16 *)(src[i]);
+ u16 pix = le16_to_cpu(*(__le16 *)(src[i]));
*r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07;
*g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03;
@@ -311,12 +311,11 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in,
break;
case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */
for (i = 0; i < 2; i++) {
- u16 pix = *(u16 *)(src[i]);
+ u16 pix = be16_to_cpu(*(__be16 *)(src[i]));
- *r++ = (u8)(((0x00f8 & pix) >> 3) << 3) | 0x07;
- *g++ = (u8)(((pix & 0x7) << 2) |
- ((pix & 0xe000) >> 5)) | 0x03;
- *b++ = (u8)(((pix & 0x1f00) >> 8) << 3) | 0x07;
+ *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07;
+ *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03;
+ *b++ = (u8)((pix & 0x1f) << 3) | 0x07;
}
break;
default:
@@ -345,21 +344,26 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in,
switch (out->fourcc) {
case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */
for (i = 0; i < 2; i++) {
- u16 *pix = (u16 *)*dst;
+ u16 pix;
+ __le16 *dst_pix = (__le16 *)*dst;
+
+ pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) |
+ (*b >> 3);
- *pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) |
- (*b >> 3);
+ *dst_pix = cpu_to_le16(pix);
*dst += 2;
}
return;
case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */
for (i = 0; i < 2; i++) {
- u16 *pix = (u16 *)*dst;
- u8 green = *g++ >> 2;
+ u16 pix;
+ __be16 *dst_pix = (__be16 *)*dst;
- *pix = ((green << 8) & 0xe000) | (green & 0x07) |
- ((*b++ << 5) & 0x1f00) | ((*r++ & 0xf8));
+ pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) |
+ (*b >> 3);
+
+ *dst_pix = cpu_to_be16(pix);
*dst += 2;
}
@@ -655,8 +659,8 @@ static void device_work(struct work_struct *w)
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
- strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
+ strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
+ strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", MEM2MEM_NAME);
return 0;
@@ -1262,6 +1266,15 @@ static int vim2m_release(struct file *file)
return 0;
}
+static void vim2m_device_release(struct video_device *vdev)
+{
+ struct vim2m_dev *dev = container_of(vdev, struct vim2m_dev, vfd);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_m2m_release(dev->m2m_dev);
+ kfree(dev);
+}
+
static const struct v4l2_file_operations vim2m_fops = {
.owner = THIS_MODULE,
.open = vim2m_open,
@@ -1277,7 +1290,7 @@ static const struct video_device vim2m_videodev = {
.fops = &vim2m_fops,
.ioctl_ops = &vim2m_ioctl_ops,
.minor = -1,
- .release = video_device_release_empty,
+ .release = vim2m_device_release,
.device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
};
@@ -1298,13 +1311,13 @@ static int vim2m_probe(struct platform_device *pdev)
struct video_device *vfd;
int ret;
- dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret)
- return ret;
+ goto error_free;
atomic_set(&dev->num_inst, 0);
mutex_init(&dev->dev_mutex);
@@ -1317,7 +1330,7 @@ static int vim2m_probe(struct platform_device *pdev)
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
- goto unreg_v4l2;
+ goto error_v4l2;
}
video_set_drvdata(vfd, dev);
@@ -1330,7 +1343,7 @@ static int vim2m_probe(struct platform_device *pdev)
if (IS_ERR(dev->m2m_dev)) {
v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
ret = PTR_ERR(dev->m2m_dev);
- goto unreg_dev;
+ goto error_dev;
}
#ifdef CONFIG_MEDIA_CONTROLLER
@@ -1346,27 +1359,29 @@ static int vim2m_probe(struct platform_device *pdev)
MEDIA_ENT_F_PROC_VIDEO_SCALER);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n");
- goto unreg_m2m;
+ goto error_m2m;
}
ret = media_device_register(&dev->mdev);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n");
- goto unreg_m2m_mc;
+ goto error_m2m_mc;
}
#endif
return 0;
#ifdef CONFIG_MEDIA_CONTROLLER
-unreg_m2m_mc:
+error_m2m_mc:
v4l2_m2m_unregister_media_controller(dev->m2m_dev);
-unreg_m2m:
+error_m2m:
v4l2_m2m_release(dev->m2m_dev);
#endif
-unreg_dev:
+error_dev:
video_unregister_device(&dev->vfd);
-unreg_v4l2:
+error_v4l2:
v4l2_device_unregister(&dev->v4l2_dev);
+error_free:
+ kfree(dev);
return ret;
}
@@ -1382,9 +1397,7 @@ static int vim2m_remove(struct platform_device *pdev)
v4l2_m2m_unregister_media_controller(dev->m2m_dev);
media_device_cleanup(&dev->mdev);
#endif
- v4l2_m2m_release(dev->m2m_dev);
video_unregister_device(&dev->vfd);
- v4l2_device_unregister(&dev->v4l2_dev);
return 0;
}
diff --git a/drivers/media/platform/vimc/Kconfig b/drivers/media/platform/vimc/Kconfig
index 71c9fe7d3370..1de9bc9aa49b 100644
--- a/drivers/media/platform/vimc/Kconfig
+++ b/drivers/media/platform/vimc/Kconfig
@@ -4,7 +4,7 @@ config VIDEO_VIMC
select VIDEOBUF2_VMALLOC
select VIDEO_V4L2_TPG
default n
- ---help---
+ help
Skeleton driver for Virtual Media Controller
This driver can be compared to the vivid driver for emulating
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c
index ea869631a3f6..e7d0fc2228a6 100644
--- a/drivers/media/platform/vimc/vimc-capture.c
+++ b/drivers/media/platform/vimc/vimc-capture.c
@@ -28,6 +28,32 @@
#define VIMC_CAP_DRV_NAME "vimc-capture"
+static const u32 vimc_cap_supported_pixfmt[] = {
+ V4L2_PIX_FMT_BGR24,
+ V4L2_PIX_FMT_RGB24,
+ V4L2_PIX_FMT_ARGB32,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_PIX_FMT_SGBRG8,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_PIX_FMT_SRGGB8,
+ V4L2_PIX_FMT_SBGGR10,
+ V4L2_PIX_FMT_SGBRG10,
+ V4L2_PIX_FMT_SGRBG10,
+ V4L2_PIX_FMT_SRGGB10,
+ V4L2_PIX_FMT_SBGGR10ALAW8,
+ V4L2_PIX_FMT_SGBRG10ALAW8,
+ V4L2_PIX_FMT_SGRBG10ALAW8,
+ V4L2_PIX_FMT_SRGGB10ALAW8,
+ V4L2_PIX_FMT_SBGGR10DPCM8,
+ V4L2_PIX_FMT_SGBRG10DPCM8,
+ V4L2_PIX_FMT_SGRBG10DPCM8,
+ V4L2_PIX_FMT_SRGGB10DPCM8,
+ V4L2_PIX_FMT_SBGGR12,
+ V4L2_PIX_FMT_SGBRG12,
+ V4L2_PIX_FMT_SGRBG12,
+ V4L2_PIX_FMT_SRGGB12,
+};
+
struct vimc_cap_device {
struct vimc_ent_device ved;
struct video_device vdev;
@@ -101,29 +127,25 @@ static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct v4l2_pix_format *format = &f->fmt.pix;
- const struct vimc_pix_map *vpix;
format->width = clamp_t(u32, format->width, VIMC_FRAME_MIN_WIDTH,
VIMC_FRAME_MAX_WIDTH) & ~1;
format->height = clamp_t(u32, format->height, VIMC_FRAME_MIN_HEIGHT,
VIMC_FRAME_MAX_HEIGHT) & ~1;
- /* Don't accept a pixelformat that is not on the table */
- vpix = vimc_pix_map_by_pixelformat(format->pixelformat);
- if (!vpix) {
- format->pixelformat = fmt_default.pixelformat;
- vpix = vimc_pix_map_by_pixelformat(format->pixelformat);
- }
- /* TODO: Add support for custom bytesperline values */
- format->bytesperline = format->width * vpix->bpp;
- format->sizeimage = format->bytesperline * format->height;
+ vimc_colorimetry_clamp(format);
if (format->field == V4L2_FIELD_ANY)
format->field = fmt_default.field;
- vimc_colorimetry_clamp(format);
+ /* TODO: Add support for custom bytesperline values */
- return 0;
+ /* Don't accept a pixelformat that is not on the table */
+ if (!v4l2_format_info(format->pixelformat))
+ format->pixelformat = fmt_default.pixelformat;
+
+ return v4l2_fill_pixfmt(format, format->pixelformat,
+ format->width, format->height);
}
static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,
@@ -159,27 +181,31 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,
static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- const struct vimc_pix_map *vpix = vimc_pix_map_by_index(f->index);
-
- if (!vpix)
+ if (f->index >= ARRAY_SIZE(vimc_cap_supported_pixfmt))
return -EINVAL;
- f->pixelformat = vpix->pixelformat;
+ f->pixelformat = vimc_cap_supported_pixfmt[f->index];
return 0;
}
+static bool vimc_cap_is_pixfmt_supported(u32 pixelformat)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vimc_cap_supported_pixfmt); i++)
+ if (vimc_cap_supported_pixfmt[i] == pixelformat)
+ return true;
+ return false;
+}
+
static int vimc_cap_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
- const struct vimc_pix_map *vpix;
-
if (fsize->index)
return -EINVAL;
- /* Only accept code in the pix map table */
- vpix = vimc_pix_map_by_code(fsize->pixel_format);
- if (!vpix)
+ if (!vimc_cap_is_pixfmt_supported(fsize->pixel_format))
return -EINVAL;
fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
@@ -187,8 +213,8 @@ static int vimc_cap_enum_framesizes(struct file *file, void *fh,
fsize->stepwise.max_width = VIMC_FRAME_MAX_WIDTH;
fsize->stepwise.min_height = VIMC_FRAME_MIN_HEIGHT;
fsize->stepwise.max_height = VIMC_FRAME_MAX_HEIGHT;
- fsize->stepwise.step_width = 2;
- fsize->stepwise.step_height = 2;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.step_height = 1;
return 0;
}
@@ -253,6 +279,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
return ret;
}
+ vcap->stream.producer_pixfmt = vcap->format.pixelformat;
ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1);
if (ret) {
media_pipeline_stop(entity);
@@ -338,6 +365,15 @@ static const struct media_entity_operations vimc_cap_mops = {
.link_validate = vimc_link_validate,
};
+static void vimc_cap_release(struct video_device *vdev)
+{
+ struct vimc_cap_device *vcap =
+ container_of(vdev, struct vimc_cap_device, vdev);
+
+ vimc_pads_cleanup(vcap->ved.pads);
+ kfree(vcap);
+}
+
static void vimc_cap_comp_unbind(struct device *comp, struct device *master,
void *master_data)
{
@@ -348,8 +384,6 @@ static void vimc_cap_comp_unbind(struct device *comp, struct device *master,
vb2_queue_release(&vcap->queue);
media_entity_cleanup(ved->ent);
video_unregister_device(&vcap->vdev);
- vimc_pads_cleanup(vcap->ved.pads);
- kfree(vcap);
}
static void *vimc_cap_process_frame(struct vimc_ent_device *ved,
@@ -396,7 +430,6 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
{
struct v4l2_device *v4l2_dev = master_data;
struct vimc_platform_data *pdata = comp->platform_data;
- const struct vimc_pix_map *vpix;
struct vimc_cap_device *vcap;
struct video_device *vdev;
struct vb2_queue *q;
@@ -451,10 +484,8 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
/* Set default frame format */
vcap->format = fmt_default;
- vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat);
- vcap->format.bytesperline = vcap->format.width * vpix->bpp;
- vcap->format.sizeimage = vcap->format.bytesperline *
- vcap->format.height;
+ v4l2_fill_pixfmt(&vcap->format, vcap->format.pixelformat,
+ vcap->format.width, vcap->format.height);
/* Fill the vimc_ent_device struct */
vcap->ved.ent = &vcap->vdev.entity;
@@ -467,7 +498,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
vdev = &vcap->vdev;
vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
vdev->entity.ops = &vimc_cap_mops;
- vdev->release = video_device_release_empty;
+ vdev->release = vimc_cap_release;
vdev->fops = &vimc_cap_fops;
vdev->ioctl_ops = &vimc_cap_ioctl_ops;
vdev->lock = &vcap->lock;
diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c
index c1a74bb2df58..fad7c7c6de93 100644
--- a/drivers/media/platform/vimc/vimc-common.c
+++ b/drivers/media/platform/vimc/vimc-common.c
@@ -20,192 +20,139 @@
#include "vimc-common.h"
-/*
- * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code
- * in the scaler)
- */
-static const struct vimc_pix_map vimc_pix_map_list[] = {
- /* TODO: add all missing formats */
-
- /* RGB formats */
- {
- .code = MEDIA_BUS_FMT_BGR888_1X24,
- .pixelformat = V4L2_PIX_FMT_BGR24,
- .bpp = 3,
- .bayer = false,
- },
- {
- .code = MEDIA_BUS_FMT_RGB888_1X24,
- .pixelformat = V4L2_PIX_FMT_RGB24,
- .bpp = 3,
- .bayer = false,
- },
- {
- .code = MEDIA_BUS_FMT_ARGB8888_1X32,
- .pixelformat = V4L2_PIX_FMT_ARGB32,
- .bpp = 4,
- .bayer = false,
- },
-
- /* Bayer formats */
- {
- .code = MEDIA_BUS_FMT_SBGGR8_1X8,
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGBRG8_1X8,
- .pixelformat = V4L2_PIX_FMT_SGBRG8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGRBG8_1X8,
- .pixelformat = V4L2_PIX_FMT_SGRBG8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SRGGB8_1X8,
- .pixelformat = V4L2_PIX_FMT_SRGGB8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SBGGR10_1X10,
- .pixelformat = V4L2_PIX_FMT_SBGGR10,
- .bpp = 2,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGBRG10_1X10,
- .pixelformat = V4L2_PIX_FMT_SGBRG10,
- .bpp = 2,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGRBG10_1X10,
- .pixelformat = V4L2_PIX_FMT_SGRBG10,
- .bpp = 2,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SRGGB10_1X10,
- .pixelformat = V4L2_PIX_FMT_SRGGB10,
- .bpp = 2,
- .bayer = true,
- },
-
- /* 10bit raw bayer a-law compressed to 8 bits */
- {
- .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8,
- .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8,
- .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
- .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8,
- .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8,
- .bpp = 1,
- .bayer = true,
- },
-
- /* 10bit raw bayer DPCM compressed to 8 bits */
- {
- .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
- .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
- .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
- .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
- .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8,
- .bpp = 1,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SBGGR12_1X12,
- .pixelformat = V4L2_PIX_FMT_SBGGR12,
- .bpp = 2,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGBRG12_1X12,
- .pixelformat = V4L2_PIX_FMT_SGBRG12,
- .bpp = 2,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SGRBG12_1X12,
- .pixelformat = V4L2_PIX_FMT_SGRBG12,
- .bpp = 2,
- .bayer = true,
- },
- {
- .code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .pixelformat = V4L2_PIX_FMT_SRGGB12,
- .bpp = 2,
- .bayer = true,
- },
+static const __u32 vimc_mbus_list[] = {
+ MEDIA_BUS_FMT_FIXED,
+ MEDIA_BUS_FMT_RGB444_1X12,
+ MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE,
+ MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
+ MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
+ MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+ MEDIA_BUS_FMT_RGB565_1X16,
+ MEDIA_BUS_FMT_BGR565_2X8_BE,
+ MEDIA_BUS_FMT_BGR565_2X8_LE,
+ MEDIA_BUS_FMT_RGB565_2X8_BE,
+ MEDIA_BUS_FMT_RGB565_2X8_LE,
+ MEDIA_BUS_FMT_RGB666_1X18,
+ MEDIA_BUS_FMT_RBG888_1X24,
+ MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
+ MEDIA_BUS_FMT_RGB666_1X7X3_SPWG,
+ MEDIA_BUS_FMT_BGR888_1X24,
+ MEDIA_BUS_FMT_GBR888_1X24,
+ MEDIA_BUS_FMT_RGB888_1X24,
+ MEDIA_BUS_FMT_RGB888_2X12_BE,
+ MEDIA_BUS_FMT_RGB888_2X12_LE,
+ MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
+ MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA,
+ MEDIA_BUS_FMT_ARGB8888_1X32,
+ MEDIA_BUS_FMT_RGB888_1X32_PADHI,
+ MEDIA_BUS_FMT_RGB101010_1X30,
+ MEDIA_BUS_FMT_RGB121212_1X36,
+ MEDIA_BUS_FMT_RGB161616_1X48,
+ MEDIA_BUS_FMT_Y8_1X8,
+ MEDIA_BUS_FMT_UV8_1X8,
+ MEDIA_BUS_FMT_UYVY8_1_5X8,
+ MEDIA_BUS_FMT_VYUY8_1_5X8,
+ MEDIA_BUS_FMT_YUYV8_1_5X8,
+ MEDIA_BUS_FMT_YVYU8_1_5X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_VYUY8_2X8,
+ MEDIA_BUS_FMT_YUYV8_2X8,
+ MEDIA_BUS_FMT_YVYU8_2X8,
+ MEDIA_BUS_FMT_Y10_1X10,
+ MEDIA_BUS_FMT_Y10_2X8_PADHI_LE,
+ MEDIA_BUS_FMT_UYVY10_2X10,
+ MEDIA_BUS_FMT_VYUY10_2X10,
+ MEDIA_BUS_FMT_YUYV10_2X10,
+ MEDIA_BUS_FMT_YVYU10_2X10,
+ MEDIA_BUS_FMT_Y12_1X12,
+ MEDIA_BUS_FMT_UYVY12_2X12,
+ MEDIA_BUS_FMT_VYUY12_2X12,
+ MEDIA_BUS_FMT_YUYV12_2X12,
+ MEDIA_BUS_FMT_YVYU12_2X12,
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_VYUY8_1X16,
+ MEDIA_BUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_YVYU8_1X16,
+ MEDIA_BUS_FMT_YDYUYDYV8_1X16,
+ MEDIA_BUS_FMT_UYVY10_1X20,
+ MEDIA_BUS_FMT_VYUY10_1X20,
+ MEDIA_BUS_FMT_YUYV10_1X20,
+ MEDIA_BUS_FMT_YVYU10_1X20,
+ MEDIA_BUS_FMT_VUY8_1X24,
+ MEDIA_BUS_FMT_YUV8_1X24,
+ MEDIA_BUS_FMT_UYYVYY8_0_5X24,
+ MEDIA_BUS_FMT_UYVY12_1X24,
+ MEDIA_BUS_FMT_VYUY12_1X24,
+ MEDIA_BUS_FMT_YUYV12_1X24,
+ MEDIA_BUS_FMT_YVYU12_1X24,
+ MEDIA_BUS_FMT_YUV10_1X30,
+ MEDIA_BUS_FMT_UYYVYY10_0_5X30,
+ MEDIA_BUS_FMT_AYUV8_1X32,
+ MEDIA_BUS_FMT_UYYVYY12_0_5X36,
+ MEDIA_BUS_FMT_YUV12_1X36,
+ MEDIA_BUS_FMT_YUV16_1X48,
+ MEDIA_BUS_FMT_UYYVYY16_0_5X48,
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8,
+ MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
+ MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8,
+ MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE,
+ MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
+ MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE,
+ MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SBGGR12_1X12,
+ MEDIA_BUS_FMT_SGBRG12_1X12,
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+ MEDIA_BUS_FMT_SBGGR14_1X14,
+ MEDIA_BUS_FMT_SGBRG14_1X14,
+ MEDIA_BUS_FMT_SGRBG14_1X14,
+ MEDIA_BUS_FMT_SRGGB14_1X14,
+ MEDIA_BUS_FMT_SBGGR16_1X16,
+ MEDIA_BUS_FMT_SGBRG16_1X16,
+ MEDIA_BUS_FMT_SGRBG16_1X16,
+ MEDIA_BUS_FMT_SRGGB16_1X16,
+ MEDIA_BUS_FMT_JPEG_1X8,
+ MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8,
+ MEDIA_BUS_FMT_AHSV8888_1X32,
};
-const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)
-{
- if (i >= ARRAY_SIZE(vimc_pix_map_list))
- return NULL;
-
- return &vimc_pix_map_list[i];
-}
-EXPORT_SYMBOL_GPL(vimc_pix_map_by_index);
-
-const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
+/* Helper function to check mbus codes */
+bool vimc_mbus_code_supported(__u32 code)
{
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
- if (vimc_pix_map_list[i].code == code)
- return &vimc_pix_map_list[i];
- }
- return NULL;
+ for (i = 0; i < ARRAY_SIZE(vimc_mbus_list); i++)
+ if (code == vimc_mbus_list[i])
+ return true;
+ return false;
}
-EXPORT_SYMBOL_GPL(vimc_pix_map_by_code);
+EXPORT_SYMBOL_GPL(vimc_mbus_code_supported);
-const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
+/* Helper function to enumerate mbus codes */
+int vimc_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code)
{
- unsigned int i;
+ if (code->index >= ARRAY_SIZE(vimc_mbus_list))
+ return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) {
- if (vimc_pix_map_list[i].pixelformat == pixelformat)
- return &vimc_pix_map_list[i];
- }
- return NULL;
+ code->code = vimc_mbus_list[code->index];
+ return 0;
}
-EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat);
+EXPORT_SYMBOL_GPL(vimc_enum_mbus_code);
/* Helper function to allocate and initialize pads */
struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag)
@@ -277,15 +224,13 @@ static int vimc_get_mbus_format(struct media_pad *pad,
struct video_device,
entity);
struct vimc_ent_device *ved = video_get_drvdata(vdev);
- const struct vimc_pix_map *vpix;
struct v4l2_pix_format vdev_fmt;
if (!ved->vdev_get_format)
return -ENOIOCTLCMD;
ved->vdev_get_format(ved, &vdev_fmt);
- vpix = vimc_pix_map_by_pixelformat(vdev_fmt.pixelformat);
- v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, vpix->code);
+ v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, 0);
} else {
return -EINVAL;
}
@@ -325,8 +270,12 @@ int vimc_link_validate(struct media_link *link)
/* The width, height and code must match. */
if (source_fmt.format.width != sink_fmt.format.width
|| source_fmt.format.height != sink_fmt.format.height
- || source_fmt.format.code != sink_fmt.format.code)
+ || (source_fmt.format.code && sink_fmt.format.code &&
+ source_fmt.format.code != sink_fmt.format.code)) {
+ pr_err("vimc: format doesn't match in link %s->%s\n",
+ link->source->entity->name, link->sink->entity->name);
return -EPIPE;
+ }
/*
* The field order must match, or the sink field order must be NONE
@@ -380,6 +329,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
u32 function,
u16 num_pads,
const unsigned long *pads_flag,
+ const struct v4l2_subdev_internal_ops *sd_int_ops,
const struct v4l2_subdev_ops *sd_ops)
{
int ret;
@@ -394,6 +344,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
/* Initialize the subdev */
v4l2_subdev_init(sd, sd_ops);
+ sd->internal_ops = sd_int_ops;
sd->entity.function = function;
sd->entity.ops = &vimc_ent_sd_mops;
sd->owner = THIS_MODULE;
@@ -431,9 +382,9 @@ EXPORT_SYMBOL_GPL(vimc_ent_sd_register);
void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd)
{
- v4l2_device_unregister_subdev(sd);
media_entity_cleanup(ved->ent);
vimc_pads_cleanup(ved->pads);
+ v4l2_device_unregister_subdev(sd);
}
EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister);
diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h
index 84539430b5e7..142ddfa69b3d 100644
--- a/drivers/media/platform/vimc/vimc-common.h
+++ b/drivers/media/platform/vimc/vimc-common.h
@@ -22,6 +22,8 @@
#include <media/media-device.h>
#include <media/v4l2-device.h>
+#include "vimc-streamer.h"
+
#define VIMC_PDEV_NAME "vimc"
/* VIMC-specific controls */
@@ -78,23 +80,6 @@ struct vimc_platform_data {
};
/**
- * struct vimc_pix_map - maps media bus code with v4l2 pixel format
- *
- * @code: media bus format code defined by MEDIA_BUS_FMT_* macros
- * @bbp: number of bytes each pixel occupies
- * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros
- *
- * Struct which matches the MEDIA_BUS_FMT_* codes with the corresponding
- * V4L2_PIX_FMT_* fourcc pixelformat and its bytes per pixel (bpp)
- */
-struct vimc_pix_map {
- unsigned int code;
- unsigned int bpp;
- u32 pixelformat;
- bool bayer;
-};
-
-/**
* struct vimc_ent_device - core struct that represents a node in the topology
*
* @ent: the pointer to struct media_entity for the node
@@ -115,6 +100,7 @@ struct vimc_pix_map {
struct vimc_ent_device {
struct media_entity *ent;
struct media_pad *pads;
+ struct vimc_stream *stream;
void * (*process_frame)(struct vimc_ent_device *ved,
const void *frame);
void (*vdev_get_format)(struct vimc_ent_device *ved,
@@ -122,6 +108,23 @@ struct vimc_ent_device {
};
/**
+ * vimc_mbus_code_supported - helper to check supported mbus codes
+ *
+ * Helper function to check if mbus code is enumerated by vimc_enum_mbus_code()
+ */
+bool vimc_mbus_code_supported(__u32 code);
+
+/**
+ * vimc_enum_mbus_code - enumerate mbus codes
+ *
+ * Helper function to be pluged in .enum_mbus_code from
+ * struct v4l2_subdev_pad_ops.
+ */
+int vimc_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *code);
+
+/**
* vimc_pads_init - initialize pads
*
* @num_pads: number of pads to initialize
@@ -156,27 +159,6 @@ static inline void vimc_pads_cleanup(struct media_pad *pads)
int vimc_pipeline_s_stream(struct media_entity *ent, int enable);
/**
- * vimc_pix_map_by_index - get vimc_pix_map struct by its index
- *
- * @i: index of the vimc_pix_map struct in vimc_pix_map_list
- */
-const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i);
-
-/**
- * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code
- *
- * @code: media bus format code defined by MEDIA_BUS_FMT_* macros
- */
-const struct vimc_pix_map *vimc_pix_map_by_code(u32 code);
-
-/**
- * vimc_pix_map_by_pixelformat - get vimc_pix_map struct by v4l2 pixel format
- *
- * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros
- */
-const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat);
-
-/**
* vimc_ent_sd_register - initialize and register a subdev node
*
* @ved: the vimc_ent_device struct to be initialize
@@ -187,6 +169,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat);
* @function: media entity function defined by MEDIA_ENT_F_* macros
* @num_pads: number of pads to initialize
* @pads_flag: flags to use in each pad
+ * @sd_int_ops: pointer to &struct v4l2_subdev_internal_ops
* @sd_ops: pointer to &struct v4l2_subdev_ops.
*
* Helper function initialize and register the struct vimc_ent_device and struct
@@ -199,6 +182,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
u32 function,
u16 num_pads,
const unsigned long *pads_flag,
+ const struct v4l2_subdev_internal_ops *sd_int_ops,
const struct v4l2_subdev_ops *sd_ops);
/**
diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c
index 0fbb7914098f..3aa62d7e3d0e 100644
--- a/drivers/media/platform/vimc/vimc-core.c
+++ b/drivers/media/platform/vimc/vimc-core.c
@@ -304,6 +304,8 @@ static int vimc_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "probe");
+ memset(&vimc->mdev, 0, sizeof(vimc->mdev));
+
/* Create platform_device for each entity in the topology*/
vimc->subdevs = devm_kcalloc(&vimc->pdev.dev, vimc->pipe_cfg->num_ents,
sizeof(*vimc->subdevs), GFP_KERNEL);
diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c
index 7d77c63b99d2..281f9c1a7249 100644
--- a/drivers/media/platform/vimc/vimc-debayer.c
+++ b/drivers/media/platform/vimc/vimc-debayer.c
@@ -26,6 +26,9 @@
#include "vimc-common.h"
#define VIMC_DEB_DRV_NAME "vimc-debayer"
+/* This module only supports tranforming a bayer format to V4L2_PIX_FMT_RGB24 */
+#define VIMC_DEB_SRC_PIXFMT V4L2_PIX_FMT_RGB24
+#define VIMC_DEB_SRC_MBUS_FMT_DEFAULT MEDIA_BUS_FMT_RGB888_1X24
static unsigned int deb_mean_win_size = 3;
module_param(deb_mean_win_size, uint, 0000);
@@ -44,6 +47,7 @@ enum vimc_deb_rgb_colors {
};
struct vimc_deb_pix_map {
+ u32 pixelformat;
u32 code;
enum vimc_deb_rgb_colors order[2][2];
};
@@ -66,68 +70,80 @@ struct vimc_deb_device {
static const struct v4l2_mbus_framefmt sink_fmt_default = {
.width = 640,
.height = 480,
- .code = MEDIA_BUS_FMT_RGB888_1X24,
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
.field = V4L2_FIELD_NONE,
.colorspace = V4L2_COLORSPACE_DEFAULT,
};
static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = {
{
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
.code = MEDIA_BUS_FMT_SBGGR8_1X8,
.order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN },
{ VIMC_DEB_GREEN, VIMC_DEB_RED } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SGBRG8,
.code = MEDIA_BUS_FMT_SGBRG8_1X8,
.order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE },
{ VIMC_DEB_RED, VIMC_DEB_GREEN } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SGRBG8,
.code = MEDIA_BUS_FMT_SGRBG8_1X8,
.order = { { VIMC_DEB_GREEN, VIMC_DEB_RED },
{ VIMC_DEB_BLUE, VIMC_DEB_GREEN } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SRGGB8,
.code = MEDIA_BUS_FMT_SRGGB8_1X8,
.order = { { VIMC_DEB_RED, VIMC_DEB_GREEN },
{ VIMC_DEB_GREEN, VIMC_DEB_BLUE } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SBGGR10,
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
.order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN },
{ VIMC_DEB_GREEN, VIMC_DEB_RED } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SGBRG10,
.code = MEDIA_BUS_FMT_SGBRG10_1X10,
.order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE },
{ VIMC_DEB_RED, VIMC_DEB_GREEN } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SGRBG10,
.code = MEDIA_BUS_FMT_SGRBG10_1X10,
.order = { { VIMC_DEB_GREEN, VIMC_DEB_RED },
{ VIMC_DEB_BLUE, VIMC_DEB_GREEN } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SRGGB10,
.code = MEDIA_BUS_FMT_SRGGB10_1X10,
.order = { { VIMC_DEB_RED, VIMC_DEB_GREEN },
{ VIMC_DEB_GREEN, VIMC_DEB_BLUE } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SBGGR12,
.code = MEDIA_BUS_FMT_SBGGR12_1X12,
.order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN },
{ VIMC_DEB_GREEN, VIMC_DEB_RED } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SGBRG12,
.code = MEDIA_BUS_FMT_SGBRG12_1X12,
.order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE },
{ VIMC_DEB_RED, VIMC_DEB_GREEN } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SGRBG12,
.code = MEDIA_BUS_FMT_SGRBG12_1X12,
.order = { { VIMC_DEB_GREEN, VIMC_DEB_RED },
{ VIMC_DEB_BLUE, VIMC_DEB_GREEN } }
},
{
+ .pixelformat = V4L2_PIX_FMT_SRGGB12,
.code = MEDIA_BUS_FMT_SRGGB12_1X12,
.order = { { VIMC_DEB_RED, VIMC_DEB_GREEN },
{ VIMC_DEB_GREEN, VIMC_DEB_BLUE } }
@@ -168,41 +184,32 @@ static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
- /* We only support one format for source pads */
- if (IS_SRC(code->pad)) {
- struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
-
- if (code->index)
- return -EINVAL;
-
- code->code = vdeb->src_code;
- } else {
+ /* For the sink pad we only support codes in the map_list */
+ if (IS_SINK(code->pad)) {
if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list))
return -EINVAL;
code->code = vimc_deb_pix_map_list[code->index].code;
+ return 0;
}
- return 0;
+ return vimc_enum_mbus_code(sd, cfg, code);
}
static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
- struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
-
if (fse->index)
return -EINVAL;
+ /* For the sink pad we only support codes in the map_list */
if (IS_SINK(fse->pad)) {
const struct vimc_deb_pix_map *vpix =
vimc_deb_pix_map_by_code(fse->code);
if (!vpix)
return -EINVAL;
- } else if (fse->code != vdeb->src_code) {
- return -EINVAL;
}
fse->min_width = VIMC_FRAME_MIN_WIDTH;
@@ -258,6 +265,9 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *sink_fmt;
+ if (!vimc_mbus_code_supported(fmt->format.code))
+ fmt->format.code = sink_fmt_default.code;
+
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Do not change the format while stream is on */
if (vdeb->src_frame)
@@ -270,11 +280,11 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
/*
* Do not change the format of the source pad,
- * it is propagated from the sink
+ * it is propagated from the sink (except for the code)
*/
if (IS_SRC(fmt->pad)) {
+ vdeb->src_code = fmt->format.code;
fmt->format = *sink_fmt;
- /* TODO: Add support for other formats */
fmt->format.code = vdeb->src_code;
} else {
/* Set the new format in the sink pad */
@@ -306,7 +316,7 @@ static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = {
.set_fmt = vimc_deb_set_fmt,
};
-static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb,
+static void vimc_deb_set_rgb_pix_rgb24(struct vimc_deb_device *vdeb,
unsigned int lin,
unsigned int col,
unsigned int rgb[3])
@@ -323,25 +333,38 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable)
struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
if (enable) {
- const struct vimc_pix_map *vpix;
+ u32 src_pixelformat = vdeb->ved.stream->producer_pixfmt;
+ const struct v4l2_format_info *pix_info;
unsigned int frame_size;
if (vdeb->src_frame)
return 0;
- /* Calculate the frame size of the source pad */
- vpix = vimc_pix_map_by_code(vdeb->src_code);
- frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height *
- vpix->bpp;
-
- /* Save the bytes per pixel of the sink */
- vpix = vimc_pix_map_by_code(vdeb->sink_fmt.code);
- vdeb->sink_bpp = vpix->bpp;
+ /* We only support translating bayer to RGB24 */
+ if (src_pixelformat != V4L2_PIX_FMT_RGB24) {
+ dev_err(vdeb->dev,
+ "translating to pixfmt (0x%08x) is not supported\n",
+ src_pixelformat);
+ return -EINVAL;
+ }
/* Get the corresponding pixel map from the table */
vdeb->sink_pix_map =
vimc_deb_pix_map_by_code(vdeb->sink_fmt.code);
+ /* Request bayer format from the pipeline for the sink pad */
+ vdeb->ved.stream->producer_pixfmt =
+ vdeb->sink_pix_map->pixelformat;
+
+ /* Calculate frame_size of the source */
+ pix_info = v4l2_format_info(src_pixelformat);
+ frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height *
+ pix_info->bpp[0];
+
+ /* Get bpp from the sink */
+ pix_info = v4l2_format_info(vdeb->sink_pix_map->pixelformat);
+ vdeb->sink_bpp = pix_info->bpp[0];
+
/*
* Allocate the frame buffer. Use vmalloc to be able to
* allocate a large amount of memory
@@ -489,6 +512,18 @@ static void *vimc_deb_process_frame(struct vimc_ent_device *ved,
}
+static void vimc_deb_release(struct v4l2_subdev *sd)
+{
+ struct vimc_deb_device *vdeb =
+ container_of(sd, struct vimc_deb_device, sd);
+
+ kfree(vdeb);
+}
+
+static const struct v4l2_subdev_internal_ops vimc_deb_int_ops = {
+ .release = vimc_deb_release,
+};
+
static void vimc_deb_comp_unbind(struct device *comp, struct device *master,
void *master_data)
{
@@ -497,7 +532,6 @@ static void vimc_deb_comp_unbind(struct device *comp, struct device *master,
ved);
vimc_ent_sd_unregister(ved, &vdeb->sd);
- kfree(vdeb);
}
static int vimc_deb_comp_bind(struct device *comp, struct device *master,
@@ -519,7 +553,7 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master,
MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2,
(const unsigned long[2]) {MEDIA_PAD_FL_SINK,
MEDIA_PAD_FL_SOURCE},
- &vimc_deb_ops);
+ &vimc_deb_int_ops, &vimc_deb_ops);
if (ret) {
kfree(vdeb);
return ret;
@@ -531,14 +565,14 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master,
/* Initialize the frame format */
vdeb->sink_fmt = sink_fmt_default;
+ vdeb->src_code = VIMC_DEB_SRC_MBUS_FMT_DEFAULT;
/*
* TODO: Add support for more output formats, we only support
- * RGB888 for now
+ * RGB24 for now.
* NOTE: the src format is always the same as the sink, except
* for the code
*/
- vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24;
- vdeb->set_rgb_src = vimc_deb_set_rgb_mbus_fmt_rgb888_1x24;
+ vdeb->set_rgb_src = vimc_deb_set_rgb_pix_rgb24;
return 0;
}
diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c
index 39b2a73dfcc1..8aecf8e92031 100644
--- a/drivers/media/platform/vimc/vimc-scaler.c
+++ b/drivers/media/platform/vimc/vimc-scaler.c
@@ -35,6 +35,12 @@ MODULE_PARM_DESC(sca_mult, " the image size multiplier");
#define IS_SRC(pad) (pad)
#define MAX_ZOOM 8
+static const u32 vimc_sca_supported_pixfmt[] = {
+ V4L2_PIX_FMT_BGR24,
+ V4L2_PIX_FMT_RGB24,
+ V4L2_PIX_FMT_ARGB32,
+};
+
struct vimc_sca_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
@@ -57,6 +63,16 @@ static const struct v4l2_mbus_framefmt sink_fmt_default = {
.colorspace = V4L2_COLORSPACE_DEFAULT,
};
+static bool vimc_sca_is_pixfmt_supported(u32 pixelformat)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vimc_sca_supported_pixfmt); i++)
+ if (vimc_sca_supported_pixfmt[i] == pixelformat)
+ return true;
+ return false;
+}
+
static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg)
{
@@ -76,35 +92,13 @@ static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
return 0;
}
-static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index);
-
- /* We don't support bayer format */
- if (!vpix || vpix->bayer)
- return -EINVAL;
-
- code->code = vpix->code;
-
- return 0;
-}
-
static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
- const struct vimc_pix_map *vpix;
-
if (fse->index)
return -EINVAL;
- /* Only accept code in the pix map table in non bayer format */
- vpix = vimc_pix_map_by_code(fse->code);
- if (!vpix || vpix->bayer)
- return -EINVAL;
-
fse->min_width = VIMC_FRAME_MIN_WIDTH;
fse->min_height = VIMC_FRAME_MIN_HEIGHT;
@@ -141,13 +135,6 @@ static int vimc_sca_get_fmt(struct v4l2_subdev *sd,
static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
{
- const struct vimc_pix_map *vpix;
-
- /* Only accept code in the pix map table in non bayer format */
- vpix = vimc_pix_map_by_code(fmt->code);
- if (!vpix || vpix->bayer)
- fmt->code = sink_fmt_default.code;
-
fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH,
VIMC_FRAME_MAX_WIDTH) & ~1;
fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT,
@@ -166,6 +153,9 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *sink_fmt;
+ if (!vimc_mbus_code_supported(fmt->format.code))
+ fmt->format.code = sink_fmt_default.code;
+
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Do not change the format while stream is on */
if (vsca->src_frame)
@@ -208,7 +198,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = {
.init_cfg = vimc_sca_init_cfg,
- .enum_mbus_code = vimc_sca_enum_mbus_code,
+ .enum_mbus_code = vimc_enum_mbus_code,
.enum_frame_size = vimc_sca_enum_frame_size,
.get_fmt = vimc_sca_get_fmt,
.set_fmt = vimc_sca_set_fmt,
@@ -219,15 +209,22 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
if (enable) {
- const struct vimc_pix_map *vpix;
+ u32 pixelformat = vsca->ved.stream->producer_pixfmt;
+ const struct v4l2_format_info *pix_info;
unsigned int frame_size;
if (vsca->src_frame)
return 0;
+ if (!vimc_sca_is_pixfmt_supported(pixelformat)) {
+ dev_err(vsca->dev, "pixfmt (0x%08x) is not supported\n",
+ pixelformat);
+ return -EINVAL;
+ }
+
/* Save the bytes per pixel of the sink */
- vpix = vimc_pix_map_by_code(vsca->sink_fmt.code);
- vsca->bpp = vpix->bpp;
+ pix_info = v4l2_format_info(pixelformat);
+ vsca->bpp = pix_info->bpp[0];
/* Calculate the width in bytes of the src frame */
vsca->src_line_size = vsca->sink_fmt.width *
@@ -348,6 +345,18 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved,
return vsca->src_frame;
};
+static void vimc_sca_release(struct v4l2_subdev *sd)
+{
+ struct vimc_sca_device *vsca =
+ container_of(sd, struct vimc_sca_device, sd);
+
+ kfree(vsca);
+}
+
+static const struct v4l2_subdev_internal_ops vimc_sca_int_ops = {
+ .release = vimc_sca_release,
+};
+
static void vimc_sca_comp_unbind(struct device *comp, struct device *master,
void *master_data)
{
@@ -356,7 +365,6 @@ static void vimc_sca_comp_unbind(struct device *comp, struct device *master,
ved);
vimc_ent_sd_unregister(ved, &vsca->sd);
- kfree(vsca);
}
@@ -379,7 +387,7 @@ static int vimc_sca_comp_bind(struct device *comp, struct device *master,
MEDIA_ENT_F_PROC_VIDEO_SCALER, 2,
(const unsigned long[2]) {MEDIA_PAD_FL_SINK,
MEDIA_PAD_FL_SOURCE},
- &vimc_sca_ops);
+ &vimc_sca_int_ops, &vimc_sca_ops);
if (ret) {
kfree(vsca);
return ret;
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c
index 59195f262623..081e54204c9f 100644
--- a/drivers/media/platform/vimc/vimc-sensor.c
+++ b/drivers/media/platform/vimc/vimc-sensor.c
@@ -65,34 +65,13 @@ static int vimc_sen_init_cfg(struct v4l2_subdev *sd,
return 0;
}
-static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code)
-{
- const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index);
-
- if (!vpix)
- return -EINVAL;
-
- code->code = vpix->code;
-
- return 0;
-}
-
static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_frame_size_enum *fse)
{
- const struct vimc_pix_map *vpix;
-
if (fse->index)
return -EINVAL;
- /* Only accept code in the pix map table */
- vpix = vimc_pix_map_by_code(fse->code);
- if (!vpix)
- return -EINVAL;
-
fse->min_width = VIMC_FRAME_MIN_WIDTH;
fse->max_width = VIMC_FRAME_MAX_WIDTH;
fse->min_height = VIMC_FRAME_MIN_HEIGHT;
@@ -117,14 +96,17 @@ static int vimc_sen_get_fmt(struct v4l2_subdev *sd,
static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen)
{
- const struct vimc_pix_map *vpix =
- vimc_pix_map_by_code(vsen->mbus_format.code);
+ u32 pixelformat = vsen->ved.stream->producer_pixfmt;
+ const struct v4l2_format_info *pix_info;
+
+ pix_info = v4l2_format_info(pixelformat);
tpg_reset_source(&vsen->tpg, vsen->mbus_format.width,
vsen->mbus_format.height, vsen->mbus_format.field);
- tpg_s_bytesperline(&vsen->tpg, 0, vsen->mbus_format.width * vpix->bpp);
+ tpg_s_bytesperline(&vsen->tpg, 0,
+ vsen->mbus_format.width * pix_info->bpp[0]);
tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height);
- tpg_s_fourcc(&vsen->tpg, vpix->pixelformat);
+ tpg_s_fourcc(&vsen->tpg, pixelformat);
/* TODO: add support for V4L2_FIELD_ALTERNATE */
tpg_s_field(&vsen->tpg, vsen->mbus_format.field, false);
tpg_s_colorspace(&vsen->tpg, vsen->mbus_format.colorspace);
@@ -135,13 +117,6 @@ static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen)
static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
{
- const struct vimc_pix_map *vpix;
-
- /* Only accept code in the pix map table */
- vpix = vimc_pix_map_by_code(fmt->code);
- if (!vpix)
- fmt->code = fmt_default.code;
-
fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH,
VIMC_FRAME_MAX_WIDTH) & ~1;
fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT,
@@ -161,6 +136,9 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
+ if (!vimc_mbus_code_supported(fmt->format.code))
+ fmt->format.code = fmt_default.code;
+
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Do not change the format while stream is on */
if (vsen->frame)
@@ -193,7 +171,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = {
.init_cfg = vimc_sen_init_cfg,
- .enum_mbus_code = vimc_sen_enum_mbus_code,
+ .enum_mbus_code = vimc_enum_mbus_code,
.enum_frame_size = vimc_sen_enum_frame_size,
.get_fmt = vimc_sen_get_fmt,
.set_fmt = vimc_sen_set_fmt,
@@ -215,7 +193,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
container_of(sd, struct vimc_sen_device, sd);
if (enable) {
- const struct vimc_pix_map *vpix;
+ u32 pixelformat = vsen->ved.stream->producer_pixfmt;
+ const struct v4l2_format_info *pix_info;
unsigned int frame_size;
if (vsen->kthread_sen)
@@ -223,8 +202,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
/* Calculate the frame size */
- vpix = vimc_pix_map_by_code(vsen->mbus_format.code);
- frame_size = vsen->mbus_format.width * vpix->bpp *
+ pix_info = v4l2_format_info(pixelformat);
+ frame_size = vsen->mbus_format.width * pix_info->bpp[0] *
vsen->mbus_format.height;
/*
@@ -301,6 +280,20 @@ static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = {
.s_ctrl = vimc_sen_s_ctrl,
};
+static void vimc_sen_release(struct v4l2_subdev *sd)
+{
+ struct vimc_sen_device *vsen =
+ container_of(sd, struct vimc_sen_device, sd);
+
+ v4l2_ctrl_handler_free(&vsen->hdl);
+ tpg_free(&vsen->tpg);
+ kfree(vsen);
+}
+
+static const struct v4l2_subdev_internal_ops vimc_sen_int_ops = {
+ .release = vimc_sen_release,
+};
+
static void vimc_sen_comp_unbind(struct device *comp, struct device *master,
void *master_data)
{
@@ -309,9 +302,6 @@ static void vimc_sen_comp_unbind(struct device *comp, struct device *master,
container_of(ved, struct vimc_sen_device, ved);
vimc_ent_sd_unregister(ved, &vsen->sd);
- v4l2_ctrl_handler_free(&vsen->hdl);
- tpg_free(&vsen->tpg);
- kfree(vsen);
}
/* Image Processing Controls */
@@ -371,7 +361,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
pdata->entity_name,
MEDIA_ENT_F_CAM_SENSOR, 1,
(const unsigned long[1]) {MEDIA_PAD_FL_SOURCE},
- &vimc_sen_ops);
+ &vimc_sen_int_ops, &vimc_sen_ops);
if (ret)
goto err_free_hdl;
diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c
index fcc897fb247b..26b674259489 100644
--- a/drivers/media/platform/vimc/vimc-streamer.c
+++ b/drivers/media/platform/vimc/vimc-streamer.c
@@ -46,19 +46,19 @@ static struct media_entity *vimc_get_source_entity(struct media_entity *ent)
*/
static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream)
{
- struct media_entity *entity;
+ struct vimc_ent_device *ved;
struct v4l2_subdev *sd;
while (stream->pipe_size) {
stream->pipe_size--;
- entity = stream->ved_pipeline[stream->pipe_size]->ent;
- entity = vimc_get_source_entity(entity);
+ ved = stream->ved_pipeline[stream->pipe_size];
+ ved->stream = NULL;
stream->ved_pipeline[stream->pipe_size] = NULL;
- if (!is_media_entity_v4l2_subdev(entity))
+ if (!is_media_entity_v4l2_subdev(ved->ent))
continue;
- sd = media_entity_to_v4l2_subdev(entity);
+ sd = media_entity_to_v4l2_subdev(ved->ent);
v4l2_subdev_call(sd, video, s_stream, 0);
}
}
@@ -88,19 +88,27 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
return -EINVAL;
}
stream->ved_pipeline[stream->pipe_size++] = ved;
+ ved->stream = stream;
+
+ if (is_media_entity_v4l2_subdev(ved->ent)) {
+ sd = media_entity_to_v4l2_subdev(ved->ent);
+ ret = v4l2_subdev_call(sd, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD) {
+ pr_err("subdev_call error %s\n",
+ ved->ent->name);
+ vimc_streamer_pipeline_terminate(stream);
+ return ret;
+ }
+ }
entity = vimc_get_source_entity(ved->ent);
/* Check if the end of the pipeline was reached*/
if (!entity)
return 0;
+ /* Get the next device in the pipeline */
if (is_media_entity_v4l2_subdev(entity)) {
sd = media_entity_to_v4l2_subdev(entity);
- ret = v4l2_subdev_call(sd, video, s_stream, 1);
- if (ret && ret != -ENOIOCTLCMD) {
- vimc_streamer_pipeline_terminate(stream);
- return ret;
- }
ved = v4l2_get_subdevdata(sd);
} else {
vdev = container_of(entity,
@@ -117,10 +125,10 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
static int vimc_streamer_thread(void *data)
{
struct vimc_stream *stream = data;
+ u8 *frame = NULL;
int i;
set_freezable();
- set_current_state(TASK_UNINTERRUPTIBLE);
for (;;) {
try_to_freeze();
@@ -128,15 +136,13 @@ static int vimc_streamer_thread(void *data)
break;
for (i = stream->pipe_size - 1; i >= 0; i--) {
- stream->frame = stream->ved_pipeline[i]->process_frame(
- stream->ved_pipeline[i],
- stream->frame);
- if (!stream->frame)
- break;
- if (IS_ERR(stream->frame))
+ frame = stream->ved_pipeline[i]->process_frame(
+ stream->ved_pipeline[i], frame);
+ if (!frame || IS_ERR(frame))
break;
}
//wait for 60hz
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ / 60);
}
diff --git a/drivers/media/platform/vimc/vimc-streamer.h b/drivers/media/platform/vimc/vimc-streamer.h
index 752af2e2d5a2..2b3667408794 100644
--- a/drivers/media/platform/vimc/vimc-streamer.h
+++ b/drivers/media/platform/vimc/vimc-streamer.h
@@ -15,12 +15,32 @@
#define VIMC_STREAMER_PIPELINE_MAX_SIZE 16
+/**
+ * struct vimc_stream - struct that represents a stream in the pipeline
+ *
+ * @pipe: the media pipeline object associated with this stream
+ * @ved_pipeline: array containing all the entities participating in the
+ * stream. The order is from a video device (usually a capture device) where
+ * stream_on was called, to the entity generating the first base image to be
+ * processed in the pipeline.
+ * @pipe_size: size of @ved_pipeline
+ * @kthread: thread that generates the frames of the stream.
+ * @producer_pixfmt: the pixel format requested from the pipeline. This must
+ * be set just before calling vimc_streamer_s_stream(ent, 1). This value is
+ * propagated up to the source of the base image (usually a sensor node) and
+ * can be modified by entities during s_stream callback to request a different
+ * format from rest of the pipeline.
+ *
+ * When the user call stream_on in a video device, struct vimc_stream is
+ * used to keep track of all entities and subdevices that generates and
+ * process frames for the stream.
+ */
struct vimc_stream {
struct media_pipeline pipe;
struct vimc_ent_device *ved_pipeline[VIMC_STREAMER_PIPELINE_MAX_SIZE];
unsigned int pipe_size;
- u8 *frame;
struct task_struct *kthread;
+ u32 producer_pixfmt;
};
/**
diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig
index 154de92dd809..4b51d4d6cf93 100644
--- a/drivers/media/platform/vivid/Kconfig
+++ b/drivers/media/platform/vivid/Kconfig
@@ -11,7 +11,7 @@ config VIDEO_VIVID
select VIDEOBUF2_DMA_CONTIG
select VIDEO_V4L2_TPG
default n
- ---help---
+ help
Enables a virtual video driver. This driver emulates a webcam,
TV, S-Video and HDMI capture hardware, including VBI support for
the SDTV inputs. Also video output, VBI output, radio receivers,
@@ -28,7 +28,7 @@ config VIDEO_VIVID_CEC
bool "Enable CEC emulation support"
depends on VIDEO_VIVID
select CEC_CORE
- ---help---
+ help
When selected the vivid module will emulate the optional
HDMI CEC feature.
@@ -36,6 +36,6 @@ config VIDEO_VIVID_MAX_DEVS
int "Maximum number of devices"
depends on VIDEO_VIVID
default "64"
- ---help---
+ help
This allows you to specify the maximum number of devices supported
by the vivid driver.
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index 342e0e6c103b..7047df6f0e0e 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -681,7 +681,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->v4l2_dev.mdev = &dev->mdev;
/* Initialize media device */
- strlcpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model));
+ strscpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model));
snprintf(dev->mdev.bus_info, sizeof(dev->mdev.bus_info),
"platform:%s-%03d", VIVID_MODULE_NAME, inst);
dev->mdev.dev = &pdev->dev;
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 52eeda624d7e..530ac8decb25 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -1007,7 +1007,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection
v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect);
if (dev->bitmap_cap && (compose->width != s->r.width ||
compose->height != s->r.height)) {
- kfree(dev->bitmap_cap);
+ vfree(dev->bitmap_cap);
dev->bitmap_cap = NULL;
}
*compose = s->r;
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index e61b91b414f9..9350ca65dd91 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -798,7 +798,7 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection
s->r.height *= factor;
if (dev->bitmap_out && (compose->width != s->r.width ||
compose->height != s->r.height)) {
- kfree(dev->bitmap_out);
+ vfree(dev->bitmap_out);
dev->bitmap_out = NULL;
}
*compose = s->r;
@@ -941,15 +941,19 @@ int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv,
return ret;
if (win->bitmap) {
- new_bitmap = memdup_user(win->bitmap, bitmap_size);
+ new_bitmap = vzalloc(bitmap_size);
- if (IS_ERR(new_bitmap))
- return PTR_ERR(new_bitmap);
+ if (!new_bitmap)
+ return -ENOMEM;
+ if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) {
+ vfree(new_bitmap);
+ return -EFAULT;
+ }
}
dev->overlay_out_top = win->w.top;
dev->overlay_out_left = win->w.left;
- kfree(dev->bitmap_out);
+ vfree(dev->bitmap_out);
dev->bitmap_out = new_bitmap;
dev->clipcount_out = win->clipcount;
if (dev->clipcount_out)
diff --git a/drivers/media/platform/vsp1/vsp1_brx.c b/drivers/media/platform/vsp1/vsp1_brx.c
index 58ad248cd7f7..2d86c718a5cf 100644
--- a/drivers/media/platform/vsp1/vsp1_brx.c
+++ b/drivers/media/platform/vsp1/vsp1_brx.c
@@ -283,6 +283,7 @@ static const struct v4l2_subdev_ops brx_ops = {
static void brx_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_brx *brx = to_brx(&entity->subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_clu.c b/drivers/media/platform/vsp1/vsp1_clu.c
index 942fc14c19d1..a47b23bf5abf 100644
--- a/drivers/media/platform/vsp1/vsp1_clu.c
+++ b/drivers/media/platform/vsp1/vsp1_clu.c
@@ -171,6 +171,7 @@ static const struct v4l2_subdev_ops clu_ops = {
static void clu_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_clu *clu = to_clu(&entity->subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 26289adaf658..104b6f514536 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -178,7 +178,7 @@ struct vsp1_dl_cmd_pool {
* @post_cmd: post command to be issued through extended dl header
* @has_chain: if true, indicates that there's a partition chain
* @chain: entry in the display list partition chain
- * @internal: whether the display list is used for internal purpose
+ * @flags: display list flags, a combination of VSP1_DL_FRAME_END_*
*/
struct vsp1_dl_list {
struct list_head list;
@@ -197,7 +197,7 @@ struct vsp1_dl_list {
bool has_chain;
struct list_head chain;
- bool internal;
+ unsigned int flags;
};
/**
@@ -699,8 +699,8 @@ struct vsp1_dl_body *vsp1_dl_list_get_body0(struct vsp1_dl_list *dl)
* which bodies are added.
*
* Adding a body to a display list passes ownership of the body to the list. The
- * caller retains its reference to the fragment when adding it to the display
- * list, but is not allowed to add new entries to the body.
+ * caller retains its reference to the body when adding it to the display list,
+ * but is not allowed to add new entries to the body.
*
* The reference must be explicitly released by a call to vsp1_dl_body_put()
* when the body isn't needed anymore.
@@ -770,17 +770,35 @@ static void vsp1_dl_list_fill_header(struct vsp1_dl_list *dl, bool is_last)
}
dl->header->num_lists = num_lists;
+ dl->header->flags = 0;
- if (!list_empty(&dl->chain) && !is_last) {
+ /*
+ * Enable the interrupt for the end of each frame. In continuous mode
+ * chained lists are used with one list per frame, so enable the
+ * interrupt for each list. In singleshot mode chained lists are used
+ * to partition a single frame, so enable the interrupt for the last
+ * list only.
+ */
+ if (!dlm->singleshot || is_last)
+ dl->header->flags |= VSP1_DLH_INT_ENABLE;
+
+ /*
+ * In continuous mode enable auto-start for all lists, as the VSP must
+ * loop on the same list until a new one is queued. In singleshot mode
+ * enable auto-start for all lists but the last to chain processing of
+ * partitions without software intervention.
+ */
+ if (!dlm->singleshot || !is_last)
+ dl->header->flags |= VSP1_DLH_AUTO_START;
+
+ if (!is_last) {
/*
- * If this display list's chain is not empty, we are on a list,
- * and the next item is the display list that we must queue for
- * automatic processing by the hardware.
+ * If this is not the last display list in the chain, queue the
+ * next item for automatic processing by the hardware.
*/
struct vsp1_dl_list *next = list_next_entry(dl, chain);
dl->header->next_header = next->dma;
- dl->header->flags = VSP1_DLH_AUTO_START;
} else if (!dlm->singleshot) {
/*
* if the display list manager works in continuous mode, the VSP
@@ -788,13 +806,6 @@ static void vsp1_dl_list_fill_header(struct vsp1_dl_list *dl, bool is_last)
* instructed to do otherwise.
*/
dl->header->next_header = dl->dma;
- dl->header->flags = VSP1_DLH_INT_ENABLE | VSP1_DLH_AUTO_START;
- } else {
- /*
- * Otherwise, in mem-to-mem mode, we work in single-shot mode
- * and the next display list must not be started automatically.
- */
- dl->header->flags = VSP1_DLH_INT_ENABLE;
}
if (!dl->extension)
@@ -861,13 +872,15 @@ static void vsp1_dl_list_commit_continuous(struct vsp1_dl_list *dl)
*
* If a display list is already pending we simply drop it as the new
* display list is assumed to contain a more recent configuration. It is
- * an error if the already pending list has the internal flag set, as
- * there is then a process waiting for that list to complete. This
- * shouldn't happen as the waiting process should perform proper
- * locking, but warn just in case.
+ * an error if the already pending list has the
+ * VSP1_DL_FRAME_END_INTERNAL flag set, as there is then a process
+ * waiting for that list to complete. This shouldn't happen as the
+ * waiting process should perform proper locking, but warn just in
+ * case.
*/
if (vsp1_dl_list_hw_update_pending(dlm)) {
- WARN_ON(dlm->pending && dlm->pending->internal);
+ WARN_ON(dlm->pending &&
+ (dlm->pending->flags & VSP1_DL_FRAME_END_INTERNAL));
__vsp1_dl_list_put(dlm->pending);
dlm->pending = dl;
return;
@@ -897,7 +910,7 @@ static void vsp1_dl_list_commit_singleshot(struct vsp1_dl_list *dl)
dlm->active = dl;
}
-void vsp1_dl_list_commit(struct vsp1_dl_list *dl, bool internal)
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl, unsigned int dl_flags)
{
struct vsp1_dl_manager *dlm = dl->dlm;
struct vsp1_dl_list *dl_next;
@@ -912,7 +925,7 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl, bool internal)
vsp1_dl_list_fill_header(dl_next, last);
}
- dl->internal = internal;
+ dl->flags = dl_flags & ~VSP1_DL_FRAME_END_COMPLETED;
spin_lock_irqsave(&dlm->lock, flags);
@@ -941,9 +954,13 @@ void vsp1_dl_list_commit(struct vsp1_dl_list *dl, bool internal)
* set in single-shot mode as display list processing is then not continuous and
* races never occur.
*
- * The VSP1_DL_FRAME_END_INTERNAL flag indicates that the previous display list
- * has completed and had been queued with the internal notification flag.
- * Internal notification is only supported for continuous mode.
+ * The following flags are only supported for continuous mode.
+ *
+ * The VSP1_DL_FRAME_END_INTERNAL flag indicates that the display list that just
+ * became active had been queued with the internal notification flag.
+ *
+ * The VSP1_DL_FRAME_END_WRITEBACK flag indicates that the previously active
+ * display list had been queued with the writeback flag.
*/
unsigned int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
{
@@ -982,13 +999,24 @@ unsigned int vsp1_dlm_irq_frame_end(struct vsp1_dl_manager *dlm)
goto done;
/*
+ * If the active display list has the writeback flag set, the frame
+ * completion marks the end of the writeback capture. Return the
+ * VSP1_DL_FRAME_END_WRITEBACK flag and reset the display list's
+ * writeback flag.
+ */
+ if (dlm->active && (dlm->active->flags & VSP1_DL_FRAME_END_WRITEBACK)) {
+ flags |= VSP1_DL_FRAME_END_WRITEBACK;
+ dlm->active->flags &= ~VSP1_DL_FRAME_END_WRITEBACK;
+ }
+
+ /*
* The device starts processing the queued display list right after the
* frame end interrupt. The display list thus becomes active.
*/
if (dlm->queued) {
- if (dlm->queued->internal)
+ if (dlm->queued->flags & VSP1_DL_FRAME_END_INTERNAL)
flags |= VSP1_DL_FRAME_END_INTERNAL;
- dlm->queued->internal = false;
+ dlm->queued->flags &= ~VSP1_DL_FRAME_END_INTERNAL;
__vsp1_dl_list_put(dlm->active);
dlm->active = dlm->queued;
diff --git a/drivers/media/platform/vsp1/vsp1_dl.h b/drivers/media/platform/vsp1/vsp1_dl.h
index 125750dc8b5c..bebe16483ca5 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.h
+++ b/drivers/media/platform/vsp1/vsp1_dl.h
@@ -17,8 +17,10 @@ struct vsp1_dl_body_pool;
struct vsp1_dl_list;
struct vsp1_dl_manager;
+/* Keep these flags in sync with VSP1_DU_STATUS_* in include/media/vsp1.h. */
#define VSP1_DL_FRAME_END_COMPLETED BIT(0)
-#define VSP1_DL_FRAME_END_INTERNAL BIT(1)
+#define VSP1_DL_FRAME_END_WRITEBACK BIT(1)
+#define VSP1_DL_FRAME_END_INTERNAL BIT(2)
/**
* struct vsp1_dl_ext_cmd - Extended Display command
@@ -61,7 +63,7 @@ struct vsp1_dl_list *vsp1_dl_list_get(struct vsp1_dl_manager *dlm);
void vsp1_dl_list_put(struct vsp1_dl_list *dl);
struct vsp1_dl_body *vsp1_dl_list_get_body0(struct vsp1_dl_list *dl);
struct vsp1_dl_ext_cmd *vsp1_dl_get_pre_cmd(struct vsp1_dl_list *dl);
-void vsp1_dl_list_commit(struct vsp1_dl_list *dl, bool internal);
+void vsp1_dl_list_commit(struct vsp1_dl_list *dl, unsigned int dl_flags);
struct vsp1_dl_body_pool *
vsp1_dl_body_pool_create(struct vsp1_device *vsp1, unsigned int num_bodies,
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 84895385d2e5..a4a45d68a6ef 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -34,14 +34,16 @@ static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe,
unsigned int completion)
{
struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
- bool complete = completion == VSP1_DL_FRAME_END_COMPLETED;
if (drm_pipe->du_complete) {
struct vsp1_entity *uif = drm_pipe->uif;
+ unsigned int status = completion
+ & (VSP1_DU_STATUS_COMPLETE |
+ VSP1_DU_STATUS_WRITEBACK);
u32 crc;
crc = uif ? vsp1_uif_get_crc(to_uif(&uif->subdev)) : 0;
- drm_pipe->du_complete(drm_pipe->du_private, complete, crc);
+ drm_pipe->du_complete(drm_pipe->du_private, status, crc);
}
if (completion & VSP1_DL_FRAME_END_INTERNAL) {
@@ -537,6 +539,12 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
struct vsp1_entity *next;
struct vsp1_dl_list *dl;
struct vsp1_dl_body *dlb;
+ unsigned int dl_flags = 0;
+
+ if (drm_pipe->force_brx_release)
+ dl_flags |= VSP1_DL_FRAME_END_INTERNAL;
+ if (pipe->output->writeback)
+ dl_flags |= VSP1_DL_FRAME_END_WRITEBACK;
dl = vsp1_dl_list_get(pipe->output->dlm);
dlb = vsp1_dl_list_get_body0(dl);
@@ -554,12 +562,42 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
}
vsp1_entity_route_setup(entity, pipe, dlb);
- vsp1_entity_configure_stream(entity, pipe, dlb);
+ vsp1_entity_configure_stream(entity, pipe, dl, dlb);
vsp1_entity_configure_frame(entity, pipe, dl, dlb);
vsp1_entity_configure_partition(entity, pipe, dl, dlb);
}
- vsp1_dl_list_commit(dl, drm_pipe->force_brx_release);
+ vsp1_dl_list_commit(dl, dl_flags);
+}
+
+static int vsp1_du_pipeline_set_rwpf_format(struct vsp1_device *vsp1,
+ struct vsp1_rwpf *rwpf,
+ u32 pixelformat, unsigned int pitch)
+{
+ const struct vsp1_format_info *fmtinfo;
+ unsigned int chroma_hsub;
+
+ fmtinfo = vsp1_get_format_info(vsp1, pixelformat);
+ if (!fmtinfo) {
+ dev_dbg(vsp1->dev, "Unsupported pixel format %08x\n",
+ pixelformat);
+ return -EINVAL;
+ }
+
+ /*
+ * Only formats with three planes can affect the chroma planes pitch.
+ * All formats with two planes have a horizontal subsampling value of 2,
+ * but combine U and V in a single chroma plane, which thus results in
+ * the luma plane and chroma plane having the same pitch.
+ */
+ chroma_hsub = (fmtinfo->planes == 3) ? fmtinfo->hsub : 1;
+
+ rwpf->fmtinfo = fmtinfo;
+ rwpf->format.num_planes = fmtinfo->planes;
+ rwpf->format.plane_fmt[0].bytesperline = pitch;
+ rwpf->format.plane_fmt[1].bytesperline = pitch / chroma_hsub;
+
+ return 0;
}
/* -----------------------------------------------------------------------------
@@ -700,8 +738,8 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
drm_pipe->du_private = cfg->callback_data;
/* Disable the display interrupts. */
- vsp1_write(vsp1, VI6_DISP_IRQ_STA, 0);
- vsp1_write(vsp1, VI6_DISP_IRQ_ENB, 0);
+ vsp1_write(vsp1, VI6_DISP_IRQ_STA(pipe_index), 0);
+ vsp1_write(vsp1, VI6_DISP_IRQ_ENB(pipe_index), 0);
/* Configure all entities in the pipeline. */
vsp1_du_pipeline_configure(pipe);
@@ -769,9 +807,8 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
{
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
- const struct vsp1_format_info *fmtinfo;
- unsigned int chroma_hsub;
struct vsp1_rwpf *rpf;
+ int ret;
if (rpf_index >= vsp1->info->rpf_count)
return -EINVAL;
@@ -804,25 +841,11 @@ int vsp1_du_atomic_update(struct device *dev, unsigned int pipe_index,
* Store the format, stride, memory buffer address, crop and compose
* rectangles and Z-order position and for the input.
*/
- fmtinfo = vsp1_get_format_info(vsp1, cfg->pixelformat);
- if (!fmtinfo) {
- dev_dbg(vsp1->dev, "Unsupported pixel format %08x for RPF\n",
- cfg->pixelformat);
- return -EINVAL;
- }
-
- /*
- * Only formats with three planes can affect the chroma planes pitch.
- * All formats with two planes have a horizontal subsampling value of 2,
- * but combine U and V in a single chroma plane, which thus results in
- * the luma plane and chroma plane having the same pitch.
- */
- chroma_hsub = (fmtinfo->planes == 3) ? fmtinfo->hsub : 1;
+ ret = vsp1_du_pipeline_set_rwpf_format(vsp1, rpf, cfg->pixelformat,
+ cfg->pitch);
+ if (ret < 0)
+ return ret;
- rpf->fmtinfo = fmtinfo;
- rpf->format.num_planes = fmtinfo->planes;
- rpf->format.plane_fmt[0].bytesperline = cfg->pitch;
- rpf->format.plane_fmt[1].bytesperline = cfg->pitch / chroma_hsub;
rpf->alpha = cfg->alpha;
rpf->mem.addr[0] = cfg->mem[0];
@@ -851,12 +874,31 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index,
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
struct vsp1_drm_pipeline *drm_pipe = &vsp1->drm->pipe[pipe_index];
struct vsp1_pipeline *pipe = &drm_pipe->pipe;
+ int ret;
drm_pipe->crc = cfg->crc;
mutex_lock(&vsp1->drm->lock);
+
+ if (cfg->writeback.pixelformat) {
+ const struct vsp1_du_writeback_config *wb_cfg = &cfg->writeback;
+
+ ret = vsp1_du_pipeline_set_rwpf_format(vsp1, pipe->output,
+ wb_cfg->pixelformat,
+ wb_cfg->pitch);
+ if (WARN_ON(ret < 0))
+ goto done;
+
+ pipe->output->mem.addr[0] = wb_cfg->mem[0];
+ pipe->output->mem.addr[1] = wb_cfg->mem[1];
+ pipe->output->mem.addr[2] = wb_cfg->mem[2];
+ pipe->output->writeback = true;
+ }
+
vsp1_du_pipeline_setup_inputs(vsp1, pipe);
vsp1_du_pipeline_configure(pipe);
+
+done:
mutex_unlock(&vsp1->drm->lock);
}
EXPORT_SYMBOL_GPL(vsp1_du_atomic_flush);
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h
index 8dfd274a59e2..e85ad4366fbb 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -42,7 +42,7 @@ struct vsp1_drm_pipeline {
struct vsp1_du_crc_config crc;
/* Frame synchronisation */
- void (*du_complete)(void *data, bool completed, u32 crc);
+ void (*du_complete)(void *data, unsigned int status, u32 crc);
void *du_private;
};
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index a54ab528b060..aa9d2286056e 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -71,10 +71,11 @@ void vsp1_entity_route_setup(struct vsp1_entity *entity,
void vsp1_entity_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
if (entity->ops->configure_stream)
- entity->ops->configure_stream(entity, pipe, dlb);
+ entity->ops->configure_stream(entity, pipe, dl, dlb);
}
void vsp1_entity_configure_frame(struct vsp1_entity *entity,
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 97acb7795cf1..a1ceb37bb837 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -67,7 +67,9 @@ struct vsp1_route {
* struct vsp1_entity_operations - Entity operations
* @destroy: Destroy the entity.
* @configure_stream: Setup the hardware parameters for the stream which do
- * not vary between frames (pipeline, formats).
+ * not vary between frames (pipeline, formats). Note that
+ * the vsp1_dl_list argument is only valid for display
+ * pipeline and will be NULL for mem-to-mem pipelines.
* @configure_frame: Configure the runtime parameters for each frame.
* @configure_partition: Configure partition specific parameters.
* @max_width: Return the max supported width of data that the entity can
@@ -78,7 +80,7 @@ struct vsp1_route {
struct vsp1_entity_operations {
void (*destroy)(struct vsp1_entity *);
void (*configure_stream)(struct vsp1_entity *, struct vsp1_pipeline *,
- struct vsp1_dl_body *);
+ struct vsp1_dl_list *, struct vsp1_dl_body *);
void (*configure_frame)(struct vsp1_entity *, struct vsp1_pipeline *,
struct vsp1_dl_list *, struct vsp1_dl_body *);
void (*configure_partition)(struct vsp1_entity *,
@@ -155,6 +157,7 @@ void vsp1_entity_route_setup(struct vsp1_entity *entity,
void vsp1_entity_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb);
void vsp1_entity_configure_frame(struct vsp1_entity *entity,
diff --git a/drivers/media/platform/vsp1/vsp1_hgo.c b/drivers/media/platform/vsp1/vsp1_hgo.c
index 827373c25351..bf3f981f93a1 100644
--- a/drivers/media/platform/vsp1/vsp1_hgo.c
+++ b/drivers/media/platform/vsp1/vsp1_hgo.c
@@ -131,6 +131,7 @@ static const struct v4l2_ctrl_config hgo_num_bins_control = {
static void hgo_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_hgo *hgo = to_hgo(&entity->subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_hgt.c b/drivers/media/platform/vsp1/vsp1_hgt.c
index bb6ce6fdd5f4..aa1c718e0453 100644
--- a/drivers/media/platform/vsp1/vsp1_hgt.c
+++ b/drivers/media/platform/vsp1/vsp1_hgt.c
@@ -127,6 +127,7 @@ static const struct v4l2_ctrl_config hgt_hue_areas = {
static void hgt_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_hgt *hgt = to_hgt(&entity->subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 39ab2e0c7c18..d5ebd9d08c8a 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -129,6 +129,7 @@ static const struct v4l2_subdev_ops hsit_ops = {
static void hsit_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_hsit *hsit = to_hsit(&entity->subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index 8b0a26335d70..14ed5d7bd061 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -84,6 +84,7 @@ static const struct v4l2_subdev_ops lif_ops = {
static void lif_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
const struct v4l2_mbus_framefmt *format;
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index 64c48d9459b0..9f88842d7048 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -147,6 +147,7 @@ static const struct v4l2_subdev_ops lut_ops = {
static void lut_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_lut *lut = to_lut(&entity->subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 54ff539ffea0..f72ac01c21ea 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -42,6 +42,30 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
1, { 16, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_RGBA444, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGBA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_RGBX444, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGBX_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_ABGR444, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XBGR444, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_BGRA444, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_BGRX444, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
@@ -50,6 +74,30 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
1, { 16, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_RGBA555, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGBA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_RGBX555, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGBX_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_ABGR555, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XBGR555, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_BGRA555, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_BGRX555, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
@@ -68,6 +116,20 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
{ V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
1, { 32, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_BGRA32, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_BGRX32, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_RGBA32, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_RGBX32, MEDIA_BUS_FMT_ARGB8888_1X32,
+ VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index f6e4157095cc..1bb1d39c60d9 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -39,12 +39,12 @@
#define VI6_WFP_IRQ_STA_DFE (1 << 1)
#define VI6_WFP_IRQ_STA_FRE (1 << 0)
-#define VI6_DISP_IRQ_ENB 0x0078
+#define VI6_DISP_IRQ_ENB(n) (0x0078 + (n) * 60)
#define VI6_DISP_IRQ_ENB_DSTE (1 << 8)
#define VI6_DISP_IRQ_ENB_MAEE (1 << 5)
#define VI6_DISP_IRQ_ENB_LNEE(n) (1 << (n))
-#define VI6_DISP_IRQ_STA 0x007c
+#define VI6_DISP_IRQ_STA(n) (0x007c + (n) * 60)
#define VI6_DISP_IRQ_STA_DST (1 << 8)
#define VI6_DISP_IRQ_STA_MAE (1 << 5)
#define VI6_DISP_IRQ_STA_LNE(n) (1 << (n))
@@ -307,7 +307,7 @@
#define VI6_WPF_DSTM_ADDR_C0 0x1028
#define VI6_WPF_DSTM_ADDR_C1 0x102c
-#define VI6_WPF_WRBCK_CTRL 0x1034
+#define VI6_WPF_WRBCK_CTRL(n) (0x1034 + (n) * 0x100)
#define VI6_WPF_WRBCK_CTRL_WBMD (1 << 0)
/* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index 616afa7e165f..85587c1b6a37 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -57,6 +57,7 @@ static const struct v4l2_subdev_ops rpf_ops = {
static void rpf_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 70742ecf766f..2f3582590618 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -61,6 +61,7 @@ struct vsp1_rwpf {
} flip;
struct vsp1_rwpf_memory mem;
+ bool writeback;
struct vsp1_dl_manager *dlm;
};
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index b1617cb1f2b9..2b65457ee12f 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -269,6 +269,7 @@ static const struct v4l2_subdev_ops sru_ops = {
static void sru_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
const struct vsp1_sru_param *param;
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 27012af973b2..5fc04c082d1a 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -257,6 +257,7 @@ static const struct v4l2_subdev_ops uds_ops = {
static void uds_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_uds *uds = to_uds(&entity->subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_uif.c b/drivers/media/platform/vsp1/vsp1_uif.c
index 4b58d51df231..467d1072577b 100644
--- a/drivers/media/platform/vsp1/vsp1_uif.c
+++ b/drivers/media/platform/vsp1/vsp1_uif.c
@@ -192,6 +192,7 @@ static const struct v4l2_subdev_ops uif_ops = {
static void uif_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_uif *uif = to_uif(&entity->subdev);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 7ceaf3222145..fd98e483b2f4 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -307,11 +307,6 @@ static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
* This function completes the current buffer by filling its sequence number,
* time stamp and payload size, and hands it back to the videobuf core.
*
- * When operating in DU output mode (deep pipeline to the DU through the LIF),
- * the VSP1 needs to constantly supply frames to the display. In that case, if
- * no other buffer is queued, reuse the one that has just been processed instead
- * of handing it back to the videobuf core.
- *
* Return the next queued buffer or NULL if the queue is empty.
*/
static struct vsp1_vb2_buffer *
@@ -333,12 +328,6 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
done = list_first_entry(&video->irqqueue,
struct vsp1_vb2_buffer, queue);
- /* In DU output mode reuse the buffer if the list is singular. */
- if (pipe->lif && list_is_singular(&video->irqqueue)) {
- spin_unlock_irqrestore(&video->irqlock, flags);
- return done;
- }
-
list_del(&done->queue);
if (!list_empty(&video->irqqueue))
@@ -432,7 +421,7 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
}
/* Complete, and commit the head display list. */
- vsp1_dl_list_commit(dl, false);
+ vsp1_dl_list_commit(dl, 0);
pipe->configured = true;
vsp1_pipeline_run(pipe);
@@ -836,7 +825,8 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
list_for_each_entry(entity, &pipe->entities, list_pipe) {
vsp1_entity_route_setup(entity, pipe, pipe->stream_config);
- vsp1_entity_configure_stream(entity, pipe, pipe->stream_config);
+ vsp1_entity_configure_stream(entity, pipe, NULL,
+ pipe->stream_config);
}
return 0;
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 32bb207b2007..208498fa6ed7 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -232,17 +232,41 @@ static void vsp1_wpf_destroy(struct vsp1_entity *entity)
vsp1_dlm_destroy(wpf->dlm);
}
+static int wpf_configure_writeback_chain(struct vsp1_rwpf *wpf,
+ struct vsp1_dl_list *dl)
+{
+ unsigned int index = wpf->entity.index;
+ struct vsp1_dl_list *dl_next;
+ struct vsp1_dl_body *dlb;
+
+ dl_next = vsp1_dl_list_get(wpf->dlm);
+ if (!dl_next) {
+ dev_err(wpf->entity.vsp1->dev,
+ "Failed to obtain a dl list, disabling writeback\n");
+ return -ENOMEM;
+ }
+
+ dlb = vsp1_dl_list_get_body0(dl_next);
+ vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(index), 0);
+ vsp1_dl_list_add_chain(dl, dl_next);
+
+ return 0;
+}
+
static void wpf_configure_stream(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
struct vsp1_device *vsp1 = wpf->entity.vsp1;
const struct v4l2_mbus_framefmt *source_format;
const struct v4l2_mbus_framefmt *sink_format;
+ unsigned int index = wpf->entity.index;
unsigned int i;
u32 outfmt = 0;
u32 srcrpf = 0;
+ int ret;
sink_format = vsp1_entity_get_pad_format(&wpf->entity,
wpf->entity.config,
@@ -250,8 +274,9 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
source_format = vsp1_entity_get_pad_format(&wpf->entity,
wpf->entity.config,
RWPF_PAD_SOURCE);
+
/* Format */
- if (!pipe->lif) {
+ if (!pipe->lif || wpf->writeback) {
const struct v4l2_pix_format_mplane *format = &wpf->format;
const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
@@ -276,8 +301,7 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
vsp1_wpf_write(wpf, dlb, VI6_WPF_DSWAP, fmtinfo->swap);
- if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP) &&
- wpf->entity.index == 0)
+ if (vsp1_feature(vsp1, VSP1_HAS_WPF_HFLIP) && index == 0)
vsp1_wpf_write(wpf, dlb, VI6_WPF_ROT_CTRL,
VI6_WPF_ROT_CTRL_LN16 |
(256 << VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT));
@@ -288,11 +312,9 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
wpf->outfmt = outfmt;
- vsp1_dl_body_write(dlb, VI6_DPR_WPF_FPORCH(wpf->entity.index),
+ vsp1_dl_body_write(dlb, VI6_DPR_WPF_FPORCH(index),
VI6_DPR_WPF_FPORCH_FP_WPFN);
- vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL, 0);
-
/*
* Sources. If the pipeline has a single input and BRx is not used,
* configure it as the master layer. Otherwise configure all
@@ -318,9 +340,26 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
vsp1_wpf_write(wpf, dlb, VI6_WPF_SRCRPF, srcrpf);
/* Enable interrupts. */
- vsp1_dl_body_write(dlb, VI6_WPF_IRQ_STA(wpf->entity.index), 0);
- vsp1_dl_body_write(dlb, VI6_WPF_IRQ_ENB(wpf->entity.index),
+ vsp1_dl_body_write(dlb, VI6_WPF_IRQ_STA(index), 0);
+ vsp1_dl_body_write(dlb, VI6_WPF_IRQ_ENB(index),
VI6_WFP_IRQ_ENB_DFEE);
+
+ /*
+ * Configure writeback for display pipelines (the wpf writeback flag is
+ * never set for memory-to-memory pipelines). Start by adding a chained
+ * display list to disable writeback after a single frame, and process
+ * to enable writeback. If the display list allocation fails don't
+ * enable writeback as we wouldn't be able to safely disable it,
+ * resulting in possible memory corruption.
+ */
+ if (wpf->writeback) {
+ ret = wpf_configure_writeback_chain(wpf, dl);
+ if (ret < 0)
+ wpf->writeback = false;
+ }
+
+ vsp1_dl_body_write(dlb, VI6_WPF_WRBCK_CTRL(index),
+ wpf->writeback ? VI6_WPF_WRBCK_CTRL_WBMD : 0);
}
static void wpf_configure_frame(struct vsp1_entity *entity,
@@ -362,6 +401,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
unsigned int width;
unsigned int height;
+ unsigned int left;
unsigned int offset;
unsigned int flip;
unsigned int i;
@@ -371,13 +411,16 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
RWPF_PAD_SINK);
width = sink_format->width;
height = sink_format->height;
+ left = 0;
/*
* Cropping. The partition algorithm can split the image into
* multiple slices.
*/
- if (pipe->partitions > 1)
+ if (pipe->partitions > 1) {
width = pipe->partition->wpf.width;
+ left = pipe->partition->wpf.left;
+ }
vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
(0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
@@ -386,7 +429,11 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
(0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
(height << VI6_WPF_SZCLIP_SIZE_SHIFT));
- if (pipe->lif)
+ /*
+ * For display pipelines without writeback enabled there's no memory
+ * address to configure, return now.
+ */
+ if (pipe->lif && !wpf->writeback)
return;
/*
@@ -408,13 +455,11 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
flip = wpf->flip.active;
if (flip & BIT(WPF_CTRL_HFLIP) && !wpf->flip.rotate)
- offset = format->width - pipe->partition->wpf.left
- - pipe->partition->wpf.width;
+ offset = format->width - left - width;
else if (flip & BIT(WPF_CTRL_VFLIP) && wpf->flip.rotate)
- offset = format->height - pipe->partition->wpf.left
- - pipe->partition->wpf.width;
+ offset = format->height - left - width;
else
- offset = pipe->partition->wpf.left;
+ offset = left;
for (i = 0; i < format->num_planes; ++i) {
unsigned int hsub = i > 0 ? fmtinfo->hsub : 1;
@@ -436,7 +481,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
* image height.
*/
if (wpf->flip.rotate)
- height = pipe->partition->wpf.width;
+ height = width;
else
height = format->height;
@@ -477,6 +522,12 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_Y, mem.addr[0]);
vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_C0, mem.addr[1]);
vsp1_wpf_write(wpf, dlb, VI6_WPF_DSTM_ADDR_C1, mem.addr[2]);
+
+ /*
+ * Writeback operates in single-shot mode and lasts for a single frame,
+ * reset the writeback flag to false for the next frame.
+ */
+ wpf->writeback = false;
}
static unsigned int wpf_max_width(struct vsp1_entity *entity,
diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig
index 74ec8aaa5ae0..a2773ad7c185 100644
--- a/drivers/media/platform/xilinx/Kconfig
+++ b/drivers/media/platform/xilinx/Kconfig
@@ -5,7 +5,7 @@ config VIDEO_XILINX
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
- ---help---
+ help
Driver for Xilinx Video IP Pipelines
if VIDEO_XILINX
@@ -14,13 +14,13 @@ config VIDEO_XILINX_TPG
tristate "Xilinx Video Test Pattern Generator"
depends on VIDEO_XILINX
select VIDEO_XILINX_VTC
- ---help---
+ help
Driver for the Xilinx Video Test Pattern Generator
config VIDEO_XILINX_VTC
tristate "Xilinx Video Timing Controller"
depends on VIDEO_XILINX
- ---help---
+ help
Driver for the Xilinx Video Timing Controller
endif #VIDEO_XILINX