summaryrefslogtreecommitdiffstats
path: root/drivers/media/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform')
-rw-r--r--drivers/media/platform/Kconfig30
-rw-r--r--drivers/media/platform/Makefile6
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.c887
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.h49
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe_regs.h36
-rw-r--r--drivers/media/platform/aspeed-video.c58
-rw-r--r--drivers/media/platform/atmel/atmel-isc-base.c94
-rw-r--r--drivers/media/platform/atmel/atmel-isi.c44
-rw-r--r--drivers/media/platform/atmel/atmel-isi.h2
-rw-r--r--drivers/media/platform/atmel/atmel-sama5d2-isc.c7
-rw-r--r--drivers/media/platform/cadence/cdns-csi2rx.c2
-rw-r--r--drivers/media/platform/cadence/cdns-csi2tx.c155
-rw-r--r--drivers/media/platform/cec-gpio/cec-gpio.c41
-rw-r--r--drivers/media/platform/coda/coda-bit.c29
-rw-r--r--drivers/media/platform/coda/coda-common.c62
-rw-r--r--drivers/media/platform/coda/coda-jpeg.c746
-rw-r--r--drivers/media/platform/coda/coda.h4
-rw-r--r--drivers/media/platform/coda/coda_regs.h83
-rw-r--r--drivers/media/platform/coda/trace.h10
-rw-r--r--drivers/media/platform/cros-ec-cec/cros-ec-cec.c75
-rw-r--r--drivers/media/platform/davinci/dm355_ccdc.c2
-rw-r--r--drivers/media/platform/davinci/dm644x_ccdc.c2
-rw-r--r--drivers/media/platform/davinci/dm644x_ccdc_regs.h20
-rw-r--r--drivers/media/platform/davinci/isif.c2
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c21
-rw-r--r--drivers/media/platform/davinci/vpbe_osd.c5
-rw-r--r--drivers/media/platform/davinci/vpbe_venc.c5
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c85
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c33
-rw-r--r--drivers/media/platform/davinci/vpif_display.c7
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c22
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c3
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.c20
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.c3
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c3
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.h80
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c8
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c1
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.h138
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c9
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c10
-rw-r--r--drivers/media/platform/fsl-viu.c11
-rw-r--r--drivers/media/platform/imx-pxp.c4
-rw-r--r--drivers/media/platform/m2m-deinterlace.c140
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c15
-rw-r--r--drivers/media/platform/marvell-ccic/mmp-driver.c1
-rw-r--r--drivers/media/platform/meson/ao-cec-g12a.c72
-rw-r--r--drivers/media/platform/meson/ao-cec.c38
-rw-r--r--drivers/media/platform/mtk-mdp/mtk_mdp_core.c12
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c90
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h7
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c10
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h1
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c23
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h8
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c17
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c1
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c1
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_vpu_if.c9
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_vpu_if.h9
-rw-r--r--drivers/media/platform/mtk-vpu/mtk_vpu.c4
-rw-r--r--drivers/media/platform/mx2_emmaprp.c141
-rw-r--r--drivers/media/platform/omap/Kconfig3
-rw-r--r--drivers/media/platform/omap/omap_vout.c1045
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.c26
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.h4
-rw-r--r--drivers/media/platform/omap/omap_voutdef.h45
-rw-r--r--drivers/media/platform/omap/omap_voutlib.c6
-rw-r--r--drivers/media/platform/omap3isp/isp.c340
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c13
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c1
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c1
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c25
-rw-r--r--drivers/media/platform/omap3isp/ispreg.h584
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c1
-rw-r--r--drivers/media/platform/omap3isp/ispstat.c2
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c15
-rw-r--r--drivers/media/platform/pxa_camera.c9
-rw-r--r--drivers/media/platform/qcom/camss/camss.c2
-rw-r--r--drivers/media/platform/qcom/venus/core.c58
-rw-r--r--drivers/media/platform/qcom/venus/core.h63
-rw-r--r--drivers/media/platform/qcom/venus/helpers.c440
-rw-r--r--drivers/media/platform/qcom/venus/helpers.h12
-rw-r--r--drivers/media/platform/qcom/venus/hfi.c11
-rw-r--r--drivers/media/platform/qcom/venus/hfi.h2
-rw-r--r--drivers/media/platform/qcom/venus/hfi_venus.c6
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c549
-rw-r--r--drivers/media/platform/qcom/venus/vdec_ctrls.c7
-rw-r--r--drivers/media/platform/qcom/venus/venc.c20
-rw-r--r--drivers/media/platform/rcar-vin/rcar-core.c72
-rw-r--r--drivers/media/platform/rcar-vin/rcar-csi2.c4
-rw-r--r--drivers/media/platform/rcar-vin/rcar-dma.c119
-rw-r--r--drivers/media/platform/rcar-vin/rcar-v4l2.c220
-rw-r--r--drivers/media/platform/rcar-vin/rcar-vin.h15
-rw-r--r--drivers/media/platform/rcar_drif.c1
-rw-r--r--drivers/media/platform/rcar_fdp1.c5
-rw-r--r--drivers/media/platform/renesas-ceu.c4
-rw-r--r--drivers/media/platform/rockchip/rga/rga.c1
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c16
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c10
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.h1
-rw-r--r--drivers/media/platform/s3c-camif/camif-regs.c2
-rw-r--r--drivers/media/platform/s3c-camif/camif-regs.h118
-rw-r--r--drivers/media/platform/s5p-cec/s5p_cec.c23
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c13
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.h1
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c32
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.h4
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-regs.h10
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_common.h1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c19
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c14
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c4
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c2
-rw-r--r--drivers/media/platform/seco-cec/seco-cec.c56
-rw-r--r--drivers/media/platform/sh_veu.c28
-rw-r--r--drivers/media/platform/sh_vou.c17
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-hw.c6
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-v4l2.c22
-rw-r--r--drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c8
-rw-r--r--drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.c26
-rw-r--r--drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c5
-rw-r--r--drivers/media/platform/sti/cec/stih-cec.c32
-rw-r--r--drivers/media/platform/sti/hva/hva-hw.c8
-rw-r--r--drivers/media/platform/stm32/stm32-dcmi.c323
-rw-r--r--drivers/media/platform/sunxi/Kconfig2
-rw-r--r--drivers/media/platform/sunxi/Makefile3
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/Kconfig11
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/Makefile5
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c361
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h162
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c462
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c385
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c7
-rw-r--r--drivers/media/platform/sunxi/sun8i-di/Makefile2
-rw-r--r--drivers/media/platform/sunxi/sun8i-di/sun8i-di.c1025
-rw-r--r--drivers/media/platform/sunxi/sun8i-di/sun8i-di.h237
-rw-r--r--drivers/media/platform/tegra-cec/tegra_cec.c37
-rw-r--r--drivers/media/platform/tegra-cec/tegra_cec.h82
-rw-r--r--drivers/media/platform/ti-vpe/cal.c779
-rw-r--r--drivers/media/platform/ti-vpe/cal_regs.h221
-rw-r--r--drivers/media/platform/ti-vpe/csc.c246
-rw-r--r--drivers/media/platform/ti-vpe/csc.h4
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.c23
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.h2
-rw-r--r--drivers/media/platform/ti-vpe/vpdma_priv.h5
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c408
-rw-r--r--drivers/media/platform/ti-vpe/vpe_regs.h94
-rw-r--r--drivers/media/platform/via-camera.c579
-rw-r--r--drivers/media/platform/vicodec/codec-v4l2-fwht.c30
-rw-r--r--drivers/media/platform/vicodec/vicodec-core.c18
-rw-r--r--drivers/media/platform/vim2m.c8
-rw-r--r--drivers/media/platform/vimc/Makefile7
-rw-r--r--drivers/media/platform/vimc/vimc-capture.c183
-rw-r--r--drivers/media/platform/vimc/vimc-common.c442
-rw-r--r--drivers/media/platform/vimc/vimc-common.h148
-rw-r--r--drivers/media/platform/vimc/vimc-core.c215
-rw-r--r--drivers/media/platform/vimc/vimc-debayer.c268
-rw-r--r--drivers/media/platform/vimc/vimc-scaler.c324
-rw-r--r--drivers/media/platform/vimc/vimc-sensor.c158
-rw-r--r--drivers/media/platform/vimc/vimc-streamer.c59
-rw-r--r--drivers/media/platform/vimc/vimc-streamer.h14
-rw-r--r--drivers/media/platform/vivid/Makefile3
-rw-r--r--drivers/media/platform/vivid/vivid-cec.c7
-rw-r--r--drivers/media/platform/vivid/vivid-core.c565
-rw-r--r--drivers/media/platform/vivid/vivid-core.h45
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c126
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.c71
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-out.c57
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-touch.c181
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-touch.h13
-rw-r--r--drivers/media/platform/vivid/vivid-meta-cap.c201
-rw-r--r--drivers/media/platform/vivid/vivid-meta-cap.h29
-rw-r--r--drivers/media/platform/vivid/vivid-meta-out.c174
-rw-r--r--drivers/media/platform/vivid/vivid-meta-out.h25
-rw-r--r--drivers/media/platform/vivid/vivid-osd.c3
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c8
-rw-r--r--drivers/media/platform/vivid/vivid-touch-cap.c341
-rw-r--r--drivers/media/platform/vivid/vivid-touch-cap.h39
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c8
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c134
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c8
-rw-r--r--drivers/media/platform/vsp1/vsp1_dl.c4
-rw-r--r--drivers/media/platform/vsp1/vsp1_histo.c3
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h224
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c10
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c18
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.h2
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.c16
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.h33
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.h2
-rw-r--r--drivers/media/platform/xilinx/xilinx-vtc.h2
195 files changed, 11798 insertions, 5621 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 8a19654b393a..f65e98d3adf2 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -16,7 +16,7 @@ source "drivers/media/platform/marvell-ccic/Kconfig"
config VIDEO_VIA_CAMERA
tristate "VIAFB camera controller support"
depends on FB_VIA
- select VIDEOBUF_DMA_SG
+ select VIDEOBUF2_DMA_SG
select VIDEO_OV7670
help
Driver support for the integrated camera controller in VIA
@@ -121,7 +121,7 @@ config VIDEO_S3C_CAMIF
config VIDEO_STM32_DCMI
tristate "STM32 Digital Camera Memory Interface (DCMI) support"
- depends on VIDEO_V4L2 && OF
+ depends on VIDEO_V4L2 && OF && MEDIA_CONTROLLER
depends on ARCH_STM32 || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
@@ -146,12 +146,12 @@ source "drivers/media/platform/am437x/Kconfig"
source "drivers/media/platform/xilinx/Kconfig"
source "drivers/media/platform/rcar-vin/Kconfig"
source "drivers/media/platform/atmel/Kconfig"
-source "drivers/media/platform/sunxi/sun6i-csi/Kconfig"
+source "drivers/media/platform/sunxi/Kconfig"
config VIDEO_TI_CAL
tristate "TI CAL (Camera Adaptation Layer) driver"
depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
- depends on SOC_DRA7XX || COMPILE_TEST
+ depends on SOC_DRA7XX || ARCH_K3 || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select V4L2_FWNODE
help
@@ -200,7 +200,7 @@ config VIDEO_IMX_PXP
config VIDEO_MEDIATEK_JPEG
tristate "Mediatek JPEG Codec driver"
- depends on MTK_IOMMU_V1 || COMPILE_TEST
+ depends on MTK_IOMMU_V1 || MTK_IOMMU || COMPILE_TEST
depends on VIDEO_DEV && VIDEO_V4L2
depends on ARCH_MEDIATEK || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
@@ -483,6 +483,7 @@ config VIDEO_QCOM_VENUS
tristate "Qualcomm Venus V4L2 encoder/decoder driver"
depends on VIDEO_DEV && VIDEO_V4L2
depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST
+ depends on INTERCONNECT || !INTERCONNECT
select QCOM_MDT_LOADER if ARCH_QCOM
select QCOM_SCM if ARCH_QCOM
select VIDEOBUF2_DMA_SG
@@ -493,6 +494,19 @@ config VIDEO_QCOM_VENUS
on various Qualcomm SoCs.
To compile this driver as a module choose m here.
+config VIDEO_SUN8I_DEINTERLACE
+ tristate "Allwinner Deinterlace driver"
+ depends on VIDEO_DEV && VIDEO_V4L2
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on COMMON_CLK && OF
+ depends on PM
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ help
+ Support for the Allwinner deinterlace unit with scaling
+ capability found on some SoCs, like H3.
+ To compile this driver as a module choose m here.
+
endif # V4L_MEM2MEM_DRIVERS
# TI VIDEO PORT Helper Modules
@@ -547,10 +561,9 @@ if CEC_PLATFORM_DRIVERS
config VIDEO_CROS_EC_CEC
tristate "ChromeOS EC CEC driver"
- depends on MFD_CROS_EC
+ depends on CROS_EC
select CEC_CORE
select CEC_NOTIFIER
- select CHROME_PLATFORMS
select CROS_EC_PROTO
help
If you say yes here you will get support for the
@@ -586,9 +599,10 @@ config VIDEO_MESON_G12A_AO_CEC
config CEC_GPIO
tristate "Generic GPIO-based CEC driver"
- depends on PREEMPT || COMPILE_TEST
+ depends on PREEMPTION || COMPILE_TEST
select CEC_CORE
select CEC_PIN
+ select CEC_NOTIFIER
select GPIOLIB
help
This is a generic GPIO-based CEC driver.
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 7cbbd925124c..d13db96e3015 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -19,9 +19,7 @@ obj-$(CONFIG_VIDEO_VIVID) += vivid/
obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o
obj-$(CONFIG_VIDEO_VICODEC) += vicodec/
-obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe/
-
-obj-$(CONFIG_VIDEO_TI_CAL) += ti-vpe/
+obj-y += ti-vpe/
obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
obj-$(CONFIG_VIDEO_CODA) += coda/
@@ -100,4 +98,4 @@ obj-y += meson/
obj-y += cros-ec-cec/
-obj-$(CONFIG_VIDEO_SUN6I_CSI) += sunxi/sun6i-csi/
+obj-y += sunxi/
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
index fe7b937eb5f2..09104304bd06 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* TI VPFE capture Driver
*
@@ -5,19 +6,6 @@
*
* Benoit Parrot <bparrot@ti.com>
* Lad, Prabhakar <prabhakar.csengg@gmail.com>
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#include <linux/delay.h>
@@ -69,137 +57,64 @@ static const struct vpfe_standard vpfe_standards[] = {
{V4L2_STD_625_50, 720, 576, {54, 59}, 1},
};
-struct bus_format {
- unsigned int width;
- unsigned int bpp;
-};
-
-/*
- * struct vpfe_fmt - VPFE media bus format information
- * @name: V4L2 format description
- * @code: V4L2 media bus format code
- * @shifted: V4L2 media bus format code for the same pixel layout but
- * shifted to be 8 bits per pixel. =0 if format is not shiftable.
- * @pixelformat: V4L2 pixel format FCC identifier
- * @width: Bits per pixel (when transferred over a bus)
- * @bpp: Bytes per pixel (when stored in memory)
- * @supported: Indicates format supported by subdev
- */
-struct vpfe_fmt {
- const char *name;
- u32 fourcc;
- u32 code;
- struct bus_format l;
- struct bus_format s;
- bool supported;
- u32 index;
-};
-
-static struct vpfe_fmt formats[] = {
+static struct vpfe_fmt formats[VPFE_NUM_FORMATS] = {
{
- .name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.code = MEDIA_BUS_FMT_YUYV8_2X8,
- .l.width = 10,
- .l.bpp = 4,
- .s.width = 8,
- .s.bpp = 2,
- .supported = false,
+ .bitsperpixel = 16,
}, {
- .name = "YUV 4:2:2 packed, CbYCrY",
.fourcc = V4L2_PIX_FMT_UYVY,
.code = MEDIA_BUS_FMT_UYVY8_2X8,
- .l.width = 10,
- .l.bpp = 4,
- .s.width = 8,
- .s.bpp = 2,
- .supported = false,
+ .bitsperpixel = 16,
}, {
- .name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
.code = MEDIA_BUS_FMT_YVYU8_2X8,
- .l.width = 10,
- .l.bpp = 4,
- .s.width = 8,
- .s.bpp = 2,
- .supported = false,
+ .bitsperpixel = 16,
}, {
- .name = "YUV 4:2:2 packed, CrYCbY",
.fourcc = V4L2_PIX_FMT_VYUY,
.code = MEDIA_BUS_FMT_VYUY8_2X8,
- .l.width = 10,
- .l.bpp = 4,
- .s.width = 8,
- .s.bpp = 2,
- .supported = false,
+ .bitsperpixel = 16,
}, {
- .name = "RAW8 BGGR",
.fourcc = V4L2_PIX_FMT_SBGGR8,
.code = MEDIA_BUS_FMT_SBGGR8_1X8,
- .l.width = 10,
- .l.bpp = 2,
- .s.width = 8,
- .s.bpp = 1,
- .supported = false,
+ .bitsperpixel = 8,
}, {
- .name = "RAW8 GBRG",
.fourcc = V4L2_PIX_FMT_SGBRG8,
.code = MEDIA_BUS_FMT_SGBRG8_1X8,
- .l.width = 10,
- .l.bpp = 2,
- .s.width = 8,
- .s.bpp = 1,
- .supported = false,
+ .bitsperpixel = 8,
}, {
- .name = "RAW8 GRBG",
.fourcc = V4L2_PIX_FMT_SGRBG8,
.code = MEDIA_BUS_FMT_SGRBG8_1X8,
- .l.width = 10,
- .l.bpp = 2,
- .s.width = 8,
- .s.bpp = 1,
- .supported = false,
+ .bitsperpixel = 8,
}, {
- .name = "RAW8 RGGB",
.fourcc = V4L2_PIX_FMT_SRGGB8,
.code = MEDIA_BUS_FMT_SRGGB8_1X8,
- .l.width = 10,
- .l.bpp = 2,
- .s.width = 8,
- .s.bpp = 1,
- .supported = false,
+ .bitsperpixel = 8,
}, {
- .name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565,
.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
- .l.width = 10,
- .l.bpp = 4,
- .s.width = 8,
- .s.bpp = 2,
- .supported = false,
+ .bitsperpixel = 16,
}, {
- .name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X,
.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
- .l.width = 10,
- .l.bpp = 4,
- .s.width = 8,
- .s.bpp = 2,
- .supported = false,
+ .bitsperpixel = 16,
},
};
-static int
-__vpfe_get_format(struct vpfe_device *vpfe,
- struct v4l2_format *format, unsigned int *bpp);
+static int __subdev_get_format(struct vpfe_device *vpfe,
+ struct v4l2_mbus_framefmt *fmt);
+static int vpfe_calc_format_size(struct vpfe_device *vpfe,
+ const struct vpfe_fmt *fmt,
+ struct v4l2_format *f);
-static struct vpfe_fmt *find_format_by_code(unsigned int code)
+static struct vpfe_fmt *find_format_by_code(struct vpfe_device *vpfe,
+ unsigned int code)
{
struct vpfe_fmt *fmt;
unsigned int k;
- for (k = 0; k < ARRAY_SIZE(formats); k++) {
- fmt = &formats[k];
+ for (k = 0; k < vpfe->num_active_fmt; k++) {
+ fmt = vpfe->active_fmt[k];
if (fmt->code == code)
return fmt;
}
@@ -207,13 +122,14 @@ static struct vpfe_fmt *find_format_by_code(unsigned int code)
return NULL;
}
-static struct vpfe_fmt *find_format_by_pix(unsigned int pixelformat)
+static struct vpfe_fmt *find_format_by_pix(struct vpfe_device *vpfe,
+ unsigned int pixelformat)
{
struct vpfe_fmt *fmt;
unsigned int k;
- for (k = 0; k < ARRAY_SIZE(formats); k++) {
- fmt = &formats[k];
+ for (k = 0; k < vpfe->num_active_fmt; k++) {
+ fmt = vpfe->active_fmt[k];
if (fmt->fourcc == pixelformat)
return fmt;
}
@@ -221,48 +137,18 @@ static struct vpfe_fmt *find_format_by_pix(unsigned int pixelformat)
return NULL;
}
-static void
-mbus_to_pix(struct vpfe_device *vpfe,
- const struct v4l2_mbus_framefmt *mbus,
- struct v4l2_pix_format *pix, unsigned int *bpp)
+static unsigned int __get_bytesperpixel(struct vpfe_device *vpfe,
+ const struct vpfe_fmt *fmt)
{
struct vpfe_subdev_info *sdinfo = vpfe->current_subdev;
unsigned int bus_width = sdinfo->vpfe_param.bus_width;
- struct vpfe_fmt *fmt;
-
- fmt = find_format_by_code(mbus->code);
- if (WARN_ON(fmt == NULL)) {
- pr_err("Invalid mbus code set\n");
- *bpp = 1;
- return;
- }
+ u32 bpp, bus_width_bytes, clocksperpixel;
- memset(pix, 0, sizeof(*pix));
- v4l2_fill_pix_format(pix, mbus);
- pix->pixelformat = fmt->fourcc;
- *bpp = (bus_width == 10) ? fmt->l.bpp : fmt->s.bpp;
+ bus_width_bytes = ALIGN(bus_width, 8) >> 3;
+ clocksperpixel = DIV_ROUND_UP(fmt->bitsperpixel, bus_width);
+ bpp = clocksperpixel * bus_width_bytes;
- /* pitch should be 32 bytes aligned */
- pix->bytesperline = ALIGN(pix->width * *bpp, 32);
- pix->sizeimage = pix->bytesperline * pix->height;
-}
-
-static void pix_to_mbus(struct vpfe_device *vpfe,
- struct v4l2_pix_format *pix_fmt,
- struct v4l2_mbus_framefmt *mbus_fmt)
-{
- struct vpfe_fmt *fmt;
-
- fmt = find_format_by_pix(pix_fmt->pixelformat);
- if (!fmt) {
- /* default to first entry */
- vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n",
- pix_fmt->pixelformat);
- fmt = &formats[0];
- }
-
- memset(mbus_fmt, 0, sizeof(*mbus_fmt));
- v4l2_fill_mbus_format(mbus_fmt, pix_fmt, fmt->code);
+ return bpp;
}
/* Print Four-character-code (FOURCC) */
@@ -279,20 +165,6 @@ static char *print_fourcc(u32 fmt)
return code;
}
-static int
-cmp_v4l2_format(const struct v4l2_format *lhs, const struct v4l2_format *rhs)
-{
- return lhs->type == rhs->type &&
- lhs->fmt.pix.width == rhs->fmt.pix.width &&
- lhs->fmt.pix.height == rhs->fmt.pix.height &&
- lhs->fmt.pix.pixelformat == rhs->fmt.pix.pixelformat &&
- lhs->fmt.pix.field == rhs->fmt.pix.field &&
- lhs->fmt.pix.colorspace == rhs->fmt.pix.colorspace &&
- lhs->fmt.pix.ycbcr_enc == rhs->fmt.pix.ycbcr_enc &&
- lhs->fmt.pix.quantization == rhs->fmt.pix.quantization &&
- lhs->fmt.pix.xfer_func == rhs->fmt.pix.xfer_func;
-}
-
static inline u32 vpfe_reg_read(struct vpfe_ccdc *ccdc, u32 offset)
{
return ioread32(ccdc->ccdc_cfg.base_addr + offset);
@@ -357,13 +229,9 @@ static void vpfe_ccdc_setwin(struct vpfe_ccdc *ccdc,
if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
vert_nr_lines = (image_win->height >> 1) - 1;
vert_start >>= 1;
- /* Since first line doesn't have any data */
- vert_start += 1;
/* configure VDINT0 */
val = (vert_start << VPFE_VDINT_VDINT0_SHIFT);
} else {
- /* Since first line doesn't have any data */
- vert_start += 1;
vert_nr_lines = image_win->height - 1;
/*
* configure VDINT0 and VDINT1. VDINT1 will be at half
@@ -417,7 +285,6 @@ vpfe_ccdc_validate_param(struct vpfe_ccdc *ccdc,
max_data = ccdc_data_size_max_bit(ccdcparam->data_sz);
if (ccdcparam->alaw.gamma_wd > VPFE_CCDC_GAMMA_BITS_09_0 ||
- ccdcparam->alaw.gamma_wd < VPFE_CCDC_GAMMA_BITS_15_6 ||
max_gamma > max_data) {
vpfe_dbg(1, vpfe, "Invalid data line select\n");
return -EINVAL;
@@ -457,40 +324,25 @@ static void vpfe_ccdc_restore_defaults(struct vpfe_ccdc *ccdc)
static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev)
{
- int dma_cntl, i, pcr;
+ struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+ u32 dma_cntl, pcr;
- /* If the CCDC module is still busy wait for it to be done */
- for (i = 0; i < 10; i++) {
- usleep_range(5000, 6000);
- pcr = vpfe_reg_read(ccdc, VPFE_PCR);
- if (!pcr)
- break;
+ pcr = vpfe_reg_read(ccdc, VPFE_PCR);
+ if (pcr)
+ vpfe_dbg(1, vpfe, "VPFE_PCR is still set (%x)", pcr);
- /* make sure it it is disabled */
- vpfe_pcr_enable(ccdc, 0);
- }
+ dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL);
+ if ((dma_cntl & VPFE_DMA_CNTL_OVERFLOW))
+ vpfe_dbg(1, vpfe, "VPFE_DMA_CNTL_OVERFLOW is still set (%x)",
+ dma_cntl);
/* Disable CCDC by resetting all register to default POR values */
vpfe_ccdc_restore_defaults(ccdc);
- /* if DMA_CNTL overflow bit is set. Clear it
- * It appears to take a while for this to become quiescent ~20ms
- */
- for (i = 0; i < 10; i++) {
- dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL);
- if (!(dma_cntl & VPFE_DMA_CNTL_OVERFLOW))
- break;
-
- /* Clear the overflow bit */
- vpfe_reg_write(ccdc, dma_cntl, VPFE_DMA_CNTL);
- usleep_range(5000, 6000);
- }
-
/* Disabled the module at the CONFIG level */
vpfe_config_enable(ccdc, 0);
pm_runtime_put_sync(dev);
-
return 0;
}
@@ -506,8 +358,8 @@ static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params)
x = copy_from_user(&raw_params, params, sizeof(raw_params));
if (x) {
vpfe_dbg(1, vpfe,
- "vpfe_ccdc_set_params: error in copying ccdc params, %d\n",
- x);
+ "%s: error in copying ccdc params, %d\n",
+ __func__, x);
return -EFAULT;
}
@@ -525,11 +377,9 @@ static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params)
*/
static void vpfe_ccdc_config_ycbcr(struct vpfe_ccdc *ccdc)
{
- struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
struct ccdc_params_ycbcr *params = &ccdc->ccdc_cfg.ycbcr;
u32 syn_mode;
- vpfe_dbg(3, vpfe, "vpfe_ccdc_config_ycbcr:\n");
/*
* first restore the CCDC registers to default values
* This is important since we assume default values to be set in
@@ -661,8 +511,6 @@ static void vpfe_ccdc_config_raw(struct vpfe_ccdc *ccdc)
unsigned int syn_mode;
unsigned int val;
- vpfe_dbg(3, vpfe, "vpfe_ccdc_config_raw:\n");
-
/* Reset CCDC */
vpfe_ccdc_restore_defaults(ccdc);
@@ -763,8 +611,8 @@ static int vpfe_ccdc_set_pixel_format(struct vpfe_ccdc *ccdc, u32 pixfmt)
{
struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
- vpfe_dbg(1, vpfe, "vpfe_ccdc_set_pixel_format: if_type: %d, pixfmt:%s\n",
- ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt));
+ vpfe_dbg(1, vpfe, "%s: if_type: %d, pixfmt:%s\n",
+ __func__, ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt));
if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) {
ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
@@ -1048,10 +896,9 @@ static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe,
static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe)
{
enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
+ u32 bpp;
int ret = 0;
- vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n");
-
vpfe_dbg(1, vpfe, "pixelformat: %s\n",
print_fourcc(vpfe->fmt.fmt.pix.pixelformat));
@@ -1062,7 +909,8 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe)
}
/* configure the image window */
- vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, vpfe->bpp);
+ bpp = __get_bytesperpixel(vpfe, vpfe->current_vpfe_fmt);
+ vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, bpp);
switch (vpfe->fmt.fmt.pix.field) {
case V4L2_FIELD_INTERLACED:
@@ -1106,7 +954,8 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe)
static int vpfe_config_image_format(struct vpfe_device *vpfe,
v4l2_std_id std_id)
{
- struct v4l2_pix_format *pix = &vpfe->fmt.fmt.pix;
+ struct vpfe_fmt *fmt;
+ struct v4l2_mbus_framefmt mbus_fmt;
int i, ret;
for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
@@ -1128,26 +977,29 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe,
return -EINVAL;
}
- vpfe->crop.top = vpfe->crop.left = 0;
- vpfe->crop.width = vpfe->std_info.active_pixels;
- vpfe->crop.height = vpfe->std_info.active_lines;
- pix->width = vpfe->crop.width;
- pix->height = vpfe->crop.height;
- pix->pixelformat = V4L2_PIX_FMT_YUYV;
-
- /* first field and frame format based on standard frame format */
- if (vpfe->std_info.frame_format)
- pix->field = V4L2_FIELD_INTERLACED;
- else
- pix->field = V4L2_FIELD_NONE;
-
- ret = __vpfe_get_format(vpfe, &vpfe->fmt, &vpfe->bpp);
+ ret = __subdev_get_format(vpfe, &mbus_fmt);
if (ret)
return ret;
+ fmt = find_format_by_code(vpfe, mbus_fmt.code);
+ if (!fmt) {
+ vpfe_dbg(3, vpfe, "mbus code format (0x%08x) not found.\n",
+ mbus_fmt.code);
+ return -EINVAL;
+ }
+
+ /* Save current subdev format */
+ v4l2_fill_pix_format(&vpfe->fmt.fmt.pix, &mbus_fmt);
+ vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vpfe->fmt.fmt.pix.pixelformat = fmt->fourcc;
+ vpfe_calc_format_size(vpfe, fmt, &vpfe->fmt);
+ vpfe->current_vpfe_fmt = fmt;
+
/* Update the crop window based on found values */
- vpfe->crop.width = pix->width;
- vpfe->crop.height = pix->height;
+ vpfe->crop.top = 0;
+ vpfe->crop.left = 0;
+ vpfe->crop.width = mbus_fmt.width;
+ vpfe->crop.height = mbus_fmt.height;
return vpfe_config_ccdc_image_format(vpfe);
}
@@ -1249,22 +1101,29 @@ unlock:
* This function will get next buffer from the dma queue and
* set the buffer address in the vpfe register for capture.
* the buffer is marked active
- *
- * Assumes caller is holding vpfe->dma_queue_lock already
*/
-static inline void vpfe_schedule_next_buffer(struct vpfe_device *vpfe)
+static void vpfe_schedule_next_buffer(struct vpfe_device *vpfe)
{
+ dma_addr_t addr;
+
+ spin_lock(&vpfe->dma_queue_lock);
+ if (list_empty(&vpfe->dma_queue)) {
+ spin_unlock(&vpfe->dma_queue_lock);
+ return;
+ }
+
vpfe->next_frm = list_entry(vpfe->dma_queue.next,
struct vpfe_cap_buffer, list);
list_del(&vpfe->next_frm->list);
+ spin_unlock(&vpfe->dma_queue_lock);
- vpfe_set_sdr_addr(&vpfe->ccdc,
- vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb.vb2_buf, 0));
+ addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb.vb2_buf, 0);
+ vpfe_set_sdr_addr(&vpfe->ccdc, addr);
}
static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe)
{
- unsigned long addr;
+ dma_addr_t addr;
addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb.vb2_buf, 0) +
vpfe->field_off;
@@ -1289,6 +1148,58 @@ static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe)
vpfe->cur_frm = vpfe->next_frm;
}
+static void vpfe_handle_interlaced_irq(struct vpfe_device *vpfe,
+ enum v4l2_field field)
+{
+ int fid;
+
+ /* interlaced or TB capture check which field
+ * we are in hardware
+ */
+ fid = vpfe_ccdc_getfid(&vpfe->ccdc);
+
+ /* switch the software maintained field id */
+ vpfe->field ^= 1;
+ if (fid == vpfe->field) {
+ /* we are in-sync here,continue */
+ if (fid == 0) {
+ /*
+ * One frame is just being captured. If the
+ * next frame is available, release the
+ * current frame and move on
+ */
+ if (vpfe->cur_frm != vpfe->next_frm)
+ vpfe_process_buffer_complete(vpfe);
+
+ if (vpfe->stopping)
+ return;
+
+ /*
+ * based on whether the two fields are stored
+ * interleave or separately in memory,
+ * reconfigure the CCDC memory address
+ */
+ if (field == V4L2_FIELD_SEQ_TB)
+ vpfe_schedule_bottom_field(vpfe);
+ } else {
+ /*
+ * if one field is just being captured configure
+ * the next frame get the next frame from the empty
+ * queue if no frame is available hold on to the
+ * current buffer
+ */
+ if (vpfe->cur_frm == vpfe->next_frm)
+ vpfe_schedule_next_buffer(vpfe);
+ }
+ } else if (fid == 0) {
+ /*
+ * out of sync. Recover from any hardware out-of-sync.
+ * May loose one frame
+ */
+ vpfe->field = fid;
+ }
+}
+
/*
* vpfe_isr : ISR handler for vpfe capture (VINT0)
* @irq: irq number
@@ -1300,76 +1211,28 @@ static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe)
static irqreturn_t vpfe_isr(int irq, void *dev)
{
struct vpfe_device *vpfe = (struct vpfe_device *)dev;
- enum v4l2_field field;
- int intr_status;
- int fid;
+ enum v4l2_field field = vpfe->fmt.fmt.pix.field;
+ int intr_status, stopping = vpfe->stopping;
intr_status = vpfe_reg_read(&vpfe->ccdc, VPFE_IRQ_STS);
if (intr_status & VPFE_VDINT0) {
- field = vpfe->fmt.fmt.pix.field;
-
if (field == V4L2_FIELD_NONE) {
- /* handle progressive frame capture */
if (vpfe->cur_frm != vpfe->next_frm)
vpfe_process_buffer_complete(vpfe);
- goto next_intr;
+ } else {
+ vpfe_handle_interlaced_irq(vpfe, field);
}
-
- /* interlaced or TB capture check which field
- we are in hardware */
- fid = vpfe_ccdc_getfid(&vpfe->ccdc);
-
- /* switch the software maintained field id */
- vpfe->field ^= 1;
- if (fid == vpfe->field) {
- /* we are in-sync here,continue */
- if (fid == 0) {
- /*
- * One frame is just being captured. If the
- * next frame is available, release the
- * current frame and move on
- */
- if (vpfe->cur_frm != vpfe->next_frm)
- vpfe_process_buffer_complete(vpfe);
- /*
- * based on whether the two fields are stored
- * interleave or separately in memory,
- * reconfigure the CCDC memory address
- */
- if (field == V4L2_FIELD_SEQ_TB)
- vpfe_schedule_bottom_field(vpfe);
-
- goto next_intr;
- }
- /*
- * if one field is just being captured configure
- * the next frame get the next frame from the empty
- * queue if no frame is available hold on to the
- * current buffer
- */
- spin_lock(&vpfe->dma_queue_lock);
- if (!list_empty(&vpfe->dma_queue) &&
- vpfe->cur_frm == vpfe->next_frm)
- vpfe_schedule_next_buffer(vpfe);
- spin_unlock(&vpfe->dma_queue_lock);
- } else if (fid == 0) {
- /*
- * out of sync. Recover from any hardware out-of-sync.
- * May loose one frame
- */
- vpfe->field = fid;
+ if (stopping) {
+ vpfe->stopping = false;
+ complete(&vpfe->capture_stop);
}
}
-next_intr:
- if (intr_status & VPFE_VDINT1) {
- spin_lock(&vpfe->dma_queue_lock);
- if (vpfe->fmt.fmt.pix.field == V4L2_FIELD_NONE &&
- !list_empty(&vpfe->dma_queue) &&
+ if (intr_status & VPFE_VDINT1 && !stopping) {
+ if (field == V4L2_FIELD_NONE &&
vpfe->cur_frm == vpfe->next_frm)
vpfe_schedule_next_buffer(vpfe);
- spin_unlock(&vpfe->dma_queue_lock);
}
vpfe_clear_intr(&vpfe->ccdc, intr_status);
@@ -1406,97 +1269,82 @@ static int vpfe_querycap(struct file *file, void *priv,
{
struct vpfe_device *vpfe = video_drvdata(file);
- vpfe_dbg(2, vpfe, "vpfe_querycap\n");
-
strscpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver));
strscpy(cap->card, "TI AM437x VPFE", sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", vpfe->v4l2_dev.name);
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
/* get the format set at output pad of the adjacent subdev */
-static int __vpfe_get_format(struct vpfe_device *vpfe,
- struct v4l2_format *format, unsigned int *bpp)
+static int __subdev_get_format(struct vpfe_device *vpfe,
+ struct v4l2_mbus_framefmt *fmt)
{
- struct v4l2_mbus_framefmt mbus_fmt;
- struct vpfe_subdev_info *sdinfo;
- struct v4l2_subdev_format fmt;
+ struct v4l2_subdev *sd = vpfe->current_subdev->sd;
+ struct v4l2_subdev_format sd_fmt;
+ struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
int ret;
- sdinfo = vpfe->current_subdev;
- if (!sdinfo->sd)
- return -EINVAL;
-
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt.pad = 0;
+ sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ sd_fmt.pad = 0;
- ret = v4l2_subdev_call(sdinfo->sd, pad, get_fmt, NULL, &fmt);
- if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
+ if (ret)
return ret;
- if (!ret) {
- v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
- mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp);
- } else {
- ret = v4l2_device_call_until_err(&vpfe->v4l2_dev,
- sdinfo->grp_id,
- pad, get_fmt,
- NULL, &fmt);
- if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
- return ret;
- v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt);
- mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp);
- }
-
- format->type = vpfe->fmt.type;
+ *fmt = *mbus_fmt;
- vpfe_dbg(1, vpfe,
- "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n",
- __func__, format->fmt.pix.width, format->fmt.pix.height,
- print_fourcc(format->fmt.pix.pixelformat),
- format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp);
+ vpfe_dbg(1, vpfe, "%s: %dx%d code:%04X\n", __func__,
+ fmt->width, fmt->height, fmt->code);
return 0;
}
/* set the format at output pad of the adjacent subdev */
-static int __vpfe_set_format(struct vpfe_device *vpfe,
- struct v4l2_format *format, unsigned int *bpp)
+static int __subdev_set_format(struct vpfe_device *vpfe,
+ struct v4l2_mbus_framefmt *fmt)
{
- struct vpfe_subdev_info *sdinfo;
- struct v4l2_subdev_format fmt;
+ struct v4l2_subdev *sd = vpfe->current_subdev->sd;
+ struct v4l2_subdev_format sd_fmt;
+ struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
int ret;
- vpfe_dbg(2, vpfe, "__vpfe_set_format\n");
+ sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ sd_fmt.pad = 0;
+ *mbus_fmt = *fmt;
- sdinfo = vpfe->current_subdev;
- if (!sdinfo->sd)
- return -EINVAL;
+ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sd_fmt);
+ if (ret)
+ return ret;
- fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt.pad = 0;
+ vpfe_dbg(1, vpfe, "%s %dx%d code:%04X\n", __func__,
+ fmt->width, fmt->height, fmt->code);
- pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format);
+ return 0;
+}
- ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt);
- if (ret)
- return ret;
+static int vpfe_calc_format_size(struct vpfe_device *vpfe,
+ const struct vpfe_fmt *fmt,
+ struct v4l2_format *f)
+{
+ u32 bpp;
- v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
- mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp);
+ if (!fmt) {
+ vpfe_dbg(3, vpfe, "No vpfe_fmt provided!\n");
+ return -EINVAL;
+ }
- format->type = vpfe->fmt.type;
+ bpp = __get_bytesperpixel(vpfe, fmt);
- vpfe_dbg(1, vpfe,
- "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n",
- __func__, format->fmt.pix.width, format->fmt.pix.height,
- print_fourcc(format->fmt.pix.pixelformat),
- format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp);
+ /* pitch should be 32 bytes aligned */
+ f->fmt.pix.bytesperline = ALIGN(f->fmt.pix.width * bpp, 32);
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+ f->fmt.pix.height;
+
+ vpfe_dbg(3, vpfe, "%s: fourcc: %s size: %dx%d bpl:%d img_size:%d\n",
+ __func__, print_fourcc(f->fmt.pix.pixelformat),
+ f->fmt.pix.width, f->fmt.pix.height,
+ f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
return 0;
}
@@ -1506,8 +1354,6 @@ static int vpfe_g_fmt(struct file *file, void *priv,
{
struct vpfe_device *vpfe = video_drvdata(file);
- vpfe_dbg(2, vpfe, "vpfe_g_fmt\n");
-
*fmt = vpfe->fmt;
return 0;
@@ -1518,84 +1364,124 @@ static int vpfe_enum_fmt(struct file *file, void *priv,
{
struct vpfe_device *vpfe = video_drvdata(file);
struct vpfe_subdev_info *sdinfo;
- struct vpfe_fmt *fmt = NULL;
- unsigned int k;
-
- vpfe_dbg(2, vpfe, "vpfe_enum_format index:%d\n",
- f->index);
+ struct vpfe_fmt *fmt;
sdinfo = vpfe->current_subdev;
if (!sdinfo->sd)
return -EINVAL;
- if (f->index > ARRAY_SIZE(formats))
+ if (f->index >= vpfe->num_active_fmt)
return -EINVAL;
- for (k = 0; k < ARRAY_SIZE(formats); k++) {
- if (formats[k].index == f->index) {
- fmt = &formats[k];
- break;
- }
- }
- if (!fmt)
- return -EINVAL;
+ fmt = vpfe->active_fmt[f->index];
- strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
- f->type = vpfe->fmt.type;
- vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s [%s]\n",
- f->index, fmt->code, print_fourcc(fmt->fourcc), fmt->name);
+ vpfe_dbg(1, vpfe, "%s: mbus index: %d code: %x pixelformat: %s\n",
+ __func__, f->index, fmt->code, print_fourcc(fmt->fourcc));
return 0;
}
static int vpfe_try_fmt(struct file *file, void *priv,
- struct v4l2_format *fmt)
+ struct v4l2_format *f)
{
struct vpfe_device *vpfe = video_drvdata(file);
- unsigned int bpp;
+ struct v4l2_subdev *sd = vpfe->current_subdev->sd;
+ const struct vpfe_fmt *fmt;
+ struct v4l2_subdev_frame_size_enum fse;
+ int ret, found;
+
+ fmt = find_format_by_pix(vpfe, f->fmt.pix.pixelformat);
+ if (!fmt) {
+ /* default to first entry */
+ vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n",
+ f->fmt.pix.pixelformat);
+ fmt = vpfe->active_fmt[0];
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ }
- vpfe_dbg(2, vpfe, "vpfe_try_fmt\n");
+ f->fmt.pix.field = vpfe->fmt.fmt.pix.field;
+
+ /* check for/find a valid width/height */
+ ret = 0;
+ found = false;
+ fse.pad = 0;
+ fse.code = fmt->code;
+ fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ for (fse.index = 0; ; fse.index++) {
+ ret = v4l2_subdev_call(sd, pad, enum_frame_size,
+ NULL, &fse);
+ if (ret)
+ break;
- return __vpfe_get_format(vpfe, fmt, &bpp);
+ if (f->fmt.pix.width == fse.max_width &&
+ f->fmt.pix.height == fse.max_height) {
+ found = true;
+ break;
+ } else if (f->fmt.pix.width >= fse.min_width &&
+ f->fmt.pix.width <= fse.max_width &&
+ f->fmt.pix.height >= fse.min_height &&
+ f->fmt.pix.height <= fse.max_height) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ /* use existing values as default */
+ f->fmt.pix.width = vpfe->fmt.fmt.pix.width;
+ f->fmt.pix.height = vpfe->fmt.fmt.pix.height;
+ }
+
+ /*
+ * Use current colorspace for now, it will get
+ * updated properly during s_fmt
+ */
+ f->fmt.pix.colorspace = vpfe->fmt.fmt.pix.colorspace;
+ return vpfe_calc_format_size(vpfe, fmt, f);
}
static int vpfe_s_fmt(struct file *file, void *priv,
struct v4l2_format *fmt)
{
struct vpfe_device *vpfe = video_drvdata(file);
- struct v4l2_format format;
- unsigned int bpp;
+ struct vpfe_fmt *f;
+ struct v4l2_mbus_framefmt mbus_fmt;
int ret;
- vpfe_dbg(2, vpfe, "vpfe_s_fmt\n");
-
/* If streaming is started, return error */
if (vb2_is_busy(&vpfe->buffer_queue)) {
vpfe_err(vpfe, "%s device busy\n", __func__);
return -EBUSY;
}
- ret = __vpfe_get_format(vpfe, &format, &bpp);
- if (ret)
+ ret = vpfe_try_fmt(file, priv, fmt);
+ if (ret < 0)
return ret;
+ f = find_format_by_pix(vpfe, fmt->fmt.pix.pixelformat);
- if (!cmp_v4l2_format(fmt, &format)) {
- /* Sensor format is different from the requested format
- * so we need to change it
- */
- ret = __vpfe_set_format(vpfe, fmt, &bpp);
- if (ret)
- return ret;
- } else /* Just make sure all of the fields are consistent */
- *fmt = format;
+ v4l2_fill_mbus_format(&mbus_fmt, &fmt->fmt.pix, f->code);
- /* First detach any IRQ if currently attached */
- vpfe_detach_irq(vpfe);
- vpfe->fmt = *fmt;
- vpfe->bpp = bpp;
+ ret = __subdev_set_format(vpfe, &mbus_fmt);
+ if (ret)
+ return ret;
+
+ /* Just double check nothing has gone wrong */
+ if (mbus_fmt.code != f->code) {
+ vpfe_dbg(3, vpfe,
+ "%s subdev changed format on us, this should not happen\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ v4l2_fill_pix_format(&vpfe->fmt.fmt.pix, &mbus_fmt);
+ vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vpfe->fmt.fmt.pix.pixelformat = f->fourcc;
+ vpfe_calc_format_size(vpfe, f, &vpfe->fmt);
+ *fmt = vpfe->fmt;
+ vpfe->current_vpfe_fmt = f;
/* Update the crop window based on found values */
vpfe->crop.width = fmt->fmt.pix.width;
@@ -1610,57 +1496,40 @@ static int vpfe_enum_size(struct file *file, void *priv,
{
struct vpfe_device *vpfe = video_drvdata(file);
struct v4l2_subdev_frame_size_enum fse;
- struct vpfe_subdev_info *sdinfo;
- struct v4l2_mbus_framefmt mbus;
- struct v4l2_pix_format pix;
+ struct v4l2_subdev *sd = vpfe->current_subdev->sd;
struct vpfe_fmt *fmt;
int ret;
- vpfe_dbg(2, vpfe, "vpfe_enum_size\n");
-
/* check for valid format */
- fmt = find_format_by_pix(fsize->pixel_format);
+ fmt = find_format_by_pix(vpfe, fsize->pixel_format);
if (!fmt) {
- vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n",
- fsize->pixel_format);
+ vpfe_dbg(3, vpfe, "Invalid pixel code: %x\n",
+ fsize->pixel_format);
return -EINVAL;
}
memset(fsize->reserved, 0x0, sizeof(fsize->reserved));
- sdinfo = vpfe->current_subdev;
- if (!sdinfo->sd)
- return -EINVAL;
-
- memset(&pix, 0x0, sizeof(pix));
- /* Construct pix from parameter and use default for the rest */
- pix.pixelformat = fsize->pixel_format;
- pix.width = 640;
- pix.height = 480;
- pix.colorspace = V4L2_COLORSPACE_SRGB;
- pix.field = V4L2_FIELD_NONE;
- pix_to_mbus(vpfe, &pix, &mbus);
-
memset(&fse, 0x0, sizeof(fse));
fse.index = fsize->index;
fse.pad = 0;
- fse.code = mbus.code;
+ fse.code = fmt->code;
fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse);
+ ret = v4l2_subdev_call(sd, pad, enum_frame_size, NULL, &fse);
if (ret)
- return -EINVAL;
+ return ret;
- vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
- fse.index, fse.code, fse.min_width, fse.max_width,
- fse.min_height, fse.max_height);
+ vpfe_dbg(1, vpfe, "%s: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
+ __func__, fse.index, fse.code, fse.min_width, fse.max_width,
+ fse.min_height, fse.max_height);
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
fsize->discrete.width = fse.max_width;
fsize->discrete.height = fse.max_height;
- vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d pixformat: %s size: %dx%d\n",
- fsize->index, print_fourcc(fsize->pixel_format),
- fsize->discrete.width, fsize->discrete.height);
+ vpfe_dbg(1, vpfe, "%s: index: %d pixformat: %s size: %dx%d\n",
+ __func__, fsize->index, print_fourcc(fsize->pixel_format),
+ fsize->discrete.width, fsize->discrete.height);
return 0;
}
@@ -1725,8 +1594,6 @@ static int vpfe_enum_input(struct file *file, void *priv,
struct vpfe_subdev_info *sdinfo;
int subdev, index;
- vpfe_dbg(2, vpfe, "vpfe_enum_input\n");
-
if (vpfe_get_subdev_input_index(vpfe, &subdev, &index,
inp->index) < 0) {
vpfe_dbg(1, vpfe,
@@ -1743,8 +1610,6 @@ static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
{
struct vpfe_device *vpfe = video_drvdata(file);
- vpfe_dbg(2, vpfe, "vpfe_g_input\n");
-
return vpfe_get_app_input_index(vpfe, index);
}
@@ -1757,8 +1622,6 @@ static int vpfe_set_input(struct vpfe_device *vpfe, unsigned int index)
u32 input, output;
int ret;
- vpfe_dbg(2, vpfe, "vpfe_set_input: index: %d\n", index);
-
/* If streaming is started, return error */
if (vb2_is_busy(&vpfe->buffer_queue)) {
vpfe_err(vpfe, "%s device busy\n", __func__);
@@ -1814,9 +1677,6 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
{
struct vpfe_device *vpfe = video_drvdata(file);
- vpfe_dbg(2, vpfe,
- "vpfe_s_input: index: %d\n", index);
-
return vpfe_set_input(vpfe, index);
}
@@ -1825,8 +1685,6 @@ static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
struct vpfe_device *vpfe = video_drvdata(file);
struct vpfe_subdev_info *sdinfo;
- vpfe_dbg(2, vpfe, "vpfe_querystd\n");
-
sdinfo = vpfe->current_subdev;
if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD))
return -ENODATA;
@@ -1842,12 +1700,14 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id)
struct vpfe_subdev_info *sdinfo;
int ret;
- vpfe_dbg(2, vpfe, "vpfe_s_std\n");
-
sdinfo = vpfe->current_subdev;
if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD))
return -ENODATA;
+ /* if trying to set the same std then nothing to do */
+ if (vpfe_standards[vpfe->std_index].std_id == std_id)
+ return 0;
+
/* If streaming is started, return error */
if (vb2_is_busy(&vpfe->buffer_queue)) {
vpfe_err(vpfe, "%s device busy\n", __func__);
@@ -1871,8 +1731,6 @@ static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
struct vpfe_device *vpfe = video_drvdata(file);
struct vpfe_subdev_info *sdinfo;
- vpfe_dbg(2, vpfe, "vpfe_g_std\n");
-
sdinfo = vpfe->current_subdev;
if (sdinfo->inputs[0].capabilities != V4L2_IN_CAP_STD)
return -ENODATA;
@@ -1890,8 +1748,6 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe)
{
struct v4l2_rect image_win;
- vpfe_dbg(2, vpfe, "vpfe_calculate_offsets\n");
-
vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win);
vpfe->field_off = image_win.height * image_win.width;
}
@@ -1975,6 +1831,29 @@ static void vpfe_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags);
}
+static void vpfe_return_all_buffers(struct vpfe_device *vpfe,
+ enum vb2_buffer_state state)
+{
+ struct vpfe_cap_buffer *buf, *node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vpfe->dma_queue_lock, flags);
+ list_for_each_entry_safe(buf, node, &vpfe->dma_queue, list) {
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ list_del(&buf->list);
+ }
+
+ if (vpfe->cur_frm)
+ vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, state);
+
+ if (vpfe->next_frm && vpfe->next_frm != vpfe->cur_frm)
+ vb2_buffer_done(&vpfe->next_frm->vb.vb2_buf, state);
+
+ vpfe->cur_frm = NULL;
+ vpfe->next_frm = NULL;
+ spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags);
+}
+
/*
* vpfe_start_streaming : Starts the DMA engine for streaming
* @vb: ptr to vb2_buffer
@@ -1983,7 +1862,6 @@ static void vpfe_buffer_queue(struct vb2_buffer *vb)
static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vpfe_device *vpfe = vb2_get_drv_priv(vq);
- struct vpfe_cap_buffer *buf, *tmp;
struct vpfe_subdev_info *sdinfo;
unsigned long flags;
unsigned long addr;
@@ -1998,6 +1876,9 @@ static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count)
vpfe_attach_irq(vpfe);
+ vpfe->stopping = false;
+ init_completion(&vpfe->capture_stop);
+
if (vpfe->ccdc.ccdc_cfg.if_type == VPFE_RAW_BAYER)
vpfe_ccdc_config_raw(&vpfe->ccdc);
else
@@ -2026,11 +1907,8 @@ static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count)
return 0;
err:
- list_for_each_entry_safe(buf, tmp, &vpfe->dma_queue, list) {
- list_del(&buf->list);
- vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
- }
-
+ vpfe_return_all_buffers(vpfe, VB2_BUF_STATE_QUEUED);
+ vpfe_pcr_enable(&vpfe->ccdc, 0);
return ret;
}
@@ -2045,11 +1923,15 @@ static void vpfe_stop_streaming(struct vb2_queue *vq)
{
struct vpfe_device *vpfe = vb2_get_drv_priv(vq);
struct vpfe_subdev_info *sdinfo;
- unsigned long flags;
int ret;
vpfe_pcr_enable(&vpfe->ccdc, 0);
+ /* Wait for the last frame to be captured */
+ vpfe->stopping = true;
+ wait_for_completion_timeout(&vpfe->capture_stop,
+ msecs_to_jiffies(250));
+
vpfe_detach_irq(vpfe);
sdinfo = vpfe->current_subdev;
@@ -2058,27 +1940,7 @@ static void vpfe_stop_streaming(struct vb2_queue *vq)
vpfe_dbg(1, vpfe, "stream off failed in subdev\n");
/* release all active buffers */
- spin_lock_irqsave(&vpfe->dma_queue_lock, flags);
- if (vpfe->cur_frm == vpfe->next_frm) {
- vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf,
- VB2_BUF_STATE_ERROR);
- } else {
- if (vpfe->cur_frm != NULL)
- vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf,
- VB2_BUF_STATE_ERROR);
- if (vpfe->next_frm != NULL)
- vb2_buffer_done(&vpfe->next_frm->vb.vb2_buf,
- VB2_BUF_STATE_ERROR);
- }
-
- while (!list_empty(&vpfe->dma_queue)) {
- vpfe->next_frm = list_entry(vpfe->dma_queue.next,
- struct vpfe_cap_buffer, list);
- list_del(&vpfe->next_frm->list);
- vb2_buffer_done(&vpfe->next_frm->vb.vb2_buf,
- VB2_BUF_STATE_ERROR);
- }
- spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags);
+ vpfe_return_all_buffers(vpfe, VB2_BUF_STATE_ERROR);
}
static int vpfe_g_pixelaspect(struct file *file, void *priv,
@@ -2086,8 +1948,6 @@ static int vpfe_g_pixelaspect(struct file *file, void *priv,
{
struct vpfe_device *vpfe = video_drvdata(file);
- vpfe_dbg(2, vpfe, "vpfe_g_pixelaspect\n");
-
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
vpfe->std_index >= ARRAY_SIZE(vpfe_standards))
return -EINVAL;
@@ -2146,6 +2006,7 @@ vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
struct vpfe_device *vpfe = video_drvdata(file);
struct v4l2_rect cr = vpfe->crop;
struct v4l2_rect r = s->r;
+ u32 bpp;
/* If streaming is started, return error */
if (vb2_is_busy(&vpfe->buffer_queue)) {
@@ -2171,10 +2032,12 @@ vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
s->r = vpfe->crop = r;
- vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, vpfe->bpp);
+ bpp = __get_bytesperpixel(vpfe, vpfe->current_vpfe_fmt);
+ vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, bpp);
vpfe->fmt.fmt.pix.width = r.width;
vpfe->fmt.fmt.pix.height = r.height;
- vpfe->fmt.fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc);
+ vpfe->fmt.fmt.pix.bytesperline =
+ vpfe_ccdc_get_line_length(&vpfe->ccdc);
vpfe->fmt.fmt.pix.sizeimage = vpfe->fmt.fmt.pix.bytesperline *
vpfe->fmt.fmt.pix.height;
@@ -2190,8 +2053,6 @@ static long vpfe_ioctl_default(struct file *file, void *priv,
struct vpfe_device *vpfe = video_drvdata(file);
int ret;
- vpfe_dbg(2, vpfe, "vpfe_ioctl_default\n");
-
if (!valid_prio) {
vpfe_err(vpfe, "%s device busy\n", __func__);
return -EBUSY;
@@ -2297,10 +2158,10 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier,
struct vpfe_device, v4l2_dev);
struct v4l2_subdev_mbus_code_enum mbus_code;
struct vpfe_subdev_info *sdinfo;
+ struct vpfe_fmt *fmt;
+ int ret = 0;
bool found = false;
- int i, j;
-
- vpfe_dbg(1, vpfe, "vpfe_async_bound\n");
+ int i, j, k;
for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) {
if (vpfe->cfg->asd[i]->match.fwnode ==
@@ -2320,27 +2181,37 @@ vpfe_async_bound(struct v4l2_async_notifier *notifier,
vpfe->video_dev.tvnorms |= sdinfo->inputs[0].std;
- /* setup the supported formats & indexes */
- for (j = 0, i = 0; ; ++j) {
- struct vpfe_fmt *fmt;
- int ret;
-
+ vpfe->num_active_fmt = 0;
+ for (j = 0, i = 0; (ret != -EINVAL); ++j) {
memset(&mbus_code, 0, sizeof(mbus_code));
mbus_code.index = j;
mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(subdev, pad, enum_mbus_code,
- NULL, &mbus_code);
+ NULL, &mbus_code);
if (ret)
- break;
-
- fmt = find_format_by_code(mbus_code.code);
- if (!fmt)
continue;
- fmt->supported = true;
- fmt->index = i++;
+ vpfe_dbg(3, vpfe,
+ "subdev %s: code: %04x idx: %d\n",
+ subdev->name, mbus_code.code, j);
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+ fmt = &formats[k];
+ if (mbus_code.code != fmt->code)
+ continue;
+ vpfe->active_fmt[i] = fmt;
+ vpfe_dbg(3, vpfe,
+ "matched fourcc: %s code: %04x idx: %d\n",
+ print_fourcc(fmt->fourcc), mbus_code.code, i);
+ vpfe->num_active_fmt = ++i;
+ }
}
+ if (!i) {
+ vpfe_err(vpfe, "No suitable format reported by subdev %s\n",
+ subdev->name);
+ return -EINVAL;
+ }
return 0;
}
@@ -2393,6 +2264,8 @@ static int vpfe_probe_complete(struct vpfe_device *vpfe)
vdev->vfl_dir = VFL_DIR_RX;
vdev->queue = q;
vdev->lock = &vpfe->lock;
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
video_set_drvdata(vdev, vpfe);
err = video_register_device(&vpfe->video_dev, VFL_TYPE_GRABBER, -1);
if (err) {
@@ -2505,10 +2378,9 @@ vpfe_get_pdata(struct vpfe_device *vpfe)
pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev(
&vpfe->notifier, of_fwnode_handle(rem),
sizeof(struct v4l2_async_subdev));
- if (IS_ERR(pdata->asd[i])) {
- of_node_put(rem);
+ of_node_put(rem);
+ if (IS_ERR(pdata->asd[i]))
goto cleanup;
- }
}
of_node_put(endpoint);
@@ -2557,7 +2429,6 @@ static int vpfe_probe(struct platform_device *pdev)
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
- dev_err(&pdev->dev, "No IRQ resource\n");
ret = -ENODEV;
goto probe_out_cleanup;
}
@@ -2623,8 +2494,6 @@ static int vpfe_remove(struct platform_device *pdev)
{
struct vpfe_device *vpfe = platform_get_drvdata(pdev);
- vpfe_dbg(2, vpfe, "vpfe_remove\n");
-
pm_runtime_disable(&pdev->dev);
v4l2_async_notifier_unregister(&vpfe->notifier);
@@ -2671,22 +2540,21 @@ static int vpfe_suspend(struct device *dev)
struct vpfe_device *vpfe = dev_get_drvdata(dev);
struct vpfe_ccdc *ccdc = &vpfe->ccdc;
- /* if streaming has not started we don't care */
- if (!vb2_start_streaming_called(&vpfe->buffer_queue))
- return 0;
-
- pm_runtime_get_sync(dev);
- vpfe_config_enable(ccdc, 1);
+ /* only do full suspend if streaming has started */
+ if (vb2_start_streaming_called(&vpfe->buffer_queue)) {
+ pm_runtime_get_sync(dev);
+ vpfe_config_enable(ccdc, 1);
- /* Save VPFE context */
- vpfe_save_context(ccdc);
+ /* Save VPFE context */
+ vpfe_save_context(ccdc);
- /* Disable CCDC */
- vpfe_pcr_enable(ccdc, 0);
- vpfe_config_enable(ccdc, 0);
+ /* Disable CCDC */
+ vpfe_pcr_enable(ccdc, 0);
+ vpfe_config_enable(ccdc, 0);
- /* Disable both master and slave clock */
- pm_runtime_put_sync(dev);
+ /* Disable both master and slave clock */
+ pm_runtime_put_sync(dev);
+ }
/* Select sleep pin state */
pinctrl_pm_select_sleep_state(dev);
@@ -2728,19 +2596,18 @@ static int vpfe_resume(struct device *dev)
struct vpfe_device *vpfe = dev_get_drvdata(dev);
struct vpfe_ccdc *ccdc = &vpfe->ccdc;
- /* if streaming has not started we don't care */
- if (!vb2_start_streaming_called(&vpfe->buffer_queue))
- return 0;
-
- /* Enable both master and slave clock */
- pm_runtime_get_sync(dev);
- vpfe_config_enable(ccdc, 1);
+ /* only do full resume if streaming has started */
+ if (vb2_start_streaming_called(&vpfe->buffer_queue)) {
+ /* Enable both master and slave clock */
+ pm_runtime_get_sync(dev);
+ vpfe_config_enable(ccdc, 1);
- /* Restore VPFE context */
- vpfe_restore_context(ccdc);
+ /* Restore VPFE context */
+ vpfe_restore_context(ccdc);
- vpfe_config_enable(ccdc, 0);
- pm_runtime_put_sync(dev);
+ vpfe_config_enable(ccdc, 0);
+ pm_runtime_put_sync(dev);
+ }
/* Select default pin state */
pinctrl_pm_select_default_state(dev);
diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h
index 17d7aa426788..05ee37db0273 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.h
+++ b/drivers/media/platform/am437x/am437x-vpfe.h
@@ -1,21 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2013 - 2014 Texas Instruments, Inc.
*
* Benoit Parrot <bparrot@ti.com>
* Lad, Prabhakar <prabhakar.csengg@gmail.com>
- *
- * This program is free software; you may redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
*/
#ifndef AM437X_VPFE_H
@@ -23,6 +11,7 @@
#include <linux/am437x-vpfe.h>
#include <linux/clk.h>
+#include <linux/completion.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/i2c.h>
@@ -65,12 +54,6 @@ struct vpfe_hw_if_param {
#define VPFE_MAX_SUBDEV 1
#define VPFE_MAX_INPUTS 1
-struct vpfe_pixel_format {
- struct v4l2_fmtdesc fmtdesc;
- /* bytes per pixel */
- int bpp;
-};
-
struct vpfe_std_info {
int active_pixels;
int active_lines;
@@ -220,6 +203,25 @@ struct vpfe_ccdc {
u32 ccdc_ctx[VPFE_REG_END / sizeof(u32)];
};
+/*
+ * struct vpfe_fmt - VPFE media bus format information
+ * fourcc: V4L2 pixel format code
+ * code: V4L2 media bus format code
+ * bitsperpixel: Bits per pixel over the bus
+ */
+struct vpfe_fmt {
+ u32 fourcc;
+ u32 code;
+ u32 bitsperpixel;
+};
+
+/*
+ * When formats[] is modified make sure to adjust this value also.
+ * Expect compile time warnings if VPFE_NUM_FORMATS is smaller then
+ * the number of elements in formats[].
+ */
+#define VPFE_NUM_FORMATS 10
+
struct vpfe_device {
/* V4l2 specific parameters */
/* Identifies video device for this channel */
@@ -255,8 +257,11 @@ struct vpfe_device {
struct vpfe_cap_buffer *next_frm;
/* Used to store pixel format */
struct v4l2_format fmt;
- /* Used to store current bytes per pixel based on current format */
- unsigned int bpp;
+ /* Used to keep a reference to the current vpfe_fmt */
+ struct vpfe_fmt *current_vpfe_fmt;
+ struct vpfe_fmt *active_fmt[VPFE_NUM_FORMATS];
+ unsigned int num_active_fmt;
+
/*
* used when IMP is chained to store the crop window which
* is different from the image window
@@ -276,6 +281,8 @@ struct vpfe_device {
*/
u32 field_off;
struct vpfe_ccdc ccdc;
+ int stopping;
+ struct completion capture_stop;
};
#endif /* AM437X_VPFE_H */
diff --git a/drivers/media/platform/am437x/am437x-vpfe_regs.h b/drivers/media/platform/am437x/am437x-vpfe_regs.h
index 4a0ed29723e8..63ecdca3b908 100644
--- a/drivers/media/platform/am437x/am437x-vpfe_regs.h
+++ b/drivers/media/platform/am437x/am437x-vpfe_regs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* TI AM437x Image Sensor Interface Registers
*
@@ -5,15 +6,6 @@
*
* Benoit Parrot <bparrot@ti.com>
* Lad, Prabhakar <prabhakar.csengg@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef AM437X_VPFE_REGS_H
@@ -66,13 +58,13 @@
#define VPFE_PIX_FMT_MASK 3
#define VPFE_PIX_FMT_SHIFT 12
#define VPFE_VP2SDR_DISABLE 0xfffbffff
-#define VPFE_WEN_ENABLE (1 << 17)
+#define VPFE_WEN_ENABLE BIT(17)
#define VPFE_SDR2RSZ_DISABLE 0xfff7ffff
-#define VPFE_VDHDEN_ENABLE (1 << 16)
-#define VPFE_LPF_ENABLE (1 << 14)
-#define VPFE_ALAW_ENABLE (1 << 3)
+#define VPFE_VDHDEN_ENABLE BIT(16)
+#define VPFE_LPF_ENABLE BIT(14)
+#define VPFE_ALAW_ENABLE BIT(3)
#define VPFE_ALAW_GAMMA_WD_MASK 7
-#define VPFE_BLK_CLAMP_ENABLE (1 << 31)
+#define VPFE_BLK_CLAMP_ENABLE BIT(31)
#define VPFE_BLK_SGAIN_MASK 0x1f
#define VPFE_BLK_ST_PXL_MASK 0x7fff
#define VPFE_BLK_ST_PXL_SHIFT 10
@@ -85,8 +77,8 @@
#define VPFE_BLK_COMP_GB_COMP_SHIFT 8
#define VPFE_BLK_COMP_GR_COMP_SHIFT 16
#define VPFE_BLK_COMP_R_COMP_SHIFT 24
-#define VPFE_LATCH_ON_VSYNC_DISABLE (1 << 15)
-#define VPFE_DATA_PACK_ENABLE (1 << 11)
+#define VPFE_LATCH_ON_VSYNC_DISABLE BIT(15)
+#define VPFE_DATA_PACK_ENABLE BIT(11)
#define VPFE_HORZ_INFO_SPH_SHIFT 16
#define VPFE_VERT_START_SLV0_SHIFT 16
#define VPFE_VDINT_VDINT0_SHIFT 16
@@ -114,15 +106,15 @@
#define VPFE_SYN_FLDMODE_MASK 1
#define VPFE_SYN_FLDMODE_SHIFT 7
#define VPFE_REC656IF_BT656_EN 3
-#define VPFE_SYN_MODE_VD_POL_NEGATIVE (1 << 2)
+#define VPFE_SYN_MODE_VD_POL_NEGATIVE BIT(2)
#define VPFE_CCDCFG_Y8POS_SHIFT 11
-#define VPFE_CCDCFG_BW656_10BIT (1 << 5)
+#define VPFE_CCDCFG_BW656_10BIT BIT(5)
#define VPFE_SDOFST_FIELD_INTERLEAVED 0x249
#define VPFE_NO_CULLING 0xffff00ff
-#define VPFE_VDINT0 (1 << 0)
-#define VPFE_VDINT1 (1 << 1)
-#define VPFE_VDINT2 (1 << 2)
-#define VPFE_DMA_CNTL_OVERFLOW (1 << 31)
+#define VPFE_VDINT0 BIT(0)
+#define VPFE_VDINT1 BIT(1)
+#define VPFE_VDINT2 BIT(2)
+#define VPFE_DMA_CNTL_OVERFLOW BIT(31)
#define VPFE_CONFIG_PCLK_INV_SHIFT 0
#define VPFE_CONFIG_PCLK_INV_MASK 1
diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
index f899ac3b4a61..d8593cb2ae84 100644
--- a/drivers/media/platform/aspeed-video.c
+++ b/drivers/media/platform/aspeed-video.c
@@ -606,6 +606,16 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg)
aspeed_video_start_frame(video);
}
+ /*
+ * CAPTURE_COMPLETE and FRAME_COMPLETE interrupts come even when these
+ * are disabled in the VE_INTERRUPT_CTRL register so clear them to
+ * prevent unnecessary interrupt calls.
+ */
+ if (sts & VE_INTERRUPT_CAPTURE_COMPLETE)
+ sts &= ~VE_INTERRUPT_CAPTURE_COMPLETE;
+ if (sts & VE_INTERRUPT_FRAME_COMPLETE)
+ sts &= ~VE_INTERRUPT_FRAME_COMPLETE;
+
return sts ? IRQ_NONE : IRQ_HANDLED;
}
@@ -614,7 +624,7 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video)
int i;
int hsync_counter = 0;
int vsync_counter = 0;
- u32 sts;
+ u32 sts, ctrl;
for (i = 0; i < NUM_POLARITY_CHECKS; ++i) {
sts = aspeed_video_read(video, VE_MODE_DETECT_STATUS);
@@ -629,29 +639,29 @@ static void aspeed_video_check_and_set_polarity(struct aspeed_video *video)
hsync_counter++;
}
- if (hsync_counter < 0 || vsync_counter < 0) {
- u32 ctrl;
+ ctrl = aspeed_video_read(video, VE_CTRL);
- if (hsync_counter < 0) {
- ctrl = VE_CTRL_HSYNC_POL;
- video->detected_timings.polarities &=
- ~V4L2_DV_HSYNC_POS_POL;
- } else {
- video->detected_timings.polarities |=
- V4L2_DV_HSYNC_POS_POL;
- }
-
- if (vsync_counter < 0) {
- ctrl = VE_CTRL_VSYNC_POL;
- video->detected_timings.polarities &=
- ~V4L2_DV_VSYNC_POS_POL;
- } else {
- video->detected_timings.polarities |=
- V4L2_DV_VSYNC_POS_POL;
- }
+ if (hsync_counter < 0) {
+ ctrl |= VE_CTRL_HSYNC_POL;
+ video->detected_timings.polarities &=
+ ~V4L2_DV_HSYNC_POS_POL;
+ } else {
+ ctrl &= ~VE_CTRL_HSYNC_POL;
+ video->detected_timings.polarities |=
+ V4L2_DV_HSYNC_POS_POL;
+ }
- aspeed_video_update(video, VE_CTRL, 0, ctrl);
+ if (vsync_counter < 0) {
+ ctrl |= VE_CTRL_VSYNC_POL;
+ video->detected_timings.polarities &=
+ ~V4L2_DV_VSYNC_POS_POL;
+ } else {
+ ctrl &= ~VE_CTRL_VSYNC_POL;
+ video->detected_timings.polarities |=
+ V4L2_DV_VSYNC_POS_POL;
}
+
+ aspeed_video_write(video, VE_CTRL, ctrl);
}
static bool aspeed_video_alloc_buf(struct aspeed_video *video,
@@ -740,6 +750,8 @@ static void aspeed_video_get_resolution(struct aspeed_video *video)
}
set_bit(VIDEO_RES_DETECT, &video->flags);
+ aspeed_video_update(video, VE_CTRL,
+ VE_CTRL_VSYNC_POL | VE_CTRL_HSYNC_POL, 0);
aspeed_video_enable_mode_detect(video);
rc = wait_event_interruptible_timeout(video->wait,
@@ -1624,6 +1636,7 @@ static int aspeed_video_init(struct aspeed_video *video)
if (!aspeed_video_alloc_buf(video, &video->jpeg,
VE_JPEG_HEADER_SIZE)) {
dev_err(dev, "Failed to allocate DMA for JPEG header\n");
+ rc = -ENOMEM;
goto err_release_reserved_mem;
}
@@ -1644,7 +1657,8 @@ static int aspeed_video_probe(struct platform_device *pdev)
{
int rc;
struct resource *res;
- struct aspeed_video *video = kzalloc(sizeof(*video), GFP_KERNEL);
+ struct aspeed_video *video =
+ devm_kzalloc(&pdev->dev, sizeof(*video), GFP_KERNEL);
if (!video)
return -ENOMEM;
diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c
index c1c776b348a9..d7669a03e98e 100644
--- a/drivers/media/platform/atmel/atmel-isc-base.c
+++ b/drivers/media/platform/atmel/atmel-isc-base.c
@@ -73,6 +73,9 @@ const struct isc_format controller_formats[] = {
{
.fourcc = V4L2_PIX_FMT_GREY,
},
+ {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ },
};
/* This is a list of formats that the ISC can receive as *input* */
@@ -164,6 +167,12 @@ struct isc_format formats_list[] = {
.mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
},
+ {
+ .fourcc = V4L2_PIX_FMT_Y10,
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
+ .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
+ },
+
};
/* Gamma table with gamma 1/2.2 */
@@ -211,6 +220,10 @@ const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = {
#define ISC_IS_FORMAT_RAW(mbus_code) \
(((mbus_code) & 0xf000) == 0x3000)
+#define ISC_IS_FORMAT_GREY(mbus_code) \
+ (((mbus_code) == MEDIA_BUS_FMT_Y10_1X10) | \
+ (((mbus_code) == MEDIA_BUS_FMT_Y8_1X8)))
+
static inline void isc_update_awb_ctrls(struct isc_device *isc)
{
struct isc_ctrls *ctrls = &isc->ctrls;
@@ -1003,6 +1016,7 @@ static int isc_try_validate_formats(struct isc_device *isc)
rgb = true;
break;
case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y10:
ret = 0;
grey = true;
break;
@@ -1010,34 +1024,29 @@ static int isc_try_validate_formats(struct isc_device *isc)
/* any other different formats are not supported */
ret = -EINVAL;
}
-
- /* 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);
+ /* we cannot output RAW if we do not receive RAW */
+ if ((bayer) && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code))
+ return -EINVAL;
+
+ /* we cannot output GREY if we do not receive RAW/GREY */
+ if (grey && !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code) &&
+ !ISC_IS_FORMAT_GREY(isc->try_config.sd_format->mbus_code))
+ return -EINVAL;
+
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.
+ * If direct_dump == true, just dump raw data 8/16 bits depending on format.
*/
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:
@@ -1115,9 +1124,23 @@ static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump)
isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
isc->try_config.bpp = 8;
break;
+ case V4L2_PIX_FMT_Y10:
+ isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY10;
+ isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16;
+ isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED;
+ isc->try_config.bpp = 16;
+ break;
default:
return -EINVAL;
}
+
+ 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;
+ return 0;
+ }
+
return 0;
}
@@ -1187,13 +1210,44 @@ static int isc_try_configure_pipeline(struct isc_device *isc)
return 0;
}
+static void isc_try_fse(struct isc_device *isc,
+ struct v4l2_subdev_pad_config *pad_cfg)
+{
+ int ret;
+ struct v4l2_subdev_frame_size_enum fse = {};
+
+ /*
+ * If we do not know yet which format the subdev is using, we cannot
+ * do anything.
+ */
+ if (!isc->try_config.sd_format)
+ return;
+
+ fse.code = isc->try_config.sd_format->mbus_code;
+ fse.which = V4L2_SUBDEV_FORMAT_TRY;
+
+ ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size,
+ pad_cfg, &fse);
+ /*
+ * Attempt to obtain format size from subdev. If not available,
+ * just use the maximum ISC can receive.
+ */
+ if (ret) {
+ pad_cfg->try_crop.width = ISC_MAX_SUPPORT_WIDTH;
+ pad_cfg->try_crop.height = ISC_MAX_SUPPORT_HEIGHT;
+ } else {
+ pad_cfg->try_crop.width = fse.max_width;
+ pad_cfg->try_crop.height = fse.max_height;
+ }
+}
+
static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
u32 *code)
{
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_pad_config pad_cfg = {};
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -1290,6 +1344,9 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f,
if (ret)
goto isc_try_fmt_err;
+ /* Obtain frame sizes if possible to have crop requirements ready */
+ isc_try_fse(isc, &pad_cfg);
+
v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code);
ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt,
&pad_cfg, &format);
@@ -1414,6 +1471,7 @@ static int isc_enum_framesizes(struct file *file, void *fh,
{
struct isc_device *isc = video_drvdata(file);
struct v4l2_subdev_frame_size_enum fse = {
+ .code = isc->config.sd_format->mbus_code,
.index = fsize->index,
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
@@ -1436,8 +1494,6 @@ static int isc_enum_framesizes(struct file *file, void *fh,
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;
@@ -1450,6 +1506,7 @@ static int isc_enum_frameintervals(struct file *file, void *fh,
{
struct isc_device *isc = video_drvdata(file);
struct v4l2_subdev_frame_interval_enum fie = {
+ .code = isc->config.sd_format->mbus_code,
.index = fival->index,
.width = fival->width,
.height = fival->height,
@@ -1474,7 +1531,6 @@ static int isc_enum_frameintervals(struct file *file, void *fh,
if (ret)
return ret;
- fie.code = isc->config.sd_format->mbus_code;
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fival->discrete = fie.interval;
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index d7d94c1a39d3..963dfd6e750e 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -148,7 +148,8 @@ static void configure_geometry(struct atmel_isi *isi)
u32 fourcc = isi->current_fmt->fourcc;
isi->enable_preview_path = fourcc == V4L2_PIX_FMT_RGB565 ||
- fourcc == V4L2_PIX_FMT_RGB32;
+ fourcc == V4L2_PIX_FMT_RGB32 ||
+ fourcc == V4L2_PIX_FMT_Y16;
/* According to sensor's output format to set cfg2 */
cfg2 = isi->current_fmt->swap;
@@ -493,7 +494,7 @@ static void stop_streaming(struct vb2_queue *vq)
spin_unlock_irq(&isi->irqlock);
if (!isi->enable_preview_path) {
- timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
+ timeout = jiffies + (FRAME_INTERVAL_MILLI_SEC * HZ) / 1000;
/* Wait until the end of the current frame. */
while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
time_before(jiffies, timeout))
@@ -554,12 +555,36 @@ static const struct isi_format *find_format_by_fourcc(struct atmel_isi *isi,
return NULL;
}
+static void isi_try_fse(struct atmel_isi *isi, const struct isi_format *isi_fmt,
+ struct v4l2_subdev_pad_config *pad_cfg)
+{
+ int ret;
+ struct v4l2_subdev_frame_size_enum fse = {
+ .code = isi_fmt->mbus_code,
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ };
+
+ ret = v4l2_subdev_call(isi->entity.subdev, pad, enum_frame_size,
+ pad_cfg, &fse);
+ /*
+ * Attempt to obtain format size from subdev. If not available,
+ * just use the maximum ISI can receive.
+ */
+ if (ret) {
+ pad_cfg->try_crop.width = MAX_SUPPORT_WIDTH;
+ pad_cfg->try_crop.height = MAX_SUPPORT_HEIGHT;
+ } else {
+ pad_cfg->try_crop.width = fse.max_width;
+ pad_cfg->try_crop.height = fse.max_height;
+ }
+}
+
static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f,
const struct isi_format **current_fmt)
{
const struct isi_format *isi_fmt;
struct v4l2_pix_format *pixfmt = &f->fmt.pix;
- struct v4l2_subdev_pad_config pad_cfg;
+ struct v4l2_subdev_pad_config pad_cfg = {};
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -576,6 +601,9 @@ static int isi_try_fmt(struct atmel_isi *isi, struct v4l2_format *f,
pixfmt->height = clamp(pixfmt->height, 0U, MAX_SUPPORT_HEIGHT);
v4l2_fill_mbus_format(&format.format, pixfmt, isi_fmt->mbus_code);
+
+ isi_try_fse(isi, isi_fmt, &pad_cfg);
+
ret = v4l2_subdev_call(isi->entity.subdev, pad, set_fmt,
&pad_cfg, &format);
if (ret < 0)
@@ -990,6 +1018,16 @@ static const struct isi_format isi_formats[] = {
.mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
.bpp = 2,
.swap = ISI_CFG2_YCC_SWAP_MODE_1,
+ }, {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
+ .bpp = 1,
+ .swap = ISI_CFG2_GS_MODE_2_PIXEL | ISI_CFG2_GRAYSCALE,
+ }, {
+ .fourcc = V4L2_PIX_FMT_Y16,
+ .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
+ .bpp = 2,
+ .swap = ISI_CFG2_GS_MODE_2_PIXEL | ISI_CFG2_GRAYSCALE,
},
};
diff --git a/drivers/media/platform/atmel/atmel-isi.h b/drivers/media/platform/atmel/atmel-isi.h
index 47a9108dba55..7ad3895a2c87 100644
--- a/drivers/media/platform/atmel/atmel-isi.h
+++ b/drivers/media/platform/atmel/atmel-isi.h
@@ -62,6 +62,8 @@
#define ISI_CFG1_THMASK_BEATS_16 (2 << 13)
/* Bitfields in CFG2 */
+#define ISI_CFG2_GS_MODE_2_PIXEL (0 << 11)
+#define ISI_CFG2_GS_MODE_1_PIXEL (1 << 11)
#define ISI_CFG2_GRAYSCALE (1 << 13)
#define ISI_CFG2_COL_SPACE_YCbCr (0 << 15)
#define ISI_CFG2_COL_SPACE_RGB (1 << 15)
diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c
index 266df14da2d5..78381651238d 100644
--- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c
+++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c
@@ -160,11 +160,8 @@ static int atmel_isc_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- dev_err(dev, "failed to get irq: %d\n", ret);
- return ret;
- }
+ if (irq < 0)
+ return irq;
ret = devm_request_irq(dev, irq, isc_interrupt, 0,
ATMEL_ISC_NAME, isc);
diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index 31ace114eda1..be9ec59774d6 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -129,7 +129,7 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx)
*/
for (i = csi2rx->num_lanes; i < csi2rx->max_lanes; i++) {
unsigned int idx = find_first_zero_bit(&lanes_used,
- sizeof(lanes_used));
+ csi2rx->max_lanes);
set_bit(idx, &lanes_used);
reg |= CSI2RX_STATIC_CFG_DLANE_MAP(i, i + 1);
}
diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c
index 5042d053b94e..e4d08acfbb49 100644
--- a/drivers/media/platform/cadence/cdns-csi2tx.c
+++ b/drivers/media/platform/cadence/cdns-csi2tx.c
@@ -2,7 +2,7 @@
/*
* Driver for Cadence MIPI-CSI2 TX Controller
*
- * Copyright (C) 2017-2018 Cadence Design Systems Inc.
+ * Copyright (C) 2017-2019 Cadence Design Systems Inc.
*/
#include <linux/clk.h>
@@ -52,6 +52,17 @@
#define CSI2TX_STREAM_IF_CFG_REG(n) (0x100 + (n) * 4)
#define CSI2TX_STREAM_IF_CFG_FILL_LEVEL(n) ((n) & 0x1f)
+/* CSI2TX V2 Registers */
+#define CSI2TX_V2_DPHY_CFG_REG 0x28
+#define CSI2TX_V2_DPHY_CFG_RESET BIT(16)
+#define CSI2TX_V2_DPHY_CFG_CLOCK_MODE BIT(10)
+#define CSI2TX_V2_DPHY_CFG_MODE_MASK GENMASK(9, 8)
+#define CSI2TX_V2_DPHY_CFG_MODE_LPDT (2 << 8)
+#define CSI2TX_V2_DPHY_CFG_MODE_HS (1 << 8)
+#define CSI2TX_V2_DPHY_CFG_MODE_ULPS (0 << 8)
+#define CSI2TX_V2_DPHY_CFG_CLK_ENABLE BIT(4)
+#define CSI2TX_V2_DPHY_CFG_LANE_ENABLE(n) BIT(n)
+
#define CSI2TX_LANES_MAX 4
#define CSI2TX_STREAMS_MAX 4
@@ -70,6 +81,13 @@ struct csi2tx_fmt {
u32 bpp;
};
+struct csi2tx_priv;
+
+/* CSI2TX Variant Operations */
+struct csi2tx_vops {
+ void (*dphy_setup)(struct csi2tx_priv *csi2tx);
+};
+
struct csi2tx_priv {
struct device *dev;
unsigned int count;
@@ -82,6 +100,8 @@ struct csi2tx_priv {
void __iomem *base;
+ struct csi2tx_vops *vops;
+
struct clk *esc_clk;
struct clk *p_clk;
struct clk *pixel_clk[CSI2TX_STREAMS_MAX];
@@ -209,53 +229,92 @@ static const struct v4l2_subdev_pad_ops csi2tx_pad_ops = {
.set_fmt = csi2tx_set_pad_format,
};
-static void csi2tx_reset(struct csi2tx_priv *csi2tx)
+/* Set Wake Up value in the D-PHY */
+static void csi2tx_dphy_set_wakeup(struct csi2tx_priv *csi2tx)
{
- writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG);
-
- udelay(10);
+ writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32),
+ csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG);
}
-static int csi2tx_start(struct csi2tx_priv *csi2tx)
+/*
+ * Finishes the D-PHY initialization
+ * reg dphy cfg value to be used
+ */
+static void csi2tx_dphy_init_finish(struct csi2tx_priv *csi2tx, u32 reg)
{
- struct media_entity *entity = &csi2tx->subdev.entity;
- struct media_link *link;
unsigned int i;
- u32 reg;
- csi2tx_reset(csi2tx);
+ udelay(10);
- writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG);
+ /* Enable our (clock and data) lanes */
+ reg |= CSI2TX_DPHY_CFG_CLK_ENABLE;
+ for (i = 0; i < csi2tx->num_lanes; i++)
+ reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i] - 1);
+ writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
udelay(10);
- /* Configure our PPI interface with the D-PHY */
- writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32),
- csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG);
+ /* Switch to HS mode */
+ reg &= ~CSI2TX_DPHY_CFG_MODE_MASK;
+ writel(reg | CSI2TX_DPHY_CFG_MODE_HS,
+ csi2tx->base + CSI2TX_DPHY_CFG_REG);
+}
+
+/* Configures D-PHY in CSIv1.3 */
+static void csi2tx_dphy_setup(struct csi2tx_priv *csi2tx)
+{
+ u32 reg;
+ unsigned int i;
+
+ csi2tx_dphy_set_wakeup(csi2tx);
/* Put our lanes (clock and data) out of reset */
reg = CSI2TX_DPHY_CFG_CLK_RESET | CSI2TX_DPHY_CFG_MODE_LPDT;
for (i = 0; i < csi2tx->num_lanes; i++)
- reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i]);
+ reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i] - 1);
writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
- udelay(10);
+ csi2tx_dphy_init_finish(csi2tx, reg);
+}
- /* Enable our (clock and data) lanes */
- reg |= CSI2TX_DPHY_CFG_CLK_ENABLE;
- for (i = 0; i < csi2tx->num_lanes; i++)
- reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i]);
- writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
+/* Configures D-PHY in CSIv2 */
+static void csi2tx_v2_dphy_setup(struct csi2tx_priv *csi2tx)
+{
+ u32 reg;
+
+ csi2tx_dphy_set_wakeup(csi2tx);
+
+ /* Put our lanes (clock and data) out of reset */
+ reg = CSI2TX_V2_DPHY_CFG_RESET | CSI2TX_V2_DPHY_CFG_MODE_LPDT;
+ writel(reg, csi2tx->base + CSI2TX_V2_DPHY_CFG_REG);
+
+ csi2tx_dphy_init_finish(csi2tx, reg);
+}
+
+static void csi2tx_reset(struct csi2tx_priv *csi2tx)
+{
+ writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG);
udelay(10);
+}
- /* Switch to HS mode */
- reg &= ~CSI2TX_DPHY_CFG_MODE_MASK;
- writel(reg | CSI2TX_DPHY_CFG_MODE_HS,
- csi2tx->base + CSI2TX_DPHY_CFG_REG);
+static int csi2tx_start(struct csi2tx_priv *csi2tx)
+{
+ struct media_entity *entity = &csi2tx->subdev.entity;
+ struct media_link *link;
+ unsigned int i;
+
+ csi2tx_reset(csi2tx);
+
+ writel(CSI2TX_CONFIG_CFG_REQ, csi2tx->base + CSI2TX_CONFIG_REG);
udelay(10);
+ if (csi2tx->vops && csi2tx->vops->dphy_setup) {
+ csi2tx->vops->dphy_setup(csi2tx);
+ udelay(10);
+ }
+
/*
* Create a static mapping between the CSI virtual channels
* and the input streams.
@@ -434,7 +493,7 @@ static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx)
{
struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
struct device_node *ep;
- int ret;
+ int ret, i;
ep = of_graph_get_endpoint_by_regs(csi2tx->dev->of_node, 0, 0);
if (!ep)
@@ -461,6 +520,15 @@ static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx)
goto out;
}
+ for (i = 0; i < csi2tx->num_lanes; i++) {
+ if (v4l2_ep.bus.mipi_csi2.data_lanes[i] < 1) {
+ dev_err(csi2tx->dev, "Invalid lane[%d] number: %u\n",
+ i, v4l2_ep.bus.mipi_csi2.data_lanes[i]);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
memcpy(csi2tx->lanes, v4l2_ep.bus.mipi_csi2.data_lanes,
sizeof(csi2tx->lanes));
@@ -469,9 +537,35 @@ out:
return ret;
}
+static const struct csi2tx_vops csi2tx_vops = {
+ .dphy_setup = csi2tx_dphy_setup,
+};
+
+static const struct csi2tx_vops csi2tx_v2_vops = {
+ .dphy_setup = csi2tx_v2_dphy_setup,
+};
+
+static const struct of_device_id csi2tx_of_table[] = {
+ {
+ .compatible = "cdns,csi2tx",
+ .data = &csi2tx_vops
+ },
+ {
+ .compatible = "cdns,csi2tx-1.3",
+ .data = &csi2tx_vops
+ },
+ {
+ .compatible = "cdns,csi2tx-2.1",
+ .data = &csi2tx_v2_vops
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, csi2tx_of_table);
+
static int csi2tx_probe(struct platform_device *pdev)
{
struct csi2tx_priv *csi2tx;
+ const struct of_device_id *of_id;
unsigned int i;
int ret;
@@ -486,6 +580,9 @@ static int csi2tx_probe(struct platform_device *pdev)
if (ret)
goto err_free_priv;
+ of_id = of_match_node(csi2tx_of_table, pdev->dev.of_node);
+ csi2tx->vops = (struct csi2tx_vops *)of_id->data;
+
v4l2_subdev_init(&csi2tx->subdev, &csi2tx_subdev_ops);
csi2tx->subdev.owner = THIS_MODULE;
csi2tx->subdev.dev = &pdev->dev;
@@ -543,12 +640,6 @@ static int csi2tx_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id csi2tx_of_table[] = {
- { .compatible = "cdns,csi2tx" },
- { },
-};
-MODULE_DEVICE_TABLE(of, csi2tx_of_table);
-
static struct platform_driver csi2tx_driver = {
.probe = csi2tx_probe,
.remove = csi2tx_remove,
diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c
index 5b17d3a31896..42d2c2cd9a78 100644
--- a/drivers/media/platform/cec-gpio/cec-gpio.c
+++ b/drivers/media/platform/cec-gpio/cec-gpio.c
@@ -8,10 +8,12 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
+#include <media/cec-notifier.h>
#include <media/cec-pin.h>
struct cec_gpio {
struct cec_adapter *adap;
+ struct cec_notifier *notifier;
struct device *dev;
struct gpio_desc *cec_gpio;
@@ -173,9 +175,17 @@ static const struct cec_pin_ops cec_gpio_pin_ops = {
static int cec_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct device *hdmi_dev;
struct cec_gpio *cec;
+ u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN;
int ret;
+ hdmi_dev = cec_notifier_parse_hdmi_phandle(dev);
+ if (PTR_ERR(hdmi_dev) == -EPROBE_DEFER)
+ return PTR_ERR(hdmi_dev);
+ if (IS_ERR(hdmi_dev))
+ caps |= CEC_CAP_PHYS_ADDR;
+
cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL);
if (!cec)
return -ENOMEM;
@@ -196,8 +206,7 @@ static int cec_gpio_probe(struct platform_device *pdev)
return PTR_ERR(cec->v5_gpio);
cec->adap = cec_pin_allocate_adapter(&cec_gpio_pin_ops,
- cec, pdev->name, CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR |
- CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN);
+ cec, pdev->name, caps);
if (IS_ERR(cec->adap))
return PTR_ERR(cec->adap);
@@ -205,7 +214,7 @@ static int cec_gpio_probe(struct platform_device *pdev)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
cec->adap->name, cec);
if (ret)
- return ret;
+ goto del_adap;
cec_gpio_disable_irq(cec->adap);
@@ -218,7 +227,7 @@ static int cec_gpio_probe(struct platform_device *pdev)
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"hpd-gpio", cec);
if (ret)
- return ret;
+ goto del_adap;
}
if (cec->v5_gpio) {
@@ -230,23 +239,37 @@ static int cec_gpio_probe(struct platform_device *pdev)
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"v5-gpio", cec);
if (ret)
- return ret;
+ goto del_adap;
}
- ret = cec_register_adapter(cec->adap, &pdev->dev);
- if (ret) {
- cec_delete_adapter(cec->adap);
- return ret;
+ if (!IS_ERR(hdmi_dev)) {
+ cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL,
+ cec->adap);
+ if (!cec->notifier) {
+ ret = -ENOMEM;
+ goto del_adap;
+ }
}
+ ret = cec_register_adapter(cec->adap, &pdev->dev);
+ if (ret)
+ goto unreg_notifier;
+
platform_set_drvdata(pdev, cec);
return 0;
+
+unreg_notifier:
+ cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
+del_adap:
+ cec_delete_adapter(cec->adap);
+ return ret;
}
static int cec_gpio_remove(struct platform_device *pdev)
{
struct cec_gpio *cec = platform_get_drvdata(pdev);
+ cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
cec_unregister_adapter(cec->adap);
return 0;
}
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 00c7bed3dd57..3443396ba5f3 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -1629,6 +1629,9 @@ static void coda_finish_encode(struct coda_ctx *ctx)
struct coda_dev *dev = ctx->dev;
u32 wr_ptr, start_ptr;
+ if (ctx->aborting)
+ return;
+
/*
* Lock to make sure that an encoder stop command running in parallel
* will either already have marked src_buf as last, or it will wake up
@@ -2165,16 +2168,21 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
} else {
if (dev->devtype->product == CODA_960) {
/*
- * The CODA960 seems to have an internal list of
- * buffers with 64 entries that includes the
- * registered frame buffers as well as the rotator
- * buffer output.
- *
- * ROT_INDEX needs to be < 0x40, but >
- * ctx->num_internal_frames.
+ * It was previously assumed that the CODA960 has an
+ * internal list of 64 buffer entries that contains
+ * both the registered internal frame buffers as well
+ * as the rotator buffer output, and that the ROT_INDEX
+ * register must be set to a value between the last
+ * internal frame buffers' index and 64.
+ * At least on firmware version 3.1.1 it turns out that
+ * setting ROT_INDEX to any value >= 32 causes CODA
+ * hangups that it can not recover from with the SRC VPU
+ * reset.
+ * It does appear to work however, to just set it to a
+ * fixed value in the [ctx->num_internal_frames, 31]
+ * range, for example CODA_MAX_FRAMEBUFFERS.
*/
- coda_write(dev,
- CODA_MAX_FRAMEBUFFERS + dst_buf->vb2_buf.index,
+ coda_write(dev, CODA_MAX_FRAMEBUFFERS,
CODA9_CMD_DEC_PIC_ROT_INDEX);
reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y;
@@ -2266,6 +2274,9 @@ static void coda_finish_decode(struct coda_ctx *ctx)
int err_vdoa = 0;
u32 val;
+ if (ctx->aborting)
+ return;
+
/* Update kfifo out pointer from coda bitstream read pointer */
coda_kfifo_sync_from_device(ctx);
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 01428de2596e..acff10ad257a 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -155,6 +155,7 @@ static const struct coda_codec coda7_codecs[] = {
static const struct coda_codec coda9_codecs[] = {
CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1088),
CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1088),
+ CODA_CODEC(CODA9_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192),
CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088),
CODA_CODEC(CODA9_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088),
CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088),
@@ -235,6 +236,22 @@ static const struct coda_video_device coda_bit_jpeg_decoder = {
},
};
+static const struct coda_video_device coda9_jpeg_encoder = {
+ .name = "coda-jpeg-encoder",
+ .type = CODA_INST_ENCODER,
+ .ops = &coda9_jpeg_encode_ops,
+ .direct = true,
+ .src_formats = {
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_YUV422P,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_JPEG,
+ },
+};
+
static const struct coda_video_device *codadx6_video_devices[] = {
&coda_bit_encoder,
};
@@ -252,6 +269,7 @@ static const struct coda_video_device *coda7_video_devices[] = {
};
static const struct coda_video_device *coda9_video_devices[] = {
+ &coda9_jpeg_encoder,
&coda_bit_encoder,
&coda_bit_decoder,
};
@@ -390,9 +408,6 @@ static int coda_querycap(struct file *file, void *priv,
strscpy(cap->card, coda_product_name(ctx->dev->devtype->product),
sizeof(cap->card));
strscpy(cap->bus_info, "platform:" CODA_NAME, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -724,7 +739,8 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f,
ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP;
break;
case V4L2_PIX_FMT_NV12:
- if (!disable_tiling && ctx->dev->devtype->product == CODA_960) {
+ if (!disable_tiling && ctx->use_bit &&
+ ctx->dev->devtype->product == CODA_960) {
ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP;
break;
}
@@ -936,7 +952,8 @@ static int coda_g_selection(struct file *file, void *fh,
rsel = &r;
/* fallthrough */
case V4L2_SEL_TGT_CROP:
- if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+ ctx->inst_type == CODA_INST_DECODER)
return -EINVAL;
break;
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
@@ -945,7 +962,8 @@ static int coda_g_selection(struct file *file, void *fh,
/* fallthrough */
case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
- if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ ctx->inst_type == CODA_INST_ENCODER)
return -EINVAL;
break;
default:
@@ -1087,16 +1105,16 @@ static int coda_decoder_cmd(struct file *file, void *fh,
switch (dc->cmd) {
case V4L2_DEC_CMD_START:
- mutex_lock(&ctx->bitstream_mutex);
mutex_lock(&dev->coda_mutex);
+ mutex_lock(&ctx->bitstream_mutex);
coda_bitstream_flush(ctx);
- mutex_unlock(&dev->coda_mutex);
dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
V4L2_BUF_TYPE_VIDEO_CAPTURE);
vb2_clear_last_buffer_dequeued(dst_vq);
ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG;
coda_fill_bitstream(ctx, NULL);
mutex_unlock(&ctx->bitstream_mutex);
+ mutex_unlock(&dev->coda_mutex);
break;
case V4L2_DEC_CMD_STOP:
stream_end = false;
@@ -1422,7 +1440,7 @@ static void coda_pic_run_work(struct work_struct *work)
if (ctx->ops->run_timeout)
ctx->ops->run_timeout(ctx);
- } else if (!ctx->aborting) {
+ } else {
ctx->ops->finish_run(ctx);
}
@@ -1788,7 +1806,7 @@ static void coda_buf_queue(struct vb2_buffer *vb)
coda_queue_source_change_event(ctx);
}
} else {
- if (ctx->inst_type == CODA_INST_ENCODER &&
+ if ((ctx->inst_type == CODA_INST_ENCODER || !ctx->use_bit) &&
vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
vbuf->sequence = ctx->qsequence++;
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
@@ -2390,6 +2408,7 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+ dst_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING;
dst_vq->mem_ops = &vb2_dma_contig_memops;
return coda_queue_init(priv, dst_vq);
@@ -2699,6 +2718,7 @@ static int coda_register_device(struct coda_dev *dev, int i)
vfd->lock = &dev->dev_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->vfl_dir = VFL_DIR_M2M;
+ vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
video_set_drvdata(vfd, dev);
/* Not applicable, use the selection API instead */
@@ -2961,8 +2981,6 @@ static int coda_probe(struct platform_device *pdev)
else
return -EINVAL;
- spin_lock_init(&dev->irqlock);
-
dev->dev = &pdev->dev;
dev->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(dev->clk_per)) {
@@ -2985,10 +3003,8 @@ static int coda_probe(struct platform_device *pdev)
irq = platform_get_irq_byname(pdev, "bit");
if (irq < 0)
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "failed to get irq resource\n");
+ if (irq < 0)
return irq;
- }
ret = devm_request_irq(&pdev->dev, irq, coda_irq_handler, 0,
dev_name(&pdev->dev), dev);
@@ -2997,6 +3013,22 @@ static int coda_probe(struct platform_device *pdev)
return ret;
}
+ /* JPEG IRQ */
+ if (dev->devtype->product == CODA_960) {
+ irq = platform_get_irq_byname(pdev, "jpeg");
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ coda9_jpeg_irq_handler,
+ IRQF_ONESHOT, CODA_NAME " jpeg",
+ dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request jpeg irq\n");
+ return ret;
+ }
+ }
+
dev->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev,
NULL);
if (IS_ERR(dev->rstc)) {
diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c
index bf61a3ecc580..92234fd1f4fd 100644
--- a/drivers/media/platform/coda/coda-jpeg.c
+++ b/drivers/media/platform/coda/coda-jpeg.c
@@ -5,46 +5,68 @@
* Copyright (C) 2014 Philipp Zabel, Pengutronix
*/
+#include <asm/unaligned.h>
+#include <linux/irqreturn.h>
#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
#include <linux/swab.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
#include "coda.h"
#include "trace.h"
#define SOI_MARKER 0xffd8
+#define DRI_MARKER 0xffdd
+#define DQT_MARKER 0xffdb
+#define DHT_MARKER 0xffc4
+#define SOF_MARKER 0xffc0
#define EOI_MARKER 0xffd9
+enum {
+ CODA9_JPEG_FORMAT_420,
+ CODA9_JPEG_FORMAT_422,
+ CODA9_JPEG_FORMAT_224,
+ CODA9_JPEG_FORMAT_444,
+ CODA9_JPEG_FORMAT_400,
+};
+
+#define CODA9_JPEG_ENC_HUFF_DATA_SIZE (256 + 256 + 16 + 16)
+
/*
* Typical Huffman tables for 8-bit precision luminance and
* chrominance from JPEG ITU-T.81 (ISO/IEC 10918-1) Annex K.3
*/
-static const unsigned char luma_dc_bits[16] = {
+static const unsigned char luma_dc[16 + 12] = {
+ /* bits */
0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static const unsigned char luma_dc_value[12] = {
+ /* values */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b,
};
-static const unsigned char chroma_dc_bits[16] = {
+static const unsigned char chroma_dc[16 + 12] = {
+ /* bits */
0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-static const unsigned char chroma_dc_value[12] = {
+ /* values */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b,
};
-static const unsigned char luma_ac_bits[16] = {
+static const unsigned char luma_ac[16 + 162 + 2] = {
+ /* bits */
0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
-};
-
-static const unsigned char luma_ac_value[162 + 2] = {
+ /* values */
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
@@ -68,12 +90,11 @@ static const unsigned char luma_ac_value[162 + 2] = {
0xf9, 0xfa, /* padded to 32-bit */
};
-static const unsigned char chroma_ac_bits[16] = {
+static const unsigned char chroma_ac[16 + 162 + 2] = {
+ /* bits */
0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
-};
-
-static const unsigned char chroma_ac_value[162 + 2] = {
+ /* values */
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
@@ -124,6 +145,38 @@ static unsigned char chroma_q[64] = {
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
};
+static const unsigned char width_align[] = {
+ [CODA9_JPEG_FORMAT_420] = 16,
+ [CODA9_JPEG_FORMAT_422] = 16,
+ [CODA9_JPEG_FORMAT_224] = 8,
+ [CODA9_JPEG_FORMAT_444] = 8,
+ [CODA9_JPEG_FORMAT_400] = 8,
+};
+
+static const unsigned char height_align[] = {
+ [CODA9_JPEG_FORMAT_420] = 16,
+ [CODA9_JPEG_FORMAT_422] = 8,
+ [CODA9_JPEG_FORMAT_224] = 16,
+ [CODA9_JPEG_FORMAT_444] = 8,
+ [CODA9_JPEG_FORMAT_400] = 8,
+};
+
+static int coda9_jpeg_chroma_format(u32 pixfmt)
+{
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ return CODA9_JPEG_FORMAT_420;
+ case V4L2_PIX_FMT_YUV422P:
+ return CODA9_JPEG_FORMAT_422;
+ case V4L2_PIX_FMT_YUV444:
+ return CODA9_JPEG_FORMAT_444;
+ case V4L2_PIX_FMT_GREY:
+ return CODA9_JPEG_FORMAT_400;
+ }
+ return -EINVAL;
+}
+
struct coda_memcpy_desc {
int offset;
const void *src;
@@ -148,14 +201,10 @@ int coda_jpeg_write_tables(struct coda_ctx *ctx)
{
int i;
static const struct coda_memcpy_desc huff[8] = {
- { 0, luma_dc_bits, sizeof(luma_dc_bits) },
- { 16, luma_dc_value, sizeof(luma_dc_value) },
- { 32, luma_ac_bits, sizeof(luma_ac_bits) },
- { 48, luma_ac_value, sizeof(luma_ac_value) },
- { 216, chroma_dc_bits, sizeof(chroma_dc_bits) },
- { 232, chroma_dc_value, sizeof(chroma_dc_value) },
- { 248, chroma_ac_bits, sizeof(chroma_ac_bits) },
- { 264, chroma_ac_value, sizeof(chroma_ac_value) },
+ { 0, luma_dc, sizeof(luma_dc) },
+ { 32, luma_ac, sizeof(luma_ac) },
+ { 216, chroma_dc, sizeof(chroma_dc) },
+ { 248, chroma_ac, sizeof(chroma_ac) },
};
struct coda_memcpy_desc qmat[3] = {
{ 512, ctx->params.jpeg_qmat_tab[0], 64 },
@@ -198,6 +247,379 @@ bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb)
return false;
}
+static const int bus_req_num[] = {
+ [CODA9_JPEG_FORMAT_420] = 2,
+ [CODA9_JPEG_FORMAT_422] = 3,
+ [CODA9_JPEG_FORMAT_224] = 3,
+ [CODA9_JPEG_FORMAT_444] = 4,
+ [CODA9_JPEG_FORMAT_400] = 4,
+};
+
+#define MCU_INFO(mcu_block_num, comp_num, comp0_info, comp1_info, comp2_info) \
+ (((mcu_block_num) << CODA9_JPEG_MCU_BLOCK_NUM_OFFSET) | \
+ ((comp_num) << CODA9_JPEG_COMP_NUM_OFFSET) | \
+ ((comp0_info) << CODA9_JPEG_COMP0_INFO_OFFSET) | \
+ ((comp1_info) << CODA9_JPEG_COMP1_INFO_OFFSET) | \
+ ((comp2_info) << CODA9_JPEG_COMP2_INFO_OFFSET))
+
+static const u32 mcu_info[] = {
+ [CODA9_JPEG_FORMAT_420] = MCU_INFO(6, 3, 10, 5, 5),
+ [CODA9_JPEG_FORMAT_422] = MCU_INFO(4, 3, 9, 5, 5),
+ [CODA9_JPEG_FORMAT_224] = MCU_INFO(4, 3, 6, 5, 5),
+ [CODA9_JPEG_FORMAT_444] = MCU_INFO(3, 3, 5, 5, 5),
+ [CODA9_JPEG_FORMAT_400] = MCU_INFO(1, 1, 5, 0, 0),
+};
+
+/*
+ * Convert Huffman table specifcations to tables of codes and code lengths.
+ * For reference, see JPEG ITU-T.81 (ISO/IEC 10918-1) [1]
+ *
+ * [1] https://www.w3.org/Graphics/JPEG/itu-t81.pdf
+ */
+static int coda9_jpeg_gen_enc_huff_tab(struct coda_ctx *ctx, int tab_num,
+ int *ehufsi, int *ehufco)
+{
+ int i, j, k, lastk, si, code, maxsymbol;
+ const u8 *bits, *huffval;
+ struct {
+ int size[256];
+ int code[256];
+ } *huff;
+ static const unsigned char *huff_tabs[4] = {
+ luma_dc, luma_ac, chroma_dc, chroma_ac,
+ };
+ int ret = -EINVAL;
+
+ huff = kzalloc(sizeof(*huff), GFP_KERNEL);
+ if (!huff)
+ return -ENOMEM;
+
+ bits = huff_tabs[tab_num];
+ huffval = huff_tabs[tab_num] + 16;
+
+ maxsymbol = tab_num & 1 ? 256 : 16;
+
+ /* Figure C.1 - Generation of table of Huffman code sizes */
+ k = 0;
+ for (i = 1; i <= 16; i++) {
+ j = bits[i - 1];
+ if (k + j > maxsymbol)
+ goto out;
+ while (j--)
+ huff->size[k++] = i;
+ }
+ lastk = k;
+
+ /* Figure C.2 - Generation of table of Huffman codes */
+ k = 0;
+ code = 0;
+ si = huff->size[0];
+ while (k < lastk) {
+ while (huff->size[k] == si) {
+ huff->code[k++] = code;
+ code++;
+ }
+ if (code >= (1 << si))
+ goto out;
+ code <<= 1;
+ si++;
+ }
+
+ /* Figure C.3 - Ordering procedure for encoding procedure code tables */
+ for (k = 0; k < lastk; k++) {
+ i = huffval[k];
+ if (i >= maxsymbol || ehufsi[i])
+ goto out;
+ ehufco[i] = huff->code[k];
+ ehufsi[i] = huff->size[k];
+ }
+
+ ret = 0;
+out:
+ kfree(huff);
+ return ret;
+}
+
+#define DC_TABLE_INDEX0 0
+#define AC_TABLE_INDEX0 1
+#define DC_TABLE_INDEX1 2
+#define AC_TABLE_INDEX1 3
+
+static int coda9_jpeg_load_huff_tab(struct coda_ctx *ctx)
+{
+ struct {
+ int size[4][256];
+ int code[4][256];
+ } *huff;
+ u32 *huff_data;
+ int i, j;
+ int ret;
+
+ huff = kzalloc(sizeof(*huff), GFP_KERNEL);
+ if (!huff)
+ return -ENOMEM;
+
+ /* Generate all four (luma/chroma DC/AC) code/size lookup tables */
+ for (i = 0; i < 4; i++) {
+ ret = coda9_jpeg_gen_enc_huff_tab(ctx, i, huff->size[i],
+ huff->code[i]);
+ if (ret)
+ goto out;
+ }
+
+ if (!ctx->params.jpeg_huff_data) {
+ ctx->params.jpeg_huff_data =
+ kzalloc(sizeof(u32) * CODA9_JPEG_ENC_HUFF_DATA_SIZE,
+ GFP_KERNEL);
+ if (!ctx->params.jpeg_huff_data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+ huff_data = ctx->params.jpeg_huff_data;
+
+ for (j = 0; j < 4; j++) {
+ /* Store Huffman lookup tables in AC0, AC1, DC0, DC1 order */
+ int t = (j == 0) ? AC_TABLE_INDEX0 :
+ (j == 1) ? AC_TABLE_INDEX1 :
+ (j == 2) ? DC_TABLE_INDEX0 :
+ DC_TABLE_INDEX1;
+ /* DC tables only have 16 entries */
+ int len = (j < 2) ? 256 : 16;
+
+ for (i = 0; i < len; i++) {
+ if (huff->size[t][i] == 0 && huff->code[t][i] == 0)
+ *(huff_data++) = 0;
+ else
+ *(huff_data++) =
+ ((huff->size[t][i] - 1) << 16) |
+ huff->code[t][i];
+ }
+ }
+
+ ret = 0;
+out:
+ kfree(huff);
+ return ret;
+}
+
+static void coda9_jpeg_write_huff_tab(struct coda_ctx *ctx)
+{
+ struct coda_dev *dev = ctx->dev;
+ u32 *huff_data = ctx->params.jpeg_huff_data;
+ int i;
+
+ /* Write Huffman size/code lookup tables in AC0, AC1, DC0, DC1 order */
+ coda_write(dev, 0x3, CODA9_REG_JPEG_HUFF_CTRL);
+ for (i = 0; i < CODA9_JPEG_ENC_HUFF_DATA_SIZE; i++)
+ coda_write(dev, *(huff_data++), CODA9_REG_JPEG_HUFF_DATA);
+ coda_write(dev, 0x0, CODA9_REG_JPEG_HUFF_CTRL);
+}
+
+static inline void coda9_jpeg_write_qmat_quotients(struct coda_dev *dev,
+ u8 *qmat, int index)
+{
+ int i;
+
+ coda_write(dev, index | 0x3, CODA9_REG_JPEG_QMAT_CTRL);
+ for (i = 0; i < 64; i++)
+ coda_write(dev, 0x80000 / qmat[i], CODA9_REG_JPEG_QMAT_DATA);
+ coda_write(dev, index, CODA9_REG_JPEG_QMAT_CTRL);
+}
+
+static void coda9_jpeg_load_qmat_tab(struct coda_ctx *ctx)
+{
+ struct coda_dev *dev = ctx->dev;
+ u8 *luma_tab;
+ u8 *chroma_tab;
+
+ luma_tab = ctx->params.jpeg_qmat_tab[0];
+ if (!luma_tab)
+ luma_tab = luma_q;
+
+ chroma_tab = ctx->params.jpeg_qmat_tab[1];
+ if (!chroma_tab)
+ chroma_tab = chroma_q;
+
+ coda9_jpeg_write_qmat_quotients(dev, luma_tab, 0x00);
+ coda9_jpeg_write_qmat_quotients(dev, chroma_tab, 0x40);
+ coda9_jpeg_write_qmat_quotients(dev, chroma_tab, 0x80);
+}
+
+struct coda_jpeg_stream {
+ u8 *curr;
+ u8 *end;
+};
+
+static inline int coda_jpeg_put_byte(u8 byte, struct coda_jpeg_stream *stream)
+{
+ if (stream->curr >= stream->end)
+ return -EINVAL;
+
+ *stream->curr++ = byte;
+
+ return 0;
+}
+
+static inline int coda_jpeg_put_word(u16 word, struct coda_jpeg_stream *stream)
+{
+ if (stream->curr + sizeof(__be16) > stream->end)
+ return -EINVAL;
+
+ put_unaligned_be16(word, stream->curr);
+ stream->curr += sizeof(__be16);
+
+ return 0;
+}
+
+static int coda_jpeg_put_table(u16 marker, u8 index, const u8 *table,
+ size_t len, struct coda_jpeg_stream *stream)
+{
+ int i, ret;
+
+ ret = coda_jpeg_put_word(marker, stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_put_word(3 + len, stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_put_byte(index, stream);
+ for (i = 0; i < len && ret == 0; i++)
+ ret = coda_jpeg_put_byte(table[i], stream);
+
+ return ret;
+}
+
+static int coda_jpeg_define_quantization_table(struct coda_ctx *ctx, u8 index,
+ struct coda_jpeg_stream *stream)
+{
+ return coda_jpeg_put_table(DQT_MARKER, index,
+ ctx->params.jpeg_qmat_tab[index], 64,
+ stream);
+}
+
+static int coda_jpeg_define_huffman_table(u8 index, const u8 *table, size_t len,
+ struct coda_jpeg_stream *stream)
+{
+ return coda_jpeg_put_table(DHT_MARKER, index, table, len, stream);
+}
+
+static int coda9_jpeg_encode_header(struct coda_ctx *ctx, int len, u8 *buf)
+{
+ struct coda_jpeg_stream stream = { buf, buf + len };
+ struct coda_q_data *q_data_src;
+ int chroma_format, comp_num;
+ int i, ret, pad;
+
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ chroma_format = coda9_jpeg_chroma_format(q_data_src->fourcc);
+ if (chroma_format < 0)
+ return 0;
+
+ /* Start Of Image */
+ ret = coda_jpeg_put_word(SOI_MARKER, &stream);
+ if (ret < 0)
+ return ret;
+
+ /* Define Restart Interval */
+ if (ctx->params.jpeg_restart_interval) {
+ ret = coda_jpeg_put_word(DRI_MARKER, &stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_put_word(4, &stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_put_word(ctx->params.jpeg_restart_interval,
+ &stream);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Define Quantization Tables */
+ ret = coda_jpeg_define_quantization_table(ctx, 0x00, &stream);
+ if (ret < 0)
+ return ret;
+ if (chroma_format != CODA9_JPEG_FORMAT_400) {
+ ret = coda_jpeg_define_quantization_table(ctx, 0x01, &stream);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Define Huffman Tables */
+ ret = coda_jpeg_define_huffman_table(0x00, luma_dc, 16 + 12, &stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_define_huffman_table(0x10, luma_ac, 16 + 162, &stream);
+ if (ret < 0)
+ return ret;
+ if (chroma_format != CODA9_JPEG_FORMAT_400) {
+ ret = coda_jpeg_define_huffman_table(0x01, chroma_dc, 16 + 12,
+ &stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_define_huffman_table(0x11, chroma_ac, 16 + 162,
+ &stream);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Start Of Frame */
+ ret = coda_jpeg_put_word(SOF_MARKER, &stream);
+ if (ret < 0)
+ return ret;
+ comp_num = (chroma_format == CODA9_JPEG_FORMAT_400) ? 1 : 3;
+ ret = coda_jpeg_put_word(8 + comp_num * 3, &stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_put_byte(0x08, &stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_put_word(q_data_src->height, &stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_put_word(q_data_src->width, &stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_put_byte(comp_num, &stream);
+ if (ret < 0)
+ return ret;
+ for (i = 0; i < comp_num; i++) {
+ static unsigned char subsampling[5][3] = {
+ [CODA9_JPEG_FORMAT_420] = { 0x22, 0x11, 0x11 },
+ [CODA9_JPEG_FORMAT_422] = { 0x21, 0x11, 0x11 },
+ [CODA9_JPEG_FORMAT_224] = { 0x12, 0x11, 0x11 },
+ [CODA9_JPEG_FORMAT_444] = { 0x11, 0x11, 0x11 },
+ [CODA9_JPEG_FORMAT_400] = { 0x11 },
+ };
+
+ /* Component identifier, matches SOS */
+ ret = coda_jpeg_put_byte(i + 1, &stream);
+ if (ret < 0)
+ return ret;
+ ret = coda_jpeg_put_byte(subsampling[chroma_format][i],
+ &stream);
+ if (ret < 0)
+ return ret;
+ /* Chroma table index */
+ ret = coda_jpeg_put_byte((i == 0) ? 0 : 1, &stream);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Pad to multiple of 8 bytes */
+ pad = (stream.curr - buf) % 8;
+ if (pad) {
+ pad = 8 - pad;
+ while (pad--) {
+ ret = coda_jpeg_put_byte(0x00, &stream);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return stream.curr - buf;
+}
+
/*
* Scale quantization table using nonlinear scaling factor
* u8 qtab[64], scale [50,190]
@@ -247,3 +669,279 @@ void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality)
coda_scale_quant_table(ctx->params.jpeg_qmat_tab[1], scale);
}
}
+
+/*
+ * Encoder context operations
+ */
+
+static int coda9_jpeg_start_encoding(struct coda_ctx *ctx)
+{
+ struct coda_dev *dev = ctx->dev;
+ int ret;
+
+ ret = coda9_jpeg_load_huff_tab(ctx);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "error loading Huffman tables\n");
+ return ret;
+ }
+ if (!ctx->params.jpeg_qmat_tab[0])
+ ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL);
+ if (!ctx->params.jpeg_qmat_tab[1])
+ ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL);
+ coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality);
+
+ return 0;
+}
+
+static int coda9_jpeg_prepare_encode(struct coda_ctx *ctx)
+{
+ struct coda_q_data *q_data_src;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ struct coda_dev *dev = ctx->dev;
+ u32 start_addr, end_addr;
+ u16 aligned_width, aligned_height;
+ bool chroma_interleave;
+ int chroma_format;
+ int header_len;
+ int ret;
+ ktime_t timeout;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 0)
+ vb2_set_plane_payload(&src_buf->vb2_buf, 0,
+ vb2_plane_size(&src_buf->vb2_buf, 0));
+
+ src_buf->sequence = ctx->osequence;
+ dst_buf->sequence = ctx->osequence;
+ ctx->osequence++;
+
+ src_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+ src_buf->flags &= ~V4L2_BUF_FLAG_PFRAME;
+
+ coda_set_gdi_regs(ctx);
+
+ start_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+ end_addr = start_addr + vb2_plane_size(&dst_buf->vb2_buf, 0);
+
+ chroma_format = coda9_jpeg_chroma_format(q_data_src->fourcc);
+ if (chroma_format < 0)
+ return chroma_format;
+
+ /* Round image dimensions to multiple of MCU size */
+ aligned_width = round_up(q_data_src->width, width_align[chroma_format]);
+ aligned_height = round_up(q_data_src->height,
+ height_align[chroma_format]);
+ if (aligned_width != q_data_src->bytesperline) {
+ v4l2_err(&dev->v4l2_dev, "wrong stride: %d instead of %d\n",
+ aligned_width, q_data_src->bytesperline);
+ }
+
+ header_len =
+ coda9_jpeg_encode_header(ctx,
+ vb2_plane_size(&dst_buf->vb2_buf, 0),
+ vb2_plane_vaddr(&dst_buf->vb2_buf, 0));
+ if (header_len < 0)
+ return header_len;
+
+ coda_write(dev, start_addr + header_len, CODA9_REG_JPEG_BBC_BAS_ADDR);
+ coda_write(dev, end_addr, CODA9_REG_JPEG_BBC_END_ADDR);
+ coda_write(dev, start_addr + header_len, CODA9_REG_JPEG_BBC_WR_PTR);
+ coda_write(dev, start_addr + header_len, CODA9_REG_JPEG_BBC_RD_PTR);
+ coda_write(dev, 0, CODA9_REG_JPEG_BBC_CUR_POS);
+ /* 64 words per 256-byte page */
+ coda_write(dev, 64, CODA9_REG_JPEG_BBC_DATA_CNT);
+ coda_write(dev, start_addr, CODA9_REG_JPEG_BBC_EXT_ADDR);
+ coda_write(dev, 0, CODA9_REG_JPEG_BBC_INT_ADDR);
+
+ coda_write(dev, 0, CODA9_REG_JPEG_GBU_BT_PTR);
+ coda_write(dev, 0, CODA9_REG_JPEG_GBU_WD_PTR);
+ coda_write(dev, 0, CODA9_REG_JPEG_GBU_BBSR);
+ coda_write(dev, 0, CODA9_REG_JPEG_BBC_STRM_CTRL);
+ coda_write(dev, 0, CODA9_REG_JPEG_GBU_CTRL);
+ coda_write(dev, 0, CODA9_REG_JPEG_GBU_FF_RPTR);
+ coda_write(dev, 127, CODA9_REG_JPEG_GBU_BBER);
+ coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBIR);
+ coda_write(dev, 64, CODA9_REG_JPEG_GBU_BBHR);
+
+ chroma_interleave = (q_data_src->fourcc == V4L2_PIX_FMT_NV12);
+ coda_write(dev, CODA9_JPEG_PIC_CTRL_TC_DIRECTION |
+ CODA9_JPEG_PIC_CTRL_ENCODER_EN, CODA9_REG_JPEG_PIC_CTRL);
+ coda_write(dev, 0, CODA9_REG_JPEG_SCL_INFO);
+ coda_write(dev, chroma_interleave, CODA9_REG_JPEG_DPB_CONFIG);
+ coda_write(dev, ctx->params.jpeg_restart_interval,
+ CODA9_REG_JPEG_RST_INTVAL);
+ coda_write(dev, 1, CODA9_REG_JPEG_BBC_CTRL);
+
+ coda_write(dev, bus_req_num[chroma_format], CODA9_REG_JPEG_OP_INFO);
+
+ coda9_jpeg_write_huff_tab(ctx);
+ coda9_jpeg_load_qmat_tab(ctx);
+
+ if (ctx->params.rot_mode & CODA_ROT_90) {
+ aligned_width = aligned_height;
+ aligned_height = q_data_src->bytesperline;
+ if (chroma_format == CODA9_JPEG_FORMAT_422)
+ chroma_format = CODA9_JPEG_FORMAT_224;
+ else if (chroma_format == CODA9_JPEG_FORMAT_224)
+ chroma_format = CODA9_JPEG_FORMAT_422;
+ }
+ /* These need to be multiples of MCU size */
+ coda_write(dev, aligned_width << 16 | aligned_height,
+ CODA9_REG_JPEG_PIC_SIZE);
+ coda_write(dev, ctx->params.rot_mode ?
+ (CODA_ROT_MIR_ENABLE | ctx->params.rot_mode) : 0,
+ CODA9_REG_JPEG_ROT_INFO);
+
+ coda_write(dev, mcu_info[chroma_format], CODA9_REG_JPEG_MCU_INFO);
+
+ coda_write(dev, 1, CODA9_GDI_CONTROL);
+ timeout = ktime_add_us(ktime_get(), 100000);
+ do {
+ ret = coda_read(dev, CODA9_GDI_STATUS);
+ if (ktime_compare(ktime_get(), timeout) > 0) {
+ v4l2_err(&dev->v4l2_dev, "timeout waiting for GDI\n");
+ return -ETIMEDOUT;
+ }
+ } while (!ret);
+
+ coda_write(dev, (chroma_format << 17) | (chroma_interleave << 16) |
+ q_data_src->bytesperline, CODA9_GDI_INFO_CONTROL);
+ /* The content of this register seems to be irrelevant: */
+ coda_write(dev, aligned_width << 16 | aligned_height,
+ CODA9_GDI_INFO_PIC_SIZE);
+
+ coda_write_base(ctx, q_data_src, src_buf, CODA9_GDI_INFO_BASE_Y);
+
+ coda_write(dev, 0, CODA9_REG_JPEG_DPB_BASE00);
+ coda_write(dev, 0, CODA9_GDI_CONTROL);
+ coda_write(dev, 1, CODA9_GDI_PIC_INIT_HOST);
+
+ coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
+ coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
+
+ trace_coda_jpeg_run(ctx, src_buf);
+
+ coda_write(dev, 1, CODA9_REG_JPEG_PIC_START);
+
+ return 0;
+}
+
+static void coda9_jpeg_finish_encode(struct coda_ctx *ctx)
+{
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ struct coda_dev *dev = ctx->dev;
+ u32 wr_ptr, start_ptr;
+ u32 err_mb;
+
+ if (ctx->aborting) {
+ coda_write(ctx->dev, 0, CODA9_REG_JPEG_BBC_FLUSH_CMD);
+ return;
+ }
+
+ /*
+ * Lock to make sure that an encoder stop command running in parallel
+ * will either already have marked src_buf as last, or it will wake up
+ * the capture queue after the buffers are returned.
+ */
+ mutex_lock(&ctx->wakeup_mutex);
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ trace_coda_jpeg_done(ctx, dst_buf);
+
+ /*
+ * Set plane payload to the number of bytes written out
+ * by the JPEG processing unit
+ */
+ start_ptr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+ wr_ptr = coda_read(dev, CODA9_REG_JPEG_BBC_WR_PTR);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, wr_ptr - start_ptr);
+
+ err_mb = coda_read(dev, CODA9_REG_JPEG_PIC_ERRMB);
+ if (err_mb)
+ coda_dbg(1, ctx, "ERRMB: 0x%x\n", err_mb);
+
+ coda_write(dev, 0, CODA9_REG_JPEG_BBC_FLUSH_CMD);
+
+ dst_buf->flags &= ~(V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_LAST);
+ dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME;
+ dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST;
+
+ v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
+
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+ coda_m2m_buf_done(ctx, dst_buf, err_mb ? VB2_BUF_STATE_ERROR :
+ VB2_BUF_STATE_DONE);
+ mutex_unlock(&ctx->wakeup_mutex);
+
+ coda_dbg(1, ctx, "job finished: encoded frame (%u)%s\n",
+ dst_buf->sequence,
+ (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : "");
+}
+
+static void coda9_jpeg_release(struct coda_ctx *ctx)
+{
+ int i;
+
+ if (ctx->params.jpeg_qmat_tab[0] == luma_q)
+ ctx->params.jpeg_qmat_tab[0] = NULL;
+ if (ctx->params.jpeg_qmat_tab[1] == chroma_q)
+ ctx->params.jpeg_qmat_tab[1] = NULL;
+ for (i = 0; i < 3; i++)
+ kfree(ctx->params.jpeg_qmat_tab[i]);
+ kfree(ctx->params.jpeg_huff_data);
+}
+
+const struct coda_context_ops coda9_jpeg_encode_ops = {
+ .queue_init = coda_encoder_queue_init,
+ .start_streaming = coda9_jpeg_start_encoding,
+ .prepare_run = coda9_jpeg_prepare_encode,
+ .finish_run = coda9_jpeg_finish_encode,
+ .release = coda9_jpeg_release,
+};
+
+irqreturn_t coda9_jpeg_irq_handler(int irq, void *data)
+{
+ struct coda_dev *dev = data;
+ struct coda_ctx *ctx;
+ int status;
+ int err_mb;
+
+ status = coda_read(dev, CODA9_REG_JPEG_PIC_STATUS);
+ if (status == 0)
+ return IRQ_HANDLED;
+ coda_write(dev, status, CODA9_REG_JPEG_PIC_STATUS);
+
+ if (status & CODA9_JPEG_STATUS_OVERFLOW)
+ v4l2_err(&dev->v4l2_dev, "JPEG overflow\n");
+
+ if (status & CODA9_JPEG_STATUS_BBC_INT)
+ v4l2_err(&dev->v4l2_dev, "JPEG BBC interrupt\n");
+
+ if (status & CODA9_JPEG_STATUS_ERROR) {
+ v4l2_err(&dev->v4l2_dev, "JPEG error\n");
+
+ err_mb = coda_read(dev, CODA9_REG_JPEG_PIC_ERRMB);
+ if (err_mb) {
+ v4l2_err(&dev->v4l2_dev,
+ "ERRMB: 0x%x: rst idx %d, mcu pos (%d,%d)\n",
+ err_mb, err_mb >> 24, (err_mb >> 12) & 0xfff,
+ err_mb & 0xfff);
+ }
+ }
+
+ ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+ if (!ctx) {
+ v4l2_err(&dev->v4l2_dev,
+ "Instance released before the end of transaction\n");
+ mutex_unlock(&dev->coda_mutex);
+ return IRQ_HANDLED;
+ }
+
+ complete(&ctx->completion);
+
+ return IRQ_HANDLED;
+}
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index 848bf1da401e..43bda175f517 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -86,7 +86,6 @@ struct coda_dev {
struct gen_pool *iram_pool;
struct coda_aux_buf iram;
- spinlock_t irqlock;
struct mutex dev_mutex;
struct mutex coda_mutex;
struct workqueue_struct *workqueue;
@@ -127,6 +126,7 @@ struct coda_params {
u8 jpeg_quality;
u8 jpeg_restart_interval;
u8 *jpeg_qmat_tab[3];
+ u32 *jpeg_huff_data;
int codec_mode;
int codec_mode_aux;
enum v4l2_mpeg_video_multi_slice_mode slice_mode;
@@ -367,7 +367,9 @@ void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality);
extern const struct coda_context_ops coda_bit_encode_ops;
extern const struct coda_context_ops coda_bit_decode_ops;
+extern const struct coda_context_ops coda9_jpeg_encode_ops;
irqreturn_t coda_irq_handler(int irq, void *data);
+irqreturn_t coda9_jpeg_irq_handler(int irq, void *data);
#endif /* __CODA_H__ */
diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h
index b17464b56d3d..da5bb3212528 100644
--- a/drivers/media/platform/coda/coda_regs.h
+++ b/drivers/media/platform/coda/coda_regs.h
@@ -451,12 +451,21 @@
#define CODA9_CMD_FIRMWARE_CODE_REV 0x1c4
#define CODA9_GDMA_BASE 0x1000
+#define CODA9_GDI_CONTROL (CODA9_GDMA_BASE + 0x034)
+#define CODA9_GDI_PIC_INIT_HOST (CODA9_GDMA_BASE + 0x038)
+#define CODA9_GDI_STATUS (CODA9_GDMA_BASE + 0x080)
#define CODA9_GDI_WPROT_ERR_CLR (CODA9_GDMA_BASE + 0x0a0)
#define CODA9_GDI_WPROT_RGN_EN (CODA9_GDMA_BASE + 0x0ac)
#define CODA9_GDI_BUS_CTRL (CODA9_GDMA_BASE + 0x0f0)
#define CODA9_GDI_BUS_STATUS (CODA9_GDMA_BASE + 0x0f4)
+#define CODA9_GDI_INFO_CONTROL (CODA9_GDMA_BASE + 0x400)
+#define CODA9_GDI_INFO_PIC_SIZE (CODA9_GDMA_BASE + 0x404)
+#define CODA9_GDI_INFO_BASE_Y (CODA9_GDMA_BASE + 0x408)
+#define CODA9_GDI_INFO_BASE_CB (CODA9_GDMA_BASE + 0x40c)
+#define CODA9_GDI_INFO_BASE_CR (CODA9_GDMA_BASE + 0x410)
+
#define CODA9_GDI_XY2_CAS_0 (CODA9_GDMA_BASE + 0x800)
#define CODA9_GDI_XY2_CAS_F (CODA9_GDMA_BASE + 0x83c)
@@ -477,4 +486,78 @@
#define CODA9_GDI_RBC2_AXI_1F (CODA9_GDMA_BASE + 0x91c)
#define CODA9_GDI_TILEDBUF_BASE (CODA9_GDMA_BASE + 0x920)
+#define CODA9_JPEG_BASE 0x3000
+#define CODA9_REG_JPEG_PIC_START (CODA9_JPEG_BASE + 0x000)
+#define CODA9_REG_JPEG_PIC_STATUS (CODA9_JPEG_BASE + 0x004)
+#define CODA9_JPEG_STATUS_OVERFLOW BIT(3)
+#define CODA9_JPEG_STATUS_BBC_INT BIT(2)
+#define CODA9_JPEG_STATUS_ERROR BIT(1)
+#define CODA9_JPEG_STATUS_DONE BIT(0)
+#define CODA9_REG_JPEG_PIC_ERRMB (CODA9_JPEG_BASE + 0x008)
+#define CODA9_JPEG_ERRMB_RESTART_IDX_MASK (0xf << 24)
+#define CODA9_JPEG_ERRMB_MCU_POS_X_MASK (0xfff << 12)
+#define CODA9_JPEG_ERRMB_MCU_POS_Y_MASK 0xfff
+#define CODA9_REG_JPEG_PIC_CTRL (CODA9_JPEG_BASE + 0x010)
+#define CODA9_JPEG_PIC_CTRL_USER_HUFFMAN_EN BIT(6)
+#define CODA9_JPEG_PIC_CTRL_TC_DIRECTION BIT(4)
+#define CODA9_JPEG_PIC_CTRL_ENCODER_EN BIT(3)
+#define CODA9_REG_JPEG_PIC_SIZE (CODA9_JPEG_BASE + 0x014)
+#define CODA9_REG_JPEG_MCU_INFO (CODA9_JPEG_BASE + 0x018)
+#define CODA9_JPEG_MCU_BLOCK_NUM_OFFSET 16
+#define CODA9_JPEG_COMP_NUM_OFFSET 12
+#define CODA9_JPEG_COMP0_INFO_OFFSET 8
+#define CODA9_JPEG_COMP1_INFO_OFFSET 4
+#define CODA9_JPEG_COMP2_INFO_OFFSET 0
+#define CODA9_REG_JPEG_ROT_INFO (CODA9_JPEG_BASE + 0x01c)
+#define CODA9_JPEG_ROT_MIR_ENABLE BIT(4)
+#define CODA9_JPEG_ROT_MIR_MODE_MASK 0xf
+#define CODA9_REG_JPEG_SCL_INFO (CODA9_JPEG_BASE + 0x020)
+#define CODA9_JPEG_SCL_ENABLE BIT(4)
+#define CODA9_JPEG_SCL_HOR_MODE_MASK (0x3 << 2)
+#define CODA9_JPEG_SCL_VER_MODE_MASK (0x3 << 0)
+#define CODA9_REG_JPEG_IF_INFO (CODA9_JPEG_BASE + 0x024)
+#define CODA9_JPEG_SENS_IF_CLR BIT(1)
+#define CODA9_JPEG_DISP_IF_CLR BIT(0)
+#define CODA9_REG_JPEG_OP_INFO (CODA9_JPEG_BASE + 0x02c)
+#define CODA9_JPEG_BUS_REQ_NUM_OFFSET 0
+#define CODA9_JPEG_BUS_REQ_NUM_MASK 0x7
+#define CODA9_REG_JPEG_DPB_CONFIG (CODA9_JPEG_BASE + 0x030)
+#define CODA9_REG_JPEG_DPB_BASE00 (CODA9_JPEG_BASE + 0x040)
+#define CODA9_REG_JPEG_HUFF_CTRL (CODA9_JPEG_BASE + 0x080)
+#define CODA9_REG_JPEG_HUFF_ADDR (CODA9_JPEG_BASE + 0x084)
+#define CODA9_REG_JPEG_HUFF_DATA (CODA9_JPEG_BASE + 0x088)
+#define CODA9_REG_JPEG_QMAT_CTRL (CODA9_JPEG_BASE + 0x090)
+#define CODA9_REG_JPEG_QMAT_ADDR (CODA9_JPEG_BASE + 0x094)
+#define CODA9_REG_JPEG_QMAT_DATA (CODA9_JPEG_BASE + 0x098)
+#define CODA9_REG_JPEG_RST_INTVAL (CODA9_JPEG_BASE + 0x0b0)
+#define CODA9_REG_JPEG_RST_INDEX (CODA9_JPEG_BASE + 0x0b4)
+#define CODA9_REG_JPEG_RST_COUNT (CODA9_JPEG_BASE + 0x0b8)
+#define CODA9_REG_JPEG_DPCM_DIFF_Y (CODA9_JPEG_BASE + 0x0f0)
+#define CODA9_REG_JPEG_DPCM_DIFF_CB (CODA9_JPEG_BASE + 0x0f4)
+#define CODA9_REG_JPEG_DPCM_DIFF_CR (CODA9_JPEG_BASE + 0x0f8)
+#define CODA9_REG_JPEG_GBU_CTRL (CODA9_JPEG_BASE + 0x100)
+#define CODA9_REG_JPEG_GBU_BT_PTR (CODA9_JPEG_BASE + 0x110)
+#define CODA9_REG_JPEG_GBU_WD_PTR (CODA9_JPEG_BASE + 0x114)
+#define CODA9_REG_JPEG_GBU_TT_CNT (CODA9_JPEG_BASE + 0x118)
+#define CODA9_REG_JPEG_GBU_BBSR (CODA9_JPEG_BASE + 0x140)
+#define CODA9_REG_JPEG_GBU_BBER (CODA9_JPEG_BASE + 0x144)
+#define CODA9_REG_JPEG_GBU_BBIR (CODA9_JPEG_BASE + 0x148)
+#define CODA9_REG_JPEG_GBU_BBHR (CODA9_JPEG_BASE + 0x14c)
+#define CODA9_REG_JPEG_GBU_BCNT (CODA9_JPEG_BASE + 0x158)
+#define CODA9_REG_JPEG_GBU_FF_RPTR (CODA9_JPEG_BASE + 0x160)
+#define CODA9_REG_JPEG_GBU_FF_WPTR (CODA9_JPEG_BASE + 0x164)
+#define CODA9_REG_JPEG_BBC_END_ADDR (CODA9_JPEG_BASE + 0x208)
+#define CODA9_REG_JPEG_BBC_WR_PTR (CODA9_JPEG_BASE + 0x20c)
+#define CODA9_REG_JPEG_BBC_RD_PTR (CODA9_JPEG_BASE + 0x210)
+#define CODA9_REG_JPEG_BBC_EXT_ADDR (CODA9_JPEG_BASE + 0x214)
+#define CODA9_REG_JPEG_BBC_INT_ADDR (CODA9_JPEG_BASE + 0x218)
+#define CODA9_REG_JPEG_BBC_DATA_CNT (CODA9_JPEG_BASE + 0x21c)
+#define CODA9_REG_JPEG_BBC_COMMAND (CODA9_JPEG_BASE + 0x220)
+#define CODA9_REG_JPEG_BBC_BUSY (CODA9_JPEG_BASE + 0x224)
+#define CODA9_REG_JPEG_BBC_CTRL (CODA9_JPEG_BASE + 0x228)
+#define CODA9_REG_JPEG_BBC_CUR_POS (CODA9_JPEG_BASE + 0x22c)
+#define CODA9_REG_JPEG_BBC_BAS_ADDR (CODA9_JPEG_BASE + 0x230)
+#define CODA9_REG_JPEG_BBC_STRM_CTRL (CODA9_JPEG_BASE + 0x234)
+#define CODA9_REG_JPEG_BBC_FLUSH_CMD (CODA9_JPEG_BASE + 0x238)
+
#endif
diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h
index 6cf58237fff2..c0791c847f7c 100644
--- a/drivers/media/platform/coda/trace.h
+++ b/drivers/media/platform/coda/trace.h
@@ -154,6 +154,16 @@ DEFINE_EVENT(coda_buf_meta_class, coda_dec_rot_done,
TP_ARGS(ctx, buf, meta)
);
+DEFINE_EVENT(coda_buf_class, coda_jpeg_run,
+ TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf),
+ TP_ARGS(ctx, buf)
+);
+
+DEFINE_EVENT(coda_buf_class, coda_jpeg_done,
+ TP_PROTO(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf),
+ TP_ARGS(ctx, buf)
+);
+
#endif /* __CODA_TRACE_H__ */
#undef TRACE_INCLUDE_PATH
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 068df9888dbf..0e7e2772f08f 100644
--- a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c
+++ b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c
@@ -14,10 +14,10 @@
#include <linux/cec.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
+#include <linux/platform_data/cros_ec_commands.h>
+#include <linux/platform_data/cros_ec_proto.h>
#include <media/cec.h>
#include <media/cec-notifier.h>
-#include <linux/mfd/cros_ec.h>
-#include <linux/mfd/cros_ec_commands.h>
#define DRV_NAME "cros-ec-cec"
@@ -206,10 +206,10 @@ static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops,
*/
struct cec_dmi_match {
- char *sys_vendor;
- char *product_name;
- char *devname;
- char *conn;
+ const char *sys_vendor;
+ const char *product_name;
+ const char *devname;
+ const char *conn;
};
static const struct cec_dmi_match cec_dmi_match_table[] = {
@@ -217,8 +217,8 @@ static const struct cec_dmi_match cec_dmi_match_table[] = {
{ "Google", "Fizz", "0000:00:02.0", "Port B" },
};
-static int cros_ec_cec_get_notifier(struct device *dev,
- struct cec_notifier **notify)
+static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
+ const char **conn)
{
int i;
@@ -233,26 +233,25 @@ static int cros_ec_cec_get_notifier(struct device *dev,
d = bus_find_device_by_name(&pci_bus_type, NULL,
m->devname);
if (!d)
- return -EPROBE_DEFER;
-
- *notify = cec_notifier_get_conn(d, m->conn);
+ return ERR_PTR(-EPROBE_DEFER);
put_device(d);
- return 0;
+ *conn = m->conn;
+ return d;
}
}
/* Hardware support must be added in the cec_dmi_match_table */
dev_warn(dev, "CEC notifier not configured for this hardware\n");
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
}
#else
-static int cros_ec_cec_get_notifier(struct device *dev,
- struct cec_notifier **notify)
+static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
+ const char **conn)
{
- return -ENODEV;
+ return ERR_PTR(-ENODEV);
}
#endif
@@ -262,8 +261,14 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent);
struct cros_ec_device *cros_ec = ec_dev->ec_dev;
struct cros_ec_cec *cros_ec_cec;
+ struct device *hdmi_dev;
+ const char *conn = NULL;
int ret;
+ hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn);
+ if (IS_ERR(hdmi_dev))
+ return PTR_ERR(hdmi_dev);
+
cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec),
GFP_KERNEL);
if (!cros_ec_cec)
@@ -272,10 +277,6 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, cros_ec_cec);
cros_ec_cec->cros_ec = cros_ec;
- ret = cros_ec_cec_get_notifier(&pdev->dev, &cros_ec_cec->notify);
- if (ret)
- return ret;
-
ret = device_init_wakeup(&pdev->dev, 1);
if (ret) {
dev_err(&pdev->dev, "failed to initialize wakeup\n");
@@ -283,29 +284,40 @@ static int cros_ec_cec_probe(struct platform_device *pdev)
}
cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec,
- DRV_NAME, CEC_CAP_DEFAULTS, 1);
+ DRV_NAME,
+ CEC_CAP_DEFAULTS |
+ CEC_CAP_CONNECTOR_INFO, 1);
if (IS_ERR(cros_ec_cec->adap))
return PTR_ERR(cros_ec_cec->adap);
+ cros_ec_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, conn,
+ cros_ec_cec->adap);
+ if (!cros_ec_cec->notify) {
+ ret = -ENOMEM;
+ goto out_probe_adapter;
+ }
+
/* Get CEC events from the EC. */
cros_ec_cec->notifier.notifier_call = cros_ec_cec_event;
ret = blocking_notifier_chain_register(&cros_ec->event_notifier,
&cros_ec_cec->notifier);
if (ret) {
dev_err(&pdev->dev, "failed to register notifier\n");
- cec_delete_adapter(cros_ec_cec->adap);
- return ret;
+ goto out_probe_notify;
}
ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev);
- if (ret < 0) {
- cec_delete_adapter(cros_ec_cec->adap);
- return ret;
- }
-
- cec_register_cec_notifier(cros_ec_cec->adap, cros_ec_cec->notify);
+ if (ret < 0)
+ goto out_probe_notify;
return 0;
+
+out_probe_notify:
+ cec_notifier_cec_adap_unregister(cros_ec_cec->notify,
+ cros_ec_cec->adap);
+out_probe_adapter:
+ cec_delete_adapter(cros_ec_cec->adap);
+ return ret;
}
static int cros_ec_cec_remove(struct platform_device *pdev)
@@ -323,11 +335,10 @@ static int cros_ec_cec_remove(struct platform_device *pdev)
return ret;
}
+ cec_notifier_cec_adap_unregister(cros_ec_cec->notify,
+ cros_ec_cec->adap);
cec_unregister_adapter(cros_ec_cec->adap);
- if (cros_ec_cec->notify)
- cec_notifier_put(cros_ec_cec->notify);
-
return 0;
}
diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c
index f299baf7cbe0..e06d113dfe96 100644
--- a/drivers/media/platform/davinci/dm355_ccdc.c
+++ b/drivers/media/platform/davinci/dm355_ccdc.c
@@ -883,7 +883,7 @@ static int dm355_ccdc_probe(struct platform_device *pdev)
goto fail_nores;
}
- ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
+ ccdc_cfg.base_addr = ioremap(res->start, resource_size(res));
if (!ccdc_cfg.base_addr) {
status = -ENOMEM;
goto fail_nomem;
diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c
index 2fc6c9c38f9c..c6378c4e0074 100644
--- a/drivers/media/platform/davinci/dm644x_ccdc.c
+++ b/drivers/media/platform/davinci/dm644x_ccdc.c
@@ -817,7 +817,7 @@ static int dm644x_ccdc_probe(struct platform_device *pdev)
goto fail_nores;
}
- ccdc_cfg.base_addr = ioremap_nocache(res->start, resource_size(res));
+ ccdc_cfg.base_addr = ioremap(res->start, resource_size(res));
if (!ccdc_cfg.base_addr) {
status = -ENOMEM;
goto fail_nomem;
diff --git a/drivers/media/platform/davinci/dm644x_ccdc_regs.h b/drivers/media/platform/davinci/dm644x_ccdc_regs.h
index 3ae301320313..c4894f6a254e 100644
--- a/drivers/media/platform/davinci/dm644x_ccdc_regs.h
+++ b/drivers/media/platform/davinci/dm644x_ccdc_regs.h
@@ -66,13 +66,13 @@
#define CCDC_PIX_FMT_MASK 3
#define CCDC_PIX_FMT_SHIFT 12
#define CCDC_VP2SDR_DISABLE 0xFFFBFFFF
-#define CCDC_WEN_ENABLE (1 << 17)
+#define CCDC_WEN_ENABLE BIT(17)
#define CCDC_SDR2RSZ_DISABLE 0xFFF7FFFF
-#define CCDC_VDHDEN_ENABLE (1 << 16)
-#define CCDC_LPF_ENABLE (1 << 14)
-#define CCDC_ALAW_ENABLE (1 << 3)
+#define CCDC_VDHDEN_ENABLE BIT(16)
+#define CCDC_LPF_ENABLE BIT(14)
+#define CCDC_ALAW_ENABLE BIT(3)
#define CCDC_ALAW_GAMMA_WD_MASK 7
-#define CCDC_BLK_CLAMP_ENABLE (1 << 31)
+#define CCDC_BLK_CLAMP_ENABLE BIT(31)
#define CCDC_BLK_SGAIN_MASK 0x1F
#define CCDC_BLK_ST_PXL_MASK 0x7FFF
#define CCDC_BLK_ST_PXL_SHIFT 10
@@ -85,11 +85,11 @@
#define CCDC_BLK_COMP_GB_COMP_SHIFT 8
#define CCDC_BLK_COMP_GR_COMP_SHIFT 16
#define CCDC_BLK_COMP_R_COMP_SHIFT 24
-#define CCDC_LATCH_ON_VSYNC_DISABLE (1 << 15)
-#define CCDC_FPC_ENABLE (1 << 15)
+#define CCDC_LATCH_ON_VSYNC_DISABLE BIT(15)
+#define CCDC_FPC_ENABLE BIT(15)
#define CCDC_FPC_DISABLE 0
#define CCDC_FPC_FPC_NUM_MASK 0x7FFF
-#define CCDC_DATA_PACK_ENABLE (1 << 11)
+#define CCDC_DATA_PACK_ENABLE BIT(11)
#define CCDC_FMTCFG_VPIN_MASK 7
#define CCDC_FMTCFG_VPIN_SHIFT 12
#define CCDC_FMT_HORZ_FMTLNH_MASK 0x1FFF
@@ -132,9 +132,9 @@
#define CCDC_SYN_FLDMODE_MASK 1
#define CCDC_SYN_FLDMODE_SHIFT 7
#define CCDC_REC656IF_BT656_EN 3
-#define CCDC_SYN_MODE_VD_POL_NEGATIVE (1 << 2)
+#define CCDC_SYN_MODE_VD_POL_NEGATIVE BIT(2)
#define CCDC_CCDCFG_Y8POS_SHIFT 11
-#define CCDC_CCDCFG_BW656_10BIT (1 << 5)
+#define CCDC_CCDCFG_BW656_10BIT BIT(5)
#define CCDC_SDOFST_FIELD_INTERLEAVED 0x249
#define CCDC_NO_CULLING 0xffff00ff
#endif
diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c
index e2e7ab7b7f45..b49378b18e5d 100644
--- a/drivers/media/platform/davinci/isif.c
+++ b/drivers/media/platform/davinci/isif.c
@@ -1045,7 +1045,7 @@ static int isif_probe(struct platform_device *pdev)
status = -EBUSY;
goto fail_nobase_res;
}
- addr = ioremap_nocache(res->start, resource_size(res));
+ addr = ioremap(res->start, resource_size(res));
if (!addr) {
status = -ENOMEM;
goto fail_base_iomap;
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index 000b191c42d8..ae419958e420 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -19,10 +19,6 @@
#include <asm/pgtable.h>
-#ifdef CONFIG_ARCH_DAVINCI
-#include <mach/cputype.h>
-#endif
-
#include <media/v4l2-dev.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
@@ -633,8 +629,6 @@ static int vpbe_display_querycap(struct file *file, void *priv,
struct vpbe_layer *layer = video_drvdata(file);
struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
- cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
snprintf(cap->driver, sizeof(cap->driver), "%s",
dev_name(vpbe_dev->pdev));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
@@ -792,7 +786,6 @@ static int vpbe_display_enum_fmt(struct file *file, void *priv,
{
struct vpbe_layer *layer = video_drvdata(file);
struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
- unsigned int index = 0;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"VIDIOC_ENUM_FMT, layer id = %d\n",
@@ -803,19 +796,10 @@ static int vpbe_display_enum_fmt(struct file *file, void *priv,
}
/* Fill in the information about format */
- index = fmt->index;
- memset(fmt, 0, sizeof(*fmt));
- fmt->index = index;
- fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- if (index == 0) {
- strscpy(fmt->description, "YUV 4:2:2 - UYVY",
- sizeof(fmt->description));
+ if (fmt->index == 0)
fmt->pixelformat = V4L2_PIX_FMT_UYVY;
- } else {
- strscpy(fmt->description, "Y/CbCr 4:2:0",
- sizeof(fmt->description));
+ else
fmt->pixelformat = V4L2_PIX_FMT_NV12;
- }
return 0;
}
@@ -1319,6 +1303,7 @@ static int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev;
vbd->lock = &vpbe_display_layer->opslock;
vbd->vfl_dir = VFL_DIR_TX;
+ vbd->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
if (disp_dev->vpbe_dev->current_timings.timings_type &
VPBE_ENC_STD)
diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c
index 491842ef33c5..91b571a0ac2c 100644
--- a/drivers/media/platform/davinci/vpbe_osd.c
+++ b/drivers/media/platform/davinci/vpbe_osd.c
@@ -16,11 +16,6 @@
#include <linux/clk.h>
#include <linux/slab.h>
-#ifdef CONFIG_ARCH_DAVINCI
-#include <mach/cputype.h>
-#include <mach/hardware.h>
-#endif
-
#include <media/davinci/vpss.h>
#include <media/v4l2-device.h>
#include <media/davinci/vpbe_types.h>
diff --git a/drivers/media/platform/davinci/vpbe_venc.c b/drivers/media/platform/davinci/vpbe_venc.c
index 425f91f07165..8caa084e5704 100644
--- a/drivers/media/platform/davinci/vpbe_venc.c
+++ b/drivers/media/platform/davinci/vpbe_venc.c
@@ -14,11 +14,6 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
-#ifdef CONFIG_ARCH_DAVINCI
-#include <mach/hardware.h>
-#include <mach/mux.h>
-#endif
-
#include <linux/platform_data/i2c-davinci.h>
#include <linux/io.h>
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index 295fbf1a49cf..9b1d9643589b 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -119,57 +119,27 @@ static const struct vpfe_standard vpfe_standards[] = {
/* Used when raw Bayer image from ccdc is directly captured to SDRAM */
static const struct vpfe_pixel_format vpfe_pix_fmts[] = {
{
- .fmtdesc = {
- .index = 0,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "Bayer GrRBGb 8bit A-Law compr.",
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
- },
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
.bpp = 1,
},
{
- .fmtdesc = {
- .index = 1,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "Bayer GrRBGb - 16bit",
- .pixelformat = V4L2_PIX_FMT_SBGGR16,
- },
+ .pixelformat = V4L2_PIX_FMT_SBGGR16,
.bpp = 2,
},
{
- .fmtdesc = {
- .index = 2,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "Bayer GrRBGb 8bit DPCM compr.",
- .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
- },
+ .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8,
.bpp = 1,
},
{
- .fmtdesc = {
- .index = 3,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "YCbCr 4:2:2 Interleaved UYVY",
- .pixelformat = V4L2_PIX_FMT_UYVY,
- },
+ .pixelformat = V4L2_PIX_FMT_UYVY,
.bpp = 2,
},
{
- .fmtdesc = {
- .index = 4,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "YCbCr 4:2:2 Interleaved YUYV",
- .pixelformat = V4L2_PIX_FMT_YUYV,
- },
+ .pixelformat = V4L2_PIX_FMT_YUYV,
.bpp = 2,
},
{
- .fmtdesc = {
- .index = 5,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .description = "Y/CbCr 4:2:0 - Semi planar",
- .pixelformat = V4L2_PIX_FMT_NV12,
- },
+ .pixelformat = V4L2_PIX_FMT_NV12,
.bpp = 1,
},
};
@@ -183,7 +153,7 @@ static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format)
int i;
for (i = 0; i < ARRAY_SIZE(vpfe_pix_fmts); i++) {
- if (pix_format == vpfe_pix_fmts[i].fmtdesc.pixelformat)
+ if (pix_format == vpfe_pix_fmts[i].pixelformat)
return &vpfe_pix_fmts[i];
}
return NULL;
@@ -198,21 +168,22 @@ int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev)
int ret = 0;
printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name);
- BUG_ON(!dev->hw_ops.open);
- BUG_ON(!dev->hw_ops.enable);
- BUG_ON(!dev->hw_ops.set_hw_if_params);
- BUG_ON(!dev->hw_ops.configure);
- BUG_ON(!dev->hw_ops.set_buftype);
- BUG_ON(!dev->hw_ops.get_buftype);
- BUG_ON(!dev->hw_ops.enum_pix);
- BUG_ON(!dev->hw_ops.set_frame_format);
- BUG_ON(!dev->hw_ops.get_frame_format);
- BUG_ON(!dev->hw_ops.get_pixel_format);
- BUG_ON(!dev->hw_ops.set_pixel_format);
- BUG_ON(!dev->hw_ops.set_image_window);
- BUG_ON(!dev->hw_ops.get_image_window);
- BUG_ON(!dev->hw_ops.get_line_length);
- BUG_ON(!dev->hw_ops.getfid);
+ if (!dev->hw_ops.open ||
+ !dev->hw_ops.enable ||
+ !dev->hw_ops.set_hw_if_params ||
+ !dev->hw_ops.configure ||
+ !dev->hw_ops.set_buftype ||
+ !dev->hw_ops.get_buftype ||
+ !dev->hw_ops.enum_pix ||
+ !dev->hw_ops.set_frame_format ||
+ !dev->hw_ops.get_frame_format ||
+ !dev->hw_ops.get_pixel_format ||
+ !dev->hw_ops.set_pixel_format ||
+ !dev->hw_ops.set_image_window ||
+ !dev->hw_ops.get_image_window ||
+ !dev->hw_ops.get_line_length ||
+ !dev->hw_ops.getfid)
+ return -EINVAL;
mutex_lock(&ccdc_lock);
if (!ccdc_cfg) {
@@ -782,7 +753,7 @@ static const struct vpfe_pixel_format *
temp = 0;
found = 0;
while (ccdc_dev->hw_ops.enum_pix(&pix, temp) >= 0) {
- if (vpfe_pix_fmt->fmtdesc.pixelformat == pix) {
+ if (vpfe_pix_fmt->pixelformat == pix) {
found = 1;
break;
}
@@ -877,8 +848,6 @@ static int vpfe_querycap(struct file *file, void *priv,
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
strscpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
strscpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
strscpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
@@ -901,7 +870,6 @@ static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv,
{
struct vpfe_device *vpfe_dev = video_drvdata(file);
const struct vpfe_pixel_format *pix_fmt;
- int temp_index;
u32 pix;
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt_vid_cap\n");
@@ -912,9 +880,7 @@ static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv,
/* Fill in the information about format */
pix_fmt = vpfe_lookup_pix_format(pix);
if (pix_fmt) {
- temp_index = fmt->index;
- *fmt = pix_fmt->fmtdesc;
- fmt->index = temp_index;
+ fmt->pixelformat = fmt->pixelformat;
return 0;
}
return -EINVAL;
@@ -1785,6 +1751,7 @@ static int vpfe_probe(struct platform_device *pdev)
vfd->ioctl_ops = &vpfe_ioctl_ops;
vfd->tvnorms = 0;
vfd->v4l2_dev = &vpfe_dev->v4l2_dev;
+ vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
snprintf(vfd->name, sizeof(vfd->name),
"%s_V%d.%d.%d",
CAPTURE_DRV_NAME,
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index f0f7ef638c56..71f4fe882d13 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -938,17 +938,10 @@ static int vpif_enum_fmt_vid_cap(struct file *file, void *priv,
}
/* Fill in the information about format */
- if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER) {
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strscpy(fmt->description, "Raw Mode -Bayer Pattern GrRBGb",
- sizeof(fmt->description));
+ if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER)
fmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
- } else {
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- strscpy(fmt->description, "YCbCr4:2:2 Semi-Planar",
- sizeof(fmt->description));
+ else
fmt->pixelformat = V4L2_PIX_FMT_NV16;
- }
return 0;
}
@@ -979,7 +972,6 @@ static int vpif_try_fmt_vid_cap(struct file *file, void *priv,
pixfmt->bytesperline = common->fmt.fmt.pix.width * 2;
pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
}
- pixfmt->priv = 0;
dev_dbg(vpif_dev, "%s: %d x %d; pitch=%d pixelformat=0x%08x, field=%d, size=%d\n", __func__,
pixfmt->width, pixfmt->height,
@@ -1085,8 +1077,6 @@ static int vpif_querycap(struct file *file, void *priv,
{
struct vpif_capture_config *config = vpif_dev->platform_data;
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(vpif_dev));
@@ -1473,6 +1463,7 @@ static int vpif_probe_complete(void)
vdev->vfl_dir = VFL_DIR_RX;
vdev->queue = q;
vdev->lock = &common->lock;
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
video_set_drvdata(&ch->video_dev, ch);
err = video_register_device(vdev,
VFL_TYPE_GRABBER, (j ? 1 : 0));
@@ -1511,6 +1502,7 @@ static struct vpif_capture_config *
vpif_capture_get_pdata(struct platform_device *pdev)
{
struct device_node *endpoint = NULL;
+ struct device_node *rem = NULL;
struct vpif_capture_config *pdata;
struct vpif_subdev_info *sdinfo;
struct vpif_capture_chan_config *chan;
@@ -1541,7 +1533,6 @@ vpif_capture_get_pdata(struct platform_device *pdev)
for (i = 0; i < VPIF_CAPTURE_NUM_CHANNELS; i++) {
struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
- struct device_node *rem;
unsigned int flags;
int err;
@@ -1554,7 +1545,6 @@ vpif_capture_get_pdata(struct platform_device *pdev)
if (!rem) {
dev_dbg(&pdev->dev, "Remote device at %pOF not found\n",
endpoint);
- of_node_put(endpoint);
goto done;
}
@@ -1564,11 +1554,8 @@ vpif_capture_get_pdata(struct platform_device *pdev)
VPIF_CAPTURE_NUM_CHANNELS,
sizeof(*chan->inputs),
GFP_KERNEL);
- if (!chan->inputs) {
- of_node_put(rem);
- of_node_put(endpoint);
+ if (!chan->inputs)
goto err_cleanup;
- }
chan->input_count++;
chan->inputs[i].input.type = V4L2_INPUT_TYPE_CAMERA;
@@ -1577,7 +1564,6 @@ vpif_capture_get_pdata(struct platform_device *pdev)
err = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
&bus_cfg);
- of_node_put(endpoint);
if (err) {
dev_err(&pdev->dev, "Could not parse the endpoint\n");
of_node_put(rem);
@@ -1601,13 +1587,14 @@ vpif_capture_get_pdata(struct platform_device *pdev)
pdata->asd[i] = v4l2_async_notifier_add_fwnode_subdev(
&vpif_obj.notifier, of_fwnode_handle(rem),
sizeof(struct v4l2_async_subdev));
- if (IS_ERR(pdata->asd[i])) {
- of_node_put(rem);
+ if (IS_ERR(pdata->asd[i]))
goto err_cleanup;
- }
+
+ of_node_put(rem);
}
done:
+ of_node_put(endpoint);
pdata->asd_sizes[0] = i;
pdata->subdev_count = i;
pdata->card_name = "DA850/OMAP-L138 Video Capture";
@@ -1615,6 +1602,8 @@ done:
return pdata;
err_cleanup:
+ of_node_put(rem);
+ of_node_put(endpoint);
v4l2_async_notifier_cleanup(&vpif_obj.notifier);
return NULL;
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index a69897c68a50..abbdbac08e6f 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -584,8 +584,6 @@ static int vpif_querycap(struct file *file, void *priv,
{
struct vpif_display_config *config = vpif_dev->platform_data;
- cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
strscpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(vpif_dev));
@@ -601,11 +599,7 @@ static int vpif_enum_fmt_vid_out(struct file *file, void *priv,
return -EINVAL;
/* Fill in the information about format */
- fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- strscpy(fmt->description, "YCbCr4:2:2 YC Planar",
- sizeof(fmt->description));
fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
- fmt->flags = 0;
return 0;
}
@@ -1218,6 +1212,7 @@ static int vpif_probe_complete(void)
vdev->vfl_dir = VFL_DIR_TX;
vdev->queue = q;
vdev->lock = &common->lock;
+ vdev->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
video_set_drvdata(&ch->video_dev, ch);
err = video_register_device(vdev, VFL_TYPE_GRABBER,
(j ? 3 : 2));
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index 854869f0024e..f6650b45bc3d 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -27,21 +27,18 @@
static const struct gsc_fmt gsc_formats[] = {
{
- .name = "RGB565",
.pixelformat = V4L2_PIX_FMT_RGB565X,
.depth = { 16 },
.color = GSC_RGB,
.num_planes = 1,
.num_comp = 1,
}, {
- .name = "BGRX-8-8-8-8, 32 bpp",
.pixelformat = V4L2_PIX_FMT_BGR32,
.depth = { 32 },
.color = GSC_RGB,
.num_planes = 1,
.num_comp = 1,
}, {
- .name = "YUV 4:2:2 packed, YCbYCr",
.pixelformat = V4L2_PIX_FMT_YUYV,
.depth = { 16 },
.color = GSC_YUV422,
@@ -51,7 +48,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_comp = 1,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
- .name = "YUV 4:2:2 packed, CbYCrY",
.pixelformat = V4L2_PIX_FMT_UYVY,
.depth = { 16 },
.color = GSC_YUV422,
@@ -61,7 +57,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_comp = 1,
.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
}, {
- .name = "YUV 4:2:2 packed, CrYCbY",
.pixelformat = V4L2_PIX_FMT_VYUY,
.depth = { 16 },
.color = GSC_YUV422,
@@ -71,7 +66,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_comp = 1,
.mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
}, {
- .name = "YUV 4:2:2 packed, YCrYCb",
.pixelformat = V4L2_PIX_FMT_YVYU,
.depth = { 16 },
.color = GSC_YUV422,
@@ -81,7 +75,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_comp = 1,
.mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
}, {
- .name = "YUV 4:4:4 planar, YCbYCr",
.pixelformat = V4L2_PIX_FMT_YUV32,
.depth = { 32 },
.color = GSC_YUV444,
@@ -90,7 +83,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 1,
.num_comp = 1,
}, {
- .name = "YUV 4:2:2 planar, Y/Cb/Cr",
.pixelformat = V4L2_PIX_FMT_YUV422P,
.depth = { 16 },
.color = GSC_YUV422,
@@ -99,7 +91,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 1,
.num_comp = 3,
}, {
- .name = "YUV 4:2:2 planar, Y/CbCr",
.pixelformat = V4L2_PIX_FMT_NV16,
.depth = { 16 },
.color = GSC_YUV422,
@@ -108,7 +99,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 1,
.num_comp = 2,
}, {
- .name = "YUV 4:2:2 non-contig, Y/CbCr",
.pixelformat = V4L2_PIX_FMT_NV16M,
.depth = { 8, 8 },
.color = GSC_YUV422,
@@ -117,7 +107,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 2,
.num_comp = 2,
}, {
- .name = "YUV 4:2:2 planar, Y/CrCb",
.pixelformat = V4L2_PIX_FMT_NV61,
.depth = { 16 },
.color = GSC_YUV422,
@@ -126,7 +115,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 1,
.num_comp = 2,
}, {
- .name = "YUV 4:2:2 non-contig, Y/CrCb",
.pixelformat = V4L2_PIX_FMT_NV61M,
.depth = { 8, 8 },
.color = GSC_YUV422,
@@ -135,7 +123,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 2,
.num_comp = 2,
}, {
- .name = "YUV 4:2:0 planar, YCbCr",
.pixelformat = V4L2_PIX_FMT_YUV420,
.depth = { 12 },
.color = GSC_YUV420,
@@ -144,7 +131,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 1,
.num_comp = 3,
}, {
- .name = "YUV 4:2:0 planar, YCrCb",
.pixelformat = V4L2_PIX_FMT_YVU420,
.depth = { 12 },
.color = GSC_YUV420,
@@ -154,7 +140,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_comp = 3,
}, {
- .name = "YUV 4:2:0 planar, Y/CbCr",
.pixelformat = V4L2_PIX_FMT_NV12,
.depth = { 12 },
.color = GSC_YUV420,
@@ -163,7 +148,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 1,
.num_comp = 2,
}, {
- .name = "YUV 4:2:0 planar, Y/CrCb",
.pixelformat = V4L2_PIX_FMT_NV21,
.depth = { 12 },
.color = GSC_YUV420,
@@ -172,7 +156,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 1,
.num_comp = 2,
}, {
- .name = "YUV 4:2:0 non-contig. 2p, Y/CrCb",
.pixelformat = V4L2_PIX_FMT_NV21M,
.depth = { 8, 4 },
.color = GSC_YUV420,
@@ -181,7 +164,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 2,
.num_comp = 2,
}, {
- .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
.pixelformat = V4L2_PIX_FMT_NV12M,
.depth = { 8, 4 },
.color = GSC_YUV420,
@@ -190,7 +172,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 2,
.num_comp = 2,
}, {
- .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
.pixelformat = V4L2_PIX_FMT_YUV420M,
.depth = { 8, 2, 2 },
.color = GSC_YUV420,
@@ -199,7 +180,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 3,
.num_comp = 3,
}, {
- .name = "YUV 4:2:0 non-contig. 3p, Y/Cr/Cb",
.pixelformat = V4L2_PIX_FMT_YVU420M,
.depth = { 8, 2, 2 },
.color = GSC_YUV420,
@@ -208,7 +188,6 @@ static const struct gsc_fmt gsc_formats[] = {
.num_planes = 3,
.num_comp = 3,
}, {
- .name = "YUV 4:2:0 n.c. 2p, Y/CbCr tiled",
.pixelformat = V4L2_PIX_FMT_NV12MT_16X16,
.depth = { 8, 4 },
.color = GSC_YUV420,
@@ -335,7 +314,6 @@ int gsc_enum_fmt(struct v4l2_fmtdesc *f)
if (!fmt)
return -EINVAL;
- strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->pixelformat;
return 0;
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h
index 772183b090c2..8e5a9acb78aa 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.h
+++ b/drivers/media/platform/exynos-gsc/gsc-core.h
@@ -103,7 +103,6 @@ enum gsc_yuv_fmt {
/**
* struct gsc_fmt - the driver's internal color format data
* @mbus_code: Media Bus pixel code, -1 if not applicable
- * @name: format description
* @pixelformat: the fourcc code for this format, 0 if not applicable
* @yorder: Y/C order
* @corder: Chrominance order control
@@ -114,7 +113,6 @@ enum gsc_yuv_fmt {
*/
struct gsc_fmt {
u32 mbus_code;
- char *name;
u32 pixelformat;
u32 color;
u32 yorder;
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 66510365dd5d..121d609ff856 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -738,10 +738,7 @@ static int fimc_cap_enum_fmt(struct file *file, void *priv,
f->index);
if (!fmt)
return -EINVAL;
- 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;
return 0;
}
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c
index 7006f54bfee2..cde60fbb23a8 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/exynos4-is/fimc-core.c
@@ -36,7 +36,6 @@ static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
static struct fimc_fmt fimc_formats[] = {
{
- .name = "RGB565",
.fourcc = V4L2_PIX_FMT_RGB565,
.depth = { 16 },
.color = FIMC_FMT_RGB565,
@@ -44,7 +43,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 1,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "BGR666",
.fourcc = V4L2_PIX_FMT_BGR666,
.depth = { 32 },
.color = FIMC_FMT_RGB666,
@@ -52,7 +50,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 1,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "BGRA8888, 32 bpp",
.fourcc = V4L2_PIX_FMT_BGR32,
.depth = { 32 },
.color = FIMC_FMT_RGB888,
@@ -60,7 +57,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 1,
.flags = FMT_FLAGS_M2M | FMT_HAS_ALPHA,
}, {
- .name = "ARGB1555",
.fourcc = V4L2_PIX_FMT_RGB555,
.depth = { 16 },
.color = FIMC_FMT_RGB555,
@@ -68,7 +64,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 1,
.flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
}, {
- .name = "ARGB4444",
.fourcc = V4L2_PIX_FMT_RGB444,
.depth = { 16 },
.color = FIMC_FMT_RGB444,
@@ -76,11 +71,9 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 1,
.flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
}, {
- .name = "YUV 4:4:4",
.mbus_code = MEDIA_BUS_FMT_YUV10_1X30,
.flags = FMT_FLAGS_WRITEBACK,
}, {
- .name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = { 16 },
.color = FIMC_FMT_YCBYCR422,
@@ -89,7 +82,6 @@ static struct fimc_fmt fimc_formats[] = {
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
- .name = "YUV 4:2:2 packed, CbYCrY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = { 16 },
.color = FIMC_FMT_CBYCRY422,
@@ -98,7 +90,6 @@ static struct fimc_fmt fimc_formats[] = {
.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
.flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
- .name = "YUV 4:2:2 packed, CrYCbY",
.fourcc = V4L2_PIX_FMT_VYUY,
.depth = { 16 },
.color = FIMC_FMT_CRYCBY422,
@@ -107,7 +98,6 @@ static struct fimc_fmt fimc_formats[] = {
.mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
.flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
- .name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
.depth = { 16 },
.color = FIMC_FMT_YCRYCB422,
@@ -116,7 +106,6 @@ static struct fimc_fmt fimc_formats[] = {
.mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
.flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
- .name = "YUV 4:2:2 planar, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV422P,
.depth = { 16 },
.color = FIMC_FMT_YCBYCR422,
@@ -124,7 +113,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 3,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:2 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV16,
.depth = { 16 },
.color = FIMC_FMT_YCBYCR422,
@@ -132,7 +120,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:2 planar, Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV61,
.depth = { 16 },
.color = FIMC_FMT_YCRYCB422,
@@ -140,7 +127,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:0 planar, YCbCr",
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = { 12 },
.color = FIMC_FMT_YCBCR420,
@@ -148,7 +134,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 3,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:0 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12,
.depth = { 12 },
.color = FIMC_FMT_YCBCR420,
@@ -156,7 +141,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:0 non-contig. 2p, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12M,
.color = FIMC_FMT_YCBCR420,
.depth = { 8, 4 },
@@ -164,7 +148,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:0 non-contig. 3p, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV420M,
.color = FIMC_FMT_YCBCR420,
.depth = { 8, 2, 2 },
@@ -172,7 +155,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 3,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "YUV 4:2:0 non-contig. 2p, tiled",
.fourcc = V4L2_PIX_FMT_NV12MT,
.color = FIMC_FMT_YCBCR420,
.depth = { 8, 4 },
@@ -180,7 +162,6 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 2,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "JPEG encoded data",
.fourcc = V4L2_PIX_FMT_JPEG,
.color = FIMC_FMT_JPEG,
.depth = { 8 },
@@ -189,7 +170,6 @@ static struct fimc_fmt fimc_formats[] = {
.mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
.flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED,
}, {
- .name = "S5C73MX interleaved UYVY/JPEG",
.fourcc = V4L2_PIX_FMT_S5C_UYVY_JPG,
.color = FIMC_FMT_YUYV_JPEG,
.depth = { 8 },
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index e043d55133a3..64148b7e0d98 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -341,7 +341,6 @@ static int fimc_is_alloc_cpu_memory(struct fimc_is *is)
return -ENOMEM;
is->memory.size = FIMC_IS_CPU_MEM_SIZE;
- memset(is->memory.vaddr, 0, is->memory.size);
dev_info(dev, "FIMC-IS CPU memory base: %#x\n", (u32)is->memory.paddr);
@@ -806,6 +805,7 @@ static int fimc_is_probe(struct platform_device *pdev)
return -ENODEV;
is->pmu_regs = of_iomap(node, 0);
+ of_node_put(node);
if (!is->pmu_regs)
return -ENOMEM;
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c
index a75f932a289a..d2cbcdca0463 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -313,7 +313,7 @@ static int isp_video_release(struct file *file)
ivc->streaming = 0;
}
- vb2_fop_release(file);
+ _vb2_fop_release(file, NULL);
if (v4l2_fh_is_singular_file(file)) {
fimc_pipeline_call(&ivc->ve, close);
@@ -362,7 +362,6 @@ static int isp_video_enum_fmt(struct file *file, void *priv,
if (WARN_ON(fmt == NULL))
return -EINVAL;
- strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index 907b83e6649d..cde0d254ec1c 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -33,21 +33,18 @@ module_param_named(debug_isp, fimc_isp_debug, int, S_IRUGO | S_IWUSR);
static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = {
{
- .name = "RAW8 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG8,
.depth = { 8 },
.color = FIMC_FMT_RAW8,
.memplanes = 1,
.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
}, {
- .name = "RAW10 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG10,
.depth = { 10 },
.color = FIMC_FMT_RAW10,
.memplanes = 1,
.mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
}, {
- .name = "RAW12 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG12,
.depth = { 12 },
.color = FIMC_FMT_RAW12,
diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/exynos4-is/fimc-lite-reg.h
index 48f2cf1148b8..c5656e902750 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite-reg.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.h
@@ -6,6 +6,8 @@
#ifndef FIMC_LITE_REG_H_
#define FIMC_LITE_REG_H_
+#include <linux/bitops.h>
+
#include "fimc-lite.h"
/* Camera Source size */
@@ -27,27 +29,27 @@
/* User defined formats. x = 0...15 */
#define FLITE_REG_CIGCTRL_USER(x) ((0x30 + x - 1) << 24)
#define FLITE_REG_CIGCTRL_FMT_MASK (0x3f << 24)
-#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE (1 << 21)
-#define FLITE_REG_CIGCTRL_ODMA_DISABLE (1 << 20)
-#define FLITE_REG_CIGCTRL_SWRST_REQ (1 << 19)
-#define FLITE_REG_CIGCTRL_SWRST_RDY (1 << 18)
-#define FLITE_REG_CIGCTRL_SWRST (1 << 17)
-#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR (1 << 15)
-#define FLITE_REG_CIGCTRL_INVPOLPCLK (1 << 14)
-#define FLITE_REG_CIGCTRL_INVPOLVSYNC (1 << 13)
-#define FLITE_REG_CIGCTRL_INVPOLHREF (1 << 12)
+#define FLITE_REG_CIGCTRL_SHADOWMASK_DISABLE BIT(21)
+#define FLITE_REG_CIGCTRL_ODMA_DISABLE BIT(20)
+#define FLITE_REG_CIGCTRL_SWRST_REQ BIT(19)
+#define FLITE_REG_CIGCTRL_SWRST_RDY BIT(18)
+#define FLITE_REG_CIGCTRL_SWRST BIT(17)
+#define FLITE_REG_CIGCTRL_TEST_PATTERN_COLORBAR BIT(15)
+#define FLITE_REG_CIGCTRL_INVPOLPCLK BIT(14)
+#define FLITE_REG_CIGCTRL_INVPOLVSYNC BIT(13)
+#define FLITE_REG_CIGCTRL_INVPOLHREF BIT(12)
/* Interrupts mask bits (1 disables an interrupt) */
-#define FLITE_REG_CIGCTRL_IRQ_LASTEN (1 << 8)
-#define FLITE_REG_CIGCTRL_IRQ_ENDEN (1 << 7)
-#define FLITE_REG_CIGCTRL_IRQ_STARTEN (1 << 6)
-#define FLITE_REG_CIGCTRL_IRQ_OVFEN (1 << 5)
+#define FLITE_REG_CIGCTRL_IRQ_LASTEN BIT(8)
+#define FLITE_REG_CIGCTRL_IRQ_ENDEN BIT(7)
+#define FLITE_REG_CIGCTRL_IRQ_STARTEN BIT(6)
+#define FLITE_REG_CIGCTRL_IRQ_OVFEN BIT(5)
#define FLITE_REG_CIGCTRL_IRQ_DISABLE_MASK (0xf << 5)
-#define FLITE_REG_CIGCTRL_SELCAM_MIPI (1 << 3)
+#define FLITE_REG_CIGCTRL_SELCAM_MIPI BIT(3)
/* Image Capture Enable */
#define FLITE_REG_CIIMGCPT 0x08
-#define FLITE_REG_CIIMGCPT_IMGCPTEN (1 << 31)
-#define FLITE_REG_CIIMGCPT_CPT_FREN (1 << 25)
+#define FLITE_REG_CIIMGCPT_IMGCPTEN BIT(31)
+#define FLITE_REG_CIIMGCPT_CPT_FREN BIT(25)
#define FLITE_REG_CIIMGCPT_CPT_MOD_FRCNT (1 << 18)
#define FLITE_REG_CIIMGCPT_CPT_MOD_FREN (0 << 18)
@@ -56,10 +58,10 @@
/* Camera Window Offset */
#define FLITE_REG_CIWDOFST 0x10
-#define FLITE_REG_CIWDOFST_WINOFSEN (1 << 31)
-#define FLITE_REG_CIWDOFST_CLROVIY (1 << 31)
-#define FLITE_REG_CIWDOFST_CLROVFICB (1 << 15)
-#define FLITE_REG_CIWDOFST_CLROVFICR (1 << 14)
+#define FLITE_REG_CIWDOFST_WINOFSEN BIT(31)
+#define FLITE_REG_CIWDOFST_CLROVIY BIT(31)
+#define FLITE_REG_CIWDOFST_CLROVFICB BIT(15)
+#define FLITE_REG_CIWDOFST_CLROVFICR BIT(14)
#define FLITE_REG_CIWDOFST_OFST_MASK ((0x1fff << 16) | 0x1fff)
/* Camera Window Offset2 */
@@ -67,8 +69,8 @@
/* Camera Output DMA Format */
#define FLITE_REG_CIODMAFMT 0x18
-#define FLITE_REG_CIODMAFMT_RAW_CON (1 << 15)
-#define FLITE_REG_CIODMAFMT_PACK12 (1 << 14)
+#define FLITE_REG_CIODMAFMT_RAW_CON BIT(15)
+#define FLITE_REG_CIODMAFMT_PACK12 BIT(14)
#define FLITE_REG_CIODMAFMT_YCBYCR (0 << 4)
#define FLITE_REG_CIODMAFMT_YCRYCB (1 << 4)
#define FLITE_REG_CIODMAFMT_CBYCRY (2 << 4)
@@ -88,34 +90,34 @@
/* Camera Status */
#define FLITE_REG_CISTATUS 0x40
-#define FLITE_REG_CISTATUS_MIPI_VVALID (1 << 22)
-#define FLITE_REG_CISTATUS_MIPI_HVALID (1 << 21)
-#define FLITE_REG_CISTATUS_MIPI_DVALID (1 << 20)
-#define FLITE_REG_CISTATUS_ITU_VSYNC (1 << 14)
-#define FLITE_REG_CISTATUS_ITU_HREFF (1 << 13)
-#define FLITE_REG_CISTATUS_OVFIY (1 << 10)
-#define FLITE_REG_CISTATUS_OVFICB (1 << 9)
-#define FLITE_REG_CISTATUS_OVFICR (1 << 8)
-#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW (1 << 7)
-#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND (1 << 6)
-#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART (1 << 5)
-#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND (1 << 4)
-#define FLITE_REG_CISTATUS_IRQ_CAM (1 << 0)
+#define FLITE_REG_CISTATUS_MIPI_VVALID BIT(22)
+#define FLITE_REG_CISTATUS_MIPI_HVALID BIT(21)
+#define FLITE_REG_CISTATUS_MIPI_DVALID BIT(20)
+#define FLITE_REG_CISTATUS_ITU_VSYNC BIT(14)
+#define FLITE_REG_CISTATUS_ITU_HREFF BIT(13)
+#define FLITE_REG_CISTATUS_OVFIY BIT(10)
+#define FLITE_REG_CISTATUS_OVFICB BIT(9)
+#define FLITE_REG_CISTATUS_OVFICR BIT(8)
+#define FLITE_REG_CISTATUS_IRQ_SRC_OVERFLOW BIT(7)
+#define FLITE_REG_CISTATUS_IRQ_SRC_LASTCAPEND BIT(6)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMSTART BIT(5)
+#define FLITE_REG_CISTATUS_IRQ_SRC_FRMEND BIT(4)
+#define FLITE_REG_CISTATUS_IRQ_CAM BIT(0)
#define FLITE_REG_CISTATUS_IRQ_MASK (0xf << 4)
/* Camera Status2 */
#define FLITE_REG_CISTATUS2 0x44
-#define FLITE_REG_CISTATUS2_LASTCAPEND (1 << 1)
-#define FLITE_REG_CISTATUS2_FRMEND (1 << 0)
+#define FLITE_REG_CISTATUS2_LASTCAPEND BIT(1)
+#define FLITE_REG_CISTATUS2_FRMEND BIT(0)
/* Qos Threshold */
#define FLITE_REG_CITHOLD 0xf0
-#define FLITE_REG_CITHOLD_W_QOS_EN (1 << 30)
+#define FLITE_REG_CITHOLD_W_QOS_EN BIT(30)
/* Camera General Purpose */
#define FLITE_REG_CIGENERAL 0xfc
/* b0: 1 - camera B, 0 - camera A */
-#define FLITE_REG_CIGENERAL_CAM_B (1 << 0)
+#define FLITE_REG_CIGENERAL_CAM_B BIT(0)
#define FLITE_REG_CIFCNTSEQ 0x100
#define FLITE_REG_CIOSAN(x) (0x200 + (4 * (x)))
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index c1f0aee02e5e..e87c6a09205b 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -39,7 +39,6 @@ module_param(debug, int, 0644);
static const struct fimc_fmt fimc_lite_formats[] = {
{
- .name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
@@ -48,7 +47,6 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
- .name = "YUV 4:2:2 packed, CbYCrY",
.fourcc = V4L2_PIX_FMT_UYVY,
.colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
@@ -57,7 +55,6 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
- .name = "YUV 4:2:2 packed, CrYCbY",
.fourcc = V4L2_PIX_FMT_VYUY,
.colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
@@ -66,7 +63,6 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
- .name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
.colorspace = V4L2_COLORSPACE_JPEG,
.depth = { 16 },
@@ -75,7 +71,6 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
- .name = "RAW8 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG8,
.colorspace = V4L2_COLORSPACE_SRGB,
.depth = { 8 },
@@ -84,7 +79,6 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
.flags = FMT_FLAGS_RAW_BAYER,
}, {
- .name = "RAW10 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG10,
.colorspace = V4L2_COLORSPACE_SRGB,
.depth = { 16 },
@@ -93,7 +87,6 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
.flags = FMT_FLAGS_RAW_BAYER,
}, {
- .name = "RAW12 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG12,
.colorspace = V4L2_COLORSPACE_SRGB,
.depth = { 16 },
@@ -667,7 +660,6 @@ static int fimc_lite_enum_fmt(struct file *file, void *priv,
return -EINVAL;
fmt = &fimc_lite_formats[f->index];
- strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index 62e876fc3555..c70c2cbe3eb1 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -247,7 +247,6 @@ static int fimc_m2m_enum_fmt(struct file *file, void *priv,
if (!fmt)
return -EINVAL;
- strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
diff --git a/drivers/media/platform/exynos4-is/fimc-reg.h b/drivers/media/platform/exynos4-is/fimc-reg.h
index 03ba6c2bc84b..b81826d04936 100644
--- a/drivers/media/platform/exynos4-is/fimc-reg.h
+++ b/drivers/media/platform/exynos4-is/fimc-reg.h
@@ -8,12 +8,14 @@
#ifndef FIMC_REG_H_
#define FIMC_REG_H_
+#include <linux/bitops.h>
+
#include "fimc-core.h"
/* Input source format */
#define FIMC_REG_CISRCFMT 0x00
-#define FIMC_REG_CISRCFMT_ITU601_8BIT (1 << 31)
-#define FIMC_REG_CISRCFMT_ITU601_16BIT (1 << 29)
+#define FIMC_REG_CISRCFMT_ITU601_8BIT BIT(31)
+#define FIMC_REG_CISRCFMT_ITU601_16BIT BIT(29)
#define FIMC_REG_CISRCFMT_ORDER422_YCBYCR (0 << 14)
#define FIMC_REG_CISRCFMT_ORDER422_YCRYCB (1 << 14)
#define FIMC_REG_CISRCFMT_ORDER422_CBYCRY (2 << 14)
@@ -21,45 +23,45 @@
/* Window offset */
#define FIMC_REG_CIWDOFST 0x04
-#define FIMC_REG_CIWDOFST_OFF_EN (1 << 31)
-#define FIMC_REG_CIWDOFST_CLROVFIY (1 << 30)
-#define FIMC_REG_CIWDOFST_CLROVRLB (1 << 29)
+#define FIMC_REG_CIWDOFST_OFF_EN BIT(31)
+#define FIMC_REG_CIWDOFST_CLROVFIY BIT(30)
+#define FIMC_REG_CIWDOFST_CLROVRLB BIT(29)
#define FIMC_REG_CIWDOFST_HOROFF_MASK (0x7ff << 16)
-#define FIMC_REG_CIWDOFST_CLROVFICB (1 << 15)
-#define FIMC_REG_CIWDOFST_CLROVFICR (1 << 14)
+#define FIMC_REG_CIWDOFST_CLROVFICB BIT(15)
+#define FIMC_REG_CIWDOFST_CLROVFICR BIT(14)
#define FIMC_REG_CIWDOFST_VEROFF_MASK (0xfff << 0)
/* Global control */
#define FIMC_REG_CIGCTRL 0x08
-#define FIMC_REG_CIGCTRL_SWRST (1 << 31)
-#define FIMC_REG_CIGCTRL_CAMRST_A (1 << 30)
-#define FIMC_REG_CIGCTRL_SELCAM_ITU_A (1 << 29)
+#define FIMC_REG_CIGCTRL_SWRST BIT(31)
+#define FIMC_REG_CIGCTRL_CAMRST_A BIT(30)
+#define FIMC_REG_CIGCTRL_SELCAM_ITU_A BIT(29)
#define FIMC_REG_CIGCTRL_TESTPAT_NORMAL (0 << 27)
#define FIMC_REG_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27)
#define FIMC_REG_CIGCTRL_TESTPAT_HOR_INC (2 << 27)
#define FIMC_REG_CIGCTRL_TESTPAT_VER_INC (3 << 27)
#define FIMC_REG_CIGCTRL_TESTPAT_MASK (3 << 27)
#define FIMC_REG_CIGCTRL_TESTPAT_SHIFT 27
-#define FIMC_REG_CIGCTRL_INVPOLPCLK (1 << 26)
-#define FIMC_REG_CIGCTRL_INVPOLVSYNC (1 << 25)
-#define FIMC_REG_CIGCTRL_INVPOLHREF (1 << 24)
-#define FIMC_REG_CIGCTRL_IRQ_OVFEN (1 << 22)
-#define FIMC_REG_CIGCTRL_HREF_MASK (1 << 21)
-#define FIMC_REG_CIGCTRL_IRQ_LEVEL (1 << 20)
-#define FIMC_REG_CIGCTRL_IRQ_CLR (1 << 19)
-#define FIMC_REG_CIGCTRL_IRQ_ENABLE (1 << 16)
-#define FIMC_REG_CIGCTRL_SHDW_DISABLE (1 << 12)
+#define FIMC_REG_CIGCTRL_INVPOLPCLK BIT(26)
+#define FIMC_REG_CIGCTRL_INVPOLVSYNC BIT(25)
+#define FIMC_REG_CIGCTRL_INVPOLHREF BIT(24)
+#define FIMC_REG_CIGCTRL_IRQ_OVFEN BIT(22)
+#define FIMC_REG_CIGCTRL_HREF_MASK BIT(21)
+#define FIMC_REG_CIGCTRL_IRQ_LEVEL BIT(20)
+#define FIMC_REG_CIGCTRL_IRQ_CLR BIT(19)
+#define FIMC_REG_CIGCTRL_IRQ_ENABLE BIT(16)
+#define FIMC_REG_CIGCTRL_SHDW_DISABLE BIT(12)
/* 0 - selects Writeback A (LCD), 1 - selects Writeback B (LCD/ISP) */
-#define FIMC_REG_CIGCTRL_SELWB_A (1 << 10)
-#define FIMC_REG_CIGCTRL_CAM_JPEG (1 << 8)
-#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A (1 << 7)
-#define FIMC_REG_CIGCTRL_CAMIF_SELWB (1 << 6)
+#define FIMC_REG_CIGCTRL_SELWB_A BIT(10)
+#define FIMC_REG_CIGCTRL_CAM_JPEG BIT(8)
+#define FIMC_REG_CIGCTRL_SELCAM_MIPI_A BIT(7)
+#define FIMC_REG_CIGCTRL_CAMIF_SELWB BIT(6)
/* 0 - ITU601; 1 - ITU709 */
-#define FIMC_REG_CIGCTRL_CSC_ITU601_709 (1 << 5)
-#define FIMC_REG_CIGCTRL_INVPOLHSYNC (1 << 4)
-#define FIMC_REG_CIGCTRL_SELCAM_MIPI (1 << 3)
-#define FIMC_REG_CIGCTRL_INVPOLFIELD (1 << 1)
-#define FIMC_REG_CIGCTRL_INTERLACE (1 << 0)
+#define FIMC_REG_CIGCTRL_CSC_ITU601_709 BIT(5)
+#define FIMC_REG_CIGCTRL_INVPOLHSYNC BIT(4)
+#define FIMC_REG_CIGCTRL_SELCAM_MIPI BIT(3)
+#define FIMC_REG_CIGCTRL_INVPOLFIELD BIT(1)
+#define FIMC_REG_CIGCTRL_INTERLACE BIT(0)
/* Window offset 2 */
#define FIMC_REG_CIWDOFST2 0x14
@@ -73,7 +75,7 @@
/* Target image format */
#define FIMC_REG_CITRGFMT 0x48
-#define FIMC_REG_CITRGFMT_INROT90 (1 << 31)
+#define FIMC_REG_CITRGFMT_INROT90 BIT(31)
#define FIMC_REG_CITRGFMT_YCBCR420 (0 << 29)
#define FIMC_REG_CITRGFMT_YCBCR422 (1 << 29)
#define FIMC_REG_CITRGFMT_YCBCR422_1P (2 << 29)
@@ -86,7 +88,7 @@
#define FIMC_REG_CITRGFMT_FLIP_Y_MIRROR (2 << 14)
#define FIMC_REG_CITRGFMT_FLIP_180 (3 << 14)
#define FIMC_REG_CITRGFMT_FLIP_MASK (3 << 14)
-#define FIMC_REG_CITRGFMT_OUTROT90 (1 << 13)
+#define FIMC_REG_CITRGFMT_OUTROT90 BIT(13)
#define FIMC_REG_CITRGFMT_VSIZE_MASK (0xfff << 0)
/* Output DMA control */
@@ -96,7 +98,7 @@
#define FIMC_REG_CIOCTRL_ORDER422_YCRYCB (1 << 0)
#define FIMC_REG_CIOCTRL_ORDER422_CBYCRY (2 << 0)
#define FIMC_REG_CIOCTRL_ORDER422_CRYCBY (3 << 0)
-#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE (1 << 2)
+#define FIMC_REG_CIOCTRL_LASTIRQ_ENABLE BIT(2)
#define FIMC_REG_CIOCTRL_YCBCR_3PLANE (0 << 3)
#define FIMC_REG_CIOCTRL_YCBCR_2PLANE (1 << 3)
#define FIMC_REG_CIOCTRL_YCBCR_PLANE_MASK (1 << 3)
@@ -116,14 +118,14 @@
/* Main scaler control */
#define FIMC_REG_CISCCTRL 0x58
-#define FIMC_REG_CISCCTRL_SCALERBYPASS (1 << 31)
-#define FIMC_REG_CISCCTRL_SCALEUP_H (1 << 30)
-#define FIMC_REG_CISCCTRL_SCALEUP_V (1 << 29)
-#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE (1 << 28)
-#define FIMC_REG_CISCCTRL_CSCY2R_WIDE (1 << 27)
-#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO (1 << 26)
-#define FIMC_REG_CISCCTRL_INTERLACE (1 << 25)
-#define FIMC_REG_CISCCTRL_SCALERSTART (1 << 15)
+#define FIMC_REG_CISCCTRL_SCALERBYPASS BIT(31)
+#define FIMC_REG_CISCCTRL_SCALEUP_H BIT(30)
+#define FIMC_REG_CISCCTRL_SCALEUP_V BIT(29)
+#define FIMC_REG_CISCCTRL_CSCR2Y_WIDE BIT(28)
+#define FIMC_REG_CISCCTRL_CSCY2R_WIDE BIT(27)
+#define FIMC_REG_CISCCTRL_LCDPATHEN_FIFO BIT(26)
+#define FIMC_REG_CISCCTRL_INTERLACE BIT(25)
+#define FIMC_REG_CISCCTRL_SCALERSTART BIT(15)
#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB565 (0 << 13)
#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB666 (1 << 13)
#define FIMC_REG_CISCCTRL_INRGB_FMT_RGB888 (2 << 13)
@@ -132,8 +134,8 @@
#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11)
#define FIMC_REG_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11)
#define FIMC_REG_CISCCTRL_OUTRGB_FMT_MASK (3 << 11)
-#define FIMC_REG_CISCCTRL_RGB_EXT (1 << 10)
-#define FIMC_REG_CISCCTRL_ONE2ONE (1 << 9)
+#define FIMC_REG_CISCCTRL_RGB_EXT BIT(10)
+#define FIMC_REG_CISCCTRL_ONE2ONE BIT(9)
#define FIMC_REG_CISCCTRL_MHRATIO(x) ((x) << 16)
#define FIMC_REG_CISCCTRL_MVRATIO(x) ((x) << 0)
#define FIMC_REG_CISCCTRL_MHRATIO_MASK (0x1ff << 16)
@@ -147,39 +149,39 @@
/* General status */
#define FIMC_REG_CISTATUS 0x64
-#define FIMC_REG_CISTATUS_OVFIY (1 << 31)
-#define FIMC_REG_CISTATUS_OVFICB (1 << 30)
-#define FIMC_REG_CISTATUS_OVFICR (1 << 29)
-#define FIMC_REG_CISTATUS_VSYNC (1 << 28)
+#define FIMC_REG_CISTATUS_OVFIY BIT(31)
+#define FIMC_REG_CISTATUS_OVFICB BIT(30)
+#define FIMC_REG_CISTATUS_OVFICR BIT(29)
+#define FIMC_REG_CISTATUS_VSYNC BIT(28)
#define FIMC_REG_CISTATUS_FRAMECNT_MASK (3 << 26)
#define FIMC_REG_CISTATUS_FRAMECNT_SHIFT 26
-#define FIMC_REG_CISTATUS_WINOFF_EN (1 << 25)
-#define FIMC_REG_CISTATUS_IMGCPT_EN (1 << 22)
-#define FIMC_REG_CISTATUS_IMGCPT_SCEN (1 << 21)
-#define FIMC_REG_CISTATUS_VSYNC_A (1 << 20)
-#define FIMC_REG_CISTATUS_VSYNC_B (1 << 19)
-#define FIMC_REG_CISTATUS_OVRLB (1 << 18)
-#define FIMC_REG_CISTATUS_FRAME_END (1 << 17)
-#define FIMC_REG_CISTATUS_LASTCAPT_END (1 << 16)
-#define FIMC_REG_CISTATUS_VVALID_A (1 << 15)
-#define FIMC_REG_CISTATUS_VVALID_B (1 << 14)
+#define FIMC_REG_CISTATUS_WINOFF_EN BIT(25)
+#define FIMC_REG_CISTATUS_IMGCPT_EN BIT(22)
+#define FIMC_REG_CISTATUS_IMGCPT_SCEN BIT(21)
+#define FIMC_REG_CISTATUS_VSYNC_A BIT(20)
+#define FIMC_REG_CISTATUS_VSYNC_B BIT(19)
+#define FIMC_REG_CISTATUS_OVRLB BIT(18)
+#define FIMC_REG_CISTATUS_FRAME_END BIT(17)
+#define FIMC_REG_CISTATUS_LASTCAPT_END BIT(16)
+#define FIMC_REG_CISTATUS_VVALID_A BIT(15)
+#define FIMC_REG_CISTATUS_VVALID_B BIT(14)
/* Indexes to the last and the currently processed buffer. */
#define FIMC_REG_CISTATUS2 0x68
/* Image capture control */
#define FIMC_REG_CIIMGCPT 0xc0
-#define FIMC_REG_CIIMGCPT_IMGCPTEN (1 << 31)
-#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC (1 << 30)
-#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE (1 << 25)
-#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT (1 << 18)
+#define FIMC_REG_CIIMGCPT_IMGCPTEN BIT(31)
+#define FIMC_REG_CIIMGCPT_IMGCPTEN_SC BIT(30)
+#define FIMC_REG_CIIMGCPT_CPT_FREN_ENABLE BIT(25)
+#define FIMC_REG_CIIMGCPT_CPT_FRMOD_CNT BIT(18)
/* Frame capture sequence */
#define FIMC_REG_CICPTSEQ 0xc4
/* Image effect */
#define FIMC_REG_CIIMGEFF 0xd0
-#define FIMC_REG_CIIMGEFF_IE_ENABLE (1 << 30)
+#define FIMC_REG_CIIMGEFF_IE_ENABLE BIT(30)
#define FIMC_REG_CIIMGEFF_IE_SC_BEFORE (0 << 29)
#define FIMC_REG_CIIMGEFF_IE_SC_AFTER (1 << 29)
#define FIMC_REG_CIIMGEFF_FIN_BYPASS (0 << 26)
@@ -198,8 +200,8 @@
/* Real input DMA image size */
#define FIMC_REG_CIREAL_ISIZE 0xf8
-#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN (1 << 31)
-#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS (1 << 30)
+#define FIMC_REG_CIREAL_ISIZE_AUTOLOAD_EN BIT(31)
+#define FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS BIT(30)
/* Input DMA control */
#define FIMC_REG_MSCTRL 0xfc
@@ -215,7 +217,7 @@
#define FIMC_REG_MSCTRL_FLIP_X_MIRROR (1 << 13)
#define FIMC_REG_MSCTRL_FLIP_Y_MIRROR (2 << 13)
#define FIMC_REG_MSCTRL_FLIP_180 (3 << 13)
-#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL (1 << 12)
+#define FIMC_REG_MSCTRL_FIFO_CTRL_FULL BIT(12)
#define FIMC_REG_MSCTRL_ORDER422_SHIFT 4
#define FIMC_REG_MSCTRL_ORDER422_CRYCBY (0 << 4)
#define FIMC_REG_MSCTRL_ORDER422_YCRYCB (1 << 4)
@@ -223,14 +225,14 @@
#define FIMC_REG_MSCTRL_ORDER422_YCBYCR (3 << 4)
#define FIMC_REG_MSCTRL_ORDER422_MASK (3 << 4)
#define FIMC_REG_MSCTRL_INPUT_EXTCAM (0 << 3)
-#define FIMC_REG_MSCTRL_INPUT_MEMORY (1 << 3)
-#define FIMC_REG_MSCTRL_INPUT_MASK (1 << 3)
+#define FIMC_REG_MSCTRL_INPUT_MEMORY BIT(3)
+#define FIMC_REG_MSCTRL_INPUT_MASK BIT(3)
#define FIMC_REG_MSCTRL_INFORMAT_YCBCR420 (0 << 1)
#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422 (1 << 1)
#define FIMC_REG_MSCTRL_INFORMAT_YCBCR422_1P (2 << 1)
#define FIMC_REG_MSCTRL_INFORMAT_RGB (3 << 1)
#define FIMC_REG_MSCTRL_INFORMAT_MASK (3 << 1)
-#define FIMC_REG_MSCTRL_ENVID (1 << 0)
+#define FIMC_REG_MSCTRL_ENVID BIT(0)
#define FIMC_REG_MSCTRL_IN_BURST_COUNT(x) ((x) << 24)
/* Output DMA Y/Cb/Cr offset */
@@ -277,10 +279,10 @@
/* SYSREG ISP Writeback register address offsets */
#define SYSREG_ISPBLK 0x020c
-#define SYSREG_ISPBLK_FIFORST_CAM_BLK (1 << 7)
+#define SYSREG_ISPBLK_FIFORST_CAM_BLK BIT(7)
#define SYSREG_CAMBLK 0x0218
-#define SYSREG_CAMBLK_FIFORST_ISP (1 << 15)
+#define SYSREG_CAMBLK_FIFORST_ISP BIT(15)
#define SYSREG_CAMBLK_ISPWB_FULL_EN (7 << 20)
/*
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index d53427a8db11..9aaf3b8060d5 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -501,6 +501,7 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
continue;
ret = fimc_md_parse_port_node(fmd, port, index);
+ of_node_put(port);
if (ret < 0) {
of_node_put(node);
goto cleanup;
@@ -542,6 +543,7 @@ static int __of_get_csis_id(struct device_node *np)
if (!np)
return -EINVAL;
of_property_read_u32(np, "reg", &reg);
+ of_node_put(np);
return reg - FIMC_INPUT_MIPI_CSI2_0;
}
@@ -1455,12 +1457,12 @@ static int fimc_md_probe(struct platform_device *pdev)
ret = v4l2_device_register(dev, &fmd->v4l2_dev);
if (ret < 0) {
v4l2_err(v4l2_dev, "Failed to register v4l2_device: %d\n", ret);
- return ret;
+ goto err_md;
}
ret = fimc_md_get_clocks(fmd);
if (ret)
- goto err_md;
+ goto err_v4l2dev;
ret = fimc_md_get_pinctrl(fmd);
if (ret < 0) {
@@ -1517,9 +1519,10 @@ err_m_ent:
fimc_md_unregister_entities(fmd);
err_clk:
fimc_md_put_clocks(fmd);
+err_v4l2dev:
+ v4l2_device_unregister(&fmd->v4l2_dev);
err_md:
media_device_cleanup(&fmd->media_dev);
- v4l2_device_unregister(&fmd->v4l2_dev);
return ret;
}
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 3e9ac6066cf6..540151bbf58f 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
/* CSIS global control */
#define S5PCSIS_CTRL 0x00
#define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31)
-#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP (1UL << 31)
#define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20)
#define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16)
#define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8)
@@ -65,7 +65,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
/* Interrupt mask */
#define S5PCSIS_INTMSK 0x10
-#define S5PCSIS_INTMSK_EVEN_BEFORE (1 << 31)
+#define S5PCSIS_INTMSK_EVEN_BEFORE (1UL << 31)
#define S5PCSIS_INTMSK_EVEN_AFTER (1 << 30)
#define S5PCSIS_INTMSK_ODD_BEFORE (1 << 29)
#define S5PCSIS_INTMSK_ODD_AFTER (1 << 28)
@@ -83,7 +83,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
/* Interrupt source */
#define S5PCSIS_INTSRC 0x14
-#define S5PCSIS_INTSRC_EVEN_BEFORE (1 << 31)
+#define S5PCSIS_INTSRC_EVEN_BEFORE (1UL << 31)
#define S5PCSIS_INTSRC_EVEN_AFTER (1 << 30)
#define S5PCSIS_INTSRC_EVEN (0x3 << 30)
#define S5PCSIS_INTSRC_ODD_BEFORE (1 << 29)
@@ -803,10 +803,8 @@ static int s5pcsis_probe(struct platform_device *pdev)
return PTR_ERR(state->regs);
state->irq = platform_get_irq(pdev, 0);
- if (state->irq < 0) {
- dev_err(dev, "Failed to get irq\n");
+ if (state->irq < 0)
return state->irq;
- }
for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
state->supplies[i].supply = csis_supply_name[i];
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index 691be788e38b..81a8faedbba6 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -32,7 +32,7 @@
#define VIU_VERSION "0.5.1"
/* Allow building this driver with COMPILE_TEST */
-#ifndef CONFIG_PPC
+#if !defined(CONFIG_PPC) && !defined(CONFIG_MICROBLAZE)
#define out_be32(v, a) iowrite32be(a, (void __iomem *)v)
#define in_be32(a) ioread32be((void __iomem *)a)
#endif
@@ -214,7 +214,7 @@ enum status_config {
FIELD_NO = 0x01 << 28, /* Field number */
DITHER_ON = 0x01 << 29, /* Dithering is on */
ROUND_ON = 0x01 << 30, /* Round is on */
- MODE_32BIT = 0x01 << 31, /* Data in RGBa888,
+ MODE_32BIT = 1UL << 31, /* Data in RGBa888,
* 0 in RGB565
*/
};
@@ -563,11 +563,6 @@ static int vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, "viu", sizeof(cap->driver));
strscpy(cap->card, "viu", sizeof(cap->card));
strscpy(cap->bus_info, "platform:viu", sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_OVERLAY |
- V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1380,6 +1375,8 @@ static const struct video_device viu_template = {
.release = video_device_release,
.tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_READWRITE,
};
static int viu_of_probe(struct platform_device *op)
diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c
index 8e7ef23b9a7e..38d942322302 100644
--- a/drivers/media/platform/imx-pxp.c
+++ b/drivers/media/platform/imx-pxp.c
@@ -1661,10 +1661,8 @@ static int pxp_probe(struct platform_device *pdev)
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "Failed to get irq resource: %d\n", irq);
+ if (irq < 0)
return irq;
- }
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, pxp_irq_handler,
IRQF_ONESHOT, dev_name(&pdev->dev), dev);
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index beb7fd7442fb..9ad24c86c5ab 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -37,7 +37,6 @@ module_param(debug, bool, 0644);
v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
struct deinterlace_fmt {
- char *name;
u32 fourcc;
/* Types the format can be used for */
u32 types;
@@ -45,12 +44,10 @@ struct deinterlace_fmt {
static struct deinterlace_fmt formats[] = {
{
- .name = "YUV 4:2:0 Planar",
.fourcc = V4L2_PIX_FMT_YUV420,
.types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
},
{
- .name = "YUYV 4:2:2",
.fourcc = V4L2_PIX_FMT_YUYV,
.types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
},
@@ -135,13 +132,13 @@ struct deinterlace_dev {
};
struct deinterlace_ctx {
+ struct v4l2_fh fh;
struct deinterlace_dev *dev;
/* Abort requested by m2m */
int aborting;
enum v4l2_colorspace colorspace;
dma_cookie_t cookie;
- struct v4l2_m2m_ctx *m2m_ctx;
struct dma_interleaved_template *xt;
};
@@ -153,9 +150,9 @@ static int deinterlace_job_ready(void *priv)
struct deinterlace_ctx *ctx = priv;
struct deinterlace_dev *pcdev = ctx->dev;
- if ((v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0)
- && (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0)
- && (atomic_read(&ctx->dev->busy) == 0)) {
+ if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0 &&
+ v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0 &&
+ !atomic_read(&ctx->dev->busy)) {
dprintk(pcdev, "Task ready\n");
return 1;
}
@@ -174,7 +171,7 @@ static void deinterlace_job_abort(void *priv)
dprintk(pcdev, "Aborting task\n");
- v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
+ v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->fh.m2m_ctx);
}
static void dma_callback(void *data)
@@ -185,8 +182,8 @@ static void dma_callback(void *data)
atomic_set(&pcdev->busy, 0);
- src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
- dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+ src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
@@ -197,7 +194,7 @@ static void dma_callback(void *data)
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
- v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
+ v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->fh.m2m_ctx);
dprintk(pcdev, "dma transfers completed.\n");
}
@@ -216,8 +213,8 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op,
dma_addr_t p_in, p_out;
enum dma_ctrl_flags flags;
- src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT);
s_width = s_q_data->width;
@@ -436,16 +433,7 @@ static int vidioc_querycap(struct file *file, void *priv,
{
strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
- strscpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card));
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
- V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
+ strscpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info));
return 0;
}
@@ -470,7 +458,6 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
if (i < NUM_FORMATS) {
/* Format found */
fmt = &formats[i];
- strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
@@ -496,7 +483,7 @@ static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f)
struct vb2_queue *vq;
struct deinterlace_q_data *q_data;
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
@@ -593,7 +580,7 @@ static int vidioc_s_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f)
struct deinterlace_q_data *q_data;
struct vb2_queue *vq;
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
@@ -666,36 +653,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
return ret;
}
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct deinterlace_ctx *ctx = priv;
-
- return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct deinterlace_ctx *ctx = priv;
-
- return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct deinterlace_ctx *ctx = priv;
-
- return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct deinterlace_ctx *ctx = priv;
-
- return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
@@ -736,15 +693,7 @@ static int vidioc_streamon(struct file *file, void *priv,
return -EINVAL;
}
- return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct deinterlace_ctx *ctx = priv;
-
- return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+ return v4l2_m2m_streamon(file, ctx->fh.m2m_ctx, type);
}
static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = {
@@ -760,14 +709,15 @@ static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = {
.vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
-
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
.vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
};
@@ -831,7 +781,7 @@ static void deinterlace_buf_queue(struct vb2_buffer *vb)
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf);
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
}
static const struct vb2_ops deinterlace_qops = {
@@ -849,7 +799,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &deinterlace_qops;
@@ -868,7 +818,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &deinterlace_qops;
@@ -897,12 +847,13 @@ static int deinterlace_open(struct file *file)
if (!ctx)
return -ENOMEM;
- file->private_data = ctx;
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
ctx->dev = pcdev;
- ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
- if (IS_ERR(ctx->m2m_ctx)) {
- int ret = PTR_ERR(ctx->m2m_ctx);
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ int ret = PTR_ERR(ctx->fh.m2m_ctx);
kfree(ctx);
return ret;
@@ -916,8 +867,10 @@ static int deinterlace_open(struct file *file)
}
ctx->colorspace = V4L2_COLORSPACE_REC709;
+ v4l2_fh_add(&ctx->fh);
- dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+ dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n",
+ ctx, ctx->fh.m2m_ctx);
return 0;
}
@@ -929,40 +882,22 @@ static int deinterlace_release(struct file *file)
dprintk(pcdev, "Releasing instance %p\n", ctx);
- v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
kfree(ctx->xt);
kfree(ctx);
return 0;
}
-static __poll_t deinterlace_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct deinterlace_ctx *ctx = file->private_data;
- __poll_t ret;
-
- mutex_lock(&ctx->dev->dev_mutex);
- ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
- mutex_unlock(&ctx->dev->dev_mutex);
-
- return ret;
-}
-
-static int deinterlace_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct deinterlace_ctx *ctx = file->private_data;
-
- return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-}
-
static const struct v4l2_file_operations deinterlace_fops = {
.owner = THIS_MODULE,
.open = deinterlace_open,
.release = deinterlace_release,
- .poll = deinterlace_poll,
+ .poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
- .mmap = deinterlace_mmap,
+ .mmap = v4l2_m2m_fop_mmap,
};
static const struct video_device deinterlace_videodev = {
@@ -972,6 +907,7 @@ static const struct video_device deinterlace_videodev = {
.minor = -1,
.release = video_device_release_empty,
.vfl_dir = VFL_DIR_M2M,
+ .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
};
static const struct v4l2_m2m_ops m2m_ops = {
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index dc30c48d4671..803baf97f06e 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -98,56 +98,48 @@ MODULE_PARM_DESC(buffer_mode,
container_of(notifier, struct mcam_camera, notifier)
static struct mcam_format_struct {
- __u8 *desc;
__u32 pixelformat;
int bpp; /* Bytes per pixel */
bool planar;
u32 mbus_code;
} mcam_formats[] = {
{
- .desc = "YUYV 4:2:2",
.pixelformat = V4L2_PIX_FMT_YUYV,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
.planar = false,
},
{
- .desc = "YVYU 4:2:2",
.pixelformat = V4L2_PIX_FMT_YVYU,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
.planar = false,
},
{
- .desc = "YUV 4:2:0 PLANAR",
.pixelformat = V4L2_PIX_FMT_YUV420,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 1,
.planar = true,
},
{
- .desc = "YVU 4:2:0 PLANAR",
.pixelformat = V4L2_PIX_FMT_YVU420,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 1,
.planar = true,
},
{
- .desc = "XRGB 444",
.pixelformat = V4L2_PIX_FMT_XRGB444,
.mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
.bpp = 2,
.planar = false,
},
{
- .desc = "RGB 565",
.pixelformat = V4L2_PIX_FMT_RGB565,
.mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.bpp = 2,
.planar = false,
},
{
- .desc = "Raw RGB Bayer",
.pixelformat = V4L2_PIX_FMT_SBGGR8,
.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
.bpp = 1,
@@ -1357,9 +1349,6 @@ static int mcam_vidioc_querycap(struct file *file, void *priv,
strscpy(cap->driver, "marvell_ccic", sizeof(cap->driver));
strscpy(cap->card, "marvell_ccic", sizeof(cap->card));
strscpy(cap->bus_info, cam->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1369,8 +1358,6 @@ static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp,
{
if (fmt->index >= N_MCAM_FMTS)
return -EINVAL;
- strscpy(fmt->description, mcam_formats[fmt->index].desc,
- sizeof(fmt->description));
fmt->pixelformat = mcam_formats[fmt->index].pixelformat;
return 0;
}
@@ -1698,6 +1685,8 @@ static const struct video_device mcam_v4l_template = {
.fops = &mcam_v4l_fops,
.ioctl_ops = &mcam_v4l_ioctl_ops,
.release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
/* ---------------------------------------------------------------------- */
diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c
index 10559492e09e..92b92255dac6 100644
--- a/drivers/media/platform/marvell-ccic/mmp-driver.c
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
@@ -372,6 +372,7 @@ static const struct of_device_id mmpcam_of_match[] = {
{ .compatible = "marvell,mmp2-ccic", },
{},
};
+MODULE_DEVICE_TABLE(of, mmpcam_of_match);
static struct platform_driver mmpcam_driver = {
.probe = mmpcam_probe,
diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c
index fb52e5dd044a..891533060d49 100644
--- a/drivers/media/platform/meson/ao-cec-g12a.c
+++ b/drivers/media/platform/meson/ao-cec-g12a.c
@@ -121,6 +121,9 @@
#define CECB_CTRL_TYPE_NEXT 2
#define CECB_CTRL2 0x01
+
+#define CECB_CTRL2_RISE_DEL_MAX GENMASK(4, 0)
+
#define CECB_INTR_MASK 0x02
#define CECB_LADD_LOW 0x05
#define CECB_LADD_HIGH 0x06
@@ -165,6 +168,11 @@
#define CECB_WAKEUPCTRL 0x31
+struct meson_ao_cec_g12a_data {
+ /* Setup the internal CECB_CTRL2 register */
+ bool ctrl2_setup;
+};
+
struct meson_ao_cec_g12a_device {
struct platform_device *pdev;
struct regmap *regmap;
@@ -175,6 +183,7 @@ struct meson_ao_cec_g12a_device {
struct cec_msg rx_msg;
struct clk *oscin;
struct clk *core;
+ const struct meson_ao_cec_g12a_data *data;
};
static const struct regmap_config meson_ao_cec_g12a_regmap_conf = {
@@ -605,6 +614,10 @@ static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable)
regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG,
CECB_GEN_CNTL_RESET, 0);
+ if (ao_cec->data->ctrl2_setup)
+ regmap_write(ao_cec->regmap_cec, CECB_CTRL2,
+ FIELD_PREP(CECB_CTRL2_RISE_DEL_MAX, 2));
+
meson_ao_cec_g12a_irq_setup(ao_cec, true);
return 0;
@@ -632,21 +645,22 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev)
if (!ao_cec)
return -ENOMEM;
+ ao_cec->data = of_device_get_match_data(&pdev->dev);
+ if (!ao_cec->data) {
+ dev_err(&pdev->dev, "failed to get match data\n");
+ return -ENODEV;
+ }
+
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_CAP_DEFAULTS |
+ CEC_CAP_CONNECTOR_INFO,
CEC_MAX_LOG_ADDRS);
- if (IS_ERR(ao_cec->adap)) {
- ret = PTR_ERR(ao_cec->adap);
- goto out_probe_notify;
- }
+ if (IS_ERR(ao_cec->adap))
+ return PTR_ERR(ao_cec->adap);
ao_cec->adap->owner = THIS_MODULE;
@@ -702,28 +716,31 @@ static int meson_ao_cec_g12a_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ao_cec);
- ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
- if (ret < 0) {
- cec_notifier_put(ao_cec->notify);
+ ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL,
+ ao_cec->adap);
+ if (!ao_cec->notify) {
+ ret = -ENOMEM;
goto out_probe_core_clk;
}
+ ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
+ if (ret < 0)
+ goto out_probe_notify;
+
/* 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_notify:
+ cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
+
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;
@@ -735,15 +752,30 @@ static int meson_ao_cec_g12a_remove(struct platform_device *pdev)
clk_disable_unprepare(ao_cec->core);
- cec_unregister_adapter(ao_cec->adap);
+ cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
- cec_notifier_put(ao_cec->notify);
+ cec_unregister_adapter(ao_cec->adap);
return 0;
}
+static const struct meson_ao_cec_g12a_data ao_cec_g12a_data = {
+ .ctrl2_setup = false,
+};
+
+static const struct meson_ao_cec_g12a_data ao_cec_sm1_data = {
+ .ctrl2_setup = true,
+};
+
static const struct of_device_id meson_ao_cec_g12a_of_match[] = {
- { .compatible = "amlogic,meson-g12a-ao-cec", },
+ {
+ .compatible = "amlogic,meson-g12a-ao-cec",
+ .data = &ao_cec_g12a_data,
+ },
+ {
+ .compatible = "amlogic,meson-sm1-ao-cec",
+ .data = &ao_cec_sm1_data,
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match);
diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c
index facf9b029e79..09aff82c3773 100644
--- a/drivers/media/platform/meson/ao-cec.c
+++ b/drivers/media/platform/meson/ao-cec.c
@@ -616,21 +616,13 @@ 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);
- if (!ao_cec->notify)
- return -ENOMEM;
-
ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_ops, ao_cec,
"meson_ao_cec",
- CEC_CAP_LOG_ADDRS |
- CEC_CAP_TRANSMIT |
- CEC_CAP_RC |
- CEC_CAP_PASSTHROUGH,
+ CEC_CAP_DEFAULTS |
+ CEC_CAP_CONNECTOR_INFO,
1); /* Use 1 for now */
- if (IS_ERR(ao_cec->adap)) {
- ret = PTR_ERR(ao_cec->adap);
- goto out_probe_notify;
- }
+ if (IS_ERR(ao_cec->adap))
+ return PTR_ERR(ao_cec->adap);
ao_cec->adap->owner = THIS_MODULE;
@@ -675,29 +667,32 @@ static int meson_ao_cec_probe(struct platform_device *pdev)
ao_cec->pdev = pdev;
platform_set_drvdata(pdev, ao_cec);
- ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
- if (ret < 0) {
- cec_notifier_put(ao_cec->notify);
+ ao_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, NULL,
+ ao_cec->adap);
+ if (!ao_cec->notify) {
+ ret = -ENOMEM;
goto out_probe_clk;
}
+ ret = cec_register_adapter(ao_cec->adap, &pdev->dev);
+ if (ret < 0)
+ goto out_probe_notify;
+
/* Setup Hardware */
writel_relaxed(CEC_GEN_CNTL_RESET,
ao_cec->base + CEC_GEN_CNTL_REG);
- cec_register_cec_notifier(ao_cec->adap, ao_cec->notify);
-
return 0;
+out_probe_notify:
+ cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
+
out_probe_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;
@@ -709,10 +704,9 @@ static int meson_ao_cec_remove(struct platform_device *pdev)
clk_disable_unprepare(ao_cec->core);
+ cec_notifier_cec_adap_unregister(ao_cec->notify, ao_cec->adap);
cec_unregister_adapter(ao_cec->adap);
- cec_notifier_put(ao_cec->notify);
-
return 0;
}
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
index fc9faec85edb..aeaed2cf4458 100644
--- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
@@ -110,7 +110,9 @@ static int mtk_mdp_probe(struct platform_device *pdev)
mutex_init(&mdp->vpulock);
/* Old dts had the components as child nodes */
- if (of_get_next_child(dev->of_node, NULL)) {
+ node = of_get_next_child(dev->of_node, NULL);
+ if (node) {
+ of_node_put(node);
parent = dev->of_node;
dev_warn(dev, "device tree is out of date\n");
} else {
@@ -145,13 +147,16 @@ static int mtk_mdp_probe(struct platform_device *pdev)
comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
if (!comp) {
ret = -ENOMEM;
+ of_node_put(node);
goto err_comp;
}
mdp->comp[comp_id] = comp;
ret = mtk_mdp_comp_init(dev, node, comp, comp_id);
- if (ret)
+ if (ret) {
+ of_node_put(node);
goto err_comp;
+ }
}
mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME);
@@ -224,6 +229,9 @@ static int mtk_mdp_remove(struct platform_device *pdev)
mtk_mdp_unregister_m2m_device(mdp);
v4l2_device_unregister(&mdp->v4l2_dev);
+ flush_workqueue(mdp->wdt_wq);
+ destroy_workqueue(mdp->wdt_wq);
+
flush_workqueue(mdp->job_wq);
destroy_workqueue(mdp->job_wq);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
index 90d1a67db7e5..0f3e710aed4e 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
@@ -29,16 +29,19 @@ static const struct mtk_video_fmt mtk_video_formats[] = {
.fourcc = V4L2_PIX_FMT_H264,
.type = MTK_FMT_DEC,
.num_planes = 1,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
},
{
.fourcc = V4L2_PIX_FMT_VP8,
.type = MTK_FMT_DEC,
.num_planes = 1,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
},
{
.fourcc = V4L2_PIX_FMT_VP9,
.type = MTK_FMT_DEC,
.num_planes = 1,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
},
{
.fourcc = V4L2_PIX_FMT_MT21C,
@@ -101,6 +104,7 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx)
{
struct vdec_fb *disp_frame_buffer = NULL;
struct mtk_video_dec_buf *dstbuf;
+ struct vb2_v4l2_buffer *vb;
mtk_v4l2_debug(3, "[%d]", ctx->id);
if (vdec_if_get_param(ctx,
@@ -118,25 +122,26 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx)
dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf,
frame_buffer);
+ vb = &dstbuf->m2m_buf.vb;
mutex_lock(&ctx->lock);
if (dstbuf->used) {
- vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0,
- ctx->picinfo.fb_sz[0]);
+ vb2_set_plane_payload(&vb->vb2_buf, 0,
+ ctx->picinfo.fb_sz[0]);
if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
- vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1,
+ vb2_set_plane_payload(&vb->vb2_buf, 1,
ctx->picinfo.fb_sz[1]);
mtk_v4l2_debug(2,
"[%d]status=%x queue id=%d to done_list %d",
ctx->id, disp_frame_buffer->status,
- dstbuf->vb.vb2_buf.index,
+ vb->vb2_buf.index,
dstbuf->queued_in_vb2);
- v4l2_m2m_buf_done(&dstbuf->vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(vb, VB2_BUF_STATE_DONE);
ctx->decoded_frame_cnt++;
}
mutex_unlock(&ctx->lock);
- return &dstbuf->vb.vb2_buf;
+ return &vb->vb2_buf;
}
/*
@@ -151,6 +156,7 @@ static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
{
struct mtk_video_dec_buf *dstbuf;
struct vdec_fb *free_frame_buffer = NULL;
+ struct vb2_v4l2_buffer *vb;
if (vdec_if_get_param(ctx,
GET_PARAM_FREE_FRAME_BUFFER,
@@ -168,6 +174,7 @@ static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf,
frame_buffer);
+ vb = &dstbuf->m2m_buf.vb;
mutex_lock(&ctx->lock);
if (dstbuf->used) {
@@ -184,9 +191,9 @@ static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
mtk_v4l2_debug(2,
"[%d]status=%x queue id=%d to rdy_queue %d",
ctx->id, free_frame_buffer->status,
- dstbuf->vb.vb2_buf.index,
+ vb->vb2_buf.index,
dstbuf->queued_in_vb2);
- v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb);
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
} else if ((dstbuf->queued_in_vb2 == false) &&
(dstbuf->queued_in_v4l2 == true)) {
/*
@@ -202,8 +209,8 @@ static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
mtk_v4l2_debug(2,
"[%d]status=%x queue id=%d to rdy_queue",
ctx->id, free_frame_buffer->status,
- dstbuf->vb.vb2_buf.index);
- v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb);
+ vb->vb2_buf.index);
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
dstbuf->queued_in_vb2 = true;
} else {
/*
@@ -216,14 +223,14 @@ static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
*/
mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d",
ctx->id, free_frame_buffer->status,
- dstbuf->vb.vb2_buf.index,
+ vb->vb2_buf.index,
dstbuf->queued_in_vb2,
dstbuf->queued_in_v4l2);
}
dstbuf->used = false;
}
mutex_unlock(&ctx->lock);
- return &dstbuf->vb.vb2_buf;
+ return &vb->vb2_buf;
}
static void clean_display_buffer(struct mtk_vcodec_ctx *ctx)
@@ -281,7 +288,7 @@ static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx,
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->fourcc, pixelformat);
dst_q_data->fmt = fmt;
return;
}
@@ -362,8 +369,10 @@ static void mtk_vdec_worker(struct work_struct *work)
return;
}
- src_buf_info = container_of(src_buf, struct mtk_video_dec_buf, vb);
- dst_buf_info = container_of(dst_buf, struct mtk_video_dec_buf, vb);
+ src_buf_info = container_of(src_buf, struct mtk_video_dec_buf,
+ m2m_buf.vb);
+ dst_buf_info = container_of(dst_buf, struct mtk_video_dec_buf,
+ m2m_buf.vb);
pfb = &dst_buf_info->frame_buffer;
pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0);
@@ -394,11 +403,11 @@ static void mtk_vdec_worker(struct work_struct *work)
vdec_if_decode(ctx, NULL, NULL, &res_chg);
clean_display_buffer(ctx);
- vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0);
if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
- vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0);
dst_buf->flags |= V4L2_BUF_FLAG_LAST;
- v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
clean_free_buffer(ctx);
v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx);
return;
@@ -414,10 +423,8 @@ static void mtk_vdec_worker(struct work_struct *work)
}
mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p",
ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf);
- dst_buf_info->vb.vb2_buf.timestamp
- = src_buf_info->vb.vb2_buf.timestamp;
- dst_buf_info->vb.timecode
- = src_buf_info->vb.timecode;
+ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
+ dst_buf->timecode = src_buf->timecode;
mutex_lock(&ctx->lock);
dst_buf_info->used = true;
mutex_unlock(&ctx->lock);
@@ -431,7 +438,7 @@ static void mtk_vdec_worker(struct work_struct *work)
ctx->id,
src_buf->vb2_buf.index,
buf.size,
- src_buf_info->vb.vb2_buf.timestamp,
+ src_buf->vb2_buf.timestamp,
dst_buf->vb2_buf.index,
ret, res_chg);
src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
@@ -440,14 +447,14 @@ static void mtk_vdec_worker(struct work_struct *work)
src_buf_info->error = true;
mutex_unlock(&ctx->lock);
}
- v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
} else if (res_chg == false) {
/*
* we only return src buffer with VB2_BUF_STATE_DONE
* when decode success without resolution change
*/
src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
- v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
}
dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
@@ -519,7 +526,8 @@ static int vidioc_decoder_cmd(struct file *file, void *priv,
mtk_v4l2_debug(1, "Capture stream is off. No need to flush.");
return 0;
}
- v4l2_m2m_buf_queue(ctx->m2m_ctx, &ctx->empty_flush_buf->vb);
+ v4l2_m2m_buf_queue(ctx->m2m_ctx,
+ &ctx->empty_flush_buf->m2m_buf.vb);
v4l2_m2m_try_schedule(ctx->m2m_ctx);
break;
@@ -838,12 +846,20 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv,
return -EINVAL;
pix_mp = &f->fmt.pix_mp;
+ /*
+ * Setting OUTPUT format after OUTPUT buffers are allocated is invalid
+ * if using the stateful API.
+ */
if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) {
mtk_v4l2_err("out_q_ctx buffers already requested");
ret = -EBUSY;
}
+ /*
+ * Setting CAPTURE format after CAPTURE buffers are allocated is
+ * invalid.
+ */
if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) &&
vb2_is_busy(&ctx->m2m_ctx->cap_q_ctx.q)) {
mtk_v4l2_err("cap_q_ctx buffers already requested");
@@ -862,6 +878,8 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv,
fmt = mtk_vdec_find_format(f);
}
}
+ if (fmt == NULL)
+ return -EINVAL;
q_data->fmt = fmt;
vidioc_try_fmt(f, q_data->fmt);
@@ -870,10 +888,10 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv,
q_data->coded_width = pix_mp->width;
q_data->coded_height = pix_mp->height;
- ctx->colorspace = f->fmt.pix_mp.colorspace;
- ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
- ctx->quantization = f->fmt.pix_mp.quantization;
- ctx->xfer_func = f->fmt.pix_mp.xfer_func;
+ ctx->colorspace = pix_mp->colorspace;
+ ctx->ycbcr_enc = pix_mp->ycbcr_enc;
+ ctx->quantization = pix_mp->quantization;
+ ctx->xfer_func = pix_mp->xfer_func;
if (ctx->state == MTK_STATE_FREE) {
ret = vdec_if_init(ctx, q_data->fmt->fourcc);
@@ -948,6 +966,7 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue)
fmt = &mtk_video_formats[i];
f->pixelformat = fmt->fourcc;
+ f->flags = fmt->flags;
return 0;
}
@@ -1134,7 +1153,8 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
*/
if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
vb2_v4l2 = to_vb2_v4l2_buffer(vb);
- buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
+ buf = container_of(vb2_v4l2, struct mtk_video_dec_buf,
+ m2m_buf.vb);
mutex_lock(&ctx->lock);
if (buf->used == false) {
v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
@@ -1161,7 +1181,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
mtk_v4l2_err("No src buffer");
return;
}
- buf = container_of(src_buf, struct mtk_video_dec_buf, vb);
+ buf = container_of(src_buf, struct mtk_video_dec_buf, m2m_buf.vb);
if (buf->lastframe) {
/* This shouldn't happen. Just in case. */
mtk_v4l2_err("Invalid flush buffer.");
@@ -1242,7 +1262,7 @@ static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb)
bool buf_error;
vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
- buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb);
+ buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, m2m_buf.vb);
mutex_lock(&ctx->lock);
if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
buf->queued_in_v4l2 = false;
@@ -1262,7 +1282,7 @@ static int vb2ops_vdec_buf_init(struct vb2_buffer *vb)
struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb,
struct vb2_v4l2_buffer, vb2_buf);
struct mtk_video_dec_buf *buf = container_of(vb2_v4l2,
- struct mtk_video_dec_buf, vb);
+ struct mtk_video_dec_buf, m2m_buf.vb);
if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
buf->used = false;
@@ -1295,7 +1315,7 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q)
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) {
struct mtk_video_dec_buf *buf_info = container_of(
- src_buf, struct mtk_video_dec_buf, vb);
+ src_buf, struct mtk_video_dec_buf, m2m_buf.vb);
if (!buf_info->lastframe)
v4l2_m2m_buf_done(src_buf,
VB2_BUF_STATE_ERROR);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
index e0c5338bde3d..cf26b6c1486a 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
@@ -9,7 +9,7 @@
#define _MTK_VCODEC_DEC_H_
#include <media/videobuf2-core.h>
-#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-mem2mem.h>
#define VCODEC_CAPABILITY_4K_DISABLED 0x10
#define VCODEC_DEC_4K_CODED_WIDTH 4096U
@@ -33,7 +33,7 @@ struct vdec_fb {
/**
* struct mtk_video_dec_buf - Private data related to each VB2 buffer.
- * @b: VB2 buffer
+ * @m2m_buf: M2M buffer
* @list: link list
* @used: Capture buffer contain decoded frame data and keep in
* codec data structure
@@ -47,8 +47,7 @@ struct vdec_fb {
* Note : These status information help us track and debug buffer state
*/
struct mtk_video_dec_buf {
- struct vb2_v4l2_buffer vb;
- struct list_head list;
+ struct v4l2_m2m_buffer m2m_buf;
bool used;
bool queued_in_vb2;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index 00d090df11bb..100ae8c5e702 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -137,7 +137,7 @@ static int fops_vcodec_open(struct file *file)
}
src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
- ctx->empty_flush_buf->vb.vb2_buf.vb2_queue = src_vq;
+ ctx->empty_flush_buf->m2m_buf.vb.vb2_buf.vb2_queue = src_vq;
ctx->empty_flush_buf->lastframe = true;
mtk_vcodec_dec_set_default_params(ctx);
@@ -253,13 +253,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
}
for (i = 0; i < NUM_MAX_VDEC_REG_BASE; i++) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- if (res == NULL) {
- dev_err(&pdev->dev, "get memory resource failed.");
- ret = -ENXIO;
- goto err_res;
- }
- dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res);
+ dev->reg_base[i] = devm_platform_ioremap_resource(pdev, i);
if (IS_ERR((__force void *)dev->reg_base[i])) {
ret = PTR_ERR((__force void *)dev->reg_base[i]);
goto err_res;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index c95de5d08dda..9fd56dee7fd1 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -99,6 +99,7 @@ struct mtk_video_fmt {
u32 fourcc;
enum mtk_fmt_type type;
u32 num_planes;
+ u32 flags;
};
/**
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
index fd8de027e83e..d469ff6464b2 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -332,14 +332,12 @@ static int vidioc_try_fmt(struct v4l2_format *f,
pix_fmt_mp->num_planes = fmt->num_planes;
pix_fmt_mp->plane_fmt[0].sizeimage =
- pix_fmt_mp->width * pix_fmt_mp->height +
- ((ALIGN(pix_fmt_mp->width, 16) * 2) * 16);
+ pix_fmt_mp->width * pix_fmt_mp->height;
pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width;
if (pix_fmt_mp->num_planes == 2) {
pix_fmt_mp->plane_fmt[1].sizeimage =
- (pix_fmt_mp->width * pix_fmt_mp->height) / 2 +
- (ALIGN(pix_fmt_mp->width, 16) * 16);
+ (pix_fmt_mp->width * pix_fmt_mp->height) / 2;
pix_fmt_mp->plane_fmt[2].sizeimage = 0;
pix_fmt_mp->plane_fmt[1].bytesperline =
pix_fmt_mp->width;
@@ -347,8 +345,7 @@ static int vidioc_try_fmt(struct v4l2_format *f,
} else if (pix_fmt_mp->num_planes == 3) {
pix_fmt_mp->plane_fmt[1].sizeimage =
pix_fmt_mp->plane_fmt[2].sizeimage =
- (pix_fmt_mp->width * pix_fmt_mp->height) / 4 +
- ((ALIGN(pix_fmt_mp->width, 16) / 2) * 16);
+ (pix_fmt_mp->width * pix_fmt_mp->height) / 4;
pix_fmt_mp->plane_fmt[1].bytesperline =
pix_fmt_mp->plane_fmt[2].bytesperline =
pix_fmt_mp->width / 2;
@@ -798,13 +795,14 @@ static void vb2ops_venc_buf_queue(struct vb2_buffer *vb)
container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
struct mtk_video_enc_buf *mtk_buf =
- container_of(vb2_v4l2, struct mtk_video_enc_buf, vb);
+ container_of(vb2_v4l2, struct mtk_video_enc_buf,
+ m2m_buf.vb);
if ((vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) &&
(ctx->param_change != MTK_ENCODE_PARAM_NONE)) {
mtk_v4l2_debug(1, "[%d] Before id=%d encode parameter change %x",
ctx->id,
- mtk_buf->vb.vb2_buf.index,
+ vb2_v4l2->vb2_buf.index,
ctx->param_change);
mtk_buf->param_change = ctx->param_change;
mtk_buf->enc_params = ctx->enc_params;
@@ -986,7 +984,8 @@ static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx)
struct venc_enc_param enc_prm;
struct vb2_v4l2_buffer *vb2_v4l2 = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
struct mtk_video_enc_buf *mtk_buf =
- container_of(vb2_v4l2, struct mtk_video_enc_buf, vb);
+ container_of(vb2_v4l2, struct mtk_video_enc_buf,
+ m2m_buf.vb);
int ret = 0;
@@ -998,7 +997,7 @@ static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx)
enc_prm.bitrate = mtk_buf->enc_params.bitrate;
mtk_v4l2_debug(1, "[%d] id=%d, change param br=%d",
ctx->id,
- mtk_buf->vb.vb2_buf.index,
+ vb2_v4l2->vb2_buf.index,
enc_prm.bitrate);
ret |= venc_if_set_param(ctx,
VENC_SET_PARAM_ADJUST_BITRATE,
@@ -1009,7 +1008,7 @@ static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx)
mtk_buf->enc_params.framerate_denom;
mtk_v4l2_debug(1, "[%d] id=%d, change param fr=%d",
ctx->id,
- mtk_buf->vb.vb2_buf.index,
+ vb2_v4l2->vb2_buf.index,
enc_prm.frm_rate);
ret |= venc_if_set_param(ctx,
VENC_SET_PARAM_ADJUST_FRAMERATE,
@@ -1026,7 +1025,7 @@ static int mtk_venc_param_change(struct mtk_vcodec_ctx *ctx)
if (!ret && mtk_buf->param_change & MTK_ENCODE_PARAM_FORCE_INTRA) {
mtk_v4l2_debug(1, "[%d] id=%d, change param force I=%d",
ctx->id,
- mtk_buf->vb.vb2_buf.index,
+ vb2_v4l2->vb2_buf.index,
mtk_buf->enc_params.force_intra);
if (mtk_buf->enc_params.force_intra)
ret |= venc_if_set_param(ctx,
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
index a9c9f86b9c83..513ee7993e34 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h
@@ -9,7 +9,7 @@
#define _MTK_VCODEC_ENC_H_
#include <media/videobuf2-core.h>
-#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-mem2mem.h>
#define MTK_VENC_IRQ_STATUS_SPS 0x1
#define MTK_VENC_IRQ_STATUS_PPS 0x2
@@ -23,15 +23,15 @@
/**
* struct mtk_video_enc_buf - Private data related to each VB2 buffer.
- * @vb: Pointer to related VB2 buffer.
+ * @m2m_buf: M2M buffer
* @list: list that buffer link to
* @param_change: Types of encode parameter change before encoding this
* buffer
* @enc_params: Encode parameters changed before encode this buffer
*/
struct mtk_video_enc_buf {
- struct vb2_v4l2_buffer vb;
- struct list_head list;
+ struct v4l2_m2m_buffer m2m_buf;
+
u32 param_change;
struct mtk_enc_params enc_params;
};
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 c5f8f1fca44c..50048c170b99 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
@@ -29,6 +29,9 @@
#define H264_MAX_FB_NUM 17
#define HDR_PARSING_BUF_SZ 1024
+#define DEC_ERR_RET(ret) ((ret) >> 16)
+#define H264_ERR_NOT_VALID 3
+
/**
* struct h264_fb - h264 decode frame buffer information
* @vdec_fb_va : virtual address of struct vdec_fb
@@ -280,7 +283,6 @@ static int vdec_h264_init(struct mtk_vcodec_ctx *ctx)
inst->vpu.id = IPI_VDEC_H264;
inst->vpu.dev = ctx->dev->vpu_plat_dev;
inst->vpu.ctx = ctx;
- inst->vpu.handler = vpu_dec_ipi_handler;
err = vpu_dec_init(&inst->vpu);
if (err) {
@@ -357,8 +359,11 @@ static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
buf = (unsigned char *)bs->va;
buf_sz = bs->size;
nal_start_idx = find_start_code(buf, buf_sz);
- if (nal_start_idx < 0)
+ if (nal_start_idx < 0) {
+ mtk_vcodec_err(inst, "invalid nal start code");
+ err = -EIO;
goto err_free_fb_out;
+ }
nal_start = buf[nal_start_idx];
nal_type = NAL_TYPE(buf[nal_start_idx]);
@@ -382,8 +387,14 @@ static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
data[0] = buf_sz;
data[1] = nal_start;
err = vpu_dec_start(vpu, data, 2);
- if (err)
+ if (err) {
+ if (err > 0 && (DEC_ERR_RET(err) == H264_ERR_NOT_VALID)) {
+ mtk_vcodec_err(inst, "- error bitstream - err = %d -",
+ err);
+ err = -EIO;
+ }
goto err_free_fb_out;
+ }
*res_chg = inst->vsi->dec.resolution_changed;
if (*res_chg) {
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 63a8708ce682..6011fdd60a22 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
@@ -402,7 +402,6 @@ static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx)
inst->vpu.id = IPI_VDEC_VP8;
inst->vpu.dev = ctx->dev->vpu_plat_dev;
inst->vpu.ctx = ctx;
- inst->vpu.handler = vpu_dec_ipi_handler;
err = vpu_dec_init(&inst->vpu);
if (err) {
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 5066c283d86d..24c1f0bf2147 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
@@ -793,7 +793,6 @@ static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx)
inst->vpu.id = IPI_VDEC_VP9;
inst->vpu.dev = ctx->dev->vpu_plat_dev;
inst->vpu.ctx = ctx;
- inst->vpu.handler = vpu_dec_ipi_handler;
if (vpu_dec_init(&inst->vpu)) {
mtk_vcodec_err(inst, "vp9_dec_vpu_init failed");
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
index 3f38cc4509ef..70abfd4cd4b9 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
@@ -25,10 +25,16 @@ static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg)
}
/*
+ * vpu_dec_ipi_handler - Handler for VPU ipi message.
+ *
+ * @data: ipi message
+ * @len : length of ipi message
+ * @priv: callback private data which is passed by decoder when register.
+ *
* This function runs in interrupt context and it means there's an IPI MSG
* from VPU.
*/
-void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
+static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
{
struct vdec_vpu_ipi_ack *msg = data;
struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
@@ -102,6 +108,7 @@ int vpu_dec_init(struct vdec_vpu_inst *vpu)
mtk_vcodec_debug_enter(vpu);
init_waitqueue_head(&vpu->wq);
+ vpu->handler = vpu_dec_ipi_handler;
err = vpu_ipi_register(vpu->dev, vpu->id, vpu->handler, "vdec", NULL);
if (err != 0) {
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
index b76f717e4fd7..f779b0676fbd 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
@@ -76,13 +76,4 @@ int vpu_dec_deinit(struct vdec_vpu_inst *vpu);
*/
int vpu_dec_reset(struct vdec_vpu_inst *vpu);
-/**
- * vpu_dec_ipi_handler - Handler for VPU ipi message.
- *
- * @data: ipi message
- * @len : length of ipi message
- * @priv: callback private data which is passed by decoder when register.
- */
-void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv);
-
#endif
diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c
index cc2ff40d060d..a768707abb94 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.c
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c
@@ -273,7 +273,7 @@ int vpu_ipi_register(struct platform_device *pdev,
return -EPROBE_DEFER;
}
- if (id >= 0 && id < IPI_MAX && handler) {
+ if (id < IPI_MAX && handler) {
ipi_desc = vpu->ipi_desc;
ipi_desc[id].name = name;
ipi_desc[id].handler = handler;
@@ -398,7 +398,7 @@ int vpu_wdt_reg_handler(struct platform_device *pdev,
handler = vpu->wdt.handler;
- if (id >= 0 && id < VPU_RST_MAX && wdt_reset) {
+ if (id < VPU_RST_MAX && wdt_reset) {
dev_dbg(vpu->dev, "wdt register id %d\n", id);
mutex_lock(&vpu->vpu_mutex);
handler[id].reset_func = wdt_reset;
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index 333324c75027..27779b75df54 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -120,7 +120,7 @@ module_param(debug, bool, 0644);
#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27)
#define PRP_CNTL_CH2B1EN (1 << 29)
#define PRP_CNTL_CH2B2EN (1 << 30)
-#define PRP_CNTL_CH2FEN (1 << 31)
+#define PRP_CNTL_CH2FEN (1UL << 31)
#define PRP_SIZE_HEIGHT(x) (x)
#define PRP_SIZE_WIDTH(x) ((x) << 16)
@@ -145,7 +145,6 @@ module_param(debug, bool, 0644);
#define PRP_INTR_ST_CH2OVF (1 << 8)
struct emmaprp_fmt {
- char *name;
u32 fourcc;
/* Types the format can be used for */
u32 types;
@@ -153,12 +152,10 @@ struct emmaprp_fmt {
static struct emmaprp_fmt formats[] = {
{
- .name = "YUV 4:2:0 Planar",
.fourcc = V4L2_PIX_FMT_YUV420,
.types = MEM2MEM_CAPTURE,
},
{
- .name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
.types = MEM2MEM_OUTPUT,
},
@@ -210,11 +207,11 @@ struct emmaprp_dev {
};
struct emmaprp_ctx {
+ struct v4l2_fh fh;
struct emmaprp_dev *dev;
/* Abort requested by m2m */
int aborting;
struct emmaprp_q_data q_data[2];
- struct v4l2_m2m_ctx *m2m_ctx;
};
static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx,
@@ -243,7 +240,7 @@ static void emmaprp_job_abort(void *priv)
dprintk(pcdev, "Aborting task\n");
- v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
+ v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->fh.m2m_ctx);
}
static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev)
@@ -278,8 +275,8 @@ static void emmaprp_device_run(void *priv)
dma_addr_t p_in, p_out;
u32 tmp;
- src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
s_width = s_q_data->width;
@@ -353,8 +350,8 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data)
pr_err("PrP bus error occurred, this transfer is probably corrupted\n");
writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
} else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */
- src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
- dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+ src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
+ dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
dst_vb->flags &=
@@ -371,7 +368,7 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data)
}
}
- v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
+ v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->fh.m2m_ctx);
return IRQ_HANDLED;
}
@@ -383,8 +380,6 @@ static int vidioc_querycap(struct file *file, void *priv,
{
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;
}
@@ -409,7 +404,6 @@ static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
if (i < NUM_FORMATS) {
/* Format found */
fmt = &formats[i];
- strscpy(f->description, fmt->name, sizeof(f->description) - 1);
f->pixelformat = fmt->fourcc;
return 0;
}
@@ -435,7 +429,7 @@ static int vidioc_g_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
struct vb2_queue *vq;
struct emmaprp_q_data *q_data;
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
@@ -540,7 +534,7 @@ static int vidioc_s_fmt(struct emmaprp_ctx *ctx, struct v4l2_format *f)
struct vb2_queue *vq;
int ret;
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
@@ -596,52 +590,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
return vidioc_s_fmt(priv, f);
}
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct emmaprp_ctx *ctx = priv;
-
- return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct emmaprp_ctx *ctx = priv;
-
- return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct emmaprp_ctx *ctx = priv;
-
- return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct emmaprp_ctx *ctx = priv;
-
- return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct emmaprp_ctx *ctx = priv;
-
- return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct emmaprp_ctx *ctx = priv;
-
- return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
@@ -655,14 +603,14 @@ static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
.vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
-
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
};
@@ -722,7 +670,7 @@ static void emmaprp_buf_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf);
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
}
static const struct vb2_ops emmaprp_qops = {
@@ -740,7 +688,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &emmaprp_qops;
@@ -754,7 +702,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
return ret;
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &emmaprp_qops;
@@ -778,7 +726,8 @@ static int emmaprp_open(struct file *file)
if (!ctx)
return -ENOMEM;
- file->private_data = ctx;
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
ctx->dev = pcdev;
if (mutex_lock_interruptible(&pcdev->dev_mutex)) {
@@ -786,10 +735,10 @@ static int emmaprp_open(struct file *file)
return -ERESTARTSYS;
}
- ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
- if (IS_ERR(ctx->m2m_ctx)) {
- int ret = PTR_ERR(ctx->m2m_ctx);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ int ret = PTR_ERR(ctx->fh.m2m_ctx);
mutex_unlock(&pcdev->dev_mutex);
kfree(ctx);
@@ -800,9 +749,10 @@ static int emmaprp_open(struct file *file)
clk_prepare_enable(pcdev->clk_emma_ahb);
ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
+ v4l2_fh_add(&ctx->fh);
mutex_unlock(&pcdev->dev_mutex);
- dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+ dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx);
return 0;
}
@@ -817,46 +767,22 @@ static int emmaprp_release(struct file *file)
mutex_lock(&pcdev->dev_mutex);
clk_disable_unprepare(pcdev->clk_emma_ahb);
clk_disable_unprepare(pcdev->clk_emma_ipg);
- v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
mutex_unlock(&pcdev->dev_mutex);
kfree(ctx);
return 0;
}
-static __poll_t emmaprp_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct emmaprp_dev *pcdev = video_drvdata(file);
- struct emmaprp_ctx *ctx = file->private_data;
- __poll_t res;
-
- mutex_lock(&pcdev->dev_mutex);
- res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
- mutex_unlock(&pcdev->dev_mutex);
- return res;
-}
-
-static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct emmaprp_dev *pcdev = video_drvdata(file);
- struct emmaprp_ctx *ctx = file->private_data;
- int ret;
-
- if (mutex_lock_interruptible(&pcdev->dev_mutex))
- return -ERESTARTSYS;
- ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
- mutex_unlock(&pcdev->dev_mutex);
- return ret;
-}
-
static const struct v4l2_file_operations emmaprp_fops = {
.owner = THIS_MODULE,
.open = emmaprp_open,
.release = emmaprp_release,
- .poll = emmaprp_poll,
+ .poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
- .mmap = emmaprp_mmap,
+ .mmap = v4l2_m2m_fop_mmap,
};
static const struct video_device emmaprp_videodev = {
@@ -866,6 +792,7 @@ static const struct video_device emmaprp_videodev = {
.minor = -1,
.release = video_device_release,
.vfl_dir = VFL_DIR_M2M,
+ .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
};
static const struct v4l2_m2m_ops m2m_ops = {
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index 1a99dff21ca0..f73b5893220d 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -10,8 +10,7 @@ config VIDEO_OMAP2_VOUT
depends on FB_OMAP2 || (COMPILE_TEST && FB_OMAP2=n)
depends on ARCH_OMAP2 || ARCH_OMAP3 || COMPILE_TEST
depends on VIDEO_V4L2
- select VIDEOBUF_GEN
- select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF2_DMA_CONTIG
select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3
select FRAME_VECTOR
help
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index cb6a9e3946b6..513b99bf963b 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -40,9 +40,9 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
-#include <media/videobuf-dma-contig.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
#include <video/omapvrfb.h>
#include <video/omapfb_dss.h>
@@ -63,33 +63,12 @@ enum omap_vout_channels {
OMAP_VIDEO2,
};
-static struct videobuf_queue_ops video_vbq_ops;
/* Variables configurable through module params*/
-static u32 video1_numbuffers = 3;
-static u32 video2_numbuffers = 3;
-static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
-static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
static bool vid1_static_vrfb_alloc;
static bool vid2_static_vrfb_alloc;
static bool debug;
/* Module parameters */
-module_param(video1_numbuffers, uint, S_IRUGO);
-MODULE_PARM_DESC(video1_numbuffers,
- "Number of buffers to be allocated at init time for Video1 device.");
-
-module_param(video2_numbuffers, uint, S_IRUGO);
-MODULE_PARM_DESC(video2_numbuffers,
- "Number of buffers to be allocated at init time for Video2 device.");
-
-module_param(video1_bufsize, uint, S_IRUGO);
-MODULE_PARM_DESC(video1_bufsize,
- "Size of the buffer to be allocated for video1 device");
-
-module_param(video2_bufsize, uint, S_IRUGO);
-MODULE_PARM_DESC(video2_bufsize,
- "Size of the buffer to be allocated for video2 device");
-
module_param(vid1_static_vrfb_alloc, bool, S_IRUGO);
MODULE_PARM_DESC(vid1_static_vrfb_alloc,
"Static allocation of the VRFB buffer for video1 device");
@@ -114,14 +93,12 @@ static const struct v4l2_fmtdesc omap_formats[] = {
* Byte 0 Byte 1
* g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
*/
- .description = "RGB565, le",
.pixelformat = V4L2_PIX_FMT_RGB565,
},
{
/* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use
* this for RGB24 unpack mode, the last 8 bits are ignored
* */
- .description = "RGB32, le",
.pixelformat = V4L2_PIX_FMT_RGB32,
},
{
@@ -129,15 +106,12 @@ static const struct v4l2_fmtdesc omap_formats[] = {
* this for RGB24 packed mode
*
*/
- .description = "RGB24, le",
.pixelformat = V4L2_PIX_FMT_RGB24,
},
{
- .description = "YUYV (YUV 4:2:2), packed",
.pixelformat = V4L2_PIX_FMT_YUYV,
},
{
- .description = "UYVY, packed",
.pixelformat = V4L2_PIX_FMT_UYVY,
},
};
@@ -164,13 +138,13 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix)
ifmt = 0;
pix->pixelformat = omap_formats[ifmt].pixelformat;
- pix->field = V4L2_FIELD_ANY;
+ pix->field = V4L2_FIELD_NONE;
switch (pix->pixelformat) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
default:
- pix->colorspace = V4L2_COLORSPACE_JPEG;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
bpp = YUYV_BPP;
break;
case V4L2_PIX_FMT_RGB565:
@@ -195,56 +169,6 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix)
}
/*
- * omap_vout_get_userptr: Convert user space virtual address to physical
- * address.
- */
-static int omap_vout_get_userptr(struct videobuf_buffer *vb, long virtp,
- u32 *physp)
-{
- struct frame_vector *vec;
- int ret;
-
- /* For kernel direct-mapped memory, take the easy way */
- if (virtp >= PAGE_OFFSET) {
- *physp = virt_to_phys((void *)virtp);
- return 0;
- }
-
- vec = frame_vector_create(1);
- if (!vec)
- return -ENOMEM;
-
- ret = get_vaddr_frames(virtp, 1, FOLL_WRITE, vec);
- if (ret != 1) {
- frame_vector_destroy(vec);
- return -EINVAL;
- }
- *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]);
- vb->priv = vec;
-
- return 0;
-}
-
-/*
- * Free the V4L2 buffers
- */
-void omap_vout_free_buffers(struct omap_vout_device *vout)
-{
- int i, numbuffers;
-
- /* Allocate memory for the buffers */
- numbuffers = (vout->vid) ? video2_numbuffers : video1_numbuffers;
- vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize;
-
- for (i = 0; i < numbuffers; i++) {
- omap_vout_free_buffer(vout->buf_virt_addr[i],
- vout->buffer_size);
- vout->buf_phy_addr[i] = 0;
- vout->buf_virt_addr[i] = 0;
- }
-}
-
-/*
* Convert V4L2 rotation to DSS rotation
* V4L2 understand 0, 90, 180, 270.
* Convert to 0, 1, 2 and 3 respectively for DSS
@@ -537,9 +461,9 @@ static int omapvid_handle_interlace_display(struct omap_vout_device *vout,
if (vout->cur_frm == vout->next_frm)
goto err;
- vout->cur_frm->ts = ts;
- vout->cur_frm->state = VIDEOBUF_DONE;
- wake_up_interruptible(&vout->cur_frm->done);
+ vout->cur_frm->vbuf.vb2_buf.timestamp = ts;
+ vout->cur_frm->vbuf.sequence = vout->sequence++;
+ vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE);
vout->cur_frm = vout->next_frm;
} else {
if (list_empty(&vout->dma_queue) ||
@@ -562,9 +486,6 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
struct omap_dss_device *cur_display;
struct omap_vout_device *vout = (struct omap_vout_device *)arg;
- if (!vout->streaming)
- return;
-
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
@@ -608,9 +529,9 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
}
if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
- vout->cur_frm->ts = ts;
- vout->cur_frm->state = VIDEOBUF_DONE;
- wake_up_interruptible(&vout->cur_frm->done);
+ vout->cur_frm->vbuf.vb2_buf.timestamp = ts;
+ vout->cur_frm->vbuf.sequence = vout->sequence++;
+ vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE);
vout->cur_frm = vout->next_frm;
}
@@ -619,12 +540,10 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus)
goto vout_isr_err;
vout->next_frm = list_entry(vout->dma_queue.next,
- struct videobuf_buffer, queue);
+ struct omap_vout_buffer, queue);
list_del(&vout->next_frm->queue);
- vout->next_frm->state = VIDEOBUF_ACTIVE;
-
- addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
+ addr = (unsigned long)vout->queued_buf_addr[vout->next_frm->vbuf.vb2_buf.index]
+ vout->cropped_offset;
/* First save the configuration in ovelray structure */
@@ -644,394 +563,6 @@ vout_isr_err:
spin_unlock(&vout->vbq_lock);
}
-/* Video buffer call backs */
-
-/*
- * Buffer setup function is called by videobuf layer when REQBUF ioctl is
- * called. This is used to setup buffers and return size and count of
- * buffers allocated. After the call to this buffer, videobuf layer will
- * setup buffer queue depending on the size and count of buffers
- */
-static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
- unsigned int *size)
-{
- int startindex = 0, i, j;
- u32 phy_addr = 0, virt_addr = 0;
- struct omap_vout_device *vout = q->priv_data;
- struct omapvideo_info *ovid = &vout->vid_info;
- int vid_max_buf_size;
-
- if (!vout)
- return -EINVAL;
-
- vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize :
- video2_bufsize;
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
- return -EINVAL;
-
- startindex = (vout->vid == OMAP_VIDEO1) ?
- video1_numbuffers : video2_numbuffers;
- if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex)
- *count = startindex;
-
- if (ovid->rotation_type == VOUT_ROT_VRFB) {
- if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
- return -ENOMEM;
- }
-
- if (V4L2_MEMORY_MMAP != vout->memory)
- return 0;
-
- /* Now allocated the V4L2 buffers */
- *size = PAGE_ALIGN(vout->pix.width * vout->pix.height * vout->bpp);
- startindex = (vout->vid == OMAP_VIDEO1) ?
- video1_numbuffers : video2_numbuffers;
-
- /* Check the size of the buffer */
- if (*size > vid_max_buf_size) {
- v4l2_err(&vout->vid_dev->v4l2_dev,
- "buffer allocation mismatch [%u] [%u]\n",
- *size, vout->buffer_size);
- return -ENOMEM;
- }
-
- for (i = startindex; i < *count; i++) {
- vout->buffer_size = *size;
-
- virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
- &phy_addr);
- if (!virt_addr) {
- if (ovid->rotation_type == VOUT_ROT_NONE)
- break;
-
- if (!is_rotation_enabled(vout))
- break;
-
- /* Free the VRFB buffers if no space for V4L2 buffers */
- for (j = i; j < *count; j++) {
- omap_vout_free_buffer(vout->smsshado_virt_addr[j],
- vout->smsshado_size);
- vout->smsshado_virt_addr[j] = 0;
- vout->smsshado_phy_addr[j] = 0;
- }
- }
- vout->buf_virt_addr[i] = virt_addr;
- vout->buf_phy_addr[i] = phy_addr;
- }
- *count = vout->buffer_allocated = i;
-
- return 0;
-}
-
-/*
- * Free the V4L2 buffers additionally allocated than default
- * number of buffers
- */
-static void omap_vout_free_extra_buffers(struct omap_vout_device *vout)
-{
- int num_buffers = 0, i;
-
- num_buffers = (vout->vid == OMAP_VIDEO1) ?
- video1_numbuffers : video2_numbuffers;
-
- for (i = num_buffers; i < vout->buffer_allocated; i++) {
- if (vout->buf_virt_addr[i])
- omap_vout_free_buffer(vout->buf_virt_addr[i],
- vout->buffer_size);
-
- vout->buf_virt_addr[i] = 0;
- vout->buf_phy_addr[i] = 0;
- }
- vout->buffer_allocated = num_buffers;
-}
-
-/*
- * This function will be called when VIDIOC_QBUF ioctl is called.
- * It prepare buffers before give out for the display. This function
- * converts user space virtual address into physical address if userptr memory
- * exchange mechanism is used. If rotation is enabled, it copies entire
- * buffer into VRFB memory space before giving it to the DSS.
- */
-static int omap_vout_buffer_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct omap_vout_device *vout = q->priv_data;
- struct omapvideo_info *ovid = &vout->vid_info;
-
- if (VIDEOBUF_NEEDS_INIT == vb->state) {
- vb->width = vout->pix.width;
- vb->height = vout->pix.height;
- vb->size = vb->width * vb->height * vout->bpp;
- vb->field = field;
- }
- vb->state = VIDEOBUF_PREPARED;
- /* if user pointer memory mechanism is used, get the physical
- * address of the buffer
- */
- if (V4L2_MEMORY_USERPTR == vb->memory) {
- int ret;
-
- if (0 == vb->baddr)
- return -EINVAL;
- /* Physical address */
- ret = omap_vout_get_userptr(vb, vb->baddr,
- (u32 *)&vout->queued_buf_addr[vb->i]);
- if (ret < 0)
- return ret;
- } else {
- unsigned long addr, dma_addr;
- unsigned long size;
-
- addr = (unsigned long) vout->buf_virt_addr[vb->i];
- size = (unsigned long) vb->size;
-
- dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr,
- size, DMA_TO_DEVICE);
- if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr))
- v4l2_err(&vout->vid_dev->v4l2_dev,
- "dma_map_single failed\n");
-
- vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
- }
-
- if (ovid->rotation_type == VOUT_ROT_VRFB)
- return omap_vout_prepare_vrfb(vout, vb);
- else
- return 0;
-}
-
-/*
- * Buffer queue function will be called from the videobuf layer when _QBUF
- * ioctl is called. It is used to enqueue buffer, which is ready to be
- * displayed.
- */
-static void omap_vout_buffer_queue(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- struct omap_vout_device *vout = q->priv_data;
-
- /* Driver is also maintainig a queue. So enqueue buffer in the driver
- * queue */
- list_add_tail(&vb->queue, &vout->dma_queue);
-
- vb->state = VIDEOBUF_QUEUED;
-}
-
-/*
- * Buffer release function is called from videobuf layer to release buffer
- * which are already allocated
- */
-static void omap_vout_buffer_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
-{
- vb->state = VIDEOBUF_NEEDS_INIT;
- if (vb->memory == V4L2_MEMORY_USERPTR && vb->priv) {
- struct frame_vector *vec = vb->priv;
-
- put_vaddr_frames(vec);
- frame_vector_destroy(vec);
- }
-}
-
-/*
- * File operations
- */
-static __poll_t omap_vout_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct omap_vout_device *vout = file->private_data;
- struct videobuf_queue *q = &vout->vbq;
-
- return videobuf_poll_stream(file, q, wait);
-}
-
-static void omap_vout_vm_open(struct vm_area_struct *vma)
-{
- struct omap_vout_device *vout = vma->vm_private_data;
-
- v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
- "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
- vout->mmap_count++;
-}
-
-static void omap_vout_vm_close(struct vm_area_struct *vma)
-{
- struct omap_vout_device *vout = vma->vm_private_data;
-
- v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
- "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
- vout->mmap_count--;
-}
-
-static const struct vm_operations_struct omap_vout_vm_ops = {
- .open = omap_vout_vm_open,
- .close = omap_vout_vm_close,
-};
-
-static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
-{
- int i;
- void *pos;
- unsigned long start = vma->vm_start;
- unsigned long size = (vma->vm_end - vma->vm_start);
- struct omap_vout_device *vout = file->private_data;
- struct videobuf_queue *q = &vout->vbq;
-
- v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
- " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__,
- vma->vm_pgoff, vma->vm_start, vma->vm_end);
-
- /* look for the buffer to map */
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (NULL == q->bufs[i])
- continue;
- if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
- continue;
- if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
- break;
- }
-
- if (VIDEO_MAX_FRAME == i) {
- v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
- "offset invalid [offset=0x%lx]\n",
- (vma->vm_pgoff << PAGE_SHIFT));
- return -EINVAL;
- }
- /* Check the size of the buffer */
- if (size > vout->buffer_size) {
- v4l2_err(&vout->vid_dev->v4l2_dev,
- "insufficient memory [%lu] [%u]\n",
- size, vout->buffer_size);
- return -ENOMEM;
- }
-
- q->bufs[i]->baddr = vma->vm_start;
-
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
- vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
- vma->vm_ops = &omap_vout_vm_ops;
- vma->vm_private_data = (void *) vout;
- pos = (void *)vout->buf_virt_addr[i];
- vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT;
- while (size > 0) {
- unsigned long pfn;
- pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT;
- if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vout->mmap_count++;
- v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
-
- return 0;
-}
-
-static int omap_vout_release(struct file *file)
-{
- unsigned int ret, i;
- struct videobuf_queue *q;
- struct omapvideo_info *ovid;
- struct omap_vout_device *vout = file->private_data;
-
- v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
- ovid = &vout->vid_info;
-
- if (!vout)
- return 0;
-
- q = &vout->vbq;
- /* Disable all the overlay managers connected with this interface */
- for (i = 0; i < ovid->num_overlays; i++) {
- struct omap_overlay *ovl = ovid->overlays[i];
- struct omap_dss_device *dssdev = ovl->get_device(ovl);
-
- if (dssdev)
- ovl->disable(ovl);
- }
- /* Turn off the pipeline */
- ret = omapvid_apply_changes(vout);
- if (ret)
- v4l2_warn(&vout->vid_dev->v4l2_dev,
- "Unable to apply changes\n");
-
- /* Free all buffers */
- omap_vout_free_extra_buffers(vout);
-
- /* Free the VRFB buffers only if they are allocated
- * during reqbufs. Don't free if init time allocated
- */
- if (ovid->rotation_type == VOUT_ROT_VRFB) {
- if (!vout->vrfb_static_allocation)
- omap_vout_free_vrfb_buffers(vout);
- }
- videobuf_mmap_free(q);
-
- /* Even if apply changes fails we should continue
- freeing allocated memory */
- if (vout->streaming) {
- u32 mask = 0;
-
- mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN |
- DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2;
- omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
- vout->streaming = false;
-
- videobuf_streamoff(q);
- videobuf_queue_cancel(q);
- }
-
- if (vout->mmap_count != 0)
- vout->mmap_count = 0;
-
- vout->opened -= 1;
- file->private_data = NULL;
-
- if (vout->buffer_allocated)
- videobuf_mmap_free(q);
-
- v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
- return ret;
-}
-
-static int omap_vout_open(struct file *file)
-{
- struct videobuf_queue *q;
- struct omap_vout_device *vout = NULL;
-
- vout = video_drvdata(file);
-
- if (vout == NULL)
- return -ENODEV;
-
- v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__);
-
- /* for now, we only support single open */
- if (vout->opened)
- return -EBUSY;
-
- vout->opened += 1;
-
- file->private_data = vout;
- vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-
- q = &vout->vbq;
- video_vbq_ops.buf_setup = omap_vout_buffer_setup;
- video_vbq_ops.buf_prepare = omap_vout_buffer_prepare;
- video_vbq_ops.buf_release = omap_vout_buffer_release;
- video_vbq_ops.buf_queue = omap_vout_buffer_queue;
- spin_lock_init(&vout->vbq_lock);
-
- videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev,
- &vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), vout, NULL);
-
- v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
- return 0;
-}
/*
* V4L2 ioctls
@@ -1039,15 +570,12 @@ static int omap_vout_open(struct file *file)
static int vidioc_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
strscpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
strscpy(cap->card, vout->vfd->name, sizeof(cap->card));
- cap->bus_info[0] = '\0';
- cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
- V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s.%d", VOUT_NAME, vout->vid);
return 0;
}
@@ -1060,8 +588,6 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
return -EINVAL;
fmt->flags = omap_formats[index].flags;
- strscpy(fmt->description, omap_formats[index].description,
- sizeof(fmt->description));
fmt->pixelformat = omap_formats[index].pixelformat;
return 0;
@@ -1070,7 +596,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
struct v4l2_format *f)
{
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
f->fmt.pix = vout->pix;
return 0;
@@ -1083,7 +609,7 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
struct omap_overlay *ovl;
struct omapvideo_info *ovid;
struct omap_video_timings *timing;
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
struct omap_dss_device *dssdev;
ovid = &vout->vid_info;
@@ -1110,14 +636,12 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
struct omap_overlay *ovl;
struct omapvideo_info *ovid;
struct omap_video_timings *timing;
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
struct omap_dss_device *dssdev;
- if (vout->streaming)
+ if (vb2_is_busy(&vout->vq))
return -EBUSY;
- mutex_lock(&vout->lock);
-
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
dssdev = ovl->get_device(ovl);
@@ -1168,7 +692,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
ret = 0;
s_fmt_vid_out_exit:
- mutex_unlock(&vout->lock);
return ret;
}
@@ -1176,7 +699,7 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
struct v4l2_format *f)
{
int ret = 0;
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
struct omap_overlay *ovl;
struct omapvideo_info *ovid;
struct v4l2_window *win = &f->fmt.win;
@@ -1186,12 +709,8 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
ret = omap_vout_try_window(&vout->fbuf, win);
- if (!ret) {
- if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
- win->global_alpha = 255;
- else
- win->global_alpha = f->fmt.win.global_alpha;
- }
+ if (!ret && !(ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA))
+ win->global_alpha = 0;
return ret;
}
@@ -1202,35 +721,53 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
int ret = 0;
struct omap_overlay *ovl;
struct omapvideo_info *ovid;
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
struct v4l2_window *win = &f->fmt.win;
- mutex_lock(&vout->lock);
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
if (!ret) {
+ enum omap_dss_trans_key_type key_type =
+ OMAP_DSS_COLOR_KEY_GFX_DST;
+ int enable;
+
/* Video1 plane does not support global alpha on OMAP3 */
- if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
- vout->win.global_alpha = 255;
+ if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA)
+ vout->win.global_alpha = win->global_alpha;
+ else
+ win->global_alpha = 0;
+ if (vout->fbuf.flags & (V4L2_FBUF_FLAG_CHROMAKEY |
+ V4L2_FBUF_FLAG_SRC_CHROMAKEY))
+ enable = 1;
else
- vout->win.global_alpha = f->fmt.win.global_alpha;
+ enable = 0;
+ if (vout->fbuf.flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)
+ key_type = OMAP_DSS_COLOR_KEY_VID_SRC;
+
+ if (ovl->manager && ovl->manager->get_manager_info &&
+ ovl->manager->set_manager_info) {
+ struct omap_overlay_manager_info info;
- vout->win.chromakey = f->fmt.win.chromakey;
+ ovl->manager->get_manager_info(ovl->manager, &info);
+ info.trans_enabled = enable;
+ info.trans_key_type = key_type;
+ info.trans_key = vout->win.chromakey;
+
+ if (ovl->manager->set_manager_info(ovl->manager, &info))
+ return -EINVAL;
+ }
}
- mutex_unlock(&vout->lock);
return ret;
}
static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
struct v4l2_format *f)
{
- u32 key_value = 0;
struct omap_overlay *ovl;
struct omapvideo_info *ovid;
- struct omap_vout_device *vout = fh;
- struct omap_overlay_manager_info info;
+ struct omap_vout_device *vout = video_drvdata(file);
struct v4l2_window *win = &f->fmt.win;
ovid = &vout->vid_info;
@@ -1238,19 +775,20 @@ static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
win->w = vout->win.w;
win->field = vout->win.field;
- win->global_alpha = vout->win.global_alpha;
-
- if (ovl->manager && ovl->manager->get_manager_info) {
- ovl->manager->get_manager_info(ovl->manager, &info);
- key_value = info.trans_key;
- }
- win->chromakey = key_value;
+ win->chromakey = vout->win.chromakey;
+ if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA)
+ win->global_alpha = vout->win.global_alpha;
+ else
+ win->global_alpha = 0;
+ win->clips = NULL;
+ win->clipcount = 0;
+ win->bitmap = NULL;
return 0;
}
static int vidioc_g_selection(struct file *file, void *fh, struct v4l2_selection *sel)
{
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
struct v4l2_pix_format *pix = &vout->pix;
if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
@@ -1277,7 +815,7 @@ static int vidioc_g_selection(struct file *file, void *fh, struct v4l2_selection
static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection *sel)
{
int ret = -EINVAL;
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
struct omapvideo_info *ovid;
struct omap_overlay *ovl;
struct omap_video_timings *timing;
@@ -1289,10 +827,9 @@ static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- if (vout->streaming)
+ if (vb2_is_busy(&vout->vq))
return -EBUSY;
- mutex_lock(&vout->lock);
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
/* get the display device attached to the overlay */
@@ -1317,7 +854,6 @@ static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection
&vout->fbuf, &sel->r);
s_crop_err:
- mutex_unlock(&vout->lock);
return ret;
}
@@ -1334,26 +870,21 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl)
ovid = &vout->vid_info;
- mutex_lock(&vout->lock);
if (rotation && ovid->rotation_type == VOUT_ROT_NONE) {
- mutex_unlock(&vout->lock);
ret = -ERANGE;
break;
}
if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
- mutex_unlock(&vout->lock);
ret = -EINVAL;
break;
}
if (v4l2_rot_to_dss_rot(rotation, &vout->rotation,
vout->mirror)) {
- mutex_unlock(&vout->lock);
ret = -EINVAL;
break;
}
- mutex_unlock(&vout->lock);
break;
}
case V4L2_CID_BG_COLOR:
@@ -1364,9 +895,7 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl)
ovl = vout->vid_info.overlays[0];
- mutex_lock(&vout->lock);
if (!ovl->manager || !ovl->manager->get_manager_info) {
- mutex_unlock(&vout->lock);
ret = -EINVAL;
break;
}
@@ -1374,11 +903,9 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl)
ovl->manager->get_manager_info(ovl->manager, &info);
info.default_color = color;
if (ovl->manager->set_manager_info(ovl->manager, &info)) {
- mutex_unlock(&vout->lock);
ret = -EINVAL;
break;
}
- mutex_unlock(&vout->lock);
break;
}
case V4L2_CID_VFLIP:
@@ -1388,20 +915,16 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl)
ovid = &vout->vid_info;
- mutex_lock(&vout->lock);
if (mirror && ovid->rotation_type == VOUT_ROT_NONE) {
- mutex_unlock(&vout->lock);
ret = -ERANGE;
break;
}
if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
- mutex_unlock(&vout->lock);
ret = -EINVAL;
break;
}
vout->mirror = mirror;
- mutex_unlock(&vout->lock);
break;
}
default:
@@ -1414,185 +937,94 @@ static const struct v4l2_ctrl_ops omap_vout_ctrl_ops = {
.s_ctrl = omap_vout_s_ctrl,
};
-static int vidioc_reqbufs(struct file *file, void *fh,
- struct v4l2_requestbuffers *req)
+static int omap_vout_vb2_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbufs,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
{
- int ret = 0;
- unsigned int i, num_buffers = 0;
- struct omap_vout_device *vout = fh;
- struct videobuf_queue *q = &vout->vbq;
-
- if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return -EINVAL;
- /* if memory is not mmp or userptr
- return error */
- if ((V4L2_MEMORY_MMAP != req->memory) &&
- (V4L2_MEMORY_USERPTR != req->memory))
- return -EINVAL;
-
- mutex_lock(&vout->lock);
- /* Cannot be requested when streaming is on */
- if (vout->streaming) {
- ret = -EBUSY;
- goto reqbuf_err;
- }
+ struct omap_vout_device *vout = vb2_get_drv_priv(vq);
+ int size = vout->pix.sizeimage;
- /* If buffers are already allocated free them */
- if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
- if (vout->mmap_count) {
- ret = -EBUSY;
- goto reqbuf_err;
- }
- num_buffers = (vout->vid == OMAP_VIDEO1) ?
- video1_numbuffers : video2_numbuffers;
- for (i = num_buffers; i < vout->buffer_allocated; i++) {
- omap_vout_free_buffer(vout->buf_virt_addr[i],
- vout->buffer_size);
- vout->buf_virt_addr[i] = 0;
- vout->buf_phy_addr[i] = 0;
- }
- vout->buffer_allocated = num_buffers;
- videobuf_mmap_free(q);
- } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) {
- if (vout->buffer_allocated) {
- videobuf_mmap_free(q);
- for (i = 0; i < vout->buffer_allocated; i++) {
- kfree(q->bufs[i]);
- q->bufs[i] = NULL;
- }
- vout->buffer_allocated = 0;
- }
+ if (is_rotation_enabled(vout) && vq->num_buffers + *nbufs > VRFB_NUM_BUFS) {
+ *nbufs = VRFB_NUM_BUFS - vq->num_buffers;
+ if (*nbufs == 0)
+ return -EINVAL;
}
- /*store the memory type in data structure */
- vout->memory = req->memory;
-
- INIT_LIST_HEAD(&vout->dma_queue);
-
- /* call videobuf_reqbufs api */
- ret = videobuf_reqbufs(q, req);
- if (ret < 0)
- goto reqbuf_err;
-
- vout->buffer_allocated = req->count;
-
-reqbuf_err:
- mutex_unlock(&vout->lock);
- return ret;
-}
-
-static int vidioc_querybuf(struct file *file, void *fh,
- struct v4l2_buffer *b)
-{
- struct omap_vout_device *vout = fh;
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
- return videobuf_querybuf(&vout->vbq, b);
+ *num_planes = 1;
+ sizes[0] = size;
+ return 0;
}
-static int vidioc_qbuf(struct file *file, void *fh,
- struct v4l2_buffer *buffer)
+static int omap_vout_vb2_prepare(struct vb2_buffer *vb)
{
- struct omap_vout_device *vout = fh;
- struct videobuf_queue *q = &vout->vbq;
+ struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue);
+ struct omapvideo_info *ovid = &vout->vid_info;
+ struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb);
+ dma_addr_t buf_phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
- if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) ||
- (buffer->index >= vout->buffer_allocated) ||
- (q->bufs[buffer->index]->memory != buffer->memory)) {
+ if (vb2_plane_size(vb, 0) < vout->pix.sizeimage) {
+ v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
+ "%s data will not fit into plane (%lu < %u)\n",
+ __func__, vb2_plane_size(vb, 0), vout->pix.sizeimage);
return -EINVAL;
}
- if (V4L2_MEMORY_USERPTR == buffer->memory) {
- if ((buffer->length < vout->pix.sizeimage) ||
- (0 == buffer->m.userptr)) {
- return -EINVAL;
- }
- }
- if ((is_rotation_enabled(vout)) &&
- vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
- v4l2_warn(&vout->vid_dev->v4l2_dev,
- "DMA Channel not allocated for Rotation\n");
- return -EINVAL;
- }
+ vb2_set_plane_payload(vb, 0, vout->pix.sizeimage);
+ voutbuf->vbuf.field = V4L2_FIELD_NONE;
- return videobuf_qbuf(q, buffer);
+ vout->queued_buf_addr[vb->index] = (u8 *)buf_phy_addr;
+ if (ovid->rotation_type == VOUT_ROT_VRFB)
+ return omap_vout_prepare_vrfb(vout, vb);
+ return 0;
}
-static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+static void omap_vout_vb2_queue(struct vb2_buffer *vb)
{
- struct omap_vout_device *vout = fh;
- struct videobuf_queue *q = &vout->vbq;
+ struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue);
+ struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb);
- int ret;
- u32 addr;
- unsigned long size;
- struct videobuf_buffer *vb;
-
- if (!vout->streaming)
- return -EINVAL;
-
- 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 0;
+ list_add_tail(&voutbuf->queue, &vout->dma_queue);
}
-static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+static int omap_vout_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- int ret = 0, j;
- u32 addr = 0, mask = 0;
- struct omap_vout_device *vout = fh;
- struct videobuf_queue *q = &vout->vbq;
+ struct omap_vout_device *vout = vb2_get_drv_priv(vq);
struct omapvideo_info *ovid = &vout->vid_info;
-
- mutex_lock(&vout->lock);
-
- if (vout->streaming) {
- ret = -EBUSY;
- goto streamon_err;
- }
-
- ret = videobuf_streamon(q);
- if (ret)
- goto streamon_err;
-
- if (list_empty(&vout->dma_queue)) {
- ret = -EIO;
- goto streamon_err1;
- }
+ struct omap_vout_buffer *buf, *tmp;
+ u32 addr = 0, mask = 0;
+ int ret, j;
/* Get the next frame from the buffer queue */
vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next,
- struct videobuf_buffer, queue);
+ struct omap_vout_buffer, queue);
/* Remove buffer from the buffer queue */
list_del(&vout->cur_frm->queue);
- /* Mark state of the current frame to active */
- vout->cur_frm->state = VIDEOBUF_ACTIVE;
/* Initialize field_id and started member */
vout->field_id = 0;
-
- /* set flag here. Next QBUF will start DMA */
- vout->streaming = true;
-
vout->first_int = 1;
+ vout->sequence = 0;
if (omap_vout_calculate_offset(vout)) {
ret = -EINVAL;
- goto streamon_err1;
+ goto out;
}
- addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
+ if (ovid->rotation_type == VOUT_ROT_VRFB)
+ if (omap_vout_vrfb_buffer_setup(vout, &count, 0)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ addr = (unsigned long)vout->queued_buf_addr[vout->cur_frm->vbuf.vb2_buf.index]
+ vout->cropped_offset;
mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
| DISPC_IRQ_VSYNC2;
- /* First save the configuration in ovelray structure */
+ /* First save the configuration in overlay structure */
ret = omapvid_init(vout, addr);
if (ret) {
v4l2_err(&vout->vid_dev->v4l2_dev,
@@ -1617,28 +1049,43 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
goto streamon_err1;
}
}
-
- ret = 0;
+ return 0;
streamon_err1:
- if (ret)
- ret = videobuf_streamoff(q);
-streamon_err:
- mutex_unlock(&vout->lock);
+ mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
+ | DISPC_IRQ_VSYNC2;
+
+ omap_dispc_unregister_isr(omap_vout_isr, vout, mask);
+
+ for (j = 0; j < ovid->num_overlays; j++) {
+ struct omap_overlay *ovl = ovid->overlays[j];
+ struct omap_dss_device *dssdev = ovl->get_device(ovl);
+
+ if (dssdev)
+ ovl->disable(ovl);
+ }
+ /* Turn of the pipeline */
+ if (omapvid_apply_changes(vout))
+ v4l2_err(&vout->vid_dev->v4l2_dev,
+ "failed to change mode in streamoff\n");
+
+out:
+ vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED);
+ list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) {
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED);
+ }
return ret;
}
-static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+static void omap_vout_vb2_stop_streaming(struct vb2_queue *vq)
{
- u32 mask = 0;
- int ret = 0, j;
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = vb2_get_drv_priv(vq);
struct omapvideo_info *ovid = &vout->vid_info;
+ struct omap_vout_buffer *buf, *tmp;
+ u32 mask = 0;
+ int j;
- if (!vout->streaming)
- return -EINVAL;
-
- vout->streaming = false;
mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD
| DISPC_IRQ_VSYNC2;
@@ -1651,17 +1098,18 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
if (dssdev)
ovl->disable(ovl);
}
-
/* Turn of the pipeline */
- ret = omapvid_apply_changes(vout);
- if (ret)
+ if (omapvid_apply_changes(vout))
v4l2_err(&vout->vid_dev->v4l2_dev,
"failed to change mode in streamoff\n");
- INIT_LIST_HEAD(&vout->dma_queue);
- ret = videobuf_streamoff(&vout->vbq);
-
- return ret;
+ if (vout->next_frm != vout->cur_frm)
+ vb2_buffer_done(&vout->next_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
+ vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
+ list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) {
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
}
static int vidioc_s_fbuf(struct file *file, void *fh,
@@ -1670,7 +1118,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh,
int enable = 0;
struct omap_overlay *ovl;
struct omapvideo_info *ovid;
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
struct omap_overlay_manager_info info;
enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
@@ -1741,17 +1189,36 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
{
struct omap_overlay *ovl;
struct omapvideo_info *ovid;
- struct omap_vout_device *vout = fh;
+ struct omap_vout_device *vout = video_drvdata(file);
struct omap_overlay_manager_info info;
+ struct omap_video_timings *timing;
+ struct omap_dss_device *dssdev;
ovid = &vout->vid_info;
ovl = ovid->overlays[0];
+ /* get the display device attached to the overlay */
+ dssdev = ovl->get_device(ovl);
+
+ if (!dssdev)
+ return -EINVAL;
+
+ timing = &dssdev->panel.timings;
- /* The video overlay must stay within the framebuffer and can't be
- positioned independently. */
- a->flags = V4L2_FBUF_FLAG_OVERLAY;
- a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
- | V4L2_FBUF_CAP_SRC_CHROMAKEY;
+ vout->fbuf.fmt.height = timing->y_res;
+ vout->fbuf.fmt.width = timing->x_res;
+ a->fmt.field = V4L2_FIELD_NONE;
+ a->fmt.colorspace = V4L2_COLORSPACE_SRGB;
+ a->fmt.pixelformat = V4L2_PIX_FMT_RGBA32;
+ a->fmt.height = vout->fbuf.fmt.height;
+ a->fmt.width = vout->fbuf.fmt.width;
+ a->fmt.bytesperline = vout->fbuf.fmt.width * 4;
+ a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline;
+ a->base = vout->fbuf.base;
+
+ a->flags = vout->fbuf.flags;
+ a->capability = vout->fbuf.capability;
+ a->flags &= ~(V4L2_FBUF_FLAG_SRC_CHROMAKEY | V4L2_FBUF_FLAG_CHROMAKEY |
+ V4L2_FBUF_FLAG_LOCAL_ALPHA);
if (ovl->manager && ovl->manager->get_manager_info) {
ovl->manager->get_manager_info(ovl->manager, &info);
@@ -1759,9 +1226,6 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
- }
- if (ovl->manager && ovl->manager->get_manager_info) {
- ovl->manager->get_manager_info(ovl->manager, &info);
if (info.partial_alpha_enabled)
a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
}
@@ -1769,6 +1233,27 @@ static int vidioc_g_fbuf(struct file *file, void *fh,
return 0;
}
+static int vidioc_enum_output(struct file *file, void *priv_fh,
+ struct v4l2_output *out)
+{
+ if (out->index)
+ return -EINVAL;
+ snprintf(out->name, sizeof(out->name), "Overlay");
+ out->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
+ return 0;
+}
+
+static int vidioc_g_output(struct file *file, void *priv_fh, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_output(struct file *file, void *priv_fh, unsigned int i)
+{
+ return i ? -EINVAL : 0;
+}
+
static const struct v4l2_ioctl_ops vout_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
@@ -1782,21 +1267,38 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = {
.vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay,
.vidioc_g_selection = vidioc_g_selection,
.vidioc_s_selection = vidioc_s_selection,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_enum_output = vidioc_enum_output,
+ .vidioc_g_output = vidioc_g_output,
+ .vidioc_s_output = vidioc_s_output,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static const struct v4l2_file_operations omap_vout_fops = {
.owner = THIS_MODULE,
- .poll = omap_vout_poll,
.unlocked_ioctl = video_ioctl2,
- .mmap = omap_vout_mmap,
- .open = omap_vout_open,
- .release = omap_vout_release,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+};
+
+static const struct vb2_ops omap_vout_vb2_ops = {
+ .queue_setup = omap_vout_vb2_queue_setup,
+ .buf_queue = omap_vout_vb2_queue,
+ .buf_prepare = omap_vout_vb2_prepare,
+ .start_streaming = omap_vout_vb2_start_streaming,
+ .stop_streaming = omap_vout_vb2_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
/* Init functions used during driver initialization */
@@ -1808,6 +1310,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
struct omap_overlay *ovl = vout->vid_info.overlays[0];
struct omap_dss_device *display = ovl->get_device(ovl);
struct v4l2_ctrl_handler *hdl;
+ struct vb2_queue *vq;
+ int ret;
/* set the default pix */
pix = &vout->pix;
@@ -1818,37 +1322,48 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
/* Default pixel format is RGB 5-6-5 */
pix->pixelformat = V4L2_PIX_FMT_RGB565;
- pix->field = V4L2_FIELD_ANY;
+ pix->field = V4L2_FIELD_NONE;
pix->bytesperline = pix->width * 2;
pix->sizeimage = pix->bytesperline * pix->height;
- pix->colorspace = V4L2_COLORSPACE_JPEG;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
vout->bpp = RGB565_BPP;
vout->fbuf.fmt.width = display->panel.timings.x_res;
vout->fbuf.fmt.height = display->panel.timings.y_res;
+ vout->cropped_offset = 0;
/* Set the data structures for the overlay parameters*/
- vout->win.global_alpha = 255;
- vout->fbuf.flags = 0;
+ vout->fbuf.flags = V4L2_FBUF_FLAG_OVERLAY;
vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
- V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
- vout->win.chromakey = 0;
+ V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY |
+ V4L2_FBUF_CAP_EXTERNOVERLAY;
+ if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) {
+ vout->win.global_alpha = 255;
+ vout->fbuf.capability |= V4L2_FBUF_CAP_GLOBAL_ALPHA;
+ vout->fbuf.flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
+ } else {
+ vout->win.global_alpha = 0;
+ }
+ vout->win.field = V4L2_FIELD_NONE;
omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
hdl = &vout->ctrl_handler;
v4l2_ctrl_handler_init(hdl, 3);
- v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
- V4L2_CID_ROTATE, 0, 270, 90, 0);
+ if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) {
+ v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
+ V4L2_CID_ROTATE, 0, 270, 90, 0);
+ v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ }
v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
V4L2_CID_BG_COLOR, 0, 0xffffff, 1, 0);
- v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
if (hdl->error)
return hdl->error;
vout->rotation = 0;
vout->mirror = false;
+ INIT_LIST_HEAD(&vout->dma_queue);
if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
vout->vrfb_bpp = 2;
@@ -1870,63 +1385,54 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
vfd->fops = &omap_vout_fops;
vfd->v4l2_dev = &vout->vid_dev->v4l2_dev;
vfd->vfl_dir = VFL_DIR_TX;
- mutex_init(&vout->lock);
-
vfd->minor = -1;
- return 0;
+ vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ mutex_init(&vout->lock);
+ vq = &vout->vq;
+ vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ vq->drv_priv = vout;
+ vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ vq->buf_struct_size = sizeof(struct omap_vout_buffer);
+ vq->dev = vfd->v4l2_dev->dev;
+
+ vq->ops = &omap_vout_vb2_ops;
+ vq->mem_ops = &vb2_dma_contig_memops;
+ vq->lock = &vout->lock;
+ vq->min_buffers_needed = 1;
+ vfd->queue = vq;
+
+ ret = vb2_queue_init(vq);
+ if (ret) {
+ v4l2_ctrl_handler_free(hdl);
+ video_device_release(vfd);
+ }
+ return ret;
}
/* Setup video buffers */
static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
int vid_num)
{
- u32 numbuffers;
- int ret = 0, i;
struct omapvideo_info *ovid;
struct omap_vout_device *vout;
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
struct omap2video_device *vid_dev =
container_of(v4l2_dev, struct omap2video_device, v4l2_dev);
+ int ret = 0;
vout = vid_dev->vouts[vid_num];
ovid = &vout->vid_info;
- numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
- vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
- dev_info(&pdev->dev, "Buffer Size = %d\n", vout->buffer_size);
-
- for (i = 0; i < numbuffers; i++) {
- vout->buf_virt_addr[i] =
- omap_vout_alloc_buffer(vout->buffer_size,
- (u32 *) &vout->buf_phy_addr[i]);
- if (!vout->buf_virt_addr[i]) {
- numbuffers = i;
- ret = -ENOMEM;
- goto free_buffers;
- }
- }
-
- vout->cropped_offset = 0;
-
if (ovid->rotation_type == VOUT_ROT_VRFB) {
bool static_vrfb_allocation = (vid_num == 0) ?
vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
ret = omap_vout_setup_vrfb_bufs(pdev, vid_num,
static_vrfb_allocation);
}
-
- return ret;
-
-free_buffers:
- for (i = 0; i < numbuffers; i++) {
- omap_vout_free_buffer(vout->buf_virt_addr[i],
- vout->buffer_size);
- vout->buf_virt_addr[i] = 0;
- vout->buf_phy_addr[i] = 0;
- }
return ret;
-
}
/* Create video out devices */
@@ -1938,6 +1444,10 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
struct omap2video_device *vid_dev = container_of(v4l2_dev,
struct omap2video_device, v4l2_dev);
+ struct omap_overlay *ovl = vid_dev->overlays[0];
+ struct omap_overlay_info info;
+
+ ovl->get_overlay_info(ovl, &info);
for (k = 0; k < pdev->num_resources; k++) {
@@ -1958,6 +1468,15 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
vout->vid_info.num_overlays = 1;
vout->vid_info.id = k + 1;
+ spin_lock_init(&vout->vbq_lock);
+ /*
+ * Set the framebuffer base, this allows applications to find
+ * the fb corresponding to this overlay.
+ *
+ * To be precise: fbuf.base should match smem_start of
+ * struct fb_fix_screeninfo.
+ */
+ vout->fbuf.base = (void *)info.paddr;
/* Set VRFB as rotation_type for omap2 and omap3 */
if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx())
@@ -2000,7 +1519,6 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
error2:
if (vout->vid_info.rotation_type == VOUT_ROT_VRFB)
omap_vout_release_vrfb(vout);
- omap_vout_free_buffers(vout);
error1:
video_device_release(vfd);
error:
@@ -2045,7 +1563,6 @@ static void omap_vout_cleanup_device(struct omap_vout_device *vout)
if (vout->vrfb_static_allocation)
omap_vout_free_vrfb_buffers(vout);
}
- omap_vout_free_buffers(vout);
kfree(vout);
}
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c
index 11ec048929e8..6bd672cbdb62 100644
--- a/drivers/media/platform/omap/omap_vout_vrfb.c
+++ b/drivers/media/platform/omap/omap_vout_vrfb.c
@@ -14,7 +14,6 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
-#include <media/videobuf-dma-contig.h>
#include <media/v4l2-device.h>
#include <video/omapvrfb.h>
@@ -40,7 +39,7 @@ static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
&vout->smsshado_phy_addr[i]);
}
if (!vout->smsshado_virt_addr[i] && startindex != -1) {
- if (V4L2_MEMORY_MMAP == vout->memory && i >= startindex)
+ if (vout->vq.memory == V4L2_MEMORY_MMAP && i >= startindex)
break;
}
if (!vout->smsshado_virt_addr[i]) {
@@ -109,8 +108,7 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
dev_info(&pdev->dev, ": VRFB allocation failed\n");
for (j = 0; j < i; j++)
omap_vrfb_release_ctx(&vout->vrfb_context[j]);
- ret = -ENOMEM;
- goto free_buffers;
+ return -ENOMEM;
}
}
@@ -155,8 +153,10 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
init_waitqueue_head(&vout->vrfb_dma_tx.wait);
- /* statically allocated the VRFB buffer is done through
- commands line aruments */
+ /*
+ * statically allocated the VRFB buffer is done through
+ * command line arguments
+ */
if (static_vrfb_allocation) {
if (omap_vout_allocate_vrfb_buffers(vout, &vrfb_num_bufs, -1)) {
ret = -ENOMEM;
@@ -169,9 +169,6 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num,
release_vrfb_ctx:
for (j = 0; j < VRFB_NUM_BUFS; j++)
omap_vrfb_release_ctx(&vout->vrfb_context[j]);
-free_buffers:
- omap_vout_free_buffers(vout);
-
return ret;
}
@@ -231,13 +228,14 @@ int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
}
int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
- struct videobuf_buffer *vb)
+ struct vb2_buffer *vb)
{
struct dma_async_tx_descriptor *tx;
enum dma_ctrl_flags flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
struct dma_chan *chan = vout->vrfb_dma_tx.chan;
struct dma_interleaved_template *xt = vout->vrfb_dma_tx.xt;
dma_cookie_t cookie;
+ dma_addr_t buf_phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
enum dma_status status;
enum dss_rotation rotation;
size_t dst_icg;
@@ -255,8 +253,8 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
pixsize = vout->bpp * vout->vrfb_bpp;
dst_icg = MAX_PIXELS_PER_LINE * pixsize - vout->pix.width * vout->bpp;
- xt->src_start = vout->buf_phy_addr[vb->i];
- xt->dst_start = vout->vrfb_context[vb->i].paddr[0];
+ xt->src_start = buf_phy_addr;
+ xt->dst_start = vout->vrfb_context[vb->index].paddr[0];
xt->numf = vout->pix.height;
xt->frame_size = 1;
@@ -307,8 +305,8 @@ int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
/* Store buffers physical address into an array. Addresses
* from this array will be used to configure DSS */
rotation = calc_rotation(vout);
- vout->queued_buf_addr[vb->i] = (u8 *)
- vout->vrfb_context[vb->i].paddr[rotation];
+ vout->queued_buf_addr[vb->index] = (u8 *)
+ vout->vrfb_context[vb->index].paddr[rotation];
return 0;
}
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.h b/drivers/media/platform/omap/omap_vout_vrfb.h
index c976975024df..40bc9e54ecc6 100644
--- a/drivers/media/platform/omap/omap_vout_vrfb.h
+++ b/drivers/media/platform/omap/omap_vout_vrfb.h
@@ -20,7 +20,7 @@ void omap_vout_release_vrfb(struct omap_vout_device *vout);
int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
unsigned int *count, unsigned int startindex);
int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
- struct videobuf_buffer *vb);
+ struct vb2_buffer *vb);
void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout);
#else
static inline void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout) { };
@@ -32,7 +32,7 @@ static inline int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
unsigned int *count, unsigned int startindex)
{ return 0; };
static inline int omap_vout_prepare_vrfb(struct omap_vout_device *vout,
- struct videobuf_buffer *vb)
+ struct vb2_buffer *vb)
{ return 0; };
static inline void omap_vout_calculate_vrfb_offset(struct omap_vout_device *vout) { };
#endif
diff --git a/drivers/media/platform/omap/omap_voutdef.h b/drivers/media/platform/omap/omap_voutdef.h
index c740393c8509..1cff6dea1879 100644
--- a/drivers/media/platform/omap/omap_voutdef.h
+++ b/drivers/media/platform/omap/omap_voutdef.h
@@ -11,6 +11,7 @@
#ifndef OMAP_VOUTDEF_H
#define OMAP_VOUTDEF_H
+#include <media/videobuf2-dma-contig.h>
#include <media/v4l2-ctrls.h>
#include <video/omapfb_dss.h>
#include <video/omapvrfb.h>
@@ -113,6 +114,20 @@ struct omap2video_device {
struct omap_overlay_manager *managers[MAX_MANAGERS];
};
+/* buffer for one video frame */
+struct omap_vout_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_v4l2_buffer vbuf;
+ struct list_head queue;
+};
+
+static inline struct omap_vout_buffer *vb2_to_omap_vout_buffer(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ return container_of(vbuf, struct omap_vout_buffer, vbuf);
+}
+
/* per-device data structure */
struct omap_vout_device {
@@ -121,29 +136,12 @@ struct omap_vout_device {
struct omap2video_device *vid_dev;
struct v4l2_ctrl_handler ctrl_handler;
int vid;
- int opened;
- /* we don't allow to change image fmt/size once buffer has
- * been allocated
- */
- int buffer_allocated;
/* allow to reuse previously allocated buffer which is big enough */
int buffer_size;
- /* keep buffer info across opens */
- unsigned long buf_virt_addr[VIDEO_MAX_FRAME];
- unsigned long buf_phy_addr[VIDEO_MAX_FRAME];
enum omap_color_mode dss_mode;
- /* we don't allow to request new buffer when old buffers are
- * still mmapped
- */
- int mmap_count;
-
- spinlock_t vbq_lock; /* spinlock for videobuf queues */
- unsigned long field_count; /* field counter for videobuf_buffer */
-
- /* non-NULL means streaming is in progress. */
- bool streaming;
+ u32 sequence;
struct v4l2_pix_format pix;
struct v4l2_rect crop;
@@ -169,19 +167,14 @@ struct omap_vout_device {
unsigned char pos;
int ps, vr_ps, line_length, first_int, field_id;
- enum v4l2_memory memory;
- struct videobuf_buffer *cur_frm, *next_frm;
+ struct omap_vout_buffer *cur_frm, *next_frm;
+ spinlock_t vbq_lock; /* spinlock for dma_queue */
struct list_head dma_queue;
u8 *queued_buf_addr[VIDEO_MAX_FRAME];
u32 cropped_offset;
s32 tv_field1_offset;
void *isr_handle;
-
- /* Buffer queue variables */
- struct omap_vout_device *vout;
- enum v4l2_buf_type type;
- struct videobuf_queue vbq;
- int io_allowed;
+ struct vb2_queue vq;
};
diff --git a/drivers/media/platform/omap/omap_voutlib.c b/drivers/media/platform/omap/omap_voutlib.c
index 58a25fdf0cce..480a7e95533d 100644
--- a/drivers/media/platform/omap/omap_voutlib.c
+++ b/drivers/media/platform/omap/omap_voutlib.c
@@ -95,7 +95,11 @@ int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
/* We now have a valid preview window, so go with it */
new_win->w = try_win;
- new_win->field = V4L2_FIELD_ANY;
+ new_win->field = V4L2_FIELD_NONE;
+ new_win->clips = NULL;
+ new_win->clipcount = 0;
+ new_win->bitmap = NULL;
+
return 0;
}
EXPORT_SYMBOL_GPL(omap_vout_try_window);
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 83216fc7156b..a4ee6b86663e 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -719,6 +719,10 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
s_stream, mode);
pipe->do_propagation = true;
}
+
+ /* Stop at the first external sub-device. */
+ if (subdev->dev != isp->dev)
+ break;
}
return 0;
@@ -806,6 +810,10 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
ret = v4l2_subdev_call(subdev, video, s_stream, 0);
+ /* Stop at the first external sub-device. */
+ if (subdev->dev != isp->dev)
+ break;
+
if (subdev == &isp->isp_res.subdev)
ret |= isp_pipeline_wait(isp, isp_pipeline_wait_resizer);
else if (subdev == &isp->isp_prev.subdev)
@@ -2014,136 +2022,6 @@ enum isp_of_phy {
ISP_OF_PHY_CSIPHY2,
};
-static int isp_fwnode_parse(struct device *dev,
- struct v4l2_fwnode_endpoint *vep,
- struct v4l2_async_subdev *asd)
-{
- struct isp_async_subdev *isd =
- container_of(asd, struct isp_async_subdev, asd);
- struct isp_bus_cfg *buscfg = &isd->bus;
- bool csi1 = false;
- unsigned int i;
-
- dev_dbg(dev, "parsing endpoint %pOF, interface %u\n",
- to_of_node(vep->base.local_fwnode), vep->base.port);
-
- switch (vep->base.port) {
- case ISP_OF_PHY_PARALLEL:
- buscfg->interface = ISP_INTERFACE_PARALLEL;
- buscfg->bus.parallel.data_lane_shift =
- vep->bus.parallel.data_shift;
- buscfg->bus.parallel.clk_pol =
- !!(vep->bus.parallel.flags
- & V4L2_MBUS_PCLK_SAMPLE_FALLING);
- buscfg->bus.parallel.hs_pol =
- !!(vep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
- buscfg->bus.parallel.vs_pol =
- !!(vep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
- buscfg->bus.parallel.fld_pol =
- !!(vep->bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
- buscfg->bus.parallel.data_pol =
- !!(vep->bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
- buscfg->bus.parallel.bt656 = vep->bus_type == V4L2_MBUS_BT656;
- break;
-
- case ISP_OF_PHY_CSIPHY1:
- case ISP_OF_PHY_CSIPHY2:
- switch (vep->bus_type) {
- case V4L2_MBUS_CCP2:
- case V4L2_MBUS_CSI1:
- dev_dbg(dev, "CSI-1/CCP-2 configuration\n");
- csi1 = true;
- break;
- case V4L2_MBUS_CSI2_DPHY:
- dev_dbg(dev, "CSI-2 configuration\n");
- csi1 = false;
- break;
- default:
- dev_err(dev, "unsupported bus type %u\n",
- vep->bus_type);
- return -EINVAL;
- }
-
- switch (vep->base.port) {
- case ISP_OF_PHY_CSIPHY1:
- if (csi1)
- buscfg->interface = ISP_INTERFACE_CCP2B_PHY1;
- else
- buscfg->interface = ISP_INTERFACE_CSI2C_PHY1;
- break;
- case ISP_OF_PHY_CSIPHY2:
- if (csi1)
- buscfg->interface = ISP_INTERFACE_CCP2B_PHY2;
- else
- buscfg->interface = ISP_INTERFACE_CSI2A_PHY2;
- break;
- }
- if (csi1) {
- buscfg->bus.ccp2.lanecfg.clk.pos =
- vep->bus.mipi_csi1.clock_lane;
- buscfg->bus.ccp2.lanecfg.clk.pol =
- vep->bus.mipi_csi1.lane_polarity[0];
- dev_dbg(dev, "clock lane polarity %u, pos %u\n",
- buscfg->bus.ccp2.lanecfg.clk.pol,
- buscfg->bus.ccp2.lanecfg.clk.pos);
-
- buscfg->bus.ccp2.lanecfg.data[0].pos =
- vep->bus.mipi_csi1.data_lane;
- buscfg->bus.ccp2.lanecfg.data[0].pol =
- vep->bus.mipi_csi1.lane_polarity[1];
-
- dev_dbg(dev, "data lane polarity %u, pos %u\n",
- buscfg->bus.ccp2.lanecfg.data[0].pol,
- buscfg->bus.ccp2.lanecfg.data[0].pos);
-
- buscfg->bus.ccp2.strobe_clk_pol =
- vep->bus.mipi_csi1.clock_inv;
- buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe;
- buscfg->bus.ccp2.ccp2_mode =
- vep->bus_type == V4L2_MBUS_CCP2;
- buscfg->bus.ccp2.vp_clk_pol = 1;
-
- buscfg->bus.ccp2.crc = 1;
- } else {
- buscfg->bus.csi2.lanecfg.clk.pos =
- vep->bus.mipi_csi2.clock_lane;
- buscfg->bus.csi2.lanecfg.clk.pol =
- vep->bus.mipi_csi2.lane_polarities[0];
- dev_dbg(dev, "clock lane polarity %u, pos %u\n",
- buscfg->bus.csi2.lanecfg.clk.pol,
- buscfg->bus.csi2.lanecfg.clk.pos);
-
- buscfg->bus.csi2.num_data_lanes =
- vep->bus.mipi_csi2.num_data_lanes;
-
- for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) {
- buscfg->bus.csi2.lanecfg.data[i].pos =
- vep->bus.mipi_csi2.data_lanes[i];
- buscfg->bus.csi2.lanecfg.data[i].pol =
- vep->bus.mipi_csi2.lane_polarities[i + 1];
- dev_dbg(dev,
- "data lane %u polarity %u, pos %u\n", i,
- buscfg->bus.csi2.lanecfg.data[i].pol,
- buscfg->bus.csi2.lanecfg.data[i].pos);
- }
- /*
- * FIXME: now we assume the CRC is always there.
- * Implement a way to obtain this information from the
- * sensor. Frame descriptors, perhaps?
- */
- buscfg->bus.csi2.crc = 1;
- }
- break;
-
- default:
- dev_warn(dev, "%pOF: invalid interface %u\n",
- to_of_node(vep->base.local_fwnode), vep->base.port);
- return -EINVAL;
- }
-
- return 0;
-}
-
static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
{
struct isp_device *isp = container_of(async, struct isp_device,
@@ -2173,6 +2051,201 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
return media_device_register(&isp->media_dev);
}
+static void isp_parse_of_parallel_endpoint(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct isp_bus_cfg *buscfg)
+{
+ buscfg->interface = ISP_INTERFACE_PARALLEL;
+ buscfg->bus.parallel.data_lane_shift = vep->bus.parallel.data_shift;
+ buscfg->bus.parallel.clk_pol =
+ !!(vep->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING);
+ buscfg->bus.parallel.hs_pol =
+ !!(vep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
+ buscfg->bus.parallel.vs_pol =
+ !!(vep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
+ buscfg->bus.parallel.fld_pol =
+ !!(vep->bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
+ buscfg->bus.parallel.data_pol =
+ !!(vep->bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
+ buscfg->bus.parallel.bt656 = vep->bus_type == V4L2_MBUS_BT656;
+}
+
+static void isp_parse_of_csi2_endpoint(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct isp_bus_cfg *buscfg)
+{
+ unsigned int i;
+
+ buscfg->bus.csi2.lanecfg.clk.pos = vep->bus.mipi_csi2.clock_lane;
+ buscfg->bus.csi2.lanecfg.clk.pol =
+ vep->bus.mipi_csi2.lane_polarities[0];
+ dev_dbg(dev, "clock lane polarity %u, pos %u\n",
+ buscfg->bus.csi2.lanecfg.clk.pol,
+ buscfg->bus.csi2.lanecfg.clk.pos);
+
+ buscfg->bus.csi2.num_data_lanes = vep->bus.mipi_csi2.num_data_lanes;
+
+ for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) {
+ buscfg->bus.csi2.lanecfg.data[i].pos =
+ vep->bus.mipi_csi2.data_lanes[i];
+ buscfg->bus.csi2.lanecfg.data[i].pol =
+ vep->bus.mipi_csi2.lane_polarities[i + 1];
+ dev_dbg(dev,
+ "data lane %u polarity %u, pos %u\n", i,
+ buscfg->bus.csi2.lanecfg.data[i].pol,
+ buscfg->bus.csi2.lanecfg.data[i].pos);
+ }
+ /*
+ * FIXME: now we assume the CRC is always there. Implement a way to
+ * obtain this information from the sensor. Frame descriptors, perhaps?
+ */
+ buscfg->bus.csi2.crc = 1;
+}
+
+static void isp_parse_of_csi1_endpoint(struct device *dev,
+ struct v4l2_fwnode_endpoint *vep,
+ struct isp_bus_cfg *buscfg)
+{
+ buscfg->bus.ccp2.lanecfg.clk.pos = vep->bus.mipi_csi1.clock_lane;
+ buscfg->bus.ccp2.lanecfg.clk.pol = vep->bus.mipi_csi1.lane_polarity[0];
+ dev_dbg(dev, "clock lane polarity %u, pos %u\n",
+ buscfg->bus.ccp2.lanecfg.clk.pol,
+ buscfg->bus.ccp2.lanecfg.clk.pos);
+
+ buscfg->bus.ccp2.lanecfg.data[0].pos = vep->bus.mipi_csi1.data_lane;
+ buscfg->bus.ccp2.lanecfg.data[0].pol =
+ vep->bus.mipi_csi1.lane_polarity[1];
+
+ dev_dbg(dev, "data lane polarity %u, pos %u\n",
+ buscfg->bus.ccp2.lanecfg.data[0].pol,
+ buscfg->bus.ccp2.lanecfg.data[0].pos);
+
+ buscfg->bus.ccp2.strobe_clk_pol = vep->bus.mipi_csi1.clock_inv;
+ buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe;
+ buscfg->bus.ccp2.ccp2_mode = vep->bus_type == V4L2_MBUS_CCP2;
+ buscfg->bus.ccp2.vp_clk_pol = 1;
+
+ buscfg->bus.ccp2.crc = 1;
+}
+
+static int isp_alloc_isd(struct isp_async_subdev **isd,
+ struct isp_bus_cfg **buscfg)
+{
+ struct isp_async_subdev *__isd;
+
+ __isd = kzalloc(sizeof(*__isd), GFP_KERNEL);
+ if (!__isd)
+ return -ENOMEM;
+
+ *isd = __isd;
+ *buscfg = &__isd->bus;
+
+ return 0;
+}
+
+static struct {
+ u32 phy;
+ u32 csi2_if;
+ u32 csi1_if;
+} isp_bus_interfaces[2] = {
+ { ISP_OF_PHY_CSIPHY1,
+ ISP_INTERFACE_CSI2C_PHY1, ISP_INTERFACE_CCP2B_PHY1 },
+ { ISP_OF_PHY_CSIPHY2,
+ ISP_INTERFACE_CSI2A_PHY2, ISP_INTERFACE_CCP2B_PHY2 },
+};
+
+static int isp_parse_of_endpoints(struct isp_device *isp)
+{
+ struct fwnode_handle *ep;
+ struct isp_async_subdev *isd = NULL;
+ struct isp_bus_cfg *buscfg;
+ unsigned int i;
+
+ ep = fwnode_graph_get_endpoint_by_id(
+ dev_fwnode(isp->dev), ISP_OF_PHY_PARALLEL, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+
+ if (ep) {
+ struct v4l2_fwnode_endpoint vep = {
+ .bus_type = V4L2_MBUS_PARALLEL
+ };
+ int ret;
+
+ dev_dbg(isp->dev, "parsing parallel interface\n");
+
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+
+ if (!ret) {
+ ret = isp_alloc_isd(&isd, &buscfg);
+ if (ret)
+ return ret;
+ }
+
+ if (!ret) {
+ isp_parse_of_parallel_endpoint(isp->dev, &vep, buscfg);
+ ret = v4l2_async_notifier_add_fwnode_remote_subdev(
+ &isp->notifier, ep, &isd->asd);
+ }
+
+ fwnode_handle_put(ep);
+ if (ret)
+ kfree(isd);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(isp_bus_interfaces); i++) {
+ struct v4l2_fwnode_endpoint vep = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ int ret;
+
+ ep = fwnode_graph_get_endpoint_by_id(
+ dev_fwnode(isp->dev), isp_bus_interfaces[i].phy, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+
+ if (!ep)
+ continue;
+
+ dev_dbg(isp->dev, "parsing serial interface %u, node %pOF\n", i,
+ to_of_node(ep));
+
+ ret = isp_alloc_isd(&isd, &buscfg);
+ if (ret)
+ return ret;
+
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+ if (!ret) {
+ buscfg->interface = isp_bus_interfaces[i].csi2_if;
+ isp_parse_of_csi2_endpoint(isp->dev, &vep, buscfg);
+ } else if (ret == -ENXIO) {
+ vep = (struct v4l2_fwnode_endpoint)
+ { .bus_type = V4L2_MBUS_CSI1 };
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+
+ if (ret == -ENXIO) {
+ vep = (struct v4l2_fwnode_endpoint)
+ { .bus_type = V4L2_MBUS_CCP2 };
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+ }
+ if (!ret) {
+ buscfg->interface =
+ isp_bus_interfaces[i].csi1_if;
+ isp_parse_of_csi1_endpoint(isp->dev, &vep,
+ buscfg);
+ }
+ }
+
+ if (!ret)
+ ret = v4l2_async_notifier_add_fwnode_remote_subdev(
+ &isp->notifier, ep, &isd->asd);
+
+ fwnode_handle_put(ep);
+ if (ret)
+ kfree(isd);
+ }
+
+ return 0;
+}
+
static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = {
.complete = isp_subdev_notifier_complete,
};
@@ -2223,14 +2296,12 @@ static int isp_probe(struct platform_device *pdev)
mutex_init(&isp->isp_mutex);
spin_lock_init(&isp->stat_lock);
v4l2_async_notifier_init(&isp->notifier);
+ isp->dev = &pdev->dev;
- ret = v4l2_async_notifier_parse_fwnode_endpoints(
- &pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev),
- isp_fwnode_parse);
+ ret = isp_parse_of_endpoints(isp);
if (ret < 0)
goto error;
- isp->dev = &pdev->dev;
isp->ref_count = 0;
ret = dma_coerce_mask_and_coherent(isp->dev, DMA_BIT_MASK(32));
@@ -2324,7 +2395,6 @@ static int isp_probe(struct platform_device *pdev)
/* Interrupt */
ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
- dev_err(isp->dev, "No IRQ resource\n");
ret = -ENODEV;
goto error_iommu;
}
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 1ba8a5ba343f..471ae7cdb813 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -1607,6 +1607,11 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
return 0;
}
+ /* Don't restart CCDC if we're just about to stop streaming. */
+ if (ccdc->state == ISP_PIPELINE_STREAM_CONTINUOUS &&
+ ccdc->stopping & CCDC_STOP_REQUEST)
+ return 0;
+
if (!ccdc_has_all_fields(ccdc))
return 1;
@@ -1661,16 +1666,15 @@ static void ccdc_vd0_isr(struct isp_ccdc_device *ccdc)
spin_unlock_irqrestore(&ccdc->lock, flags);
}
- if (ccdc->output & CCDC_OUTPUT_MEMORY)
- restart = ccdc_isr_buffer(ccdc);
-
spin_lock_irqsave(&ccdc->lock, flags);
-
if (ccdc_handle_stopping(ccdc, CCDC_EVENT_VD0)) {
spin_unlock_irqrestore(&ccdc->lock, flags);
return;
}
+ if (ccdc->output & CCDC_OUTPUT_MEMORY)
+ restart = ccdc_isr_buffer(ccdc);
+
if (!ccdc->shadow_update)
ccdc_apply_controls(ccdc);
spin_unlock_irqrestore(&ccdc->lock, flags);
@@ -2602,6 +2606,7 @@ int omap3isp_ccdc_register_entities(struct isp_ccdc_device *ccdc,
int ret;
/* Register the subdev and video node. */
+ ccdc->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &ccdc->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index efca45bb02c8..d0a49cdfd22d 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -1031,6 +1031,7 @@ int omap3isp_ccp2_register_entities(struct isp_ccp2_device *ccp2,
int ret;
/* Register the subdev and video nodes. */
+ ccp2->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &ccp2->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index e85917f4a50c..fd493c5e4e24 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -1198,6 +1198,7 @@ int omap3isp_csi2_register_entities(struct isp_csi2_device *csi2,
int ret;
/* Register the subdev and video nodes. */
+ csi2->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 40e22400cf5e..4dbdf3180d10 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -753,7 +753,7 @@ static const struct preview_update update_attrs[] = {
preview_config_luma_enhancement,
preview_enable_luma_enhancement,
offsetof(struct prev_params, luma),
- FIELD_SIZEOF(struct prev_params, luma),
+ sizeof_field(struct prev_params, luma),
offsetof(struct omap3isp_prev_update_config, luma),
}, /* OMAP3ISP_PREV_INVALAW */ {
NULL,
@@ -762,55 +762,55 @@ static const struct preview_update update_attrs[] = {
preview_config_hmed,
preview_enable_hmed,
offsetof(struct prev_params, hmed),
- FIELD_SIZEOF(struct prev_params, hmed),
+ sizeof_field(struct prev_params, hmed),
offsetof(struct omap3isp_prev_update_config, hmed),
}, /* OMAP3ISP_PREV_CFA */ {
preview_config_cfa,
NULL,
offsetof(struct prev_params, cfa),
- FIELD_SIZEOF(struct prev_params, cfa),
+ sizeof_field(struct prev_params, cfa),
offsetof(struct omap3isp_prev_update_config, cfa),
}, /* OMAP3ISP_PREV_CHROMA_SUPP */ {
preview_config_chroma_suppression,
preview_enable_chroma_suppression,
offsetof(struct prev_params, csup),
- FIELD_SIZEOF(struct prev_params, csup),
+ sizeof_field(struct prev_params, csup),
offsetof(struct omap3isp_prev_update_config, csup),
}, /* OMAP3ISP_PREV_WB */ {
preview_config_whitebalance,
NULL,
offsetof(struct prev_params, wbal),
- FIELD_SIZEOF(struct prev_params, wbal),
+ sizeof_field(struct prev_params, wbal),
offsetof(struct omap3isp_prev_update_config, wbal),
}, /* OMAP3ISP_PREV_BLKADJ */ {
preview_config_blkadj,
NULL,
offsetof(struct prev_params, blkadj),
- FIELD_SIZEOF(struct prev_params, blkadj),
+ sizeof_field(struct prev_params, blkadj),
offsetof(struct omap3isp_prev_update_config, blkadj),
}, /* OMAP3ISP_PREV_RGB2RGB */ {
preview_config_rgb_blending,
NULL,
offsetof(struct prev_params, rgb2rgb),
- FIELD_SIZEOF(struct prev_params, rgb2rgb),
+ sizeof_field(struct prev_params, rgb2rgb),
offsetof(struct omap3isp_prev_update_config, rgb2rgb),
}, /* OMAP3ISP_PREV_COLOR_CONV */ {
preview_config_csc,
NULL,
offsetof(struct prev_params, csc),
- FIELD_SIZEOF(struct prev_params, csc),
+ sizeof_field(struct prev_params, csc),
offsetof(struct omap3isp_prev_update_config, csc),
}, /* OMAP3ISP_PREV_YC_LIMIT */ {
preview_config_yc_range,
NULL,
offsetof(struct prev_params, yclimit),
- FIELD_SIZEOF(struct prev_params, yclimit),
+ sizeof_field(struct prev_params, yclimit),
offsetof(struct omap3isp_prev_update_config, yclimit),
}, /* OMAP3ISP_PREV_DEFECT_COR */ {
preview_config_dcor,
preview_enable_dcor,
offsetof(struct prev_params, dcor),
- FIELD_SIZEOF(struct prev_params, dcor),
+ sizeof_field(struct prev_params, dcor),
offsetof(struct omap3isp_prev_update_config, dcor),
}, /* Previously OMAP3ISP_PREV_GAMMABYPASS, not used anymore */ {
NULL,
@@ -828,13 +828,13 @@ static const struct preview_update update_attrs[] = {
preview_config_noisefilter,
preview_enable_noisefilter,
offsetof(struct prev_params, nf),
- FIELD_SIZEOF(struct prev_params, nf),
+ sizeof_field(struct prev_params, nf),
offsetof(struct omap3isp_prev_update_config, nf),
}, /* OMAP3ISP_PREV_GAMMA */ {
preview_config_gammacorrn,
preview_enable_gammacorrn,
offsetof(struct prev_params, gamma),
- FIELD_SIZEOF(struct prev_params, gamma),
+ sizeof_field(struct prev_params, gamma),
offsetof(struct omap3isp_prev_update_config, gamma),
}, /* OMAP3ISP_PREV_CONTRAST */ {
preview_config_contrast,
@@ -2225,6 +2225,7 @@ int omap3isp_preview_register_entities(struct isp_prev_device *prev,
int ret;
/* Register the subdev and video nodes. */
+ prev->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &prev->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h
index 38e2b99b3f10..86b6ebb0438d 100644
--- a/drivers/media/platform/omap3isp/ispreg.h
+++ b/drivers/media/platform/omap3isp/ispreg.h
@@ -45,7 +45,7 @@
#define ISPCCP2_REVISION (0x000)
#define ISPCCP2_SYSCONFIG (0x004)
-#define ISPCCP2_SYSCONFIG_SOFT_RESET (1 << 1)
+#define ISPCCP2_SYSCONFIG_SOFT_RESET BIT(1)
#define ISPCCP2_SYSCONFIG_AUTO_IDLE 0x1
#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT 12
#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_FORCE \
@@ -55,44 +55,44 @@
#define ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SMART \
(0x2 << ISPCCP2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
#define ISPCCP2_SYSSTATUS (0x008)
-#define ISPCCP2_SYSSTATUS_RESET_DONE (1 << 0)
+#define ISPCCP2_SYSSTATUS_RESET_DONE BIT(0)
#define ISPCCP2_LC01_IRQENABLE (0x00C)
#define ISPCCP2_LC01_IRQSTATUS (0x010)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ (1 << 11)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_LE_IRQ (1 << 10)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_LS_IRQ (1 << 9)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_FE_IRQ (1 << 8)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_COUNT_IRQ (1 << 7)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ (1 << 5)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ (1 << 4)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ (1 << 3)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ (1 << 2)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ (1 << 1)
-#define ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ (1 << 0)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FS_IRQ BIT(11)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_LE_IRQ BIT(10)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_LS_IRQ BIT(9)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FE_IRQ BIT(8)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_COUNT_IRQ BIT(7)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ BIT(5)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_CRC_IRQ BIT(4)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FSP_IRQ BIT(3)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FW_IRQ BIT(2)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_FSC_IRQ BIT(1)
+#define ISPCCP2_LC01_IRQSTATUS_LC0_SSC_IRQ BIT(0)
#define ISPCCP2_LC23_IRQENABLE (0x014)
#define ISPCCP2_LC23_IRQSTATUS (0x018)
#define ISPCCP2_LCM_IRQENABLE (0x02C)
-#define ISPCCP2_LCM_IRQSTATUS_EOF_IRQ (1 << 0)
-#define ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ (1 << 1)
+#define ISPCCP2_LCM_IRQSTATUS_EOF_IRQ BIT(0)
+#define ISPCCP2_LCM_IRQSTATUS_OCPERROR_IRQ BIT(1)
#define ISPCCP2_LCM_IRQSTATUS (0x030)
#define ISPCCP2_CTRL (0x040)
-#define ISPCCP2_CTRL_IF_EN (1 << 0)
-#define ISPCCP2_CTRL_PHY_SEL (1 << 1)
+#define ISPCCP2_CTRL_IF_EN BIT(0)
+#define ISPCCP2_CTRL_PHY_SEL BIT(1)
#define ISPCCP2_CTRL_PHY_SEL_CLOCK (0 << 1)
#define ISPCCP2_CTRL_PHY_SEL_STROBE (1 << 1)
#define ISPCCP2_CTRL_PHY_SEL_MASK 0x1
#define ISPCCP2_CTRL_PHY_SEL_SHIFT 1
-#define ISPCCP2_CTRL_IO_OUT_SEL (1 << 2)
+#define ISPCCP2_CTRL_IO_OUT_SEL BIT(2)
#define ISPCCP2_CTRL_IO_OUT_SEL_MASK 0x1
#define ISPCCP2_CTRL_IO_OUT_SEL_SHIFT 2
-#define ISPCCP2_CTRL_MODE (1 << 4)
-#define ISPCCP2_CTRL_VP_CLK_FORCE_ON (1 << 9)
-#define ISPCCP2_CTRL_INV (1 << 10)
+#define ISPCCP2_CTRL_MODE BIT(4)
+#define ISPCCP2_CTRL_VP_CLK_FORCE_ON BIT(9)
+#define ISPCCP2_CTRL_INV BIT(10)
#define ISPCCP2_CTRL_INV_MASK 0x1
#define ISPCCP2_CTRL_INV_SHIFT 10
-#define ISPCCP2_CTRL_VP_ONLY_EN (1 << 11)
-#define ISPCCP2_CTRL_VP_CLK_POL (1 << 12)
+#define ISPCCP2_CTRL_VP_ONLY_EN BIT(11)
+#define ISPCCP2_CTRL_VP_CLK_POL BIT(12)
#define ISPCCP2_CTRL_VP_CLK_POL_MASK 0x1
#define ISPCCP2_CTRL_VP_CLK_POL_SHIFT 12
#define ISPCCP2_CTRL_VPCLK_DIV_SHIFT 15
@@ -102,12 +102,12 @@
#define ISPCCP2_DBG (0x044)
#define ISPCCP2_GNQ (0x048)
#define ISPCCP2_LCx_CTRL(x) ((0x050)+0x30*(x))
-#define ISPCCP2_LCx_CTRL_CHAN_EN (1 << 0)
-#define ISPCCP2_LCx_CTRL_CRC_EN (1 << 19)
+#define ISPCCP2_LCx_CTRL_CHAN_EN BIT(0)
+#define ISPCCP2_LCx_CTRL_CRC_EN BIT(19)
#define ISPCCP2_LCx_CTRL_CRC_MASK 0x1
#define ISPCCP2_LCx_CTRL_CRC_SHIFT 2
#define ISPCCP2_LCx_CTRL_CRC_SHIFT_15_0 19
-#define ISPCCP2_LCx_CTRL_REGION_EN (1 << 1)
+#define ISPCCP2_LCx_CTRL_REGION_EN BIT(1)
#define ISPCCP2_LCx_CTRL_REGION_MASK 0x1
#define ISPCCP2_LCx_CTRL_REGION_SHIFT 1
#define ISPCCP2_LCx_CTRL_FORMAT_MASK_15_0 0x3f
@@ -127,8 +127,8 @@
#define ISPCCP2_LCx_DAT_PONG_ADDR(x) ((0x074)+0x30*(x))
#define ISPCCP2_LCx_DAT_OFST(x) ((0x078)+0x30*(x))
#define ISPCCP2_LCM_CTRL (0x1D0)
-#define ISPCCP2_LCM_CTRL_CHAN_EN (1 << 0)
-#define ISPCCP2_LCM_CTRL_DST_PORT (1 << 2)
+#define ISPCCP2_LCM_CTRL_CHAN_EN BIT(0)
+#define ISPCCP2_LCM_CTRL_DST_PORT BIT(2)
#define ISPCCP2_LCM_CTRL_DST_PORT_SHIFT 2
#define ISPCCP2_LCM_CTRL_READ_THROTTLE_SHIFT 3
#define ISPCCP2_LCM_CTRL_READ_THROTTLE_MASK 0x11
@@ -138,8 +138,8 @@
#define ISPCCP2_LCM_CTRL_SRC_FORMAT_MASK 0x7
#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_SHIFT 20
#define ISPCCP2_LCM_CTRL_SRC_DECOMPR_MASK 0x3
-#define ISPCCP2_LCM_CTRL_SRC_DPCM_PRED (1 << 22)
-#define ISPCCP2_LCM_CTRL_SRC_PACK (1 << 23)
+#define ISPCCP2_LCM_CTRL_SRC_DPCM_PRED BIT(22)
+#define ISPCCP2_LCM_CTRL_SRC_PACK BIT(23)
#define ISPCCP2_LCM_CTRL_DST_FORMAT_SHIFT 24
#define ISPCCP2_LCM_CTRL_DST_FORMAT_MASK 0x7
#define ISPCCP2_LCM_VSIZE (0x1D4)
@@ -201,19 +201,19 @@
/* SBL */
#define ISPSBL_PCR 0x4
-#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF (1 << 16)
-#define ISPSBL_PCR_H3A_AF_WBL_OVF (1 << 17)
-#define ISPSBL_PCR_RSZ4_WBL_OVF (1 << 18)
-#define ISPSBL_PCR_RSZ3_WBL_OVF (1 << 19)
-#define ISPSBL_PCR_RSZ2_WBL_OVF (1 << 20)
-#define ISPSBL_PCR_RSZ1_WBL_OVF (1 << 21)
-#define ISPSBL_PCR_PRV_WBL_OVF (1 << 22)
-#define ISPSBL_PCR_CCDC_WBL_OVF (1 << 23)
-#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF (1 << 24)
-#define ISPSBL_PCR_CSIA_WBL_OVF (1 << 25)
-#define ISPSBL_PCR_CSIB_WBL_OVF (1 << 26)
+#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF BIT(16)
+#define ISPSBL_PCR_H3A_AF_WBL_OVF BIT(17)
+#define ISPSBL_PCR_RSZ4_WBL_OVF BIT(18)
+#define ISPSBL_PCR_RSZ3_WBL_OVF BIT(19)
+#define ISPSBL_PCR_RSZ2_WBL_OVF BIT(20)
+#define ISPSBL_PCR_RSZ1_WBL_OVF BIT(21)
+#define ISPSBL_PCR_PRV_WBL_OVF BIT(22)
+#define ISPSBL_PCR_CCDC_WBL_OVF BIT(23)
+#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF BIT(24)
+#define ISPSBL_PCR_CSIA_WBL_OVF BIT(25)
+#define ISPSBL_PCR_CSIB_WBL_OVF BIT(26)
#define ISPSBL_CCDC_WR_0 (0x028)
-#define ISPSBL_CCDC_WR_0_DATA_READY (1 << 21)
+#define ISPSBL_CCDC_WR_0_DATA_READY BIT(21)
#define ISPSBL_CCDC_WR_1 (0x02C)
#define ISPSBL_CCDC_WR_2 (0x030)
#define ISPSBL_CCDC_WR_3 (0x034)
@@ -366,16 +366,16 @@
#define ISP_INT_CLR 0xFF113F11
#define ISPPRV_PCR_EN 1
-#define ISPPRV_PCR_BUSY (1 << 1)
-#define ISPPRV_PCR_SOURCE (1 << 2)
-#define ISPPRV_PCR_ONESHOT (1 << 3)
-#define ISPPRV_PCR_WIDTH (1 << 4)
-#define ISPPRV_PCR_INVALAW (1 << 5)
-#define ISPPRV_PCR_DRKFEN (1 << 6)
-#define ISPPRV_PCR_DRKFCAP (1 << 7)
-#define ISPPRV_PCR_HMEDEN (1 << 8)
-#define ISPPRV_PCR_NFEN (1 << 9)
-#define ISPPRV_PCR_CFAEN (1 << 10)
+#define ISPPRV_PCR_BUSY BIT(1)
+#define ISPPRV_PCR_SOURCE BIT(2)
+#define ISPPRV_PCR_ONESHOT BIT(3)
+#define ISPPRV_PCR_WIDTH BIT(4)
+#define ISPPRV_PCR_INVALAW BIT(5)
+#define ISPPRV_PCR_DRKFEN BIT(6)
+#define ISPPRV_PCR_DRKFCAP BIT(7)
+#define ISPPRV_PCR_HMEDEN BIT(8)
+#define ISPPRV_PCR_NFEN BIT(9)
+#define ISPPRV_PCR_CFAEN BIT(10)
#define ISPPRV_PCR_CFAFMT_SHIFT 11
#define ISPPRV_PCR_CFAFMT_MASK 0x7800
#define ISPPRV_PCR_CFAFMT_BAYER (0 << 11)
@@ -384,22 +384,22 @@
#define ISPPRV_PCR_CFAFMT_DNSPL (3 << 11)
#define ISPPRV_PCR_CFAFMT_HONEYCOMB (4 << 11)
#define ISPPRV_PCR_CFAFMT_RRGGBBFOVEON (5 << 11)
-#define ISPPRV_PCR_YNENHEN (1 << 15)
-#define ISPPRV_PCR_SUPEN (1 << 16)
+#define ISPPRV_PCR_YNENHEN BIT(15)
+#define ISPPRV_PCR_SUPEN BIT(16)
#define ISPPRV_PCR_YCPOS_SHIFT 17
#define ISPPRV_PCR_YCPOS_YCrYCb (0 << 17)
#define ISPPRV_PCR_YCPOS_YCbYCr (1 << 17)
#define ISPPRV_PCR_YCPOS_CbYCrY (2 << 17)
#define ISPPRV_PCR_YCPOS_CrYCbY (3 << 17)
-#define ISPPRV_PCR_RSZPORT (1 << 19)
-#define ISPPRV_PCR_SDRPORT (1 << 20)
-#define ISPPRV_PCR_SCOMP_EN (1 << 21)
+#define ISPPRV_PCR_RSZPORT BIT(19)
+#define ISPPRV_PCR_SDRPORT BIT(20)
+#define ISPPRV_PCR_SCOMP_EN BIT(21)
#define ISPPRV_PCR_SCOMP_SFT_SHIFT (22)
#define ISPPRV_PCR_SCOMP_SFT_MASK (7 << 22)
-#define ISPPRV_PCR_GAMMA_BYPASS (1 << 26)
-#define ISPPRV_PCR_DCOREN (1 << 27)
-#define ISPPRV_PCR_DCCOUP (1 << 28)
-#define ISPPRV_PCR_DRK_FAIL (1 << 31)
+#define ISPPRV_PCR_GAMMA_BYPASS BIT(26)
+#define ISPPRV_PCR_DCOREN BIT(27)
+#define ISPPRV_PCR_DCCOUP BIT(28)
+#define ISPPRV_PCR_DRK_FAIL BIT(31)
#define ISPPRV_HORZ_INFO_EPH_SHIFT 0
#define ISPPRV_HORZ_INFO_EPH_MASK 0x3fff
@@ -423,8 +423,8 @@
#define ISPPRV_AVE_ODDDIST_4 0x3
#define ISPPRV_HMED_THRESHOLD_SHIFT 0
-#define ISPPRV_HMED_EVENDIST (1 << 8)
-#define ISPPRV_HMED_ODDDIST (1 << 9)
+#define ISPPRV_HMED_EVENDIST BIT(8)
+#define ISPPRV_HMED_ODDDIST BIT(9)
#define ISPPRV_WBGAIN_COEF0_SHIFT 0
#define ISPPRV_WBGAIN_COEF1_SHIFT 8
@@ -517,8 +517,8 @@
/* Define bit fields within selected registers */
#define ISP_REVISION_SHIFT 0
-#define ISP_SYSCONFIG_AUTOIDLE (1 << 0)
-#define ISP_SYSCONFIG_SOFTRESET (1 << 1)
+#define ISP_SYSCONFIG_AUTOIDLE BIT(0)
+#define ISP_SYSCONFIG_SOFTRESET BIT(1)
#define ISP_SYSCONFIG_MIDLEMODE_SHIFT 12
#define ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY 0x0
#define ISP_SYSCONFIG_MIDLEMODE_NOSTANBY 0x1
@@ -526,68 +526,68 @@
#define ISP_SYSSTATUS_RESETDONE 0
-#define IRQ0ENABLE_CSIA_IRQ (1 << 0)
-#define IRQ0ENABLE_CSIC_IRQ (1 << 1)
-#define IRQ0ENABLE_CCP2_LCM_IRQ (1 << 3)
-#define IRQ0ENABLE_CCP2_LC0_IRQ (1 << 4)
-#define IRQ0ENABLE_CCP2_LC1_IRQ (1 << 5)
-#define IRQ0ENABLE_CCP2_LC2_IRQ (1 << 6)
-#define IRQ0ENABLE_CCP2_LC3_IRQ (1 << 7)
+#define IRQ0ENABLE_CSIA_IRQ BIT(0)
+#define IRQ0ENABLE_CSIC_IRQ BIT(1)
+#define IRQ0ENABLE_CCP2_LCM_IRQ BIT(3)
+#define IRQ0ENABLE_CCP2_LC0_IRQ BIT(4)
+#define IRQ0ENABLE_CCP2_LC1_IRQ BIT(5)
+#define IRQ0ENABLE_CCP2_LC2_IRQ BIT(6)
+#define IRQ0ENABLE_CCP2_LC3_IRQ BIT(7)
#define IRQ0ENABLE_CSIB_IRQ (IRQ0ENABLE_CCP2_LCM_IRQ | \
IRQ0ENABLE_CCP2_LC0_IRQ | \
IRQ0ENABLE_CCP2_LC1_IRQ | \
IRQ0ENABLE_CCP2_LC2_IRQ | \
IRQ0ENABLE_CCP2_LC3_IRQ)
-#define IRQ0ENABLE_CCDC_VD0_IRQ (1 << 8)
-#define IRQ0ENABLE_CCDC_VD1_IRQ (1 << 9)
-#define IRQ0ENABLE_CCDC_VD2_IRQ (1 << 10)
-#define IRQ0ENABLE_CCDC_ERR_IRQ (1 << 11)
-#define IRQ0ENABLE_H3A_AF_DONE_IRQ (1 << 12)
-#define IRQ0ENABLE_H3A_AWB_DONE_IRQ (1 << 13)
-#define IRQ0ENABLE_HIST_DONE_IRQ (1 << 16)
-#define IRQ0ENABLE_CCDC_LSC_DONE_IRQ (1 << 17)
-#define IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ (1 << 18)
-#define IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ (1 << 19)
-#define IRQ0ENABLE_PRV_DONE_IRQ (1 << 20)
-#define IRQ0ENABLE_RSZ_DONE_IRQ (1 << 24)
-#define IRQ0ENABLE_OVF_IRQ (1 << 25)
-#define IRQ0ENABLE_PING_IRQ (1 << 26)
-#define IRQ0ENABLE_PONG_IRQ (1 << 27)
-#define IRQ0ENABLE_MMU_ERR_IRQ (1 << 28)
-#define IRQ0ENABLE_OCP_ERR_IRQ (1 << 29)
-#define IRQ0ENABLE_SEC_ERR_IRQ (1 << 30)
-#define IRQ0ENABLE_HS_VS_IRQ (1 << 31)
-
-#define IRQ0STATUS_CSIA_IRQ (1 << 0)
-#define IRQ0STATUS_CSI2C_IRQ (1 << 1)
-#define IRQ0STATUS_CCP2_LCM_IRQ (1 << 3)
-#define IRQ0STATUS_CCP2_LC0_IRQ (1 << 4)
+#define IRQ0ENABLE_CCDC_VD0_IRQ BIT(8)
+#define IRQ0ENABLE_CCDC_VD1_IRQ BIT(9)
+#define IRQ0ENABLE_CCDC_VD2_IRQ BIT(10)
+#define IRQ0ENABLE_CCDC_ERR_IRQ BIT(11)
+#define IRQ0ENABLE_H3A_AF_DONE_IRQ BIT(12)
+#define IRQ0ENABLE_H3A_AWB_DONE_IRQ BIT(13)
+#define IRQ0ENABLE_HIST_DONE_IRQ BIT(16)
+#define IRQ0ENABLE_CCDC_LSC_DONE_IRQ BIT(17)
+#define IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ BIT(18)
+#define IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ BIT(19)
+#define IRQ0ENABLE_PRV_DONE_IRQ BIT(20)
+#define IRQ0ENABLE_RSZ_DONE_IRQ BIT(24)
+#define IRQ0ENABLE_OVF_IRQ BIT(25)
+#define IRQ0ENABLE_PING_IRQ BIT(26)
+#define IRQ0ENABLE_PONG_IRQ BIT(27)
+#define IRQ0ENABLE_MMU_ERR_IRQ BIT(28)
+#define IRQ0ENABLE_OCP_ERR_IRQ BIT(29)
+#define IRQ0ENABLE_SEC_ERR_IRQ BIT(30)
+#define IRQ0ENABLE_HS_VS_IRQ BIT(31)
+
+#define IRQ0STATUS_CSIA_IRQ BIT(0)
+#define IRQ0STATUS_CSI2C_IRQ BIT(1)
+#define IRQ0STATUS_CCP2_LCM_IRQ BIT(3)
+#define IRQ0STATUS_CCP2_LC0_IRQ BIT(4)
#define IRQ0STATUS_CSIB_IRQ (IRQ0STATUS_CCP2_LCM_IRQ | \
IRQ0STATUS_CCP2_LC0_IRQ)
-#define IRQ0STATUS_CSIB_LC1_IRQ (1 << 5)
-#define IRQ0STATUS_CSIB_LC2_IRQ (1 << 6)
-#define IRQ0STATUS_CSIB_LC3_IRQ (1 << 7)
-#define IRQ0STATUS_CCDC_VD0_IRQ (1 << 8)
-#define IRQ0STATUS_CCDC_VD1_IRQ (1 << 9)
-#define IRQ0STATUS_CCDC_VD2_IRQ (1 << 10)
-#define IRQ0STATUS_CCDC_ERR_IRQ (1 << 11)
-#define IRQ0STATUS_H3A_AF_DONE_IRQ (1 << 12)
-#define IRQ0STATUS_H3A_AWB_DONE_IRQ (1 << 13)
-#define IRQ0STATUS_HIST_DONE_IRQ (1 << 16)
-#define IRQ0STATUS_CCDC_LSC_DONE_IRQ (1 << 17)
-#define IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ (1 << 18)
-#define IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ (1 << 19)
-#define IRQ0STATUS_PRV_DONE_IRQ (1 << 20)
-#define IRQ0STATUS_RSZ_DONE_IRQ (1 << 24)
-#define IRQ0STATUS_OVF_IRQ (1 << 25)
-#define IRQ0STATUS_PING_IRQ (1 << 26)
-#define IRQ0STATUS_PONG_IRQ (1 << 27)
-#define IRQ0STATUS_MMU_ERR_IRQ (1 << 28)
-#define IRQ0STATUS_OCP_ERR_IRQ (1 << 29)
-#define IRQ0STATUS_SEC_ERR_IRQ (1 << 30)
-#define IRQ0STATUS_HS_VS_IRQ (1 << 31)
+#define IRQ0STATUS_CSIB_LC1_IRQ BIT(5)
+#define IRQ0STATUS_CSIB_LC2_IRQ BIT(6)
+#define IRQ0STATUS_CSIB_LC3_IRQ BIT(7)
+#define IRQ0STATUS_CCDC_VD0_IRQ BIT(8)
+#define IRQ0STATUS_CCDC_VD1_IRQ BIT(9)
+#define IRQ0STATUS_CCDC_VD2_IRQ BIT(10)
+#define IRQ0STATUS_CCDC_ERR_IRQ BIT(11)
+#define IRQ0STATUS_H3A_AF_DONE_IRQ BIT(12)
+#define IRQ0STATUS_H3A_AWB_DONE_IRQ BIT(13)
+#define IRQ0STATUS_HIST_DONE_IRQ BIT(16)
+#define IRQ0STATUS_CCDC_LSC_DONE_IRQ BIT(17)
+#define IRQ0STATUS_CCDC_LSC_PREF_COMP_IRQ BIT(18)
+#define IRQ0STATUS_CCDC_LSC_PREF_ERR_IRQ BIT(19)
+#define IRQ0STATUS_PRV_DONE_IRQ BIT(20)
+#define IRQ0STATUS_RSZ_DONE_IRQ BIT(24)
+#define IRQ0STATUS_OVF_IRQ BIT(25)
+#define IRQ0STATUS_PING_IRQ BIT(26)
+#define IRQ0STATUS_PONG_IRQ BIT(27)
+#define IRQ0STATUS_MMU_ERR_IRQ BIT(28)
+#define IRQ0STATUS_OCP_ERR_IRQ BIT(29)
+#define IRQ0STATUS_SEC_ERR_IRQ BIT(30)
+#define IRQ0STATUS_HS_VS_IRQ BIT(31)
#define TCTRL_GRESET_LEN 0
@@ -607,20 +607,20 @@
#define ISPCTRL_PAR_BRIDGE_MASK (0x3 << 2)
#define ISPCTRL_PAR_CLK_POL_SHIFT 4
-#define ISPCTRL_PAR_CLK_POL_INV (1 << 4)
-#define ISPCTRL_PING_PONG_EN (1 << 5)
+#define ISPCTRL_PAR_CLK_POL_INV BIT(4)
+#define ISPCTRL_PING_PONG_EN BIT(5)
#define ISPCTRL_SHIFT_SHIFT 6
#define ISPCTRL_SHIFT_0 (0x0 << 6)
#define ISPCTRL_SHIFT_2 (0x1 << 6)
#define ISPCTRL_SHIFT_4 (0x2 << 6)
#define ISPCTRL_SHIFT_MASK (0x3 << 6)
-#define ISPCTRL_CCDC_CLK_EN (1 << 8)
-#define ISPCTRL_SCMP_CLK_EN (1 << 9)
-#define ISPCTRL_H3A_CLK_EN (1 << 10)
-#define ISPCTRL_HIST_CLK_EN (1 << 11)
-#define ISPCTRL_PREV_CLK_EN (1 << 12)
-#define ISPCTRL_RSZ_CLK_EN (1 << 13)
+#define ISPCTRL_CCDC_CLK_EN BIT(8)
+#define ISPCTRL_SCMP_CLK_EN BIT(9)
+#define ISPCTRL_H3A_CLK_EN BIT(10)
+#define ISPCTRL_HIST_CLK_EN BIT(11)
+#define ISPCTRL_PREV_CLK_EN BIT(12)
+#define ISPCTRL_RSZ_CLK_EN BIT(13)
#define ISPCTRL_SYNC_DETECT_SHIFT 14
#define ISPCTRL_SYNC_DETECT_HSFALL (0x0 << ISPCTRL_SYNC_DETECT_SHIFT)
#define ISPCTRL_SYNC_DETECT_HSRISE (0x1 << ISPCTRL_SYNC_DETECT_SHIFT)
@@ -628,17 +628,17 @@
#define ISPCTRL_SYNC_DETECT_VSRISE (0x3 << ISPCTRL_SYNC_DETECT_SHIFT)
#define ISPCTRL_SYNC_DETECT_MASK (0x3 << ISPCTRL_SYNC_DETECT_SHIFT)
-#define ISPCTRL_CCDC_RAM_EN (1 << 16)
-#define ISPCTRL_PREV_RAM_EN (1 << 17)
-#define ISPCTRL_SBL_RD_RAM_EN (1 << 18)
-#define ISPCTRL_SBL_WR1_RAM_EN (1 << 19)
-#define ISPCTRL_SBL_WR0_RAM_EN (1 << 20)
-#define ISPCTRL_SBL_AUTOIDLE (1 << 21)
-#define ISPCTRL_SBL_SHARED_WPORTC (1 << 26)
-#define ISPCTRL_SBL_SHARED_RPORTA (1 << 27)
-#define ISPCTRL_SBL_SHARED_RPORTB (1 << 28)
-#define ISPCTRL_JPEG_FLUSH (1 << 30)
-#define ISPCTRL_CCDC_FLUSH (1 << 31)
+#define ISPCTRL_CCDC_RAM_EN BIT(16)
+#define ISPCTRL_PREV_RAM_EN BIT(17)
+#define ISPCTRL_SBL_RD_RAM_EN BIT(18)
+#define ISPCTRL_SBL_WR1_RAM_EN BIT(19)
+#define ISPCTRL_SBL_WR0_RAM_EN BIT(20)
+#define ISPCTRL_SBL_AUTOIDLE BIT(21)
+#define ISPCTRL_SBL_SHARED_WPORTC BIT(26)
+#define ISPCTRL_SBL_SHARED_RPORTA BIT(27)
+#define ISPCTRL_SBL_SHARED_RPORTB BIT(28)
+#define ISPCTRL_JPEG_FLUSH BIT(30)
+#define ISPCTRL_CCDC_FLUSH BIT(31)
#define ISPSECURE_SECUREMODE 0
@@ -655,20 +655,20 @@
#define ISPTCTRL_CTRL_DIVC_SHIFT 10
#define ISPTCTRL_CTRL_DIVC_NOCLOCK (0x0 << 10)
-#define ISPTCTRL_CTRL_SHUTEN (1 << 21)
-#define ISPTCTRL_CTRL_PSTRBEN (1 << 22)
-#define ISPTCTRL_CTRL_STRBEN (1 << 23)
-#define ISPTCTRL_CTRL_SHUTPOL (1 << 24)
-#define ISPTCTRL_CTRL_STRBPSTRBPOL (1 << 26)
+#define ISPTCTRL_CTRL_SHUTEN BIT(21)
+#define ISPTCTRL_CTRL_PSTRBEN BIT(22)
+#define ISPTCTRL_CTRL_STRBEN BIT(23)
+#define ISPTCTRL_CTRL_SHUTPOL BIT(24)
+#define ISPTCTRL_CTRL_STRBPSTRBPOL BIT(26)
#define ISPTCTRL_CTRL_INSEL_SHIFT 27
#define ISPTCTRL_CTRL_INSEL_PARALLEL (0x0 << 27)
#define ISPTCTRL_CTRL_INSEL_CSIA (0x1 << 27)
#define ISPTCTRL_CTRL_INSEL_CSIB (0x2 << 27)
-#define ISPTCTRL_CTRL_GRESETEn (1 << 29)
-#define ISPTCTRL_CTRL_GRESETPOL (1 << 30)
-#define ISPTCTRL_CTRL_GRESETDIR (1 << 31)
+#define ISPTCTRL_CTRL_GRESETEn BIT(29)
+#define ISPTCTRL_CTRL_GRESETPOL BIT(30)
+#define ISPTCTRL_CTRL_GRESETDIR BIT(31)
#define ISPTCTRL_FRAME_SHUT_SHIFT 0
#define ISPTCTRL_FRAME_PSTRB_SHIFT 6
@@ -679,33 +679,33 @@
#define ISPCCDC_PID_TID_SHIFT 16
#define ISPCCDC_PCR_EN 1
-#define ISPCCDC_PCR_BUSY (1 << 1)
+#define ISPCCDC_PCR_BUSY BIT(1)
#define ISPCCDC_SYN_MODE_VDHDOUT 0x1
-#define ISPCCDC_SYN_MODE_FLDOUT (1 << 1)
-#define ISPCCDC_SYN_MODE_VDPOL (1 << 2)
-#define ISPCCDC_SYN_MODE_HDPOL (1 << 3)
-#define ISPCCDC_SYN_MODE_FLDPOL (1 << 4)
-#define ISPCCDC_SYN_MODE_EXWEN (1 << 5)
-#define ISPCCDC_SYN_MODE_DATAPOL (1 << 6)
-#define ISPCCDC_SYN_MODE_FLDMODE (1 << 7)
+#define ISPCCDC_SYN_MODE_FLDOUT BIT(1)
+#define ISPCCDC_SYN_MODE_VDPOL BIT(2)
+#define ISPCCDC_SYN_MODE_HDPOL BIT(3)
+#define ISPCCDC_SYN_MODE_FLDPOL BIT(4)
+#define ISPCCDC_SYN_MODE_EXWEN BIT(5)
+#define ISPCCDC_SYN_MODE_DATAPOL BIT(6)
+#define ISPCCDC_SYN_MODE_FLDMODE BIT(7)
#define ISPCCDC_SYN_MODE_DATSIZ_MASK (0x7 << 8)
#define ISPCCDC_SYN_MODE_DATSIZ_8_16 (0x0 << 8)
#define ISPCCDC_SYN_MODE_DATSIZ_12 (0x4 << 8)
#define ISPCCDC_SYN_MODE_DATSIZ_11 (0x5 << 8)
#define ISPCCDC_SYN_MODE_DATSIZ_10 (0x6 << 8)
#define ISPCCDC_SYN_MODE_DATSIZ_8 (0x7 << 8)
-#define ISPCCDC_SYN_MODE_PACK8 (1 << 11)
+#define ISPCCDC_SYN_MODE_PACK8 BIT(11)
#define ISPCCDC_SYN_MODE_INPMOD_MASK (3 << 12)
#define ISPCCDC_SYN_MODE_INPMOD_RAW (0 << 12)
#define ISPCCDC_SYN_MODE_INPMOD_YCBCR16 (1 << 12)
#define ISPCCDC_SYN_MODE_INPMOD_YCBCR8 (2 << 12)
-#define ISPCCDC_SYN_MODE_LPF (1 << 14)
-#define ISPCCDC_SYN_MODE_FLDSTAT (1 << 15)
-#define ISPCCDC_SYN_MODE_VDHDEN (1 << 16)
-#define ISPCCDC_SYN_MODE_WEN (1 << 17)
-#define ISPCCDC_SYN_MODE_VP2SDR (1 << 18)
-#define ISPCCDC_SYN_MODE_SDR2RSZ (1 << 19)
+#define ISPCCDC_SYN_MODE_LPF BIT(14)
+#define ISPCCDC_SYN_MODE_FLDSTAT BIT(15)
+#define ISPCCDC_SYN_MODE_VDHDEN BIT(16)
+#define ISPCCDC_SYN_MODE_WEN BIT(17)
+#define ISPCCDC_SYN_MODE_VP2SDR BIT(18)
+#define ISPCCDC_SYN_MODE_SDR2RSZ BIT(19)
#define ISPCCDC_HD_VD_WID_VDW_SHIFT 0
#define ISPCCDC_HD_VD_WID_HDW_SHIFT 16
@@ -731,7 +731,7 @@
#define ISPCCDC_HSIZE_OFF_SHIFT 0
-#define ISPCCDC_SDOFST_FIINV (1 << 14)
+#define ISPCCDC_SDOFST_FIINV BIT(14)
#define ISPCCDC_SDOFST_FOFST_SHIFT 12
#define ISPCCDC_SDOFST_FOFST_MASK (3 << 12)
#define ISPCCDC_SDOFST_LOFST3_SHIFT 0
@@ -743,7 +743,7 @@
#define ISPCCDC_CLAMP_OBST_SHIFT 10
#define ISPCCDC_CLAMP_OBSLN_SHIFT 25
#define ISPCCDC_CLAMP_OBSLEN_SHIFT 28
-#define ISPCCDC_CLAMP_CLAMPEN (1 << 31)
+#define ISPCCDC_CLAMP_CLAMPEN BIT(31)
#define ISPCCDC_COLPTN_R_Ye 0x0
#define ISPCCDC_COLPTN_Gr_Cy 0x1
@@ -772,8 +772,8 @@
#define ISPCCDC_BLKCMP_R_YE_SHIFT 24
#define ISPCCDC_FPC_FPNUM_SHIFT 0
-#define ISPCCDC_FPC_FPCEN (1 << 15)
-#define ISPCCDC_FPC_FPERR (1 << 16)
+#define ISPCCDC_FPC_FPCEN BIT(15)
+#define ISPCCDC_FPC_FPERR BIT(16)
#define ISPCCDC_VDINT_1_SHIFT 0
#define ISPCCDC_VDINT_1_MASK 0x00007fff
@@ -784,23 +784,23 @@
#define ISPCCDC_ALAW_GWDI_11_2 (0x4 << 0)
#define ISPCCDC_ALAW_GWDI_10_1 (0x5 << 0)
#define ISPCCDC_ALAW_GWDI_9_0 (0x6 << 0)
-#define ISPCCDC_ALAW_CCDTBL (1 << 3)
+#define ISPCCDC_ALAW_CCDTBL BIT(3)
#define ISPCCDC_REC656IF_R656ON 1
-#define ISPCCDC_REC656IF_ECCFVH (1 << 1)
+#define ISPCCDC_REC656IF_ECCFVH BIT(1)
-#define ISPCCDC_CFG_BW656 (1 << 5)
+#define ISPCCDC_CFG_BW656 BIT(5)
#define ISPCCDC_CFG_FIDMD_SHIFT 6
-#define ISPCCDC_CFG_WENLOG (1 << 8)
+#define ISPCCDC_CFG_WENLOG BIT(8)
#define ISPCCDC_CFG_WENLOG_AND (0 << 8)
#define ISPCCDC_CFG_WENLOG_OR (1 << 8)
-#define ISPCCDC_CFG_Y8POS (1 << 11)
-#define ISPCCDC_CFG_BSWD (1 << 12)
-#define ISPCCDC_CFG_MSBINVI (1 << 13)
-#define ISPCCDC_CFG_VDLC (1 << 15)
+#define ISPCCDC_CFG_Y8POS BIT(11)
+#define ISPCCDC_CFG_BSWD BIT(12)
+#define ISPCCDC_CFG_MSBINVI BIT(13)
+#define ISPCCDC_CFG_VDLC BIT(15)
#define ISPCCDC_FMTCFG_FMTEN 0x1
-#define ISPCCDC_FMTCFG_LNALT (1 << 1)
+#define ISPCCDC_FMTCFG_LNALT BIT(1)
#define ISPCCDC_FMTCFG_LNUM_SHIFT 2
#define ISPCCDC_FMTCFG_PLEN_ODD_SHIFT 4
#define ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT 8
@@ -809,7 +809,7 @@
#define ISPCCDC_FMTCFG_VPIN_11_2 (0x4 << 12)
#define ISPCCDC_FMTCFG_VPIN_10_1 (0x5 << 12)
#define ISPCCDC_FMTCFG_VPIN_9_0 (0x6 << 12)
-#define ISPCCDC_FMTCFG_VPEN (1 << 15)
+#define ISPCCDC_FMTCFG_VPEN BIT(15)
#define ISPCCDC_FMTCFG_VPIF_FRQ_MASK 0x003f0000
#define ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT 16
@@ -839,9 +839,9 @@
#define ISPRSZ_PID_CID_SHIFT 8
#define ISPRSZ_PID_TID_SHIFT 16
-#define ISPRSZ_PCR_ENABLE (1 << 0)
-#define ISPRSZ_PCR_BUSY (1 << 1)
-#define ISPRSZ_PCR_ONESHOT (1 << 2)
+#define ISPRSZ_PCR_ENABLE BIT(0)
+#define ISPRSZ_PCR_BUSY BIT(1)
+#define ISPRSZ_PCR_ONESHOT BIT(2)
#define ISPRSZ_CNT_HRSZ_SHIFT 0
#define ISPRSZ_CNT_HRSZ_MASK \
@@ -853,10 +853,10 @@
#define ISPRSZ_CNT_HSTPH_MASK (0x7 << ISPRSZ_CNT_HSTPH_SHIFT)
#define ISPRSZ_CNT_VSTPH_SHIFT 23
#define ISPRSZ_CNT_VSTPH_MASK (0x7 << ISPRSZ_CNT_VSTPH_SHIFT)
-#define ISPRSZ_CNT_YCPOS (1 << 26)
-#define ISPRSZ_CNT_INPTYP (1 << 27)
-#define ISPRSZ_CNT_INPSRC (1 << 28)
-#define ISPRSZ_CNT_CBILIN (1 << 29)
+#define ISPRSZ_CNT_YCPOS BIT(26)
+#define ISPRSZ_CNT_INPTYP BIT(27)
+#define ISPRSZ_CNT_INPSRC BIT(28)
+#define ISPRSZ_CNT_CBILIN BIT(29)
#define ISPRSZ_OUT_SIZE_HORZ_SHIFT 0
#define ISPRSZ_OUT_SIZE_HORZ_MASK \
@@ -1081,8 +1081,8 @@
#define ISPH3A_PCR_AF_RGBPOS_SHIFT 11
#define ISPH3A_PCR_AEW_AVE2LMT_SHIFT 22
#define ISPH3A_PCR_AEW_AVE2LMT_MASK 0xFFC00000
-#define ISPH3A_PCR_BUSYAF (1 << 15)
-#define ISPH3A_PCR_BUSYAEAWB (1 << 18)
+#define ISPH3A_PCR_BUSYAF BIT(15)
+#define ISPH3A_PCR_BUSYAEAWB BIT(18)
#define ISPH3A_AEWWIN1_WINHC_SHIFT 0
#define ISPH3A_AEWWIN1_WINHC_MASK 0x3F
@@ -1166,15 +1166,15 @@
#define ISPHIST_HV_INFO_MASK 0x3FFF3FFF
-#define ISPCCDC_LSC_ENABLE 1
-#define ISPCCDC_LSC_BUSY (1 << 7)
+#define ISPCCDC_LSC_ENABLE BIT(0)
+#define ISPCCDC_LSC_BUSY BIT(7)
#define ISPCCDC_LSC_GAIN_MODE_N_MASK 0x700
#define ISPCCDC_LSC_GAIN_MODE_N_SHIFT 8
#define ISPCCDC_LSC_GAIN_MODE_M_MASK 0x3800
#define ISPCCDC_LSC_GAIN_MODE_M_SHIFT 12
#define ISPCCDC_LSC_GAIN_FORMAT_MASK 0xE
#define ISPCCDC_LSC_GAIN_FORMAT_SHIFT 1
-#define ISPCCDC_LSC_AFTER_REFORMATTER_MASK (1<<6)
+#define ISPCCDC_LSC_AFTER_REFORMATTER_MASK BIT(6)
#define ISPCCDC_LSC_INITIAL_X_MASK 0x3F
#define ISPCCDC_LSC_INITIAL_X_SHIFT 0
@@ -1196,43 +1196,43 @@
(0x1 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
#define ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART \
(0x2 << ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SHIFT)
-#define ISPCSI2_SYSCONFIG_SOFT_RESET (1 << 1)
-#define ISPCSI2_SYSCONFIG_AUTO_IDLE (1 << 0)
+#define ISPCSI2_SYSCONFIG_SOFT_RESET BIT(1)
+#define ISPCSI2_SYSCONFIG_AUTO_IDLE BIT(0)
#define ISPCSI2_SYSSTATUS (0x014)
-#define ISPCSI2_SYSSTATUS_RESET_DONE (1 << 0)
+#define ISPCSI2_SYSSTATUS_RESET_DONE BIT(0)
#define ISPCSI2_IRQSTATUS (0x018)
-#define ISPCSI2_IRQSTATUS_OCP_ERR_IRQ (1 << 14)
-#define ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ (1 << 13)
-#define ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 12)
-#define ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ (1 << 11)
-#define ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ (1 << 10)
-#define ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ (1 << 9)
-#define ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ (1 << 8)
-#define ISPCSI2_IRQSTATUS_CONTEXT(n) (1 << (n))
+#define ISPCSI2_IRQSTATUS_OCP_ERR_IRQ BIT(14)
+#define ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ BIT(13)
+#define ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ BIT(12)
+#define ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ BIT(11)
+#define ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ BIT(10)
+#define ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ BIT(9)
+#define ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ BIT(8)
+#define ISPCSI2_IRQSTATUS_CONTEXT(n) BIT(n)
#define ISPCSI2_IRQENABLE (0x01c)
#define ISPCSI2_CTRL (0x040)
-#define ISPCSI2_CTRL_VP_CLK_EN (1 << 15)
-#define ISPCSI2_CTRL_VP_ONLY_EN (1 << 11)
+#define ISPCSI2_CTRL_VP_CLK_EN BIT(15)
+#define ISPCSI2_CTRL_VP_ONLY_EN BIT(11)
#define ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT 8
#define ISPCSI2_CTRL_VP_OUT_CTRL_MASK \
(3 << ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT)
-#define ISPCSI2_CTRL_DBG_EN (1 << 7)
+#define ISPCSI2_CTRL_DBG_EN BIT(7)
#define ISPCSI2_CTRL_BURST_SIZE_SHIFT 5
#define ISPCSI2_CTRL_BURST_SIZE_MASK \
(3 << ISPCSI2_CTRL_BURST_SIZE_SHIFT)
-#define ISPCSI2_CTRL_FRAME (1 << 3)
-#define ISPCSI2_CTRL_ECC_EN (1 << 2)
-#define ISPCSI2_CTRL_SECURE (1 << 1)
-#define ISPCSI2_CTRL_IF_EN (1 << 0)
+#define ISPCSI2_CTRL_FRAME BIT(3)
+#define ISPCSI2_CTRL_ECC_EN BIT(2)
+#define ISPCSI2_CTRL_SECURE BIT(1)
+#define ISPCSI2_CTRL_IF_EN BIT(0)
#define ISPCSI2_DBG_H (0x044)
#define ISPCSI2_GNQ (0x048)
#define ISPCSI2_PHY_CFG (0x050)
-#define ISPCSI2_PHY_CFG_RESET_CTRL (1 << 30)
-#define ISPCSI2_PHY_CFG_RESET_DONE (1 << 29)
+#define ISPCSI2_PHY_CFG_RESET_CTRL BIT(30)
+#define ISPCSI2_PHY_CFG_RESET_DONE BIT(29)
#define ISPCSI2_PHY_CFG_PWR_CMD_SHIFT 27
#define ISPCSI2_PHY_CFG_PWR_CMD_MASK \
(0x3 << ISPCSI2_PHY_CFG_PWR_CMD_SHIFT)
@@ -1251,7 +1251,7 @@
(0x1 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
#define ISPCSI2_PHY_CFG_PWR_STATUS_ULPW \
(0x2 << ISPCSI2_PHY_CFG_PWR_STATUS_SHIFT)
-#define ISPCSI2_PHY_CFG_PWR_AUTO (1 << 24)
+#define ISPCSI2_PHY_CFG_PWR_AUTO BIT(24)
#define ISPCSI2_PHY_CFG_DATA_POL_SHIFT(n) (3 + ((n) * 4))
#define ISPCSI2_PHY_CFG_DATA_POL_MASK(n) \
@@ -1300,63 +1300,63 @@
(0x5 << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT)
#define ISPCSI2_PHY_IRQSTATUS (0x054)
-#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMEXIT (1 << 26)
-#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMENTER (1 << 25)
-#define ISPCSI2_PHY_IRQSTATUS_STATEULPM5 (1 << 24)
-#define ISPCSI2_PHY_IRQSTATUS_STATEULPM4 (1 << 23)
-#define ISPCSI2_PHY_IRQSTATUS_STATEULPM3 (1 << 22)
-#define ISPCSI2_PHY_IRQSTATUS_STATEULPM2 (1 << 21)
-#define ISPCSI2_PHY_IRQSTATUS_STATEULPM1 (1 << 20)
-#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL5 (1 << 19)
-#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL4 (1 << 18)
-#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL3 (1 << 17)
-#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL2 (1 << 16)
-#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL1 (1 << 15)
-#define ISPCSI2_PHY_IRQSTATUS_ERRESC5 (1 << 14)
-#define ISPCSI2_PHY_IRQSTATUS_ERRESC4 (1 << 13)
-#define ISPCSI2_PHY_IRQSTATUS_ERRESC3 (1 << 12)
-#define ISPCSI2_PHY_IRQSTATUS_ERRESC2 (1 << 11)
-#define ISPCSI2_PHY_IRQSTATUS_ERRESC1 (1 << 10)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS5 (1 << 9)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS4 (1 << 8)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS3 (1 << 7)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS2 (1 << 6)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS1 (1 << 5)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS5 (1 << 4)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS4 (1 << 3)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS3 (1 << 2)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS2 (1 << 1)
-#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS1 1
+#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMEXIT BIT(26)
+#define ISPCSI2_PHY_IRQSTATUS_STATEALLULPMENTER BIT(25)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM5 BIT(24)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM4 BIT(23)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM3 BIT(22)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM2 BIT(21)
+#define ISPCSI2_PHY_IRQSTATUS_STATEULPM1 BIT(20)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL5 BIT(19)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL4 BIT(18)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL3 BIT(17)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL2 BIT(16)
+#define ISPCSI2_PHY_IRQSTATUS_ERRCONTROL1 BIT(15)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC5 BIT(14)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC4 BIT(13)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC3 BIT(12)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC2 BIT(11)
+#define ISPCSI2_PHY_IRQSTATUS_ERRESC1 BIT(10)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS5 BIT(9)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS4 BIT(8)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS3 BIT(7)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS2 BIT(6)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTSYNCHS1 BIT(5)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS5 BIT(4)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS4 BIT(3)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS3 BIT(2)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS2 BIT(1)
+#define ISPCSI2_PHY_IRQSTATUS_ERRSOTHS1 BIT(0)
#define ISPCSI2_SHORT_PACKET (0x05c)
#define ISPCSI2_PHY_IRQENABLE (0x060)
-#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT (1 << 26)
-#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER (1 << 25)
-#define ISPCSI2_PHY_IRQENABLE_STATEULPM5 (1 << 24)
-#define ISPCSI2_PHY_IRQENABLE_STATEULPM4 (1 << 23)
-#define ISPCSI2_PHY_IRQENABLE_STATEULPM3 (1 << 22)
-#define ISPCSI2_PHY_IRQENABLE_STATEULPM2 (1 << 21)
-#define ISPCSI2_PHY_IRQENABLE_STATEULPM1 (1 << 20)
-#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 (1 << 19)
-#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 (1 << 18)
-#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 (1 << 17)
-#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 (1 << 16)
-#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 (1 << 15)
-#define ISPCSI2_PHY_IRQENABLE_ERRESC5 (1 << 14)
-#define ISPCSI2_PHY_IRQENABLE_ERRESC4 (1 << 13)
-#define ISPCSI2_PHY_IRQENABLE_ERRESC3 (1 << 12)
-#define ISPCSI2_PHY_IRQENABLE_ERRESC2 (1 << 11)
-#define ISPCSI2_PHY_IRQENABLE_ERRESC1 (1 << 10)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 (1 << 9)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 (1 << 8)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 (1 << 7)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 (1 << 6)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 (1 << 5)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 (1 << 4)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 (1 << 3)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 (1 << 2)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 (1 << 1)
-#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS1 (1 << 0)
+#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMEXIT BIT(26)
+#define ISPCSI2_PHY_IRQENABLE_STATEALLULPMENTER BIT(25)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM5 BIT(24)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM4 BIT(23)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM3 BIT(22)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM2 BIT(21)
+#define ISPCSI2_PHY_IRQENABLE_STATEULPM1 BIT(20)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL5 BIT(19)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL4 BIT(18)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL3 BIT(17)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL2 BIT(16)
+#define ISPCSI2_PHY_IRQENABLE_ERRCONTROL1 BIT(15)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC5 BIT(14)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC4 BIT(13)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC3 BIT(12)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC2 BIT(11)
+#define ISPCSI2_PHY_IRQENABLE_ERRESC1 BIT(10)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS5 BIT(9)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS4 BIT(8)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS3 BIT(7)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS2 BIT(6)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTSYNCHS1 BIT(5)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS5 BIT(4)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS4 BIT(3)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS3 BIT(2)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS2 BIT(1)
+#define ISPCSI2_PHY_IRQENABLE_ERRSOTHS1 BIT(0)
#define ISPCSI2_DBG_P (0x068)
#define ISPCSI2_TIMING (0x06c)
@@ -1371,12 +1371,12 @@
#define ISPCSI2_CTX_CTRL1_COUNT_SHIFT 8
#define ISPCSI2_CTX_CTRL1_COUNT_MASK \
(0xff << ISPCSI2_CTX_CTRL1_COUNT_SHIFT)
-#define ISPCSI2_CTX_CTRL1_EOF_EN (1 << 7)
-#define ISPCSI2_CTX_CTRL1_EOL_EN (1 << 6)
-#define ISPCSI2_CTX_CTRL1_CS_EN (1 << 5)
-#define ISPCSI2_CTX_CTRL1_COUNT_UNLOCK (1 << 4)
-#define ISPCSI2_CTX_CTRL1_PING_PONG (1 << 3)
-#define ISPCSI2_CTX_CTRL1_CTX_EN (1 << 0)
+#define ISPCSI2_CTX_CTRL1_EOF_EN BIT(7)
+#define ISPCSI2_CTX_CTRL1_EOL_EN BIT(6)
+#define ISPCSI2_CTX_CTRL1_CS_EN BIT(5)
+#define ISPCSI2_CTX_CTRL1_COUNT_UNLOCK BIT(4)
+#define ISPCSI2_CTX_CTRL1_PING_PONG BIT(3)
+#define ISPCSI2_CTX_CTRL1_CTX_EN BIT(0)
#define ISPCSI2_CTX_CTRL2(n) ((0x074) + 0x20 * (n))
#define ISPCSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13
@@ -1385,7 +1385,7 @@
#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT 11
#define ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK \
(0x3 << ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT)
-#define ISPCSI2_CTX_CTRL2_DPCM_PRED (1 << 10)
+#define ISPCSI2_CTX_CTRL2_DPCM_PRED BIT(10)
#define ISPCSI2_CTX_CTRL2_FORMAT_SHIFT 0
#define ISPCSI2_CTX_CTRL2_FORMAT_MASK \
(0x3ff << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT)
@@ -1401,24 +1401,24 @@
#define ISPCSI2_CTX_DAT_PING_ADDR(n) ((0x07c) + 0x20 * (n))
#define ISPCSI2_CTX_DAT_PONG_ADDR(n) ((0x080) + 0x20 * (n))
#define ISPCSI2_CTX_IRQENABLE(n) ((0x084) + 0x20 * (n))
-#define ISPCSI2_CTX_IRQENABLE_ECC_CORRECTION_IRQ (1 << 8)
-#define ISPCSI2_CTX_IRQENABLE_LINE_NUMBER_IRQ (1 << 7)
-#define ISPCSI2_CTX_IRQENABLE_FRAME_NUMBER_IRQ (1 << 6)
-#define ISPCSI2_CTX_IRQENABLE_CS_IRQ (1 << 5)
-#define ISPCSI2_CTX_IRQENABLE_LE_IRQ (1 << 3)
-#define ISPCSI2_CTX_IRQENABLE_LS_IRQ (1 << 2)
-#define ISPCSI2_CTX_IRQENABLE_FE_IRQ (1 << 1)
-#define ISPCSI2_CTX_IRQENABLE_FS_IRQ (1 << 0)
+#define ISPCSI2_CTX_IRQENABLE_ECC_CORRECTION_IRQ BIT(8)
+#define ISPCSI2_CTX_IRQENABLE_LINE_NUMBER_IRQ BIT(7)
+#define ISPCSI2_CTX_IRQENABLE_FRAME_NUMBER_IRQ BIT(6)
+#define ISPCSI2_CTX_IRQENABLE_CS_IRQ BIT(5)
+#define ISPCSI2_CTX_IRQENABLE_LE_IRQ BIT(3)
+#define ISPCSI2_CTX_IRQENABLE_LS_IRQ BIT(2)
+#define ISPCSI2_CTX_IRQENABLE_FE_IRQ BIT(1)
+#define ISPCSI2_CTX_IRQENABLE_FS_IRQ BIT(0)
#define ISPCSI2_CTX_IRQSTATUS(n) ((0x088) + 0x20 * (n))
-#define ISPCSI2_CTX_IRQSTATUS_ECC_CORRECTION_IRQ (1 << 8)
-#define ISPCSI2_CTX_IRQSTATUS_LINE_NUMBER_IRQ (1 << 7)
-#define ISPCSI2_CTX_IRQSTATUS_FRAME_NUMBER_IRQ (1 << 6)
-#define ISPCSI2_CTX_IRQSTATUS_CS_IRQ (1 << 5)
-#define ISPCSI2_CTX_IRQSTATUS_LE_IRQ (1 << 3)
-#define ISPCSI2_CTX_IRQSTATUS_LS_IRQ (1 << 2)
-#define ISPCSI2_CTX_IRQSTATUS_FE_IRQ (1 << 1)
-#define ISPCSI2_CTX_IRQSTATUS_FS_IRQ (1 << 0)
+#define ISPCSI2_CTX_IRQSTATUS_ECC_CORRECTION_IRQ BIT(8)
+#define ISPCSI2_CTX_IRQSTATUS_LINE_NUMBER_IRQ BIT(7)
+#define ISPCSI2_CTX_IRQSTATUS_FRAME_NUMBER_IRQ BIT(6)
+#define ISPCSI2_CTX_IRQSTATUS_CS_IRQ BIT(5)
+#define ISPCSI2_CTX_IRQSTATUS_LE_IRQ BIT(3)
+#define ISPCSI2_CTX_IRQSTATUS_LS_IRQ BIT(2)
+#define ISPCSI2_CTX_IRQSTATUS_FE_IRQ BIT(1)
+#define ISPCSI2_CTX_IRQSTATUS_FS_IRQ BIT(0)
#define ISPCSI2_CTX_CTRL3(n) ((0x08c) + 0x20 * (n))
#define ISPCSI2_CTX_CTRL3_ALPHA_SHIFT 5
@@ -1454,9 +1454,9 @@
(0xff << ISPCSIPHY_REG0_THS_SETTLE_SHIFT)
#define ISPCSIPHY_REG1 (0x004)
-#define ISPCSIPHY_REG1_RESET_DONE_CTRLCLK (1 << 29)
+#define ISPCSIPHY_REG1_RESET_DONE_CTRLCLK BIT(29)
/* This field is for OMAP3630 only */
-#define ISPCSIPHY_REG1_CLOCK_MISS_DETECTOR_STATUS (1 << 25)
+#define ISPCSIPHY_REG1_CLOCK_MISS_DETECTOR_STATUS BIT(25)
#define ISPCSIPHY_REG1_TCLK_TERM_SHIFT 18
#define ISPCSIPHY_REG1_TCLK_TERM_MASK \
(0x7f << ISPCSIPHY_REG1_TCLK_TERM_SHIFT)
@@ -1498,11 +1498,11 @@
*/
/* OMAP343X_CONTROL_CSIRXFE */
-#define OMAP343X_CONTROL_CSIRXFE_CSIB_INV (1 << 7)
-#define OMAP343X_CONTROL_CSIRXFE_RESENABLE (1 << 8)
-#define OMAP343X_CONTROL_CSIRXFE_SELFORM (1 << 10)
-#define OMAP343X_CONTROL_CSIRXFE_PWRDNZ (1 << 12)
-#define OMAP343X_CONTROL_CSIRXFE_RESET (1 << 13)
+#define OMAP343X_CONTROL_CSIRXFE_CSIB_INV BIT(7)
+#define OMAP343X_CONTROL_CSIRXFE_RESENABLE BIT(8)
+#define OMAP343X_CONTROL_CSIRXFE_SELFORM BIT(10)
+#define OMAP343X_CONTROL_CSIRXFE_PWRDNZ BIT(12)
+#define OMAP343X_CONTROL_CSIRXFE_RESET BIT(13)
/* OMAP3630_CONTROL_CAMERA_PHY_CTRL */
#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT 2
@@ -1513,6 +1513,6 @@
#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_GPI 0x3
#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK 0x3
/* CCP2B: set to receive data from PHY2 instead of PHY1 */
-#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2 (1 << 4)
+#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2 BIT(4)
#endif /* OMAP3_ISP_REG_H */
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index 21ca6954df72..78d9dd7ea2da 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -1681,6 +1681,7 @@ int omap3isp_resizer_register_entities(struct isp_res_device *res,
int ret;
/* Register the subdev and video nodes. */
+ res->subdev.dev = vdev->mdev->dev;
ret = v4l2_device_register_subdev(vdev, &res->subdev);
if (ret < 0)
goto error;
diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c
index 62b2eacb96fd..5b9b57f4d9bf 100644
--- a/drivers/media/platform/omap3isp/ispstat.c
+++ b/drivers/media/platform/omap3isp/ispstat.c
@@ -1026,6 +1026,8 @@ void omap3isp_stat_unregister_entities(struct ispstat *stat)
int omap3isp_stat_register_entities(struct ispstat *stat,
struct v4l2_device *vdev)
{
+ stat->subdev.dev = vdev->mdev->dev;
+
return v4l2_device_register_subdev(vdev, &stat->subdev);
}
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 499a7284c5a8..ee183c35ff3b 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -658,10 +658,6 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
| V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- else
- cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
return 0;
}
@@ -1024,8 +1020,8 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
ctrls.count = 1;
ctrls.controls = &ctrl;
-
- ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, NULL, &ctrls);
+ ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &video->video,
+ NULL, &ctrls);
if (ret < 0) {
dev_warn(isp->dev, "no pixel rate control in subdev %s\n",
pipe->external->name);
@@ -1460,6 +1456,13 @@ int omap3isp_video_init(struct isp_video *video, const char *name)
video->video.vfl_type = VFL_TYPE_GRABBER;
video->video.release = video_device_release_empty;
video->video.ioctl_ops = &isp_video_ioctl_ops;
+ if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE
+ | V4L2_CAP_STREAMING;
+ else
+ video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT
+ | V4L2_CAP_STREAMING;
+
video->pipe.stream_state = ISP_PIPELINE_STREAM_STOPPED;
video_set_drvdata(&video->video, video);
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index 1c9bfaabc54c..43ae645d866b 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -64,7 +64,7 @@
#define CIBR1 0x0030
#define CIBR2 0x0038
-#define CICR0_DMAEN (1 << 31) /* DMA request enable */
+#define CICR0_DMAEN (1UL << 31) /* DMA request enable */
#define CICR0_PAR_EN (1 << 30) /* Parity enable */
#define CICR0_SL_CAP_EN (1 << 29) /* Capture enable for slave mode */
#define CICR0_ENB (1 << 28) /* Camera interface enable */
@@ -81,7 +81,7 @@
#define CICR0_EOFM (1 << 1) /* End-of-frame mask */
#define CICR0_FOM (1 << 0) /* FIFO-overrun mask */
-#define CICR1_TBIT (1 << 31) /* Transparency bit */
+#define CICR1_TBIT (1UL << 31) /* Transparency bit */
#define CICR1_RGBT_CONV (0x3 << 29) /* RGBT conversion mask */
#define CICR1_PPL (0x7ff << 15) /* Pixels per line mask */
#define CICR1_RGB_CONV (0x7 << 12) /* RGB conversion mask */
@@ -1992,9 +1992,6 @@ static int pxac_vidioc_querycap(struct file *file, void *priv,
strscpy(cap->bus_info, "platform:pxa-camera", sizeof(cap->bus_info));
strscpy(cap->driver, PXA_CAM_DRV_NAME, sizeof(cap->driver));
strscpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -2533,6 +2530,7 @@ exit_free_v4l2dev:
v4l2_device_unregister(&pcdev->v4l2_dev);
exit_deactivate:
pxa_camera_deactivate(pcdev);
+ tasklet_kill(&pcdev->task_eof);
exit_free_dma:
dma_release_channel(pcdev->dma_chans[2]);
exit_free_dma_u:
@@ -2547,6 +2545,7 @@ static int pxa_camera_remove(struct platform_device *pdev)
struct pxa_camera_dev *pcdev = dev_get_drvdata(&pdev->dev);
pxa_camera_deactivate(pcdev);
+ tasklet_kill(&pcdev->task_eof);
dma_release_channel(pcdev->dma_chans[0]);
dma_release_channel(pcdev->dma_chans[1]);
dma_release_channel(pcdev->dma_chans[2]);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 63da18773d24..3fdc9f964a3c 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -486,9 +486,9 @@ static int camss_of_parse_ports(struct camss *camss)
asd = v4l2_async_notifier_add_fwnode_subdev(
&camss->notifier, of_fwnode_handle(remote),
sizeof(*csd));
+ of_node_put(remote);
if (IS_ERR(asd)) {
ret = PTR_ERR(asd);
- of_node_put(remote);
goto err_cleanup;
}
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 0acc7576cc58..07312a2fab24 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -5,6 +5,7 @@
*/
#include <linux/clk.h>
#include <linux/init.h>
+#include <linux/interconnect.h>
#include <linux/ioctl.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -198,7 +199,7 @@ static int venus_enumerate_codecs(struct venus_core *core, u32 type)
goto err;
for (i = 0; i < MAX_CODEC_NUM; i++) {
- codec = (1 << i) & codecs;
+ codec = (1UL << i) & codecs;
if (!codec)
continue;
@@ -239,6 +240,14 @@ static int venus_probe(struct platform_device *pdev)
if (IS_ERR(core->base))
return PTR_ERR(core->base);
+ core->video_path = of_icc_get(dev, "video-mem");
+ if (IS_ERR(core->video_path))
+ return PTR_ERR(core->video_path);
+
+ core->cpucfg_path = of_icc_get(dev, "cpu-cfg");
+ if (IS_ERR(core->cpucfg_path))
+ return PTR_ERR(core->cpucfg_path);
+
core->irq = platform_get_irq(pdev, 0);
if (core->irq < 0)
return core->irq;
@@ -273,6 +282,10 @@ static int venus_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ret = icc_set_bw(core->cpucfg_path, 0, kbps_to_icc(1000));
+ if (ret)
+ return ret;
+
ret = hfi_create(core, &venus_core_ops);
if (ret)
return ret;
@@ -355,6 +368,9 @@ static int venus_remove(struct platform_device *pdev)
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
+ icc_put(core->video_path);
+ icc_put(core->cpucfg_path);
+
v4l2_device_unregister(&core->v4l2_dev);
return ret;
@@ -427,10 +443,11 @@ static const struct venus_resources msm8916_res = {
};
static const struct freq_tbl msm8996_freq_table[] = {
- { 1944000, 490000000 }, /* 4k UHD @ 60 */
- { 972000, 320000000 }, /* 4k UHD @ 30 */
- { 489600, 150000000 }, /* 1080p @ 60 */
- { 244800, 75000000 }, /* 1080p @ 30 */
+ { 1944000, 520000000 }, /* 4k UHD @ 60 (decode only) */
+ { 972000, 520000000 }, /* 4k UHD @ 30 */
+ { 489600, 346666667 }, /* 1080p @ 60 */
+ { 244800, 150000000 }, /* 1080p @ 30 */
+ { 108000, 75000000 }, /* 720p @ 30 */
};
static const struct reg_val msm8996_reg_preset[] = {
@@ -464,9 +481,40 @@ static const struct freq_tbl sdm845_freq_table[] = {
{ 244800, 100000000 }, /* 1920x1080@30 */
};
+static struct codec_freq_data sdm845_codec_freq_data[] = {
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10 },
+ { V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10 },
+ { V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10 },
+ { V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10 },
+ { V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10 },
+ { V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10 },
+};
+
+static const struct bw_tbl sdm845_bw_table_enc[] = {
+ { 1944000, 1612000, 0, 2416000, 0 }, /* 3840x2160@60 */
+ { 972000, 951000, 0, 1434000, 0 }, /* 3840x2160@30 */
+ { 489600, 723000, 0, 973000, 0 }, /* 1920x1080@60 */
+ { 244800, 370000, 0, 495000, 0 }, /* 1920x1080@30 */
+};
+
+static const struct bw_tbl sdm845_bw_table_dec[] = {
+ { 2073600, 3929000, 0, 5551000, 0 }, /* 4096x2160@60 */
+ { 1036800, 1987000, 0, 2797000, 0 }, /* 4096x2160@30 */
+ { 489600, 1040000, 0, 1298000, 0 }, /* 1920x1080@60 */
+ { 244800, 530000, 0, 659000, 0 }, /* 1920x1080@30 */
+};
+
static const struct venus_resources sdm845_res = {
.freq_tbl = sdm845_freq_table,
.freq_tbl_size = ARRAY_SIZE(sdm845_freq_table),
+ .bw_tbl_enc = sdm845_bw_table_enc,
+ .bw_tbl_enc_size = ARRAY_SIZE(sdm845_bw_table_enc),
+ .bw_tbl_dec = sdm845_bw_table_dec,
+ .bw_tbl_dec_size = ARRAY_SIZE(sdm845_bw_table_dec),
+ .codec_freq_data = sdm845_codec_freq_data,
+ .codec_freq_data_size = ARRAY_SIZE(sdm845_codec_freq_data),
.clks = {"core", "iface", "bus" },
.clks_num = 3,
.max_load = 3110400, /* 4096x2160@90 */
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 9ab95fd57760..11585fb3cae3 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -26,12 +26,33 @@ struct reg_val {
u32 value;
};
+struct codec_freq_data {
+ u32 pixfmt;
+ u32 session_type;
+ unsigned long vpp_freq;
+ unsigned long vsp_freq;
+};
+
+struct bw_tbl {
+ u32 mbs_per_sec;
+ u32 avg;
+ u32 peak;
+ u32 avg_10bit;
+ u32 peak_10bit;
+};
+
struct venus_resources {
u64 dma_mask;
const struct freq_tbl *freq_tbl;
unsigned int freq_tbl_size;
+ const struct bw_tbl *bw_tbl_enc;
+ unsigned int bw_tbl_enc_size;
+ const struct bw_tbl *bw_tbl_dec;
+ unsigned int bw_tbl_dec_size;
const struct reg_val *reg_tbl;
unsigned int reg_tbl_size;
+ const struct codec_freq_data *codec_freq_data;
+ unsigned int codec_freq_data_size;
const char * const clks[VIDC_CLKS_NUM_MAX];
unsigned int clks_num;
enum hfi_version hfi_version;
@@ -46,6 +67,7 @@ struct venus_format {
u32 pixfmt;
unsigned int num_planes;
u32 type;
+ u32 flags;
};
#define MAX_PLANES 4
@@ -114,6 +136,8 @@ struct venus_core {
struct clk *core1_clk;
struct clk *core0_bus_clk;
struct clk *core1_bus_clk;
+ struct icc_path *video_path;
+ struct icc_path *cpucfg_path;
struct video_device *vdev_dec;
struct video_device *vdev_enc;
struct v4l2_device v4l2_dev;
@@ -207,8 +231,33 @@ struct venus_buffer {
struct list_head ref_list;
};
+struct clock_data {
+ u32 core_id;
+ unsigned long freq;
+ const struct codec_freq_data *codec_freq_data;
+};
+
#define to_venus_buffer(ptr) container_of(ptr, struct venus_buffer, vb)
+enum venus_dec_state {
+ VENUS_DEC_STATE_DEINIT = 0,
+ VENUS_DEC_STATE_INIT = 1,
+ VENUS_DEC_STATE_CAPTURE_SETUP = 2,
+ VENUS_DEC_STATE_STOPPED = 3,
+ VENUS_DEC_STATE_SEEK = 4,
+ VENUS_DEC_STATE_DRAIN = 5,
+ VENUS_DEC_STATE_DECODING = 6,
+ VENUS_DEC_STATE_DRC = 7
+};
+
+struct venus_ts_metadata {
+ bool used;
+ u64 ts_ns;
+ u64 ts_us;
+ u32 flags;
+ struct v4l2_timecode tc;
+};
+
/**
* struct venus_inst - holds per instance parameters
*
@@ -232,6 +281,10 @@ struct venus_buffer {
* @colorspace: current color space
* @quantization: current quantization
* @xfer_func: current xfer function
+ * @codec_state: current codec API state (see DEC/ENC_STATE_)
+ * @reconf_wait: wait queue for resolution change event
+ * @subscriptions: used to hold current events subscriptions
+ * @buf_count: used to count number of buffers (reqbuf(0))
* @fps: holds current FPS
* @timeperframe: holds current time per frame structure
* @fmt_out: a reference to output format structure
@@ -246,8 +299,6 @@ struct venus_buffer {
* @opb_buftype: output picture buffer type
* @opb_fmt: output picture buffer raw format
* @reconfig: a flag raised by decoder when the stream resolution changed
- * @reconfig_width: holds the new width
- * @reconfig_height: holds the new height
* @hfi_codec: current codec for this instance in HFI space
* @sequence_cap: a sequence counter for capture queue
* @sequence_out: a sequence counter for output queue
@@ -266,6 +317,7 @@ struct venus_inst {
struct list_head list;
struct mutex lock;
struct venus_core *core;
+ struct clock_data clk_data;
struct list_head dpbbufs;
struct list_head internalbufs;
struct list_head registeredbufs;
@@ -287,6 +339,11 @@ struct venus_inst {
u8 ycbcr_enc;
u8 quantization;
u8 xfer_func;
+ enum venus_dec_state codec_state;
+ wait_queue_head_t reconf_wait;
+ unsigned int subscriptions;
+ int buf_count;
+ struct venus_ts_metadata tss[VIDEO_MAX_FRAME];
u64 fps;
struct v4l2_fract timeperframe;
const struct venus_format *fmt_out;
@@ -301,8 +358,6 @@ struct venus_inst {
u32 opb_buftype;
u32 opb_fmt;
bool reconfig;
- u32 reconfig_width;
- u32 reconfig_height;
u32 hfi_codec;
u32 sequence_cap;
u32 sequence_out;
diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index 71b06dfc6dc4..a172f1ac0b35 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -5,6 +5,7 @@
*/
#include <linux/clk.h>
#include <linux/iopoll.h>
+#include <linux/interconnect.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
@@ -79,7 +80,7 @@ bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt)
}
EXPORT_SYMBOL_GPL(venus_helper_check_codec);
-static int venus_helper_queue_dpb_bufs(struct venus_inst *inst)
+int venus_helper_queue_dpb_bufs(struct venus_inst *inst)
{
struct intbuf *buf;
int ret = 0;
@@ -100,6 +101,7 @@ static int venus_helper_queue_dpb_bufs(struct venus_inst *inst)
fail:
return ret;
}
+EXPORT_SYMBOL_GPL(venus_helper_queue_dpb_bufs);
int venus_helper_free_dpb_bufs(struct venus_inst *inst)
{
@@ -278,7 +280,7 @@ static const unsigned int intbuf_types_4xx[] = {
HFI_BUFFER_INTERNAL_PERSIST_1,
};
-static int intbufs_alloc(struct venus_inst *inst)
+int venus_helper_intbufs_alloc(struct venus_inst *inst)
{
const unsigned int *intbuf;
size_t arr_sz, i;
@@ -304,11 +306,59 @@ error:
intbufs_unset_buffers(inst);
return ret;
}
+EXPORT_SYMBOL_GPL(venus_helper_intbufs_alloc);
-static int intbufs_free(struct venus_inst *inst)
+int venus_helper_intbufs_free(struct venus_inst *inst)
{
return intbufs_unset_buffers(inst);
}
+EXPORT_SYMBOL_GPL(venus_helper_intbufs_free);
+
+int venus_helper_intbufs_realloc(struct venus_inst *inst)
+{
+ enum hfi_version ver = inst->core->res->hfi_version;
+ struct hfi_buffer_desc bd;
+ struct intbuf *buf, *n;
+ int ret;
+
+ list_for_each_entry_safe(buf, n, &inst->internalbufs, list) {
+ if (buf->type == HFI_BUFFER_INTERNAL_PERSIST ||
+ buf->type == HFI_BUFFER_INTERNAL_PERSIST_1)
+ continue;
+
+ memset(&bd, 0, sizeof(bd));
+ bd.buffer_size = buf->size;
+ bd.buffer_type = buf->type;
+ bd.num_buffers = 1;
+ bd.device_addr = buf->da;
+ bd.response_required = true;
+
+ ret = hfi_session_unset_buffers(inst, &bd);
+
+ dma_free_attrs(inst->core->dev, buf->size, buf->va, buf->da,
+ buf->attrs);
+
+ list_del_init(&buf->list);
+ kfree(buf);
+ }
+
+ ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH(ver));
+ if (ret)
+ goto err;
+
+ ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_1(ver));
+ if (ret)
+ goto err;
+
+ ret = intbufs_set_buffer(inst, HFI_BUFFER_INTERNAL_SCRATCH_2(ver));
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(venus_helper_intbufs_realloc);
static u32 load_per_instance(struct venus_inst *inst)
{
@@ -339,12 +389,91 @@ static u32 load_per_type(struct venus_core *core, u32 session_type)
return mbs_per_sec;
}
-static int load_scale_clocks(struct venus_core *core)
+static void mbs_to_bw(struct venus_inst *inst, u32 mbs, u32 *avg, u32 *peak)
+{
+ const struct venus_resources *res = inst->core->res;
+ const struct bw_tbl *bw_tbl;
+ unsigned int num_rows, i;
+
+ *avg = 0;
+ *peak = 0;
+
+ if (mbs == 0)
+ return;
+
+ if (inst->session_type == VIDC_SESSION_TYPE_ENC) {
+ num_rows = res->bw_tbl_enc_size;
+ bw_tbl = res->bw_tbl_enc;
+ } else if (inst->session_type == VIDC_SESSION_TYPE_DEC) {
+ num_rows = res->bw_tbl_dec_size;
+ bw_tbl = res->bw_tbl_dec;
+ } else {
+ return;
+ }
+
+ if (!bw_tbl || num_rows == 0)
+ return;
+
+ for (i = 0; i < num_rows; i++) {
+ if (mbs > bw_tbl[i].mbs_per_sec)
+ break;
+
+ if (inst->dpb_fmt & HFI_COLOR_FORMAT_10_BIT_BASE) {
+ *avg = bw_tbl[i].avg_10bit;
+ *peak = bw_tbl[i].peak_10bit;
+ } else {
+ *avg = bw_tbl[i].avg;
+ *peak = bw_tbl[i].peak;
+ }
+ }
+}
+
+static int load_scale_bw(struct venus_core *core)
+{
+ struct venus_inst *inst = NULL;
+ u32 mbs_per_sec, avg, peak, total_avg = 0, total_peak = 0;
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ mbs_per_sec = load_per_instance(inst);
+ mbs_to_bw(inst, mbs_per_sec, &avg, &peak);
+ total_avg += avg;
+ total_peak += peak;
+ }
+ mutex_unlock(&core->lock);
+
+ dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n",
+ total_avg, total_peak);
+
+ return icc_set_bw(core->video_path, total_avg, total_peak);
+}
+
+static int set_clk_freq(struct venus_core *core, unsigned long freq)
+{
+ struct clk *clk = core->clks[0];
+ int ret;
+
+ ret = clk_set_rate(clk, freq);
+ if (ret)
+ return ret;
+
+ ret = clk_set_rate(core->core0_clk, freq);
+ if (ret)
+ return ret;
+
+ ret = clk_set_rate(core->core1_clk, freq);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int scale_clocks(struct venus_inst *inst)
{
+ struct venus_core *core = inst->core;
const struct freq_tbl *table = core->res->freq_tbl;
unsigned int num_rows = core->res->freq_tbl_size;
unsigned long freq = table[0].freq;
- struct clk *clk = core->clks[0];
struct device *dev = core->dev;
u32 mbs_per_sec;
unsigned int i;
@@ -370,24 +499,126 @@ static int load_scale_clocks(struct venus_core *core)
set_freq:
- ret = clk_set_rate(clk, freq);
- if (ret)
- goto err;
+ ret = set_clk_freq(core, freq);
+ if (ret) {
+ dev_err(dev, "failed to set clock rate %lu (%d)\n",
+ freq, ret);
+ return ret;
+ }
- ret = clk_set_rate(core->core0_clk, freq);
- if (ret)
- goto err;
+ ret = load_scale_bw(core);
+ if (ret) {
+ dev_err(dev, "failed to set bandwidth (%d)\n",
+ ret);
+ return ret;
+ }
- ret = clk_set_rate(core->core1_clk, freq);
- if (ret)
- goto err;
+ return 0;
+}
+
+static unsigned long calculate_inst_freq(struct venus_inst *inst,
+ unsigned long filled_len)
+{
+ unsigned long vpp_freq = 0, vsp_freq = 0;
+ u32 fps = (u32)inst->fps;
+ u32 mbs_per_sec;
+
+ mbs_per_sec = load_per_instance(inst) / fps;
+
+ vpp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vpp_freq;
+ /* 21 / 20 is overhead factor */
+ vpp_freq += vpp_freq / 20;
+ vsp_freq = mbs_per_sec * inst->clk_data.codec_freq_data->vsp_freq;
+
+ /* 10 / 7 is overhead factor */
+ if (inst->session_type == VIDC_SESSION_TYPE_ENC)
+ vsp_freq += (inst->controls.enc.bitrate * 10) / 7;
+ else
+ vsp_freq += ((fps * filled_len * 8) * 10) / 7;
+
+ return max(vpp_freq, vsp_freq);
+}
+
+static int scale_clocks_v4(struct venus_inst *inst)
+{
+ struct venus_core *core = inst->core;
+ const struct freq_tbl *table = core->res->freq_tbl;
+ unsigned int num_rows = core->res->freq_tbl_size;
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct device *dev = core->dev;
+ unsigned long freq = 0, freq_core1 = 0, freq_core2 = 0;
+ unsigned long filled_len = 0;
+ struct venus_buffer *buf, *n;
+ struct vb2_buffer *vb;
+ int i, ret;
+
+ v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
+ vb = &buf->vb.vb2_buf;
+ filled_len = max(filled_len, vb2_get_plane_payload(vb, 0));
+ }
+
+ if (inst->session_type == VIDC_SESSION_TYPE_DEC && !filled_len)
+ return 0;
+
+ freq = calculate_inst_freq(inst, filled_len);
+ inst->clk_data.freq = freq;
+
+ mutex_lock(&core->lock);
+ list_for_each_entry(inst, &core->instances, list) {
+ if (inst->clk_data.core_id == VIDC_CORE_ID_1) {
+ freq_core1 += inst->clk_data.freq;
+ } else if (inst->clk_data.core_id == VIDC_CORE_ID_2) {
+ freq_core2 += inst->clk_data.freq;
+ } else if (inst->clk_data.core_id == VIDC_CORE_ID_3) {
+ freq_core1 += inst->clk_data.freq;
+ freq_core2 += inst->clk_data.freq;
+ }
+ }
+ mutex_unlock(&core->lock);
+
+ freq = max(freq_core1, freq_core2);
+
+ if (freq >= table[0].freq) {
+ freq = table[0].freq;
+ dev_warn(dev, "HW is overloaded, needed: %lu max: %lu\n",
+ freq, table[0].freq);
+ goto set_freq;
+ }
+
+ for (i = num_rows - 1 ; i >= 0; i--) {
+ if (freq <= table[i].freq) {
+ freq = table[i].freq;
+ break;
+ }
+ }
+
+set_freq:
+
+ ret = set_clk_freq(core, freq);
+ if (ret) {
+ dev_err(dev, "failed to set clock rate %lu (%d)\n",
+ freq, ret);
+ return ret;
+ }
+
+ ret = load_scale_bw(core);
+ if (ret) {
+ dev_err(dev, "failed to set bandwidth (%d)\n",
+ ret);
+ return ret;
+ }
return 0;
+}
-err:
- dev_err(dev, "failed to set clock rate %lu (%d)\n", freq, ret);
- return ret;
+int venus_helper_load_scale_clocks(struct venus_inst *inst)
+{
+ if (IS_V4(inst->core))
+ return scale_clocks_v4(inst);
+
+ return scale_clocks(inst);
}
+EXPORT_SYMBOL_GPL(venus_helper_load_scale_clocks);
static void fill_buffer_desc(const struct venus_buffer *buf,
struct hfi_buffer_desc *bd, bool response)
@@ -413,6 +644,57 @@ static void return_buf_error(struct venus_inst *inst,
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
}
+static void
+put_ts_metadata(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
+{
+ struct vb2_buffer *vb = &vbuf->vb2_buf;
+ unsigned int i;
+ int slot = -1;
+ u64 ts_us = vb->timestamp;
+
+ for (i = 0; i < ARRAY_SIZE(inst->tss); i++) {
+ if (!inst->tss[i].used) {
+ slot = i;
+ break;
+ }
+ }
+
+ if (slot == -1) {
+ dev_dbg(inst->core->dev, "%s: no free slot\n", __func__);
+ return;
+ }
+
+ do_div(ts_us, NSEC_PER_USEC);
+
+ inst->tss[slot].used = true;
+ inst->tss[slot].flags = vbuf->flags;
+ inst->tss[slot].tc = vbuf->timecode;
+ inst->tss[slot].ts_us = ts_us;
+ inst->tss[slot].ts_ns = vb->timestamp;
+}
+
+void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us,
+ struct vb2_v4l2_buffer *vbuf)
+{
+ struct vb2_buffer *vb = &vbuf->vb2_buf;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(inst->tss); ++i) {
+ if (!inst->tss[i].used)
+ continue;
+
+ if (inst->tss[i].ts_us != timestamp_us)
+ continue;
+
+ inst->tss[i].used = false;
+ vbuf->flags |= inst->tss[i].flags;
+ vbuf->timecode = inst->tss[i].tc;
+ vb->timestamp = inst->tss[i].ts_ns;
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(venus_helper_get_ts_metadata);
+
static int
session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
{
@@ -437,6 +719,11 @@ session_process_buf(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
if (vbuf->flags & V4L2_BUF_FLAG_LAST || !fdata.filled_len)
fdata.flags |= HFI_BUFFERFLAG_EOS;
+
+ if (inst->session_type == VIDC_SESSION_TYPE_DEC)
+ put_ts_metadata(inst, vbuf);
+
+ venus_helper_load_scale_clocks(inst);
} else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (inst->session_type == VIDC_SESSION_TYPE_ENC)
fdata.buffer_type = HFI_BUFFER_OUTPUT;
@@ -472,7 +759,7 @@ static bool is_dynamic_bufmode(struct venus_inst *inst)
return caps->cap_bufs_mode_dynamic;
}
-static int session_unregister_bufs(struct venus_inst *inst)
+int venus_helper_unregister_bufs(struct venus_inst *inst)
{
struct venus_buffer *buf, *n;
struct hfi_buffer_desc bd;
@@ -489,6 +776,7 @@ static int session_unregister_bufs(struct venus_inst *inst)
return ret;
}
+EXPORT_SYMBOL_GPL(venus_helper_unregister_bufs);
static int session_register_bufs(struct venus_inst *inst)
{
@@ -704,6 +992,7 @@ int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage)
const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE;
struct hfi_videocores_usage_type cu;
+ inst->clk_data.core_id = usage;
if (!IS_V4(inst->core))
return 0;
@@ -713,6 +1002,36 @@ int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage)
}
EXPORT_SYMBOL_GPL(venus_helper_set_core_usage);
+int venus_helper_init_codec_freq_data(struct venus_inst *inst)
+{
+ const struct codec_freq_data *data;
+ unsigned int i, data_size;
+ u32 pixfmt;
+ int ret = 0;
+
+ if (!IS_V4(inst->core))
+ return 0;
+
+ data = inst->core->res->codec_freq_data;
+ data_size = inst->core->res->codec_freq_data_size;
+ pixfmt = inst->session_type == VIDC_SESSION_TYPE_DEC ?
+ inst->fmt_out->pixfmt : inst->fmt_cap->pixfmt;
+
+ for (i = 0; i < data_size; i++) {
+ if (data[i].pixfmt == pixfmt &&
+ data[i].session_type == inst->session_type) {
+ inst->clk_data.codec_freq_data = &data[i];
+ break;
+ }
+ }
+
+ if (!inst->clk_data.codec_freq_data)
+ ret = -EINVAL;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(venus_helper_init_codec_freq_data);
+
int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs,
unsigned int output_bufs,
unsigned int output2_bufs)
@@ -947,6 +1266,17 @@ int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb)
{
struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
unsigned int out_buf_size = venus_helper_get_opb_size(inst);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ 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) {
+ dev_err(inst->core->dev, "%s field isn't supported\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
vb2_plane_size(vb, 0) < out_buf_size)
@@ -970,16 +1300,19 @@ void venus_helper_vb2_buf_queue(struct vb2_buffer *vb)
v4l2_m2m_buf_queue(m2m_ctx, vbuf);
- if (!(inst->streamon_out & inst->streamon_cap))
+ if (inst->session_type == VIDC_SESSION_TYPE_ENC &&
+ !(inst->streamon_out && inst->streamon_cap))
goto unlock;
- ret = is_buf_refed(inst, vbuf);
- if (ret)
- goto unlock;
+ if (vb2_start_streaming_called(vb->vb2_queue)) {
+ ret = is_buf_refed(inst, vbuf);
+ if (ret)
+ goto unlock;
- ret = session_process_buf(inst, vbuf);
- if (ret)
- return_buf_error(inst, vbuf);
+ ret = session_process_buf(inst, vbuf);
+ if (ret)
+ return_buf_error(inst, vbuf);
+ }
unlock:
mutex_unlock(&inst->lock);
@@ -1009,8 +1342,8 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
if (inst->streamon_out & inst->streamon_cap) {
ret = hfi_session_stop(inst);
ret |= hfi_session_unload_res(inst);
- ret |= session_unregister_bufs(inst);
- ret |= intbufs_free(inst);
+ ret |= venus_helper_unregister_bufs(inst);
+ ret |= venus_helper_intbufs_free(inst);
ret |= hfi_session_deinit(inst);
if (inst->session_error || core->sys_error)
@@ -1021,7 +1354,7 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
venus_helper_free_dpb_bufs(inst);
- load_scale_clocks(core);
+ venus_helper_load_scale_clocks(inst);
INIT_LIST_HEAD(&inst->registeredbufs);
}
@@ -1036,12 +1369,47 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q)
}
EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming);
+int venus_helper_process_initial_cap_bufs(struct venus_inst *inst)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct v4l2_m2m_buffer *buf, *n;
+ int ret;
+
+ v4l2_m2m_for_each_dst_buf_safe(m2m_ctx, buf, n) {
+ ret = session_process_buf(inst, &buf->vb);
+ if (ret) {
+ return_buf_error(inst, &buf->vb);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(venus_helper_process_initial_cap_bufs);
+
+int venus_helper_process_initial_out_bufs(struct venus_inst *inst)
+{
+ struct v4l2_m2m_ctx *m2m_ctx = inst->m2m_ctx;
+ struct v4l2_m2m_buffer *buf, *n;
+ int ret;
+
+ v4l2_m2m_for_each_src_buf_safe(m2m_ctx, buf, n) {
+ ret = session_process_buf(inst, &buf->vb);
+ if (ret) {
+ return_buf_error(inst, &buf->vb);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(venus_helper_process_initial_out_bufs);
+
int venus_helper_vb2_start_streaming(struct venus_inst *inst)
{
- struct venus_core *core = inst->core;
int ret;
- ret = intbufs_alloc(inst);
+ ret = venus_helper_intbufs_alloc(inst);
if (ret)
return ret;
@@ -1049,7 +1417,7 @@ int venus_helper_vb2_start_streaming(struct venus_inst *inst)
if (ret)
goto err_bufs_free;
- load_scale_clocks(core);
+ venus_helper_load_scale_clocks(inst);
ret = hfi_session_load_res(inst);
if (ret)
@@ -1059,20 +1427,14 @@ int venus_helper_vb2_start_streaming(struct venus_inst *inst)
if (ret)
goto err_unload_res;
- ret = venus_helper_queue_dpb_bufs(inst);
- if (ret)
- goto err_session_stop;
-
return 0;
-err_session_stop:
- hfi_session_stop(inst);
err_unload_res:
hfi_session_unload_res(inst);
err_unreg_bufs:
- session_unregister_bufs(inst);
+ venus_helper_unregister_bufs(inst);
err_bufs_free:
- intbufs_free(inst);
+ venus_helper_intbufs_free(inst);
return ret;
}
EXPORT_SYMBOL_GPL(venus_helper_vb2_start_streaming);
diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h
index 153783687a0c..34dcd0c13f06 100644
--- a/drivers/media/platform/qcom/venus/helpers.h
+++ b/drivers/media/platform/qcom/venus/helpers.h
@@ -9,6 +9,7 @@
#include <media/videobuf2-v4l2.h>
struct venus_inst;
+struct venus_core;
bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt);
struct vb2_v4l2_buffer *venus_helper_find_buf(struct venus_inst *inst,
@@ -32,6 +33,7 @@ int venus_helper_set_output_resolution(struct venus_inst *inst,
unsigned int width, unsigned int height,
u32 buftype);
int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode);
+int venus_helper_init_codec_freq_data(struct venus_inst *inst);
int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage);
int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs,
unsigned int output_bufs,
@@ -53,4 +55,14 @@ int venus_helper_alloc_dpb_bufs(struct venus_inst *inst);
int venus_helper_free_dpb_bufs(struct venus_inst *inst);
int venus_helper_power_enable(struct venus_core *core, u32 session_type,
bool enable);
+int venus_helper_intbufs_alloc(struct venus_inst *inst);
+int venus_helper_intbufs_free(struct venus_inst *inst);
+int venus_helper_intbufs_realloc(struct venus_inst *inst);
+int venus_helper_queue_dpb_bufs(struct venus_inst *inst);
+int venus_helper_unregister_bufs(struct venus_inst *inst);
+int venus_helper_load_scale_clocks(struct venus_inst *inst);
+int venus_helper_process_initial_cap_bufs(struct venus_inst *inst);
+int venus_helper_process_initial_out_bufs(struct venus_inst *inst);
+void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us,
+ struct vb2_v4l2_buffer *vbuf);
#endif
diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c
index 6ad0c1772ea7..3d8b1284d1f3 100644
--- a/drivers/media/platform/qcom/venus/hfi.c
+++ b/drivers/media/platform/qcom/venus/hfi.c
@@ -198,6 +198,9 @@ int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
const struct hfi_ops *ops = core->ops;
int ret;
+ if (inst->state != INST_UNINIT)
+ return -EINVAL;
+
inst->hfi_codec = to_codec_type(pixfmt);
reinit_completion(&inst->done);
@@ -276,6 +279,7 @@ int hfi_session_start(struct venus_inst *inst)
return 0;
}
+EXPORT_SYMBOL_GPL(hfi_session_start);
int hfi_session_stop(struct venus_inst *inst)
{
@@ -299,6 +303,7 @@ int hfi_session_stop(struct venus_inst *inst)
return 0;
}
+EXPORT_SYMBOL_GPL(hfi_session_stop);
int hfi_session_continue(struct venus_inst *inst)
{
@@ -328,6 +333,7 @@ int hfi_session_abort(struct venus_inst *inst)
return 0;
}
+EXPORT_SYMBOL_GPL(hfi_session_abort);
int hfi_session_load_res(struct venus_inst *inst)
{
@@ -374,15 +380,16 @@ int hfi_session_unload_res(struct venus_inst *inst)
return 0;
}
+EXPORT_SYMBOL_GPL(hfi_session_unload_res);
-int hfi_session_flush(struct venus_inst *inst)
+int hfi_session_flush(struct venus_inst *inst, u32 type)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
reinit_completion(&inst->done);
- ret = ops->session_flush(inst, HFI_FLUSH_ALL);
+ ret = ops->session_flush(inst, type);
if (ret)
return ret;
diff --git a/drivers/media/platform/qcom/venus/hfi.h b/drivers/media/platform/qcom/venus/hfi.h
index b121cb1427ac..855822c9f39b 100644
--- a/drivers/media/platform/qcom/venus/hfi.h
+++ b/drivers/media/platform/qcom/venus/hfi.h
@@ -161,7 +161,7 @@ int hfi_session_continue(struct venus_inst *inst);
int hfi_session_abort(struct venus_inst *inst);
int hfi_session_load_res(struct venus_inst *inst);
int hfi_session_unload_res(struct venus_inst *inst);
-int hfi_session_flush(struct venus_inst *inst);
+int hfi_session_flush(struct venus_inst *inst, u32 type);
int hfi_session_set_buffers(struct venus_inst *inst,
struct hfi_buffer_desc *bd);
int hfi_session_unset_buffers(struct venus_inst *inst,
diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c
index 7129a2aea09a..0d8855014ab3 100644
--- a/drivers/media/platform/qcom/venus/hfi_venus.c
+++ b/drivers/media/platform/qcom/venus/hfi_venus.c
@@ -1472,6 +1472,7 @@ static int venus_suspend_3xx(struct venus_core *core)
{
struct venus_hfi_device *hdev = to_hfi_priv(core);
struct device *dev = core->dev;
+ u32 ctrl_status;
bool val;
int ret;
@@ -1487,6 +1488,10 @@ static int venus_suspend_3xx(struct venus_core *core)
return -EINVAL;
}
+ ctrl_status = venus_readl(hdev, CPU_CS_SCIACMDARG0);
+ if (ctrl_status & CPU_CS_SCIACMDARG0_PC_READY)
+ goto power_off;
+
/*
* Power collapse sequence for Venus 3xx and 4xx versions:
* 1. Check for ARM9 and video core to be idle by checking WFI bit
@@ -1511,6 +1516,7 @@ static int venus_suspend_3xx(struct venus_core *core)
if (ret)
return ret;
+power_off:
mutex_lock(&hdev->lock);
ret = venus_power_off(hdev);
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index e1f998656c07..8feaf5daece9 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -37,42 +37,52 @@ static const struct venus_format vdec_formats[] = {
.pixfmt = V4L2_PIX_FMT_MPEG4,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
}, {
.pixfmt = V4L2_PIX_FMT_MPEG2,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
}, {
.pixfmt = V4L2_PIX_FMT_H263,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
}, {
.pixfmt = V4L2_PIX_FMT_VC1_ANNEX_G,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
}, {
.pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
}, {
.pixfmt = V4L2_PIX_FMT_H264,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
}, {
.pixfmt = V4L2_PIX_FMT_VP8,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
}, {
.pixfmt = V4L2_PIX_FMT_VP9,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
}, {
.pixfmt = V4L2_PIX_FMT_XVID,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
}, {
.pixfmt = V4L2_PIX_FMT_HEVC,
.num_planes = 1,
.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
},
};
@@ -133,6 +143,7 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
const struct venus_format *fmt;
+ u32 szimage;
memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
@@ -161,14 +172,17 @@ vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
pixmp->num_planes = fmt->num_planes;
pixmp->flags = 0;
- pfmt[0].sizeimage = venus_helper_get_framesz(pixmp->pixelformat,
- pixmp->width,
- pixmp->height);
+ szimage = venus_helper_get_framesz(pixmp->pixelformat, pixmp->width,
+ pixmp->height);
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ pfmt[0].sizeimage = szimage;
pfmt[0].bytesperline = ALIGN(pixmp->width, 128);
- else
+ } else {
+ pfmt[0].sizeimage = clamp_t(u32, pfmt[0].sizeimage, 0, SZ_8M);
+ pfmt[0].sizeimage = max(pfmt[0].sizeimage, szimage);
pfmt[0].bytesperline = 0;
+ }
return fmt;
}
@@ -182,33 +196,56 @@ static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
return 0;
}
+static int vdec_check_src_change(struct venus_inst *inst)
+{
+ int ret;
+
+ if (inst->subscriptions & V4L2_EVENT_SOURCE_CHANGE &&
+ inst->codec_state == VENUS_DEC_STATE_INIT &&
+ !inst->reconfig)
+ return -EINVAL;
+
+ if (inst->subscriptions & V4L2_EVENT_SOURCE_CHANGE)
+ return 0;
+
+ /*
+ * The code snippet below is a workaround for backward compatibility
+ * with applications which doesn't support V4L2 events. It will be
+ * dropped in future once those applications are fixed.
+ */
+
+ if (inst->codec_state != VENUS_DEC_STATE_INIT)
+ goto done;
+
+ ret = wait_event_timeout(inst->reconf_wait, inst->reconfig,
+ msecs_to_jiffies(100));
+ if (!ret)
+ return -EINVAL;
+
+ if (!(inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) ||
+ !inst->reconfig)
+ dev_dbg(inst->core->dev, "%s: wrong state\n", __func__);
+
+done:
+ return 0;
+}
+
static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
{
struct venus_inst *inst = to_inst(file);
const struct venus_format *fmt = NULL;
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
+ int ret;
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
fmt = inst->fmt_cap;
else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
fmt = inst->fmt_out;
- if (inst->reconfig) {
- struct v4l2_format format = {};
-
- inst->out_width = inst->reconfig_width;
- inst->out_height = inst->reconfig_height;
- inst->reconfig = false;
-
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- format.fmt.pix_mp.pixelformat = inst->fmt_cap->pixfmt;
- format.fmt.pix_mp.width = inst->out_width;
- format.fmt.pix_mp.height = inst->out_height;
-
- vdec_try_fmt_common(inst, &format);
-
- inst->width = format.fmt.pix_mp.width;
- inst->height = format.fmt.pix_mp.height;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ ret = vdec_check_src_change(inst);
+ if (ret)
+ return ret;
}
pixmp->pixelformat = fmt->pixfmt;
@@ -266,6 +303,7 @@ static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
inst->ycbcr_enc = pixmp->ycbcr_enc;
inst->quantization = pixmp->quantization;
inst->xfer_func = pixmp->xfer_func;
+ inst->input_buf_size = pixmp->plane_fmt[0].sizeimage;
}
memset(&format, 0, sizeof(format));
@@ -351,6 +389,7 @@ static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
return -EINVAL;
f->pixelformat = fmt->pixfmt;
+ f->flags = fmt->flags;
return 0;
}
@@ -422,11 +461,18 @@ static int vdec_enum_framesizes(struct file *file, void *fh,
static int vdec_subscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
+ struct venus_inst *inst = container_of(fh, struct venus_inst, fh);
+ int ret;
+
switch (sub->type) {
case V4L2_EVENT_EOS:
return v4l2_event_subscribe(fh, sub, 2, NULL);
case V4L2_EVENT_SOURCE_CHANGE:
- return v4l2_src_change_event_subscribe(fh, sub);
+ ret = v4l2_src_change_event_subscribe(fh, sub);
+ if (ret)
+ return ret;
+ inst->subscriptions |= V4L2_EVENT_SOURCE_CHANGE;
+ return 0;
case V4L2_EVENT_CTRL:
return v4l2_ctrl_subscribe_event(fh, sub);
default:
@@ -435,45 +481,35 @@ static int vdec_subscribe_event(struct v4l2_fh *fh,
}
static int
-vdec_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
-{
- switch (cmd->cmd) {
- case V4L2_DEC_CMD_STOP:
- if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int
vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
{
struct venus_inst *inst = to_inst(file);
struct hfi_frame_data fdata = {0};
int ret;
- ret = vdec_try_decoder_cmd(file, fh, cmd);
+ ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd);
if (ret)
return ret;
mutex_lock(&inst->lock);
- /*
- * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on decoder
- * input to signal EOS.
- */
- if (!(inst->streamon_out & inst->streamon_cap))
- goto unlock;
+ if (cmd->cmd == V4L2_DEC_CMD_STOP) {
+ /*
+ * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on
+ * decoder input to signal EOS.
+ */
+ if (!(inst->streamon_out && inst->streamon_cap))
+ goto unlock;
- fdata.buffer_type = HFI_BUFFER_INPUT;
- fdata.flags |= HFI_BUFFERFLAG_EOS;
- fdata.device_addr = 0xdeadbeef;
+ fdata.buffer_type = HFI_BUFFER_INPUT;
+ fdata.flags |= HFI_BUFFERFLAG_EOS;
+ fdata.device_addr = 0xdeadb000;
- ret = hfi_session_process_buf(inst, &fdata);
+ ret = hfi_session_process_buf(inst, &fdata);
+
+ if (!ret && inst->codec_state == VENUS_DEC_STATE_DECODING)
+ inst->codec_state = VENUS_DEC_STATE_DRAIN;
+ }
unlock:
mutex_unlock(&inst->lock);
@@ -504,7 +540,7 @@ static const struct v4l2_ioctl_ops vdec_ioctl_ops = {
.vidioc_enum_framesizes = vdec_enum_framesizes,
.vidioc_subscribe_event = vdec_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_try_decoder_cmd = vdec_try_decoder_cmd,
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
.vidioc_decoder_cmd = vdec_decoder_cmd,
};
@@ -634,20 +670,22 @@ static int vdec_output_conf(struct venus_inst *inst)
return 0;
}
-static int vdec_init_session(struct venus_inst *inst)
+static int vdec_session_init(struct venus_inst *inst)
{
int ret;
ret = hfi_session_init(inst, inst->fmt_out->pixfmt);
- if (ret)
+ if (ret == -EINVAL)
+ return 0;
+ else if (ret)
return ret;
- ret = venus_helper_set_input_resolution(inst, inst->out_width,
- inst->out_height);
+ ret = venus_helper_set_input_resolution(inst, frame_width_min(inst),
+ frame_height_min(inst));
if (ret)
goto deinit;
- ret = venus_helper_set_color_format(inst, inst->fmt_cap->pixfmt);
+ ret = venus_helper_init_codec_freq_data(inst);
if (ret)
goto deinit;
@@ -666,26 +704,19 @@ static int vdec_num_buffers(struct venus_inst *inst, unsigned int *in_num,
*in_num = *out_num = 0;
- ret = vdec_init_session(inst);
- if (ret)
- return ret;
-
ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq);
if (ret)
- goto deinit;
+ return ret;
*in_num = HFI_BUFREQ_COUNT_MIN(&bufreq, ver);
ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq);
if (ret)
- goto deinit;
+ return ret;
*out_num = HFI_BUFREQ_COUNT_MIN(&bufreq, ver);
-deinit:
- hfi_session_deinit(inst);
-
- return ret;
+ return 0;
}
static int vdec_queue_setup(struct vb2_queue *q,
@@ -718,6 +749,10 @@ static int vdec_queue_setup(struct vb2_queue *q,
return 0;
}
+ ret = vdec_session_init(inst);
+ if (ret)
+ return ret;
+
ret = vdec_num_buffers(inst, &in_num, &out_num);
if (ret)
return ret;
@@ -728,6 +763,7 @@ static int vdec_queue_setup(struct vb2_queue *q,
sizes[0] = venus_helper_get_framesz(inst->fmt_out->pixfmt,
inst->out_width,
inst->out_height);
+ sizes[0] = max(sizes[0], inst->input_buf_size);
inst->input_buf_size = sizes[0];
*num_buffers = max(*num_buffers, in_num);
inst->num_input_bufs = *num_buffers;
@@ -741,6 +777,11 @@ static int vdec_queue_setup(struct vb2_queue *q,
inst->output_buf_size = sizes[0];
*num_buffers = max(*num_buffers, out_num);
inst->num_output_bufs = *num_buffers;
+
+ mutex_lock(&inst->lock);
+ if (inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP)
+ inst->codec_state = VENUS_DEC_STATE_STOPPED;
+ mutex_unlock(&inst->lock);
break;
default:
ret = -EINVAL;
@@ -777,80 +818,295 @@ static int vdec_verify_conf(struct venus_inst *inst)
return 0;
}
-static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+static int vdec_start_capture(struct venus_inst *inst)
{
- struct venus_inst *inst = vb2_get_drv_priv(q);
int ret;
- mutex_lock(&inst->lock);
+ if (!inst->streamon_out)
+ return 0;
- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- inst->streamon_out = 1;
- else
- inst->streamon_cap = 1;
+ if (inst->codec_state == VENUS_DEC_STATE_DECODING) {
+ if (inst->reconfig)
+ goto reconfigure;
- if (!(inst->streamon_out & inst->streamon_cap)) {
- mutex_unlock(&inst->lock);
+ venus_helper_queue_dpb_bufs(inst);
+ venus_helper_process_initial_cap_bufs(inst);
+ inst->streamon_cap = 1;
return 0;
}
- venus_helper_init_instance(inst);
+ if (inst->codec_state != VENUS_DEC_STATE_STOPPED)
+ return 0;
- inst->reconfig = false;
- inst->sequence_cap = 0;
- inst->sequence_out = 0;
+reconfigure:
+ ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT);
+ if (ret)
+ return ret;
- ret = vdec_init_session(inst);
+ ret = vdec_output_conf(inst);
if (ret)
- goto bufs_done;
+ return ret;
+
+ ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs,
+ VB2_MAX_FRAME, VB2_MAX_FRAME);
+ if (ret)
+ return ret;
+
+ ret = venus_helper_intbufs_realloc(inst);
+ if (ret)
+ goto err;
+
+ ret = venus_helper_alloc_dpb_bufs(inst);
+ if (ret)
+ goto err;
+
+ ret = venus_helper_queue_dpb_bufs(inst);
+ if (ret)
+ goto free_dpb_bufs;
+
+ ret = venus_helper_process_initial_cap_bufs(inst);
+ if (ret)
+ goto free_dpb_bufs;
+
+ venus_helper_load_scale_clocks(inst);
+
+ ret = hfi_session_continue(inst);
+ if (ret)
+ goto free_dpb_bufs;
+
+ inst->codec_state = VENUS_DEC_STATE_DECODING;
+
+ inst->streamon_cap = 1;
+ inst->sequence_cap = 0;
+ inst->reconfig = false;
+
+ return 0;
+
+free_dpb_bufs:
+ venus_helper_free_dpb_bufs(inst);
+err:
+ return ret;
+}
+
+static int vdec_start_output(struct venus_inst *inst)
+{
+ int ret;
+
+ if (inst->codec_state == VENUS_DEC_STATE_SEEK) {
+ ret = venus_helper_process_initial_out_bufs(inst);
+ inst->codec_state = VENUS_DEC_STATE_DECODING;
+ goto done;
+ }
+
+ if (inst->codec_state == VENUS_DEC_STATE_INIT ||
+ inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) {
+ ret = venus_helper_process_initial_out_bufs(inst);
+ goto done;
+ }
+
+ if (inst->codec_state != VENUS_DEC_STATE_DEINIT)
+ return -EINVAL;
+
+ venus_helper_init_instance(inst);
+ inst->sequence_out = 0;
+ inst->reconfig = false;
ret = vdec_set_properties(inst);
if (ret)
- goto deinit_sess;
+ return ret;
ret = vdec_output_conf(inst);
if (ret)
- goto deinit_sess;
+ return ret;
ret = vdec_verify_conf(inst);
if (ret)
- goto deinit_sess;
+ return ret;
ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs,
VB2_MAX_FRAME, VB2_MAX_FRAME);
if (ret)
- goto deinit_sess;
+ return ret;
- ret = venus_helper_alloc_dpb_bufs(inst);
+ ret = venus_helper_vb2_start_streaming(inst);
if (ret)
- goto deinit_sess;
+ return ret;
- ret = venus_helper_vb2_start_streaming(inst);
+ ret = venus_helper_process_initial_out_bufs(inst);
if (ret)
- goto deinit_sess;
+ return ret;
- mutex_unlock(&inst->lock);
+ inst->codec_state = VENUS_DEC_STATE_INIT;
+
+done:
+ inst->streamon_out = 1;
+ return ret;
+}
+
+static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct venus_inst *inst = vb2_get_drv_priv(q);
+ int ret;
+
+ mutex_lock(&inst->lock);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ ret = vdec_start_capture(inst);
+ else
+ ret = vdec_start_output(inst);
+
+ if (ret)
+ goto error;
+ mutex_unlock(&inst->lock);
return 0;
-deinit_sess:
- hfi_session_deinit(inst);
-bufs_done:
+error:
venus_helper_buffers_done(inst, VB2_BUF_STATE_QUEUED);
+ mutex_unlock(&inst->lock);
+ return ret;
+}
+
+static void vdec_cancel_dst_buffers(struct venus_inst *inst)
+{
+ struct vb2_v4l2_buffer *buf;
+
+ while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx)))
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
+}
+
+static int vdec_stop_capture(struct venus_inst *inst)
+{
+ int ret = 0;
+
+ switch (inst->codec_state) {
+ case VENUS_DEC_STATE_DECODING:
+ ret = hfi_session_flush(inst, HFI_FLUSH_ALL);
+ /* fallthrough */
+ case VENUS_DEC_STATE_DRAIN:
+ vdec_cancel_dst_buffers(inst);
+ inst->codec_state = VENUS_DEC_STATE_STOPPED;
+ break;
+ case VENUS_DEC_STATE_DRC:
+ ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT);
+ vdec_cancel_dst_buffers(inst);
+ inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP;
+ INIT_LIST_HEAD(&inst->registeredbufs);
+ venus_helper_free_dpb_bufs(inst);
+ break;
+ default:
+ return 0;
+ }
+
+ return ret;
+}
+
+static int vdec_stop_output(struct venus_inst *inst)
+{
+ int ret = 0;
+
+ switch (inst->codec_state) {
+ case VENUS_DEC_STATE_DECODING:
+ case VENUS_DEC_STATE_DRAIN:
+ case VENUS_DEC_STATE_STOPPED:
+ ret = hfi_session_flush(inst, HFI_FLUSH_ALL);
+ inst->codec_state = VENUS_DEC_STATE_SEEK;
+ break;
+ case VENUS_DEC_STATE_INIT:
+ case VENUS_DEC_STATE_CAPTURE_SETUP:
+ ret = hfi_session_flush(inst, HFI_FLUSH_INPUT);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static void vdec_stop_streaming(struct vb2_queue *q)
+{
+ struct venus_inst *inst = vb2_get_drv_priv(q);
+ int ret = -EINVAL;
+
+ mutex_lock(&inst->lock);
+
+ if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ ret = vdec_stop_capture(inst);
+ else
+ ret = vdec_stop_output(inst);
+
+ venus_helper_buffers_done(inst, VB2_BUF_STATE_ERROR);
+
+ if (ret)
+ goto unlock;
+
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
inst->streamon_out = 0;
else
inst->streamon_cap = 0;
+
+unlock:
mutex_unlock(&inst->lock);
- return ret;
+}
+
+static void vdec_session_release(struct venus_inst *inst)
+{
+ struct venus_core *core = inst->core;
+ int ret, abort = 0;
+
+ mutex_lock(&inst->lock);
+
+ inst->codec_state = VENUS_DEC_STATE_DEINIT;
+
+ ret = hfi_session_stop(inst);
+ abort = (ret && ret != -EINVAL) ? 1 : 0;
+ ret = hfi_session_unload_res(inst);
+ abort = (ret && ret != -EINVAL) ? 1 : 0;
+ ret = venus_helper_unregister_bufs(inst);
+ abort = (ret && ret != -EINVAL) ? 1 : 0;
+ ret = venus_helper_intbufs_free(inst);
+ abort = (ret && ret != -EINVAL) ? 1 : 0;
+ ret = hfi_session_deinit(inst);
+ abort = (ret && ret != -EINVAL) ? 1 : 0;
+
+ if (inst->session_error || core->sys_error)
+ abort = 1;
+
+ if (abort)
+ hfi_session_abort(inst);
+
+ venus_helper_free_dpb_bufs(inst);
+ venus_helper_load_scale_clocks(inst);
+ INIT_LIST_HEAD(&inst->registeredbufs);
+
+ mutex_unlock(&inst->lock);
+}
+
+static int vdec_buf_init(struct vb2_buffer *vb)
+{
+ struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
+
+ inst->buf_count++;
+
+ return venus_helper_vb2_buf_init(vb);
+}
+
+static void vdec_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
+
+ inst->buf_count--;
+ if (!inst->buf_count)
+ vdec_session_release(inst);
}
static const struct vb2_ops vdec_vb2_ops = {
.queue_setup = vdec_queue_setup,
- .buf_init = venus_helper_vb2_buf_init,
+ .buf_init = vdec_buf_init,
+ .buf_cleanup = vdec_buf_cleanup,
.buf_prepare = venus_helper_vb2_buf_prepare,
.start_streaming = vdec_start_streaming,
- .stop_streaming = venus_helper_vb2_stop_streaming,
+ .stop_streaming = vdec_stop_streaming,
.buf_queue = venus_helper_vb2_buf_queue,
};
@@ -874,9 +1130,9 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type,
vbuf->flags = flags;
vbuf->field = V4L2_FIELD_NONE;
+ vb = &vbuf->vb2_buf;
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- vb = &vbuf->vb2_buf;
vb2_set_plane_payload(vb, 0, bytesused);
vb->planes[0].data_offset = data_offset;
vb->timestamp = timestamp_us * NSEC_PER_USEC;
@@ -886,28 +1142,85 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type,
const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
v4l2_event_queue_fh(&inst->fh, &ev);
+
+ if (inst->codec_state == VENUS_DEC_STATE_DRAIN)
+ inst->codec_state = VENUS_DEC_STATE_STOPPED;
}
} else {
vbuf->sequence = inst->sequence_out++;
}
+ venus_helper_get_ts_metadata(inst, timestamp_us, vbuf);
+
if (hfi_flags & HFI_BUFFERFLAG_READONLY)
venus_helper_acquire_buf_ref(vbuf);
if (hfi_flags & HFI_BUFFERFLAG_DATACORRUPT)
state = VB2_BUF_STATE_ERROR;
+ if (hfi_flags & HFI_BUFFERFLAG_DROP_FRAME) {
+ state = VB2_BUF_STATE_ERROR;
+ vb2_set_plane_payload(vb, 0, 0);
+ vb->timestamp = 0;
+ }
+
v4l2_m2m_buf_done(vbuf, state);
}
+static void vdec_event_change(struct venus_inst *inst,
+ struct hfi_event_data *ev_data, bool sufficient)
+{
+ static const struct v4l2_event ev = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION };
+ struct device *dev = inst->core->dev_dec;
+ struct v4l2_format format = {};
+
+ mutex_lock(&inst->lock);
+
+ format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ format.fmt.pix_mp.pixelformat = inst->fmt_cap->pixfmt;
+ format.fmt.pix_mp.width = ev_data->width;
+ format.fmt.pix_mp.height = ev_data->height;
+
+ vdec_try_fmt_common(inst, &format);
+
+ inst->width = format.fmt.pix_mp.width;
+ inst->height = format.fmt.pix_mp.height;
+
+ inst->out_width = ev_data->width;
+ inst->out_height = ev_data->height;
+
+ dev_dbg(dev, "event %s sufficient resources (%ux%u)\n",
+ sufficient ? "" : "not", ev_data->width, ev_data->height);
+
+ if (sufficient) {
+ hfi_session_continue(inst);
+ } else {
+ switch (inst->codec_state) {
+ case VENUS_DEC_STATE_INIT:
+ inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP;
+ break;
+ case VENUS_DEC_STATE_DECODING:
+ inst->codec_state = VENUS_DEC_STATE_DRC;
+ break;
+ default:
+ break;
+ }
+ }
+
+ inst->reconfig = true;
+ v4l2_event_queue_fh(&inst->fh, &ev);
+ wake_up(&inst->reconf_wait);
+
+ mutex_unlock(&inst->lock);
+}
+
static void vdec_event_notify(struct venus_inst *inst, u32 event,
struct hfi_event_data *data)
{
struct venus_core *core = inst->core;
struct device *dev = core->dev_dec;
- static const struct v4l2_event ev = {
- .type = V4L2_EVENT_SOURCE_CHANGE,
- .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION };
switch (event) {
case EVT_SESSION_ERROR:
@@ -917,18 +1230,10 @@ static void vdec_event_notify(struct venus_inst *inst, u32 event,
case EVT_SYS_EVENT_CHANGE:
switch (data->event_type) {
case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES:
- hfi_session_continue(inst);
- dev_dbg(dev, "event sufficient resources\n");
+ vdec_event_change(inst, data, true);
break;
case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES:
- inst->reconfig_height = data->height;
- inst->reconfig_width = data->width;
- inst->reconfig = true;
-
- v4l2_event_queue_fh(&inst->fh, &ev);
-
- dev_dbg(dev, "event not sufficient resources (%ux%u)\n",
- data->width, data->height);
+ vdec_event_change(inst, data, false);
break;
case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
venus_helper_release_buf_ref(inst, data->tag);
@@ -949,20 +1254,25 @@ static const struct hfi_inst_ops vdec_hfi_ops = {
static void vdec_inst_init(struct venus_inst *inst)
{
+ inst->hfi_codec = HFI_VIDEO_CODEC_H264;
inst->fmt_out = &vdec_formats[6];
inst->fmt_cap = &vdec_formats[0];
- inst->width = 1280;
- inst->height = ALIGN(720, 32);
- inst->out_width = 1280;
- inst->out_height = 720;
+ inst->width = frame_width_min(inst);
+ inst->height = ALIGN(frame_height_min(inst), 32);
+ inst->out_width = frame_width_min(inst);
+ inst->out_height = frame_height_min(inst);
inst->fps = 30;
inst->timeperframe.numerator = 1;
inst->timeperframe.denominator = 30;
- inst->hfi_codec = HFI_VIDEO_CODEC_H264;
+ inst->opb_buftype = HFI_BUFFER_OUTPUT;
+}
+
+static void vdec_m2m_device_run(void *priv)
+{
}
static const struct v4l2_m2m_ops vdec_m2m_ops = {
- .device_run = venus_helper_m2m_device_run,
+ .device_run = vdec_m2m_device_run,
.job_abort = venus_helper_m2m_job_abort,
};
@@ -980,7 +1290,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->drv_priv = inst;
src_vq->buf_struct_size = sizeof(struct venus_buffer);
src_vq->allow_zero_bytesused = 1;
- src_vq->min_buffers_needed = 1;
+ src_vq->min_buffers_needed = 0;
src_vq->dev = inst->core->dev;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -994,7 +1304,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->drv_priv = inst;
dst_vq->buf_struct_size = sizeof(struct venus_buffer);
dst_vq->allow_zero_bytesused = 1;
- dst_vq->min_buffers_needed = 1;
+ dst_vq->min_buffers_needed = 0;
dst_vq->dev = inst->core->dev;
ret = vb2_queue_init(dst_vq);
if (ret) {
@@ -1024,7 +1334,9 @@ static int vdec_open(struct file *file)
inst->core = core;
inst->session_type = VIDC_SESSION_TYPE_DEC;
inst->num_output_bufs = 1;
-
+ inst->codec_state = VENUS_DEC_STATE_DEINIT;
+ inst->buf_count = 0;
+ init_waitqueue_head(&inst->reconf_wait);
venus_helper_init_instance(inst);
ret = pm_runtime_get_sync(core->dev_dec);
@@ -1104,9 +1416,6 @@ static const struct v4l2_file_operations vdec_fops = {
.unlocked_ioctl = video_ioctl2,
.poll = v4l2_m2m_fop_poll,
.mmap = v4l2_m2m_fop_mmap,
-#ifdef CONFIG_COMPAT
- .compat_ioctl32 = v4l2_compat_ioctl32,
-#endif
};
static int vdec_probe(struct platform_device *pdev)
diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c
index 300350bfe8bd..3a963cbd342a 100644
--- a/drivers/media/platform/qcom/venus/vdec_ctrls.c
+++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c
@@ -7,6 +7,7 @@
#include <media/v4l2-ctrls.h>
#include "core.h"
+#include "helpers.h"
#include "vdec.h"
static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -38,7 +39,9 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct venus_inst *inst = ctrl_to_inst(ctrl);
struct vdec_controls *ctr = &inst->controls.dec;
+ struct hfi_buffer_requirements bufreq;
union hfi_get_property hprop;
+ enum hfi_version ver = inst->core->res->hfi_version;
u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
int ret;
@@ -62,7 +65,9 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
ctrl->val = ctr->post_loop_deb_mode;
break;
case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
- ctrl->val = inst->num_output_bufs;
+ ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq);
+ if (!ret)
+ ctrl->val = HFI_BUFREQ_COUNT_MIN(&bufreq, ver);
break;
default:
return -EINVAL;
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index a5f3d2c46bea..453edf966d4f 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -294,6 +294,7 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
const struct venus_format *fmt;
+ u32 sizeimage;
memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
@@ -325,9 +326,10 @@ venc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
pixmp->num_planes = fmt->num_planes;
pixmp->flags = 0;
- pfmt[0].sizeimage = venus_helper_get_framesz(pixmp->pixelformat,
- pixmp->width,
- pixmp->height);
+ sizeimage = venus_helper_get_framesz(pixmp->pixelformat,
+ pixmp->width,
+ pixmp->height);
+ pfmt[0].sizeimage = max(ALIGN(pfmt[0].sizeimage, SZ_4K), sizeimage);
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
pfmt[0].bytesperline = ALIGN(pixmp->width, 128);
@@ -399,8 +401,10 @@ static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
inst->fmt_out = fmt;
- else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
inst->fmt_cap = fmt;
+ inst->output_buf_size = pixmp->plane_fmt[0].sizeimage;
+ }
return 0;
}
@@ -838,6 +842,10 @@ static int venc_init_session(struct venus_inst *inst)
if (ret)
goto deinit;
+ ret = venus_helper_init_codec_freq_data(inst);
+ if (ret)
+ goto deinit;
+
ret = venc_set_properties(inst);
if (ret)
goto deinit;
@@ -918,6 +926,7 @@ static int venc_queue_setup(struct vb2_queue *q,
sizes[0] = venus_helper_get_framesz(inst->fmt_cap->pixfmt,
inst->width,
inst->height);
+ sizes[0] = max(sizes[0], inst->output_buf_size);
inst->output_buf_size = sizes[0];
break;
default:
@@ -1230,9 +1239,6 @@ static const struct v4l2_file_operations venc_fops = {
.unlocked_ioctl = video_ioctl2,
.poll = v4l2_m2m_fop_poll,
.mmap = v4l2_m2m_fop_mmap,
-#ifdef CONFIG_COMPAT
- .compat_ioctl32 = v4l2_compat_ioctl32,
-#endif
};
static int venc_probe(struct platform_device *pdev)
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 64f9cf790445..7440c8965d27 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -390,6 +390,28 @@ out:
}
/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static int rvin_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct rvin_dev *vin =
+ container_of(ctrl->handler, struct rvin_dev, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_ALPHA_COMPONENT:
+ rvin_set_alpha(vin, ctrl->val);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops rvin_ctrl_ops = {
+ .s_ctrl = rvin_s_ctrl,
+};
+
+/* -----------------------------------------------------------------------------
* Async notifier
*/
@@ -478,6 +500,15 @@ static int rvin_parallel_subdevice_attach(struct rvin_dev *vin,
if (ret < 0)
return ret;
+ v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
+
+ if (vin->ctrl_handler.error) {
+ ret = vin->ctrl_handler.error;
+ v4l2_ctrl_handler_free(&vin->ctrl_handler);
+ return ret;
+ }
+
ret = v4l2_ctrl_add_handler(&vin->ctrl_handler, subdev->ctrl_handler,
NULL, true);
if (ret < 0) {
@@ -633,7 +664,7 @@ static int rvin_parallel_init(struct rvin_dev *vin)
ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
if (ret < 0) {
vin_err(vin, "Notifier registration failed\n");
- v4l2_async_notifier_cleanup(&vin->group->notifier);
+ v4l2_async_notifier_cleanup(&vin->notifier);
return ret;
}
@@ -870,6 +901,21 @@ static int rvin_mc_init(struct rvin_dev *vin)
if (ret)
rvin_group_put(vin);
+ ret = v4l2_ctrl_handler_init(&vin->ctrl_handler, 1);
+ if (ret < 0)
+ return ret;
+
+ v4l2_ctrl_new_std(&vin->ctrl_handler, &rvin_ctrl_ops,
+ V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255);
+
+ if (vin->ctrl_handler.error) {
+ ret = vin->ctrl_handler.error;
+ v4l2_ctrl_handler_free(&vin->ctrl_handler);
+ return ret;
+ }
+
+ vin->vdev.ctrl_handler = &vin->ctrl_handler;
+
return ret;
}
@@ -937,6 +983,7 @@ static const struct rvin_group_route rcar_info_r8a7795_routes[] = {
static const struct rvin_info rcar_info_r8a7795 = {
.model = RCAR_GEN3,
.use_mc = true,
+ .nv12 = true,
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a7795_routes,
@@ -1031,6 +1078,7 @@ static const struct rvin_group_route rcar_info_r8a7796_routes[] = {
static const struct rvin_info rcar_info_r8a7796 = {
.model = RCAR_GEN3,
.use_mc = true,
+ .nv12 = true,
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a7796_routes,
@@ -1075,6 +1123,7 @@ static const struct rvin_group_route rcar_info_r8a77965_routes[] = {
static const struct rvin_info rcar_info_r8a77965 = {
.model = RCAR_GEN3,
.use_mc = true,
+ .nv12 = true,
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a77965_routes,
@@ -1122,6 +1171,7 @@ static const struct rvin_group_route rcar_info_r8a77980_routes[] = {
static const struct rvin_info rcar_info_r8a77980 = {
.model = RCAR_GEN3,
.use_mc = true,
+ .nv12 = true,
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a77980_routes,
@@ -1138,6 +1188,7 @@ static const struct rvin_group_route rcar_info_r8a77990_routes[] = {
static const struct rvin_info rcar_info_r8a77990 = {
.model = RCAR_GEN3,
.use_mc = true,
+ .nv12 = true,
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a77990_routes,
@@ -1150,6 +1201,7 @@ static const struct rvin_group_route rcar_info_r8a77995_routes[] = {
static const struct rvin_info rcar_info_r8a77995 = {
.model = RCAR_GEN3,
.use_mc = true,
+ .nv12 = true,
.max_width = 4096,
.max_height = 4096,
.routes = rcar_info_r8a77995_routes,
@@ -1161,6 +1213,10 @@ static const struct of_device_id rvin_of_id_table[] = {
.data = &rcar_info_r8a7796,
},
{
+ .compatible = "renesas,vin-r8a774b1",
+ .data = &rcar_info_r8a77965,
+ },
+ {
.compatible = "renesas,vin-r8a774c0",
.data = &rcar_info_r8a77990,
},
@@ -1236,7 +1292,6 @@ static int rcar_vin_probe(struct platform_device *pdev)
{
const struct soc_device_attribute *attr;
struct rvin_dev *vin;
- struct resource *mem;
int irq, ret;
vin = devm_kzalloc(&pdev->dev, sizeof(*vin), GFP_KERNEL);
@@ -1245,6 +1300,7 @@ static int rcar_vin_probe(struct platform_device *pdev)
vin->dev = &pdev->dev;
vin->info = of_device_get_match_data(&pdev->dev);
+ vin->alpha = 0xff;
/*
* Special care is needed on r8a7795 ES1.x since it
@@ -1254,11 +1310,7 @@ static int rcar_vin_probe(struct platform_device *pdev)
if (attr)
vin->info = attr->data;
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (mem == NULL)
- return -EINVAL;
-
- vin->base = devm_ioremap_resource(vin->dev, mem);
+ vin->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(vin->base))
return PTR_ERR(vin->base);
@@ -1288,6 +1340,8 @@ static int rcar_vin_probe(struct platform_device *pdev)
return 0;
error_group_unregister:
+ v4l2_ctrl_handler_free(&vin->ctrl_handler);
+
if (vin->info->use_mc) {
mutex_lock(&vin->group->lock);
if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) {
@@ -1323,10 +1377,10 @@ static int rcar_vin_remove(struct platform_device *pdev)
}
mutex_unlock(&vin->group->lock);
rvin_group_put(vin);
- } else {
- v4l2_ctrl_handler_free(&vin->ctrl_handler);
}
+ v4l2_ctrl_handler_free(&vin->ctrl_handler);
+
rvin_dma_unregister(vin);
return 0;
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index c14af1b929df..faa9fb23a2e9 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -1082,6 +1082,10 @@ static const struct of_device_id rcar_csi2_of_table[] = {
.data = &rcar_csi2_info_r8a7796,
},
{
+ .compatible = "renesas,r8a774b1-csi2",
+ .data = &rcar_csi2_info_r8a77965,
+ },
+ {
.compatible = "renesas,r8a774c0-csi2",
.data = &rcar_csi2_info_r8a77990,
},
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index 91ab064404a1..cf9029efeb04 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -111,10 +111,14 @@
#define VNIE_EFE (1 << 1)
/* Video n Data Mode Register bits */
+#define VNDMR_A8BIT(n) (((n) & 0xff) << 24)
+#define VNDMR_A8BIT_MASK (0xff << 24)
#define VNDMR_EXRGB (1 << 8)
#define VNDMR_BPSM (1 << 4)
+#define VNDMR_ABIT (1 << 2)
#define VNDMR_DTMD_YCSEP (1 << 1)
-#define VNDMR_DTMD_ARGB1555 (1 << 0)
+#define VNDMR_DTMD_ARGB (1 << 0)
+#define VNDMR_DTMD_YCSEP_420 (3 << 0)
/* Video n Data Mode Register 2 bits */
#define VNDMR2_VPS (1 << 30)
@@ -526,12 +530,17 @@ static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs)
static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin)
{
+ unsigned int crop_height;
u32 xs, ys;
/* Set scaling coefficient */
+ crop_height = vin->crop.height;
+ if (V4L2_FIELD_IS_INTERLACED(vin->format.field))
+ crop_height *= 2;
+
ys = 0;
- if (vin->crop.height != vin->compose.height)
- ys = (4096 * vin->crop.height) / vin->compose.height;
+ if (crop_height != vin->compose.height)
+ ys = (4096 * crop_height) / vin->compose.height;
rvin_write(vin, ys, VNYS_REG);
xs = 0;
@@ -554,16 +563,11 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin)
rvin_write(vin, 0, VNSPPOC_REG);
rvin_write(vin, 0, VNSLPOC_REG);
rvin_write(vin, vin->format.width - 1, VNEPPOC_REG);
- switch (vin->format.field) {
- case V4L2_FIELD_INTERLACED:
- case V4L2_FIELD_INTERLACED_TB:
- case V4L2_FIELD_INTERLACED_BT:
+
+ if (V4L2_FIELD_IS_INTERLACED(vin->format.field))
rvin_write(vin, vin->format.height / 2 - 1, VNELPOC_REG);
- break;
- default:
+ else
rvin_write(vin, vin->format.height - 1, VNELPOC_REG);
- break;
- }
vin_dbg(vin,
"Pre-Clip: %ux%u@%u:%u YS: %d XS: %d Post-Clip: %ux%u@%u:%u\n",
@@ -574,33 +578,23 @@ static void rvin_crop_scale_comp_gen2(struct rvin_dev *vin)
void rvin_crop_scale_comp(struct rvin_dev *vin)
{
+ const struct rvin_video_format *fmt;
+ u32 stride;
+
/* Set Start/End Pixel/Line Pre-Clip */
rvin_write(vin, vin->crop.left, VNSPPRC_REG);
rvin_write(vin, vin->crop.left + vin->crop.width - 1, VNEPPRC_REG);
+ rvin_write(vin, vin->crop.top, VNSLPRC_REG);
+ rvin_write(vin, vin->crop.top + vin->crop.height - 1, VNELPRC_REG);
- switch (vin->format.field) {
- case V4L2_FIELD_INTERLACED:
- case V4L2_FIELD_INTERLACED_TB:
- case V4L2_FIELD_INTERLACED_BT:
- rvin_write(vin, vin->crop.top / 2, VNSLPRC_REG);
- rvin_write(vin, (vin->crop.top + vin->crop.height) / 2 - 1,
- VNELPRC_REG);
- break;
- default:
- rvin_write(vin, vin->crop.top, VNSLPRC_REG);
- rvin_write(vin, vin->crop.top + vin->crop.height - 1,
- VNELPRC_REG);
- break;
- }
/* TODO: Add support for the UDS scaler. */
if (vin->info->model != RCAR_GEN3)
rvin_crop_scale_comp_gen2(vin);
- if (vin->format.pixelformat == V4L2_PIX_FMT_NV16)
- rvin_write(vin, ALIGN(vin->format.width, 0x20), VNIS_REG);
- else
- rvin_write(vin, ALIGN(vin->format.width, 0x10), VNIS_REG);
+ fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
+ stride = vin->format.bytesperline / fmt->bpp;
+ rvin_write(vin, stride, VNIS_REG);
}
/* -----------------------------------------------------------------------------
@@ -636,6 +630,9 @@ static int rvin_setup(struct rvin_dev *vin)
vnmc = VNMC_IM_ODD_EVEN;
progressive = true;
break;
+ case V4L2_FIELD_ALTERNATE:
+ vnmc = VNMC_IM_ODD_EVEN;
+ break;
default:
vnmc = VNMC_IM_ODD;
break;
@@ -705,11 +702,13 @@ static int rvin_setup(struct rvin_dev *vin)
* Output format
*/
switch (vin->format.pixelformat) {
+ case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV16:
rvin_write(vin,
- ALIGN(vin->format.width * vin->format.height, 0x80),
- VNUVAOF_REG);
- dmr = VNDMR_DTMD_YCSEP;
+ ALIGN(vin->format.bytesperline * vin->format.height,
+ 0x80), VNUVAOF_REG);
+ dmr = vin->format.pixelformat == V4L2_PIX_FMT_NV12 ?
+ VNDMR_DTMD_YCSEP_420 : VNDMR_DTMD_YCSEP;
output_is_yuv = true;
break;
case V4L2_PIX_FMT_YUYV:
@@ -721,7 +720,7 @@ static int rvin_setup(struct rvin_dev *vin)
output_is_yuv = true;
break;
case V4L2_PIX_FMT_XRGB555:
- dmr = VNDMR_DTMD_ARGB1555;
+ dmr = VNDMR_DTMD_ARGB;
break;
case V4L2_PIX_FMT_RGB565:
dmr = 0;
@@ -730,6 +729,12 @@ static int rvin_setup(struct rvin_dev *vin)
/* Note: not supported on M1 */
dmr = VNDMR_EXRGB;
break;
+ case V4L2_PIX_FMT_ARGB555:
+ dmr = (vin->alpha ? VNDMR_ABIT : 0) | VNDMR_DTMD_ARGB;
+ break;
+ case V4L2_PIX_FMT_ABGR32:
+ dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB;
+ break;
default:
vin_err(vin, "Invalid pixelformat (0x%x)\n",
vin->format.pixelformat);
@@ -788,13 +793,25 @@ static bool rvin_capture_active(struct rvin_dev *vin)
return rvin_read(vin, VNMS_REG) & VNMS_CA;
}
+static enum v4l2_field rvin_get_active_field(struct rvin_dev *vin, u32 vnms)
+{
+ if (vin->format.field == V4L2_FIELD_ALTERNATE) {
+ /* If FS is set it is an Even field. */
+ if (vnms & VNMS_FS)
+ return V4L2_FIELD_BOTTOM;
+ return V4L2_FIELD_TOP;
+ }
+
+ return vin->format.field;
+}
+
static void rvin_set_slot_addr(struct rvin_dev *vin, int slot, dma_addr_t addr)
{
const struct rvin_video_format *fmt;
int offsetx, offsety;
dma_addr_t offset;
- fmt = rvin_format_from_pixel(vin->format.pixelformat);
+ fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
/*
* There is no HW support for composition do the beast we can
@@ -937,7 +954,7 @@ static irqreturn_t rvin_irq(int irq, void *data)
/* Capture frame */
if (vin->queue_buf[slot]) {
- vin->queue_buf[slot]->field = vin->format.field;
+ vin->queue_buf[slot]->field = rvin_get_active_field(vin, vnms);
vin->queue_buf[slot]->sequence = vin->sequence;
vin->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&vin->queue_buf[slot]->vb2_buf,
@@ -1064,6 +1081,7 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
case V4L2_FIELD_NONE:
+ case V4L2_FIELD_ALTERNATE:
break;
case V4L2_FIELD_INTERLACED_TB:
case V4L2_FIELD_INTERLACED_BT:
@@ -1343,3 +1361,34 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
return 0;
}
+
+void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha)
+{
+ unsigned long flags;
+ u32 dmr;
+
+ spin_lock_irqsave(&vin->qlock, flags);
+
+ vin->alpha = alpha;
+
+ if (vin->state == STOPPED)
+ goto out;
+
+ switch (vin->format.pixelformat) {
+ case V4L2_PIX_FMT_ARGB555:
+ dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_ABIT;
+ if (vin->alpha)
+ dmr |= VNDMR_ABIT;
+ break;
+ case V4L2_PIX_FMT_ABGR32:
+ dmr = rvin_read(vin, VNDMR_REG) & ~VNDMR_A8BIT_MASK;
+ dmr |= VNDMR_A8BIT(vin->alpha);
+ break;
+ default:
+ goto out;
+ }
+
+ rvin_write(vin, dmr, VNDMR_REG);
+out:
+ spin_unlock_irqrestore(&vin->qlock, flags);
+}
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index 0936bcd98df1..5ff565e76bca 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -31,6 +31,10 @@
static const struct rvin_video_format rvin_formats[] = {
{
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .bpp = 1,
+ },
+ {
.fourcc = V4L2_PIX_FMT_NV16,
.bpp = 1,
},
@@ -54,12 +58,27 @@ static const struct rvin_video_format rvin_formats[] = {
.fourcc = V4L2_PIX_FMT_XBGR32,
.bpp = 4,
},
+ {
+ .fourcc = V4L2_PIX_FMT_ARGB555,
+ .bpp = 2,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ABGR32,
+ .bpp = 4,
+ },
};
-const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat)
+const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
+ u32 pixelformat)
{
int i;
+ if (vin->info->model == RCAR_M1 && pixelformat == V4L2_PIX_FMT_XBGR32)
+ return NULL;
+
+ if (pixelformat == V4L2_PIX_FMT_NV12 && !vin->info->nv12)
+ return NULL;
+
for (i = 0; i < ARRAY_SIZE(rvin_formats); i++)
if (rvin_formats[i].fourcc == pixelformat)
return rvin_formats + i;
@@ -67,33 +86,47 @@ const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat)
return NULL;
}
-static u32 rvin_format_bytesperline(struct v4l2_pix_format *pix)
+static u32 rvin_format_bytesperline(struct rvin_dev *vin,
+ struct v4l2_pix_format *pix)
{
const struct rvin_video_format *fmt;
+ u32 align;
- fmt = rvin_format_from_pixel(pix->pixelformat);
+ fmt = rvin_format_from_pixel(vin, pix->pixelformat);
if (WARN_ON(!fmt))
return -EINVAL;
- return pix->width * fmt->bpp;
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ align = 0x20;
+ break;
+ default:
+ align = 0x10;
+ break;
+ }
+
+ return ALIGN(pix->width, align) * fmt->bpp;
}
static u32 rvin_format_sizeimage(struct v4l2_pix_format *pix)
{
- if (pix->pixelformat == V4L2_PIX_FMT_NV16)
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_NV12:
+ return pix->bytesperline * pix->height * 3 / 2;
+ case V4L2_PIX_FMT_NV16:
return pix->bytesperline * pix->height * 2;
-
- return pix->bytesperline * pix->height;
+ default:
+ return pix->bytesperline * pix->height;
+ }
}
static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
{
u32 walign;
- if (!rvin_format_from_pixel(pix->pixelformat) ||
- (vin->info->model == RCAR_M1 &&
- pix->pixelformat == V4L2_PIX_FMT_XBGR32))
+ if (!rvin_format_from_pixel(vin, pix->pixelformat))
pix->pixelformat = RVIN_DEFAULT_FORMAT;
switch (pix->field) {
@@ -103,29 +136,29 @@ static void rvin_format_align(struct rvin_dev *vin, struct v4l2_pix_format *pix)
case V4L2_FIELD_INTERLACED_TB:
case V4L2_FIELD_INTERLACED_BT:
case V4L2_FIELD_INTERLACED:
- break;
case V4L2_FIELD_ALTERNATE:
- /*
- * Driver does not (yet) support outputting ALTERNATE to a
- * userspace. It does support outputting INTERLACED so use
- * the VIN hardware to combine the two fields.
- */
- pix->field = V4L2_FIELD_INTERLACED;
- pix->height *= 2;
break;
default:
pix->field = RVIN_DEFAULT_FIELD;
break;
}
- /* HW limit width to a multiple of 32 (2^5) for NV16 else 2 (2^1) */
- walign = vin->format.pixelformat == V4L2_PIX_FMT_NV16 ? 5 : 1;
+ /* HW limit width to a multiple of 32 (2^5) for NV12/16 else 2 (2^1) */
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV16:
+ walign = 5;
+ break;
+ default:
+ walign = 1;
+ break;
+ }
/* Limit to VIN capabilities */
v4l_bound_align_image(&pix->width, 2, vin->info->max_width, walign,
&pix->height, 4, vin->info->max_height, 2, 0);
- pix->bytesperline = rvin_format_bytesperline(pix);
+ pix->bytesperline = rvin_format_bytesperline(vin, pix);
pix->sizeimage = rvin_format_sizeimage(pix);
vin_dbg(vin, "Format %ux%u bpl: %u size: %u\n",
@@ -150,22 +183,32 @@ static int rvin_reset_format(struct rvin_dev *vin)
v4l2_fill_pix_format(&vin->format, &fmt.format);
+ vin->src_rect.top = 0;
+ vin->src_rect.left = 0;
+ vin->src_rect.width = vin->format.width;
+ vin->src_rect.height = vin->format.height;
+
+ /* Make use of the hardware interlacer by default. */
+ if (vin->format.field == V4L2_FIELD_ALTERNATE) {
+ vin->format.field = V4L2_FIELD_INTERLACED;
+ vin->format.height *= 2;
+ }
+
rvin_format_align(vin, &vin->format);
- vin->source.top = 0;
- vin->source.left = 0;
- vin->source.width = vin->format.width;
- vin->source.height = vin->format.height;
+ vin->crop = vin->src_rect;
- vin->crop = vin->source;
- vin->compose = vin->source;
+ vin->compose.top = 0;
+ vin->compose.left = 0;
+ vin->compose.width = vin->format.width;
+ vin->compose.height = vin->format.height;
return 0;
}
static int rvin_try_format(struct rvin_dev *vin, u32 which,
struct v4l2_pix_format *pix,
- struct v4l2_rect *crop, struct v4l2_rect *compose)
+ struct v4l2_rect *src_rect)
{
struct v4l2_subdev *sd = vin_to_source(vin);
struct v4l2_subdev_pad_config *pad_cfg;
@@ -181,9 +224,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
if (pad_cfg == NULL)
return -ENOMEM;
- if (!rvin_format_from_pixel(pix->pixelformat) ||
- (vin->info->model == RCAR_M1 &&
- pix->pixelformat == V4L2_PIX_FMT_XBGR32))
+ if (!rvin_format_from_pixel(vin, pix->pixelformat))
pix->pixelformat = RVIN_DEFAULT_FORMAT;
v4l2_fill_mbus_format(&format.format, pix, vin->mbus_code);
@@ -196,21 +237,15 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
ret = v4l2_subdev_call(sd, pad, set_fmt, pad_cfg, &format);
if (ret < 0 && ret != -ENOIOCTLCMD)
goto done;
+ ret = 0;
v4l2_fill_pix_format(pix, &format.format);
- if (crop) {
- crop->top = 0;
- crop->left = 0;
- crop->width = pix->width;
- crop->height = pix->height;
-
- /*
- * If source is ALTERNATE the driver will use the VIN hardware
- * to INTERLACE it. The crop height then needs to be doubled.
- */
- if (pix->field == V4L2_FIELD_ALTERNATE)
- crop->height *= 2;
+ if (src_rect) {
+ src_rect->top = 0;
+ src_rect->left = 0;
+ src_rect->width = pix->width;
+ src_rect->height = pix->height;
}
if (field != V4L2_FIELD_ANY)
@@ -220,17 +255,10 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
pix->height = height;
rvin_format_align(vin, pix);
-
- if (compose) {
- compose->top = 0;
- compose->left = 0;
- compose->width = pix->width;
- compose->height = pix->height;
- }
done:
v4l2_subdev_free_pad_config(pad_cfg);
- return 0;
+ return ret;
}
static int rvin_querycap(struct file *file, void *priv,
@@ -250,29 +278,34 @@ static int rvin_try_fmt_vid_cap(struct file *file, void *priv,
{
struct rvin_dev *vin = video_drvdata(file);
- return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL,
- NULL);
+ return rvin_try_format(vin, V4L2_SUBDEV_FORMAT_TRY, &f->fmt.pix, NULL);
}
static int rvin_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct rvin_dev *vin = video_drvdata(file);
- struct v4l2_rect crop, compose;
+ struct v4l2_rect fmt_rect, src_rect;
int ret;
if (vb2_is_busy(&vin->queue))
return -EBUSY;
ret = rvin_try_format(vin, V4L2_SUBDEV_FORMAT_ACTIVE, &f->fmt.pix,
- &crop, &compose);
+ &src_rect);
if (ret)
return ret;
vin->format = f->fmt.pix;
- vin->crop = crop;
- vin->compose = compose;
- vin->source = crop;
+
+ fmt_rect.top = 0;
+ fmt_rect.left = 0;
+ fmt_rect.width = vin->format.width;
+ fmt_rect.height = vin->format.height;
+
+ v4l2_rect_map_inside(&vin->crop, &src_rect);
+ v4l2_rect_map_inside(&vin->compose, &fmt_rect);
+ vin->src_rect = src_rect;
return 0;
}
@@ -290,12 +323,22 @@ static int rvin_g_fmt_vid_cap(struct file *file, void *priv,
static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- if (f->index >= ARRAY_SIZE(rvin_formats))
- return -EINVAL;
+ struct rvin_dev *vin = video_drvdata(file);
+ unsigned int i;
+ int matched;
- f->pixelformat = rvin_formats[f->index].fourcc;
+ matched = -1;
+ for (i = 0; i < ARRAY_SIZE(rvin_formats); i++) {
+ if (rvin_format_from_pixel(vin, rvin_formats[i].fourcc))
+ matched++;
- return 0;
+ if (matched == f->index) {
+ f->pixelformat = rvin_formats[i].fourcc;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
}
static int rvin_g_selection(struct file *file, void *fh,
@@ -310,8 +353,8 @@ static int rvin_g_selection(struct file *file, void *fh,
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
s->r.left = s->r.top = 0;
- s->r.width = vin->source.width;
- s->r.height = vin->source.height;
+ s->r.width = vin->src_rect.width;
+ s->r.height = vin->src_rect.height;
break;
case V4L2_SEL_TGT_CROP:
s->r = vin->crop;
@@ -353,21 +396,22 @@ static int rvin_s_selection(struct file *file, void *fh,
case V4L2_SEL_TGT_CROP:
/* Can't crop outside of source input */
max_rect.top = max_rect.left = 0;
- max_rect.width = vin->source.width;
- max_rect.height = vin->source.height;
+ max_rect.width = vin->src_rect.width;
+ max_rect.height = vin->src_rect.height;
v4l2_rect_map_inside(&r, &max_rect);
- v4l_bound_align_image(&r.width, 6, vin->source.width, 0,
- &r.height, 2, vin->source.height, 0, 0);
+ v4l_bound_align_image(&r.width, 6, vin->src_rect.width, 0,
+ &r.height, 2, vin->src_rect.height, 0, 0);
- r.top = clamp_t(s32, r.top, 0, vin->source.height - r.height);
- r.left = clamp_t(s32, r.left, 0, vin->source.width - r.width);
+ r.top = clamp_t(s32, r.top, 0,
+ vin->src_rect.height - r.height);
+ r.left = clamp_t(s32, r.left, 0, vin->src_rect.width - r.width);
vin->crop = s->r = r;
vin_dbg(vin, "Cropped %dx%d@%d:%d of %dx%d\n",
r.width, r.height, r.left, r.top,
- vin->source.width, vin->source.height);
+ vin->src_rect.width, vin->src_rect.height);
break;
case V4L2_SEL_TGT_COMPOSE:
/* Make sure compose rect fits inside output format */
@@ -384,7 +428,7 @@ static int rvin_s_selection(struct file *file, void *fh,
while ((r.top * vin->format.bytesperline) & HW_BUFFER_MASK)
r.top--;
- fmt = rvin_format_from_pixel(vin->format.pixelformat);
+ fmt = rvin_format_from_pixel(vin, vin->format.pixelformat);
while ((r.left * fmt->bpp) & HW_BUFFER_MASK)
r.left--;
@@ -781,26 +825,26 @@ static int rvin_open(struct file *file)
if (ret)
goto err_unlock;
- if (vin->info->use_mc) {
+ if (vin->info->use_mc)
ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1);
- if (ret < 0)
- goto err_open;
- } else {
- if (v4l2_fh_is_singular_file(file)) {
- ret = rvin_power_parallel(vin, true);
- if (ret < 0)
- goto err_open;
-
- ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler);
- if (ret)
- goto err_parallel;
- }
- }
+ else if (v4l2_fh_is_singular_file(file))
+ ret = rvin_power_parallel(vin, true);
+
+ if (ret < 0)
+ goto err_open;
+
+ ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler);
+ if (ret)
+ goto err_power;
+
mutex_unlock(&vin->lock);
return 0;
-err_parallel:
- rvin_power_parallel(vin, false);
+err_power:
+ if (vin->info->use_mc)
+ v4l2_pipeline_pm_use(&vin->vdev.entity, 0);
+ else if (v4l2_fh_is_singular_file(file))
+ rvin_power_parallel(vin, false);
err_open:
v4l2_fh_release(file);
err_unlock:
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index 0b13b34d03e3..a36b0824f81d 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -126,6 +126,7 @@ struct rvin_group_route {
* struct rvin_info - Information about the particular VIN implementation
* @model: VIN model
* @use_mc: use media controller instead of controlling subdevice
+ * @nv12: support outputing NV12 pixel format
* @max_width: max input width the VIN supports
* @max_height: max input height the VIN supports
* @routes: list of possible routes from the CSI-2 recivers to
@@ -134,6 +135,7 @@ struct rvin_group_route {
struct rvin_info {
enum model_id model;
bool use_mc;
+ bool nv12;
unsigned int max_width;
unsigned int max_height;
@@ -176,8 +178,10 @@ struct rvin_info {
*
* @crop: active cropping
* @compose: active composing
- * @source: active size of the video source
+ * @src_rect: active size of the video source
* @std: active video standard of the video source
+ *
+ * @alpha: Alpha component to fill in for supported pixel formats
*/
struct rvin_dev {
struct device *dev;
@@ -213,8 +217,10 @@ struct rvin_dev {
struct v4l2_rect crop;
struct v4l2_rect compose;
- struct v4l2_rect source;
+ struct v4l2_rect src_rect;
v4l2_std_id std;
+
+ unsigned int alpha;
};
#define vin_to_source(vin) ((vin)->parallel->subdev)
@@ -260,11 +266,14 @@ void rvin_dma_unregister(struct rvin_dev *vin);
int rvin_v4l2_register(struct rvin_dev *vin);
void rvin_v4l2_unregister(struct rvin_dev *vin);
-const struct rvin_video_format *rvin_format_from_pixel(u32 pixelformat);
+const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
+ u32 pixelformat);
+
/* Cropping, composing and scaling */
void rvin_crop_scale_comp(struct rvin_dev *vin);
int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel);
+void rvin_set_alpha(struct rvin_dev *vin, unsigned int alpha);
#endif
diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
index 608e5217ccd5..0f267a237b42 100644
--- a/drivers/media/platform/rcar_drif.c
+++ b/drivers/media/platform/rcar_drif.c
@@ -912,6 +912,7 @@ static int rcar_drif_g_fmt_sdr_cap(struct file *file, void *priv,
{
struct rcar_drif_sdr *sdr = video_drvdata(file);
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
f->fmt.sdr.pixelformat = sdr->fmt->pixelformat;
f->fmt.sdr.buffersize = sdr->fmt->buffersize;
diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c
index 43aae9b6bb20..97bed45360f0 100644
--- a/drivers/media/platform/rcar_fdp1.c
+++ b/drivers/media/platform/rcar_fdp1.c
@@ -2122,6 +2122,7 @@ static int fdp1_open(struct file *file)
if (ctx->hdl.error) {
ret = ctx->hdl.error;
v4l2_ctrl_handler_free(&ctx->hdl);
+ kfree(ctx);
goto done;
}
@@ -2306,7 +2307,7 @@ static int fdp1_probe(struct platform_device *pdev)
fdp1->fcp = rcar_fcp_get(fcp_node);
of_node_put(fcp_node);
if (IS_ERR(fdp1->fcp)) {
- dev_err(&pdev->dev, "FCP not found (%ld)\n",
+ dev_dbg(&pdev->dev, "FCP not found (%ld)\n",
PTR_ERR(fdp1->fcp));
return PTR_ERR(fdp1->fcp);
}
@@ -2368,7 +2369,7 @@ static int fdp1_probe(struct platform_device *pdev)
dprintk(fdp1, "FDP1 Version R-Car H3\n");
break;
case FD1_IP_M3N:
- dprintk(fdp1, "FDP1 Version R-Car M3N\n");
+ dprintk(fdp1, "FDP1 Version R-Car M3-N\n");
break;
case FD1_IP_E3:
dprintk(fdp1, "FDP1 Version R-Car E3\n");
diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c
index 57d0c0f9fa4b..197b3991330d 100644
--- a/drivers/media/platform/renesas-ceu.c
+++ b/drivers/media/platform/renesas-ceu.c
@@ -1659,10 +1659,8 @@ static int ceu_probe(struct platform_device *pdev)
}
ret = platform_get_irq(pdev, 0);
- if (ret < 0) {
- dev_err(dev, "Failed to get irq: %d\n", ret);
+ if (ret < 0)
goto error_free_ceudev;
- }
irq = ret;
ret = devm_request_irq(dev, irq, ceu_irq,
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 5283d4533fa0..e9ff12b6b5bb 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -831,7 +831,6 @@ static int rga_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(rga->dev, "failed to get irq\n");
ret = irq;
goto err_put_clk;
}
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index a876d0873ebc..2fb45db8e4ba 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -641,10 +641,6 @@ static int s3c_camif_vidioc_querycap(struct file *file, void *priv,
strscpy(cap->card, S3C_CAMIF_DRIVER_NAME, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s.%d",
dev_name(vp->camif->dev), vp->id);
-
- cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -685,10 +681,7 @@ static int s3c_camif_vidioc_enum_fmt(struct file *file, void *priv,
if (!fmt)
return -EINVAL;
- strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
-
- pr_debug("fmt(%d): %s\n", f->index, f->description);
return 0;
}
@@ -802,10 +795,10 @@ static int s3c_camif_vidioc_s_fmt(struct file *file, void *priv,
if (vp->owner == NULL)
vp->owner = priv;
- pr_debug("%ux%u. payload: %u. fmt: %s. %d %d. sizeimage: %d. bpl: %d\n",
- out_frame->f_width, out_frame->f_height, vp->payload, fmt->name,
- pix->width * pix->height * fmt->depth, fmt->depth,
- pix->sizeimage, pix->bytesperline);
+ pr_debug("%ux%u. payload: %u. fmt: 0x%08x. %d %d. sizeimage: %d. bpl: %d\n",
+ out_frame->f_width, out_frame->f_height, vp->payload,
+ fmt->fourcc, pix->width * pix->height * fmt->depth,
+ fmt->depth, pix->sizeimage, pix->bytesperline);
return 0;
}
@@ -1163,6 +1156,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx)
goto err_me_cleanup;
vfd->ctrl_handler = &vp->ctrl_handler;
+ vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
if (ret)
diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c
index b05ce0149ca1..c6fbcd7036d6 100644
--- a/drivers/media/platform/s3c-camif/camif-core.c
+++ b/drivers/media/platform/s3c-camif/camif-core.c
@@ -42,7 +42,6 @@ static char *camif_clocks[CLK_MAX_NUM] = {
static const struct camif_fmt camif_formats[] = {
{
- .name = "YUV 4:2:2 planar, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV422P,
.depth = 16,
.ybpp = 1,
@@ -51,7 +50,6 @@ static const struct camif_fmt camif_formats[] = {
.flags = FMT_FL_S3C24XX_CODEC |
FMT_FL_S3C64XX,
}, {
- .name = "YUV 4:2:0 planar, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = 12,
.ybpp = 1,
@@ -60,7 +58,6 @@ static const struct camif_fmt camif_formats[] = {
.flags = FMT_FL_S3C24XX_CODEC |
FMT_FL_S3C64XX,
}, {
- .name = "YVU 4:2:0 planar, Y/Cr/Cb",
.fourcc = V4L2_PIX_FMT_YVU420,
.depth = 12,
.ybpp = 1,
@@ -69,7 +66,6 @@ static const struct camif_fmt camif_formats[] = {
.flags = FMT_FL_S3C24XX_CODEC |
FMT_FL_S3C64XX,
}, {
- .name = "RGB565, 16 bpp",
.fourcc = V4L2_PIX_FMT_RGB565X,
.depth = 16,
.ybpp = 2,
@@ -78,7 +74,6 @@ static const struct camif_fmt camif_formats[] = {
.flags = FMT_FL_S3C24XX_PREVIEW |
FMT_FL_S3C64XX,
}, {
- .name = "XRGB8888, 32 bpp",
.fourcc = V4L2_PIX_FMT_RGB32,
.depth = 32,
.ybpp = 4,
@@ -87,7 +82,6 @@ static const struct camif_fmt camif_formats[] = {
.flags = FMT_FL_S3C24XX_PREVIEW |
FMT_FL_S3C64XX,
}, {
- .name = "BGR666",
.fourcc = V4L2_PIX_FMT_BGR666,
.depth = 32,
.ybpp = 4,
@@ -386,10 +380,8 @@ static int camif_request_irqs(struct platform_device *pdev,
init_waitqueue_head(&vp->irq_queue);
irq = platform_get_irq(pdev, i);
- if (irq <= 0) {
- dev_err(&pdev->dev, "failed to get IRQ %d\n", i);
+ if (irq <= 0)
return -ENXIO;
- }
ret = devm_request_irq(&pdev->dev, irq, s3c_camif_irq_handler,
0, dev_name(&pdev->dev), vp);
diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h
index efdc00b4ec6f..f937e638490f 100644
--- a/drivers/media/platform/s3c-camif/camif-core.h
+++ b/drivers/media/platform/s3c-camif/camif-core.h
@@ -89,7 +89,6 @@ enum img_fmt {
* @ybpp: number of luminance bytes per pixel
*/
struct camif_fmt {
- char *name;
u32 fourcc;
u32 color;
u16 colplanes;
diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c
index 1a65532dc36d..e80204f5720c 100644
--- a/drivers/media/platform/s3c-camif/camif-regs.c
+++ b/drivers/media/platform/s3c-camif/camif-regs.c
@@ -553,7 +553,7 @@ void camif_hw_disable_capture(struct camif_vp *vp)
void camif_hw_dump_regs(struct camif_dev *camif, const char *label)
{
- struct {
+ static const struct {
u32 offset;
const char * const name;
} registers[] = {
diff --git a/drivers/media/platform/s3c-camif/camif-regs.h b/drivers/media/platform/s3c-camif/camif-regs.h
index 29f839cdb486..052948a7b669 100644
--- a/drivers/media/platform/s3c-camif/camif-regs.h
+++ b/drivers/media/platform/s3c-camif/camif-regs.h
@@ -9,6 +9,8 @@
#ifndef CAMIF_REGS_H_
#define CAMIF_REGS_H_
+#include <linux/bitops.h>
+
#include "camif-core.h"
#include <media/drv-intf/s3c_camif.h>
@@ -19,7 +21,7 @@
/* Camera input format */
#define S3C_CAMIF_REG_CISRCFMT 0x00
-#define CISRCFMT_ITU601_8BIT (1 << 31)
+#define CISRCFMT_ITU601_8BIT BIT(31)
#define CISRCFMT_ITU656_8BIT (0 << 31)
#define CISRCFMT_ORDER422_YCBYCR (0 << 14)
#define CISRCFMT_ORDER422_YCRYCB (1 << 14)
@@ -30,14 +32,14 @@
/* Window offset */
#define S3C_CAMIF_REG_CIWDOFST 0x04
-#define CIWDOFST_WINOFSEN (1 << 31)
-#define CIWDOFST_CLROVCOFIY (1 << 30)
-#define CIWDOFST_CLROVRLB_PR (1 << 28)
-/* #define CIWDOFST_CLROVPRFIY (1 << 27) */
-#define CIWDOFST_CLROVCOFICB (1 << 15)
-#define CIWDOFST_CLROVCOFICR (1 << 14)
-#define CIWDOFST_CLROVPRFICB (1 << 13)
-#define CIWDOFST_CLROVPRFICR (1 << 12)
+#define CIWDOFST_WINOFSEN BIT(31)
+#define CIWDOFST_CLROVCOFIY BIT(30)
+#define CIWDOFST_CLROVRLB_PR BIT(28)
+/* #define CIWDOFST_CLROVPRFIY BIT(27) */
+#define CIWDOFST_CLROVCOFICB BIT(15)
+#define CIWDOFST_CLROVCOFICR BIT(14)
+#define CIWDOFST_CLROVPRFICB BIT(13)
+#define CIWDOFST_CLROVPRFICR BIT(12)
#define CIWDOFST_OFST_MASK (0x7ff << 16 | 0x7ff)
/* Window offset 2 */
@@ -46,24 +48,24 @@
/* Global control */
#define S3C_CAMIF_REG_CIGCTRL 0x08
-#define CIGCTRL_SWRST (1 << 31)
-#define CIGCTRL_CAMRST (1 << 30)
+#define CIGCTRL_SWRST BIT(31)
+#define CIGCTRL_CAMRST BIT(30)
#define CIGCTRL_TESTPATTERN_NORMAL (0 << 27)
#define CIGCTRL_TESTPATTERN_COLOR_BAR (1 << 27)
#define CIGCTRL_TESTPATTERN_HOR_INC (2 << 27)
#define CIGCTRL_TESTPATTERN_VER_INC (3 << 27)
#define CIGCTRL_TESTPATTERN_MASK (3 << 27)
-#define CIGCTRL_INVPOLPCLK (1 << 26)
-#define CIGCTRL_INVPOLVSYNC (1 << 25)
-#define CIGCTRL_INVPOLHREF (1 << 24)
-#define CIGCTRL_IRQ_OVFEN (1 << 22)
-#define CIGCTRL_HREF_MASK (1 << 21)
-#define CIGCTRL_IRQ_LEVEL (1 << 20)
+#define CIGCTRL_INVPOLPCLK BIT(26)
+#define CIGCTRL_INVPOLVSYNC BIT(25)
+#define CIGCTRL_INVPOLHREF BIT(24)
+#define CIGCTRL_IRQ_OVFEN BIT(22)
+#define CIGCTRL_HREF_MASK BIT(21)
+#define CIGCTRL_IRQ_LEVEL BIT(20)
/* IRQ_CLR_C, IRQ_CLR_P */
-#define CIGCTRL_IRQ_CLR(id) (1 << (19 - (id)))
-#define CIGCTRL_FIELDMODE (1 << 2)
-#define CIGCTRL_INVPOLFIELD (1 << 1)
-#define CIGCTRL_CAM_INTERLACE (1 << 0)
+#define CIGCTRL_IRQ_CLR(id) BIT(19 - (id))
+#define CIGCTRL_FIELDMODE BIT(2)
+#define CIGCTRL_INVPOLFIELD BIT(1)
+#define CIGCTRL_CAM_INTERLACE BIT(0)
/* Y DMA output frame start address. n = 0..3. */
#define S3C_CAMIF_REG_CIYSA(id, n) (0x18 + (id) * 0x54 + (n) * 4)
@@ -74,8 +76,8 @@
/* CICOTRGFMT, CIPRTRGFMT - Target format */
#define S3C_CAMIF_REG_CITRGFMT(id, _offs) (0x48 + (id) * (0x34 + (_offs)))
-#define CITRGFMT_IN422 (1 << 31) /* only for s3c24xx */
-#define CITRGFMT_OUT422 (1 << 30) /* only for s3c24xx */
+#define CITRGFMT_IN422 BIT(31) /* only for s3c24xx */
+#define CITRGFMT_OUT422 BIT(30) /* only for s3c24xx */
#define CITRGFMT_OUTFORMAT_YCBCR420 (0 << 29) /* only for s3c6410 */
#define CITRGFMT_OUTFORMAT_YCBCR422 (1 << 29) /* only for s3c6410 */
#define CITRGFMT_OUTFORMAT_YCBCR422I (2 << 29) /* only for s3c6410 */
@@ -88,7 +90,7 @@
#define CITRGFMT_FLIP_180 (3 << 14)
#define CITRGFMT_FLIP_MASK (3 << 14)
/* Preview path only */
-#define CITRGFMT_ROT90_PR (1 << 13)
+#define CITRGFMT_ROT90_PR BIT(13)
#define CITRGFMT_TARGETVSIZE(x) ((x) << 0)
#define CITRGFMT_TARGETSIZE_MASK ((0x1fff << 16) | 0x1fff)
@@ -102,7 +104,7 @@
#define CICTRL_RGBBURST2(x) ((x) << 14)
#define CICTRL_CBURST1(x) ((x) << 9)
#define CICTRL_CBURST2(x) ((x) << 4)
-#define CICTRL_LASTIRQ_ENABLE (1 << 2)
+#define CICTRL_LASTIRQ_ENABLE BIT(2)
#define CICTRL_ORDER422_MASK (3 << 0)
/* CICOSCPRERATIO, CIPRSCPRERATIO. Pre-scaler control 1. */
@@ -113,22 +115,22 @@
/* CICOSCCTRL, CIPRSCCTRL. Main scaler control. */
#define S3C_CAMIF_REG_CISCCTRL(id, _offs) (0x58 + (id) * (0x34 + (_offs)))
-#define CISCCTRL_SCALERBYPASS (1 << 31)
+#define CISCCTRL_SCALERBYPASS BIT(31)
/* s3c244x preview path only, s3c64xx both */
-#define CIPRSCCTRL_SAMPLE (1 << 31)
+#define CIPRSCCTRL_SAMPLE BIT(31)
/* 0 - 16-bit RGB, 1 - 24-bit RGB */
-#define CIPRSCCTRL_RGB_FORMAT_24BIT (1 << 30) /* only for s3c244x */
-#define CIPRSCCTRL_SCALEUP_H (1 << 29) /* only for s3c244x */
-#define CIPRSCCTRL_SCALEUP_V (1 << 28) /* only for s3c244x */
+#define CIPRSCCTRL_RGB_FORMAT_24BIT BIT(30) /* only for s3c244x */
+#define CIPRSCCTRL_SCALEUP_H BIT(29) /* only for s3c244x */
+#define CIPRSCCTRL_SCALEUP_V BIT(28) /* only for s3c244x */
/* s3c64xx */
-#define CISCCTRL_SCALEUP_H (1 << 30)
-#define CISCCTRL_SCALEUP_V (1 << 29)
+#define CISCCTRL_SCALEUP_H BIT(30)
+#define CISCCTRL_SCALEUP_V BIT(29)
#define CISCCTRL_SCALEUP_MASK (0x3 << 29)
-#define CISCCTRL_CSCR2Y_WIDE (1 << 28)
-#define CISCCTRL_CSCY2R_WIDE (1 << 27)
-#define CISCCTRL_LCDPATHEN_FIFO (1 << 26)
-#define CISCCTRL_INTERLACE (1 << 25)
-#define CISCCTRL_SCALERSTART (1 << 15)
+#define CISCCTRL_CSCR2Y_WIDE BIT(28)
+#define CISCCTRL_CSCY2R_WIDE BIT(27)
+#define CISCCTRL_LCDPATHEN_FIFO BIT(26)
+#define CISCCTRL_INTERLACE BIT(25)
+#define CISCCTRL_SCALERSTART BIT(15)
#define CISCCTRL_INRGB_FMT_RGB565 (0 << 13)
#define CISCCTRL_INRGB_FMT_RGB666 (1 << 13)
#define CISCCTRL_INRGB_FMT_RGB888 (2 << 13)
@@ -137,8 +139,8 @@
#define CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11)
#define CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11)
#define CISCCTRL_OUTRGB_FMT_MASK (3 << 11)
-#define CISCCTRL_EXTRGB_EXTENSION (1 << 10)
-#define CISCCTRL_ONE2ONE (1 << 9)
+#define CISCCTRL_EXTRGB_EXTENSION BIT(10)
+#define CISCCTRL_ONE2ONE BIT(9)
#define CISCCTRL_MAIN_RATIO_MASK (0x1ff << 16 | 0x1ff)
/* CICOTAREA, CIPRTAREA. Target area for DMA (Hsize x Vsize). */
@@ -147,38 +149,38 @@
/* Codec (id = 0) or preview (id = 1) path status. */
#define S3C_CAMIF_REG_CISTATUS(id, _offs) (0x64 + (id) * (0x34 + (_offs)))
-#define CISTATUS_OVFIY_STATUS (1 << 31)
-#define CISTATUS_OVFICB_STATUS (1 << 30)
-#define CISTATUS_OVFICR_STATUS (1 << 29)
+#define CISTATUS_OVFIY_STATUS BIT(31)
+#define CISTATUS_OVFICB_STATUS BIT(30)
+#define CISTATUS_OVFICR_STATUS BIT(29)
#define CISTATUS_OVF_MASK (0x7 << 29)
#define CIPRSTATUS_OVF_MASK (0x3 << 30)
-#define CISTATUS_VSYNC_STATUS (1 << 28)
+#define CISTATUS_VSYNC_STATUS BIT(28)
#define CISTATUS_FRAMECNT_MASK (3 << 26)
#define CISTATUS_FRAMECNT(__reg) (((__reg) >> 26) & 0x3)
-#define CISTATUS_WINOFSTEN_STATUS (1 << 25)
-#define CISTATUS_IMGCPTEN_STATUS (1 << 22)
-#define CISTATUS_IMGCPTENSC_STATUS (1 << 21)
-#define CISTATUS_VSYNC_A_STATUS (1 << 20)
-#define CISTATUS_FRAMEEND_STATUS (1 << 19) /* 17 on s3c64xx */
+#define CISTATUS_WINOFSTEN_STATUS BIT(25)
+#define CISTATUS_IMGCPTEN_STATUS BIT(22)
+#define CISTATUS_IMGCPTENSC_STATUS BIT(21)
+#define CISTATUS_VSYNC_A_STATUS BIT(20)
+#define CISTATUS_FRAMEEND_STATUS BIT(19) /* 17 on s3c64xx */
/* Image capture enable */
#define S3C_CAMIF_REG_CIIMGCPT(_offs) (0xa0 + (_offs))
-#define CIIMGCPT_IMGCPTEN (1 << 31)
-#define CIIMGCPT_IMGCPTEN_SC(id) (1 << (30 - (id)))
+#define CIIMGCPT_IMGCPTEN BIT(31)
+#define CIIMGCPT_IMGCPTEN_SC(id) BIT(30 - (id))
/* Frame control: 1 - one-shot, 0 - free run */
-#define CIIMGCPT_CPT_FREN_ENABLE(id) (1 << (25 - (id)))
+#define CIIMGCPT_CPT_FREN_ENABLE(id) BIT(25 - (id))
#define CIIMGCPT_CPT_FRMOD_ENABLE (0 << 18)
-#define CIIMGCPT_CPT_FRMOD_CNT (1 << 18)
+#define CIIMGCPT_CPT_FRMOD_CNT BIT(18)
/* Capture sequence */
#define S3C_CAMIF_REG_CICPTSEQ 0xc4
/* Image effects */
#define S3C_CAMIF_REG_CIIMGEFF(_offs) (0xb0 + (_offs))
-#define CIIMGEFF_IE_ENABLE(id) (1 << (30 + (id)))
+#define CIIMGEFF_IE_ENABLE(id) BIT(30 + (id))
#define CIIMGEFF_IE_ENABLE_MASK (3 << 30)
/* Image effect: 1 - after scaler, 0 - before scaler */
-#define CIIMGEFF_IE_AFTER_SC (1 << 29)
+#define CIIMGEFF_IE_AFTER_SC BIT(29)
#define CIIMGEFF_FIN_MASK (7 << 26)
#define CIIMGEFF_FIN_BYPASS (0 << 26)
#define CIIMGEFF_FIN_ARBITRARY (1 << 26)
@@ -207,8 +209,8 @@
/* Real input DMA data size. n = 0 - codec, 1 - preview. */
#define S3C_CAMIF_REG_MSWIDTH(id) (0xf8 + (id) * 0x2c)
-#define AUTOLOAD_ENABLE (1 << 31)
-#define ADDR_CH_DIS (1 << 30)
+#define AUTOLOAD_ENABLE BIT(31)
+#define ADDR_CH_DIS BIT(30)
#define MSHEIGHT(x) (((x) & 0x3ff) << 16)
#define MSWIDTH(x) ((x) & 0x3ff)
@@ -219,12 +221,12 @@
#define MSCTRL_ORDER422_M_CBYCRY (2 << 4)
#define MSCTRL_ORDER422_M_CRYCBY (3 << 4)
/* 0 - camera, 1 - DMA */
-#define MSCTRL_SEL_DMA_CAM (1 << 3)
+#define MSCTRL_SEL_DMA_CAM BIT(3)
#define MSCTRL_INFORMAT_M_YCBCR420 (0 << 1)
#define MSCTRL_INFORMAT_M_YCBCR422 (1 << 1)
#define MSCTRL_INFORMAT_M_YCBCR422I (2 << 1)
#define MSCTRL_INFORMAT_M_RGB (3 << 1)
-#define MSCTRL_ENVID_M (1 << 0)
+#define MSCTRL_ENVID_M BIT(0)
/* CICOSCOSY, CIPRSCOSY. Scan line Y/Cb/Cr offset. */
#define S3C_CAMIF_REG_CISSY(id) (0x12c + (id) * 0x0c)
diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c
index ea6231b387ed..2a3e7ffefe0a 100644
--- a/drivers/media/platform/s5p-cec/s5p_cec.c
+++ b/drivers/media/platform/s5p-cec/s5p_cec.c
@@ -214,21 +214,23 @@ 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);
- if (cec->notifier == NULL)
- return -ENOMEM;
-
cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, CEC_NAME,
- CEC_CAP_DEFAULTS | (needs_hpd ? CEC_CAP_NEEDS_HPD : 0), 1);
+ CEC_CAP_DEFAULTS | (needs_hpd ? CEC_CAP_NEEDS_HPD : 0) |
+ CEC_CAP_CONNECTOR_INFO, 1);
ret = PTR_ERR_OR_ZERO(cec->adap);
if (ret)
return ret;
- ret = cec_register_adapter(cec->adap, &pdev->dev);
- if (ret)
+ cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL,
+ cec->adap);
+ if (!cec->notifier) {
+ ret = -ENOMEM;
goto err_delete_adapter;
+ }
- cec_register_cec_notifier(cec->adap, cec->notifier);
+ ret = cec_register_adapter(cec->adap, &pdev->dev);
+ if (ret)
+ goto err_notifier;
platform_set_drvdata(pdev, cec);
pm_runtime_enable(dev);
@@ -236,6 +238,9 @@ static int s5p_cec_probe(struct platform_device *pdev)
dev_dbg(dev, "successfully probed\n");
return 0;
+err_notifier:
+ cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
+
err_delete_adapter:
cec_delete_adapter(cec->adap);
return ret;
@@ -245,8 +250,8 @@ static int s5p_cec_remove(struct platform_device *pdev)
{
struct s5p_cec_dev *cec = platform_get_drvdata(pdev);
+ cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
cec_unregister_adapter(cec->adap);
- cec_notifier_put(cec->notifier);
pm_runtime_disable(&pdev->dev);
return 0;
}
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index 152d192d5c3f..f5f05ea9f521 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -29,31 +29,26 @@
static struct g2d_fmt formats[] = {
{
- .name = "XRGB_8888",
.fourcc = V4L2_PIX_FMT_RGB32,
.depth = 32,
.hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_8888),
},
{
- .name = "RGB_565",
.fourcc = V4L2_PIX_FMT_RGB565X,
.depth = 16,
.hw = COLOR_MODE(ORDER_XRGB, MODE_RGB_565),
},
{
- .name = "XRGB_1555",
.fourcc = V4L2_PIX_FMT_RGB555X,
.depth = 16,
.hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_1555),
},
{
- .name = "XRGB_4444",
.fourcc = V4L2_PIX_FMT_RGB444,
.depth = 16,
.hw = COLOR_MODE(ORDER_XRGB, MODE_XRGB_4444),
},
{
- .name = "PACKED_RGB_888",
.fourcc = V4L2_PIX_FMT_RGB24,
.depth = 24,
.hw = COLOR_MODE(ORDER_XRGB, MODE_PACKED_RGB_888),
@@ -296,19 +291,14 @@ static int vidioc_querycap(struct file *file, void *priv,
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;
return 0;
}
static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f)
{
- struct g2d_fmt *fmt;
if (f->index >= NUM_FORMATS)
return -EINVAL;
- fmt = &formats[f->index];
- f->pixelformat = fmt->fourcc;
- strscpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = formats[f->index].fourcc;
return 0;
}
@@ -704,6 +694,7 @@ static int g2d_probe(struct platform_device *pdev)
set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags);
vfd->lock = &dev->mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
diff --git a/drivers/media/platform/s5p-g2d/g2d.h b/drivers/media/platform/s5p-g2d/g2d.h
index def0ec0dabeb..c2309c1370da 100644
--- a/drivers/media/platform/s5p-g2d/g2d.h
+++ b/drivers/media/platform/s5p-g2d/g2d.h
@@ -61,7 +61,6 @@ struct g2d_ctx {
};
struct g2d_fmt {
- char *name;
u32 fourcc;
int depth;
u32 hw;
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index a3bc884b7df1..ac2162235cef 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -35,7 +35,6 @@
static struct s5p_jpeg_fmt sjpeg_formats[] = {
{
- .name = "JPEG JFIF",
.fourcc = V4L2_PIX_FMT_JPEG,
.flags = SJPEG_FMT_FLAG_ENC_CAPTURE |
SJPEG_FMT_FLAG_DEC_OUTPUT |
@@ -44,7 +43,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
SJPEG_FMT_FLAG_EXYNOS4,
},
{
- .name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.colplanes = 1,
@@ -57,7 +55,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
{
- .name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.colplanes = 1,
@@ -70,7 +67,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
{
- .name = "YUV 4:2:2 packed, YCbYCr",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
.colplanes = 1,
@@ -83,7 +79,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
{
- .name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
.depth = 16,
.colplanes = 1,
@@ -96,7 +91,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
{
- .name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
.depth = 16,
.colplanes = 1,
@@ -109,7 +103,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
{
- .name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
.colplanes = 1,
@@ -122,7 +115,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
{
- .name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_VYUY,
.depth = 16,
.colplanes = 1,
@@ -135,7 +127,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
{
- .name = "RGB565",
.fourcc = V4L2_PIX_FMT_RGB565,
.depth = 16,
.colplanes = 1,
@@ -148,7 +139,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
{
- .name = "RGB565",
.fourcc = V4L2_PIX_FMT_RGB565,
.depth = 16,
.colplanes = 1,
@@ -161,7 +151,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
{
- .name = "RGB565X",
.fourcc = V4L2_PIX_FMT_RGB565X,
.depth = 16,
.colplanes = 1,
@@ -174,7 +163,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
{
- .name = "RGB565",
.fourcc = V4L2_PIX_FMT_RGB565,
.depth = 16,
.colplanes = 1,
@@ -186,7 +174,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
{
- .name = "ARGB8888, 32 bpp",
.fourcc = V4L2_PIX_FMT_RGB32,
.depth = 32,
.colplanes = 1,
@@ -199,7 +186,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
{
- .name = "ARGB8888, 32 bpp",
.fourcc = V4L2_PIX_FMT_RGB32,
.depth = 32,
.colplanes = 1,
@@ -212,7 +198,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
{
- .name = "YUV 4:4:4 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV24,
.depth = 24,
.colplanes = 2,
@@ -225,7 +210,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
{
- .name = "YUV 4:4:4 planar, Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV42,
.depth = 24,
.colplanes = 2,
@@ -238,7 +222,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
{
- .name = "YUV 4:2:2 planar, Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV61,
.depth = 16,
.colplanes = 2,
@@ -251,7 +234,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
{
- .name = "YUV 4:2:2 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV16,
.depth = 16,
.colplanes = 2,
@@ -264,7 +246,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
{
- .name = "YUV 4:2:0 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12,
.depth = 12,
.colplanes = 2,
@@ -277,7 +258,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
{
- .name = "YUV 4:2:0 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12,
.depth = 12,
.colplanes = 2,
@@ -290,7 +270,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
{
- .name = "YUV 4:2:0 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12,
.depth = 12,
.colplanes = 2,
@@ -303,7 +282,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
{
- .name = "YUV 4:2:0 planar, Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV21,
.depth = 12,
.colplanes = 2,
@@ -316,7 +294,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
{
- .name = "YUV 4:2:0 planar, Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV21,
.depth = 12,
.colplanes = 2,
@@ -330,7 +307,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
{
- .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = 12,
.colplanes = 3,
@@ -343,7 +319,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
{
- .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
.fourcc = V4L2_PIX_FMT_YUV420,
.depth = 12,
.colplanes = 3,
@@ -356,7 +331,6 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
{
- .name = "Gray",
.fourcc = V4L2_PIX_FMT_GREY,
.depth = 8,
.colplanes = 1,
@@ -1262,7 +1236,6 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
}
result->sof = sof;
result->sof_len = sof_len;
- result->components = components;
return true;
}
@@ -1285,8 +1258,6 @@ static int s5p_jpeg_querycap(struct file *file, void *priv,
}
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(ctx->jpeg->dev));
- cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1314,7 +1285,6 @@ static int enum_fmt(struct s5p_jpeg_ctx *ctx,
if (i >= n)
return -EINVAL;
- strscpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
f->pixelformat = sjpeg_formats[i].fourcc;
return 0;
@@ -2974,6 +2944,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
jpeg->vfd_encoder->lock = &jpeg->lock;
jpeg->vfd_encoder->v4l2_dev = &jpeg->v4l2_dev;
jpeg->vfd_encoder->vfl_dir = VFL_DIR_M2M;
+ jpeg->vfd_encoder->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
if (ret) {
@@ -3003,6 +2974,7 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
jpeg->vfd_decoder->lock = &jpeg->lock;
jpeg->vfd_decoder->v4l2_dev = &jpeg->v4l2_dev;
jpeg->vfd_decoder->vfl_dir = VFL_DIR_M2M;
+ jpeg->vfd_decoder->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
if (ret) {
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index 34f87f6c02f2..4407fe775afa 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -150,7 +150,6 @@ struct s5p_jpeg_variant {
/**
* struct jpeg_fmt - driver's internal color format data
- * @name: format description
* @fourcc: the fourcc code, 0 if not applicable
* @depth: number of bits per pixel
* @colplanes: number of color planes (1 for packed formats)
@@ -159,7 +158,6 @@ struct s5p_jpeg_variant {
* @flags: flags describing format applicability
*/
struct s5p_jpeg_fmt {
- char *name;
u32 fourcc;
int depth;
int colplanes;
@@ -192,7 +190,6 @@ struct s5p_jpeg_marker {
* @dqt: DQT markers' positions relative to the buffer beginning
* @sof: SOF0 marker's position relative to the buffer beginning
* @sof_len: SOF0 marker's payload length (without length field itself)
- * @components: number of image components
* @size: image buffer size in bytes
*/
struct s5p_jpeg_q_data {
@@ -204,7 +201,6 @@ struct s5p_jpeg_q_data {
struct s5p_jpeg_marker dqt;
u32 sof;
u32 sof_len;
- u32 components;
u32 size;
};
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
index bab7fa46b89a..86f376b50581 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
@@ -121,14 +121,14 @@
/* JPEG timer setting register */
#define S5P_JPG_TIMER_SE 0x7c
-#define S5P_TIMER_INT_EN_MASK (0x1 << 31)
-#define S5P_TIMER_INT_EN (0x1 << 31)
+#define S5P_TIMER_INT_EN_MASK (0x1UL << 31)
+#define S5P_TIMER_INT_EN (0x1UL << 31)
#define S5P_TIMER_INIT_MASK 0x7fffffff
/* JPEG timer status register */
#define S5P_JPG_TIMER_ST 0x80
#define S5P_TIMER_INT_STAT_SHIFT 31
-#define S5P_TIMER_INT_STAT_MASK (0x1 << S5P_TIMER_INT_STAT_SHIFT)
+#define S5P_TIMER_INT_STAT_MASK (0x1UL << S5P_TIMER_INT_STAT_SHIFT)
#define S5P_TIMER_CNT_SHIFT 0
#define S5P_TIMER_CNT_MASK 0x7fffffff
@@ -562,13 +562,13 @@
/* JPEG timer setting register */
#define EXYNOS3250_TIMER_SE 0x148
#define EXYNOS3250_TIMER_INT_EN_SHIFT 31
-#define EXYNOS3250_TIMER_INT_EN (1 << EXYNOS3250_TIMER_INT_EN_SHIFT)
+#define EXYNOS3250_TIMER_INT_EN (1UL << EXYNOS3250_TIMER_INT_EN_SHIFT)
#define EXYNOS3250_TIMER_INIT_MASK 0x7fffffff
/* JPEG timer status register */
#define EXYNOS3250_TIMER_ST 0x14c
#define EXYNOS3250_TIMER_INT_STAT_SHIFT 31
-#define EXYNOS3250_TIMER_INT_STAT (1 << EXYNOS3250_TIMER_INT_STAT_SHIFT)
+#define EXYNOS3250_TIMER_INT_STAT (1UL << EXYNOS3250_TIMER_INT_STAT_SHIFT)
#define EXYNOS3250_TIMER_CNT_SHIFT 0
#define EXYNOS3250_TIMER_CNT_MASK 0x7fffffff
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index 5dc086516360..96d1ecd1521b 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -718,7 +718,6 @@ struct s5p_mfc_ctx {
* used by the MFC
*/
struct s5p_mfc_fmt {
- char *name;
u32 fourcc;
u32 codec_mode;
enum s5p_mfc_fmt_type type;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 4017c8b471f4..61e144a35201 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -29,7 +29,6 @@
static struct s5p_mfc_fmt formats[] = {
{
- .name = "4:2:0 2 Planes 16x16 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT_16X16,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
@@ -37,7 +36,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V6_BIT | MFC_V7_BIT,
},
{
- .name = "4:2:0 2 Planes 64x32 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
@@ -45,7 +43,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5_BIT,
},
{
- .name = "4:2:0 2 Planes Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
@@ -53,7 +50,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V6PLUS_BITS,
},
{
- .name = "4:2:0 2 Planes Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV21M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
@@ -61,7 +57,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V6PLUS_BITS,
},
{
- .name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
.codec_mode = S5P_MFC_CODEC_H264_DEC,
.type = MFC_FMT_DEC,
@@ -69,7 +64,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "H264/MVC Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264_MVC,
.codec_mode = S5P_MFC_CODEC_H264_MVC_DEC,
.type = MFC_FMT_DEC,
@@ -77,7 +71,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V6PLUS_BITS,
},
{
- .name = "H263 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H263,
.codec_mode = S5P_MFC_CODEC_H263_DEC,
.type = MFC_FMT_DEC,
@@ -85,7 +78,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "MPEG1 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG1,
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
@@ -93,7 +85,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "MPEG2 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG2,
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
@@ -101,7 +92,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
@@ -109,7 +99,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "XviD Encoded Stream",
.fourcc = V4L2_PIX_FMT_XVID,
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
@@ -117,7 +106,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "VC1 Encoded Stream",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
.codec_mode = S5P_MFC_CODEC_VC1_DEC,
.type = MFC_FMT_DEC,
@@ -125,7 +113,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "VC1 RCV Encoded Stream",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
.codec_mode = S5P_MFC_CODEC_VC1RCV_DEC,
.type = MFC_FMT_DEC,
@@ -133,7 +120,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "VP8 Encoded Stream",
.fourcc = V4L2_PIX_FMT_VP8,
.codec_mode = S5P_MFC_CODEC_VP8_DEC,
.type = MFC_FMT_DEC,
@@ -279,7 +265,6 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
bool out)
{
struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_fmt *fmt;
int i, j = 0;
for (i = 0; i < ARRAY_SIZE(formats); ++i) {
@@ -296,9 +281,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
}
if (i == ARRAY_SIZE(formats))
return -EINVAL;
- fmt = &formats[i];
- strscpy(f->description, fmt->name, sizeof(f->description));
- f->pixelformat = fmt->fourcc;
+ f->pixelformat = formats[i].fourcc;
return 0;
}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 97e76480e942..912fe0c5ab18 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -32,7 +32,6 @@
static struct s5p_mfc_fmt formats[] = {
{
- .name = "4:2:0 2 Planes 16x16 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT_16X16,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
@@ -40,7 +39,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V6_BIT | MFC_V7_BIT,
},
{
- .name = "4:2:0 2 Planes 64x32 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
@@ -48,7 +46,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5_BIT,
},
{
- .name = "4:2:0 2 Planes Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
@@ -56,7 +53,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "4:2:0 2 Planes Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV21M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
@@ -64,7 +60,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V6PLUS_BITS,
},
{
- .name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
.codec_mode = S5P_MFC_CODEC_H264_ENC,
.type = MFC_FMT_ENC,
@@ -72,7 +67,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
.codec_mode = S5P_MFC_CODEC_MPEG4_ENC,
.type = MFC_FMT_ENC,
@@ -80,7 +74,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "H263 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H263,
.codec_mode = S5P_MFC_CODEC_H263_ENC,
.type = MFC_FMT_ENC,
@@ -88,7 +81,6 @@ static struct s5p_mfc_fmt formats[] = {
.versions = MFC_V5PLUS_BITS,
},
{
- .name = "VP8 Encoded Stream",
.fourcc = V4L2_PIX_FMT_VP8,
.codec_mode = S5P_MFC_CODEC_VP8_ENC,
.type = MFC_FMT_ENC,
@@ -1320,7 +1312,6 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
bool out)
{
struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_fmt *fmt;
int i, j = 0;
for (i = 0; i < ARRAY_SIZE(formats); ++i) {
@@ -1332,10 +1323,7 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
continue;
if (j == f->index) {
- fmt = &formats[i];
- strscpy(f->description, fmt->name,
- sizeof(f->description));
- f->pixelformat = fmt->fourcc;
+ f->pixelformat = formats[i].fourcc;
return 0;
}
++j;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index f76a07400966..49503c20d320 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -711,7 +711,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL);
if (p->pad) {
/** enable */
- reg |= (1 << 31);
+ reg |= (1UL << 31);
/** cr value */
reg &= ~(0xFF << 16);
reg |= (p->pad_cr << 16);
@@ -955,7 +955,7 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
S5P_FIMV_ENC_RC_FRAME_RATE);
shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING);
shm &= ~(0xFFFFFFFF);
- shm |= (1 << 31);
+ shm |= (1UL << 31);
shm |= ((p->rc_framerate_num & 0x7FFF) << 16);
shm |= (p->rc_framerate_denom & 0xFFFF);
s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index f7621a9051cb..a1453053e31a 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -840,7 +840,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
if (p->pad) {
reg = 0;
/** enable */
- reg |= (1 << 31);
+ reg |= (1UL << 31);
/** cr value */
reg |= ((p->pad_cr & 0xFF) << 16);
/** cb value */
diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c
index 1d0133f01e00..2ff62a488b27 100644
--- a/drivers/media/platform/seco-cec/seco-cec.c
+++ b/drivers/media/platform/seco-cec/seco-cec.c
@@ -507,10 +507,10 @@ err:
}
struct cec_dmi_match {
- char *sys_vendor;
- char *product_name;
- char *devname;
- char *conn;
+ const char *sys_vendor;
+ const char *product_name;
+ const char *devname;
+ const char *conn;
};
static const struct cec_dmi_match secocec_dmi_match_table[] = {
@@ -518,7 +518,8 @@ static const struct cec_dmi_match secocec_dmi_match_table[] = {
{ "SECO", "UDOO x86", "0000:00:02.0", "Port B" },
};
-static int secocec_cec_get_notifier(struct cec_notifier **notify)
+static struct device *secocec_cec_find_hdmi_dev(struct device *dev,
+ const char **conn)
{
int i;
@@ -533,16 +534,15 @@ static int secocec_cec_get_notifier(struct cec_notifier **notify)
d = bus_find_device_by_name(&pci_bus_type, NULL,
m->devname);
if (!d)
- return -EPROBE_DEFER;
+ return ERR_PTR(-EPROBE_DEFER);
- *notify = cec_notifier_get_conn(d, m->conn);
put_device(d);
-
- return 0;
+ *conn = m->conn;
+ return d;
}
}
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
static int secocec_acpi_probe(struct secocec_data *sdev)
@@ -573,9 +573,15 @@ static int secocec_probe(struct platform_device *pdev)
{
struct secocec_data *secocec;
struct device *dev = &pdev->dev;
+ struct device *hdmi_dev;
+ const char *conn = NULL;
int ret;
u16 val;
+ hdmi_dev = secocec_cec_find_hdmi_dev(&pdev->dev, &conn);
+ if (IS_ERR(hdmi_dev))
+ return PTR_ERR(hdmi_dev);
+
secocec = devm_kzalloc(dev, sizeof(*secocec), GFP_KERNEL);
if (!secocec)
return -ENOMEM;
@@ -617,12 +623,6 @@ static int secocec_probe(struct platform_device *pdev)
goto err;
}
- ret = secocec_cec_get_notifier(&secocec->notifier);
- if (ret) {
- dev_err(dev, "no CEC notifier available\n");
- goto err;
- }
-
ret = devm_request_threaded_irq(dev,
secocec->irq,
NULL,
@@ -640,7 +640,8 @@ static int secocec_probe(struct platform_device *pdev)
secocec->cec_adap = cec_allocate_adapter(&secocec_cec_adap_ops,
secocec,
dev_name(dev),
- CEC_CAP_DEFAULTS,
+ CEC_CAP_DEFAULTS |
+ CEC_CAP_CONNECTOR_INFO,
SECOCEC_MAX_ADDRS);
if (IS_ERR(secocec->cec_adap)) {
@@ -648,16 +649,20 @@ static int secocec_probe(struct platform_device *pdev)
goto err;
}
- ret = cec_register_adapter(secocec->cec_adap, dev);
- if (ret)
+ secocec->notifier = cec_notifier_cec_adap_register(hdmi_dev, conn,
+ secocec->cec_adap);
+ if (!secocec->notifier) {
+ ret = -ENOMEM;
goto err_delete_adapter;
+ }
- if (secocec->notifier)
- cec_register_cec_notifier(secocec->cec_adap, secocec->notifier);
+ ret = cec_register_adapter(secocec->cec_adap, dev);
+ if (ret)
+ goto err_notifier;
ret = secocec_ir_probe(secocec);
if (ret)
- goto err_delete_adapter;
+ goto err_notifier;
platform_set_drvdata(pdev, secocec);
@@ -665,9 +670,12 @@ static int secocec_probe(struct platform_device *pdev)
return ret;
+err_notifier:
+ cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap);
err_delete_adapter:
cec_delete_adapter(secocec->cec_adap);
err:
+ release_region(BRA_SMB_BASE_ADDR, 7);
dev_err(dev, "%s device probe failed\n", dev_name(dev));
return ret;
@@ -685,11 +693,9 @@ static int secocec_remove(struct platform_device *pdev)
dev_dbg(&pdev->dev, "IR disabled");
}
+ cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap);
cec_unregister_adapter(secocec->cec_adap);
- if (secocec->notifier)
- cec_notifier_put(secocec->notifier);
-
release_region(BRA_SMB_BASE_ADDR, 7);
dev_dbg(&pdev->dev, "CEC device removed");
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index 5a9ba05c996e..2b4c0d9d6928 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -81,12 +81,12 @@
struct sh_veu_dev;
struct sh_veu_file {
+ struct v4l2_fh fh;
struct sh_veu_dev *veu_dev;
bool cfg_needed;
};
struct sh_veu_format {
- char *name;
u32 fourcc;
unsigned int depth;
unsigned int ydepth;
@@ -144,14 +144,14 @@ enum sh_veu_fmt_idx {
* aligned for NV24.
*/
static const struct sh_veu_format sh_veu_fmt[] = {
- [SH_VEU_FMT_NV12] = { .ydepth = 8, .depth = 12, .name = "NV12", .fourcc = V4L2_PIX_FMT_NV12 },
- [SH_VEU_FMT_NV16] = { .ydepth = 8, .depth = 16, .name = "NV16", .fourcc = V4L2_PIX_FMT_NV16 },
- [SH_VEU_FMT_NV24] = { .ydepth = 8, .depth = 24, .name = "NV24", .fourcc = V4L2_PIX_FMT_NV24 },
- [SH_VEU_FMT_RGB332] = { .ydepth = 8, .depth = 8, .name = "RGB332", .fourcc = V4L2_PIX_FMT_RGB332 },
- [SH_VEU_FMT_RGB444] = { .ydepth = 16, .depth = 16, .name = "RGB444", .fourcc = V4L2_PIX_FMT_RGB444 },
- [SH_VEU_FMT_RGB565] = { .ydepth = 16, .depth = 16, .name = "RGB565", .fourcc = V4L2_PIX_FMT_RGB565 },
- [SH_VEU_FMT_RGB666] = { .ydepth = 32, .depth = 32, .name = "BGR666", .fourcc = V4L2_PIX_FMT_BGR666 },
- [SH_VEU_FMT_RGB24] = { .ydepth = 24, .depth = 24, .name = "RGB24", .fourcc = V4L2_PIX_FMT_RGB24 },
+ [SH_VEU_FMT_NV12] = { .ydepth = 8, .depth = 12, .fourcc = V4L2_PIX_FMT_NV12 },
+ [SH_VEU_FMT_NV16] = { .ydepth = 8, .depth = 16, .fourcc = V4L2_PIX_FMT_NV16 },
+ [SH_VEU_FMT_NV24] = { .ydepth = 8, .depth = 24, .fourcc = V4L2_PIX_FMT_NV24 },
+ [SH_VEU_FMT_RGB332] = { .ydepth = 8, .depth = 8, .fourcc = V4L2_PIX_FMT_RGB332 },
+ [SH_VEU_FMT_RGB444] = { .ydepth = 16, .depth = 16, .fourcc = V4L2_PIX_FMT_RGB444 },
+ [SH_VEU_FMT_RGB565] = { .ydepth = 16, .depth = 16, .fourcc = V4L2_PIX_FMT_RGB565 },
+ [SH_VEU_FMT_RGB666] = { .ydepth = 32, .depth = 32, .fourcc = V4L2_PIX_FMT_BGR666 },
+ [SH_VEU_FMT_RGB24] = { .ydepth = 24, .depth = 24, .fourcc = V4L2_PIX_FMT_RGB24 },
};
#define DEFAULT_IN_VFMT (struct sh_veu_vfmt){ \
@@ -348,9 +348,6 @@ static int sh_veu_querycap(struct file *file, void *priv,
strscpy(cap->driver, "sh-veu", sizeof(cap->driver));
strscpy(cap->card, "sh-mobile VEU", sizeof(cap->card));
strscpy(cap->bus_info, "platform:sh-veu", sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -359,8 +356,6 @@ static int sh_veu_enum_fmt(struct v4l2_fmtdesc *f, const int *fmt, int fmt_num)
if (f->index >= fmt_num)
return -EINVAL;
- strscpy(f->description, sh_veu_fmt[fmt[f->index]].name,
- sizeof(f->description));
f->pixelformat = sh_veu_fmt[fmt[f->index]].fourcc;
return 0;
}
@@ -967,12 +962,14 @@ static int sh_veu_open(struct file *file)
if (!veu_file)
return -ENOMEM;
+ v4l2_fh_init(&veu_file->fh, video_devdata(file));
veu_file->veu_dev = veu;
veu_file->cfg_needed = true;
file->private_data = veu_file;
pm_runtime_get_sync(veu->dev);
+ v4l2_fh_add(&veu_file->fh);
dev_dbg(veu->dev, "Created instance %p\n", veu_file);
@@ -1002,6 +999,8 @@ static int sh_veu_release(struct file *file)
}
pm_runtime_put(veu->dev);
+ v4l2_fh_del(&veu_file->fh);
+ v4l2_fh_exit(&veu_file->fh);
kfree(veu_file);
@@ -1039,6 +1038,7 @@ static const struct video_device sh_veu_videodev = {
.minor = -1,
.release = video_device_release_empty,
.vfl_dir = VFL_DIR_M2M,
+ .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
};
static const struct v4l2_m2m_ops sh_veu_m2m_ops = {
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index 5799aa4b9323..2236702c21b4 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -138,7 +138,6 @@ static void sh_vou_reg_ab_set(struct sh_vou_device *vou_dev, unsigned int reg,
struct sh_vou_fmt {
u32 pfmt;
- char *desc;
unsigned char bpp;
unsigned char bpl;
unsigned char rgb;
@@ -152,7 +151,6 @@ static struct sh_vou_fmt vou_fmt[] = {
.pfmt = V4L2_PIX_FMT_NV12,
.bpp = 12,
.bpl = 1,
- .desc = "YVU420 planar",
.yf = 0,
.rgb = 0,
},
@@ -160,7 +158,6 @@ static struct sh_vou_fmt vou_fmt[] = {
.pfmt = V4L2_PIX_FMT_NV16,
.bpp = 16,
.bpl = 1,
- .desc = "YVYU planar",
.yf = 1,
.rgb = 0,
},
@@ -168,7 +165,6 @@ static struct sh_vou_fmt vou_fmt[] = {
.pfmt = V4L2_PIX_FMT_RGB24,
.bpp = 24,
.bpl = 3,
- .desc = "RGB24",
.pkf = 2,
.rgb = 1,
},
@@ -176,7 +172,6 @@ static struct sh_vou_fmt vou_fmt[] = {
.pfmt = V4L2_PIX_FMT_RGB565,
.bpp = 16,
.bpl = 2,
- .desc = "RGB565",
.pkf = 3,
.rgb = 1,
},
@@ -184,7 +179,6 @@ static struct sh_vou_fmt vou_fmt[] = {
.pfmt = V4L2_PIX_FMT_RGB565X,
.bpp = 16,
.bpl = 2,
- .desc = "RGB565 byteswapped",
.pkf = 3,
.rgb = 1,
},
@@ -381,9 +375,6 @@ static int sh_vou_querycap(struct file *file, void *priv,
strscpy(cap->card, "SuperH VOU", sizeof(cap->card));
strscpy(cap->driver, "sh-vou", sizeof(cap->driver));
strscpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -398,9 +389,6 @@ static int sh_vou_enum_fmt_vid_out(struct file *file, void *priv,
dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
- fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- strscpy(fmt->description, vou_fmt[fmt->index].desc,
- sizeof(fmt->description));
fmt->pixelformat = vou_fmt[fmt->index].pfmt;
return 0;
@@ -494,7 +482,8 @@ static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev,
if (h_idx)
vouvcr |= (1 << 14) | vou_scale_v_fld[h_idx - 1];
- dev_dbg(vou_dev->v4l2_dev.dev, "%s: scaling 0x%x\n", fmt->desc, vouvcr);
+ dev_dbg(vou_dev->v4l2_dev.dev, "0x%08x: scaling 0x%x\n",
+ fmt->pfmt, vouvcr);
/* To produce a colour bar for testing set bit 23 of VOUVCR */
sh_vou_reg_ab_write(vou_dev, VOUVCR, vouvcr);
@@ -1218,6 +1207,8 @@ static const struct video_device sh_vou_video_template = {
.ioctl_ops = &sh_vou_ioctl_ops,
.tvnorms = V4L2_STD_525_60, /* PAL only supported in 8-bit non-bt656 mode */
.vfl_dir = VFL_DIR_TX,
+ .device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
static int sh_vou_probe(struct platform_device *pdev)
diff --git a/drivers/media/platform/sti/bdisp/bdisp-hw.c b/drivers/media/platform/sti/bdisp/bdisp-hw.c
index 4372abbb5950..a74e9fd65238 100644
--- a/drivers/media/platform/sti/bdisp/bdisp-hw.c
+++ b/drivers/media/platform/sti/bdisp/bdisp-hw.c
@@ -14,8 +14,8 @@
#define MAX_SRC_WIDTH 2048
/* Reset & boot poll config */
-#define POLL_RST_MAX 50
-#define POLL_RST_DELAY_MS 20
+#define POLL_RST_MAX 500
+#define POLL_RST_DELAY_MS 2
enum bdisp_target_plan {
BDISP_RGB,
@@ -382,7 +382,7 @@ int bdisp_hw_reset(struct bdisp_dev *bdisp)
for (i = 0; i < POLL_RST_MAX; i++) {
if (readl(bdisp->regs + BLT_STA1) & BLT_STA1_IDLE)
break;
- msleep(POLL_RST_DELAY_MS);
+ udelay(POLL_RST_DELAY_MS * 1000);
}
if (i == POLL_RST_MAX)
dev_err(bdisp->dev, "Reset timeout\n");
diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
index 79f7db1a9d18..d1025a53709f 100644
--- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
+++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
@@ -651,8 +651,7 @@ static int bdisp_release(struct file *file)
dev_dbg(bdisp->dev, "%s\n", __func__);
- if (mutex_lock_interruptible(&bdisp->lock))
- return -ERESTARTSYS;
+ mutex_lock(&bdisp->lock);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
@@ -692,11 +691,6 @@ static int bdisp_querycap(struct file *file, void *fh,
strscpy(cap->card, bdisp->pdev->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s%d",
BDISP_NAME, bdisp->id);
-
- cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
-
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
-
return 0;
}
@@ -1059,6 +1053,7 @@ static int bdisp_register_device(struct bdisp_dev *bdisp)
bdisp->vdev.lock = &bdisp->lock;
bdisp->vdev.vfl_dir = VFL_DIR_M2M;
bdisp->vdev.v4l2_dev = &bdisp->v4l2_dev;
+ bdisp->vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
snprintf(bdisp->vdev.name, sizeof(bdisp->vdev.name), "%s.%d",
BDISP_NAME, bdisp->id);
@@ -1279,6 +1274,8 @@ static int bdisp_remove(struct platform_device *pdev)
if (!IS_ERR(bdisp->clock))
clk_unprepare(bdisp->clock);
+ destroy_workqueue(bdisp->work_queue);
+
dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name);
return 0;
@@ -1322,20 +1319,22 @@ static int bdisp_probe(struct platform_device *pdev)
bdisp->regs = devm_ioremap_resource(dev, res);
if (IS_ERR(bdisp->regs)) {
dev_err(dev, "failed to get regs\n");
- return PTR_ERR(bdisp->regs);
+ ret = PTR_ERR(bdisp->regs);
+ goto err_wq;
}
bdisp->clock = devm_clk_get(dev, BDISP_NAME);
if (IS_ERR(bdisp->clock)) {
dev_err(dev, "failed to get clock\n");
- return PTR_ERR(bdisp->clock);
+ ret = PTR_ERR(bdisp->clock);
+ goto err_wq;
}
ret = clk_prepare(bdisp->clock);
if (ret < 0) {
dev_err(dev, "clock prepare failed\n");
bdisp->clock = ERR_PTR(-EINVAL);
- return ret;
+ goto err_wq;
}
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -1407,7 +1406,8 @@ err_v4l2:
err_clk:
if (!IS_ERR(bdisp->clock))
clk_unprepare(bdisp->clock);
-
+err_wq:
+ destroy_workqueue(bdisp->work_queue);
return ret;
}
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
index 3c05b3dc49ec..5baada4f65e5 100644
--- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
+++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
@@ -693,16 +693,12 @@ static int c8sectpfe_probe(struct platform_device *pdev)
fei->sram_size = resource_size(res);
fei->idle_irq = platform_get_irq_byname(pdev, "c8sectpfe-idle-irq");
- if (fei->idle_irq < 0) {
- dev_err(dev, "Can't get c8sectpfe-idle-irq\n");
+ if (fei->idle_irq < 0)
return fei->idle_irq;
- }
fei->error_irq = platform_get_irq_byname(pdev, "c8sectpfe-error-irq");
- if (fei->error_irq < 0) {
- dev_err(dev, "Can't get c8sectpfe-error-irq\n");
+ if (fei->error_irq < 0)
return fei->error_irq;
- }
platform_set_drvdata(pdev, fei);
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.c
index 8f0ddcbeed9d..301fa10f419b 100644
--- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.c
+++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-debugfs.c
@@ -225,36 +225,16 @@ static const struct debugfs_reg32 fei_sys_regs[] = {
void c8sectpfe_debugfs_init(struct c8sectpfei *fei)
{
- struct dentry *root;
- struct dentry *file;
-
- root = debugfs_create_dir("c8sectpfe", NULL);
- if (!root)
- goto err;
-
- fei->root = root;
-
fei->regset = devm_kzalloc(fei->dev, sizeof(*fei->regset), GFP_KERNEL);
if (!fei->regset)
- goto err;
+ return;
fei->regset->regs = fei_sys_regs;
fei->regset->nregs = ARRAY_SIZE(fei_sys_regs);
fei->regset->base = fei->io;
- file = debugfs_create_regset32("registers", S_IRUGO, root,
- fei->regset);
- if (!file) {
- dev_err(fei->dev,
- "%s not able to create 'registers' debugfs\n"
- , __func__);
- goto err;
- }
-
- return;
-
-err:
- debugfs_remove_recursive(root);
+ fei->root = debugfs_create_dir("c8sectpfe", NULL);
+ debugfs_create_regset32("registers", S_IRUGO, fei->root, fei->regset);
}
void c8sectpfe_debugfs_exit(struct c8sectpfei *fei)
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
index a79250a7f812..0560a9cb004b 100644
--- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
+++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
@@ -170,8 +170,9 @@ int c8sectpfe_frontend_attach(struct dvb_frontend **fe,
/* attach tuner */
request_module("tda18212");
- client = i2c_new_device(tsin->i2c_adapter, &tda18212_info);
- if (!client || !client->dev.driver) {
+ client = i2c_new_client_device(tsin->i2c_adapter,
+ &tda18212_info);
+ if (!i2c_client_has_driver(client)) {
dvb_frontend_detach(*fe);
return -ENODEV;
}
diff --git a/drivers/media/platform/sti/cec/stih-cec.c b/drivers/media/platform/sti/cec/stih-cec.c
index fc37efe1d554..f0c73e64b586 100644
--- a/drivers/media/platform/sti/cec/stih-cec.c
+++ b/drivers/media/platform/sti/cec/stih-cec.c
@@ -313,10 +313,6 @@ static int stih_cec_probe(struct platform_device *pdev)
if (!cec)
return -ENOMEM;
- cec->notifier = cec_notifier_get(hdmi_dev);
- if (!cec->notifier)
- return -ENOMEM;
-
cec->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -340,30 +336,42 @@ static int stih_cec_probe(struct platform_device *pdev)
return PTR_ERR(cec->clk);
}
- cec->adap = cec_allocate_adapter(&sti_cec_adap_ops, cec,
- CEC_NAME, CEC_CAP_DEFAULTS, CEC_MAX_LOG_ADDRS);
+ cec->adap = cec_allocate_adapter(&sti_cec_adap_ops, cec, CEC_NAME,
+ CEC_CAP_DEFAULTS |
+ CEC_CAP_CONNECTOR_INFO,
+ CEC_MAX_LOG_ADDRS);
ret = PTR_ERR_OR_ZERO(cec->adap);
if (ret)
return ret;
- ret = cec_register_adapter(cec->adap, &pdev->dev);
- if (ret) {
- cec_delete_adapter(cec->adap);
- return ret;
+ cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL,
+ cec->adap);
+ if (!cec->notifier) {
+ ret = -ENOMEM;
+ goto err_delete_adapter;
}
- cec_register_cec_notifier(cec->adap, cec->notifier);
+ ret = cec_register_adapter(cec->adap, &pdev->dev);
+ if (ret)
+ goto err_notifier;
platform_set_drvdata(pdev, cec);
return 0;
+
+err_notifier:
+ cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
+
+err_delete_adapter:
+ cec_delete_adapter(cec->adap);
+ return ret;
}
static int stih_cec_remove(struct platform_device *pdev)
{
struct stih_cec *cec = platform_get_drvdata(pdev);
+ cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
cec_unregister_adapter(cec->adap);
- cec_notifier_put(cec->notifier);
return 0;
}
diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c
index 7917fd2c4bd4..401aaafa1710 100644
--- a/drivers/media/platform/sti/hva/hva-hw.c
+++ b/drivers/media/platform/sti/hva/hva-hw.c
@@ -341,10 +341,8 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva)
/* get status interruption resource */
ret = platform_get_irq(pdev, 0);
- if (ret < 0) {
- dev_err(dev, "%s failed to get status IRQ\n", HVA_PREFIX);
+ if (ret < 0)
goto err_clk;
- }
hva->irq_its = ret;
ret = devm_request_threaded_irq(dev, hva->irq_its, hva_hw_its_interrupt,
@@ -360,10 +358,8 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva)
/* get error interruption resource */
ret = platform_get_irq(pdev, 1);
- if (ret < 0) {
- dev_err(dev, "%s failed to get error IRQ\n", HVA_PREFIX);
+ if (ret < 0)
goto err_clk;
- }
hva->irq_err = ret;
ret = devm_request_threaded_irq(dev, hva->irq_err, hva_hw_err_interrupt,
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index d855e9c09c08..9392e3409fba 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -100,10 +100,10 @@ enum state {
#define OVERRUN_ERROR_THRESHOLD 3
struct dcmi_graph_entity {
- struct device_node *node;
-
struct v4l2_async_subdev asd;
- struct v4l2_subdev *subdev;
+
+ struct device_node *remote_node;
+ struct v4l2_subdev *source;
};
struct dcmi_format {
@@ -169,6 +169,10 @@ struct stm32_dcmi {
/* Ensure DMA operations atomicity */
struct mutex dma_lock;
+
+ struct media_device mdev;
+ struct media_pad vid_cap_pad;
+ struct media_pipeline pipeline;
};
static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n)
@@ -580,6 +584,144 @@ static void dcmi_buf_queue(struct vb2_buffer *vb)
spin_unlock_irq(&dcmi->irqlock);
}
+static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi)
+{
+ struct media_entity *entity = &dcmi->vdev->entity;
+ struct media_pad *pad;
+
+ /* Walk searching for entity having no sink */
+ while (1) {
+ pad = &entity->pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+
+ pad = media_entity_remote_pad(pad);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ break;
+
+ entity = pad->entity;
+ }
+
+ return entity;
+}
+
+static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi,
+ struct v4l2_subdev_pad_config *pad_cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct media_entity *entity = &dcmi->entity.source->entity;
+ struct v4l2_subdev *subdev;
+ struct media_pad *sink_pad = NULL;
+ struct media_pad *src_pad = NULL;
+ struct media_pad *pad = NULL;
+ struct v4l2_subdev_format fmt = *format;
+ bool found = false;
+ int ret;
+
+ /*
+ * Starting from sensor subdevice, walk within
+ * pipeline and set format on each subdevice
+ */
+ while (1) {
+ unsigned int i;
+
+ /* Search if current entity has a source pad */
+ for (i = 0; i < entity->num_pads; i++) {
+ pad = &entity->pads[i];
+ if (pad->flags & MEDIA_PAD_FL_SOURCE) {
+ src_pad = pad;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ break;
+
+ subdev = media_entity_to_v4l2_subdev(entity);
+
+ /* Propagate format on sink pad if any, otherwise source pad */
+ if (sink_pad)
+ pad = sink_pad;
+
+ dev_dbg(dcmi->dev, "\"%s\":%d pad format set to 0x%x %ux%u\n",
+ subdev->name, pad->index, format->format.code,
+ format->format.width, format->format.height);
+
+ fmt.pad = pad->index;
+ ret = v4l2_subdev_call(subdev, pad, set_fmt, pad_cfg, &fmt);
+ if (ret < 0) {
+ dev_err(dcmi->dev, "%s: Failed to set format 0x%x %ux%u on \"%s\":%d pad (%d)\n",
+ __func__, format->format.code,
+ format->format.width, format->format.height,
+ subdev->name, pad->index, ret);
+ return ret;
+ }
+
+ if (fmt.format.code != format->format.code ||
+ fmt.format.width != format->format.width ||
+ fmt.format.height != format->format.height) {
+ dev_dbg(dcmi->dev, "\"%s\":%d pad format has been changed to 0x%x %ux%u\n",
+ subdev->name, pad->index, fmt.format.code,
+ fmt.format.width, fmt.format.height);
+ }
+
+ /* Walk to next entity */
+ sink_pad = media_entity_remote_pad(src_pad);
+ if (!sink_pad || !is_media_entity_v4l2_subdev(sink_pad->entity))
+ break;
+
+ entity = sink_pad->entity;
+ }
+ *format = fmt;
+
+ return 0;
+}
+
+static int dcmi_pipeline_s_stream(struct stm32_dcmi *dcmi, int state)
+{
+ struct media_entity *entity = &dcmi->vdev->entity;
+ struct v4l2_subdev *subdev;
+ struct media_pad *pad;
+ int ret;
+
+ /* Start/stop all entities within pipeline */
+ while (1) {
+ pad = &entity->pads[0];
+ if (!(pad->flags & MEDIA_PAD_FL_SINK))
+ break;
+
+ pad = media_entity_remote_pad(pad);
+ if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
+ break;
+
+ entity = pad->entity;
+ subdev = media_entity_to_v4l2_subdev(entity);
+
+ ret = v4l2_subdev_call(subdev, video, s_stream, state);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(dcmi->dev, "%s: \"%s\" failed to %s streaming (%d)\n",
+ __func__, subdev->name,
+ state ? "start" : "stop", ret);
+ return ret;
+ }
+
+ dev_dbg(dcmi->dev, "\"%s\" is %s\n",
+ subdev->name, state ? "started" : "stopped");
+ }
+
+ return 0;
+}
+
+static int dcmi_pipeline_start(struct stm32_dcmi *dcmi)
+{
+ return dcmi_pipeline_s_stream(dcmi, 1);
+}
+
+static void dcmi_pipeline_stop(struct stm32_dcmi *dcmi)
+{
+ dcmi_pipeline_s_stream(dcmi, 0);
+}
+
static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq);
@@ -594,14 +736,17 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
goto err_release_buffers;
}
- /* Enable stream on the sub device */
- ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 1);
- if (ret && ret != -ENOIOCTLCMD) {
- dev_err(dcmi->dev, "%s: Failed to start streaming, subdev streamon error",
- __func__);
+ ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline);
+ if (ret < 0) {
+ dev_err(dcmi->dev, "%s: Failed to start streaming, media pipeline start error (%d)\n",
+ __func__, ret);
goto err_pm_put;
}
+ ret = dcmi_pipeline_start(dcmi);
+ if (ret)
+ goto err_media_pipeline_stop;
+
spin_lock_irq(&dcmi->irqlock);
/* Set bus width */
@@ -673,7 +818,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
if (ret) {
dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n",
__func__);
- goto err_subdev_streamoff;
+ goto err_pipeline_stop;
}
/* Enable interruptions */
@@ -684,8 +829,11 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
return 0;
-err_subdev_streamoff:
- v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0);
+err_pipeline_stop:
+ dcmi_pipeline_stop(dcmi);
+
+err_media_pipeline_stop:
+ media_pipeline_stop(&dcmi->vdev->entity);
err_pm_put:
pm_runtime_put(dcmi->dev);
@@ -710,13 +858,10 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
{
struct stm32_dcmi *dcmi = vb2_get_drv_priv(vq);
struct dcmi_buf *buf, *node;
- int ret;
- /* Disable stream on the sub device */
- ret = v4l2_subdev_call(dcmi->entity.subdev, video, s_stream, 0);
- if (ret && ret != -ENOIOCTLCMD)
- dev_err(dcmi->dev, "%s: Failed to stop streaming, subdev streamoff error (%d)\n",
- __func__, ret);
+ dcmi_pipeline_stop(dcmi);
+
+ media_pipeline_stop(&dcmi->vdev->entity);
spin_lock_irq(&dcmi->irqlock);
@@ -857,7 +1002,7 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
}
v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code);
- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt,
+ ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt,
&pad_cfg, &format);
if (ret < 0)
return ret;
@@ -934,8 +1079,7 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f)
mf->width = sd_framesize.width;
mf->height = sd_framesize.height;
- ret = v4l2_subdev_call(dcmi->entity.subdev, pad,
- set_fmt, NULL, &format);
+ ret = dcmi_pipeline_s_fmt(dcmi, NULL, &format);
if (ret < 0)
return ret;
@@ -991,7 +1135,7 @@ static int dcmi_get_sensor_format(struct stm32_dcmi *dcmi,
};
int ret;
- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_fmt, NULL, &fmt);
+ ret = v4l2_subdev_call(dcmi->entity.source, pad, get_fmt, NULL, &fmt);
if (ret)
return ret;
@@ -1020,7 +1164,7 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi,
}
v4l2_fill_mbus_format(&format.format, pix, sd_fmt->mbus_code);
- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, set_fmt,
+ ret = v4l2_subdev_call(dcmi->entity.source, pad, set_fmt,
&pad_cfg, &format);
if (ret < 0)
return ret;
@@ -1043,7 +1187,7 @@ static int dcmi_get_sensor_bounds(struct stm32_dcmi *dcmi,
/*
* Get sensor bounds first
*/
- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, get_selection,
+ ret = v4l2_subdev_call(dcmi->entity.source, pad, get_selection,
NULL, &bounds);
if (!ret)
*r = bounds.r;
@@ -1224,7 +1368,7 @@ static int dcmi_enum_framesizes(struct file *file, void *fh,
fse.code = sd_fmt->mbus_code;
- ret = v4l2_subdev_call(dcmi->entity.subdev, pad, enum_frame_size,
+ ret = v4l2_subdev_call(dcmi->entity.source, pad, enum_frame_size,
NULL, &fse);
if (ret)
return ret;
@@ -1241,7 +1385,7 @@ static int dcmi_g_parm(struct file *file, void *priv,
{
struct stm32_dcmi *dcmi = video_drvdata(file);
- return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.subdev, p);
+ return v4l2_g_parm_cap(video_devdata(file), dcmi->entity.source, p);
}
static int dcmi_s_parm(struct file *file, void *priv,
@@ -1249,7 +1393,7 @@ static int dcmi_s_parm(struct file *file, void *priv,
{
struct stm32_dcmi *dcmi = video_drvdata(file);
- return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.subdev, p);
+ return v4l2_s_parm_cap(video_devdata(file), dcmi->entity.source, p);
}
static int dcmi_enum_frameintervals(struct file *file, void *fh,
@@ -1271,7 +1415,7 @@ static int dcmi_enum_frameintervals(struct file *file, void *fh,
fie.code = sd_fmt->mbus_code;
- ret = v4l2_subdev_call(dcmi->entity.subdev, pad,
+ ret = v4l2_subdev_call(dcmi->entity.source, pad,
enum_frame_interval, NULL, &fie);
if (ret)
return ret;
@@ -1291,7 +1435,7 @@ MODULE_DEVICE_TABLE(of, stm32_dcmi_of_match);
static int dcmi_open(struct file *file)
{
struct stm32_dcmi *dcmi = video_drvdata(file);
- struct v4l2_subdev *sd = dcmi->entity.subdev;
+ struct v4l2_subdev *sd = dcmi->entity.source;
int ret;
if (mutex_lock_interruptible(&dcmi->lock))
@@ -1322,7 +1466,7 @@ unlock:
static int dcmi_release(struct file *file)
{
struct stm32_dcmi *dcmi = video_drvdata(file);
- struct v4l2_subdev *sd = dcmi->entity.subdev;
+ struct v4l2_subdev *sd = dcmi->entity.source;
bool fh_singular;
int ret;
@@ -1409,6 +1553,12 @@ static int dcmi_set_default_fmt(struct stm32_dcmi *dcmi)
return 0;
}
+/*
+ * FIXME: For the time being we only support subdevices
+ * which expose RGB & YUV "parallel form" mbus code (_2X8).
+ * Nevertheless, this allows to support serial source subdevices
+ * and serial to parallel bridges which conform to this.
+ */
static const struct dcmi_format dcmi_formats[] = {
{
.fourcc = V4L2_PIX_FMT_RGB565,
@@ -1433,7 +1583,7 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi)
{
const struct dcmi_format *sd_fmts[ARRAY_SIZE(dcmi_formats)];
unsigned int num_fmts = 0, i, j;
- struct v4l2_subdev *subdev = dcmi->entity.subdev;
+ struct v4l2_subdev *subdev = dcmi->entity.source;
struct v4l2_subdev_mbus_code_enum mbus_code = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
@@ -1447,12 +1597,20 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi)
/* Code supported, have we got this fourcc yet? */
for (j = 0; j < num_fmts; j++)
if (sd_fmts[j]->fourcc ==
- dcmi_formats[i].fourcc)
+ dcmi_formats[i].fourcc) {
/* Already available */
+ dev_dbg(dcmi->dev, "Skipping fourcc/code: %4.4s/0x%x\n",
+ (char *)&sd_fmts[j]->fourcc,
+ mbus_code.code);
break;
- if (j == num_fmts)
+ }
+ if (j == num_fmts) {
/* New */
sd_fmts[num_fmts++] = dcmi_formats + i;
+ dev_dbg(dcmi->dev, "Supported fourcc/code: %4.4s/0x%x\n",
+ (char *)&sd_fmts[num_fmts - 1]->fourcc,
+ sd_fmts[num_fmts - 1]->mbus_code);
+ }
}
mbus_code.index++;
}
@@ -1479,7 +1637,7 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi)
static int dcmi_framesizes_init(struct stm32_dcmi *dcmi)
{
unsigned int num_fsize = 0;
- struct v4l2_subdev *subdev = dcmi->entity.subdev;
+ struct v4l2_subdev *subdev = dcmi->entity.source;
struct v4l2_subdev_frame_size_enum fse = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
.code = dcmi->sd_format->mbus_code,
@@ -1526,7 +1684,20 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier)
struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
int ret;
- dcmi->vdev->ctrl_handler = dcmi->entity.subdev->ctrl_handler;
+ /*
+ * Now that the graph is complete,
+ * we search for the source subdevice
+ * in order to expose it through V4L2 interface
+ */
+ dcmi->entity.source =
+ media_entity_to_v4l2_subdev(dcmi_find_source(dcmi));
+ if (!dcmi->entity.source) {
+ dev_err(dcmi->dev, "Source subdevice not found\n");
+ return -ENODEV;
+ }
+
+ dcmi->vdev->ctrl_handler = dcmi->entity.source->ctrl_handler;
+
ret = dcmi_formats_init(dcmi);
if (ret) {
dev_err(dcmi->dev, "No supported mediabus format found\n");
@@ -1551,14 +1722,6 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier)
return ret;
}
- ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1);
- if (ret) {
- dev_err(dcmi->dev, "Failed to register video device\n");
- return ret;
- }
-
- dev_dbg(dcmi->dev, "Device registered as %s\n",
- video_device_node_name(dcmi->vdev));
return 0;
}
@@ -1579,12 +1742,31 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,
struct v4l2_async_subdev *asd)
{
struct stm32_dcmi *dcmi = notifier_to_dcmi(notifier);
+ unsigned int ret;
+ int src_pad;
- dev_dbg(dcmi->dev, "Subdev %s bound\n", subdev->name);
+ dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name);
- dcmi->entity.subdev = subdev;
+ /*
+ * Link this sub-device to DCMI, it could be
+ * a parallel camera sensor or a bridge
+ */
+ src_pad = media_entity_get_fwnode_pad(&subdev->entity,
+ subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+
+ ret = media_create_pad_link(&subdev->entity, src_pad,
+ &dcmi->vdev->entity, 0,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ dev_err(dcmi->dev, "Failed to create media pad link with subdev \"%s\"\n",
+ subdev->name);
+ else
+ dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n",
+ subdev->name);
- return 0;
+ return ret;
}
static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = {
@@ -1608,7 +1790,7 @@ static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node)
return -EINVAL;
/* Remote node to connect */
- dcmi->entity.node = remote;
+ dcmi->entity.remote_node = remote;
dcmi->entity.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
dcmi->entity.asd.match.fwnode = of_fwnode_handle(remote);
return 0;
@@ -1631,7 +1813,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
&dcmi->entity.asd);
if (ret) {
dev_err(dcmi->dev, "Failed to add subdev notifier\n");
- of_node_put(dcmi->entity.node);
+ of_node_put(dcmi->entity.remote_node);
return ret;
}
@@ -1679,7 +1861,6 @@ static int dcmi_probe(struct platform_device *pdev)
np = of_graph_get_next_endpoint(np, NULL);
if (!np) {
dev_err(&pdev->dev, "Could not find the endpoint\n");
- of_node_put(np);
return -ENODEV;
}
@@ -1699,11 +1880,8 @@ static int dcmi_probe(struct platform_device *pdev)
dcmi->bus.data_shift = ep.bus.parallel.data_shift;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- if (irq != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Could not get irq\n");
+ if (irq <= 0)
return irq ? irq : -ENXIO;
- }
dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!dcmi->res) {
@@ -1751,10 +1929,19 @@ static int dcmi_probe(struct platform_device *pdev)
q = &dcmi->queue;
+ dcmi->v4l2_dev.mdev = &dcmi->mdev;
+
+ /* Initialize media device */
+ strscpy(dcmi->mdev.model, DRV_NAME, sizeof(dcmi->mdev.model));
+ snprintf(dcmi->mdev.bus_info, sizeof(dcmi->mdev.bus_info),
+ "platform:%s", DRV_NAME);
+ dcmi->mdev.dev = &pdev->dev;
+ media_device_init(&dcmi->mdev);
+
/* Initialize the top-level structure */
ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev);
if (ret)
- goto err_dma_release;
+ goto err_media_device_cleanup;
dcmi->vdev = video_device_alloc();
if (!dcmi->vdev) {
@@ -1774,6 +1961,25 @@ static int dcmi_probe(struct platform_device *pdev)
V4L2_CAP_READWRITE;
video_set_drvdata(dcmi->vdev, dcmi);
+ /* Media entity pads */
+ dcmi->vid_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&dcmi->vdev->entity,
+ 1, &dcmi->vid_cap_pad);
+ if (ret) {
+ dev_err(dcmi->dev, "Failed to init media entity pad\n");
+ goto err_device_release;
+ }
+ dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
+
+ ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ dev_err(dcmi->dev, "Failed to register video device\n");
+ goto err_media_entity_cleanup;
+ }
+
+ dev_dbg(dcmi->dev, "Device registered as %s\n",
+ video_device_node_name(dcmi->vdev));
+
/* Buffer queue */
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
@@ -1789,12 +1995,12 @@ static int dcmi_probe(struct platform_device *pdev)
ret = vb2_queue_init(q);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to initialize vb2 queue\n");
- goto err_device_release;
+ goto err_media_entity_cleanup;
}
ret = dcmi_graph_init(dcmi);
if (ret < 0)
- goto err_device_release;
+ goto err_media_entity_cleanup;
/* Reset device */
ret = reset_control_assert(dcmi->rstc);
@@ -1821,11 +2027,14 @@ static int dcmi_probe(struct platform_device *pdev)
err_cleanup:
v4l2_async_notifier_cleanup(&dcmi->notifier);
+err_media_entity_cleanup:
+ media_entity_cleanup(&dcmi->vdev->entity);
err_device_release:
video_device_release(dcmi->vdev);
err_device_unregister:
v4l2_device_unregister(&dcmi->v4l2_dev);
-err_dma_release:
+err_media_device_cleanup:
+ media_device_cleanup(&dcmi->mdev);
dma_release_channel(dcmi->dma_chan);
return ret;
@@ -1839,7 +2048,9 @@ static int dcmi_remove(struct platform_device *pdev)
v4l2_async_notifier_unregister(&dcmi->notifier);
v4l2_async_notifier_cleanup(&dcmi->notifier);
+ media_entity_cleanup(&dcmi->vdev->entity);
v4l2_device_unregister(&dcmi->v4l2_dev);
+ media_device_cleanup(&dcmi->mdev);
dma_release_channel(dcmi->dma_chan);
diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig
new file mode 100644
index 000000000000..71808e93ac2e
--- /dev/null
+++ b/drivers/media/platform/sunxi/Kconfig
@@ -0,0 +1,2 @@
+source "drivers/media/platform/sunxi/sun4i-csi/Kconfig"
+source "drivers/media/platform/sunxi/sun6i-csi/Kconfig"
diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile
new file mode 100644
index 000000000000..3878cb4efdc2
--- /dev/null
+++ b/drivers/media/platform/sunxi/Makefile
@@ -0,0 +1,3 @@
+obj-y += sun4i-csi/
+obj-y += sun6i-csi/
+obj-y += sun8i-di/
diff --git a/drivers/media/platform/sunxi/sun4i-csi/Kconfig b/drivers/media/platform/sunxi/sun4i-csi/Kconfig
new file mode 100644
index 000000000000..e86e29b6a603
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/Kconfig
@@ -0,0 +1,11 @@
+config VIDEO_SUN4I_CSI
+ tristate "Allwinner A10 CMOS Sensor Interface Support"
+ depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA
+ depends on ARCH_SUNXI || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_FWNODE
+ help
+ This is a V4L2 driver for the Allwinner A10 CSI
+
+ To compile this driver as a module, choose M here: the module
+ will be called sun4i_csi.
diff --git a/drivers/media/platform/sunxi/sun4i-csi/Makefile b/drivers/media/platform/sunxi/sun4i-csi/Makefile
new file mode 100644
index 000000000000..7c790a57f5ee
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/Makefile
@@ -0,0 +1,5 @@
+sun4i-csi-y += sun4i_csi.o
+sun4i-csi-y += sun4i_dma.o
+sun4i-csi-y += sun4i_v4l2.o
+
+obj-$(CONFIG_VIDEO_SUN4I_CSI) += sun4i-csi.o
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
new file mode 100644
index 000000000000..eff34ded6305
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 NextThing Co
+ * Copyright (C) 2016-2019 Bootlin
+ *
+ * Author: Maxime Ripard <maxime.ripard@bootlin.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mediabus.h>
+
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "sun4i_csi.h"
+
+struct sun4i_csi_traits {
+ unsigned int channels;
+ unsigned int max_width;
+ bool has_isp;
+};
+
+static const struct media_entity_operations sun4i_csi_video_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int sun4i_csi_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct sun4i_csi *csi = container_of(notifier, struct sun4i_csi,
+ notifier);
+
+ csi->src_subdev = subdev;
+ csi->src_pad = media_entity_get_fwnode_pad(&subdev->entity,
+ subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (csi->src_pad < 0) {
+ dev_err(csi->dev, "Couldn't find output pad for subdev %s\n",
+ subdev->name);
+ return csi->src_pad;
+ }
+
+ dev_dbg(csi->dev, "Bound %s pad: %d\n", subdev->name, csi->src_pad);
+ return 0;
+}
+
+static int sun4i_csi_notify_complete(struct v4l2_async_notifier *notifier)
+{
+ struct sun4i_csi *csi = container_of(notifier, struct sun4i_csi,
+ notifier);
+ struct v4l2_subdev *subdev = &csi->subdev;
+ struct video_device *vdev = &csi->vdev;
+ int ret;
+
+ ret = v4l2_device_register_subdev(&csi->v4l, subdev);
+ if (ret < 0)
+ return ret;
+
+ ret = sun4i_csi_v4l2_register(csi);
+ if (ret < 0)
+ return ret;
+
+ ret = media_device_register(&csi->mdev);
+ if (ret)
+ return ret;
+
+ /* Create link from subdev to main device */
+ ret = media_create_pad_link(&subdev->entity, CSI_SUBDEV_SOURCE,
+ &vdev->entity, 0,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret)
+ goto err_clean_media;
+
+ ret = media_create_pad_link(&csi->src_subdev->entity, csi->src_pad,
+ &subdev->entity, CSI_SUBDEV_SINK,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret)
+ goto err_clean_media;
+
+ ret = v4l2_device_register_subdev_nodes(&csi->v4l);
+ if (ret < 0)
+ goto err_clean_media;
+
+ return 0;
+
+err_clean_media:
+ media_device_unregister(&csi->mdev);
+
+ return ret;
+}
+
+static const struct v4l2_async_notifier_operations sun4i_csi_notify_ops = {
+ .bound = sun4i_csi_notify_bound,
+ .complete = sun4i_csi_notify_complete,
+};
+
+static int sun4i_csi_notifier_init(struct sun4i_csi *csi)
+{
+ struct v4l2_fwnode_endpoint vep = {
+ .bus_type = V4L2_MBUS_PARALLEL,
+ };
+ struct fwnode_handle *ep;
+ int ret;
+
+ v4l2_async_notifier_init(&csi->notifier);
+
+ ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(csi->dev), 0, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!ep)
+ return -EINVAL;
+
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+ if (ret)
+ goto out;
+
+ csi->bus = vep.bus.parallel;
+
+ ret = v4l2_async_notifier_add_fwnode_remote_subdev(&csi->notifier,
+ ep, &csi->asd);
+ if (ret)
+ goto out;
+
+ csi->notifier.ops = &sun4i_csi_notify_ops;
+
+out:
+ fwnode_handle_put(ep);
+ return ret;
+}
+
+static int sun4i_csi_probe(struct platform_device *pdev)
+{
+ struct v4l2_subdev *subdev;
+ struct video_device *vdev;
+ struct sun4i_csi *csi;
+ struct resource *res;
+ int ret;
+ int irq;
+
+ csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL);
+ if (!csi)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, csi);
+ csi->dev = &pdev->dev;
+ subdev = &csi->subdev;
+ vdev = &csi->vdev;
+
+ csi->traits = of_device_get_match_data(&pdev->dev);
+ if (!csi->traits)
+ return -EINVAL;
+
+ /*
+ * On Allwinner SoCs, some high memory bandwidth devices do DMA
+ * directly over the memory bus (called MBUS), instead of the
+ * system bus. The memory bus has a different addressing scheme
+ * without the DRAM starting offset.
+ *
+ * In some cases this can be described by an interconnect in
+ * the device tree. In other cases where the hardware is not
+ * fully understood and the interconnect is left out of the
+ * device tree, fall back to a default offset.
+ */
+ if (of_find_property(csi->dev->of_node, "interconnects", NULL)) {
+ ret = of_dma_configure(csi->dev, csi->dev->of_node, true);
+ if (ret)
+ return ret;
+ } else {
+#ifdef PHYS_PFN_OFFSET
+ csi->dev->dma_pfn_offset = PHYS_PFN_OFFSET;
+#endif
+ }
+
+ csi->mdev.dev = csi->dev;
+ strscpy(csi->mdev.model, "Allwinner Video Capture Device",
+ sizeof(csi->mdev.model));
+ csi->mdev.hw_revision = 0;
+ media_device_init(&csi->mdev);
+ csi->v4l.mdev = &csi->mdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ csi->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(csi->regs))
+ return PTR_ERR(csi->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ csi->bus_clk = devm_clk_get(&pdev->dev, "bus");
+ if (IS_ERR(csi->bus_clk)) {
+ dev_err(&pdev->dev, "Couldn't get our bus clock\n");
+ return PTR_ERR(csi->bus_clk);
+ }
+
+ if (csi->traits->has_isp) {
+ csi->isp_clk = devm_clk_get(&pdev->dev, "isp");
+ if (IS_ERR(csi->isp_clk)) {
+ dev_err(&pdev->dev, "Couldn't get our ISP clock\n");
+ return PTR_ERR(csi->isp_clk);
+ }
+ }
+
+ csi->ram_clk = devm_clk_get(&pdev->dev, "ram");
+ if (IS_ERR(csi->ram_clk)) {
+ dev_err(&pdev->dev, "Couldn't get our ram clock\n");
+ return PTR_ERR(csi->ram_clk);
+ }
+
+ csi->rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(csi->rst)) {
+ dev_err(&pdev->dev, "Couldn't get our reset line\n");
+ return PTR_ERR(csi->rst);
+ }
+
+ /* Initialize subdev */
+ v4l2_subdev_init(subdev, &sun4i_csi_subdev_ops);
+ subdev->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ subdev->owner = THIS_MODULE;
+ snprintf(subdev->name, sizeof(subdev->name), "sun4i-csi-0");
+ v4l2_set_subdevdata(subdev, csi);
+
+ csi->subdev_pads[CSI_SUBDEV_SINK].flags =
+ MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+ csi->subdev_pads[CSI_SUBDEV_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&subdev->entity, CSI_SUBDEV_PADS,
+ csi->subdev_pads);
+ if (ret < 0)
+ return ret;
+
+ csi->vdev_pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+ vdev->entity.ops = &sun4i_csi_video_entity_ops;
+ ret = media_entity_pads_init(&vdev->entity, 1, &csi->vdev_pad);
+ if (ret < 0)
+ return ret;
+
+ ret = sun4i_csi_dma_register(csi, irq);
+ if (ret)
+ goto err_clean_pad;
+
+ ret = sun4i_csi_notifier_init(csi);
+ if (ret)
+ goto err_unregister_media;
+
+ ret = v4l2_async_notifier_register(&csi->v4l, &csi->notifier);
+ if (ret) {
+ dev_err(csi->dev, "Couldn't register our notifier.\n");
+ goto err_unregister_media;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+
+err_unregister_media:
+ media_device_unregister(&csi->mdev);
+ sun4i_csi_dma_unregister(csi);
+
+err_clean_pad:
+ media_device_cleanup(&csi->mdev);
+
+ return ret;
+}
+
+static int sun4i_csi_remove(struct platform_device *pdev)
+{
+ struct sun4i_csi *csi = platform_get_drvdata(pdev);
+
+ v4l2_async_notifier_unregister(&csi->notifier);
+ v4l2_async_notifier_cleanup(&csi->notifier);
+ media_device_unregister(&csi->mdev);
+ sun4i_csi_dma_unregister(csi);
+ media_device_cleanup(&csi->mdev);
+
+ return 0;
+}
+
+static const struct sun4i_csi_traits sun4i_a10_csi1_traits = {
+ .channels = 1,
+ .max_width = 24,
+ .has_isp = false,
+};
+
+static const struct sun4i_csi_traits sun7i_a20_csi0_traits = {
+ .channels = 4,
+ .max_width = 16,
+ .has_isp = true,
+};
+
+static const struct of_device_id sun4i_csi_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-csi1", .data = &sun4i_a10_csi1_traits },
+ { .compatible = "allwinner,sun7i-a20-csi0", .data = &sun7i_a20_csi0_traits },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_csi_of_match);
+
+static int __maybe_unused sun4i_csi_runtime_resume(struct device *dev)
+{
+ struct sun4i_csi *csi = dev_get_drvdata(dev);
+
+ reset_control_deassert(csi->rst);
+ clk_prepare_enable(csi->bus_clk);
+ clk_prepare_enable(csi->ram_clk);
+ clk_set_rate(csi->isp_clk, 80000000);
+ clk_prepare_enable(csi->isp_clk);
+
+ writel(1, csi->regs + CSI_EN_REG);
+
+ return 0;
+}
+
+static int __maybe_unused sun4i_csi_runtime_suspend(struct device *dev)
+{
+ struct sun4i_csi *csi = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(csi->isp_clk);
+ clk_disable_unprepare(csi->ram_clk);
+ clk_disable_unprepare(csi->bus_clk);
+
+ reset_control_assert(csi->rst);
+
+ return 0;
+}
+
+static const struct dev_pm_ops sun4i_csi_pm_ops = {
+ SET_RUNTIME_PM_OPS(sun4i_csi_runtime_suspend,
+ sun4i_csi_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver sun4i_csi_driver = {
+ .probe = sun4i_csi_probe,
+ .remove = sun4i_csi_remove,
+ .driver = {
+ .name = "sun4i-csi",
+ .of_match_table = sun4i_csi_of_match,
+ .pm = &sun4i_csi_pm_ops,
+ },
+};
+module_platform_driver(sun4i_csi_driver);
+
+MODULE_DESCRIPTION("Allwinner A10 Camera Sensor Interface driver");
+MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
new file mode 100644
index 000000000000..0f67ff652c2e
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.h
@@ -0,0 +1,162 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 NextThing Co
+ * Copyright (C) 2016-2019 Bootlin
+ *
+ * Author: Maxime Ripard <maxime.ripard@bootlin.com>
+ */
+
+#ifndef _SUN4I_CSI_H_
+#define _SUN4I_CSI_H_
+
+#include <media/media-device.h>
+#include <media/v4l2-async.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+#include <media/videobuf2-core.h>
+
+#define CSI_EN_REG 0x00
+
+#define CSI_CFG_REG 0x04
+#define CSI_CFG_INPUT_FMT(fmt) ((fmt) << 20)
+#define CSI_CFG_OUTPUT_FMT(fmt) ((fmt) << 16)
+#define CSI_CFG_YUV_DATA_SEQ(seq) ((seq) << 8)
+#define CSI_CFG_VREF_POL(pol) ((pol) << 2)
+#define CSI_CFG_HREF_POL(pol) ((pol) << 1)
+#define CSI_CFG_PCLK_POL(pol) ((pol) << 0)
+
+#define CSI_CPT_CTRL_REG 0x08
+#define CSI_CPT_CTRL_VIDEO_START BIT(1)
+#define CSI_CPT_CTRL_IMAGE_START BIT(0)
+
+#define CSI_BUF_ADDR_REG(fifo, buf) (0x10 + (0x8 * (fifo)) + (0x4 * (buf)))
+
+#define CSI_BUF_CTRL_REG 0x28
+#define CSI_BUF_CTRL_DBN BIT(2)
+#define CSI_BUF_CTRL_DBS BIT(1)
+#define CSI_BUF_CTRL_DBE BIT(0)
+
+#define CSI_INT_EN_REG 0x30
+#define CSI_INT_FRM_DONE BIT(1)
+#define CSI_INT_CPT_DONE BIT(0)
+
+#define CSI_INT_STA_REG 0x34
+
+#define CSI_WIN_CTRL_W_REG 0x40
+#define CSI_WIN_CTRL_W_ACTIVE(w) ((w) << 16)
+
+#define CSI_WIN_CTRL_H_REG 0x44
+#define CSI_WIN_CTRL_H_ACTIVE(h) ((h) << 16)
+
+#define CSI_BUF_LEN_REG 0x48
+
+#define CSI_MAX_BUFFER 2
+#define CSI_MAX_HEIGHT 8192U
+#define CSI_MAX_WIDTH 8192U
+
+enum csi_input {
+ CSI_INPUT_RAW = 0,
+ CSI_INPUT_BT656 = 2,
+ CSI_INPUT_YUV = 3,
+};
+
+enum csi_output_raw {
+ CSI_OUTPUT_RAW_PASSTHROUGH = 0,
+};
+
+enum csi_output_yuv {
+ CSI_OUTPUT_YUV_422_PLANAR = 0,
+ CSI_OUTPUT_YUV_420_PLANAR = 1,
+ CSI_OUTPUT_YUV_422_UV = 4,
+ CSI_OUTPUT_YUV_420_UV = 5,
+ CSI_OUTPUT_YUV_422_MACRO = 8,
+ CSI_OUTPUT_YUV_420_MACRO = 9,
+};
+
+enum csi_yuv_data_seq {
+ CSI_YUV_DATA_SEQ_YUYV = 0,
+ CSI_YUV_DATA_SEQ_YVYU = 1,
+ CSI_YUV_DATA_SEQ_UYVY = 2,
+ CSI_YUV_DATA_SEQ_VYUY = 3,
+};
+
+enum csi_subdev_pads {
+ CSI_SUBDEV_SINK,
+ CSI_SUBDEV_SOURCE,
+
+ CSI_SUBDEV_PADS,
+};
+
+extern const struct v4l2_subdev_ops sun4i_csi_subdev_ops;
+
+struct sun4i_csi_format {
+ u32 mbus;
+ u32 fourcc;
+ enum csi_input input;
+ u32 output;
+ unsigned int num_planes;
+ u8 bpp[3];
+ unsigned int hsub;
+ unsigned int vsub;
+};
+
+const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc,
+ const u32 *mbus);
+
+struct sun4i_csi {
+ /* Device resources */
+ struct device *dev;
+
+ const struct sun4i_csi_traits *traits;
+
+ void __iomem *regs;
+ struct clk *bus_clk;
+ struct clk *isp_clk;
+ struct clk *ram_clk;
+ struct reset_control *rst;
+
+ struct vb2_v4l2_buffer *current_buf[CSI_MAX_BUFFER];
+
+ struct {
+ size_t size;
+ void *vaddr;
+ dma_addr_t paddr;
+ } scratch;
+
+ struct v4l2_fwnode_bus_parallel bus;
+
+ /* Main Device */
+ struct v4l2_device v4l;
+ struct media_device mdev;
+ struct video_device vdev;
+ struct media_pad vdev_pad;
+ struct v4l2_pix_format_mplane fmt;
+
+ /* Local subdev */
+ struct v4l2_subdev subdev;
+ struct media_pad subdev_pads[CSI_SUBDEV_PADS];
+ struct v4l2_mbus_framefmt subdev_fmt;
+
+ /* V4L2 Async variables */
+ struct v4l2_async_subdev asd;
+ struct v4l2_async_notifier notifier;
+ struct v4l2_subdev *src_subdev;
+ int src_pad;
+
+ /* V4L2 variables */
+ struct mutex lock;
+
+ /* Videobuf2 */
+ struct vb2_queue queue;
+ struct list_head buf_list;
+ spinlock_t qlock;
+ unsigned int sequence;
+};
+
+int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq);
+void sun4i_csi_dma_unregister(struct sun4i_csi *csi);
+
+int sun4i_csi_v4l2_register(struct sun4i_csi *csi);
+
+#endif /* _SUN4I_CSI_H_ */
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
new file mode 100644
index 000000000000..78fa1c535ac6
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
@@ -0,0 +1,462 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 NextThing Co
+ * Copyright (C) 2016-2019 Bootlin
+ *
+ * Author: Maxime Ripard <maxime.ripard@bootlin.com>
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "sun4i_csi.h"
+
+struct sun4i_csi_buffer {
+ struct vb2_v4l2_buffer vb;
+ struct list_head list;
+};
+
+static inline struct sun4i_csi_buffer *
+vb2_v4l2_to_csi_buffer(const struct vb2_v4l2_buffer *p)
+{
+ return container_of(p, struct sun4i_csi_buffer, vb);
+}
+
+static inline struct sun4i_csi_buffer *
+vb2_to_csi_buffer(const struct vb2_buffer *p)
+{
+ return vb2_v4l2_to_csi_buffer(to_vb2_v4l2_buffer(p));
+}
+
+static void sun4i_csi_capture_start(struct sun4i_csi *csi)
+{
+ writel(CSI_CPT_CTRL_VIDEO_START, csi->regs + CSI_CPT_CTRL_REG);
+}
+
+static void sun4i_csi_capture_stop(struct sun4i_csi *csi)
+{
+ writel(0, csi->regs + CSI_CPT_CTRL_REG);
+}
+
+static int sun4i_csi_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers,
+ unsigned int *nplanes,
+ unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct sun4i_csi *csi = vb2_get_drv_priv(vq);
+ unsigned int num_planes = csi->fmt.num_planes;
+ unsigned int i;
+
+ if (*nplanes) {
+ if (*nplanes != num_planes)
+ return -EINVAL;
+
+ for (i = 0; i < num_planes; i++)
+ if (sizes[i] < csi->fmt.plane_fmt[i].sizeimage)
+ return -EINVAL;
+ return 0;
+ }
+
+ *nplanes = num_planes;
+ for (i = 0; i < num_planes; i++)
+ sizes[i] = csi->fmt.plane_fmt[i].sizeimage;
+
+ return 0;
+};
+
+static int sun4i_csi_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct sun4i_csi *csi = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned int i;
+
+ for (i = 0; i < csi->fmt.num_planes; i++) {
+ unsigned long size = csi->fmt.plane_fmt[i].sizeimage;
+
+ if (vb2_plane_size(vb, i) < size) {
+ dev_err(csi->dev, "buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, i), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, i, size);
+ }
+
+ return 0;
+}
+
+static int sun4i_csi_setup_scratch_buffer(struct sun4i_csi *csi,
+ unsigned int slot)
+{
+ dma_addr_t addr = csi->scratch.paddr;
+ unsigned int plane;
+
+ dev_dbg(csi->dev,
+ "No more available buffer, using the scratch buffer\n");
+
+ for (plane = 0; plane < csi->fmt.num_planes; plane++) {
+ writel(addr, csi->regs + CSI_BUF_ADDR_REG(plane, slot));
+ addr += csi->fmt.plane_fmt[plane].sizeimage;
+ }
+
+ csi->current_buf[slot] = NULL;
+ return 0;
+}
+
+static int sun4i_csi_buffer_fill_slot(struct sun4i_csi *csi, unsigned int slot)
+{
+ struct sun4i_csi_buffer *c_buf;
+ struct vb2_v4l2_buffer *v_buf;
+ unsigned int plane;
+
+ /*
+ * We should never end up in a situation where we overwrite an
+ * already filled slot.
+ */
+ if (WARN_ON(csi->current_buf[slot]))
+ return -EINVAL;
+
+ if (list_empty(&csi->buf_list))
+ return sun4i_csi_setup_scratch_buffer(csi, slot);
+
+ c_buf = list_first_entry(&csi->buf_list, struct sun4i_csi_buffer, list);
+ list_del_init(&c_buf->list);
+
+ v_buf = &c_buf->vb;
+ csi->current_buf[slot] = v_buf;
+
+ for (plane = 0; plane < csi->fmt.num_planes; plane++) {
+ dma_addr_t buf_addr;
+
+ buf_addr = vb2_dma_contig_plane_dma_addr(&v_buf->vb2_buf,
+ plane);
+ writel(buf_addr, csi->regs + CSI_BUF_ADDR_REG(plane, slot));
+ }
+
+ return 0;
+}
+
+static int sun4i_csi_buffer_fill_all(struct sun4i_csi *csi)
+{
+ unsigned int slot;
+ int ret;
+
+ for (slot = 0; slot < CSI_MAX_BUFFER; slot++) {
+ ret = sun4i_csi_buffer_fill_slot(csi, slot);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void sun4i_csi_buffer_mark_done(struct sun4i_csi *csi,
+ unsigned int slot,
+ unsigned int sequence)
+{
+ struct vb2_v4l2_buffer *v_buf;
+
+ if (!csi->current_buf[slot]) {
+ dev_dbg(csi->dev, "Scratch buffer was used, ignoring..\n");
+ return;
+ }
+
+ v_buf = csi->current_buf[slot];
+ v_buf->field = csi->fmt.field;
+ v_buf->sequence = sequence;
+ v_buf->vb2_buf.timestamp = ktime_get_ns();
+ vb2_buffer_done(&v_buf->vb2_buf, VB2_BUF_STATE_DONE);
+
+ csi->current_buf[slot] = NULL;
+}
+
+static int sun4i_csi_buffer_flip(struct sun4i_csi *csi, unsigned int sequence)
+{
+ u32 reg = readl(csi->regs + CSI_BUF_CTRL_REG);
+ unsigned int next;
+
+ /* Our next buffer is not the current buffer */
+ next = !(reg & CSI_BUF_CTRL_DBS);
+
+ /* Report the previous buffer as done */
+ sun4i_csi_buffer_mark_done(csi, next, sequence);
+
+ /* Put a new buffer in there */
+ return sun4i_csi_buffer_fill_slot(csi, next);
+}
+
+static void sun4i_csi_buffer_queue(struct vb2_buffer *vb)
+{
+ struct sun4i_csi *csi = vb2_get_drv_priv(vb->vb2_queue);
+ struct sun4i_csi_buffer *buf = vb2_to_csi_buffer(vb);
+ unsigned long flags;
+
+ spin_lock_irqsave(&csi->qlock, flags);
+ list_add_tail(&buf->list, &csi->buf_list);
+ spin_unlock_irqrestore(&csi->qlock, flags);
+}
+
+static void return_all_buffers(struct sun4i_csi *csi,
+ enum vb2_buffer_state state)
+{
+ struct sun4i_csi_buffer *buf, *node;
+ unsigned int slot;
+
+ list_for_each_entry_safe(buf, node, &csi->buf_list, list) {
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ list_del(&buf->list);
+ }
+
+ for (slot = 0; slot < CSI_MAX_BUFFER; slot++) {
+ struct vb2_v4l2_buffer *v_buf = csi->current_buf[slot];
+
+ if (!v_buf)
+ continue;
+
+ vb2_buffer_done(&v_buf->vb2_buf, state);
+ csi->current_buf[slot] = NULL;
+ }
+}
+
+static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct sun4i_csi *csi = vb2_get_drv_priv(vq);
+ struct v4l2_fwnode_bus_parallel *bus = &csi->bus;
+ const struct sun4i_csi_format *csi_fmt;
+ unsigned long href_pol, pclk_pol, vref_pol;
+ unsigned long flags;
+ unsigned int i;
+ int ret;
+
+ csi_fmt = sun4i_csi_find_format(&csi->fmt.pixelformat, NULL);
+ if (!csi_fmt)
+ return -EINVAL;
+
+ dev_dbg(csi->dev, "Starting capture\n");
+
+ csi->sequence = 0;
+
+ /*
+ * We need a scratch buffer in case where we'll not have any
+ * more buffer queued so that we don't error out. One of those
+ * cases is when you end up at the last frame to capture, you
+ * don't havea any buffer queued any more, and yet it doesn't
+ * really matter since you'll never reach the next buffer.
+ *
+ * Since we support the multi-planar API, we need to have a
+ * buffer for each plane. Allocating a single one large enough
+ * to hold all the buffers is simpler, so let's go for that.
+ */
+ csi->scratch.size = 0;
+ for (i = 0; i < csi->fmt.num_planes; i++)
+ csi->scratch.size += csi->fmt.plane_fmt[i].sizeimage;
+
+ csi->scratch.vaddr = dma_alloc_coherent(csi->dev,
+ csi->scratch.size,
+ &csi->scratch.paddr,
+ GFP_KERNEL);
+ if (!csi->scratch.vaddr) {
+ dev_err(csi->dev, "Failed to allocate scratch buffer\n");
+ ret = -ENOMEM;
+ goto err_clear_dma_queue;
+ }
+
+ ret = media_pipeline_start(&csi->vdev.entity, &csi->vdev.pipe);
+ if (ret < 0)
+ goto err_free_scratch_buffer;
+
+ spin_lock_irqsave(&csi->qlock, flags);
+
+ /* Setup timings */
+ writel(CSI_WIN_CTRL_W_ACTIVE(csi->fmt.width * 2),
+ csi->regs + CSI_WIN_CTRL_W_REG);
+ writel(CSI_WIN_CTRL_H_ACTIVE(csi->fmt.height),
+ csi->regs + CSI_WIN_CTRL_H_REG);
+
+ /*
+ * This hardware uses [HV]REF instead of [HV]SYNC. Based on the
+ * provided timing diagrams in the manual, positive polarity
+ * equals active high [HV]REF.
+ *
+ * When the back porch is 0, [HV]REF is more or less equivalent
+ * to [HV]SYNC inverted.
+ */
+ href_pol = !!(bus->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
+ vref_pol = !!(bus->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
+ pclk_pol = !!(bus->flags & V4L2_MBUS_PCLK_SAMPLE_RISING);
+ writel(CSI_CFG_INPUT_FMT(csi_fmt->input) |
+ CSI_CFG_OUTPUT_FMT(csi_fmt->output) |
+ CSI_CFG_VREF_POL(vref_pol) |
+ CSI_CFG_HREF_POL(href_pol) |
+ CSI_CFG_PCLK_POL(pclk_pol),
+ csi->regs + CSI_CFG_REG);
+
+ /* Setup buffer length */
+ writel(csi->fmt.plane_fmt[0].bytesperline,
+ csi->regs + CSI_BUF_LEN_REG);
+
+ /* Prepare our buffers in hardware */
+ ret = sun4i_csi_buffer_fill_all(csi);
+ if (ret) {
+ spin_unlock_irqrestore(&csi->qlock, flags);
+ goto err_disable_pipeline;
+ }
+
+ /* Enable double buffering */
+ writel(CSI_BUF_CTRL_DBE, csi->regs + CSI_BUF_CTRL_REG);
+
+ /* Clear the pending interrupts */
+ writel(CSI_INT_FRM_DONE, csi->regs + 0x34);
+
+ /* Enable frame done interrupt */
+ writel(CSI_INT_FRM_DONE, csi->regs + CSI_INT_EN_REG);
+
+ sun4i_csi_capture_start(csi);
+
+ spin_unlock_irqrestore(&csi->qlock, flags);
+
+ ret = v4l2_subdev_call(csi->src_subdev, video, s_stream, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ goto err_disable_device;
+
+ return 0;
+
+err_disable_device:
+ sun4i_csi_capture_stop(csi);
+
+err_disable_pipeline:
+ media_pipeline_stop(&csi->vdev.entity);
+
+err_free_scratch_buffer:
+ dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr,
+ csi->scratch.paddr);
+
+err_clear_dma_queue:
+ spin_lock_irqsave(&csi->qlock, flags);
+ return_all_buffers(csi, VB2_BUF_STATE_QUEUED);
+ spin_unlock_irqrestore(&csi->qlock, flags);
+
+ return ret;
+}
+
+static void sun4i_csi_stop_streaming(struct vb2_queue *vq)
+{
+ struct sun4i_csi *csi = vb2_get_drv_priv(vq);
+ unsigned long flags;
+
+ dev_dbg(csi->dev, "Stopping capture\n");
+
+ v4l2_subdev_call(csi->src_subdev, video, s_stream, 0);
+ sun4i_csi_capture_stop(csi);
+
+ /* Release all active buffers */
+ spin_lock_irqsave(&csi->qlock, flags);
+ return_all_buffers(csi, VB2_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&csi->qlock, flags);
+
+ media_pipeline_stop(&csi->vdev.entity);
+
+ dma_free_coherent(csi->dev, csi->scratch.size, csi->scratch.vaddr,
+ csi->scratch.paddr);
+}
+
+static const struct vb2_ops sun4i_csi_qops = {
+ .queue_setup = sun4i_csi_queue_setup,
+ .buf_prepare = sun4i_csi_buffer_prepare,
+ .buf_queue = sun4i_csi_buffer_queue,
+ .start_streaming = sun4i_csi_start_streaming,
+ .stop_streaming = sun4i_csi_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static irqreturn_t sun4i_csi_irq(int irq, void *data)
+{
+ struct sun4i_csi *csi = data;
+ u32 reg;
+
+ reg = readl(csi->regs + CSI_INT_STA_REG);
+
+ /* Acknowledge the interrupts */
+ writel(reg, csi->regs + CSI_INT_STA_REG);
+
+ if (!(reg & CSI_INT_FRM_DONE))
+ return IRQ_HANDLED;
+
+ spin_lock(&csi->qlock);
+ if (sun4i_csi_buffer_flip(csi, csi->sequence++)) {
+ dev_warn(csi->dev, "%s: Flip failed\n", __func__);
+ sun4i_csi_capture_stop(csi);
+ }
+ spin_unlock(&csi->qlock);
+
+ return IRQ_HANDLED;
+}
+
+int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq)
+{
+ struct vb2_queue *q = &csi->queue;
+ int ret;
+ int i;
+
+ spin_lock_init(&csi->qlock);
+ mutex_init(&csi->lock);
+
+ INIT_LIST_HEAD(&csi->buf_list);
+ for (i = 0; i < CSI_MAX_BUFFER; i++)
+ csi->current_buf[i] = NULL;
+
+ q->min_buffers_needed = 3;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ q->io_modes = VB2_MMAP;
+ q->lock = &csi->lock;
+ q->drv_priv = csi;
+ q->buf_struct_size = sizeof(struct sun4i_csi_buffer);
+ q->ops = &sun4i_csi_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->dev = csi->dev;
+
+ ret = vb2_queue_init(q);
+ if (ret < 0) {
+ dev_err(csi->dev, "failed to initialize VB2 queue\n");
+ goto err_free_mutex;
+ }
+
+ ret = v4l2_device_register(csi->dev, &csi->v4l);
+ if (ret) {
+ dev_err(csi->dev, "Couldn't register the v4l2 device\n");
+ goto err_free_queue;
+ }
+
+ ret = devm_request_irq(csi->dev, irq, sun4i_csi_irq, 0,
+ dev_name(csi->dev), csi);
+ if (ret) {
+ dev_err(csi->dev, "Couldn't register our interrupt\n");
+ goto err_unregister_device;
+ }
+
+ return 0;
+
+err_unregister_device:
+ v4l2_device_unregister(&csi->v4l);
+
+err_free_queue:
+ vb2_queue_release(q);
+
+err_free_mutex:
+ mutex_destroy(&csi->lock);
+ return ret;
+}
+
+void sun4i_csi_dma_unregister(struct sun4i_csi *csi)
+{
+ v4l2_device_unregister(&csi->v4l);
+ vb2_queue_release(&csi->queue);
+ mutex_destroy(&csi->lock);
+}
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
new file mode 100644
index 000000000000..83a3a0257c7b
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_v4l2.c
@@ -0,0 +1,385 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 NextThing Co
+ * Copyright (C) 2016-2019 Bootlin
+ *
+ * Author: Maxime Ripard <maxime.ripard@bootlin.com>
+ */
+
+#include <linux/device.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-v4l2.h>
+
+#include "sun4i_csi.h"
+
+#define CSI_DEFAULT_WIDTH 640
+#define CSI_DEFAULT_HEIGHT 480
+
+static const struct sun4i_csi_format sun4i_csi_formats[] = {
+ /* YUV422 inputs */
+ {
+ .mbus = MEDIA_BUS_FMT_YUYV8_2X8,
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .input = CSI_INPUT_YUV,
+ .output = CSI_OUTPUT_YUV_420_PLANAR,
+ .num_planes = 3,
+ .bpp = { 8, 8, 8 },
+ .hsub = 2,
+ .vsub = 2,
+ },
+};
+
+const struct sun4i_csi_format *sun4i_csi_find_format(const u32 *fourcc,
+ const u32 *mbus)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun4i_csi_formats); i++) {
+ if (fourcc && *fourcc != sun4i_csi_formats[i].fourcc)
+ continue;
+
+ if (mbus && *mbus != sun4i_csi_formats[i].mbus)
+ continue;
+
+ return &sun4i_csi_formats[i];
+ }
+
+ return NULL;
+}
+
+static int sun4i_csi_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct sun4i_csi *csi = video_drvdata(file);
+
+ strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strscpy(cap->card, "sun4i-csi", sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ dev_name(csi->dev));
+
+ return 0;
+}
+
+static int sun4i_csi_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ strscpy(inp->name, "Camera", sizeof(inp->name));
+
+ return 0;
+}
+
+static int sun4i_csi_g_input(struct file *file, void *fh,
+ unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int sun4i_csi_s_input(struct file *file, void *fh,
+ unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void _sun4i_csi_try_fmt(struct sun4i_csi *csi,
+ struct v4l2_pix_format_mplane *pix)
+{
+ const struct sun4i_csi_format *_fmt;
+ unsigned int height, width;
+ unsigned int i;
+
+ _fmt = sun4i_csi_find_format(&pix->pixelformat, NULL);
+ if (!_fmt)
+ _fmt = &sun4i_csi_formats[0];
+
+ pix->field = V4L2_FIELD_NONE;
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ pix->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(pix->colorspace);
+ pix->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(pix->colorspace);
+ pix->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, pix->colorspace,
+ pix->ycbcr_enc);
+
+ pix->num_planes = _fmt->num_planes;
+ pix->pixelformat = _fmt->fourcc;
+
+ memset(pix->reserved, 0, sizeof(pix->reserved));
+
+ /* Align the width and height on the subsampling */
+ width = ALIGN(pix->width, _fmt->hsub);
+ height = ALIGN(pix->height, _fmt->vsub);
+
+ /* Clamp the width and height to our capabilities */
+ pix->width = clamp(width, _fmt->hsub, CSI_MAX_WIDTH);
+ pix->height = clamp(height, _fmt->vsub, CSI_MAX_HEIGHT);
+
+ for (i = 0; i < _fmt->num_planes; i++) {
+ unsigned int hsub = i > 0 ? _fmt->hsub : 1;
+ unsigned int vsub = i > 0 ? _fmt->vsub : 1;
+ unsigned int bpl;
+
+ bpl = pix->width / hsub * _fmt->bpp[i] / 8;
+ pix->plane_fmt[i].bytesperline = bpl;
+ pix->plane_fmt[i].sizeimage = bpl * pix->height / vsub;
+ memset(pix->plane_fmt[i].reserved, 0,
+ sizeof(pix->plane_fmt[i].reserved));
+ }
+}
+
+static int sun4i_csi_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct sun4i_csi *csi = video_drvdata(file);
+
+ _sun4i_csi_try_fmt(csi, &f->fmt.pix_mp);
+
+ return 0;
+}
+
+static int sun4i_csi_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct sun4i_csi *csi = video_drvdata(file);
+
+ _sun4i_csi_try_fmt(csi, &f->fmt.pix_mp);
+ csi->fmt = f->fmt.pix_mp;
+
+ return 0;
+}
+
+static int sun4i_csi_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct sun4i_csi *csi = video_drvdata(file);
+
+ f->fmt.pix_mp = csi->fmt;
+
+ return 0;
+}
+
+static int sun4i_csi_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index >= ARRAY_SIZE(sun4i_csi_formats))
+ return -EINVAL;
+
+ f->pixelformat = sun4i_csi_formats[f->index].fourcc;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops sun4i_csi_ioctl_ops = {
+ .vidioc_querycap = sun4i_csi_querycap,
+
+ .vidioc_enum_fmt_vid_cap = sun4i_csi_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap_mplane = sun4i_csi_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap_mplane = sun4i_csi_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap_mplane = sun4i_csi_try_fmt_vid_cap,
+
+ .vidioc_enum_input = sun4i_csi_enum_input,
+ .vidioc_g_input = sun4i_csi_g_input,
+ .vidioc_s_input = sun4i_csi_s_input,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+static int sun4i_csi_open(struct file *file)
+{
+ struct sun4i_csi *csi = video_drvdata(file);
+ int ret;
+
+ ret = mutex_lock_interruptible(&csi->lock);
+ if (ret)
+ return ret;
+
+ ret = pm_runtime_get_sync(csi->dev);
+ if (ret < 0)
+ goto err_pm_put;
+
+ ret = v4l2_pipeline_pm_use(&csi->vdev.entity, 1);
+ if (ret)
+ goto err_pm_put;
+
+ ret = v4l2_fh_open(file);
+ if (ret)
+ goto err_pipeline_pm_put;
+
+ mutex_unlock(&csi->lock);
+
+ return 0;
+
+err_pipeline_pm_put:
+ v4l2_pipeline_pm_use(&csi->vdev.entity, 0);
+
+err_pm_put:
+ pm_runtime_put(csi->dev);
+ mutex_unlock(&csi->lock);
+
+ return ret;
+}
+
+static int sun4i_csi_release(struct file *file)
+{
+ struct sun4i_csi *csi = video_drvdata(file);
+
+ mutex_lock(&csi->lock);
+
+ v4l2_fh_release(file);
+ v4l2_pipeline_pm_use(&csi->vdev.entity, 0);
+ pm_runtime_put(csi->dev);
+
+ mutex_unlock(&csi->lock);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations sun4i_csi_fops = {
+ .owner = THIS_MODULE,
+ .open = sun4i_csi_open,
+ .release = sun4i_csi_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .write = vb2_fop_write,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+};
+
+static const struct v4l2_mbus_framefmt sun4i_csi_pad_fmt_default = {
+ .width = CSI_DEFAULT_WIDTH,
+ .height = CSI_DEFAULT_HEIGHT,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+ .quantization = V4L2_QUANTIZATION_DEFAULT,
+ .xfer_func = V4L2_XFER_FUNC_DEFAULT,
+};
+
+static int sun4i_csi_subdev_init_cfg(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg)
+{
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_get_try_format(subdev, cfg, CSI_SUBDEV_SINK);
+ *fmt = sun4i_csi_pad_fmt_default;
+
+ return 0;
+}
+
+static int sun4i_csi_subdev_get_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
+ struct v4l2_mbus_framefmt *subdev_fmt;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
+ else
+ subdev_fmt = &csi->subdev_fmt;
+
+ fmt->format = *subdev_fmt;
+
+ return 0;
+}
+
+static int sun4i_csi_subdev_set_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *fmt)
+{
+ struct sun4i_csi *csi = container_of(subdev, struct sun4i_csi, subdev);
+ struct v4l2_mbus_framefmt *subdev_fmt;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ subdev_fmt = v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
+ else
+ subdev_fmt = &csi->subdev_fmt;
+
+ /* We can only set the format on the sink pad */
+ if (fmt->pad == CSI_SUBDEV_SINK) {
+ /* It's the sink, only allow changing the frame size */
+ subdev_fmt->width = fmt->format.width;
+ subdev_fmt->height = fmt->format.height;
+ subdev_fmt->code = fmt->format.code;
+ }
+
+ fmt->format = *subdev_fmt;
+
+ return 0;
+}
+
+static int
+sun4i_csi_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_mbus_code_enum *mbus)
+{
+ if (mbus->index >= ARRAY_SIZE(sun4i_csi_formats))
+ return -EINVAL;
+
+ mbus->code = sun4i_csi_formats[mbus->index].mbus;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops sun4i_csi_subdev_pad_ops = {
+ .link_validate = v4l2_subdev_link_validate_default,
+ .init_cfg = sun4i_csi_subdev_init_cfg,
+ .get_fmt = sun4i_csi_subdev_get_fmt,
+ .set_fmt = sun4i_csi_subdev_set_fmt,
+ .enum_mbus_code = sun4i_csi_subdev_enum_mbus_code,
+};
+
+const struct v4l2_subdev_ops sun4i_csi_subdev_ops = {
+ .pad = &sun4i_csi_subdev_pad_ops,
+};
+
+int sun4i_csi_v4l2_register(struct sun4i_csi *csi)
+{
+ struct video_device *vdev = &csi->vdev;
+ int ret;
+
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING;
+ vdev->v4l2_dev = &csi->v4l;
+ vdev->queue = &csi->queue;
+ strscpy(vdev->name, KBUILD_MODNAME, sizeof(vdev->name));
+ vdev->release = video_device_release_empty;
+ vdev->lock = &csi->lock;
+
+ /* Set a default format */
+ csi->fmt.pixelformat = sun4i_csi_formats[0].fourcc,
+ csi->fmt.width = CSI_DEFAULT_WIDTH;
+ csi->fmt.height = CSI_DEFAULT_HEIGHT;
+ _sun4i_csi_try_fmt(csi, &csi->fmt);
+ csi->subdev_fmt = sun4i_csi_pad_fmt_default;
+
+ vdev->fops = &sun4i_csi_fops;
+ vdev->ioctl_ops = &sun4i_csi_ioctl_ops;
+ video_set_drvdata(vdev, csi);
+
+ ret = video_register_device(&csi->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ return ret;
+
+ dev_info(csi->dev, "Device registered as %s\n",
+ video_device_node_name(vdev));
+
+ return 0;
+}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index 6e0e894154f4..055eb0b8e396 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -866,11 +866,8 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
}
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "No csi IRQ specified\n");
- ret = -ENXIO;
- return ret;
- }
+ if (irq < 0)
+ return -ENXIO;
ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, MODULE_NAME,
sdev);
diff --git a/drivers/media/platform/sunxi/sun8i-di/Makefile b/drivers/media/platform/sunxi/sun8i-di/Makefile
new file mode 100644
index 000000000000..109f7e5442b7
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-di/Makefile
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_VIDEO_SUN8I_DEINTERLACE) += sun8i-di.o
diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
new file mode 100644
index 000000000000..b61f3dea7c93
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
@@ -0,0 +1,1025 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Allwinner sun8i deinterlacer with scaler driver
+ *
+ * Copyright (C) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
+ *
+ * Based on vim2m driver.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+
+#include "sun8i-di.h"
+
+#define FLAG_SIZE (DEINTERLACE_MAX_WIDTH * DEINTERLACE_MAX_HEIGHT / 4)
+
+static u32 deinterlace_formats[] = {
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_NV21,
+};
+
+static inline u32 deinterlace_read(struct deinterlace_dev *dev, u32 reg)
+{
+ return readl(dev->base + reg);
+}
+
+static inline void deinterlace_write(struct deinterlace_dev *dev,
+ u32 reg, u32 value)
+{
+ writel(value, dev->base + reg);
+}
+
+static inline void deinterlace_set_bits(struct deinterlace_dev *dev,
+ u32 reg, u32 bits)
+{
+ writel(readl(dev->base + reg) | bits, dev->base + reg);
+}
+
+static inline void deinterlace_clr_set_bits(struct deinterlace_dev *dev,
+ u32 reg, u32 clr, u32 set)
+{
+ u32 val = readl(dev->base + reg);
+
+ val &= ~clr;
+ val |= set;
+
+ writel(val, dev->base + reg);
+}
+
+static void deinterlace_device_run(void *priv)
+{
+ struct deinterlace_ctx *ctx = priv;
+ struct deinterlace_dev *dev = ctx->dev;
+ u32 size, stride, width, height, val;
+ struct vb2_v4l2_buffer *src, *dst;
+ unsigned int hstep, vstep;
+ dma_addr_t addr;
+
+ src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ v4l2_m2m_buf_copy_metadata(src, dst, true);
+
+ deinterlace_write(dev, DEINTERLACE_MOD_ENABLE,
+ DEINTERLACE_MOD_ENABLE_EN);
+
+ if (ctx->field) {
+ deinterlace_write(dev, DEINTERLACE_TILE_FLAG0,
+ ctx->flag1_buf_dma);
+ deinterlace_write(dev, DEINTERLACE_TILE_FLAG1,
+ ctx->flag2_buf_dma);
+ } else {
+ deinterlace_write(dev, DEINTERLACE_TILE_FLAG0,
+ ctx->flag2_buf_dma);
+ deinterlace_write(dev, DEINTERLACE_TILE_FLAG1,
+ ctx->flag1_buf_dma);
+ }
+ deinterlace_write(dev, DEINTERLACE_FLAG_LINE_STRIDE, 0x200);
+
+ width = ctx->src_fmt.width;
+ height = ctx->src_fmt.height;
+ stride = ctx->src_fmt.bytesperline;
+ size = stride * height;
+
+ addr = vb2_dma_contig_plane_dma_addr(&src->vb2_buf, 0);
+ deinterlace_write(dev, DEINTERLACE_BUF_ADDR0, addr);
+ deinterlace_write(dev, DEINTERLACE_BUF_ADDR1, addr + size);
+ deinterlace_write(dev, DEINTERLACE_BUF_ADDR2, 0);
+
+ deinterlace_write(dev, DEINTERLACE_LINE_STRIDE0, stride);
+ deinterlace_write(dev, DEINTERLACE_LINE_STRIDE1, stride);
+
+ deinterlace_write(dev, DEINTERLACE_CH0_IN_SIZE,
+ DEINTERLACE_SIZE(width, height));
+ deinterlace_write(dev, DEINTERLACE_CH1_IN_SIZE,
+ DEINTERLACE_SIZE(width / 2, height / 2));
+
+ val = DEINTERLACE_IN_FMT_FMT(DEINTERLACE_IN_FMT_YUV420) |
+ DEINTERLACE_IN_FMT_MOD(DEINTERLACE_MODE_UV_COMBINED);
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_NV12:
+ val |= DEINTERLACE_IN_FMT_PS(DEINTERLACE_PS_UVUV);
+ break;
+ case V4L2_PIX_FMT_NV21:
+ val |= DEINTERLACE_IN_FMT_PS(DEINTERLACE_PS_VUVU);
+ break;
+ }
+ deinterlace_write(dev, DEINTERLACE_IN_FMT, val);
+
+ if (ctx->prev)
+ addr = vb2_dma_contig_plane_dma_addr(&ctx->prev->vb2_buf, 0);
+
+ deinterlace_write(dev, DEINTERLACE_PRELUMA, addr);
+ deinterlace_write(dev, DEINTERLACE_PRECHROMA, addr + size);
+
+ val = DEINTERLACE_OUT_FMT_FMT(DEINTERLACE_OUT_FMT_YUV420SP);
+ switch (ctx->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_NV12:
+ val |= DEINTERLACE_OUT_FMT_PS(DEINTERLACE_PS_UVUV);
+ break;
+ case V4L2_PIX_FMT_NV21:
+ val |= DEINTERLACE_OUT_FMT_PS(DEINTERLACE_PS_VUVU);
+ break;
+ }
+ deinterlace_write(dev, DEINTERLACE_OUT_FMT, val);
+
+ width = ctx->dst_fmt.width;
+ height = ctx->dst_fmt.height;
+ stride = ctx->dst_fmt.bytesperline;
+ size = stride * height;
+
+ deinterlace_write(dev, DEINTERLACE_CH0_OUT_SIZE,
+ DEINTERLACE_SIZE(width, height));
+ deinterlace_write(dev, DEINTERLACE_CH1_OUT_SIZE,
+ DEINTERLACE_SIZE(width / 2, height / 2));
+
+ deinterlace_write(dev, DEINTERLACE_WB_LINE_STRIDE0, stride);
+ deinterlace_write(dev, DEINTERLACE_WB_LINE_STRIDE1, stride);
+
+ addr = vb2_dma_contig_plane_dma_addr(&dst->vb2_buf, 0);
+ deinterlace_write(dev, DEINTERLACE_WB_ADDR0, addr);
+ deinterlace_write(dev, DEINTERLACE_WB_ADDR1, addr + size);
+ deinterlace_write(dev, DEINTERLACE_WB_ADDR2, 0);
+
+ hstep = (ctx->src_fmt.width << 16) / ctx->dst_fmt.width;
+ vstep = (ctx->src_fmt.height << 16) / ctx->dst_fmt.height;
+ deinterlace_write(dev, DEINTERLACE_CH0_HORZ_FACT, hstep);
+ deinterlace_write(dev, DEINTERLACE_CH0_VERT_FACT, vstep);
+ deinterlace_write(dev, DEINTERLACE_CH1_HORZ_FACT, hstep);
+ deinterlace_write(dev, DEINTERLACE_CH1_VERT_FACT, vstep);
+
+ deinterlace_clr_set_bits(dev, DEINTERLACE_FIELD_CTRL,
+ DEINTERLACE_FIELD_CTRL_FIELD_CNT_MSK,
+ DEINTERLACE_FIELD_CTRL_FIELD_CNT(ctx->field));
+
+ deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL,
+ DEINTERLACE_FRM_CTRL_START);
+
+ deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL,
+ DEINTERLACE_FRM_CTRL_REG_READY);
+
+ deinterlace_set_bits(dev, DEINTERLACE_INT_ENABLE,
+ DEINTERLACE_INT_ENABLE_WB_EN);
+
+ deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL,
+ DEINTERLACE_FRM_CTRL_WB_EN);
+}
+
+static int deinterlace_job_ready(void *priv)
+{
+ struct deinterlace_ctx *ctx = priv;
+
+ return v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) >= 1 &&
+ v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) >= 2;
+}
+
+static void deinterlace_job_abort(void *priv)
+{
+ struct deinterlace_ctx *ctx = priv;
+
+ /* Will cancel the transaction in the next interrupt handler */
+ ctx->aborting = 1;
+}
+
+static irqreturn_t deinterlace_irq(int irq, void *data)
+{
+ struct deinterlace_dev *dev = data;
+ struct vb2_v4l2_buffer *src, *dst;
+ enum vb2_buffer_state state;
+ struct deinterlace_ctx *ctx;
+ unsigned int val;
+
+ ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+ if (!ctx) {
+ v4l2_err(&dev->v4l2_dev,
+ "Instance released before the end of transaction\n");
+ return IRQ_NONE;
+ }
+
+ val = deinterlace_read(dev, DEINTERLACE_INT_STATUS);
+ if (!(val & DEINTERLACE_INT_STATUS_WRITEBACK))
+ return IRQ_NONE;
+
+ deinterlace_write(dev, DEINTERLACE_INT_ENABLE, 0);
+ deinterlace_set_bits(dev, DEINTERLACE_INT_STATUS,
+ DEINTERLACE_INT_STATUS_WRITEBACK);
+ deinterlace_write(dev, DEINTERLACE_MOD_ENABLE, 0);
+ deinterlace_clr_set_bits(dev, DEINTERLACE_FRM_CTRL,
+ DEINTERLACE_FRM_CTRL_START, 0);
+
+ val = deinterlace_read(dev, DEINTERLACE_STATUS);
+ if (val & DEINTERLACE_STATUS_WB_ERROR)
+ state = VB2_BUF_STATE_ERROR;
+ else
+ state = VB2_BUF_STATE_DONE;
+
+ dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(dst, state);
+
+ if (ctx->field != ctx->first_field || ctx->aborting) {
+ ctx->field = ctx->first_field;
+
+ src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ if (ctx->prev)
+ v4l2_m2m_buf_done(ctx->prev, state);
+ ctx->prev = src;
+
+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+ } else {
+ ctx->field = !ctx->first_field;
+ deinterlace_device_run(ctx);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void deinterlace_init(struct deinterlace_dev *dev)
+{
+ u32 val;
+ int i;
+
+ deinterlace_write(dev, DEINTERLACE_BYPASS,
+ DEINTERLACE_BYPASS_CSC);
+ deinterlace_write(dev, DEINTERLACE_WB_LINE_STRIDE_CTRL,
+ DEINTERLACE_WB_LINE_STRIDE_CTRL_EN);
+ deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL,
+ DEINTERLACE_FRM_CTRL_OUT_CTRL);
+ deinterlace_write(dev, DEINTERLACE_AGTH_SEL,
+ DEINTERLACE_AGTH_SEL_LINEBUF);
+
+ val = DEINTERLACE_CTRL_EN |
+ DEINTERLACE_CTRL_MODE_MIXED |
+ DEINTERLACE_CTRL_DIAG_INTP_EN |
+ DEINTERLACE_CTRL_TEMP_DIFF_EN;
+ deinterlace_write(dev, DEINTERLACE_CTRL, val);
+
+ deinterlace_clr_set_bits(dev, DEINTERLACE_LUMA_TH,
+ DEINTERLACE_LUMA_TH_MIN_LUMA_MSK,
+ DEINTERLACE_LUMA_TH_MIN_LUMA(4));
+
+ deinterlace_clr_set_bits(dev, DEINTERLACE_SPAT_COMP,
+ DEINTERLACE_SPAT_COMP_TH2_MSK,
+ DEINTERLACE_SPAT_COMP_TH2(5));
+
+ deinterlace_clr_set_bits(dev, DEINTERLACE_TEMP_DIFF,
+ DEINTERLACE_TEMP_DIFF_AMBIGUITY_TH_MSK,
+ DEINTERLACE_TEMP_DIFF_AMBIGUITY_TH(5));
+
+ val = DEINTERLACE_DIAG_INTP_TH0(60) |
+ DEINTERLACE_DIAG_INTP_TH1(0) |
+ DEINTERLACE_DIAG_INTP_TH3(30);
+ deinterlace_write(dev, DEINTERLACE_DIAG_INTP, val);
+
+ deinterlace_clr_set_bits(dev, DEINTERLACE_CHROMA_DIFF,
+ DEINTERLACE_CHROMA_DIFF_TH_MSK,
+ DEINTERLACE_CHROMA_DIFF_TH(5));
+
+ /* neutral filter coefficients */
+ deinterlace_set_bits(dev, DEINTERLACE_FRM_CTRL,
+ DEINTERLACE_FRM_CTRL_COEF_ACCESS);
+ readl_poll_timeout(dev->base + DEINTERLACE_STATUS, val,
+ val & DEINTERLACE_STATUS_COEF_STATUS, 2, 40);
+
+ for (i = 0; i < 32; i++) {
+ deinterlace_write(dev, DEINTERLACE_CH0_HORZ_COEF0 + i * 4,
+ DEINTERLACE_IDENTITY_COEF);
+ deinterlace_write(dev, DEINTERLACE_CH0_VERT_COEF + i * 4,
+ DEINTERLACE_IDENTITY_COEF);
+ deinterlace_write(dev, DEINTERLACE_CH1_HORZ_COEF0 + i * 4,
+ DEINTERLACE_IDENTITY_COEF);
+ deinterlace_write(dev, DEINTERLACE_CH1_VERT_COEF + i * 4,
+ DEINTERLACE_IDENTITY_COEF);
+ }
+
+ deinterlace_clr_set_bits(dev, DEINTERLACE_FRM_CTRL,
+ DEINTERLACE_FRM_CTRL_COEF_ACCESS, 0);
+}
+
+static inline struct deinterlace_ctx *deinterlace_file2ctx(struct file *file)
+{
+ return container_of(file->private_data, struct deinterlace_ctx, fh);
+}
+
+static bool deinterlace_check_format(u32 pixelformat)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(deinterlace_formats); i++)
+ if (deinterlace_formats[i] == pixelformat)
+ return true;
+
+ return false;
+}
+
+static void deinterlace_prepare_format(struct v4l2_pix_format *pix_fmt)
+{
+ unsigned int height = pix_fmt->height;
+ unsigned int width = pix_fmt->width;
+ unsigned int bytesperline;
+ unsigned int sizeimage;
+
+ width = clamp(width, DEINTERLACE_MIN_WIDTH,
+ DEINTERLACE_MAX_WIDTH);
+ height = clamp(height, DEINTERLACE_MIN_HEIGHT,
+ DEINTERLACE_MAX_HEIGHT);
+
+ bytesperline = ALIGN(width, 2);
+ /* luma */
+ sizeimage = bytesperline * height;
+ /* chroma */
+ sizeimage += bytesperline * height / 2;
+
+ pix_fmt->width = width;
+ pix_fmt->height = height;
+ pix_fmt->bytesperline = bytesperline;
+ pix_fmt->sizeimage = sizeimage;
+}
+
+static int deinterlace_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, DEINTERLACE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, DEINTERLACE_NAME, sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", DEINTERLACE_NAME);
+
+ return 0;
+}
+
+static int deinterlace_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index < ARRAY_SIZE(deinterlace_formats)) {
+ f->pixelformat = deinterlace_formats[f->index];
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int deinterlace_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ if (fsize->index != 0)
+ return -EINVAL;
+
+ if (!deinterlace_check_format(fsize->pixel_format))
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = DEINTERLACE_MIN_WIDTH;
+ fsize->stepwise.min_height = DEINTERLACE_MIN_HEIGHT;
+ fsize->stepwise.max_width = DEINTERLACE_MAX_WIDTH;
+ fsize->stepwise.max_height = DEINTERLACE_MAX_HEIGHT;
+ fsize->stepwise.step_width = 2;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static int deinterlace_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct deinterlace_ctx *ctx = deinterlace_file2ctx(file);
+
+ f->fmt.pix = ctx->dst_fmt;
+
+ return 0;
+}
+
+static int deinterlace_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct deinterlace_ctx *ctx = deinterlace_file2ctx(file);
+
+ f->fmt.pix = ctx->src_fmt;
+
+ return 0;
+}
+
+static int deinterlace_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ if (!deinterlace_check_format(f->fmt.pix.pixelformat))
+ f->fmt.pix.pixelformat = deinterlace_formats[0];
+
+ if (f->fmt.pix.field != V4L2_FIELD_NONE)
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+ deinterlace_prepare_format(&f->fmt.pix);
+
+ return 0;
+}
+
+static int deinterlace_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ if (!deinterlace_check_format(f->fmt.pix.pixelformat))
+ f->fmt.pix.pixelformat = deinterlace_formats[0];
+
+ if (f->fmt.pix.field != V4L2_FIELD_INTERLACED_TB &&
+ f->fmt.pix.field != V4L2_FIELD_INTERLACED_BT &&
+ f->fmt.pix.field != V4L2_FIELD_INTERLACED)
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ deinterlace_prepare_format(&f->fmt.pix);
+
+ return 0;
+}
+
+static int deinterlace_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct deinterlace_ctx *ctx = deinterlace_file2ctx(file);
+ struct vb2_queue *vq;
+ int ret;
+
+ ret = deinterlace_try_fmt_vid_cap(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+ ctx->dst_fmt = f->fmt.pix;
+
+ return 0;
+}
+
+static int deinterlace_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct deinterlace_ctx *ctx = deinterlace_file2ctx(file);
+ struct vb2_queue *vq;
+ int ret;
+
+ ret = deinterlace_try_fmt_vid_out(file, priv, f);
+ if (ret)
+ return ret;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (vb2_is_busy(vq))
+ return -EBUSY;
+
+ ctx->src_fmt = f->fmt.pix;
+
+ /* Propagate colorspace information to capture. */
+ ctx->dst_fmt.colorspace = f->fmt.pix.colorspace;
+ ctx->dst_fmt.xfer_func = f->fmt.pix.xfer_func;
+ ctx->dst_fmt.ycbcr_enc = f->fmt.pix.ycbcr_enc;
+ ctx->dst_fmt.quantization = f->fmt.pix.quantization;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = {
+ .vidioc_querycap = deinterlace_querycap,
+
+ .vidioc_enum_framesizes = deinterlace_enum_framesizes,
+
+ .vidioc_enum_fmt_vid_cap = deinterlace_enum_fmt,
+ .vidioc_g_fmt_vid_cap = deinterlace_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = deinterlace_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = deinterlace_s_fmt_vid_cap,
+
+ .vidioc_enum_fmt_vid_out = deinterlace_enum_fmt,
+ .vidioc_g_fmt_vid_out = deinterlace_g_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = deinterlace_try_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = deinterlace_s_fmt_vid_out,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+};
+
+static int deinterlace_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq);
+ struct v4l2_pix_format *pix_fmt;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ pix_fmt = &ctx->src_fmt;
+ else
+ pix_fmt = &ctx->dst_fmt;
+
+ if (*nplanes) {
+ if (sizes[0] < pix_fmt->sizeimage)
+ return -EINVAL;
+ } else {
+ sizes[0] = pix_fmt->sizeimage;
+ *nplanes = 1;
+ }
+
+ return 0;
+}
+
+static int deinterlace_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vb2_queue *vq = vb->vb2_queue;
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq);
+ struct v4l2_pix_format *pix_fmt;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ pix_fmt = &ctx->src_fmt;
+ else
+ pix_fmt = &ctx->dst_fmt;
+
+ if (vb2_plane_size(vb, 0) < pix_fmt->sizeimage)
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb, 0, pix_fmt->sizeimage);
+
+ return 0;
+}
+
+static void deinterlace_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static void deinterlace_queue_cleanup(struct vb2_queue *vq, u32 state)
+{
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq);
+ struct vb2_v4l2_buffer *vbuf;
+
+ do {
+ if (V4L2_TYPE_IS_OUTPUT(vq->type))
+ vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ if (vbuf)
+ v4l2_m2m_buf_done(vbuf, state);
+ } while (vbuf);
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type) && ctx->prev)
+ v4l2_m2m_buf_done(ctx->prev, state);
+}
+
+static int deinterlace_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq);
+ struct device *dev = ctx->dev->dev;
+ int ret;
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable module\n");
+
+ goto err_runtime_get;
+ }
+
+ ctx->first_field =
+ ctx->src_fmt.field == V4L2_FIELD_INTERLACED_BT;
+ ctx->field = ctx->first_field;
+
+ ctx->prev = NULL;
+ ctx->aborting = 0;
+
+ ctx->flag1_buf = dma_alloc_coherent(dev, FLAG_SIZE,
+ &ctx->flag1_buf_dma,
+ GFP_KERNEL);
+ if (!ctx->flag1_buf) {
+ ret = -ENOMEM;
+
+ goto err_no_mem1;
+ }
+
+ ctx->flag2_buf = dma_alloc_coherent(dev, FLAG_SIZE,
+ &ctx->flag2_buf_dma,
+ GFP_KERNEL);
+ if (!ctx->flag2_buf) {
+ ret = -ENOMEM;
+
+ goto err_no_mem2;
+ }
+ }
+
+ return 0;
+
+err_no_mem2:
+ dma_free_coherent(dev, FLAG_SIZE, ctx->flag1_buf,
+ ctx->flag1_buf_dma);
+err_no_mem1:
+ pm_runtime_put(dev);
+err_runtime_get:
+ deinterlace_queue_cleanup(vq, VB2_BUF_STATE_QUEUED);
+
+ return ret;
+}
+
+static void deinterlace_stop_streaming(struct vb2_queue *vq)
+{
+ struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq);
+
+ if (V4L2_TYPE_IS_OUTPUT(vq->type)) {
+ struct device *dev = ctx->dev->dev;
+
+ dma_free_coherent(dev, FLAG_SIZE, ctx->flag1_buf,
+ ctx->flag1_buf_dma);
+ dma_free_coherent(dev, FLAG_SIZE, ctx->flag2_buf,
+ ctx->flag2_buf_dma);
+
+ pm_runtime_put(dev);
+ }
+
+ deinterlace_queue_cleanup(vq, VB2_BUF_STATE_ERROR);
+}
+
+static const struct vb2_ops deinterlace_qops = {
+ .queue_setup = deinterlace_queue_setup,
+ .buf_prepare = deinterlace_buf_prepare,
+ .buf_queue = deinterlace_buf_queue,
+ .start_streaming = deinterlace_start_streaming,
+ .stop_streaming = deinterlace_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int deinterlace_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct deinterlace_ctx *ctx = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ src_vq->min_buffers_needed = 1;
+ src_vq->ops = &deinterlace_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->dev->dev_mutex;
+ src_vq->dev = ctx->dev->dev;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->min_buffers_needed = 2;
+ dst_vq->ops = &deinterlace_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->dev->dev_mutex;
+ dst_vq->dev = ctx->dev->dev;
+
+ ret = vb2_queue_init(dst_vq);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int deinterlace_open(struct file *file)
+{
+ struct deinterlace_dev *dev = video_drvdata(file);
+ struct deinterlace_ctx *ctx = NULL;
+ int ret;
+
+ if (mutex_lock_interruptible(&dev->dev_mutex))
+ return -ERESTARTSYS;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx) {
+ mutex_unlock(&dev->dev_mutex);
+ return -ENOMEM;
+ }
+
+ /* default output format */
+ ctx->src_fmt.pixelformat = deinterlace_formats[0];
+ ctx->src_fmt.field = V4L2_FIELD_INTERLACED;
+ ctx->src_fmt.width = 640;
+ ctx->src_fmt.height = 480;
+ deinterlace_prepare_format(&ctx->src_fmt);
+
+ /* default capture format */
+ ctx->dst_fmt.pixelformat = deinterlace_formats[0];
+ ctx->dst_fmt.field = V4L2_FIELD_NONE;
+ ctx->dst_fmt.width = 640;
+ ctx->dst_fmt.height = 480;
+ deinterlace_prepare_format(&ctx->dst_fmt);
+
+ v4l2_fh_init(&ctx->fh, video_devdata(file));
+ file->private_data = &ctx->fh;
+ ctx->dev = dev;
+
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+ &deinterlace_queue_init);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ goto err_free;
+ }
+
+ v4l2_fh_add(&ctx->fh);
+
+ mutex_unlock(&dev->dev_mutex);
+
+ return 0;
+
+err_free:
+ kfree(ctx);
+ mutex_unlock(&dev->dev_mutex);
+
+ return ret;
+}
+
+static int deinterlace_release(struct file *file)
+{
+ struct deinterlace_dev *dev = video_drvdata(file);
+ struct deinterlace_ctx *ctx = container_of(file->private_data,
+ struct deinterlace_ctx, fh);
+
+ mutex_lock(&dev->dev_mutex);
+
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+
+ kfree(ctx);
+
+ mutex_unlock(&dev->dev_mutex);
+
+ return 0;
+}
+
+static const struct v4l2_file_operations deinterlace_fops = {
+ .owner = THIS_MODULE,
+ .open = deinterlace_open,
+ .release = deinterlace_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static const struct video_device deinterlace_video_device = {
+ .name = DEINTERLACE_NAME,
+ .vfl_dir = VFL_DIR_M2M,
+ .fops = &deinterlace_fops,
+ .ioctl_ops = &deinterlace_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING,
+};
+
+static const struct v4l2_m2m_ops deinterlace_m2m_ops = {
+ .device_run = deinterlace_device_run,
+ .job_ready = deinterlace_job_ready,
+ .job_abort = deinterlace_job_abort,
+};
+
+static int deinterlace_probe(struct platform_device *pdev)
+{
+ struct deinterlace_dev *dev;
+ struct video_device *vfd;
+ struct resource *res;
+ int irq, ret;
+
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->vfd = deinterlace_video_device;
+ dev->dev = &pdev->dev;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(dev->dev, "Failed to get IRQ\n");
+
+ return irq;
+ }
+
+ ret = devm_request_irq(dev->dev, irq, deinterlace_irq,
+ 0, dev_name(dev->dev), dev);
+ if (ret) {
+ dev_err(dev->dev, "Failed to request IRQ\n");
+
+ return ret;
+ }
+
+ ret = of_dma_configure(dev->dev, dev->dev->of_node, true);
+ if (ret)
+ return ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->base))
+ return PTR_ERR(dev->base);
+
+ dev->bus_clk = devm_clk_get(dev->dev, "bus");
+ if (IS_ERR(dev->bus_clk)) {
+ dev_err(dev->dev, "Failed to get bus clock\n");
+
+ return PTR_ERR(dev->bus_clk);
+ }
+
+ dev->mod_clk = devm_clk_get(dev->dev, "mod");
+ if (IS_ERR(dev->mod_clk)) {
+ dev_err(dev->dev, "Failed to get mod clock\n");
+
+ return PTR_ERR(dev->mod_clk);
+ }
+
+ dev->ram_clk = devm_clk_get(dev->dev, "ram");
+ if (IS_ERR(dev->ram_clk)) {
+ dev_err(dev->dev, "Failed to get ram clock\n");
+
+ return PTR_ERR(dev->ram_clk);
+ }
+
+ dev->rstc = devm_reset_control_get(dev->dev, NULL);
+ if (IS_ERR(dev->rstc)) {
+ dev_err(dev->dev, "Failed to get reset control\n");
+
+ return PTR_ERR(dev->rstc);
+ }
+
+ mutex_init(&dev->dev_mutex);
+
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ dev_err(dev->dev, "Failed to register V4L2 device\n");
+
+ return ret;
+ }
+
+ vfd = &dev->vfd;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s",
+ deinterlace_video_device.name);
+ 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_v4l2;
+ }
+
+ v4l2_info(&dev->v4l2_dev,
+ "Device registered as /dev/video%d\n", vfd->num);
+
+ dev->m2m_dev = v4l2_m2m_init(&deinterlace_m2m_ops);
+ if (IS_ERR(dev->m2m_dev)) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to initialize V4L2 M2M device\n");
+ ret = PTR_ERR(dev->m2m_dev);
+
+ goto err_video;
+ }
+
+ platform_set_drvdata(pdev, dev);
+
+ pm_runtime_enable(dev->dev);
+
+ return 0;
+
+err_video:
+ video_unregister_device(&dev->vfd);
+err_v4l2:
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ return ret;
+}
+
+static int deinterlace_remove(struct platform_device *pdev)
+{
+ struct deinterlace_dev *dev = platform_get_drvdata(pdev);
+
+ v4l2_m2m_release(dev->m2m_dev);
+ video_unregister_device(&dev->vfd);
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ pm_runtime_force_suspend(&pdev->dev);
+
+ return 0;
+}
+
+static int deinterlace_runtime_resume(struct device *device)
+{
+ struct deinterlace_dev *dev = dev_get_drvdata(device);
+ int ret;
+
+ ret = clk_set_rate_exclusive(dev->mod_clk, 300000000);
+ if (ret) {
+ dev_err(dev->dev, "Failed to set exclusive mod clock rate\n");
+
+ return ret;
+ }
+
+ ret = clk_prepare_enable(dev->bus_clk);
+ if (ret) {
+ dev_err(dev->dev, "Failed to enable bus clock\n");
+
+ goto err_exlusive_rate;
+ }
+
+ ret = clk_prepare_enable(dev->mod_clk);
+ if (ret) {
+ dev_err(dev->dev, "Failed to enable mod clock\n");
+
+ goto err_bus_clk;
+ }
+
+ ret = clk_prepare_enable(dev->ram_clk);
+ if (ret) {
+ dev_err(dev->dev, "Failed to enable ram clock\n");
+
+ goto err_mod_clk;
+ }
+
+ ret = reset_control_deassert(dev->rstc);
+ if (ret) {
+ dev_err(dev->dev, "Failed to apply reset\n");
+
+ goto err_ram_clk;
+ }
+
+ deinterlace_init(dev);
+
+ return 0;
+
+err_exlusive_rate:
+ clk_rate_exclusive_put(dev->mod_clk);
+err_ram_clk:
+ clk_disable_unprepare(dev->ram_clk);
+err_mod_clk:
+ clk_disable_unprepare(dev->mod_clk);
+err_bus_clk:
+ clk_disable_unprepare(dev->bus_clk);
+
+ return ret;
+}
+
+static int deinterlace_runtime_suspend(struct device *device)
+{
+ struct deinterlace_dev *dev = dev_get_drvdata(device);
+
+ reset_control_assert(dev->rstc);
+
+ clk_disable_unprepare(dev->ram_clk);
+ clk_disable_unprepare(dev->mod_clk);
+ clk_disable_unprepare(dev->bus_clk);
+ clk_rate_exclusive_put(dev->mod_clk);
+
+ return 0;
+}
+
+static const struct of_device_id deinterlace_dt_match[] = {
+ { .compatible = "allwinner,sun8i-h3-deinterlace" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, deinterlace_dt_match);
+
+static const struct dev_pm_ops deinterlace_pm_ops = {
+ .runtime_resume = deinterlace_runtime_resume,
+ .runtime_suspend = deinterlace_runtime_suspend,
+};
+
+static struct platform_driver deinterlace_driver = {
+ .probe = deinterlace_probe,
+ .remove = deinterlace_remove,
+ .driver = {
+ .name = DEINTERLACE_NAME,
+ .of_match_table = deinterlace_dt_match,
+ .pm = &deinterlace_pm_ops,
+ },
+};
+module_platform_driver(deinterlace_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_DESCRIPTION("Allwinner Deinterlace driver");
diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.h b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.h
new file mode 100644
index 000000000000..0254251d8687
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.h
@@ -0,0 +1,237 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Allwinner Deinterlace driver
+ *
+ * Copyright (C) 2019 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#ifndef _SUN8I_DEINTERLACE_H_
+#define _SUN8I_DEINTERLACE_H_
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-v4l2.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <linux/platform_device.h>
+
+#define DEINTERLACE_NAME "sun8i-di"
+
+#define DEINTERLACE_MOD_ENABLE 0x00
+#define DEINTERLACE_MOD_ENABLE_EN BIT(0)
+
+#define DEINTERLACE_FRM_CTRL 0x04
+#define DEINTERLACE_FRM_CTRL_REG_READY BIT(0)
+#define DEINTERLACE_FRM_CTRL_WB_EN BIT(2)
+#define DEINTERLACE_FRM_CTRL_OUT_CTRL BIT(11)
+#define DEINTERLACE_FRM_CTRL_START BIT(16)
+#define DEINTERLACE_FRM_CTRL_COEF_ACCESS BIT(23)
+
+#define DEINTERLACE_BYPASS 0x08
+#define DEINTERLACE_BYPASS_CSC BIT(1)
+
+#define DEINTERLACE_AGTH_SEL 0x0c
+#define DEINTERLACE_AGTH_SEL_LINEBUF BIT(8)
+
+#define DEINTERLACE_LINT_CTRL 0x10
+#define DEINTERLACE_TRD_PRELUMA 0x1c
+#define DEINTERLACE_BUF_ADDR0 0x20
+#define DEINTERLACE_BUF_ADDR1 0x24
+#define DEINTERLACE_BUF_ADDR2 0x28
+
+#define DEINTERLACE_FIELD_CTRL 0x2c
+#define DEINTERLACE_FIELD_CTRL_FIELD_CNT(v) ((v) & 0xff)
+#define DEINTERLACE_FIELD_CTRL_FIELD_CNT_MSK (0xff)
+
+#define DEINTERLACE_TB_OFFSET0 0x30
+#define DEINTERLACE_TB_OFFSET1 0x34
+#define DEINTERLACE_TB_OFFSET2 0x38
+#define DEINTERLACE_TRD_PRECHROMA 0x3c
+#define DEINTERLACE_LINE_STRIDE0 0x40
+#define DEINTERLACE_LINE_STRIDE1 0x44
+#define DEINTERLACE_LINE_STRIDE2 0x48
+
+#define DEINTERLACE_IN_FMT 0x4c
+#define DEINTERLACE_IN_FMT_PS(v) ((v) & 3)
+#define DEINTERLACE_IN_FMT_FMT(v) (((v) & 7) << 4)
+#define DEINTERLACE_IN_FMT_MOD(v) (((v) & 7) << 8)
+
+#define DEINTERLACE_WB_ADDR0 0x50
+#define DEINTERLACE_WB_ADDR1 0x54
+#define DEINTERLACE_WB_ADDR2 0x58
+
+#define DEINTERLACE_OUT_FMT 0x5c
+#define DEINTERLACE_OUT_FMT_FMT(v) ((v) & 0xf)
+#define DEINTERLACE_OUT_FMT_PS(v) (((v) & 3) << 5)
+
+#define DEINTERLACE_INT_ENABLE 0x60
+#define DEINTERLACE_INT_ENABLE_WB_EN BIT(7)
+
+#define DEINTERLACE_INT_STATUS 0x64
+#define DEINTERLACE_INT_STATUS_WRITEBACK BIT(7)
+
+#define DEINTERLACE_STATUS 0x68
+#define DEINTERLACE_STATUS_COEF_STATUS BIT(11)
+#define DEINTERLACE_STATUS_WB_ERROR BIT(12)
+
+#define DEINTERLACE_CSC_COEF 0x70 /* 12 registers */
+
+#define DEINTERLACE_CTRL 0xa0
+#define DEINTERLACE_CTRL_EN BIT(0)
+#define DEINTERLACE_CTRL_FLAG_OUT_EN BIT(8)
+#define DEINTERLACE_CTRL_MODE_PASSTROUGH (0 << 16)
+#define DEINTERLACE_CTRL_MODE_WEAVE (1 << 16)
+#define DEINTERLACE_CTRL_MODE_BOB (2 << 16)
+#define DEINTERLACE_CTRL_MODE_MIXED (3 << 16)
+#define DEINTERLACE_CTRL_DIAG_INTP_EN BIT(24)
+#define DEINTERLACE_CTRL_TEMP_DIFF_EN BIT(25)
+
+#define DEINTERLACE_DIAG_INTP 0xa4
+#define DEINTERLACE_DIAG_INTP_TH0(v) ((v) & 0x7f)
+#define DEINTERLACE_DIAG_INTP_TH0_MSK (0x7f)
+#define DEINTERLACE_DIAG_INTP_TH1(v) (((v) & 0x7f) << 8)
+#define DEINTERLACE_DIAG_INTP_TH1_MSK (0x7f << 8)
+#define DEINTERLACE_DIAG_INTP_TH3(v) (((v) & 0xff) << 24)
+#define DEINTERLACE_DIAG_INTP_TH3_MSK (0xff << 24)
+
+#define DEINTERLACE_TEMP_DIFF 0xa8
+#define DEINTERLACE_TEMP_DIFF_SAD_CENTRAL_TH(v) ((v) & 0x7f)
+#define DEINTERLACE_TEMP_DIFF_SAD_CENTRAL_TH_MSK (0x7f)
+#define DEINTERLACE_TEMP_DIFF_AMBIGUITY_TH(v) (((v) & 0x7f) << 8)
+#define DEINTERLACE_TEMP_DIFF_AMBIGUITY_TH_MSK (0x7f << 8)
+#define DEINTERLACE_TEMP_DIFF_DIRECT_DITHER_TH(v) (((v) & 0x7ff) << 16)
+#define DEINTERLACE_TEMP_DIFF_DIRECT_DITHER_TH_MSK (0x7ff << 16)
+
+#define DEINTERLACE_LUMA_TH 0xac
+#define DEINTERLACE_LUMA_TH_MIN_LUMA(v) ((v) & 0xff)
+#define DEINTERLACE_LUMA_TH_MIN_LUMA_MSK (0xff)
+#define DEINTERLACE_LUMA_TH_MAX_LUMA(v) (((v) & 0xff) << 8)
+#define DEINTERLACE_LUMA_TH_MAX_LUMA_MSK (0xff << 8)
+#define DEINTERLACE_LUMA_TH_AVG_LUMA_SHIFT(v) (((v) & 0xff) << 16)
+#define DEINTERLACE_LUMA_TH_AVG_LUMA_SHIFT_MSK (0xff << 16)
+#define DEINTERLACE_LUMA_TH_PIXEL_STATIC(v) (((v) & 3) << 24)
+#define DEINTERLACE_LUMA_TH_PIXEL_STATIC_MSK (3 << 24)
+
+#define DEINTERLACE_SPAT_COMP 0xb0
+#define DEINTERLACE_SPAT_COMP_TH2(v) ((v) & 0xff)
+#define DEINTERLACE_SPAT_COMP_TH2_MSK (0xff)
+#define DEINTERLACE_SPAT_COMP_TH3(v) (((v) & 0xff) << 16)
+#define DEINTERLACE_SPAT_COMP_TH3_MSK (0xff << 16)
+
+#define DEINTERLACE_CHROMA_DIFF 0xb4
+#define DEINTERLACE_CHROMA_DIFF_TH(v) ((v) & 0xff)
+#define DEINTERLACE_CHROMA_DIFF_TH_MSK (0xff)
+#define DEINTERLACE_CHROMA_DIFF_LUMA(v) (((v) & 0x3f) << 16)
+#define DEINTERLACE_CHROMA_DIFF_LUMA_MSK (0x3f << 16)
+#define DEINTERLACE_CHROMA_DIFF_CHROMA(v) (((v) & 0x3f) << 24)
+#define DEINTERLACE_CHROMA_DIFF_CHROMA_MSK (0x3f << 24)
+
+#define DEINTERLACE_PRELUMA 0xb8
+#define DEINTERLACE_PRECHROMA 0xbc
+#define DEINTERLACE_TILE_FLAG0 0xc0
+#define DEINTERLACE_TILE_FLAG1 0xc4
+#define DEINTERLACE_FLAG_LINE_STRIDE 0xc8
+#define DEINTERLACE_FLAG_SEQ 0xcc
+
+#define DEINTERLACE_WB_LINE_STRIDE_CTRL 0xd0
+#define DEINTERLACE_WB_LINE_STRIDE_CTRL_EN BIT(0)
+
+#define DEINTERLACE_WB_LINE_STRIDE0 0xd4
+#define DEINTERLACE_WB_LINE_STRIDE1 0xd8
+#define DEINTERLACE_WB_LINE_STRIDE2 0xdc
+#define DEINTERLACE_TRD_CTRL 0xe0
+#define DEINTERLACE_TRD_BUF_ADDR0 0xe4
+#define DEINTERLACE_TRD_BUF_ADDR1 0xe8
+#define DEINTERLACE_TRD_BUF_ADDR2 0xec
+#define DEINTERLACE_TRD_TB_OFF0 0xf0
+#define DEINTERLACE_TRD_TB_OFF1 0xf4
+#define DEINTERLACE_TRD_TB_OFF2 0xf8
+#define DEINTERLACE_TRD_WB_STRIDE 0xfc
+#define DEINTERLACE_CH0_IN_SIZE 0x100
+#define DEINTERLACE_CH0_OUT_SIZE 0x104
+#define DEINTERLACE_CH0_HORZ_FACT 0x108
+#define DEINTERLACE_CH0_VERT_FACT 0x10c
+#define DEINTERLACE_CH0_HORZ_PHASE 0x110
+#define DEINTERLACE_CH0_VERT_PHASE0 0x114
+#define DEINTERLACE_CH0_VERT_PHASE1 0x118
+#define DEINTERLACE_CH0_HORZ_TAP0 0x120
+#define DEINTERLACE_CH0_HORZ_TAP1 0x124
+#define DEINTERLACE_CH0_VERT_TAP 0x128
+#define DEINTERLACE_CH1_IN_SIZE 0x200
+#define DEINTERLACE_CH1_OUT_SIZE 0x204
+#define DEINTERLACE_CH1_HORZ_FACT 0x208
+#define DEINTERLACE_CH1_VERT_FACT 0x20c
+#define DEINTERLACE_CH1_HORZ_PHASE 0x210
+#define DEINTERLACE_CH1_VERT_PHASE0 0x214
+#define DEINTERLACE_CH1_VERT_PHASE1 0x218
+#define DEINTERLACE_CH1_HORZ_TAP0 0x220
+#define DEINTERLACE_CH1_HORZ_TAP1 0x224
+#define DEINTERLACE_CH1_VERT_TAP 0x228
+#define DEINTERLACE_CH0_HORZ_COEF0 0x400 /* 32 registers */
+#define DEINTERLACE_CH0_HORZ_COEF1 0x480 /* 32 registers */
+#define DEINTERLACE_CH0_VERT_COEF 0x500 /* 32 registers */
+#define DEINTERLACE_CH1_HORZ_COEF0 0x600 /* 32 registers */
+#define DEINTERLACE_CH1_HORZ_COEF1 0x680 /* 32 registers */
+#define DEINTERLACE_CH1_VERT_COEF 0x700 /* 32 registers */
+#define DEINTERLACE_CH3_HORZ_COEF0 0x800 /* 32 registers */
+#define DEINTERLACE_CH3_HORZ_COEF1 0x880 /* 32 registers */
+#define DEINTERLACE_CH3_VERT_COEF 0x900 /* 32 registers */
+
+#define DEINTERLACE_MIN_WIDTH 2U
+#define DEINTERLACE_MIN_HEIGHT 2U
+#define DEINTERLACE_MAX_WIDTH 2048U
+#define DEINTERLACE_MAX_HEIGHT 1100U
+
+#define DEINTERLACE_MODE_UV_COMBINED 2
+
+#define DEINTERLACE_IN_FMT_YUV420 2
+
+#define DEINTERLACE_OUT_FMT_YUV420SP 13
+
+#define DEINTERLACE_PS_UVUV 0
+#define DEINTERLACE_PS_VUVU 1
+
+#define DEINTERLACE_IDENTITY_COEF 0x4000
+
+#define DEINTERLACE_SIZE(w, h) (((h) - 1) << 16 | ((w) - 1))
+
+struct deinterlace_ctx {
+ struct v4l2_fh fh;
+ struct deinterlace_dev *dev;
+
+ struct v4l2_pix_format src_fmt;
+ struct v4l2_pix_format dst_fmt;
+
+ void *flag1_buf;
+ dma_addr_t flag1_buf_dma;
+
+ void *flag2_buf;
+ dma_addr_t flag2_buf_dma;
+
+ struct vb2_v4l2_buffer *prev;
+
+ unsigned int first_field;
+ unsigned int field;
+
+ int aborting;
+};
+
+struct deinterlace_dev {
+ struct v4l2_device v4l2_dev;
+ struct video_device vfd;
+ struct device *dev;
+ struct v4l2_m2m_dev *m2m_dev;
+
+ /* Device file mutex */
+ struct mutex dev_mutex;
+
+ void __iomem *base;
+
+ struct clk *bus_clk;
+ struct clk *mod_clk;
+ struct clk *ram_clk;
+
+ struct reset_control *rstc;
+};
+
+#endif
diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c
index 6498b2d0492e..1ac0c70a5981 100644
--- a/drivers/media/platform/tegra-cec/tegra_cec.c
+++ b/drivers/media/platform/tegra-cec/tegra_cec.c
@@ -351,7 +351,7 @@ static int tegra_cec_probe(struct platform_device *pdev)
if (cec->tegra_cec_irq <= 0)
return -EBUSY;
- cec->cec_base = devm_ioremap_nocache(&pdev->dev, res->start,
+ cec->cec_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!cec->cec_base) {
@@ -380,38 +380,39 @@ static int tegra_cec_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev,
"Unable to request interrupt for device\n");
- goto clk_error;
- }
-
- cec->notifier = cec_notifier_get(hdmi_dev);
- if (!cec->notifier) {
- ret = -ENOMEM;
- goto clk_error;
+ goto err_clk;
}
cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME,
- CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL,
+ CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL |
+ CEC_CAP_CONNECTOR_INFO,
CEC_MAX_LOG_ADDRS);
if (IS_ERR(cec->adap)) {
ret = -ENOMEM;
dev_err(&pdev->dev, "Couldn't create cec adapter\n");
- goto cec_error;
+ goto err_clk;
+ }
+
+ cec->notifier = cec_notifier_cec_adap_register(hdmi_dev, NULL,
+ cec->adap);
+ if (!cec->notifier) {
+ ret = -ENOMEM;
+ goto err_adapter;
}
+
ret = cec_register_adapter(cec->adap, &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "Couldn't register device\n");
- goto cec_error;
+ goto err_notifier;
}
- cec_register_cec_notifier(cec->adap, cec->notifier);
-
return 0;
-cec_error:
- if (cec->notifier)
- cec_notifier_put(cec->notifier);
+err_notifier:
+ cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
+err_adapter:
cec_delete_adapter(cec->adap);
-clk_error:
+err_clk:
clk_disable_unprepare(cec->clk);
return ret;
}
@@ -422,8 +423,8 @@ static int tegra_cec_remove(struct platform_device *pdev)
clk_disable_unprepare(cec->clk);
+ cec_notifier_cec_adap_unregister(cec->notifier, cec->adap);
cec_unregister_adapter(cec->adap);
- cec_notifier_put(cec->notifier);
return 0;
}
diff --git a/drivers/media/platform/tegra-cec/tegra_cec.h b/drivers/media/platform/tegra-cec/tegra_cec.h
index 32d7d69f9491..8c370be38e1e 100644
--- a/drivers/media/platform/tegra-cec/tegra_cec.h
+++ b/drivers/media/platform/tegra-cec/tegra_cec.h
@@ -34,24 +34,24 @@
#define TEGRA_CEC_HWCTRL_RX_LADDR_MASK 0x7fff
#define TEGRA_CEC_HWCTRL_RX_LADDR(x) \
((x) & TEGRA_CEC_HWCTRL_RX_LADDR_MASK)
-#define TEGRA_CEC_HWCTRL_RX_SNOOP (1 << 15)
-#define TEGRA_CEC_HWCTRL_RX_NAK_MODE (1 << 16)
-#define TEGRA_CEC_HWCTRL_TX_NAK_MODE (1 << 24)
-#define TEGRA_CEC_HWCTRL_FAST_SIM_MODE (1 << 30)
-#define TEGRA_CEC_HWCTRL_TX_RX_MODE (1 << 31)
+#define TEGRA_CEC_HWCTRL_RX_SNOOP BIT(15)
+#define TEGRA_CEC_HWCTRL_RX_NAK_MODE BIT(16)
+#define TEGRA_CEC_HWCTRL_TX_NAK_MODE BIT(24)
+#define TEGRA_CEC_HWCTRL_FAST_SIM_MODE BIT(30)
+#define TEGRA_CEC_HWCTRL_TX_RX_MODE BIT(31)
-#define TEGRA_CEC_INPUT_FILTER_MODE (1 << 31)
+#define TEGRA_CEC_INPUT_FILTER_MODE BIT(31)
#define TEGRA_CEC_INPUT_FILTER_FIFO_LENGTH_SHIFT 0
#define TEGRA_CEC_TX_REG_DATA_SHIFT 0
-#define TEGRA_CEC_TX_REG_EOM (1 << 8)
-#define TEGRA_CEC_TX_REG_BCAST (1 << 12)
-#define TEGRA_CEC_TX_REG_START_BIT (1 << 16)
-#define TEGRA_CEC_TX_REG_RETRY (1 << 17)
+#define TEGRA_CEC_TX_REG_EOM BIT(8)
+#define TEGRA_CEC_TX_REG_BCAST BIT(12)
+#define TEGRA_CEC_TX_REG_START_BIT BIT(16)
+#define TEGRA_CEC_TX_REG_RETRY BIT(17)
#define TEGRA_CEC_RX_REGISTER_SHIFT 0
-#define TEGRA_CEC_RX_REGISTER_EOM (1 << 8)
-#define TEGRA_CEC_RX_REGISTER_ACK (1 << 9)
+#define TEGRA_CEC_RX_REGISTER_EOM BIT(8)
+#define TEGRA_CEC_RX_REGISTER_ACK BIT(9)
#define TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT 0
#define TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT 8
@@ -79,38 +79,38 @@
#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT 4
#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT 8
-#define TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY (1 << 0)
-#define TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN (1 << 1)
-#define TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD (1 << 2)
-#define TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED (1 << 3)
-#define TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED (1 << 4)
-#define TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED (1 << 5)
-#define TEGRA_CEC_INT_STAT_RX_REGISTER_FULL (1 << 8)
-#define TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN (1 << 9)
-#define TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED (1 << 10)
-#define TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED (1 << 11)
-#define TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED (1 << 12)
-#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1 << 13)
-#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1 << 14)
-
-#define TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY (1 << 0)
-#define TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN (1 << 1)
-#define TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD (1 << 2)
-#define TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED (1 << 3)
-#define TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED (1 << 4)
-#define TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED (1 << 5)
-#define TEGRA_CEC_INT_MASK_RX_REGISTER_FULL (1 << 8)
-#define TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN (1 << 9)
-#define TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED (1 << 10)
-#define TEGRA_CEC_INT_MASK_RX_BUS_ANOMALY_DETECTED (1 << 11)
-#define TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED (1 << 12)
-#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1 << 13)
-#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1 << 14)
+#define TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY BIT(0)
+#define TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN BIT(1)
+#define TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD BIT(2)
+#define TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED BIT(3)
+#define TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED BIT(4)
+#define TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED BIT(5)
+#define TEGRA_CEC_INT_STAT_RX_REGISTER_FULL BIT(8)
+#define TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN BIT(9)
+#define TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED BIT(10)
+#define TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED BIT(11)
+#define TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED BIT(12)
+#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_H2L BIT(13)
+#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_L2H BIT(14)
+
+#define TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY BIT(0)
+#define TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN BIT(1)
+#define TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD BIT(2)
+#define TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED BIT(3)
+#define TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED BIT(4)
+#define TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED BIT(5)
+#define TEGRA_CEC_INT_MASK_RX_REGISTER_FULL BIT(8)
+#define TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN BIT(9)
+#define TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED BIT(10)
+#define TEGRA_CEC_INT_MASK_RX_BUS_ANOMALY_DETECTED BIT(11)
+#define TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED BIT(12)
+#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_H2L BIT(13)
+#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_L2H BIT(14)
#define TEGRA_CEC_HW_DEBUG_TX_DURATION_COUNT_SHIFT 0
#define TEGRA_CEC_HW_DEBUG_TX_TXBIT_COUNT_SHIFT 17
#define TEGRA_CEC_HW_DEBUG_TX_STATE_SHIFT 21
-#define TEGRA_CEC_HW_DEBUG_TX_FORCELOOUT (1 << 25)
-#define TEGRA_CEC_HW_DEBUG_TX_TXDATABIT_SAMPLE_TIMER (1 << 26)
+#define TEGRA_CEC_HW_DEBUG_TX_FORCELOOUT BIT(25)
+#define TEGRA_CEC_HW_DEBUG_TX_TXDATABIT_SAMPLE_TIMER BIT(26)
#endif /* TEGRA_CEC_H */
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
index 9e86d761546b..be54806180a5 100644
--- a/drivers/media/platform/ti-vpe/cal.c
+++ b/drivers/media/platform/ti-vpe/cal.c
@@ -14,6 +14,8 @@
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include <linux/videodev2.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
@@ -32,8 +34,8 @@
#define CAL_MODULE_NAME "cal"
-#define MAX_WIDTH 1920
-#define MAX_HEIGHT 1200
+#define MAX_WIDTH_BYTES (8192 * 8)
+#define MAX_HEIGHT_LINES 16383
#define CAL_VERSION "0.1.0"
@@ -71,8 +73,6 @@ static const struct v4l2_fract
#define CAL_NUM_INPUT 1
#define CAL_NUM_CONTEXT 2
-#define bytes_per_line(pixel, bpp) (ALIGN(pixel * bpp, 16))
-
#define reg_read(dev, offset) ioread32(dev->base + offset)
#define reg_write(dev, offset, val) iowrite32(val, dev->base + offset)
@@ -91,102 +91,103 @@ static const struct v4l2_fract
struct cal_fmt {
u32 fourcc;
u32 code;
- u8 depth;
+ /* Bits per pixel */
+ u8 bpp;
};
static struct cal_fmt cal_formats[] = {
{
.fourcc = V4L2_PIX_FMT_YUYV,
.code = MEDIA_BUS_FMT_YUYV8_2X8,
- .depth = 16,
+ .bpp = 16,
}, {
.fourcc = V4L2_PIX_FMT_UYVY,
.code = MEDIA_BUS_FMT_UYVY8_2X8,
- .depth = 16,
+ .bpp = 16,
}, {
.fourcc = V4L2_PIX_FMT_YVYU,
.code = MEDIA_BUS_FMT_YVYU8_2X8,
- .depth = 16,
+ .bpp = 16,
}, {
.fourcc = V4L2_PIX_FMT_VYUY,
.code = MEDIA_BUS_FMT_VYUY8_2X8,
- .depth = 16,
+ .bpp = 16,
}, {
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
.code = MEDIA_BUS_FMT_RGB565_2X8_LE,
- .depth = 16,
+ .bpp = 16,
}, {
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
.code = MEDIA_BUS_FMT_RGB565_2X8_BE,
- .depth = 16,
+ .bpp = 16,
}, {
.fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
.code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
- .depth = 16,
+ .bpp = 16,
}, {
.fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
.code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
- .depth = 16,
+ .bpp = 16,
}, {
.fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
.code = MEDIA_BUS_FMT_RGB888_2X12_LE,
- .depth = 24,
+ .bpp = 24,
}, {
.fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
.code = MEDIA_BUS_FMT_RGB888_2X12_BE,
- .depth = 24,
+ .bpp = 24,
}, {
.fourcc = V4L2_PIX_FMT_RGB32, /* argb */
.code = MEDIA_BUS_FMT_ARGB8888_1X32,
- .depth = 32,
+ .bpp = 32,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR8,
.code = MEDIA_BUS_FMT_SBGGR8_1X8,
- .depth = 8,
+ .bpp = 8,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG8,
.code = MEDIA_BUS_FMT_SGBRG8_1X8,
- .depth = 8,
+ .bpp = 8,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG8,
.code = MEDIA_BUS_FMT_SGRBG8_1X8,
- .depth = 8,
+ .bpp = 8,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB8,
.code = MEDIA_BUS_FMT_SRGGB8_1X8,
- .depth = 8,
+ .bpp = 8,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
- .depth = 16,
+ .bpp = 10,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG10,
.code = MEDIA_BUS_FMT_SGBRG10_1X10,
- .depth = 16,
+ .bpp = 10,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG10,
.code = MEDIA_BUS_FMT_SGRBG10_1X10,
- .depth = 16,
+ .bpp = 10,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB10,
.code = MEDIA_BUS_FMT_SRGGB10_1X10,
- .depth = 16,
+ .bpp = 10,
}, {
.fourcc = V4L2_PIX_FMT_SBGGR12,
.code = MEDIA_BUS_FMT_SBGGR12_1X12,
- .depth = 16,
+ .bpp = 12,
}, {
.fourcc = V4L2_PIX_FMT_SGBRG12,
.code = MEDIA_BUS_FMT_SGBRG12_1X12,
- .depth = 16,
+ .bpp = 12,
}, {
.fourcc = V4L2_PIX_FMT_SGRBG12,
.code = MEDIA_BUS_FMT_SGRBG12_1X12,
- .depth = 16,
+ .bpp = 12,
}, {
.fourcc = V4L2_PIX_FMT_SRGGB12,
.code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .depth = 16,
+ .bpp = 12,
},
};
@@ -220,20 +221,118 @@ struct cal_dmaqueue {
int ini_jiffies;
};
-struct cm_data {
+struct cc_data {
void __iomem *base;
struct resource *res;
- unsigned int camerrx_control;
-
struct platform_device *pdev;
};
-struct cc_data {
- void __iomem *base;
- struct resource *res;
+/* CTRL_CORE_CAMERRX_CONTROL register field id */
+enum cal_camerarx_field {
+ F_CTRLCLKEN,
+ F_CAMMODE,
+ F_LANEENABLE,
+ F_CSI_MODE,
- struct platform_device *pdev;
+ F_MAX_FIELDS,
+};
+
+struct cal_csi2_phy {
+ struct regmap_field *fields[F_MAX_FIELDS];
+ struct reg_field *base_fields;
+ const int num_lanes;
+};
+
+struct cal_data {
+ const int num_csi2_phy;
+ struct cal_csi2_phy *csi2_phy_core;
+
+ const unsigned int flags;
+};
+
+static struct reg_field dra72x_ctrl_core_csi0_reg_fields[F_MAX_FIELDS] = {
+ [F_CTRLCLKEN] = REG_FIELD(0, 10, 10),
+ [F_CAMMODE] = REG_FIELD(0, 11, 12),
+ [F_LANEENABLE] = REG_FIELD(0, 13, 16),
+ [F_CSI_MODE] = REG_FIELD(0, 17, 17),
+};
+
+static struct reg_field dra72x_ctrl_core_csi1_reg_fields[F_MAX_FIELDS] = {
+ [F_CTRLCLKEN] = REG_FIELD(0, 0, 0),
+ [F_CAMMODE] = REG_FIELD(0, 1, 2),
+ [F_LANEENABLE] = REG_FIELD(0, 3, 4),
+ [F_CSI_MODE] = REG_FIELD(0, 5, 5),
+};
+
+static struct cal_csi2_phy dra72x_cal_csi_phy[] = {
+ {
+ .base_fields = dra72x_ctrl_core_csi0_reg_fields,
+ .num_lanes = 4,
+ },
+ {
+ .base_fields = dra72x_ctrl_core_csi1_reg_fields,
+ .num_lanes = 2,
+ },
+};
+
+static const struct cal_data dra72x_cal_data = {
+ .csi2_phy_core = dra72x_cal_csi_phy,
+ .num_csi2_phy = ARRAY_SIZE(dra72x_cal_csi_phy),
+};
+
+static const struct cal_data dra72x_es1_cal_data = {
+ .csi2_phy_core = dra72x_cal_csi_phy,
+ .num_csi2_phy = ARRAY_SIZE(dra72x_cal_csi_phy),
+ .flags = DRA72_CAL_PRE_ES2_LDO_DISABLE,
+};
+
+static struct reg_field dra76x_ctrl_core_csi0_reg_fields[F_MAX_FIELDS] = {
+ [F_CTRLCLKEN] = REG_FIELD(0, 8, 8),
+ [F_CAMMODE] = REG_FIELD(0, 9, 10),
+ [F_CSI_MODE] = REG_FIELD(0, 11, 11),
+ [F_LANEENABLE] = REG_FIELD(0, 27, 31),
+};
+
+static struct reg_field dra76x_ctrl_core_csi1_reg_fields[F_MAX_FIELDS] = {
+ [F_CTRLCLKEN] = REG_FIELD(0, 0, 0),
+ [F_CAMMODE] = REG_FIELD(0, 1, 2),
+ [F_CSI_MODE] = REG_FIELD(0, 3, 3),
+ [F_LANEENABLE] = REG_FIELD(0, 24, 26),
+};
+
+static struct cal_csi2_phy dra76x_cal_csi_phy[] = {
+ {
+ .base_fields = dra76x_ctrl_core_csi0_reg_fields,
+ .num_lanes = 5,
+ },
+ {
+ .base_fields = dra76x_ctrl_core_csi1_reg_fields,
+ .num_lanes = 3,
+ },
+};
+
+static const struct cal_data dra76x_cal_data = {
+ .csi2_phy_core = dra76x_cal_csi_phy,
+ .num_csi2_phy = ARRAY_SIZE(dra76x_cal_csi_phy),
+};
+
+static struct reg_field am654_ctrl_core_csi0_reg_fields[F_MAX_FIELDS] = {
+ [F_CTRLCLKEN] = REG_FIELD(0, 15, 15),
+ [F_CAMMODE] = REG_FIELD(0, 24, 25),
+ [F_LANEENABLE] = REG_FIELD(0, 0, 4),
+};
+
+static struct cal_csi2_phy am654_cal_csi_phy[] = {
+ {
+ .base_fields = am654_ctrl_core_csi0_reg_fields,
+ .num_lanes = 5,
+ },
+};
+
+static const struct cal_data am654_cal_data = {
+ .csi2_phy_core = am654_cal_csi_phy,
+ .num_csi2_phy = ARRAY_SIZE(am654_cal_csi_phy),
};
/*
@@ -247,8 +346,15 @@ struct cal_dev {
struct platform_device *pdev;
struct v4l2_device v4l2_dev;
+ /* Controller flags for special cases */
+ unsigned int flags;
+
+ const struct cal_data *data;
+
/* Control Module handle */
- struct cm_data *cm;
+ struct regmap *syscon_camerrx;
+ u32 syscon_camerrx_offset;
+
/* Camera Core Module handle */
struct cc_data *cc[CAL_NUM_CSI2_PORTS];
@@ -359,73 +465,115 @@ static inline void set_field(u32 *valp, u32 field, u32 mask)
*valp = val;
}
-/*
- * Control Module block access
- */
-static struct cm_data *cm_create(struct cal_dev *dev)
+static u32 cal_data_get_phy_max_lanes(struct cal_ctx *ctx)
{
- struct platform_device *pdev = dev->pdev;
- struct cm_data *cm;
+ struct cal_dev *dev = ctx->dev;
+ u32 phy_id = ctx->csi2_port - 1;
- cm = devm_kzalloc(&pdev->dev, sizeof(*cm), GFP_KERNEL);
- if (!cm)
- return ERR_PTR(-ENOMEM);
+ return dev->data->csi2_phy_core[phy_id].num_lanes;
+}
+
+static u32 cal_data_get_num_csi2_phy(struct cal_dev *dev)
+{
+ return dev->data->num_csi2_phy;
+}
+
+static int cal_camerarx_regmap_init(struct cal_dev *dev)
+{
+ struct reg_field *field;
+ struct cal_csi2_phy *phy;
+ int i, j;
+
+ if (!dev->data)
+ return -EINVAL;
+
+ for (i = 0; i < cal_data_get_num_csi2_phy(dev); i++) {
+ phy = &dev->data->csi2_phy_core[i];
+ for (j = 0; j < F_MAX_FIELDS; j++) {
+ field = &phy->base_fields[j];
+ /*
+ * Here we update the reg offset with the
+ * value found in DT
+ */
+ field->reg = dev->syscon_camerrx_offset;
+ phy->fields[j] =
+ devm_regmap_field_alloc(&dev->pdev->dev,
+ dev->syscon_camerrx,
+ *field);
+ if (IS_ERR(phy->fields[j])) {
+ cal_err(dev, "Unable to allocate regmap fields\n");
+ return PTR_ERR(phy->fields[j]);
+ }
+ }
+ }
+ return 0;
+}
+
+static const struct regmap_config cal_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
- cm->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "camerrx_control");
- cm->base = devm_ioremap_resource(&pdev->dev, cm->res);
- if (IS_ERR(cm->base)) {
+static struct regmap *cal_get_camerarx_regmap(struct cal_dev *dev)
+{
+ struct platform_device *pdev = dev->pdev;
+ struct regmap *regmap;
+ void __iomem *base;
+ u32 reg_io_width;
+ struct regmap_config r_config = cal_regmap_config;
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "camerrx_control");
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base)) {
cal_err(dev, "failed to ioremap\n");
- return ERR_CAST(cm->base);
+ return ERR_CAST(base);
}
cal_dbg(1, dev, "ioresource %s at %pa - %pa\n",
- cm->res->name, &cm->res->start, &cm->res->end);
+ res->name, &res->start, &res->end);
- return cm;
+ reg_io_width = 4;
+ r_config.reg_stride = reg_io_width;
+ r_config.val_bits = reg_io_width * 8;
+ r_config.max_register = resource_size(res) - reg_io_width;
+
+ regmap = regmap_init_mmio(NULL, base, &r_config);
+ if (IS_ERR(regmap))
+ pr_err("regmap init failed\n");
+
+ return regmap;
}
+/*
+ * Control Module CAMERARX block access
+ */
static void camerarx_phy_enable(struct cal_ctx *ctx)
{
- u32 val;
-
- if (!ctx->dev->cm->base) {
- ctx_err(ctx, "cm not mapped\n");
- return;
- }
-
- val = reg_read(ctx->dev->cm, CM_CTRL_CORE_CAMERRX_CONTROL);
- if (ctx->csi2_port == 1) {
- set_field(&val, 1, CM_CAMERRX_CTRL_CSI0_CTRLCLKEN_MASK);
- set_field(&val, 0, CM_CAMERRX_CTRL_CSI0_CAMMODE_MASK);
- /* enable all lanes by default */
- set_field(&val, 0xf, CM_CAMERRX_CTRL_CSI0_LANEENABLE_MASK);
- set_field(&val, 1, CM_CAMERRX_CTRL_CSI0_MODE_MASK);
- } else if (ctx->csi2_port == 2) {
- set_field(&val, 1, CM_CAMERRX_CTRL_CSI1_CTRLCLKEN_MASK);
- set_field(&val, 0, CM_CAMERRX_CTRL_CSI1_CAMMODE_MASK);
- /* enable all lanes by default */
- set_field(&val, 0x3, CM_CAMERRX_CTRL_CSI1_LANEENABLE_MASK);
- set_field(&val, 1, CM_CAMERRX_CTRL_CSI1_MODE_MASK);
- }
- reg_write(ctx->dev->cm, CM_CTRL_CORE_CAMERRX_CONTROL, val);
+ struct cal_csi2_phy *phy;
+ u32 phy_id = ctx->csi2_port - 1;
+ u32 max_lanes;
+
+ phy = &ctx->dev->data->csi2_phy_core[phy_id];
+ regmap_field_write(phy->fields[F_CAMMODE], 0);
+ /* Always enable all lanes at the phy control level */
+ max_lanes = (1 << cal_data_get_phy_max_lanes(ctx)) - 1;
+ regmap_field_write(phy->fields[F_LANEENABLE], max_lanes);
+ /* F_CSI_MODE is not present on every architecture */
+ if (phy->fields[F_CSI_MODE])
+ regmap_field_write(phy->fields[F_CSI_MODE], 1);
+ regmap_field_write(phy->fields[F_CTRLCLKEN], 1);
}
static void camerarx_phy_disable(struct cal_ctx *ctx)
{
- u32 val;
-
- if (!ctx->dev->cm->base) {
- ctx_err(ctx, "cm not mapped\n");
- return;
- }
+ struct cal_csi2_phy *phy;
+ u32 phy_id = ctx->csi2_port - 1;
- val = reg_read(ctx->dev->cm, CM_CTRL_CORE_CAMERRX_CONTROL);
- if (ctx->csi2_port == 1)
- set_field(&val, 0x0, CM_CAMERRX_CTRL_CSI0_CTRLCLKEN_MASK);
- else if (ctx->csi2_port == 2)
- set_field(&val, 0x0, CM_CAMERRX_CTRL_CSI1_CTRLCLKEN_MASK);
- reg_write(ctx->dev->cm, CM_CTRL_CORE_CAMERRX_CONTROL, val);
+ phy = &ctx->dev->data->csi2_phy_core[phy_id];
+ regmap_field_write(phy->fields[F_CTRLCLKEN], 0);
}
/*
@@ -474,9 +622,52 @@ static void cal_get_hwinfo(struct cal_dev *dev)
hwinfo);
}
-static inline int cal_runtime_get(struct cal_dev *dev)
+/*
+ * Errata i913: CSI2 LDO Needs to be disabled when module is powered on
+ *
+ * Enabling CSI2 LDO shorts it to core supply. It is crucial the 2 CSI2
+ * LDOs on the device are disabled if CSI-2 module is powered on
+ * (0x4845 B304 | 0x4845 B384 [28:27] = 0x1) or in ULPS (0x4845 B304
+ * | 0x4845 B384 [28:27] = 0x2) mode. Common concerns include: high
+ * current draw on the module supply in active mode.
+ *
+ * Errata does not apply when CSI-2 module is powered off
+ * (0x4845 B304 | 0x4845 B384 [28:27] = 0x0).
+ *
+ * SW Workaround:
+ * Set the following register bits to disable the LDO,
+ * which is essentially CSI2 REG10 bit 6:
+ *
+ * Core 0: 0x4845 B828 = 0x0000 0040
+ * Core 1: 0x4845 B928 = 0x0000 0040
+ */
+static void i913_errata(struct cal_dev *dev, unsigned int port)
+{
+ u32 reg10 = reg_read(dev->cc[port], CAL_CSI2_PHY_REG10);
+
+ set_field(&reg10, CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE,
+ CAL_CSI2_PHY_REG10_I933_LDO_DISABLE_MASK);
+
+ cal_dbg(1, dev, "CSI2_%d_REG10 = 0x%08x\n", port, reg10);
+ reg_write(dev->cc[port], CAL_CSI2_PHY_REG10, reg10);
+}
+
+static int cal_runtime_get(struct cal_dev *dev)
{
- return pm_runtime_get_sync(&dev->pdev->dev);
+ int r;
+
+ r = pm_runtime_get_sync(&dev->pdev->dev);
+
+ if (dev->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) {
+ /*
+ * Apply errata on both port eveytime we (re-)enable
+ * the clock
+ */
+ i913_errata(dev, 0);
+ i913_errata(dev, 1);
+ }
+
+ return r;
}
static inline void cal_runtime_put(struct cal_dev *dev)
@@ -508,12 +699,6 @@ static void cal_quickdump_regs(struct cal_dev *dev)
resource_size(dev->ctx[1]->cc->res),
false);
}
-
- cal_info(dev, "CAMERRX_Control Registers @ %pa:\n",
- &dev->cm->res->start);
- print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
- (__force const void *)dev->cm->base,
- resource_size(dev->cm->res), false);
}
/*
@@ -551,29 +736,76 @@ static void disable_irqs(struct cal_ctx *ctx)
reg_write(ctx->dev, CAL_CSI2_VC_IRQENABLE(1), 0);
}
-static void csi2_init(struct cal_ctx *ctx)
+static void csi2_phy_config(struct cal_ctx *ctx);
+
+static void csi2_phy_init(struct cal_ctx *ctx)
{
int i;
u32 val;
+ /* Steps
+ * 1. Configure D-PHY mode and enable required lanes
+ * 2. Reset complex IO - Wait for completion of reset
+ * Note if the external sensor is not sending byte clock,
+ * the reset will timeout
+ * 3 Program Stop States
+ * A. Program THS_TERM, THS_SETTLE, etc... Timings parameters
+ * in terms of DDR clock periods
+ * B. Enable stop state transition timeouts
+ * 4.Force FORCERXMODE
+ * D. Enable pull down using pad control
+ * E. Power up PHY
+ * F. Wait for power up completion
+ * G. Wait for all enabled lane to reach stop state
+ * H. Disable pull down using pad control
+ */
+
+ /* 1. Configure D-PHY mode and enable required lanes */
+ camerarx_phy_enable(ctx);
+
+ /* 2. Reset complex IO - Do not wait for reset completion */
+ val = reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port));
+ set_field(&val, CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL,
+ CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK);
+ reg_write(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), val);
+ ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x De-assert Complex IO Reset\n",
+ ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port)));
+
+ /* Dummy read to allow SCP to complete */
+ val = reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port));
+
+ /* 3.A. Program Phy Timing Parameters */
+ csi2_phy_config(ctx);
+
+ /* 3.B. Program Stop States */
val = reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port));
set_field(&val, CAL_GEN_ENABLE,
- CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK);
- set_field(&val, CAL_GEN_ENABLE,
CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK);
set_field(&val, CAL_GEN_DISABLE,
CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK);
set_field(&val, 407, CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK);
reg_write(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port), val);
- ctx_dbg(3, ctx, "CAL_CSI2_TIMING(%d) = 0x%08x\n", ctx->csi2_port,
+ ctx_dbg(3, ctx, "CAL_CSI2_TIMING(%d) = 0x%08x Stop States\n",
+ ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port)));
+
+ /* 4. Force FORCERXMODE */
+ val = reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port));
+ set_field(&val, CAL_GEN_ENABLE,
+ CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK);
+ reg_write(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port), val);
+ ctx_dbg(3, ctx, "CAL_CSI2_TIMING(%d) = 0x%08x Force RXMODE\n",
+ ctx->csi2_port,
reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port)));
+ /* E. Power up the PHY using the complex IO */
val = reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port));
- set_field(&val, CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL,
- CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK);
set_field(&val, CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON,
CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK);
reg_write(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), val);
+
+ /* F. Wait for power up completion */
for (i = 0; i < 10; i++) {
if (reg_read_field(ctx->dev,
CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port),
@@ -582,18 +814,104 @@ static void csi2_init(struct cal_ctx *ctx)
break;
usleep_range(1000, 1100);
}
- ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x\n", ctx->csi2_port,
- reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port)));
+ ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Powered UP %s\n",
+ ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port)),
+ (i >= 10) ? "(timeout)" : "");
+}
- val = reg_read(ctx->dev, CAL_CTRL);
- set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, CAL_CTRL_BURSTSIZE_MASK);
- set_field(&val, 0xF, CAL_CTRL_TAGCNT_MASK);
- set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED,
- CAL_CTRL_POSTED_WRITES_MASK);
- set_field(&val, 0xFF, CAL_CTRL_MFLAGL_MASK);
- set_field(&val, 0xFF, CAL_CTRL_MFLAGH_MASK);
- reg_write(ctx->dev, CAL_CTRL, val);
- ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", reg_read(ctx->dev, CAL_CTRL));
+static void csi2_wait_for_phy(struct cal_ctx *ctx)
+{
+ int i;
+
+ /* Steps
+ * 2. Wait for completion of reset
+ * Note if the external sensor is not sending byte clock,
+ * the reset will timeout
+ * 4.Force FORCERXMODE
+ * G. Wait for all enabled lane to reach stop state
+ * H. Disable pull down using pad control
+ */
+
+ /* 2. Wait for reset completion */
+ for (i = 0; i < 250; i++) {
+ if (reg_read_field(ctx->dev,
+ CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port),
+ CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) ==
+ CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED)
+ break;
+ usleep_range(1000, 1100);
+ }
+ ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO Reset Done (%d) %s\n",
+ ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port)), i,
+ (i >= 250) ? "(timeout)" : "");
+
+ /* 4. G. Wait for all enabled lane to reach stop state */
+ for (i = 0; i < 10; i++) {
+ if (reg_read_field(ctx->dev,
+ CAL_CSI2_TIMING(ctx->csi2_port),
+ CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) ==
+ CAL_GEN_DISABLE)
+ break;
+ usleep_range(1000, 1100);
+ }
+ ctx_dbg(3, ctx, "CAL_CSI2_TIMING(%d) = 0x%08x Stop State Reached %s\n",
+ ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_TIMING(ctx->csi2_port)),
+ (i >= 10) ? "(timeout)" : "");
+
+ ctx_dbg(1, ctx, "CSI2_%d_REG1 = 0x%08x (Bit(31,28) should be set!)\n",
+ (ctx->csi2_port - 1), reg_read(ctx->cc, CAL_CSI2_PHY_REG1));
+}
+
+static void csi2_phy_deinit(struct cal_ctx *ctx)
+{
+ int i;
+ u32 val;
+
+ /* Power down the PHY using the complex IO */
+ val = reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port));
+ set_field(&val, CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF,
+ CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK);
+ reg_write(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), val);
+
+ /* Wait for power down completion */
+ for (i = 0; i < 10; i++) {
+ if (reg_read_field(ctx->dev,
+ CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port),
+ CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK) ==
+ CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_OFF)
+ break;
+ usleep_range(1000, 1100);
+ }
+ ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Powered Down %s\n",
+ ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port)),
+ (i >= 10) ? "(timeout)" : "");
+
+ /* Assert Comple IO Reset */
+ val = reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port));
+ set_field(&val, CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL,
+ CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK);
+ reg_write(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port), val);
+
+ /* Wait for power down completion */
+ for (i = 0; i < 10; i++) {
+ if (reg_read_field(ctx->dev,
+ CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port),
+ CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) ==
+ CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING)
+ break;
+ usleep_range(1000, 1100);
+ }
+ ctx_dbg(3, ctx, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset (%d) %s\n",
+ ctx->csi2_port,
+ reg_read(ctx->dev, CAL_CSI2_COMPLEXIO_CFG(ctx->csi2_port)), i,
+ (i >= 10) ? "(timeout)" : "");
+
+ /* Disable the phy */
+ camerarx_phy_disable(ctx);
}
static void csi2_lane_config(struct cal_ctx *ctx)
@@ -665,13 +983,48 @@ static void csi2_ctx_config(struct cal_ctx *ctx)
static void pix_proc_config(struct cal_ctx *ctx)
{
- u32 val;
+ u32 val, extract, pack;
+
+ switch (ctx->fmt->bpp) {
+ case 8:
+ extract = CAL_PIX_PROC_EXTRACT_B8;
+ pack = CAL_PIX_PROC_PACK_B8;
+ break;
+ case 10:
+ extract = CAL_PIX_PROC_EXTRACT_B10_MIPI;
+ pack = CAL_PIX_PROC_PACK_B16;
+ break;
+ case 12:
+ extract = CAL_PIX_PROC_EXTRACT_B12_MIPI;
+ pack = CAL_PIX_PROC_PACK_B16;
+ break;
+ case 16:
+ extract = CAL_PIX_PROC_EXTRACT_B16_LE;
+ pack = CAL_PIX_PROC_PACK_B16;
+ break;
+ default:
+ /*
+ * If you see this warning then it means that you added
+ * some new entry in the cal_formats[] array with a different
+ * bit per pixel values then the one supported below.
+ * Either add support for the new bpp value below or adjust
+ * the new entry to use one of the value below.
+ *
+ * Instead of failing here just use 8 bpp as a default.
+ */
+ dev_warn_once(&ctx->dev->pdev->dev,
+ "%s:%d:%s: bpp:%d unsupported! Overwritten with 8.\n",
+ __FILE__, __LINE__, __func__, ctx->fmt->bpp);
+ extract = CAL_PIX_PROC_EXTRACT_B8;
+ pack = CAL_PIX_PROC_PACK_B8;
+ break;
+ }
val = reg_read(ctx->dev, CAL_PIX_PROC(ctx->csi2_port));
- set_field(&val, CAL_PIX_PROC_EXTRACT_B8, CAL_PIX_PROC_EXTRACT_MASK);
+ set_field(&val, extract, CAL_PIX_PROC_EXTRACT_MASK);
set_field(&val, CAL_PIX_PROC_DPCMD_BYPASS, CAL_PIX_PROC_DPCMD_MASK);
set_field(&val, CAL_PIX_PROC_DPCME_BYPASS, CAL_PIX_PROC_DPCME_MASK);
- set_field(&val, CAL_PIX_PROC_PACK_B8, CAL_PIX_PROC_PACK_MASK);
+ set_field(&val, pack, CAL_PIX_PROC_PACK_MASK);
set_field(&val, ctx->csi2_port, CAL_PIX_PROC_CPORT_MASK);
set_field(&val, CAL_GEN_ENABLE, CAL_PIX_PROC_EN_MASK);
reg_write(ctx->dev, CAL_PIX_PROC(ctx->csi2_port), val);
@@ -680,12 +1033,13 @@ static void pix_proc_config(struct cal_ctx *ctx)
}
static void cal_wr_dma_config(struct cal_ctx *ctx,
- unsigned int width)
+ unsigned int width, unsigned int height)
{
u32 val;
val = reg_read(ctx->dev, CAL_WR_DMA_CTRL(ctx->csi2_port));
set_field(&val, ctx->csi2_port, CAL_WR_DMA_CTRL_CPORT_MASK);
+ set_field(&val, height, CAL_WR_DMA_CTRL_YSIZE_MASK);
set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT,
CAL_WR_DMA_CTRL_DTAG_MASK);
set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST,
@@ -720,6 +1074,16 @@ static void cal_wr_dma_config(struct cal_ctx *ctx,
reg_write(ctx->dev, CAL_WR_DMA_XSIZE(ctx->csi2_port), val);
ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->csi2_port,
reg_read(ctx->dev, CAL_WR_DMA_XSIZE(ctx->csi2_port)));
+
+ val = reg_read(ctx->dev, CAL_CTRL);
+ set_field(&val, CAL_CTRL_BURSTSIZE_BURST128, CAL_CTRL_BURSTSIZE_MASK);
+ set_field(&val, 0xF, CAL_CTRL_TAGCNT_MASK);
+ set_field(&val, CAL_CTRL_POSTED_WRITES_NONPOSTED,
+ CAL_CTRL_POSTED_WRITES_MASK);
+ set_field(&val, 0xFF, CAL_CTRL_MFLAGL_MASK);
+ set_field(&val, 0xFF, CAL_CTRL_MFLAGH_MASK);
+ reg_write(ctx->dev, CAL_CTRL, val);
+ ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", reg_read(ctx->dev, CAL_CTRL));
}
static void cal_wr_dma_addr(struct cal_ctx *ctx, unsigned int dmaaddr)
@@ -733,41 +1097,28 @@ static void cal_wr_dma_addr(struct cal_ctx *ctx, unsigned int dmaaddr)
#define TCLK_TERM 0
#define TCLK_MISS 1
#define TCLK_SETTLE 14
-#define THS_SETTLE 15
static void csi2_phy_config(struct cal_ctx *ctx)
{
unsigned int reg0, reg1;
unsigned int ths_term, ths_settle;
- unsigned int ddrclkperiod_us;
+ unsigned int csi2_ddrclk_khz;
+ struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 =
+ &ctx->endpoint.bus.mipi_csi2;
+ u32 num_lanes = mipi_csi2->num_data_lanes;
- /*
- * THS_TERM: Programmed value = floor(20 ns/DDRClk period) - 2.
- */
- ddrclkperiod_us = ctx->external_rate / 2000000;
- ddrclkperiod_us = 1000000 / ddrclkperiod_us;
- ctx_dbg(1, ctx, "ddrclkperiod_us: %d\n", ddrclkperiod_us);
+ /* DPHY timing configuration */
+ /* CSI-2 is DDR and we only count used lanes. */
+ csi2_ddrclk_khz = ctx->external_rate / 1000
+ / (2 * num_lanes) * ctx->fmt->bpp;
+ ctx_dbg(1, ctx, "csi2_ddrclk_khz: %d\n", csi2_ddrclk_khz);
- ths_term = 20000 / ddrclkperiod_us;
- ths_term = (ths_term >= 2) ? ths_term - 2 : ths_term;
+ /* THS_TERM: Programmed value = floor(20 ns/DDRClk period) */
+ ths_term = 20 * csi2_ddrclk_khz / 1000000;
ctx_dbg(1, ctx, "ths_term: %d (0x%02x)\n", ths_term, ths_term);
- /*
- * THS_SETTLE: Programmed value = floor(176.3 ns/CtrlClk period) - 1.
- * Since CtrlClk is fixed at 96Mhz then we get
- * ths_settle = floor(176.3 / 10.416) - 1 = 15
- * If we ever switch to a dynamic clock then this code might be useful
- *
- * unsigned int ctrlclkperiod_us;
- * ctrlclkperiod_us = 96000000 / 1000000;
- * ctrlclkperiod_us = 1000000 / ctrlclkperiod_us;
- * ctx_dbg(1, ctx, "ctrlclkperiod_us: %d\n", ctrlclkperiod_us);
-
- * ths_settle = 176300 / ctrlclkperiod_us;
- * ths_settle = (ths_settle > 1) ? ths_settle - 1 : ths_settle;
- */
-
- ths_settle = THS_SETTLE;
+ /* THS_SETTLE: Programmed value = floor(105 ns/DDRClk period) + 4 */
+ ths_settle = (105 * csi2_ddrclk_khz / 1000000) + 4;
ctx_dbg(1, ctx, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle);
reg0 = reg_read(ctx->cc, CAL_CSI2_PHY_REG0);
@@ -913,9 +1264,6 @@ static int cal_querycap(struct file *file, void *priv,
snprintf(cap->bus_info, sizeof(cap->bus_info),
"platform:%s", ctx->v4l2_dev.name);
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -982,15 +1330,25 @@ static int cal_calc_format_size(struct cal_ctx *ctx,
const struct cal_fmt *fmt,
struct v4l2_format *f)
{
+ u32 bpl, max_width;
+
if (!fmt) {
ctx_dbg(3, ctx, "No cal_fmt provided!\n");
return -EINVAL;
}
- v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
- &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
- f->fmt.pix.bytesperline = bytes_per_line(f->fmt.pix.width,
- fmt->depth >> 3);
+ /*
+ * Maximum width is bound by the DMA max width in bytes.
+ * We need to recalculate the actual maxi width depending on the
+ * number of bytes per pixels required.
+ */
+ max_width = MAX_WIDTH_BYTES / (ALIGN(fmt->bpp, 8) >> 3);
+ v4l_bound_align_image(&f->fmt.pix.width, 48, max_width, 2,
+ &f->fmt.pix.height, 32, MAX_HEIGHT_LINES, 0, 0);
+
+ bpl = (f->fmt.pix.width * ALIGN(fmt->bpp, 8)) >> 3;
+ f->fmt.pix.bytesperline = ALIGN(bpl, 16);
+
f->fmt.pix.sizeimage = f->fmt.pix.height *
f->fmt.pix.bytesperline;
@@ -1135,6 +1493,7 @@ static int cal_enum_framesizes(struct file *file, void *fh,
fse.index = fsize->index;
fse.pad = 0;
fse.code = fmt->code;
+ fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(ctx->sensor, pad, enum_frame_size, NULL, &fse);
if (ret)
@@ -1302,36 +1661,50 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
if (ret < 0)
goto err;
+ ret = v4l2_subdev_call(ctx->sensor, core, s_power, 1);
+ if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) {
+ ctx_err(ctx, "power on failed in subdev\n");
+ goto err;
+ }
+
cal_runtime_get(ctx->dev);
- enable_irqs(ctx);
- camerarx_phy_enable(ctx);
- csi2_init(ctx);
- csi2_phy_config(ctx);
- csi2_lane_config(ctx);
csi2_ctx_config(ctx);
pix_proc_config(ctx);
- cal_wr_dma_config(ctx, ctx->v_fmt.fmt.pix.bytesperline);
- cal_wr_dma_addr(ctx, addr);
- csi2_ppi_enable(ctx);
+ cal_wr_dma_config(ctx, ctx->v_fmt.fmt.pix.bytesperline,
+ ctx->v_fmt.fmt.pix.height);
+ csi2_lane_config(ctx);
+
+ enable_irqs(ctx);
+ csi2_phy_init(ctx);
ret = v4l2_subdev_call(ctx->sensor, video, s_stream, 1);
if (ret) {
+ v4l2_subdev_call(ctx->sensor, core, s_power, 0);
ctx_err(ctx, "stream on failed in subdev\n");
cal_runtime_put(ctx->dev);
goto err;
}
+ csi2_wait_for_phy(ctx);
+ cal_wr_dma_addr(ctx, addr);
+ csi2_ppi_enable(ctx);
+
if (debug >= 4)
cal_quickdump_regs(ctx->dev);
return 0;
err:
+ spin_lock_irqsave(&ctx->slock, flags);
+ vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
+ ctx->cur_frm = NULL;
+ ctx->next_frm = NULL;
list_for_each_entry_safe(buf, tmp, &dma_q->active, list) {
list_del(&buf->list);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
}
+ spin_unlock_irqrestore(&ctx->slock, flags);
return ret;
}
@@ -1341,12 +1714,18 @@ static void cal_stop_streaming(struct vb2_queue *vq)
struct cal_dmaqueue *dma_q = &ctx->vidq;
struct cal_buffer *buf, *tmp;
unsigned long flags;
+ int ret;
+
+ csi2_ppi_disable(ctx);
+ disable_irqs(ctx);
+ csi2_phy_deinit(ctx);
if (v4l2_subdev_call(ctx->sensor, video, s_stream, 0))
ctx_err(ctx, "stream off failed in subdev\n");
- csi2_ppi_disable(ctx);
- disable_irqs(ctx);
+ ret = v4l2_subdev_call(ctx->sensor, core, s_power, 0);
+ if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ ctx_err(ctx, "power off failed in subdev\n");
/* Release all active buffers */
spin_lock_irqsave(&ctx->slock, flags);
@@ -1402,6 +1781,7 @@ static const struct v4l2_ioctl_ops cal_ioctl_ops = {
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_enum_input = cal_enum_input,
.vidioc_g_input = cal_g_input,
.vidioc_s_input = cal_s_input,
@@ -1419,6 +1799,8 @@ static const struct video_device cal_videodev = {
.ioctl_ops = &cal_ioctl_ops,
.minor = -1,
.release = video_device_release_empty,
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE,
};
/* -----------------------------------------------------------------
@@ -1452,6 +1834,7 @@ static int cal_async_bound(struct v4l2_async_notifier *notifier,
memset(&mbus_code, 0, sizeof(mbus_code));
mbus_code.index = j;
+ mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
ret = v4l2_subdev_call(subdev, pad, enum_mbus_code,
NULL, &mbus_code);
if (ret)
@@ -1613,6 +1996,7 @@ of_get_next_port(const struct device_node *parent,
}
prev = port;
} while (!of_node_name_eq(port, "port"));
+ of_node_put(ports);
}
return port;
@@ -1804,10 +2188,15 @@ err_exit:
return NULL;
}
+static const struct of_device_id cal_of_match[];
+
static int cal_probe(struct platform_device *pdev)
{
struct cal_dev *dev;
struct cal_ctx *ctx;
+ struct device_node *parent = pdev->dev.of_node;
+ struct regmap *syscon_camerrx = NULL;
+ u32 syscon_camerrx_offset = 0;
int ret;
int irq;
int i;
@@ -1816,6 +2205,14 @@ static int cal_probe(struct platform_device *pdev)
if (!dev)
return -ENOMEM;
+ dev->data = of_device_get_match_data(&pdev->dev);
+ if (!dev->data) {
+ dev_err(&pdev->dev, "Could not get feature data based on compatible version\n");
+ return -ENODEV;
+ }
+
+ dev->flags = dev->data->flags;
+
/* set pseudo v4l2 device name so we can use v4l2_printk */
strscpy(dev->v4l2_dev.name, CAL_MODULE_NAME,
sizeof(dev->v4l2_dev.name));
@@ -1823,6 +2220,38 @@ static int cal_probe(struct platform_device *pdev)
/* save pdev pointer */
dev->pdev = pdev;
+ syscon_camerrx = syscon_regmap_lookup_by_phandle(parent,
+ "ti,camerrx-control");
+ ret = of_property_read_u32_index(parent, "ti,camerrx-control", 1,
+ &syscon_camerrx_offset);
+ if (IS_ERR(syscon_camerrx))
+ ret = PTR_ERR(syscon_camerrx);
+ if (ret) {
+ dev_warn(&pdev->dev, "failed to get ti,camerrx-control: %d\n",
+ ret);
+
+ /*
+ * Backward DTS compatibility.
+ * If syscon entry is not present then check if the
+ * camerrx_control resource is present.
+ */
+ syscon_camerrx = cal_get_camerarx_regmap(dev);
+ if (IS_ERR(syscon_camerrx)) {
+ dev_err(&pdev->dev, "failed to get camerrx_control regmap\n");
+ return PTR_ERR(syscon_camerrx);
+ }
+ /* In this case the base already point to the direct
+ * CM register so no need for an offset
+ */
+ syscon_camerrx_offset = 0;
+ }
+
+ dev->syscon_camerrx = syscon_camerrx;
+ dev->syscon_camerrx_offset = syscon_camerrx_offset;
+ ret = cal_camerarx_regmap_init(dev);
+ if (ret)
+ return ret;
+
dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"cal_top");
dev->base = devm_ioremap_resource(&pdev->dev, dev->res);
@@ -1841,23 +2270,24 @@ static int cal_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dev);
- dev->cm = cm_create(dev);
- if (IS_ERR(dev->cm))
- return PTR_ERR(dev->cm);
-
dev->cc[0] = cc_create(dev, 0);
if (IS_ERR(dev->cc[0]))
return PTR_ERR(dev->cc[0]);
- dev->cc[1] = cc_create(dev, 1);
- if (IS_ERR(dev->cc[1]))
- return PTR_ERR(dev->cc[1]);
+ if (cal_data_get_num_csi2_phy(dev) > 1) {
+ dev->cc[1] = cc_create(dev, 1);
+ if (IS_ERR(dev->cc[1]))
+ return PTR_ERR(dev->cc[1]);
+ } else {
+ dev->cc[1] = NULL;
+ }
dev->ctx[0] = NULL;
dev->ctx[1] = NULL;
dev->ctx[0] = cal_create_instance(dev, 0);
- dev->ctx[1] = cal_create_instance(dev, 1);
+ if (cal_data_get_num_csi2_phy(dev) > 1)
+ dev->ctx[1] = cal_create_instance(dev, 1);
if (!dev->ctx[0] && !dev->ctx[1]) {
cal_err(dev, "Neither port is configured, no point in staying up\n");
return -ENODEV;
@@ -1924,7 +2354,22 @@ static int cal_remove(struct platform_device *pdev)
#if defined(CONFIG_OF)
static const struct of_device_id cal_of_match[] = {
- { .compatible = "ti,dra72-cal", },
+ {
+ .compatible = "ti,dra72-cal",
+ .data = (void *)&dra72x_cal_data,
+ },
+ {
+ .compatible = "ti,dra72-pre-es2-cal",
+ .data = (void *)&dra72x_es1_cal_data,
+ },
+ {
+ .compatible = "ti,dra76-cal",
+ .data = (void *)&dra76x_cal_data,
+ },
+ {
+ .compatible = "ti,am654-cal",
+ .data = (void *)&am654_cal_data,
+ },
{},
};
MODULE_DEVICE_TABLE(of, cal_of_match);
diff --git a/drivers/media/platform/ti-vpe/cal_regs.h b/drivers/media/platform/ti-vpe/cal_regs.h
index 68cfc922b422..0b76d1186074 100644
--- a/drivers/media/platform/ti-vpe/cal_regs.h
+++ b/drivers/media/platform/ti-vpe/cal_regs.h
@@ -10,6 +10,30 @@
#ifndef __TI_CAL_REGS_H
#define __TI_CAL_REGS_H
+/*
+ * struct cal_dev.flags possibilities
+ *
+ * DRA72_CAL_PRE_ES2_LDO_DISABLE:
+ * Errata i913: CSI2 LDO Needs to be disabled when module is powered on
+ *
+ * Enabling CSI2 LDO shorts it to core supply. It is crucial the 2 CSI2
+ * LDOs on the device are disabled if CSI-2 module is powered on
+ * (0x4845 B304 | 0x4845 B384 [28:27] = 0x1) or in ULPS (0x4845 B304
+ * | 0x4845 B384 [28:27] = 0x2) mode. Common concerns include: high
+ * current draw on the module supply in active mode.
+ *
+ * Errata does not apply when CSI-2 module is powered off
+ * (0x4845 B304 | 0x4845 B384 [28:27] = 0x0).
+ *
+ * SW Workaround:
+ * Set the following register bits to disable the LDO,
+ * which is essentially CSI2 REG10 bit 6:
+ *
+ * Core 0: 0x4845 B828 = 0x0000 0040
+ * Core 1: 0x4845 B928 = 0x0000 0040
+ */
+#define DRA72_CAL_PRE_ES2_LDO_DISABLE BIT(0)
+
#define CAL_NUM_CSI2_PORTS 2
/* CAL register offsets */
@@ -71,6 +95,7 @@
#define CAL_CSI2_PHY_REG0 0x000
#define CAL_CSI2_PHY_REG1 0x004
#define CAL_CSI2_PHY_REG2 0x008
+#define CAL_CSI2_PHY_REG10 0x028
/* CAL Control Module Core Camerrx Control register offsets */
#define CM_CTRL_CORE_CAMERRX_CONTROL 0x000
@@ -110,7 +135,7 @@
#define CAL_HL_HWINFO_NPPI_CONTEXTS_EIGHT 2
#define CAL_HL_HWINFO_NPPI_CONTEXTS_RESERVED 3
-#define CAL_HL_SYSCONFIG_SOFTRESET_MASK BIT_MASK(0)
+#define CAL_HL_SYSCONFIG_SOFTRESET_MASK BIT(0)
#define CAL_HL_SYSCONFIG_SOFTRESET_DONE 0x0
#define CAL_HL_SYSCONFIG_SOFTRESET_PENDING 0x1
#define CAL_HL_SYSCONFIG_SOFTRESET_NOACTION 0x0
@@ -121,11 +146,11 @@
#define CAL_HL_SYSCONFIG_IDLEMODE_SMART1 2
#define CAL_HL_SYSCONFIG_IDLEMODE_SMART2 3
-#define CAL_HL_IRQ_EOI_LINE_NUMBER_MASK BIT_MASK(0)
+#define CAL_HL_IRQ_EOI_LINE_NUMBER_MASK BIT(0)
#define CAL_HL_IRQ_EOI_LINE_NUMBER_READ0 0
#define CAL_HL_IRQ_EOI_LINE_NUMBER_EOI0 0
-#define CAL_HL_IRQ_MASK(m) BIT_MASK(m-1)
+#define CAL_HL_IRQ_MASK(m) BIT((m) - 1)
#define CAL_HL_IRQ_NOACTION 0x0
#define CAL_HL_IRQ_ENABLE 0x1
#define CAL_HL_IRQ_CLEAR 0x1
@@ -133,7 +158,7 @@
#define CAL_HL_IRQ_ENABLED 0x1
#define CAL_HL_IRQ_PENDING 0x1
-#define CAL_PIX_PROC_EN_MASK BIT_MASK(0)
+#define CAL_PIX_PROC_EN_MASK BIT(0)
#define CAL_PIX_PROC_EXTRACT_MASK GENMASK(4, 1)
#define CAL_PIX_PROC_EXTRACT_B6 0x0
#define CAL_PIX_PROC_EXTRACT_B7 0x1
@@ -179,7 +204,7 @@
#define CAL_PIX_PROC_PACK_ARGB 0x6
#define CAL_PIX_PROC_CPORT_MASK GENMASK(23, 19)
-#define CAL_CTRL_POSTED_WRITES_MASK BIT_MASK(0)
+#define CAL_CTRL_POSTED_WRITES_MASK BIT(0)
#define CAL_CTRL_POSTED_WRITES_NONPOSTED 0
#define CAL_CTRL_POSTED_WRITES 1
#define CAL_CTRL_TAGCNT_MASK GENMASK(4, 1)
@@ -190,10 +215,10 @@
#define CAL_CTRL_BURSTSIZE_BURST128 0x3
#define CAL_CTRL_LL_FORCE_STATE_MASK GENMASK(12, 7)
#define CAL_CTRL_MFLAGL_MASK GENMASK(20, 13)
-#define CAL_CTRL_PWRSCPCLK_MASK BIT_MASK(21)
+#define CAL_CTRL_PWRSCPCLK_MASK BIT(21)
#define CAL_CTRL_PWRSCPCLK_AUTO 0
#define CAL_CTRL_PWRSCPCLK_FORCE 1
-#define CAL_CTRL_RD_DMA_STALL_MASK BIT_MASK(22)
+#define CAL_CTRL_RD_DMA_STALL_MASK BIT(22)
#define CAL_CTRL_MFLAGH_MASK GENMASK(31, 24)
#define CAL_CTRL1_PPI_GROUPING_MASK GENMASK(1, 0)
@@ -218,18 +243,18 @@
#define CAL_VPORT_CTRL1_PCLK_MASK GENMASK(16, 0)
#define CAL_VPORT_CTRL1_XBLK_MASK GENMASK(24, 17)
#define CAL_VPORT_CTRL1_YBLK_MASK GENMASK(30, 25)
-#define CAL_VPORT_CTRL1_WIDTH_MASK BIT_MASK(31)
+#define CAL_VPORT_CTRL1_WIDTH_MASK BIT(31)
#define CAL_VPORT_CTRL1_WIDTH_ONE 0
#define CAL_VPORT_CTRL1_WIDTH_TWO 1
#define CAL_VPORT_CTRL2_CPORT_MASK GENMASK(4, 0)
-#define CAL_VPORT_CTRL2_FREERUNNING_MASK BIT_MASK(15)
+#define CAL_VPORT_CTRL2_FREERUNNING_MASK BIT(15)
#define CAL_VPORT_CTRL2_FREERUNNING_GATED 0
#define CAL_VPORT_CTRL2_FREERUNNING_FREE 1
-#define CAL_VPORT_CTRL2_FS_RESETS_MASK BIT_MASK(16)
+#define CAL_VPORT_CTRL2_FS_RESETS_MASK BIT(16)
#define CAL_VPORT_CTRL2_FS_RESETS_NO 0
#define CAL_VPORT_CTRL2_FS_RESETS_YES 1
-#define CAL_VPORT_CTRL2_FSM_RESET_MASK BIT_MASK(17)
+#define CAL_VPORT_CTRL2_FSM_RESET_MASK BIT(17)
#define CAL_VPORT_CTRL2_FSM_RESET_NOEFFECT 0
#define CAL_VPORT_CTRL2_FSM_RESET 1
#define CAL_VPORT_CTRL2_RDY_THR_MASK GENMASK(31, 18)
@@ -237,23 +262,23 @@
#define CAL_BYS_CTRL1_PCLK_MASK GENMASK(16, 0)
#define CAL_BYS_CTRL1_XBLK_MASK GENMASK(24, 17)
#define CAL_BYS_CTRL1_YBLK_MASK GENMASK(30, 25)
-#define CAL_BYS_CTRL1_BYSINEN_MASK BIT_MASK(31)
+#define CAL_BYS_CTRL1_BYSINEN_MASK BIT(31)
#define CAL_BYS_CTRL2_CPORTIN_MASK GENMASK(4, 0)
#define CAL_BYS_CTRL2_CPORTOUT_MASK GENMASK(9, 5)
-#define CAL_BYS_CTRL2_DUPLICATEDDATA_MASK BIT_MASK(10)
+#define CAL_BYS_CTRL2_DUPLICATEDDATA_MASK BIT(10)
#define CAL_BYS_CTRL2_DUPLICATEDDATA_NO 0
#define CAL_BYS_CTRL2_DUPLICATEDDATA_YES 1
-#define CAL_BYS_CTRL2_FREERUNNING_MASK BIT_MASK(11)
+#define CAL_BYS_CTRL2_FREERUNNING_MASK BIT(11)
#define CAL_BYS_CTRL2_FREERUNNING_NO 0
#define CAL_BYS_CTRL2_FREERUNNING_YES 1
-#define CAL_RD_DMA_CTRL_GO_MASK BIT_MASK(0)
+#define CAL_RD_DMA_CTRL_GO_MASK BIT(0)
#define CAL_RD_DMA_CTRL_GO_DIS 0
#define CAL_RD_DMA_CTRL_GO_EN 1
#define CAL_RD_DMA_CTRL_GO_IDLE 0
#define CAL_RD_DMA_CTRL_GO_BUSY 1
-#define CAL_RD_DMA_CTRL_INIT_MASK BIT_MASK(1)
+#define CAL_RD_DMA_CTRL_INIT_MASK BIT(1)
#define CAL_RD_DMA_CTRL_BW_LIMITER_MASK GENMASK(10, 2)
#define CAL_RD_DMA_CTRL_OCP_TAG_CNT_MASK GENMASK(14, 11)
#define CAL_RD_DMA_CTRL_PCLK_MASK GENMASK(31, 15)
@@ -277,13 +302,13 @@
#define CAL_RD_DMA_CTRL2_CIRC_MODE_SIXTEEN 3
#define CAL_RD_DMA_CTRL2_CIRC_MODE_SIXTYFOUR 4
#define CAL_RD_DMA_CTRL2_CIRC_MODE_RESERVED 5
-#define CAL_RD_DMA_CTRL2_ICM_CSTART_MASK BIT_MASK(3)
+#define CAL_RD_DMA_CTRL2_ICM_CSTART_MASK BIT(3)
#define CAL_RD_DMA_CTRL2_PATTERN_MASK GENMASK(5, 4)
#define CAL_RD_DMA_CTRL2_PATTERN_LINEAR 0
#define CAL_RD_DMA_CTRL2_PATTERN_YUV420 1
#define CAL_RD_DMA_CTRL2_PATTERN_RD2SKIP2 2
#define CAL_RD_DMA_CTRL2_PATTERN_RD2SKIP4 3
-#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_MASK BIT_MASK(6)
+#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_MASK BIT(6)
#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_FREERUNNING 0
#define CAL_RD_DMA_CTRL2_BYSOUT_LE_WAIT_WAITFORBYSOUT 1
#define CAL_RD_DMA_CTRL2_CIRC_SIZE_MASK GENMASK(29, 16)
@@ -300,7 +325,7 @@
#define CAL_WR_DMA_CTRL_PATTERN_WR2SKIP2 2
#define CAL_WR_DMA_CTRL_PATTERN_WR2SKIP4 3
#define CAL_WR_DMA_CTRL_PATTERN_RESERVED 1
-#define CAL_WR_DMA_CTRL_ICM_PSTART_MASK BIT_MASK(5)
+#define CAL_WR_DMA_CTRL_ICM_PSTART_MASK BIT(5)
#define CAL_WR_DMA_CTRL_DTAG_MASK GENMASK(8, 6)
#define CAL_WR_DMA_CTRL_DTAG_ATT_HDR 0
#define CAL_WR_DMA_CTRL_DTAG_ATT_DAT 1
@@ -311,7 +336,7 @@
#define CAL_WR_DMA_CTRL_DTAG_D6 6
#define CAL_WR_DMA_CTRL_DTAG_D7 7
#define CAL_WR_DMA_CTRL_CPORT_MASK GENMASK(13, 9)
-#define CAL_WR_DMA_CTRL_STALL_RD_MASK BIT_MASK(14)
+#define CAL_WR_DMA_CTRL_STALL_RD_MASK BIT(14)
#define CAL_WR_DMA_CTRL_YSIZE_MASK GENMASK(31, 18)
#define CAL_WR_DMA_ADDR_MASK GENMASK(31, 4)
@@ -327,9 +352,9 @@
#define CAL_WR_DMA_XSIZE_XSKIP_MASK GENMASK(15, 3)
#define CAL_WR_DMA_XSIZE_MASK GENMASK(31, 19)
-#define CAL_CSI2_PPI_CTRL_IF_EN_MASK BIT_MASK(0)
-#define CAL_CSI2_PPI_CTRL_ECC_EN_MASK BIT_MASK(2)
-#define CAL_CSI2_PPI_CTRL_FRAME_MASK BIT_MASK(3)
+#define CAL_CSI2_PPI_CTRL_IF_EN_MASK BIT(0)
+#define CAL_CSI2_PPI_CTRL_ECC_EN_MASK BIT(2)
+#define CAL_CSI2_PPI_CTRL_FRAME_MASK BIT(3)
#define CAL_CSI2_PPI_CTRL_FRAME_IMMEDIATE 0
#define CAL_CSI2_PPI_CTRL_FRAME 1
@@ -340,18 +365,18 @@
#define CAL_CSI2_COMPLEXIO_CFG_POSITION_2 2
#define CAL_CSI2_COMPLEXIO_CFG_POSITION_1 1
#define CAL_CSI2_COMPLEXIO_CFG_POSITION_NOT_USED 0
-#define CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK BIT_MASK(3)
+#define CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK BIT(3)
#define CAL_CSI2_COMPLEXIO_CFG_POL_PLUSMINUS 0
#define CAL_CSI2_COMPLEXIO_CFG_POL_MINUSPLUS 1
#define CAL_CSI2_COMPLEXIO_CFG_DATA1_POSITION_MASK GENMASK(6, 4)
-#define CAL_CSI2_COMPLEXIO_CFG_DATA1_POL_MASK BIT_MASK(7)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA1_POL_MASK BIT(7)
#define CAL_CSI2_COMPLEXIO_CFG_DATA2_POSITION_MASK GENMASK(10, 8)
-#define CAL_CSI2_COMPLEXIO_CFG_DATA2_POL_MASK BIT_MASK(11)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA2_POL_MASK BIT(11)
#define CAL_CSI2_COMPLEXIO_CFG_DATA3_POSITION_MASK GENMASK(14, 12)
-#define CAL_CSI2_COMPLEXIO_CFG_DATA3_POL_MASK BIT_MASK(15)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA3_POL_MASK BIT(15)
#define CAL_CSI2_COMPLEXIO_CFG_DATA4_POSITION_MASK GENMASK(18, 16)
-#define CAL_CSI2_COMPLEXIO_CFG_DATA4_POL_MASK BIT_MASK(19)
-#define CAL_CSI2_COMPLEXIO_CFG_PWR_AUTO_MASK BIT_MASK(24)
+#define CAL_CSI2_COMPLEXIO_CFG_DATA4_POL_MASK BIT(19)
+#define CAL_CSI2_COMPLEXIO_CFG_PWR_AUTO_MASK BIT(24)
#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK GENMASK(26, 25)
#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_OFF 0
#define CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_STATE_ON 1
@@ -360,83 +385,83 @@
#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF 0
#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON 1
#define CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ULP 2
-#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK BIT_MASK(29)
+#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK BIT(29)
#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED 1
#define CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETONGOING 0
-#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK BIT_MASK(30)
+#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK BIT(30)
#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL 0
#define CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL 1
#define CAL_CSI2_SHORT_PACKET_MASK GENMASK(23, 0)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS1_MASK BIT_MASK(0)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS2_MASK BIT_MASK(1)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS3_MASK BIT_MASK(2)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS4_MASK BIT_MASK(3)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS5_MASK BIT_MASK(4)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1_MASK BIT_MASK(5)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2_MASK BIT_MASK(6)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3_MASK BIT_MASK(7)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4_MASK BIT_MASK(8)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5_MASK BIT_MASK(9)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC1_MASK BIT_MASK(10)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC2_MASK BIT_MASK(11)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC3_MASK BIT_MASK(12)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC4_MASK BIT_MASK(13)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC5_MASK BIT_MASK(14)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL1_MASK BIT_MASK(15)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL2_MASK BIT_MASK(16)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL3_MASK BIT_MASK(17)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL4_MASK BIT_MASK(18)
-#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL5_MASK BIT_MASK(19)
-#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM1_MASK BIT_MASK(20)
-#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM2_MASK BIT_MASK(21)
-#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM3_MASK BIT_MASK(22)
-#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM4_MASK BIT_MASK(23)
-#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM5_MASK BIT_MASK(24)
-#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER_MASK BIT_MASK(25)
-#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT_MASK BIT_MASK(26)
-#define CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK BIT_MASK(27)
-#define CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK BIT_MASK(28)
-#define CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK BIT_MASK(30)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS1_MASK BIT(0)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS2_MASK BIT(1)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS3_MASK BIT(2)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS4_MASK BIT(3)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTHS5_MASK BIT(4)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1_MASK BIT(5)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2_MASK BIT(6)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3_MASK BIT(7)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4_MASK BIT(8)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5_MASK BIT(9)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC1_MASK BIT(10)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC2_MASK BIT(11)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC3_MASK BIT(12)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC4_MASK BIT(13)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRESC5_MASK BIT(14)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL1_MASK BIT(15)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL2_MASK BIT(16)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL3_MASK BIT(17)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL4_MASK BIT(18)
+#define CAL_CSI2_COMPLEXIO_IRQ_ERRCONTROL5_MASK BIT(19)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM1_MASK BIT(20)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM2_MASK BIT(21)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM3_MASK BIT(22)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM4_MASK BIT(23)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEULPM5_MASK BIT(24)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER_MASK BIT(25)
+#define CAL_CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT_MASK BIT(26)
+#define CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK BIT(27)
+#define CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK BIT(28)
+#define CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK BIT(30)
#define CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK GENMASK(12, 0)
-#define CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK BIT_MASK(13)
-#define CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK BIT_MASK(14)
-#define CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK BIT_MASK(15)
-
-#define CAL_CSI2_VC_IRQ_FS_IRQ_0_MASK BIT_MASK(0)
-#define CAL_CSI2_VC_IRQ_FE_IRQ_0_MASK BIT_MASK(1)
-#define CAL_CSI2_VC_IRQ_LS_IRQ_0_MASK BIT_MASK(2)
-#define CAL_CSI2_VC_IRQ_LE_IRQ_0_MASK BIT_MASK(3)
-#define CAL_CSI2_VC_IRQ_CS_IRQ_0_MASK BIT_MASK(4)
-#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_0_MASK BIT_MASK(5)
-#define CAL_CSI2_VC_IRQ_FS_IRQ_1_MASK BIT_MASK(8)
-#define CAL_CSI2_VC_IRQ_FE_IRQ_1_MASK BIT_MASK(9)
-#define CAL_CSI2_VC_IRQ_LS_IRQ_1_MASK BIT_MASK(10)
-#define CAL_CSI2_VC_IRQ_LE_IRQ_1_MASK BIT_MASK(11)
-#define CAL_CSI2_VC_IRQ_CS_IRQ_1_MASK BIT_MASK(12)
-#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_1_MASK BIT_MASK(13)
-#define CAL_CSI2_VC_IRQ_FS_IRQ_2_MASK BIT_MASK(16)
-#define CAL_CSI2_VC_IRQ_FE_IRQ_2_MASK BIT_MASK(17)
-#define CAL_CSI2_VC_IRQ_LS_IRQ_2_MASK BIT_MASK(18)
-#define CAL_CSI2_VC_IRQ_LE_IRQ_2_MASK BIT_MASK(19)
-#define CAL_CSI2_VC_IRQ_CS_IRQ_2_MASK BIT_MASK(20)
-#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_2_MASK BIT_MASK(21)
-#define CAL_CSI2_VC_IRQ_FS_IRQ_3_MASK BIT_MASK(24)
-#define CAL_CSI2_VC_IRQ_FE_IRQ_3_MASK BIT_MASK(25)
-#define CAL_CSI2_VC_IRQ_LS_IRQ_3_MASK BIT_MASK(26)
-#define CAL_CSI2_VC_IRQ_LE_IRQ_3_MASK BIT_MASK(27)
-#define CAL_CSI2_VC_IRQ_CS_IRQ_3_MASK BIT_MASK(28)
-#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_3_MASK BIT_MASK(29)
+#define CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK BIT(13)
+#define CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK BIT(14)
+#define CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK BIT(15)
+
+#define CAL_CSI2_VC_IRQ_FS_IRQ_0_MASK BIT(0)
+#define CAL_CSI2_VC_IRQ_FE_IRQ_0_MASK BIT(1)
+#define CAL_CSI2_VC_IRQ_LS_IRQ_0_MASK BIT(2)
+#define CAL_CSI2_VC_IRQ_LE_IRQ_0_MASK BIT(3)
+#define CAL_CSI2_VC_IRQ_CS_IRQ_0_MASK BIT(4)
+#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_0_MASK BIT(5)
+#define CAL_CSI2_VC_IRQ_FS_IRQ_1_MASK BIT(8)
+#define CAL_CSI2_VC_IRQ_FE_IRQ_1_MASK BIT(9)
+#define CAL_CSI2_VC_IRQ_LS_IRQ_1_MASK BIT(10)
+#define CAL_CSI2_VC_IRQ_LE_IRQ_1_MASK BIT(11)
+#define CAL_CSI2_VC_IRQ_CS_IRQ_1_MASK BIT(12)
+#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_1_MASK BIT(13)
+#define CAL_CSI2_VC_IRQ_FS_IRQ_2_MASK BIT(16)
+#define CAL_CSI2_VC_IRQ_FE_IRQ_2_MASK BIT(17)
+#define CAL_CSI2_VC_IRQ_LS_IRQ_2_MASK BIT(18)
+#define CAL_CSI2_VC_IRQ_LE_IRQ_2_MASK BIT(19)
+#define CAL_CSI2_VC_IRQ_CS_IRQ_2_MASK BIT(20)
+#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_2_MASK BIT(21)
+#define CAL_CSI2_VC_IRQ_FS_IRQ_3_MASK BIT(24)
+#define CAL_CSI2_VC_IRQ_FE_IRQ_3_MASK BIT(25)
+#define CAL_CSI2_VC_IRQ_LS_IRQ_3_MASK BIT(26)
+#define CAL_CSI2_VC_IRQ_LE_IRQ_3_MASK BIT(27)
+#define CAL_CSI2_VC_IRQ_CS_IRQ_3_MASK BIT(28)
+#define CAL_CSI2_VC_IRQ_ECC_CORRECTION0_IRQ_3_MASK BIT(29)
#define CAL_CSI2_CTX_DT_MASK GENMASK(5, 0)
#define CAL_CSI2_CTX_VC_MASK GENMASK(7, 6)
#define CAL_CSI2_CTX_CPORT_MASK GENMASK(12, 8)
-#define CAL_CSI2_CTX_ATT_MASK BIT_MASK(13)
+#define CAL_CSI2_CTX_ATT_MASK BIT(13)
#define CAL_CSI2_CTX_ATT_PIX 0
#define CAL_CSI2_CTX_ATT 1
-#define CAL_CSI2_CTX_PACK_MODE_MASK BIT_MASK(14)
+#define CAL_CSI2_CTX_PACK_MODE_MASK BIT(14)
#define CAL_CSI2_CTX_PACK_MODE_LINE 0
#define CAL_CSI2_CTX_PACK_MODE_FRAME 1
#define CAL_CSI2_CTX_LINES_MASK GENMASK(29, 16)
@@ -445,7 +470,7 @@
#define CAL_CSI2_PHY_REG0_THS_SETTLE_MASK GENMASK(7, 0)
#define CAL_CSI2_PHY_REG0_THS_TERM_MASK GENMASK(15, 8)
-#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK BIT_MASK(24)
+#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK BIT(24)
#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE 1
#define CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_ENABLE 0
@@ -453,24 +478,26 @@
#define CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK GENMASK(9, 8)
#define CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK GENMASK(17, 10)
#define CAL_CSI2_PHY_REG1_TCLK_TERM_MASK GENMASK(24, 18)
-#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_MASK BIT_MASK(25)
+#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_MASK BIT(25)
#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_ERROR 1
#define CAL_CSI2_PHY_REG1_CLOCK_MISS_DETECTOR_STATUS_SUCCESS 0
#define CAL_CSI2_PHY_REG1_RESET_DONE_STATUS_MASK GENMASK(29, 28)
+#define CAL_CSI2_PHY_REG10_I933_LDO_DISABLE_MASK BIT(6)
+
#define CAL_CSI2_PHY_REG2_CCP2_SYNC_PATTERN_MASK GENMASK(23, 0)
#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC3_MASK GENMASK(25, 24)
#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC2_MASK GENMASK(27, 26)
#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC1_MASK GENMASK(29, 28)
#define CAL_CSI2_PHY_REG2_TRIGGER_CMD_RXTRIGESC0_MASK GENMASK(31, 30)
-#define CM_CAMERRX_CTRL_CSI1_CTRLCLKEN_MASK BIT_MASK(0)
+#define CM_CAMERRX_CTRL_CSI1_CTRLCLKEN_MASK BIT(0)
#define CM_CAMERRX_CTRL_CSI1_CAMMODE_MASK GENMASK(2, 1)
#define CM_CAMERRX_CTRL_CSI1_LANEENABLE_MASK GENMASK(4, 3)
-#define CM_CAMERRX_CTRL_CSI1_MODE_MASK BIT_MASK(5)
-#define CM_CAMERRX_CTRL_CSI0_CTRLCLKEN_MASK BIT_MASK(10)
+#define CM_CAMERRX_CTRL_CSI1_MODE_MASK BIT(5)
+#define CM_CAMERRX_CTRL_CSI0_CTRLCLKEN_MASK BIT(10)
#define CM_CAMERRX_CTRL_CSI0_CAMMODE_MASK GENMASK(12, 11)
#define CM_CAMERRX_CTRL_CSI0_LANEENABLE_MASK GENMASK(16, 13)
-#define CM_CAMERRX_CTRL_CSI0_MODE_MASK BIT_MASK(17)
+#define CM_CAMERRX_CTRL_CSI0_MODE_MASK BIT(17)
#endif
diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c
index eda2a5985da7..f4e0cf72d1cf 100644
--- a/drivers/media/platform/ti-vpe/csc.c
+++ b/drivers/media/platform/ti-vpe/csc.c
@@ -15,76 +15,96 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
#include "csc.h"
/*
- * 16 coefficients in the order:
+ * 12 coefficients in the order:
* a0, b0, c0, a1, b1, c1, a2, b2, c2, d0, d1, d2
- * (we may need to pass non-default values from user space later on, we might
- * need to make the coefficient struct more easy to populate)
*/
-struct colorspace_coeffs {
- u16 sd[12];
- u16 hd[12];
+struct quantization {
+ u16 coeff[12];
};
-/* VIDEO_RANGE: limited range, GRAPHICS_RANGE: full range */
-#define CSC_COEFFS_VIDEO_RANGE_Y2R 0
-#define CSC_COEFFS_GRAPHICS_RANGE_Y2R 1
-#define CSC_COEFFS_VIDEO_RANGE_R2Y 2
-#define CSC_COEFFS_GRAPHICS_RANGE_R2Y 3
+struct colorspace {
+ struct quantization limited;
+ struct quantization full;
+};
+
+struct encoding_direction {
+ struct colorspace r601;
+ struct colorspace r709;
+};
+
+struct csc_coeffs {
+ struct encoding_direction y2r;
+ struct encoding_direction r2y;
+};
/* default colorspace coefficients */
-static struct colorspace_coeffs colorspace_coeffs[4] = {
- [CSC_COEFFS_VIDEO_RANGE_Y2R] = {
- {
- /* SDTV */
- 0x0400, 0x0000, 0x057D, 0x0400, 0x1EA7, 0x1D35,
- 0x0400, 0x06EF, 0x1FFE, 0x0D40, 0x0210, 0x0C88,
- },
- {
- /* HDTV */
- 0x0400, 0x0000, 0x0629, 0x0400, 0x1F45, 0x1E2B,
- 0x0400, 0x0742, 0x0000, 0x0CEC, 0x0148, 0x0C60,
- },
- },
- [CSC_COEFFS_GRAPHICS_RANGE_Y2R] = {
- {
- /* SDTV */
- 0x04A8, 0x1FFE, 0x0662, 0x04A8, 0x1E6F, 0x1CBF,
- 0x04A8, 0x0812, 0x1FFF, 0x0C84, 0x0220, 0x0BAC,
- },
- {
- /* HDTV */
- 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE,
- 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C,
- },
- },
- [CSC_COEFFS_VIDEO_RANGE_R2Y] = {
- {
- /* SDTV */
- 0x0132, 0x0259, 0x0075, 0x1F50, 0x1EA5, 0x020B,
- 0x020B, 0x1E4A, 0x1FAB, 0x0000, 0x0200, 0x0200,
+static struct csc_coeffs csc_coeffs = {
+ .y2r = {
+ .r601 = {
+ .limited = {
+ { /* SDTV */
+ 0x0400, 0x0000, 0x057D, 0x0400, 0x1EA7, 0x1D35,
+ 0x0400, 0x06EF, 0x1FFE, 0x0D40, 0x0210, 0x0C88,
+ }
+ },
+ .full = {
+ { /* SDTV */
+ 0x04A8, 0x1FFE, 0x0662, 0x04A8, 0x1E6F, 0x1CBF,
+ 0x04A8, 0x0812, 0x1FFF, 0x0C84, 0x0220, 0x0BAC,
+ }
+ },
},
- {
- /* HDTV */
- 0x00DA, 0x02DC, 0x004A, 0x1F88, 0x1E6C, 0x020C,
- 0x020C, 0x1E24, 0x1FD0, 0x0000, 0x0200, 0x0200,
+ .r709 = {
+ .limited = {
+ { /* HDTV */
+ 0x0400, 0x0000, 0x0629, 0x0400, 0x1F45, 0x1E2B,
+ 0x0400, 0x0742, 0x0000, 0x0CEC, 0x0148, 0x0C60,
+ }
+ },
+ .full = {
+ { /* HDTV */
+ 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE,
+ 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C,
+ }
+ },
},
},
- [CSC_COEFFS_GRAPHICS_RANGE_R2Y] = {
- {
- /* SDTV */
- 0x0107, 0x0204, 0x0064, 0x1F68, 0x1ED6, 0x01C2,
- 0x01C2, 0x1E87, 0x1FB7, 0x0040, 0x0200, 0x0200,
+ .r2y = {
+ .r601 = {
+ .limited = {
+ { /* SDTV */
+ 0x0132, 0x0259, 0x0075, 0x1F50, 0x1EA5, 0x020B,
+ 0x020B, 0x1E4A, 0x1FAB, 0x0000, 0x0200, 0x0200,
+ }
+ },
+ .full = {
+ { /* SDTV */
+ 0x0107, 0x0204, 0x0064, 0x1F68, 0x1ED6, 0x01C2,
+ 0x01C2, 0x1E87, 0x1FB7, 0x0040, 0x0200, 0x0200,
+ }
+ },
},
- {
- /* HDTV */
- 0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE,
- 0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C,
+ .r709 = {
+ .limited = {
+ { /* HDTV */
+ 0x00DA, 0x02DC, 0x004A, 0x1F88, 0x1E6C, 0x020C,
+ 0x020C, 0x1E24, 0x1FD0, 0x0000, 0x0200, 0x0200,
+ }
+ },
+ .full = {
+ { /* HDTV */
+ 0x00bb, 0x0275, 0x003f, 0x1f99, 0x1ea5, 0x01c2,
+ 0x01c2, 0x1e67, 0x1fd7, 0x0040, 0x0200, 0x0200,
+ }
+ },
},
},
+
};
void csc_dump_regs(struct csc_data *csc)
@@ -117,46 +137,106 @@ EXPORT_SYMBOL(csc_set_coeff_bypass);
* set the color space converter coefficient shadow register values
*/
void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0,
- enum v4l2_colorspace src_colorspace,
- enum v4l2_colorspace dst_colorspace)
+ struct v4l2_format *src_fmt, struct v4l2_format *dst_fmt)
{
u32 *csc_reg5 = csc_reg0 + 5;
u32 *shadow_csc = csc_reg0;
- struct colorspace_coeffs *sd_hd_coeffs;
u16 *coeff, *end_coeff;
- enum v4l2_colorspace yuv_colorspace;
- int sel = 0;
-
- /*
- * support only graphics data range(full range) for now, a control ioctl
- * would be nice here
- */
- /* Y2R */
- if (dst_colorspace == V4L2_COLORSPACE_SRGB &&
- (src_colorspace == V4L2_COLORSPACE_SMPTE170M ||
- src_colorspace == V4L2_COLORSPACE_REC709)) {
+ const struct v4l2_pix_format *pix;
+ const struct v4l2_pix_format_mplane *mp;
+ const struct v4l2_format_info *src_finfo, *dst_finfo;
+ enum v4l2_ycbcr_encoding src_ycbcr_enc, dst_ycbcr_enc;
+ enum v4l2_quantization src_quantization, dst_quantization;
+ u32 src_pixelformat, dst_pixelformat;
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(src_fmt->type)) {
+ mp = &src_fmt->fmt.pix_mp;
+ src_pixelformat = mp->pixelformat;
+ src_ycbcr_enc = mp->ycbcr_enc;
+ src_quantization = mp->quantization;
+ } else {
+ pix = &src_fmt->fmt.pix;
+ src_pixelformat = pix->pixelformat;
+ src_ycbcr_enc = pix->ycbcr_enc;
+ src_quantization = pix->quantization;
+ }
+
+ if (V4L2_TYPE_IS_MULTIPLANAR(dst_fmt->type)) {
+ mp = &dst_fmt->fmt.pix_mp;
+ dst_pixelformat = mp->pixelformat;
+ dst_ycbcr_enc = mp->ycbcr_enc;
+ dst_quantization = mp->quantization;
+ } else {
+ pix = &dst_fmt->fmt.pix;
+ dst_pixelformat = pix->pixelformat;
+ dst_ycbcr_enc = pix->ycbcr_enc;
+ dst_quantization = pix->quantization;
+ }
+
+ src_finfo = v4l2_format_info(src_pixelformat);
+ dst_finfo = v4l2_format_info(dst_pixelformat);
+
+ if (v4l2_is_format_yuv(src_finfo) &&
+ v4l2_is_format_rgb(dst_finfo)) {
/* Y2R */
- sel = 1;
- yuv_colorspace = src_colorspace;
- } else if ((dst_colorspace == V4L2_COLORSPACE_SMPTE170M ||
- dst_colorspace == V4L2_COLORSPACE_REC709) &&
- src_colorspace == V4L2_COLORSPACE_SRGB) {
+
+ /*
+ * These are not the standard default values but are
+ * set this way for historical compatibility
+ */
+ if (src_ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
+ src_ycbcr_enc = V4L2_YCBCR_ENC_601;
+
+ if (src_quantization == V4L2_QUANTIZATION_DEFAULT)
+ src_quantization = V4L2_QUANTIZATION_FULL_RANGE;
+
+ if (src_ycbcr_enc == V4L2_YCBCR_ENC_601) {
+ if (src_quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ coeff = csc_coeffs.y2r.r601.full.coeff;
+ else
+ coeff = csc_coeffs.y2r.r601.limited.coeff;
+ } else if (src_ycbcr_enc == V4L2_YCBCR_ENC_709) {
+ if (src_quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ coeff = csc_coeffs.y2r.r709.full.coeff;
+ else
+ coeff = csc_coeffs.y2r.r709.limited.coeff;
+ } else {
+ /* Should never reach this, but it keeps gcc happy */
+ coeff = csc_coeffs.y2r.r601.full.coeff;
+ }
+ } else if (v4l2_is_format_rgb(src_finfo) &&
+ v4l2_is_format_yuv(dst_finfo)) {
/* R2Y */
- sel = 3;
- yuv_colorspace = dst_colorspace;
+
+ /*
+ * These are not the standard default values but are
+ * set this way for historical compatibility
+ */
+ if (dst_ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
+ dst_ycbcr_enc = V4L2_YCBCR_ENC_601;
+
+ if (dst_quantization == V4L2_QUANTIZATION_DEFAULT)
+ dst_quantization = V4L2_QUANTIZATION_FULL_RANGE;
+
+ if (dst_ycbcr_enc == V4L2_YCBCR_ENC_601) {
+ if (dst_quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ coeff = csc_coeffs.r2y.r601.full.coeff;
+ else
+ coeff = csc_coeffs.r2y.r601.limited.coeff;
+ } else if (dst_ycbcr_enc == V4L2_YCBCR_ENC_709) {
+ if (dst_quantization == V4L2_QUANTIZATION_FULL_RANGE)
+ coeff = csc_coeffs.r2y.r709.full.coeff;
+ else
+ coeff = csc_coeffs.r2y.r709.limited.coeff;
+ } else {
+ /* Should never reach this, but it keeps gcc happy */
+ coeff = csc_coeffs.r2y.r601.full.coeff;
+ }
} else {
*csc_reg5 |= CSC_BYPASS;
return;
}
- sd_hd_coeffs = &colorspace_coeffs[sel];
-
- /* select between SD or HD coefficients */
- if (yuv_colorspace == V4L2_COLORSPACE_SMPTE170M)
- coeff = sd_hd_coeffs->sd;
- else
- coeff = sd_hd_coeffs->hd;
-
end_coeff = coeff + 12;
for (; coeff < end_coeff; coeff += 2)
diff --git a/drivers/media/platform/ti-vpe/csc.h b/drivers/media/platform/ti-vpe/csc.h
index de9a58af2ca8..af2e86bccf57 100644
--- a/drivers/media/platform/ti-vpe/csc.h
+++ b/drivers/media/platform/ti-vpe/csc.h
@@ -58,8 +58,8 @@ struct csc_data {
void csc_dump_regs(struct csc_data *csc);
void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5);
void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0,
- enum v4l2_colorspace src_colorspace,
- enum v4l2_colorspace dst_colorspace);
+ struct v4l2_format *src_fmt, struct v4l2_format *dst_fmt);
+
struct csc_data *csc_create(struct platform_device *pdev, const char *res_name);
#endif
diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c
index fd37d79e1619..2e5148ae7a0f 100644
--- a/drivers/media/platform/ti-vpe/vpdma.c
+++ b/drivers/media/platform/ti-vpe/vpdma.c
@@ -56,6 +56,11 @@ const struct vpdma_data_format vpdma_yuv_fmts[] = {
.data_type = DATA_TYPE_C420,
.depth = 4,
},
+ [VPDMA_DATA_FMT_CB420] = {
+ .type = VPDMA_DATA_FMT_TYPE_YUV,
+ .data_type = DATA_TYPE_CB420,
+ .depth = 4,
+ },
[VPDMA_DATA_FMT_YCR422] = {
.type = VPDMA_DATA_FMT_TYPE_YUV,
.data_type = DATA_TYPE_YCR422,
@@ -445,23 +450,25 @@ int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num,
ret = vpdma_map_desc_buf(vpdma, &abort_list.buf);
if (ret)
- return ret;
+ goto free_desc;
ret = vpdma_submit_descs(vpdma, &abort_list, list_num);
if (ret)
- return ret;
+ goto unmap_desc;
while (vpdma_list_busy(vpdma, list_num) && --timeout)
;
if (timeout == 0) {
dev_err(&vpdma->pdev->dev, "Timed out cleaning up VPDMA list\n");
- return -EBUSY;
+ ret = -EBUSY;
}
+unmap_desc:
vpdma_unmap_desc_buf(vpdma, &abort_list.buf);
+free_desc:
vpdma_free_desc_buf(&abort_list.buf);
- return 0;
+ return ret;
}
EXPORT_SYMBOL(vpdma_list_cleanup);
@@ -757,7 +764,7 @@ static void dump_dtd(struct vpdma_dtd *dtd)
pr_debug("word1: line_length = %d, xfer_height = %d\n",
dtd_get_line_length(dtd), dtd_get_xfer_height(dtd));
- pr_debug("word2: start_addr = %pad\n", &dtd->start_addr);
+ pr_debug("word2: start_addr = %x\n", dtd->start_addr);
pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, pri = %d, next_chan = %d\n",
dtd_get_pkt_type(dtd),
@@ -823,7 +830,8 @@ void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width,
channel = next_chan = raw_vpdma_chan;
if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
- fmt->data_type == DATA_TYPE_C420) {
+ (fmt->data_type == DATA_TYPE_C420 ||
+ fmt->data_type == DATA_TYPE_CB420)) {
rect.height >>= 1;
rect.top >>= 1;
depth = 8;
@@ -891,7 +899,8 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
channel = next_chan = chan_info[chan].num;
if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
- fmt->data_type == DATA_TYPE_C420) {
+ (fmt->data_type == DATA_TYPE_C420 ||
+ fmt->data_type == DATA_TYPE_CB420)) {
rect.height >>= 1;
rect.top >>= 1;
depth = 8;
diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h
index 28bc94129348..393fcbb3cb40 100644
--- a/drivers/media/platform/ti-vpe/vpdma.h
+++ b/drivers/media/platform/ti-vpe/vpdma.h
@@ -57,6 +57,7 @@ struct vpdma_data_format {
* line stride of source and dest
* buffers should be 16 byte aligned
*/
+#define VPDMA_MAX_STRIDE 65520 /* Max line stride 16 byte aligned */
#define VPDMA_DTD_DESC_SIZE 32 /* 8 words */
#define VPDMA_CFD_CTD_DESC_SIZE 16 /* 4 words */
@@ -71,6 +72,7 @@ enum vpdma_yuv_formats {
VPDMA_DATA_FMT_C444,
VPDMA_DATA_FMT_C422,
VPDMA_DATA_FMT_C420,
+ VPDMA_DATA_FMT_CB420,
VPDMA_DATA_FMT_YCR422,
VPDMA_DATA_FMT_YC444,
VPDMA_DATA_FMT_CRY422,
diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h
index c488609bc162..0bbee45338bd 100644
--- a/drivers/media/platform/ti-vpe/vpdma_priv.h
+++ b/drivers/media/platform/ti-vpe/vpdma_priv.h
@@ -92,6 +92,7 @@
#define DATA_TYPE_C444 0x4
#define DATA_TYPE_C422 0x5
#define DATA_TYPE_C420 0x6
+#define DATA_TYPE_CB420 0x16
#define DATA_TYPE_YC444 0x8
#define DATA_TYPE_YCB422 0x7
#define DATA_TYPE_YCR422 0x17
@@ -165,11 +166,11 @@ struct vpdma_dtd {
u32 xfer_length_height;
u32 w1;
};
- dma_addr_t start_addr;
+ u32 start_addr;
u32 pkt_ctl;
union {
u32 frame_width_height; /* inbound */
- dma_addr_t desc_write_addr; /* outbound */
+ u32 desc_write_addr; /* outbound */
};
union {
u32 start_h_v; /* inbound */
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index dda04498ac56..65c2c048b018 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -52,7 +52,7 @@
#define MIN_W 32
#define MIN_H 32
#define MAX_W 2048
-#define MAX_H 1184
+#define MAX_H 2048
/* required alignments */
#define S_ALIGN 0 /* multiple of 1 */
@@ -224,7 +224,6 @@ static const struct vpe_port_data port_data[11] = {
/* driver info for each of the supported video formats */
struct vpe_fmt {
- char *name; /* human-readable name */
u32 fourcc; /* standard format identifier */
u8 types; /* CAPTURE and/or OUTPUT */
u8 coplanar; /* set for unpacked Luma and Chroma */
@@ -234,7 +233,6 @@ struct vpe_fmt {
static struct vpe_fmt vpe_formats[] = {
{
- .name = "NV16 YUV 422 co-planar",
.fourcc = V4L2_PIX_FMT_NV16,
.types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,
.coplanar = 1,
@@ -243,7 +241,6 @@ static struct vpe_fmt vpe_formats[] = {
},
},
{
- .name = "NV12 YUV 420 co-planar",
.fourcc = V4L2_PIX_FMT_NV12,
.types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,
.coplanar = 1,
@@ -252,7 +249,14 @@ static struct vpe_fmt vpe_formats[] = {
},
},
{
- .name = "YUYV 422 packed",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,
+ .coplanar = 1,
+ .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420],
+ &vpdma_yuv_fmts[VPDMA_DATA_FMT_CB420],
+ },
+ },
+ {
.fourcc = V4L2_PIX_FMT_YUYV,
.types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,
.coplanar = 0,
@@ -260,7 +264,6 @@ static struct vpe_fmt vpe_formats[] = {
},
},
{
- .name = "UYVY 422 packed",
.fourcc = V4L2_PIX_FMT_UYVY,
.types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT,
.coplanar = 0,
@@ -268,7 +271,6 @@ static struct vpe_fmt vpe_formats[] = {
},
},
{
- .name = "RGB888 packed",
.fourcc = V4L2_PIX_FMT_RGB24,
.types = VPE_FMT_TYPE_CAPTURE,
.coplanar = 0,
@@ -276,7 +278,6 @@ static struct vpe_fmt vpe_formats[] = {
},
},
{
- .name = "ARGB32",
.fourcc = V4L2_PIX_FMT_RGB32,
.types = VPE_FMT_TYPE_CAPTURE,
.coplanar = 0,
@@ -284,7 +285,6 @@ static struct vpe_fmt vpe_formats[] = {
},
},
{
- .name = "BGR888 packed",
.fourcc = V4L2_PIX_FMT_BGR24,
.types = VPE_FMT_TYPE_CAPTURE,
.coplanar = 0,
@@ -292,7 +292,6 @@ static struct vpe_fmt vpe_formats[] = {
},
},
{
- .name = "ABGR32",
.fourcc = V4L2_PIX_FMT_BGR32,
.types = VPE_FMT_TYPE_CAPTURE,
.coplanar = 0,
@@ -300,7 +299,6 @@ static struct vpe_fmt vpe_formats[] = {
},
},
{
- .name = "RGB565",
.fourcc = V4L2_PIX_FMT_RGB565,
.types = VPE_FMT_TYPE_CAPTURE,
.coplanar = 0,
@@ -308,7 +306,6 @@ static struct vpe_fmt vpe_formats[] = {
},
},
{
- .name = "RGB5551",
.fourcc = V4L2_PIX_FMT_RGB555,
.types = VPE_FMT_TYPE_CAPTURE,
.coplanar = 0,
@@ -322,14 +319,9 @@ static struct vpe_fmt vpe_formats[] = {
* there is one source queue and one destination queue for each m2m context.
*/
struct vpe_q_data {
- unsigned int width; /* frame width */
- unsigned int height; /* frame height */
- unsigned int nplanes; /* Current number of planes */
- unsigned int bytesperline[VPE_MAX_PLANES]; /* bytes per line in memory */
- enum v4l2_colorspace colorspace;
- enum v4l2_field field; /* supported field value */
+ /* current v4l2 format info */
+ struct v4l2_format format;
unsigned int flags;
- unsigned int sizeimage[VPE_MAX_PLANES]; /* image size in memory */
struct v4l2_rect c_rect; /* crop/compose rectangle */
struct vpe_fmt *fmt; /* format info */
};
@@ -339,9 +331,14 @@ struct vpe_q_data {
#define Q_DATA_MODE_TILED BIT(1)
#define Q_DATA_INTERLACED_ALTERNATE BIT(2)
#define Q_DATA_INTERLACED_SEQ_TB BIT(3)
+#define Q_DATA_INTERLACED_SEQ_BT BIT(4)
+
+#define Q_IS_SEQ_XX (Q_DATA_INTERLACED_SEQ_TB | \
+ Q_DATA_INTERLACED_SEQ_BT)
#define Q_IS_INTERLACED (Q_DATA_INTERLACED_ALTERNATE | \
- Q_DATA_INTERLACED_SEQ_TB)
+ Q_DATA_INTERLACED_SEQ_TB | \
+ Q_DATA_INTERLACED_SEQ_BT)
enum {
Q_DATA_SRC = 0,
@@ -349,20 +346,25 @@ enum {
};
/* find our format description corresponding to the passed v4l2_format */
-static struct vpe_fmt *find_format(struct v4l2_format *f)
+static struct vpe_fmt *__find_format(u32 fourcc)
{
struct vpe_fmt *fmt;
unsigned int k;
for (k = 0; k < ARRAY_SIZE(vpe_formats); k++) {
fmt = &vpe_formats[k];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
+ if (fmt->fourcc == fourcc)
return fmt;
}
return NULL;
}
+static struct vpe_fmt *find_format(struct v4l2_format *f)
+{
+ return __find_format(f->fmt.pix.pixelformat);
+}
+
/*
* there is one vpe_dev structure in the driver, it is shared by
* all instances.
@@ -692,7 +694,8 @@ static void set_cfg_modes(struct vpe_ctx *ctx)
* Cfg Mode 1: YUV422 source, disable upsampler, DEI is de-interlacing.
*/
- if (fmt->fourcc == V4L2_PIX_FMT_NV12)
+ if (fmt->fourcc == V4L2_PIX_FMT_NV12 ||
+ fmt->fourcc == V4L2_PIX_FMT_NV21)
cfg_mode = 0;
write_field(us1_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT);
@@ -707,7 +710,8 @@ static void set_line_modes(struct vpe_ctx *ctx)
struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt;
int line_mode = 1;
- if (fmt->fourcc == V4L2_PIX_FMT_NV12)
+ if (fmt->fourcc == V4L2_PIX_FMT_NV12 ||
+ fmt->fourcc == V4L2_PIX_FMT_NV21)
line_mode = 0; /* double lines to line buffer */
/* regs for now */
@@ -752,11 +756,12 @@ static void set_src_registers(struct vpe_ctx *ctx)
static void set_dst_registers(struct vpe_ctx *ctx)
{
struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
- enum v4l2_colorspace clrspc = ctx->q_data[Q_DATA_DST].colorspace;
struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt;
+ const struct v4l2_format_info *finfo;
u32 val = 0;
- if (clrspc == V4L2_COLORSPACE_SRGB) {
+ finfo = v4l2_format_info(fmt->fourcc);
+ if (v4l2_is_format_rgb(finfo)) {
val |= VPE_RGB_OUT_SELECT;
vpdma_set_bg_color(ctx->dev->vpdma,
(struct vpdma_data_format *)fmt->vpdma_fmt[0], 0xff);
@@ -769,7 +774,8 @@ static void set_dst_registers(struct vpe_ctx *ctx)
*/
val |= VPE_DS_SRC_DEI_SCALER | VPE_CSC_SRC_DEI_SCALER;
- if (fmt->fourcc != V4L2_PIX_FMT_NV12)
+ if (fmt->fourcc != V4L2_PIX_FMT_NV12 &&
+ fmt->fourcc != V4L2_PIX_FMT_NV21)
val |= VPE_DS_BYPASS;
mmr_adb->out_fmt_reg[0] = val;
@@ -858,11 +864,13 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
unsigned int src_h = s_q_data->c_rect.height;
unsigned int dst_w = d_q_data->c_rect.width;
unsigned int dst_h = d_q_data->c_rect.height;
+ struct v4l2_pix_format_mplane *spix;
size_t mv_buf_size;
int ret;
ctx->sequence = 0;
ctx->field = V4L2_FIELD_TOP;
+ spix = &s_q_data->format.fmt.pix_mp;
if ((s_q_data->flags & Q_IS_INTERLACED) &&
!(d_q_data->flags & Q_IS_INTERLACED)) {
@@ -877,9 +885,9 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
* extra space will not be used by the de-interlacer, but will
* ensure that vpdma operates correctly
*/
- bytes_per_line = ALIGN((s_q_data->width * mv->depth) >> 3,
- VPDMA_STRIDE_ALIGN);
- mv_buf_size = bytes_per_line * s_q_data->height;
+ bytes_per_line = ALIGN((spix->width * mv->depth) >> 3,
+ VPDMA_STRIDE_ALIGN);
+ mv_buf_size = bytes_per_line * spix->height;
ctx->deinterlacing = true;
src_h <<= 1;
@@ -899,7 +907,7 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
set_dei_regs(ctx);
csc_set_coeff(ctx->dev->csc, &mmr_adb->csc_regs[0],
- s_q_data->colorspace, d_q_data->colorspace);
+ &s_q_data->format, &d_q_data->format);
sc_set_hs_coeffs(ctx->dev->sc, ctx->sc_coeff_h.addr, src_w, dst_w);
sc_set_vs_coeffs(ctx->dev->sc, ctx->sc_coeff_v.addr, src_h, dst_h);
@@ -912,14 +920,6 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
}
/*
- * Return the vpe_ctx structure for a given struct file
- */
-static struct vpe_ctx *file2ctx(struct file *file)
-{
- return container_of(file->private_data, struct vpe_ctx, fh);
-}
-
-/*
* mem2mem callbacks
*/
@@ -1021,27 +1021,33 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
struct vpe_fmt *fmt = q_data->fmt;
const struct vpdma_data_format *vpdma_fmt;
int mv_buf_selector = !ctx->src_mv_buf_selector;
+ struct v4l2_pix_format_mplane *pix;
dma_addr_t dma_addr;
u32 flags = 0;
u32 offset = 0;
+ u32 stride;
if (port == VPE_PORT_MV_OUT) {
vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
dma_addr = ctx->mv_buf_dma[mv_buf_selector];
q_data = &ctx->q_data[Q_DATA_SRC];
+ pix = &q_data->format.fmt.pix_mp;
+ stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3,
+ VPDMA_STRIDE_ALIGN);
} else {
/* to incorporate interleaved formats */
int plane = fmt->coplanar ? p_data->vb_part : 0;
+ pix = &q_data->format.fmt.pix_mp;
vpdma_fmt = fmt->vpdma_fmt[plane];
/*
* If we are using a single plane buffer and
* we need to set a separate vpdma chroma channel.
*/
- if (q_data->nplanes == 1 && plane) {
+ if (pix->num_planes == 1 && plane) {
dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
/* Compute required offset */
- offset = q_data->bytesperline[0] * q_data->height;
+ offset = pix->plane_fmt[0].bytesperline * pix->height;
} else {
dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane);
/* Use address as is, no offset */
@@ -1055,6 +1061,7 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
}
/* Apply the offset */
dma_addr += offset;
+ stride = pix->plane_fmt[VPE_LUMA].bytesperline;
}
if (q_data->flags & Q_DATA_FRAME_1D)
@@ -1065,8 +1072,8 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1,
MAX_W, MAX_H);
- vpdma_add_out_dtd(&ctx->desc_list, q_data->width,
- q_data->bytesperline[VPE_LUMA], &q_data->c_rect,
+ vpdma_add_out_dtd(&ctx->desc_list, pix->width,
+ stride, &q_data->c_rect,
vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1,
MAX_OUT_HEIGHT_REG1, p_data->channel, flags);
}
@@ -1078,6 +1085,7 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
struct vb2_buffer *vb = &ctx->src_vbs[p_data->vb_index]->vb2_buf;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vpe_fmt *fmt = q_data->fmt;
+ struct v4l2_pix_format_mplane *pix;
const struct vpdma_data_format *vpdma_fmt;
int mv_buf_selector = ctx->src_mv_buf_selector;
int field = vbuf->field == V4L2_FIELD_BOTTOM;
@@ -1085,10 +1093,14 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
dma_addr_t dma_addr;
u32 flags = 0;
u32 offset = 0;
+ u32 stride;
+ pix = &q_data->format.fmt.pix_mp;
if (port == VPE_PORT_MV_IN) {
vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
dma_addr = ctx->mv_buf_dma[mv_buf_selector];
+ stride = ALIGN((pix->width * vpdma_fmt->depth) >> 3,
+ VPDMA_STRIDE_ALIGN);
} else {
/* to incorporate interleaved formats */
int plane = fmt->coplanar ? p_data->vb_part : 0;
@@ -1098,10 +1110,10 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
* If we are using a single plane buffer and
* we need to set a separate vpdma chroma channel.
*/
- if (q_data->nplanes == 1 && plane) {
+ if (pix->num_planes == 1 && plane) {
dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
/* Compute required offset */
- offset = q_data->bytesperline[0] * q_data->height;
+ offset = pix->plane_fmt[0].bytesperline * pix->height;
} else {
dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane);
/* Use address as is, no offset */
@@ -1115,26 +1127,39 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
}
/* Apply the offset */
dma_addr += offset;
+ stride = pix->plane_fmt[VPE_LUMA].bytesperline;
- if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) {
- /*
- * Use top or bottom field from same vb alternately
- * f,f-1,f-2 = TBT when seq is even
- * f,f-1,f-2 = BTB when seq is odd
- */
- field = (p_data->vb_index + (ctx->sequence % 2)) % 2;
+ /*
+ * field used in VPDMA desc = 0 (top) / 1 (bottom)
+ * Use top or bottom field from same vb alternately
+ * For each de-interlacing operation, f,f-1,f-2 should be one
+ * of TBT or BTB
+ */
+ if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB ||
+ q_data->flags & Q_DATA_INTERLACED_SEQ_BT) {
+ /* Select initial value based on format */
+ if (q_data->flags & Q_DATA_INTERLACED_SEQ_BT)
+ field = 1;
+ else
+ field = 0;
+
+ /* Toggle for each vb_index and each operation */
+ field = (field + p_data->vb_index + ctx->sequence) % 2;
if (field) {
- /*
- * bottom field of a SEQ_TB buffer
- * Skip the top field data by
- */
- int height = q_data->height / 2;
- int bpp = fmt->fourcc == V4L2_PIX_FMT_NV12 ?
- 1 : (vpdma_fmt->depth >> 3);
+ int height = pix->height / 2;
+ int bpp;
+
+ if (fmt->fourcc == V4L2_PIX_FMT_NV12 ||
+ fmt->fourcc == V4L2_PIX_FMT_NV21)
+ bpp = 1;
+ else
+ bpp = vpdma_fmt->depth >> 3;
+
if (plane)
height /= 2;
- dma_addr += q_data->width * height * bpp;
+
+ dma_addr += pix->width * height * bpp;
}
}
}
@@ -1147,13 +1172,14 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
frame_width = q_data->c_rect.width;
frame_height = q_data->c_rect.height;
- if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
+ if (p_data->vb_part && (fmt->fourcc == V4L2_PIX_FMT_NV12 ||
+ fmt->fourcc == V4L2_PIX_FMT_NV21))
frame_height /= 2;
- vpdma_add_in_dtd(&ctx->desc_list, q_data->width,
- q_data->bytesperline[VPE_LUMA], &q_data->c_rect,
- vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width,
- frame_height, 0, 0);
+ vpdma_add_in_dtd(&ctx->desc_list, pix->width, stride,
+ &q_data->c_rect, vpdma_fmt, dma_addr,
+ p_data->channel, field, flags, frame_width,
+ frame_height, 0, 0);
}
/*
@@ -1187,13 +1213,18 @@ static void device_run(void *priv)
struct sc_data *sc = ctx->dev->sc;
struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST];
struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC];
-
- if (ctx->deinterlacing && s_q_data->flags & Q_DATA_INTERLACED_SEQ_TB &&
- ctx->sequence % 2 == 0) {
- /* When using SEQ_TB buffers, When using it first time,
- * No need to remove the buffer as the next field is present
- * in the same buffer. (so that job_ready won't fail)
- * It will be removed when using bottom field
+ const struct v4l2_format_info *d_finfo;
+
+ d_finfo = v4l2_format_info(d_q_data->fmt->fourcc);
+
+ if (ctx->deinterlacing && s_q_data->flags & Q_IS_SEQ_XX &&
+ ctx->sequence % 2 == 0) {
+ /* When using SEQ_XX type buffers, each buffer has two fields
+ * each buffer has two fields (top & bottom)
+ * Removing one buffer is actually getting two fields
+ * Alternate between two operations:-
+ * Even : consume one field but DO NOT REMOVE from queue
+ * Odd : consume other field and REMOVE from queue
*/
ctx->src_vbs[0] = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
WARN_ON(ctx->src_vbs[0] == NULL);
@@ -1257,7 +1288,7 @@ static void device_run(void *priv)
if (ctx->deinterlacing)
add_out_dtd(ctx, VPE_PORT_MV_OUT);
- if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) {
+ if (v4l2_is_format_rgb(d_finfo)) {
add_out_dtd(ctx, VPE_PORT_RGB_OUT);
} else {
add_out_dtd(ctx, VPE_PORT_LUMA_OUT);
@@ -1299,7 +1330,7 @@ static void device_run(void *priv)
}
/* sync on channel control descriptors for output ports */
- if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) {
+ if (v4l2_is_format_rgb(d_finfo)) {
vpdma_add_sync_on_channel_ctd(&ctx->desc_list,
VPE_CHAN_RGB_OUT);
} else {
@@ -1402,9 +1433,6 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
/* the previous dst mv buffer becomes the next src mv buffer */
ctx->src_mv_buf_selector = !ctx->src_mv_buf_selector;
- if (ctx->aborting)
- goto finished;
-
s_vb = ctx->src_vbs[0];
d_vb = ctx->dst_vb;
@@ -1415,6 +1443,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
d_vb->timecode = s_vb->timecode;
d_vb->sequence = ctx->sequence;
+ s_vb->sequence = ctx->sequence;
d_q_data = &ctx->q_data[Q_DATA_DST];
if (d_q_data->flags & Q_IS_INTERLACED) {
@@ -1468,6 +1497,9 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
ctx->src_vbs[0] = NULL;
ctx->dst_vb = NULL;
+ if (ctx->aborting)
+ goto finished;
+
ctx->bufs_completed++;
if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) {
device_run(ctx);
@@ -1514,7 +1546,6 @@ static int __enum_fmt(struct v4l2_fmtdesc *f, u32 type)
if (!fmt)
return -EINVAL;
- strscpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
@@ -1531,38 +1562,32 @@ static int vpe_enum_fmt(struct file *file, void *priv,
static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
- struct vpe_ctx *ctx = file2ctx(file);
+ struct vpe_ctx *ctx = file->private_data;
struct vb2_queue *vq;
struct vpe_q_data *q_data;
- int i;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
q_data = get_q_data(ctx, f->type);
+ if (!q_data)
+ return -EINVAL;
- pix->width = q_data->width;
- pix->height = q_data->height;
- pix->pixelformat = q_data->fmt->fourcc;
- pix->field = q_data->field;
+ *f = q_data->format;
- if (V4L2_TYPE_IS_OUTPUT(f->type)) {
- pix->colorspace = q_data->colorspace;
- } else {
+ if (!V4L2_TYPE_IS_OUTPUT(f->type)) {
struct vpe_q_data *s_q_data;
+ struct v4l2_pix_format_mplane *spix;
- /* get colorspace from the source queue */
+ /* get colorimetry from the source queue */
s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ spix = &s_q_data->format.fmt.pix_mp;
- pix->colorspace = s_q_data->colorspace;
- }
-
- pix->num_planes = q_data->nplanes;
-
- for (i = 0; i < pix->num_planes; i++) {
- pix->plane_fmt[i].bytesperline = q_data->bytesperline[i];
- pix->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+ pix->colorspace = spix->colorspace;
+ pix->xfer_func = spix->xfer_func;
+ pix->ycbcr_enc = spix->ycbcr_enc;
+ pix->quantization = spix->quantization;
}
return 0;
@@ -1576,15 +1601,18 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
unsigned int w_align;
int i, depth, depth_bytes, height;
unsigned int stride = 0;
+ const struct v4l2_format_info *finfo;
if (!fmt || !(fmt->types & type)) {
- vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
+ vpe_dbg(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
pix->pixelformat);
- return -EINVAL;
+ fmt = __find_format(V4L2_PIX_FMT_YUYV);
}
- if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE
- && pix->field != V4L2_FIELD_SEQ_TB)
+ if (pix->field != V4L2_FIELD_NONE &&
+ pix->field != V4L2_FIELD_ALTERNATE &&
+ pix->field != V4L2_FIELD_SEQ_TB &&
+ pix->field != V4L2_FIELD_SEQ_BT)
pix->field = V4L2_FIELD_NONE;
depth = fmt->vpdma_fmt[VPE_LUMA]->depth;
@@ -1627,27 +1655,25 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
&pix->height, MIN_H, MAX_H, H_ALIGN,
S_ALIGN);
- if (!pix->num_planes)
+ if (!pix->num_planes || pix->num_planes > 2)
pix->num_planes = fmt->coplanar ? 2 : 1;
else if (pix->num_planes > 1 && !fmt->coplanar)
pix->num_planes = 1;
pix->pixelformat = fmt->fourcc;
+ finfo = v4l2_format_info(fmt->fourcc);
/*
* For the actual image parameters, we need to consider the field
- * height of the image for SEQ_TB buffers.
+ * height of the image for SEQ_XX buffers.
*/
- if (pix->field == V4L2_FIELD_SEQ_TB)
+ if (pix->field == V4L2_FIELD_SEQ_TB || pix->field == V4L2_FIELD_SEQ_BT)
height = pix->height / 2;
else
height = pix->height;
if (!pix->colorspace) {
- if (fmt->fourcc == V4L2_PIX_FMT_RGB24 ||
- fmt->fourcc == V4L2_PIX_FMT_BGR24 ||
- fmt->fourcc == V4L2_PIX_FMT_RGB32 ||
- fmt->fourcc == V4L2_PIX_FMT_BGR32) {
+ if (v4l2_is_format_rgb(finfo)) {
pix->colorspace = V4L2_COLORSPACE_SRGB;
} else {
if (height > 1280) /* HD */
@@ -1666,6 +1692,10 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
if (stride > plane_fmt->bytesperline)
plane_fmt->bytesperline = stride;
+ plane_fmt->bytesperline = clamp_t(u32, plane_fmt->bytesperline,
+ stride,
+ VPDMA_MAX_STRIDE);
+
plane_fmt->bytesperline = ALIGN(plane_fmt->bytesperline,
VPDMA_STRIDE_ALIGN);
@@ -1691,7 +1721,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
- struct vpe_ctx *ctx = file2ctx(file);
+ struct vpe_ctx *ctx = file->private_data;
struct vpe_fmt *fmt = find_format(f);
if (V4L2_TYPE_IS_OUTPUT(f->type))
@@ -1703,10 +1733,9 @@ static int vpe_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f)
{
struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
- struct v4l2_plane_pix_format *plane_fmt;
+ struct v4l2_pix_format_mplane *qpix;
struct vpe_q_data *q_data;
struct vb2_queue *vq;
- int i;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
@@ -1721,42 +1750,34 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f)
if (!q_data)
return -EINVAL;
+ qpix = &q_data->format.fmt.pix_mp;
q_data->fmt = find_format(f);
- q_data->width = pix->width;
- q_data->height = pix->height;
- q_data->colorspace = pix->colorspace;
- q_data->field = pix->field;
- q_data->nplanes = pix->num_planes;
-
- for (i = 0; i < pix->num_planes; i++) {
- plane_fmt = &pix->plane_fmt[i];
-
- q_data->bytesperline[i] = plane_fmt->bytesperline;
- q_data->sizeimage[i] = plane_fmt->sizeimage;
- }
+ q_data->format = *f;
q_data->c_rect.left = 0;
q_data->c_rect.top = 0;
- q_data->c_rect.width = q_data->width;
- q_data->c_rect.height = q_data->height;
+ q_data->c_rect.width = pix->width;
+ q_data->c_rect.height = pix->height;
- if (q_data->field == V4L2_FIELD_ALTERNATE)
+ if (qpix->field == V4L2_FIELD_ALTERNATE)
q_data->flags |= Q_DATA_INTERLACED_ALTERNATE;
- else if (q_data->field == V4L2_FIELD_SEQ_TB)
+ else if (qpix->field == V4L2_FIELD_SEQ_TB)
q_data->flags |= Q_DATA_INTERLACED_SEQ_TB;
+ else if (qpix->field == V4L2_FIELD_SEQ_BT)
+ q_data->flags |= Q_DATA_INTERLACED_SEQ_BT;
else
q_data->flags &= ~Q_IS_INTERLACED;
- /* the crop height is halved for the case of SEQ_TB buffers */
- if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB)
+ /* the crop height is halved for the case of SEQ_XX buffers */
+ if (q_data->flags & Q_IS_SEQ_XX)
q_data->c_rect.height /= 2;
vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d bpl_y %d",
- f->type, q_data->width, q_data->height, q_data->fmt->fourcc,
- q_data->bytesperline[VPE_LUMA]);
- if (q_data->nplanes == 2)
+ f->type, pix->width, pix->height, pix->pixelformat,
+ pix->plane_fmt[0].bytesperline);
+ if (pix->num_planes == 2)
vpe_dbg(ctx->dev, " bpl_uv %d\n",
- q_data->bytesperline[VPE_CHROMA]);
+ pix->plane_fmt[1].bytesperline);
return 0;
}
@@ -1764,7 +1785,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f)
static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
int ret;
- struct vpe_ctx *ctx = file2ctx(file);
+ struct vpe_ctx *ctx = file->private_data;
ret = vpe_try_fmt(file, priv, f);
if (ret)
@@ -1785,6 +1806,7 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
{
struct vpe_q_data *q_data;
+ struct v4l2_pix_format_mplane *pix;
int height;
if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
@@ -1795,6 +1817,8 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
if (!q_data)
return -EINVAL;
+ pix = &q_data->format.fmt.pix_mp;
+
switch (s->target) {
case V4L2_SEL_TGT_COMPOSE:
/*
@@ -1821,27 +1845,27 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
}
/*
- * For SEQ_TB buffers, crop height should be less than the height of
+ * For SEQ_XX buffers, crop height should be less than the height of
* the field height, not the buffer height
*/
- if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB)
- height = q_data->height / 2;
+ if (q_data->flags & Q_IS_SEQ_XX)
+ height = pix->height / 2;
else
- height = q_data->height;
+ height = pix->height;
if (s->r.top < 0 || s->r.left < 0) {
vpe_err(ctx->dev, "negative values for top and left\n");
s->r.top = s->r.left = 0;
}
- v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1,
+ v4l_bound_align_image(&s->r.width, MIN_W, pix->width, 1,
&s->r.height, MIN_H, height, H_ALIGN, S_ALIGN);
/* adjust left/top if cropping rectangle is out of bounds */
- if (s->r.left + s->r.width > q_data->width)
- s->r.left = q_data->width - s->r.width;
- if (s->r.top + s->r.height > q_data->height)
- s->r.top = q_data->height - s->r.height;
+ if (s->r.left + s->r.width > pix->width)
+ s->r.left = pix->width - s->r.width;
+ if (s->r.top + s->r.height > pix->height)
+ s->r.top = pix->height - s->r.height;
return 0;
}
@@ -1849,8 +1873,9 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
static int vpe_g_selection(struct file *file, void *fh,
struct v4l2_selection *s)
{
- struct vpe_ctx *ctx = file2ctx(file);
+ struct vpe_ctx *ctx = file->private_data;
struct vpe_q_data *q_data;
+ struct v4l2_pix_format_mplane *pix;
bool use_c_rect = false;
if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
@@ -1861,6 +1886,8 @@ static int vpe_g_selection(struct file *file, void *fh,
if (!q_data)
return -EINVAL;
+ pix = &q_data->format.fmt.pix_mp;
+
switch (s->target) {
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
@@ -1899,8 +1926,8 @@ static int vpe_g_selection(struct file *file, void *fh,
*/
s->r.left = 0;
s->r.top = 0;
- s->r.width = q_data->width;
- s->r.height = q_data->height;
+ s->r.width = pix->width;
+ s->r.height = pix->height;
}
return 0;
@@ -1910,7 +1937,7 @@ static int vpe_g_selection(struct file *file, void *fh,
static int vpe_s_selection(struct file *file, void *fh,
struct v4l2_selection *s)
{
- struct vpe_ctx *ctx = file2ctx(file);
+ struct vpe_ctx *ctx = file->private_data;
struct vpe_q_data *q_data;
struct v4l2_selection sel = *s;
int ret;
@@ -2003,17 +2030,21 @@ static int vpe_queue_setup(struct vb2_queue *vq,
int i;
struct vpe_ctx *ctx = vb2_get_drv_priv(vq);
struct vpe_q_data *q_data;
+ struct v4l2_pix_format_mplane *pix;
q_data = get_q_data(ctx, vq->type);
+ if (!q_data)
+ return -EINVAL;
- *nplanes = q_data->nplanes;
+ pix = &q_data->format.fmt.pix_mp;
+ *nplanes = pix->num_planes;
for (i = 0; i < *nplanes; i++)
- sizes[i] = q_data->sizeimage[i];
+ sizes[i] = pix->plane_fmt[i].sizeimage;
vpe_dbg(ctx->dev, "get %d buffer(s) of size %d", *nbuffers,
sizes[VPE_LUMA]);
- if (q_data->nplanes == 2)
+ if (*nplanes == 2)
vpe_dbg(ctx->dev, " and %d\n", sizes[VPE_CHROMA]);
return 0;
@@ -2024,12 +2055,16 @@ static int vpe_buf_prepare(struct vb2_buffer *vb)
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct vpe_q_data *q_data;
- int i, num_planes;
+ struct v4l2_pix_format_mplane *pix;
+ int i;
vpe_dbg(ctx->dev, "type: %d\n", vb->vb2_queue->type);
q_data = get_q_data(ctx, vb->vb2_queue->type);
- num_planes = q_data->nplanes;
+ if (!q_data)
+ return -EINVAL;
+
+ pix = &q_data->format.fmt.pix_mp;
if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
if (!(q_data->flags & Q_IS_INTERLACED)) {
@@ -2037,23 +2072,24 @@ static int vpe_buf_prepare(struct vb2_buffer *vb)
} else {
if (vbuf->field != V4L2_FIELD_TOP &&
vbuf->field != V4L2_FIELD_BOTTOM &&
- vbuf->field != V4L2_FIELD_SEQ_TB)
+ vbuf->field != V4L2_FIELD_SEQ_TB &&
+ vbuf->field != V4L2_FIELD_SEQ_BT)
return -EINVAL;
}
}
- for (i = 0; i < num_planes; i++) {
- if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) {
+ for (i = 0; i < pix->num_planes; i++) {
+ if (vb2_plane_size(vb, i) < pix->plane_fmt[i].sizeimage) {
vpe_err(ctx->dev,
"data will not fit into plane (%lu < %lu)\n",
vb2_plane_size(vb, i),
- (long) q_data->sizeimage[i]);
+ (long)pix->plane_fmt[i].sizeimage);
return -EINVAL;
}
}
- for (i = 0; i < num_planes; i++)
- vb2_set_plane_payload(vb, i, q_data->sizeimage[i]);
+ for (i = 0; i < pix->num_planes; i++)
+ vb2_set_plane_payload(vb, i, pix->plane_fmt[i].sizeimage);
return 0;
}
@@ -2238,6 +2274,7 @@ static int vpe_open(struct file *file)
struct vpe_q_data *s_q_data;
struct v4l2_ctrl_handler *hdl;
struct vpe_ctx *ctx;
+ struct v4l2_pix_format_mplane *pix;
int ret;
vpe_dbg(dev, "vpe_open\n");
@@ -2273,7 +2310,7 @@ static int vpe_open(struct file *file)
init_adb_hdrs(ctx);
v4l2_fh_init(&ctx->fh, video_devdata(file));
- file->private_data = &ctx->fh;
+ file->private_data = ctx;
hdl = &ctx->hdl;
v4l2_ctrl_handler_init(hdl, 1);
@@ -2286,23 +2323,32 @@ static int vpe_open(struct file *file)
v4l2_ctrl_handler_setup(hdl);
s_q_data = &ctx->q_data[Q_DATA_SRC];
- s_q_data->fmt = &vpe_formats[2];
- s_q_data->width = 1920;
- s_q_data->height = 1080;
- s_q_data->nplanes = 1;
- s_q_data->bytesperline[VPE_LUMA] = (s_q_data->width *
+ pix = &s_q_data->format.fmt.pix_mp;
+ s_q_data->fmt = __find_format(V4L2_PIX_FMT_YUYV);
+ pix->pixelformat = s_q_data->fmt->fourcc;
+ s_q_data->format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ pix->width = 1920;
+ pix->height = 1080;
+ pix->num_planes = 1;
+ pix->plane_fmt[VPE_LUMA].bytesperline = (pix->width *
s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3;
- s_q_data->sizeimage[VPE_LUMA] = (s_q_data->bytesperline[VPE_LUMA] *
- s_q_data->height);
- s_q_data->colorspace = V4L2_COLORSPACE_REC709;
- s_q_data->field = V4L2_FIELD_NONE;
+ pix->plane_fmt[VPE_LUMA].sizeimage =
+ pix->plane_fmt[VPE_LUMA].bytesperline *
+ pix->height;
+ pix->colorspace = V4L2_COLORSPACE_REC709;
+ pix->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ pix->quantization = V4L2_QUANTIZATION_DEFAULT;
+ pix->field = V4L2_FIELD_NONE;
s_q_data->c_rect.left = 0;
s_q_data->c_rect.top = 0;
- s_q_data->c_rect.width = s_q_data->width;
- s_q_data->c_rect.height = s_q_data->height;
+ s_q_data->c_rect.width = pix->width;
+ s_q_data->c_rect.height = pix->height;
s_q_data->flags = 0;
ctx->q_data[Q_DATA_DST] = *s_q_data;
+ ctx->q_data[Q_DATA_DST].format.type =
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
set_dei_shadow_registers(ctx);
set_src_registers(ctx);
@@ -2358,12 +2404,18 @@ free_ctx:
static int vpe_release(struct file *file)
{
struct vpe_dev *dev = video_drvdata(file);
- struct vpe_ctx *ctx = file2ctx(file);
+ struct vpe_ctx *ctx = file->private_data;
vpe_dbg(dev, "releasing instance %p\n", ctx);
mutex_lock(&dev->dev_mutex);
free_mv_buffers(ctx);
+
+ vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf);
+ vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb);
+ vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h);
+ vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v);
+
vpdma_free_desc_list(&ctx->desc_list);
vpdma_free_desc_buf(&ctx->mmr_adb);
@@ -2471,6 +2523,13 @@ static int vpe_probe(struct platform_device *pdev)
struct vpe_dev *dev;
int ret, irq, func;
+ ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return ret;
+ }
+
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
@@ -2485,7 +2544,12 @@ static int vpe_probe(struct platform_device *pdev)
mutex_init(&dev->dev_mutex);
dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "vpe_top");
+ "vpe_top");
+ if (!dev->res) {
+ dev_err(&pdev->dev, "missing 'vpe_top' resources data\n");
+ return -ENODEV;
+ }
+
/*
* HACK: we get resource info from device tree in the form of a list of
* VPE sub blocks, the driver currently uses only the base of vpe_top
@@ -2580,7 +2644,7 @@ static int vpe_remove(struct platform_device *pdev)
#if defined(CONFIG_OF)
static const struct of_device_id vpe_of_match[] = {
{
- .compatible = "ti,vpe",
+ .compatible = "ti,dra7-vpe",
},
{},
};
diff --git a/drivers/media/platform/ti-vpe/vpe_regs.h b/drivers/media/platform/ti-vpe/vpe_regs.h
index 9969bea0dded..1a1ad5ae1228 100644
--- a/drivers/media/platform/ti-vpe/vpe_regs.h
+++ b/drivers/media/platform/ti-vpe/vpe_regs.h
@@ -48,24 +48,24 @@
#define VPE_INT0_ENABLE0_SET 0x0030
#define VPE_INT0_ENABLE0 VPE_INT0_ENABLE0_SET
#define VPE_INT0_ENABLE0_CLR 0x0038
-#define VPE_INT0_LIST0_COMPLETE (1 << 0)
-#define VPE_INT0_LIST0_NOTIFY (1 << 1)
-#define VPE_INT0_LIST1_COMPLETE (1 << 2)
-#define VPE_INT0_LIST1_NOTIFY (1 << 3)
-#define VPE_INT0_LIST2_COMPLETE (1 << 4)
-#define VPE_INT0_LIST2_NOTIFY (1 << 5)
-#define VPE_INT0_LIST3_COMPLETE (1 << 6)
-#define VPE_INT0_LIST3_NOTIFY (1 << 7)
-#define VPE_INT0_LIST4_COMPLETE (1 << 8)
-#define VPE_INT0_LIST4_NOTIFY (1 << 9)
-#define VPE_INT0_LIST5_COMPLETE (1 << 10)
-#define VPE_INT0_LIST5_NOTIFY (1 << 11)
-#define VPE_INT0_LIST6_COMPLETE (1 << 12)
-#define VPE_INT0_LIST6_NOTIFY (1 << 13)
-#define VPE_INT0_LIST7_COMPLETE (1 << 14)
-#define VPE_INT0_LIST7_NOTIFY (1 << 15)
-#define VPE_INT0_DESCRIPTOR (1 << 16)
-#define VPE_DEI_FMD_INT (1 << 18)
+#define VPE_INT0_LIST0_COMPLETE BIT(0)
+#define VPE_INT0_LIST0_NOTIFY BIT(1)
+#define VPE_INT0_LIST1_COMPLETE BIT(2)
+#define VPE_INT0_LIST1_NOTIFY BIT(3)
+#define VPE_INT0_LIST2_COMPLETE BIT(4)
+#define VPE_INT0_LIST2_NOTIFY BIT(5)
+#define VPE_INT0_LIST3_COMPLETE BIT(6)
+#define VPE_INT0_LIST3_NOTIFY BIT(7)
+#define VPE_INT0_LIST4_COMPLETE BIT(8)
+#define VPE_INT0_LIST4_NOTIFY BIT(9)
+#define VPE_INT0_LIST5_COMPLETE BIT(10)
+#define VPE_INT0_LIST5_NOTIFY BIT(11)
+#define VPE_INT0_LIST6_COMPLETE BIT(12)
+#define VPE_INT0_LIST6_NOTIFY BIT(13)
+#define VPE_INT0_LIST7_COMPLETE BIT(14)
+#define VPE_INT0_LIST7_NOTIFY BIT(15)
+#define VPE_INT0_DESCRIPTOR BIT(16)
+#define VPE_DEI_FMD_INT BIT(18)
#define VPE_INT0_STATUS1_RAW_SET 0x0024
#define VPE_INT0_STATUS1_RAW VPE_INT0_STATUS1_RAW_SET
@@ -74,21 +74,21 @@
#define VPE_INT0_ENABLE1_SET 0x0034
#define VPE_INT0_ENABLE1 VPE_INT0_ENABLE1_SET
#define VPE_INT0_ENABLE1_CLR 0x003c
-#define VPE_INT0_CHANNEL_GROUP0 (1 << 0)
-#define VPE_INT0_CHANNEL_GROUP1 (1 << 1)
-#define VPE_INT0_CHANNEL_GROUP2 (1 << 2)
-#define VPE_INT0_CHANNEL_GROUP3 (1 << 3)
-#define VPE_INT0_CHANNEL_GROUP4 (1 << 4)
-#define VPE_INT0_CHANNEL_GROUP5 (1 << 5)
-#define VPE_INT0_CLIENT (1 << 7)
-#define VPE_DEI_ERROR_INT (1 << 16)
-#define VPE_DS1_UV_ERROR_INT (1 << 22)
+#define VPE_INT0_CHANNEL_GROUP0 BIT(0)
+#define VPE_INT0_CHANNEL_GROUP1 BIT(1)
+#define VPE_INT0_CHANNEL_GROUP2 BIT(2)
+#define VPE_INT0_CHANNEL_GROUP3 BIT(3)
+#define VPE_INT0_CHANNEL_GROUP4 BIT(4)
+#define VPE_INT0_CHANNEL_GROUP5 BIT(5)
+#define VPE_INT0_CLIENT BIT(7)
+#define VPE_DEI_ERROR_INT BIT(16)
+#define VPE_DS1_UV_ERROR_INT BIT(22)
#define VPE_INTC_EOI 0x00a0
#define VPE_CLK_ENABLE 0x0100
-#define VPE_VPEDMA_CLK_ENABLE (1 << 0)
-#define VPE_DATA_PATH_CLK_ENABLE (1 << 1)
+#define VPE_VPEDMA_CLK_ENABLE BIT(0)
+#define VPE_DATA_PATH_CLK_ENABLE BIT(1)
#define VPE_CLK_RESET 0x0104
#define VPE_VPDMA_CLK_RESET_MASK 0x1
@@ -101,11 +101,11 @@
#define VPE_CLK_FORMAT_SELECT 0x010c
#define VPE_CSC_SRC_SELECT_MASK 0x03
#define VPE_CSC_SRC_SELECT_SHIFT 0
-#define VPE_RGB_OUT_SELECT (1 << 8)
+#define VPE_RGB_OUT_SELECT BIT(8)
#define VPE_DS_SRC_SELECT_MASK 0x07
#define VPE_DS_SRC_SELECT_SHIFT 9
-#define VPE_DS_BYPASS (1 << 16)
-#define VPE_COLOR_SEPARATE_422 (1 << 18)
+#define VPE_DS_BYPASS BIT(16)
+#define VPE_COLOR_SEPARATE_422 BIT(18)
#define VPE_DS_SRC_DEI_SCALER (5 << VPE_DS_SRC_SELECT_SHIFT)
#define VPE_CSC_SRC_DEI_SCALER (3 << VPE_CSC_SRC_SELECT_SHIFT)
@@ -115,8 +115,8 @@
#define VPE_RANGE_RANGE_MAP_Y_SHIFT 0
#define VPE_RANGE_RANGE_MAP_UV_MASK 0x07
#define VPE_RANGE_RANGE_MAP_UV_SHIFT 3
-#define VPE_RANGE_MAP_ON (1 << 6)
-#define VPE_RANGE_REDUCTION_ON (1 << 28)
+#define VPE_RANGE_MAP_ON BIT(6)
+#define VPE_RANGE_REDUCTION_ON BIT(28)
/* VPE chrominance upsampler regs */
#define VPE_US1_R0 0x0304
@@ -195,13 +195,13 @@
#define VPE_DEI_WIDTH_SHIFT 0
#define VPE_DEI_HEIGHT_MASK 0x07ff
#define VPE_DEI_HEIGHT_SHIFT 16
-#define VPE_DEI_INTERLACE_BYPASS (1 << 29)
-#define VPE_DEI_FIELD_FLUSH (1 << 30)
-#define VPE_DEI_PROGRESSIVE (1 << 31)
+#define VPE_DEI_INTERLACE_BYPASS BIT(29)
+#define VPE_DEI_FIELD_FLUSH BIT(30)
+#define VPE_DEI_PROGRESSIVE BIT(31)
#define VPE_MDT_BYPASS 0x0604
-#define VPE_MDT_TEMPMAX_BYPASS (1 << 0)
-#define VPE_MDT_SPATMAX_BYPASS (1 << 1)
+#define VPE_MDT_TEMPMAX_BYPASS BIT(0)
+#define VPE_MDT_SPATMAX_BYPASS BIT(1)
#define VPE_MDT_SF_THRESHOLD 0x0608
#define VPE_MDT_SF_SC_THR1_MASK 0xff
@@ -214,8 +214,8 @@
#define VPE_EDI_CONFIG 0x060c
#define VPE_EDI_INP_MODE_MASK 0x03
#define VPE_EDI_INP_MODE_SHIFT 0
-#define VPE_EDI_ENABLE_3D (1 << 2)
-#define VPE_EDI_ENABLE_CHROMA_3D (1 << 3)
+#define VPE_EDI_ENABLE_3D BIT(2)
+#define VPE_EDI_ENABLE_CHROMA_3D BIT(3)
#define VPE_EDI_CHROMA3D_COR_THR_MASK 0xff
#define VPE_EDI_CHROMA3D_COR_THR_SHIFT 8
#define VPE_EDI_DIR_COR_LOWER_THR_MASK 0xff
@@ -268,7 +268,7 @@
#define VPE_FMD_WINDOW_MINX_SHIFT 0
#define VPE_FMD_WINDOW_MAXX_MASK 0x07ff
#define VPE_FMD_WINDOW_MAXX_SHIFT 16
-#define VPE_FMD_WINDOW_ENABLE (1 << 31)
+#define VPE_FMD_WINDOW_ENABLE BIT(31)
#define VPE_DEI_FMD_WINDOW_R1 0x0624
#define VPE_FMD_WINDOW_MINY_MASK 0x07ff
@@ -277,10 +277,10 @@
#define VPE_FMD_WINDOW_MAXY_SHIFT 16
#define VPE_DEI_FMD_CONTROL_R0 0x0628
-#define VPE_FMD_ENABLE (1 << 0)
-#define VPE_FMD_LOCK (1 << 1)
-#define VPE_FMD_JAM_DIR (1 << 2)
-#define VPE_FMD_BED_ENABLE (1 << 3)
+#define VPE_FMD_ENABLE BIT(0)
+#define VPE_FMD_LOCK BIT(1)
+#define VPE_FMD_JAM_DIR BIT(2)
+#define VPE_FMD_BED_ENABLE BIT(3)
#define VPE_FMD_CAF_FIELD_THR_MASK 0xff
#define VPE_FMD_CAF_FIELD_THR_SHIFT 16
#define VPE_FMD_CAF_LINE_THR_MASK 0xff
@@ -293,7 +293,7 @@
#define VPE_DEI_FMD_STATUS_R0 0x0630
#define VPE_FMD_CAF_MASK 0x000fffff
#define VPE_FMD_CAF_SHIFT 0
-#define VPE_FMD_RESET (1 << 24)
+#define VPE_FMD_RESET BIT(24)
#define VPE_DEI_FMD_STATUS_R1 0x0634
#define VPE_FMD_FIELD_DIFF_MASK 0x0fffffff
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index 038de7a2027a..78841b9015ce 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -18,9 +18,10 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-image-sizes.h>
#include <media/i2c/ov7670.h>
-#include <media/videobuf-dma-sg.h>
+#include <media/videobuf2-dma-sg.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/pm_qos.h>
@@ -84,16 +85,11 @@ struct via_camera {
* live in frame buffer memory, so we don't call them "DMA".
*/
unsigned int cb_offsets[3]; /* offsets into fb mem */
- u8 __iomem *cb_addrs[3]; /* Kernel-space addresses */
+ u8 __iomem *cb_addrs[3]; /* Kernel-space addresses */
int n_cap_bufs; /* How many are we using? */
- int next_buf;
- struct videobuf_queue vb_queue;
- struct list_head buffer_queue; /* prot. by reg_lock */
- /*
- * User tracking.
- */
- int users;
- struct file *owner;
+ struct vb2_queue vq;
+ struct list_head buffer_queue;
+ u32 sequence;
/*
* Video format information. sensor_format is kept in a form
* that we can use to pass to the sensor. We always run the
@@ -106,6 +102,13 @@ struct via_camera {
u32 mbus_code;
};
+/* buffer for one video frame */
+struct via_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct vb2_v4l2_buffer vbuf;
+ struct list_head queue;
+};
+
/*
* Yes, this is a hack, but there's only going to be one of these
* on any system we know of.
@@ -142,13 +145,11 @@ static struct via_camera *via_cam_info;
* now this information must be managed at this level too.
*/
static struct via_format {
- __u8 *desc;
__u32 pixelformat;
int bpp; /* Bytes per pixel */
u32 mbus_code;
} via_formats[] = {
{
- .desc = "YUYV 4:2:2",
.pixelformat = V4L2_PIX_FMT_YUYV,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
@@ -324,28 +325,15 @@ static irqreturn_t viacam_quick_irq(int irq, void *data)
}
/*
- * Find the next videobuf buffer which has somebody waiting on it.
+ * Find the next buffer which has somebody waiting on it.
*/
-static struct videobuf_buffer *viacam_next_buffer(struct via_camera *cam)
+static struct via_buffer *viacam_next_buffer(struct via_camera *cam)
{
- unsigned long flags;
- struct videobuf_buffer *buf = NULL;
-
- spin_lock_irqsave(&cam->viadev->reg_lock, flags);
if (cam->opstate != S_RUNNING)
- goto out;
+ return NULL;
if (list_empty(&cam->buffer_queue))
- goto out;
- buf = list_entry(cam->buffer_queue.next, struct videobuf_buffer, queue);
- if (!waitqueue_active(&buf->done)) {/* Nobody waiting */
- buf = NULL;
- goto out;
- }
- list_del(&buf->queue);
- buf->state = VIDEOBUF_ACTIVE;
-out:
- spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
- return buf;
+ return NULL;
+ return list_entry(cam->buffer_queue.next, struct via_buffer, queue);
}
/*
@@ -353,11 +341,12 @@ out:
*/
static irqreturn_t viacam_irq(int irq, void *data)
{
- int bufn;
- struct videobuf_buffer *vb;
struct via_camera *cam = data;
- struct videobuf_dmabuf *vdma;
+ struct via_buffer *vb;
+ int bufn;
+ struct sg_table *sgt;
+ mutex_lock(&cam->lock);
/*
* If there is no place to put the data frame, don't bother
* with anything else.
@@ -375,12 +364,15 @@ static irqreturn_t viacam_irq(int irq, void *data)
/*
* Copy over the data and let any waiters know.
*/
- vdma = videobuf_to_dma(vb);
- viafb_dma_copy_out_sg(cam->cb_offsets[bufn], vdma->sglist, vdma->sglen);
- vb->state = VIDEOBUF_DONE;
- vb->size = cam->user_format.sizeimage;
- wake_up(&vb->done);
+ sgt = vb2_dma_sg_plane_desc(&vb->vbuf.vb2_buf, 0);
+ vb->vbuf.vb2_buf.timestamp = ktime_get_ns();
+ viafb_dma_copy_out_sg(cam->cb_offsets[bufn], sgt->sgl, sgt->nents);
+ vb->vbuf.sequence = cam->sequence++;
+ vb->vbuf.field = V4L2_FIELD_NONE;
+ list_del(&vb->queue);
+ vb2_buffer_done(&vb->vbuf.vb2_buf, VB2_BUF_STATE_DONE);
done:
+ mutex_unlock(&cam->lock);
return IRQ_HANDLED;
}
@@ -556,7 +548,6 @@ static int viacam_config_controller(struct via_camera *cam)
static void viacam_start_engine(struct via_camera *cam)
{
spin_lock_irq(&cam->viadev->reg_lock);
- cam->next_buf = 0;
viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_ENABLE, VCR_CI_ENABLE);
viacam_int_enable(cam);
(void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
@@ -577,81 +568,117 @@ static void viacam_stop_engine(struct via_camera *cam)
/* --------------------------------------------------------------------------*/
-/* Videobuf callback ops */
+/* vb2 callback ops */
-/*
- * buffer_setup. The purpose of this one would appear to be to tell
- * videobuf how big a single image is. It's also evidently up to us
- * to put some sort of limit on the maximum number of buffers allowed.
- */
-static int viacam_vb_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
+static struct via_buffer *vb2_to_via_buffer(struct vb2_buffer *vb)
{
- struct via_camera *cam = q->priv_data;
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- *size = cam->user_format.sizeimage;
- if (*count == 0 || *count > 6) /* Arbitrary number */
- *count = 6;
- return 0;
+ return container_of(vbuf, struct via_buffer, vbuf);
}
-/*
- * Prepare a buffer.
- */
-static int viacam_vb_buf_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
+static void viacam_vb2_queue(struct vb2_buffer *vb)
{
- struct via_camera *cam = q->priv_data;
-
- vb->size = cam->user_format.sizeimage;
- vb->width = cam->user_format.width; /* bytesperline???? */
- vb->height = cam->user_format.height;
- vb->field = field;
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- int ret = videobuf_iolock(q, vb, NULL);
- if (ret)
- return ret;
+ struct via_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+ struct via_buffer *via = vb2_to_via_buffer(vb);
+
+ list_add_tail(&via->queue, &cam->buffer_queue);
+}
+
+static int viacam_vb2_prepare(struct vb2_buffer *vb)
+{
+ struct via_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (vb2_plane_size(vb, 0) < cam->user_format.sizeimage) {
+ cam_dbg(cam,
+ "Plane size too small (%lu < %u)\n",
+ vb2_plane_size(vb, 0),
+ cam->user_format.sizeimage);
+ return -EINVAL;
}
- vb->state = VIDEOBUF_PREPARED;
+
+ vb2_set_plane_payload(vb, 0, cam->user_format.sizeimage);
+
return 0;
}
-/*
- * We've got a buffer to put data into.
- *
- * FIXME: check for a running engine and valid buffers?
- */
-static void viacam_vb_buf_queue(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
+static int viacam_vb2_queue_setup(struct vb2_queue *vq,
+ unsigned int *nbufs,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
{
- struct via_camera *cam = q->priv_data;
+ struct via_camera *cam = vb2_get_drv_priv(vq);
+ int size = cam->user_format.sizeimage;
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *num_planes = 1;
+ sizes[0] = size;
+ return 0;
+}
+
+static int viacam_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct via_camera *cam = vb2_get_drv_priv(vq);
+ struct via_buffer *buf, *tmp;
+ int ret = 0;
+
+ if (cam->opstate != S_IDLE) {
+ ret = -EBUSY;
+ goto out;
+ }
+ /*
+ * Configure things if need be.
+ */
+ if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+ ret = viacam_configure_sensor(cam);
+ if (ret)
+ goto out;
+ ret = viacam_config_controller(cam);
+ if (ret)
+ goto out;
+ }
+ cam->sequence = 0;
/*
- * Note that videobuf holds the lock when it calls
- * us, so we need not (indeed, cannot) take it here.
+ * If the CPU goes into C3, the DMA transfer gets corrupted and
+ * users start filing unsightly bug reports. Put in a "latency"
+ * requirement which will keep the CPU out of the deeper sleep
+ * states.
*/
- vb->state = VIDEOBUF_QUEUED;
- list_add_tail(&vb->queue, &cam->buffer_queue);
+ pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50);
+ viacam_start_engine(cam);
+ return 0;
+out:
+ list_for_each_entry_safe(buf, tmp, &cam->buffer_queue, queue) {
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED);
+ }
+ return ret;
}
-/*
- * Free a buffer.
- */
-static void viacam_vb_buf_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
+static void viacam_vb2_stop_streaming(struct vb2_queue *vq)
{
- struct via_camera *cam = q->priv_data;
+ struct via_camera *cam = vb2_get_drv_priv(vq);
+ struct via_buffer *buf, *tmp;
- videobuf_dma_unmap(&cam->platdev->dev, videobuf_to_dma(vb));
- videobuf_dma_free(videobuf_to_dma(vb));
- vb->state = VIDEOBUF_NEEDS_INIT;
+ pm_qos_remove_request(&cam->qos_request);
+ viacam_stop_engine(cam);
+
+ list_for_each_entry_safe(buf, tmp, &cam->buffer_queue, queue) {
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
}
-static const struct videobuf_queue_ops viacam_vb_ops = {
- .buf_setup = viacam_vb_buf_setup,
- .buf_prepare = viacam_vb_buf_prepare,
- .buf_queue = viacam_vb_buf_queue,
- .buf_release = viacam_vb_buf_release,
+static const struct vb2_ops viacam_vb2_ops = {
+ .queue_setup = viacam_vb2_queue_setup,
+ .buf_queue = viacam_vb2_queue,
+ .buf_prepare = viacam_vb2_prepare,
+ .start_streaming = viacam_vb2_start_streaming,
+ .stop_streaming = viacam_vb2_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
/* --------------------------------------------------------------------------*/
@@ -660,62 +687,43 @@ static const struct videobuf_queue_ops viacam_vb_ops = {
static int viacam_open(struct file *filp)
{
struct via_camera *cam = video_drvdata(filp);
+ int ret;
- filp->private_data = cam;
/*
* Note the new user. If this is the first one, we'll also
* need to power up the sensor.
*/
mutex_lock(&cam->lock);
- if (cam->users == 0) {
- int ret = viafb_request_dma();
+ ret = v4l2_fh_open(filp);
+ if (ret)
+ goto out;
+ if (v4l2_fh_is_singular_file(filp)) {
+ ret = viafb_request_dma();
if (ret) {
- mutex_unlock(&cam->lock);
- return ret;
+ v4l2_fh_release(filp);
+ goto out;
}
via_sensor_power_up(cam);
set_bit(CF_CONFIG_NEEDED, &cam->flags);
- /*
- * Hook into videobuf. Evidently this cannot fail.
- */
- videobuf_queue_sg_init(&cam->vb_queue, &viacam_vb_ops,
- &cam->platdev->dev, &cam->viadev->reg_lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), cam, NULL);
}
- (cam->users)++;
+out:
mutex_unlock(&cam->lock);
- return 0;
+ return ret;
}
static int viacam_release(struct file *filp)
{
struct via_camera *cam = video_drvdata(filp);
+ bool last_open;
mutex_lock(&cam->lock);
- (cam->users)--;
- /*
- * If the "owner" is closing, shut down any ongoing
- * operations.
- */
- if (filp == cam->owner) {
- videobuf_stop(&cam->vb_queue);
- /*
- * We don't hold the spinlock here, but, if release()
- * is being called by the owner, nobody else will
- * be changing the state. And an extra stop would
- * not hurt anyway.
- */
- if (cam->opstate != S_IDLE)
- viacam_stop_engine(cam);
- cam->owner = NULL;
- }
+ last_open = v4l2_fh_is_singular_file(filp);
+ _vb2_fop_release(filp, NULL);
/*
* Last one out needs to turn out the lights.
*/
- if (cam->users == 0) {
- videobuf_mmap_free(&cam->vb_queue);
+ if (last_open) {
via_sensor_power_down(cam);
viafb_release_dma();
}
@@ -723,77 +731,14 @@ static int viacam_release(struct file *filp)
return 0;
}
-/*
- * Read a frame from the device.
- */
-static ssize_t viacam_read(struct file *filp, char __user *buffer,
- size_t len, loff_t *pos)
-{
- struct via_camera *cam = video_drvdata(filp);
- int ret;
-
- mutex_lock(&cam->lock);
- /*
- * Enforce the V4l2 "only one owner gets to read data" rule.
- */
- if (cam->owner && cam->owner != filp) {
- ret = -EBUSY;
- goto out_unlock;
- }
- cam->owner = filp;
- /*
- * Do we need to configure the hardware?
- */
- if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
- ret = viacam_configure_sensor(cam);
- if (!ret)
- ret = viacam_config_controller(cam);
- if (ret)
- goto out_unlock;
- }
- /*
- * Fire up the capture engine, then have videobuf do
- * the heavy lifting. Someday it would be good to avoid
- * stopping and restarting the engine each time.
- */
- INIT_LIST_HEAD(&cam->buffer_queue);
- viacam_start_engine(cam);
- ret = videobuf_read_stream(&cam->vb_queue, buffer, len, pos, 0,
- filp->f_flags & O_NONBLOCK);
- viacam_stop_engine(cam);
- /* videobuf_stop() ?? */
-
-out_unlock:
- mutex_unlock(&cam->lock);
- return ret;
-}
-
-
-static __poll_t viacam_poll(struct file *filp, struct poll_table_struct *pt)
-{
- struct via_camera *cam = video_drvdata(filp);
-
- return videobuf_poll_stream(filp, &cam->vb_queue, pt);
-}
-
-
-static int viacam_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct via_camera *cam = video_drvdata(filp);
-
- return videobuf_mmap_mapper(&cam->vb_queue, vma);
-}
-
-
-
static const struct v4l2_file_operations viacam_fops = {
.owner = THIS_MODULE,
.open = viacam_open,
.release = viacam_release,
- .read = viacam_read,
- .poll = viacam_poll,
- .mmap = viacam_mmap,
- .unlocked_ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
};
/*----------------------------------------------------------------------------*/
@@ -811,7 +756,6 @@ static int viacam_enum_input(struct file *filp, void *priv,
return -EINVAL;
input->type = V4L2_INPUT_TYPE_CAMERA;
- input->std = V4L2_STD_ALL; /* Not sure what should go here */
strscpy(input->name, "Camera", sizeof(input->name));
return 0;
}
@@ -829,17 +773,6 @@ static int viacam_s_input(struct file *filp, void *priv, unsigned int i)
return 0;
}
-static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id std)
-{
- return 0;
-}
-
-static int viacam_g_std(struct file *filp, void *priv, v4l2_std_id *std)
-{
- *std = V4L2_STD_NTSC_M;
- return 0;
-}
-
/*
* Video format stuff. Here is our default format until
* user space messes with things.
@@ -851,6 +784,7 @@ static const struct v4l2_pix_format viacam_def_pix_format = {
.field = V4L2_FIELD_NONE,
.bytesperline = VGA_WIDTH * 2,
.sizeimage = VGA_WIDTH * VGA_HEIGHT * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
};
static const u32 via_def_mbus_code = MEDIA_BUS_FMT_YUYV8_2X8;
@@ -860,8 +794,6 @@ static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv,
{
if (fmt->index >= N_VIA_FMTS)
return -EINVAL;
- strscpy(fmt->description, via_formats[fmt->index].desc,
- sizeof(fmt->description));
fmt->pixelformat = via_formats[fmt->index].pixelformat;
return 0;
}
@@ -897,6 +829,10 @@ static void viacam_fmt_post(struct v4l2_pix_format *userfmt,
userfmt->field = sensorfmt->field;
userfmt->bytesperline = 2 * userfmt->width;
userfmt->sizeimage = userfmt->bytesperline * userfmt->height;
+ userfmt->colorspace = sensorfmt->colorspace;
+ userfmt->ycbcr_enc = sensorfmt->ycbcr_enc;
+ userfmt->quantization = sensorfmt->quantization;
+ userfmt->xfer_func = sensorfmt->xfer_func;
}
@@ -927,32 +863,26 @@ static int viacam_do_try_fmt(struct via_camera *cam,
static int viacam_try_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *fmt)
{
- struct via_camera *cam = priv;
+ struct via_camera *cam = video_drvdata(filp);
struct v4l2_format sfmt;
- int ret;
- mutex_lock(&cam->lock);
- ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix);
- mutex_unlock(&cam->lock);
- return ret;
+ return viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix);
}
static int viacam_g_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *fmt)
{
- struct via_camera *cam = priv;
+ struct via_camera *cam = video_drvdata(filp);
- mutex_lock(&cam->lock);
fmt->fmt.pix = cam->user_format;
- mutex_unlock(&cam->lock);
return 0;
}
static int viacam_s_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *fmt)
{
- struct via_camera *cam = priv;
+ struct via_camera *cam = video_drvdata(filp);
int ret;
struct v4l2_format sfmt;
struct via_format *f = via_find_format(fmt->fmt.pix.pixelformat);
@@ -961,18 +891,15 @@ static int viacam_s_fmt_vid_cap(struct file *filp, void *priv,
* Camera must be idle or we can't mess with the
* video setup.
*/
- mutex_lock(&cam->lock);
- if (cam->opstate != S_IDLE) {
- ret = -EBUSY;
- goto out;
- }
+ if (cam->opstate != S_IDLE)
+ return -EBUSY;
/*
* Let the sensor code look over and tweak the
* requested formatting.
*/
ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix);
if (ret)
- goto out;
+ return ret;
/*
* OK, let's commit to the new format.
*/
@@ -982,8 +909,6 @@ static int viacam_s_fmt_vid_cap(struct file *filp, void *priv,
ret = viacam_configure_sensor(cam);
if (!ret)
ret = viacam_config_controller(cam);
-out:
- mutex_unlock(&cam->lock);
return ret;
}
@@ -992,155 +917,40 @@ static int viacam_querycap(struct file *filp, void *priv,
{
strscpy(cap->driver, "via-camera", sizeof(cap->driver));
strscpy(cap->card, "via-camera", sizeof(cap->card));
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+ strscpy(cap->bus_info, "platform:via-camera", sizeof(cap->bus_info));
return 0;
}
-/*
- * Streaming operations - pure videobuf stuff.
- */
-static int viacam_reqbufs(struct file *filp, void *priv,
- struct v4l2_requestbuffers *rb)
-{
- struct via_camera *cam = priv;
-
- return videobuf_reqbufs(&cam->vb_queue, rb);
-}
-
-static int viacam_querybuf(struct file *filp, void *priv,
- struct v4l2_buffer *buf)
-{
- struct via_camera *cam = priv;
-
- return videobuf_querybuf(&cam->vb_queue, buf);
-}
-
-static int viacam_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
-{
- struct via_camera *cam = priv;
-
- return videobuf_qbuf(&cam->vb_queue, buf);
-}
-
-static int viacam_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
-{
- struct via_camera *cam = priv;
-
- return videobuf_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK);
-}
-
-static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
-{
- struct via_camera *cam = priv;
- int ret = 0;
-
- if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- mutex_lock(&cam->lock);
- if (cam->opstate != S_IDLE) {
- ret = -EBUSY;
- goto out;
- }
- /*
- * Enforce the V4l2 "only one owner gets to read data" rule.
- */
- if (cam->owner && cam->owner != filp) {
- ret = -EBUSY;
- goto out;
- }
- cam->owner = filp;
- /*
- * Configure things if need be.
- */
- if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
- ret = viacam_configure_sensor(cam);
- if (ret)
- goto out;
- ret = viacam_config_controller(cam);
- if (ret)
- goto out;
- }
- /*
- * If the CPU goes into C3, the DMA transfer gets corrupted and
- * users start filing unsightly bug reports. Put in a "latency"
- * requirement which will keep the CPU out of the deeper sleep
- * states.
- */
- pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50);
- /*
- * Fire things up.
- */
- INIT_LIST_HEAD(&cam->buffer_queue);
- ret = videobuf_streamon(&cam->vb_queue);
- if (!ret)
- viacam_start_engine(cam);
-out:
- mutex_unlock(&cam->lock);
- return ret;
-}
-
-static int viacam_streamoff(struct file *filp, void *priv, enum v4l2_buf_type t)
-{
- struct via_camera *cam = priv;
- int ret;
-
- if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- mutex_lock(&cam->lock);
- if (cam->opstate != S_RUNNING) {
- ret = -EINVAL;
- goto out;
- }
- pm_qos_remove_request(&cam->qos_request);
- viacam_stop_engine(cam);
- /*
- * Videobuf will recycle all of the outstanding buffers, but
- * we should be sure we don't retain any references to
- * any of them.
- */
- ret = videobuf_streamoff(&cam->vb_queue);
- INIT_LIST_HEAD(&cam->buffer_queue);
-out:
- mutex_unlock(&cam->lock);
- return ret;
-}
-
/* G/S_PARM */
static int viacam_g_parm(struct file *filp, void *priv,
struct v4l2_streamparm *parm)
{
- struct via_camera *cam = priv;
- int ret;
+ struct via_camera *cam = video_drvdata(filp);
- mutex_lock(&cam->lock);
- ret = v4l2_g_parm_cap(video_devdata(filp), cam->sensor, parm);
- mutex_unlock(&cam->lock);
- parm->parm.capture.readbuffers = cam->n_cap_bufs;
- return ret;
+ return v4l2_g_parm_cap(video_devdata(filp), cam->sensor, parm);
}
static int viacam_s_parm(struct file *filp, void *priv,
struct v4l2_streamparm *parm)
{
- struct via_camera *cam = priv;
- int ret;
+ struct via_camera *cam = video_drvdata(filp);
- mutex_lock(&cam->lock);
- ret = v4l2_s_parm_cap(video_devdata(filp), cam->sensor, parm);
- mutex_unlock(&cam->lock);
- parm->parm.capture.readbuffers = cam->n_cap_bufs;
- return ret;
+ return v4l2_s_parm_cap(video_devdata(filp), cam->sensor, parm);
}
static int viacam_enum_framesizes(struct file *filp, void *priv,
struct v4l2_frmsizeenum *sizes)
{
+ unsigned int i;
+
if (sizes->index != 0)
return -EINVAL;
+ for (i = 0; i < N_VIA_FMTS; i++)
+ if (sizes->pixel_format == via_formats[i].pixelformat)
+ break;
+ if (i >= N_VIA_FMTS)
+ return -EINVAL;
sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
sizes->stepwise.min_width = QCIF_WIDTH;
sizes->stepwise.min_height = QCIF_HEIGHT;
@@ -1153,7 +963,7 @@ static int viacam_enum_framesizes(struct file *filp, void *priv,
static int viacam_enum_frameintervals(struct file *filp, void *priv,
struct v4l2_frmivalenum *interval)
{
- struct via_camera *cam = priv;
+ struct via_camera *cam = video_drvdata(filp);
struct v4l2_subdev_frame_interval_enum fie = {
.index = interval->index,
.code = cam->mbus_code,
@@ -1161,11 +971,18 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv,
.height = cam->sensor_format.height,
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
};
+ unsigned int i;
int ret;
- mutex_lock(&cam->lock);
+ for (i = 0; i < N_VIA_FMTS; i++)
+ if (interval->pixel_format == via_formats[i].pixelformat)
+ break;
+ if (i >= N_VIA_FMTS)
+ return -EINVAL;
+ if (interval->width < QCIF_WIDTH || interval->width > VGA_WIDTH ||
+ interval->height < QCIF_HEIGHT || interval->height > VGA_HEIGHT)
+ return -EINVAL;
ret = sensor_call(cam, pad, enum_frame_interval, NULL, &fie);
- mutex_unlock(&cam->lock);
if (ret)
return ret;
interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
@@ -1173,29 +990,30 @@ static int viacam_enum_frameintervals(struct file *filp, void *priv,
return 0;
}
-
-
static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
.vidioc_enum_input = viacam_enum_input,
.vidioc_g_input = viacam_g_input,
.vidioc_s_input = viacam_s_input,
- .vidioc_s_std = viacam_s_std,
- .vidioc_g_std = viacam_g_std,
.vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = viacam_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = viacam_s_fmt_vid_cap,
.vidioc_querycap = viacam_querycap,
- .vidioc_reqbufs = viacam_reqbufs,
- .vidioc_querybuf = viacam_querybuf,
- .vidioc_qbuf = viacam_qbuf,
- .vidioc_dqbuf = viacam_dqbuf,
- .vidioc_streamon = viacam_streamon,
- .vidioc_streamoff = viacam_streamoff,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_parm = viacam_g_parm,
.vidioc_s_parm = viacam_s_parm,
.vidioc_enum_framesizes = viacam_enum_framesizes,
.vidioc_enum_frameintervals = viacam_enum_frameintervals,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/*----------------------------------------------------------------------------*/
@@ -1233,7 +1051,7 @@ static int viacam_resume(void *priv)
/*
* Make sure the sensor's power state is correct
*/
- if (cam->users > 0)
+ if (!list_empty(&cam->vdev.fh_list))
via_sensor_power_up(cam);
else
via_sensor_power_down(cam);
@@ -1267,10 +1085,11 @@ static struct viafb_pm_hooks viacam_pm_hooks = {
static const struct video_device viacam_v4l_template = {
.name = "via-camera",
.minor = -1,
- .tvnorms = V4L2_STD_NTSC_M,
.fops = &viacam_fops,
.ioctl_ops = &viacam_ioctl_ops,
.release = video_device_release_empty, /* Check this */
+ .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING,
};
/*
@@ -1317,6 +1136,7 @@ static int viacam_probe(struct platform_device *pdev)
int ret;
struct i2c_adapter *sensor_adapter;
struct viafb_dev *viadev = pdev->dev.platform_data;
+ struct vb2_queue *vq;
struct i2c_board_info ov7670_info = {
.type = "ov7670",
.addr = 0x42 >> 1,
@@ -1360,8 +1180,6 @@ static int viacam_probe(struct platform_device *pdev)
via_cam_info = cam;
cam->platdev = pdev;
cam->viadev = viadev;
- cam->users = 0;
- cam->owner = NULL;
cam->opstate = S_IDLE;
cam->user_format = cam->sensor_format = viacam_def_pix_format;
mutex_init(&cam->lock);
@@ -1422,15 +1240,31 @@ static int viacam_probe(struct platform_device *pdev)
viacam_irq, IRQF_SHARED, "via-camera", cam);
if (ret)
goto out_power_down;
+
+ vq = &cam->vq;
+ vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+ vq->drv_priv = cam;
+ vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ vq->buf_struct_size = sizeof(struct via_buffer);
+ vq->dev = cam->v4l2_dev.dev;
+
+ vq->ops = &viacam_vb2_ops;
+ vq->mem_ops = &vb2_dma_sg_memops;
+ vq->lock = &cam->lock;
+
+ ret = vb2_queue_init(vq);
/*
* Tell V4l2 that we exist.
*/
cam->vdev = viacam_v4l_template;
cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ cam->vdev.lock = &cam->lock;
+ cam->vdev.queue = vq;
+ video_set_drvdata(&cam->vdev, cam);
ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
if (ret)
goto out_irq;
- video_set_drvdata(&cam->vdev, cam);
#ifdef CONFIG_PM
/*
@@ -1464,6 +1298,9 @@ static int viacam_remove(struct platform_device *pdev)
video_unregister_device(&cam->vdev);
v4l2_device_unregister(&cam->v4l2_dev);
+#ifdef CONFIG_PM
+ viafb_pm_unregister(&viacam_pm_hooks);
+#endif
free_irq(viadev->pdev->irq, cam);
via_sensor_power_release(cam);
v4l2_ctrl_handler_free(&cam->ctrl_handler);
diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.c b/drivers/media/platform/vicodec/codec-v4l2-fwht.c
index 01e7f09efc4e..3c93d9232c3c 100644
--- a/drivers/media/platform/vicodec/codec-v4l2-fwht.c
+++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.c
@@ -29,11 +29,15 @@ static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = {
{ V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
{ V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
{ V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+ { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
{ V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
{ V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
- { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
{ V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
- { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
+ { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+ { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
+ { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB},
+ { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB},
+ { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV},
{ V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB},
};
@@ -193,6 +197,28 @@ static int prepare_raw_frame(struct fwht_raw_frame *rf,
rf->luma++;
rf->alpha = rf->cr + 1;
break;
+ case V4L2_PIX_FMT_BGRX32:
+ rf->cb = rf->luma + 1;
+ rf->cr = rf->cb + 2;
+ rf->luma += 2;
+ break;
+ case V4L2_PIX_FMT_BGRA32:
+ rf->alpha = rf->luma;
+ rf->cb = rf->luma + 1;
+ rf->cr = rf->cb + 2;
+ rf->luma += 2;
+ break;
+ case V4L2_PIX_FMT_RGBX32:
+ rf->cr = rf->luma;
+ rf->cb = rf->cr + 2;
+ rf->luma++;
+ break;
+ case V4L2_PIX_FMT_RGBA32:
+ rf->alpha = rf->luma + 3;
+ rf->cr = rf->luma;
+ rf->cb = rf->cr + 2;
+ rf->luma++;
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c
index 7e7c1e80f29f..82350097503e 100644
--- a/drivers/media/platform/vicodec/vicodec-core.c
+++ b/drivers/media/platform/vicodec/vicodec-core.c
@@ -742,6 +742,9 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx,
return -EINVAL;
f->pixelformat = ctx->is_stateless ?
V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT;
+ if (!ctx->is_enc && !ctx->is_stateless)
+ f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION |
+ V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM;
}
return 0;
}
@@ -1661,19 +1664,22 @@ static int vicodec_start_streaming(struct vb2_queue *q,
kvfree(state->compressed_frame);
state->compressed_frame = new_comp_frame;
- if (info->components_num >= 3) {
- state->ref_frame.cb = state->ref_frame.luma + size;
- state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
- } else {
+ if (info->components_num < 3) {
state->ref_frame.cb = NULL;
state->ref_frame.cr = NULL;
+ state->ref_frame.alpha = NULL;
+ return 0;
}
+ state->ref_frame.cb = state->ref_frame.luma + size;
+ state->ref_frame.cr = state->ref_frame.cb + size / chroma_div;
+
if (info->components_num == 4)
state->ref_frame.alpha =
state->ref_frame.cr + size / chroma_div;
else
state->ref_frame.alpha = NULL;
+
return 0;
}
@@ -2133,6 +2139,9 @@ static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev)
v4l2_m2m_release(dev->stateful_enc.m2m_dev);
v4l2_m2m_release(dev->stateful_dec.m2m_dev);
v4l2_m2m_release(dev->stateless_dec.m2m_dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ media_device_cleanup(&dev->mdev);
+#endif
kfree(dev);
}
@@ -2244,7 +2253,6 @@ static int vicodec_remove(struct platform_device *pdev)
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
video_unregister_device(&dev->stateful_enc.vfd);
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index acd3bd48c7e2..8d6b09623d88 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -1073,6 +1073,9 @@ static int vim2m_start_streaming(struct vb2_queue *q, unsigned int count)
if (!q_data)
return -EINVAL;
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ ctx->aborting = 0;
+
q_data->sequence = 0;
return 0;
}
@@ -1272,6 +1275,9 @@ static void vim2m_device_release(struct video_device *vdev)
v4l2_device_unregister(&dev->v4l2_dev);
v4l2_m2m_release(dev->m2m_dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ media_device_cleanup(&dev->mdev);
+#endif
kfree(dev);
}
@@ -1343,6 +1349,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);
+ dev->m2m_dev = NULL;
goto error_dev;
}
@@ -1395,7 +1402,6 @@ static int vim2m_remove(struct platform_device *pdev)
#ifdef CONFIG_MEDIA_CONTROLLER
media_device_unregister(&dev->mdev);
v4l2_m2m_unregister_media_controller(dev->m2m_dev);
- media_device_cleanup(&dev->mdev);
#endif
video_unregister_device(&dev->vfd);
diff --git a/drivers/media/platform/vimc/Makefile b/drivers/media/platform/vimc/Makefile
index 96d06f030c31..a53b2b532e9f 100644
--- a/drivers/media/platform/vimc/Makefile
+++ b/drivers/media/platform/vimc/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-vimc-y := vimc-core.o vimc-common.o vimc-streamer.o
+vimc-y := vimc-core.o vimc-common.o vimc-streamer.o vimc-capture.o \
+ vimc-debayer.o vimc-scaler.o vimc-sensor.o
+
+obj-$(CONFIG_VIDEO_VIMC) += vimc.o
-obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc-capture.o vimc-debayer.o \
- vimc-scaler.o vimc-sensor.o
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c
index 664855708fdf..76c015898cfd 100644
--- a/drivers/media/platform/vimc/vimc-capture.c
+++ b/drivers/media/platform/vimc/vimc-capture.c
@@ -5,10 +5,6 @@
* Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
*/
-#include <linux/component.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/platform_device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-vmalloc.h>
@@ -16,38 +12,9 @@
#include "vimc-common.h"
#include "vimc-streamer.h"
-#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;
- struct device *dev;
struct v4l2_pix_format format;
struct vb2_queue queue;
struct list_head buf_list;
@@ -62,6 +29,7 @@ struct vimc_cap_device {
struct mutex lock;
u32 sequence;
struct vimc_stream stream;
+ struct media_pad pad;
};
static const struct v4l2_pix_format fmt_default = {
@@ -117,25 +85,29 @@ 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;
- vimc_colorimetry_clamp(format);
+ /* 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;
if (format->field == V4L2_FIELD_ANY)
format->field = fmt_default.field;
- /* TODO: Add support for custom bytesperline values */
-
- /* Don't accept a pixelformat that is not on the table */
- if (!v4l2_format_info(format->pixelformat))
- format->pixelformat = fmt_default.pixelformat;
+ vimc_colorimetry_clamp(format);
- return v4l2_fill_pixfmt(format, format->pixelformat,
- format->width, format->height);
+ return 0;
}
static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,
@@ -152,7 +124,7 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,
if (ret)
return ret;
- dev_dbg(vcap->dev, "%s: format update: "
+ dev_dbg(vcap->ved.dev, "%s: format update: "
"old:%dx%d (0x%x, %d, %d, %d, %d) "
"new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name,
/* old */
@@ -174,31 +146,27 @@ 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)
{
- if (f->index >= ARRAY_SIZE(vimc_cap_supported_pixfmt))
+ const struct vimc_pix_map *vpix = vimc_pix_map_by_index(f->index);
+
+ if (!vpix)
return -EINVAL;
- f->pixelformat = vimc_cap_supported_pixfmt[f->index];
+ f->pixelformat = vpix->pixelformat;
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;
- if (!vimc_cap_is_pixfmt_supported(fsize->pixel_format))
+ /* Only accept code in the pix map table */
+ vpix = vimc_pix_map_by_code(fsize->pixel_format);
+ if (!vpix)
return -EINVAL;
fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
@@ -272,7 +240,6 @@ 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);
@@ -333,7 +300,7 @@ static int vimc_cap_buffer_prepare(struct vb2_buffer *vb)
unsigned long size = vcap->format.sizeimage;
if (vb2_plane_size(vb, 0) < size) {
- dev_err(vcap->dev, "%s: buffer too small (%lu < %lu)\n",
+ dev_err(vcap->ved.dev, "%s: buffer too small (%lu < %lu)\n",
vcap->vdev.name, vb2_plane_size(vb, 0), size);
return -EINVAL;
}
@@ -355,7 +322,7 @@ static const struct vb2_ops vimc_cap_qops = {
};
static const struct media_entity_operations vimc_cap_mops = {
- .link_validate = vimc_link_validate,
+ .link_validate = vimc_vdev_link_validate,
};
static void vimc_cap_release(struct video_device *vdev)
@@ -363,19 +330,16 @@ 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);
+ media_entity_cleanup(vcap->ved.ent);
kfree(vcap);
}
-static void vimc_cap_comp_unbind(struct device *comp, struct device *master,
- void *master_data)
+void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
{
- struct vimc_ent_device *ved = dev_get_drvdata(comp);
- struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device,
- ved);
+ struct vimc_cap_device *vcap;
+ vcap = container_of(ved, struct vimc_cap_device, ved);
vb2_queue_release(&vcap->queue);
- media_entity_cleanup(ved->ent);
video_unregister_device(&vcap->vdev);
}
@@ -418,11 +382,11 @@ static void *vimc_cap_process_frame(struct vimc_ent_device *ved,
return NULL;
}
-static int vimc_cap_comp_bind(struct device *comp, struct device *master,
- void *master_data)
+struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
+ const char *vcfg_name)
{
- struct v4l2_device *v4l2_dev = master_data;
- struct vimc_platform_data *pdata = comp->platform_data;
+ struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
+ const struct vimc_pix_map *vpix;
struct vimc_cap_device *vcap;
struct video_device *vdev;
struct vb2_queue *q;
@@ -431,23 +395,16 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
/* Allocate the vimc_cap_device struct */
vcap = kzalloc(sizeof(*vcap), GFP_KERNEL);
if (!vcap)
- return -ENOMEM;
-
- /* Allocate the pads */
- vcap->ved.pads =
- vimc_pads_init(1, (const unsigned long[1]) {MEDIA_PAD_FL_SINK});
- if (IS_ERR(vcap->ved.pads)) {
- ret = PTR_ERR(vcap->ved.pads);
- goto err_free_vcap;
- }
+ return NULL;
/* Initialize the media entity */
- vcap->vdev.entity.name = pdata->entity_name;
+ vcap->vdev.entity.name = vcfg_name;
vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L;
+ vcap->pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&vcap->vdev.entity,
- 1, vcap->ved.pads);
+ 1, &vcap->pad);
if (ret)
- goto err_clean_pads;
+ goto err_free_vcap;
/* Initialize the lock */
mutex_init(&vcap->lock);
@@ -466,8 +423,8 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
ret = vb2_queue_init(q);
if (ret) {
- dev_err(comp, "%s: vb2 queue init failed (err=%d)\n",
- pdata->entity_name, ret);
+ dev_err(&vimc->pdev.dev, "%s: vb2 queue init failed (err=%d)\n",
+ vcfg_name, ret);
goto err_clean_m_ent;
}
@@ -477,15 +434,16 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
/* Set default frame format */
vcap->format = fmt_default;
- v4l2_fill_pixfmt(&vcap->format, vcap->format.pixelformat,
- vcap->format.width, vcap->format.height);
+ 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;
/* Fill the vimc_ent_device struct */
vcap->ved.ent = &vcap->vdev.entity;
vcap->ved.process_frame = vimc_cap_process_frame;
vcap->ved.vdev_get_format = vimc_cap_get_format;
- dev_set_drvdata(comp, &vcap->ved);
- vcap->dev = comp;
+ vcap->ved.dev = &vimc->pdev.dev;
/* Initialize the video_device struct */
vdev = &vcap->vdev;
@@ -498,68 +456,25 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master,
vdev->queue = q;
vdev->v4l2_dev = v4l2_dev;
vdev->vfl_dir = VFL_DIR_RX;
- strscpy(vdev->name, pdata->entity_name, sizeof(vdev->name));
+ strscpy(vdev->name, vcfg_name, sizeof(vdev->name));
video_set_drvdata(vdev, &vcap->ved);
/* Register the video_device with the v4l2 and the media framework */
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
if (ret) {
- dev_err(comp, "%s: video register failed (err=%d)\n",
+ dev_err(&vimc->pdev.dev, "%s: video register failed (err=%d)\n",
vcap->vdev.name, ret);
goto err_release_queue;
}
- return 0;
+ return &vcap->ved;
err_release_queue:
vb2_queue_release(q);
err_clean_m_ent:
media_entity_cleanup(&vcap->vdev.entity);
-err_clean_pads:
- vimc_pads_cleanup(vcap->ved.pads);
err_free_vcap:
kfree(vcap);
- return ret;
-}
-
-static const struct component_ops vimc_cap_comp_ops = {
- .bind = vimc_cap_comp_bind,
- .unbind = vimc_cap_comp_unbind,
-};
-
-static int vimc_cap_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &vimc_cap_comp_ops);
-}
-
-static int vimc_cap_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &vimc_cap_comp_ops);
-
- return 0;
+ return NULL;
}
-
-static const struct platform_device_id vimc_cap_driver_ids[] = {
- {
- .name = VIMC_CAP_DRV_NAME,
- },
- { }
-};
-
-static struct platform_driver vimc_cap_pdrv = {
- .probe = vimc_cap_probe,
- .remove = vimc_cap_remove,
- .id_table = vimc_cap_driver_ids,
- .driver = {
- .name = VIMC_CAP_DRV_NAME,
- },
-};
-
-module_platform_driver(vimc_cap_pdrv);
-
-MODULE_DEVICE_TABLE(platform, vimc_cap_driver_ids);
-
-MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Capture");
-MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c
index 03016f204d05..16ce9f3b7c75 100644
--- a/drivers/media/platform/vimc/vimc-common.c
+++ b/drivers/media/platform/vimc/vimc-common.c
@@ -10,217 +10,230 @@
#include "vimc-common.h"
-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,
+/*
+ * 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,
+ },
};
-/* Helper function to check mbus codes */
-bool vimc_mbus_code_supported(__u32 code)
+bool vimc_is_source(struct media_entity *ent)
{
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(vimc_mbus_list); i++)
- if (code == vimc_mbus_list[i])
- return true;
- return false;
+ for (i = 0; i < ent->num_pads; i++)
+ if (ent->pads[i].flags & MEDIA_PAD_FL_SINK)
+ return false;
+ return true;
}
-EXPORT_SYMBOL_GPL(vimc_mbus_code_supported);
-/* 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)
+const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i)
{
- if (code->index >= ARRAY_SIZE(vimc_mbus_list))
- return -EINVAL;
+ if (i >= ARRAY_SIZE(vimc_pix_map_list))
+ return NULL;
- code->code = vimc_mbus_list[code->index];
- return 0;
+ return &vimc_pix_map_list[i];
}
-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)
+const struct vimc_pix_map *vimc_pix_map_by_code(u32 code)
{
- struct media_pad *pads;
unsigned int i;
- /* Allocate memory for the pads */
- pads = kcalloc(num_pads, sizeof(*pads), GFP_KERNEL);
- if (!pads)
- return ERR_PTR(-ENOMEM);
-
- /* Initialize the pads */
- for (i = 0; i < num_pads; i++) {
- pads[i].index = i;
- pads[i].flags = pads_flag[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 pads;
+ return NULL;
}
-EXPORT_SYMBOL_GPL(vimc_pads_init);
-int vimc_pipeline_s_stream(struct media_entity *ent, int enable)
+const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat)
{
- struct v4l2_subdev *sd;
- struct media_pad *pad;
unsigned int i;
- int ret;
-
- for (i = 0; i < ent->num_pads; i++) {
- if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE)
- continue;
-
- /* Start the stream in the subdevice direct connected */
- pad = media_entity_remote_pad(&ent->pads[i]);
- if (!pad)
- continue;
-
- if (!is_media_entity_v4l2_subdev(pad->entity))
- return -EINVAL;
- sd = media_entity_to_v4l2_subdev(pad->entity);
- ret = v4l2_subdev_call(sd, video, s_stream, enable);
- if (ret && ret != -ENOIOCTLCMD)
- return ret;
+ 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 0;
+ return NULL;
}
-EXPORT_SYMBOL_GPL(vimc_pipeline_s_stream);
-static int vimc_get_mbus_format(struct media_pad *pad,
- struct v4l2_subdev_format *fmt)
+static int vimc_get_pix_format(struct media_pad *pad,
+ struct v4l2_pix_format *fmt)
{
if (is_media_entity_v4l2_subdev(pad->entity)) {
struct v4l2_subdev *sd =
media_entity_to_v4l2_subdev(pad->entity);
+ struct v4l2_subdev_format sd_fmt;
+ const struct vimc_pix_map *pix_map;
int ret;
- fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt->pad = pad->index;
+ sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ sd_fmt.pad = pad->index;
- ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
if (ret)
return ret;
+ v4l2_fill_pix_format(fmt, &sd_fmt.format);
+ pix_map = vimc_pix_map_by_code(sd_fmt.format.code);
+ fmt->pixelformat = pix_map->pixelformat;
} else if (is_media_entity_v4l2_video_device(pad->entity)) {
struct video_device *vdev = container_of(pad->entity,
struct video_device,
entity);
struct vimc_ent_device *ved = video_get_drvdata(vdev);
- struct v4l2_pix_format vdev_fmt;
if (!ved->vdev_get_format)
return -ENOIOCTLCMD;
- ved->vdev_get_format(ved, &vdev_fmt);
- v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, 0);
+ ved->vdev_get_format(ved, fmt);
} else {
return -EINVAL;
}
@@ -228,16 +241,16 @@ static int vimc_get_mbus_format(struct media_pad *pad,
return 0;
}
-int vimc_link_validate(struct media_link *link)
+int vimc_vdev_link_validate(struct media_link *link)
{
- struct v4l2_subdev_format source_fmt, sink_fmt;
+ struct v4l2_pix_format source_fmt, sink_fmt;
int ret;
- ret = vimc_get_mbus_format(link->source, &source_fmt);
+ ret = vimc_get_pix_format(link->source, &source_fmt);
if (ret)
return ret;
- ret = vimc_get_mbus_format(link->sink, &sink_fmt);
+ ret = vimc_get_pix_format(link->sink, &sink_fmt);
if (ret)
return ret;
@@ -246,70 +259,65 @@ int vimc_link_validate(struct media_link *link)
"%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n",
/* src */
link->source->entity->name,
- source_fmt.format.width, source_fmt.format.height,
- source_fmt.format.code, source_fmt.format.colorspace,
- source_fmt.format.quantization, source_fmt.format.xfer_func,
- source_fmt.format.ycbcr_enc,
+ source_fmt.width, source_fmt.height,
+ source_fmt.pixelformat, source_fmt.colorspace,
+ source_fmt.quantization, source_fmt.xfer_func,
+ source_fmt.ycbcr_enc,
/* sink */
link->sink->entity->name,
- sink_fmt.format.width, sink_fmt.format.height,
- sink_fmt.format.code, sink_fmt.format.colorspace,
- sink_fmt.format.quantization, sink_fmt.format.xfer_func,
- sink_fmt.format.ycbcr_enc);
-
- /* 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)) {
- pr_err("vimc: format doesn't match in link %s->%s\n",
- link->source->entity->name, link->sink->entity->name);
+ sink_fmt.width, sink_fmt.height,
+ sink_fmt.pixelformat, sink_fmt.colorspace,
+ sink_fmt.quantization, sink_fmt.xfer_func,
+ sink_fmt.ycbcr_enc);
+
+ /* The width, height and pixelformat must match. */
+ if (source_fmt.width != sink_fmt.width ||
+ source_fmt.height != sink_fmt.height ||
+ source_fmt.pixelformat != sink_fmt.pixelformat)
return -EPIPE;
- }
/*
* The field order must match, or the sink field order must be NONE
* to support interlaced hardware connected to bridges that support
* progressive formats only.
*/
- if (source_fmt.format.field != sink_fmt.format.field &&
- sink_fmt.format.field != V4L2_FIELD_NONE)
+ if (source_fmt.field != sink_fmt.field &&
+ sink_fmt.field != V4L2_FIELD_NONE)
return -EPIPE;
/*
* If colorspace is DEFAULT, then assume all the colorimetry is also
* DEFAULT, return 0 to skip comparing the other colorimetry parameters
*/
- if (source_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT
- || sink_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT)
+ if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT ||
+ sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT)
return 0;
/* Colorspace must match. */
- if (source_fmt.format.colorspace != sink_fmt.format.colorspace)
+ if (source_fmt.colorspace != sink_fmt.colorspace)
return -EPIPE;
/* Colorimetry must match if they are not set to DEFAULT */
- if (source_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT
- && sink_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT
- && source_fmt.format.ycbcr_enc != sink_fmt.format.ycbcr_enc)
+ if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
+ sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT &&
+ source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc)
return -EPIPE;
- if (source_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT
- && sink_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT
- && source_fmt.format.quantization != sink_fmt.format.quantization)
+ if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
+ sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT &&
+ source_fmt.quantization != sink_fmt.quantization)
return -EPIPE;
- if (source_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT
- && sink_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT
- && source_fmt.format.xfer_func != sink_fmt.format.xfer_func)
+ if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
+ sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT &&
+ source_fmt.xfer_func != sink_fmt.xfer_func)
return -EPIPE;
return 0;
}
-EXPORT_SYMBOL_GPL(vimc_link_validate);
static const struct media_entity_operations vimc_ent_sd_mops = {
- .link_validate = vimc_link_validate,
+ .link_validate = v4l2_subdev_link_validate,
};
int vimc_ent_sd_register(struct vimc_ent_device *ved,
@@ -318,17 +326,12 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
const char *const name,
u32 function,
u16 num_pads,
- const unsigned long *pads_flag,
+ struct media_pad *pads,
const struct v4l2_subdev_internal_ops *sd_int_ops,
const struct v4l2_subdev_ops *sd_ops)
{
int ret;
- /* Allocate the pads */
- ved->pads = vimc_pads_init(num_pads, pads_flag);
- if (IS_ERR(ved->pads))
- return PTR_ERR(ved->pads);
-
/* Fill the vimc_ent_device struct */
ved->ent = &sd->entity;
@@ -347,9 +350,9 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
/* Initialize the media entity */
- ret = media_entity_pads_init(&sd->entity, num_pads, ved->pads);
+ ret = media_entity_pads_init(&sd->entity, num_pads, pads);
if (ret)
- goto err_clean_pads;
+ return ret;
/* Register the subdev with the v4l2 and the media framework */
ret = v4l2_device_register_subdev(v4l2_dev, sd);
@@ -364,16 +367,5 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
err_clean_m_ent:
media_entity_cleanup(&sd->entity);
-err_clean_pads:
- vimc_pads_cleanup(ved->pads);
return ret;
}
-EXPORT_SYMBOL_GPL(vimc_ent_sd_register);
-
-void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_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 7b4d988b208b..87eb8259c2a8 100644
--- a/drivers/media/platform/vimc/vimc-common.h
+++ b/drivers/media/platform/vimc/vimc-common.h
@@ -8,18 +8,18 @@
#ifndef _VIMC_COMMON_H_
#define _VIMC_COMMON_H_
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <media/media-device.h>
#include <media/v4l2-device.h>
-#include "vimc-streamer.h"
-
#define VIMC_PDEV_NAME "vimc"
/* VIMC-specific controls */
#define VIMC_CID_VIMC_BASE (0x00f00000 | 0xf000)
#define VIMC_CID_VIMC_CLASS (0x00f00000 | 1)
#define VIMC_CID_TEST_PATTERN (VIMC_CID_VIMC_BASE + 0)
+#define VIMC_CID_MEAN_WIN_SIZE (VIMC_CID_VIMC_BASE + 1)
#define VIMC_FRAME_MAX_WIDTH 4096
#define VIMC_FRAME_MAX_HEIGHT 2160
@@ -28,6 +28,10 @@
#define VIMC_FRAME_INDEX(lin, col, width, bpp) ((lin * width + col) * bpp)
+/* Source and sink pad checks */
+#define VIMC_IS_SRC(pad) (pad)
+#define VIMC_IS_SINK(pad) (!(pad))
+
/**
* struct vimc_colorimetry_clamp - Adjust colorimetry parameters
*
@@ -55,25 +59,28 @@ do { \
} while (0)
/**
- * struct vimc_platform_data - platform data to components
+ * struct vimc_pix_map - maps media bus code with v4l2 pixel format
*
- * @entity_name: The name of the entity to be created
+ * @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
*
- * Board setup code will often provide additional information using the device's
- * platform_data field to hold additional information.
- * When injecting a new platform_device in the component system the core needs
- * to provide to the corresponding submodules the name of the entity that should
- * be used when registering the subdevice in the Media Controller system.
+ * Struct which matches the MEDIA_BUS_FMT_* codes with the corresponding
+ * V4L2_PIX_FMT_* fourcc pixelformat and its bytes per pixel (bpp)
*/
-struct vimc_platform_data {
- char entity_name[32];
+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
+ * struct vimc_ent_device - core struct that represents an entity in the
+ * topology
*
+ * @dev: a pointer of the device struct of the driver
* @ent: the pointer to struct media_entity for the node
- * @pads: the list of pads of the node
* @process_frame: callback send a frame to that node
* @vdev_get_format: callback that returns the current format a pad, used
* only when is_media_entity_v4l2_video_device(ent) returns
@@ -88,9 +95,8 @@ struct vimc_platform_data {
* media_entity
*/
struct vimc_ent_device {
+ struct device *dev;
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,
@@ -98,55 +104,86 @@ struct vimc_ent_device {
};
/**
- * vimc_mbus_code_supported - helper to check supported mbus codes
+ * struct vimc_device - main device for vimc driver
*
- * Helper function to check if mbus code is enumerated by vimc_enum_mbus_code()
+ * @pdev pointer to the platform device
+ * @pipe_cfg pointer to the vimc pipeline configuration structure
+ * @ent_devs array of vimc_ent_device pointers
+ * @mdev the associated media_device parent
+ * @v4l2_dev Internal v4l2 parent device
*/
-bool vimc_mbus_code_supported(__u32 code);
+struct vimc_device {
+ struct platform_device pdev;
+ const struct vimc_pipeline_config *pipe_cfg;
+ struct vimc_ent_device **ent_devs;
+ struct media_device mdev;
+ struct v4l2_device v4l2_dev;
+};
/**
- * vimc_enum_mbus_code - enumerate mbus codes
- *
- * Helper function to be pluged in .enum_mbus_code from
- * struct v4l2_subdev_pad_ops.
+ * struct vimc_ent_config Structure which describes individual
+ * configuration for each entity
+ *
+ * @name entity name
+ * @ved pointer to vimc_ent_device (a node in the
+ * topology)
+ * @add subdev add hook - initializes and registers
+ * subdev called from vimc-core
+ * @rm subdev rm hook - unregisters and frees
+ * subdev called from vimc-core
*/
-int vimc_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_mbus_code_enum *code);
+struct vimc_ent_config {
+ const char *name;
+ struct vimc_ent_device *(*add)(struct vimc_device *vimc,
+ const char *vcfg_name);
+ void (*rm)(struct vimc_device *vimc, struct vimc_ent_device *ved);
+};
/**
- * vimc_pads_init - initialize pads
+ * vimc_is_source - returns true if the entity has only source pads
*
- * @num_pads: number of pads to initialize
- * @pads_flags: flags to use in each pad
+ * @ent: pointer to &struct media_entity
*
- * Helper functions to allocate/initialize pads
*/
-struct media_pad *vimc_pads_init(u16 num_pads,
- const unsigned long *pads_flag);
+bool vimc_is_source(struct media_entity *ent);
+
+/* prototypes for vimc_ent_config add and rm hooks */
+struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
+ const char *vcfg_name);
+void vimc_cap_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);
+
+struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc,
+ const char *vcfg_name);
+void vimc_deb_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);
+
+struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc,
+ const char *vcfg_name);
+void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);
+
+struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc,
+ const char *vcfg_name);
+void vimc_sen_rm(struct vimc_device *vimc, struct vimc_ent_device *ved);
/**
- * vimc_pads_cleanup - free pads
- *
- * @pads: pointer to the pads
+ * vimc_pix_map_by_index - get vimc_pix_map struct by its index
*
- * Helper function to free the pads initialized with vimc_pads_init
+ * @i: index of the vimc_pix_map struct in vimc_pix_map_list
*/
-static inline void vimc_pads_cleanup(struct media_pad *pads)
-{
- kfree(pads);
-}
+const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i);
/**
- * vimc_pipeline_s_stream - start stream through the pipeline
+ * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code
*
- * @ent: the pointer to struct media_entity for the node
- * @enable: 1 to start the stream and 0 to stop
+ * @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
*
- * Helper function to call the s_stream of the subdevices connected
- * in all the sink pads of the entity
+ * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros
*/
-int vimc_pipeline_s_stream(struct media_entity *ent, int enable);
+const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat);
/**
* vimc_ent_sd_register - initialize and register a subdev node
@@ -158,7 +195,8 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable);
* unique.
* @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
+ * @pads: the array of pads of the entity, the caller should set the
+ flags of the pads
* @sd_int_ops: pointer to &struct v4l2_subdev_internal_ops
* @sd_ops: pointer to &struct v4l2_subdev_ops.
*
@@ -171,29 +209,17 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
const char *const name,
u32 function,
u16 num_pads,
- const unsigned long *pads_flag,
+ struct media_pad *pads,
const struct v4l2_subdev_internal_ops *sd_int_ops,
const struct v4l2_subdev_ops *sd_ops);
/**
- * vimc_ent_sd_unregister - cleanup and unregister a subdev node
- *
- * @ved: the vimc_ent_device struct to be cleaned up
- * @sd: the v4l2_subdev struct to be unregistered
- *
- * Helper function cleanup and unregister the struct vimc_ent_device and struct
- * v4l2_subdev which represents a subdev node in the topology
- */
-void vimc_ent_sd_unregister(struct vimc_ent_device *ved,
- struct v4l2_subdev *sd);
-
-/**
- * vimc_link_validate - validates a media link
+ * vimc_vdev_link_validate - validates a media link
*
* @link: pointer to &struct media_link
*
* This function calls validates if a media link is valid for streaming.
*/
-int vimc_link_validate(struct media_link *link);
+int vimc_vdev_link_validate(struct media_link *link);
#endif
diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c
index 571c55aa0e16..97a272f3350a 100644
--- a/drivers/media/platform/vimc/vimc-core.c
+++ b/drivers/media/platform/vimc/vimc-core.c
@@ -5,7 +5,6 @@
* Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
*/
-#include <linux/component.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -24,29 +23,6 @@
.flags = link_flags, \
}
-struct vimc_device {
- /* The platform device */
- struct platform_device pdev;
-
- /* The pipeline configuration */
- const struct vimc_pipeline_config *pipe_cfg;
-
- /* The Associated media_device parent */
- struct media_device mdev;
-
- /* Internal v4l2 parent device*/
- struct v4l2_device v4l2_dev;
-
- /* Subdevices */
- struct platform_device **subdevs;
-};
-
-/* Structure which describes individual configuration for each entity */
-struct vimc_ent_config {
- const char *name;
- const char *drv;
-};
-
/* Structure which describes links between entities */
struct vimc_ent_link {
unsigned int src_ent;
@@ -68,43 +44,52 @@ struct vimc_pipeline_config {
* Topology Configuration
*/
-static const struct vimc_ent_config ent_config[] = {
+static struct vimc_ent_config ent_config[] = {
{
.name = "Sensor A",
- .drv = "vimc-sensor",
+ .add = vimc_sen_add,
+ .rm = vimc_sen_rm,
},
{
.name = "Sensor B",
- .drv = "vimc-sensor",
+ .add = vimc_sen_add,
+ .rm = vimc_sen_rm,
},
{
.name = "Debayer A",
- .drv = "vimc-debayer",
+ .add = vimc_deb_add,
+ .rm = vimc_deb_rm,
},
{
.name = "Debayer B",
- .drv = "vimc-debayer",
+ .add = vimc_deb_add,
+ .rm = vimc_deb_rm,
},
{
.name = "Raw Capture 0",
- .drv = "vimc-capture",
+ .add = vimc_cap_add,
+ .rm = vimc_cap_rm,
},
{
.name = "Raw Capture 1",
- .drv = "vimc-capture",
+ .add = vimc_cap_add,
+ .rm = vimc_cap_rm,
},
{
- .name = "RGB/YUV Input",
/* TODO: change this to vimc-input when it is implemented */
- .drv = "vimc-sensor",
+ .name = "RGB/YUV Input",
+ .add = vimc_sen_add,
+ .rm = vimc_sen_rm,
},
{
.name = "Scaler",
- .drv = "vimc-scaler",
+ .add = vimc_sca_add,
+ .rm = vimc_sca_rm,
},
{
.name = "RGB/YUV Capture",
- .drv = "vimc-capture",
+ .add = vimc_cap_add,
+ .rm = vimc_cap_rm,
},
};
@@ -127,7 +112,7 @@ static const struct vimc_ent_link ent_links[] = {
VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
};
-static const struct vimc_pipeline_config pipe_cfg = {
+static struct vimc_pipeline_config pipe_cfg = {
.ents = ent_config,
.num_ents = ARRAY_SIZE(ent_config),
.links = ent_links,
@@ -136,6 +121,14 @@ static const struct vimc_pipeline_config pipe_cfg = {
/* -------------------------------------------------------------------------- */
+static void vimc_rm_links(struct vimc_device *vimc)
+{
+ unsigned int i;
+
+ for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
+ media_entity_remove_links(vimc->ent_devs[i]->ent);
+}
+
static int vimc_create_links(struct vimc_device *vimc)
{
unsigned int i;
@@ -144,32 +137,56 @@ static int vimc_create_links(struct vimc_device *vimc)
/* Initialize the links between entities */
for (i = 0; i < vimc->pipe_cfg->num_links; i++) {
const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i];
- /*
- * TODO: Check another way of retrieving ved struct without
- * relying on platform_get_drvdata
- */
+
struct vimc_ent_device *ved_src =
- platform_get_drvdata(vimc->subdevs[link->src_ent]);
+ vimc->ent_devs[link->src_ent];
struct vimc_ent_device *ved_sink =
- platform_get_drvdata(vimc->subdevs[link->sink_ent]);
+ vimc->ent_devs[link->sink_ent];
ret = media_create_pad_link(ved_src->ent, link->src_pad,
ved_sink->ent, link->sink_pad,
link->flags);
if (ret)
- return ret;
+ goto err_rm_links;
}
return 0;
+
+err_rm_links:
+ vimc_rm_links(vimc);
+ return ret;
}
-static int vimc_comp_bind(struct device *master)
+static int vimc_add_subdevs(struct vimc_device *vimc)
{
- struct vimc_device *vimc = container_of(to_platform_device(master),
- struct vimc_device, pdev);
- int ret;
+ unsigned int i;
+
+ for (i = 0; i < vimc->pipe_cfg->num_ents; i++) {
+ dev_dbg(&vimc->pdev.dev, "new entity for %s\n",
+ vimc->pipe_cfg->ents[i].name);
+ vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].add(vimc,
+ vimc->pipe_cfg->ents[i].name);
+ if (!vimc->ent_devs[i]) {
+ dev_err(&vimc->pdev.dev, "add new entity for %s\n",
+ vimc->pipe_cfg->ents[i].name);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static void vimc_rm_subdevs(struct vimc_device *vimc)
+{
+ unsigned int i;
+
+ for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
+ if (vimc->ent_devs[i])
+ vimc->pipe_cfg->ents[i].rm(vimc, vimc->ent_devs[i]);
+}
- dev_dbg(master, "bind");
+static int vimc_register_devices(struct vimc_device *vimc)
+{
+ int ret;
/* Register the v4l2 struct */
ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev);
@@ -179,22 +196,31 @@ static int vimc_comp_bind(struct device *master)
return ret;
}
- /* Bind subdevices */
- ret = component_bind_all(master, &vimc->v4l2_dev);
- if (ret)
+ /* allocate ent_devs */
+ vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents,
+ sizeof(*vimc->ent_devs), GFP_KERNEL);
+ if (!vimc->ent_devs) {
+ ret = -ENOMEM;
goto err_v4l2_unregister;
+ }
+
+ /* Invoke entity config hooks to initialize and register subdevs */
+ ret = vimc_add_subdevs(vimc);
+ if (ret)
+ /* remove sundevs that got added */
+ goto err_rm_subdevs;
/* Initialize links */
ret = vimc_create_links(vimc);
if (ret)
- goto err_comp_unbind_all;
+ goto err_rm_subdevs;
/* Register the media device */
ret = media_device_register(&vimc->mdev);
if (ret) {
dev_err(vimc->mdev.dev,
"media device register failed (err=%d)\n", ret);
- goto err_comp_unbind_all;
+ goto err_rm_subdevs;
}
/* Expose all subdev's nodes*/
@@ -211,98 +237,32 @@ static int vimc_comp_bind(struct device *master)
err_mdev_unregister:
media_device_unregister(&vimc->mdev);
media_device_cleanup(&vimc->mdev);
-err_comp_unbind_all:
- component_unbind_all(master, NULL);
+err_rm_subdevs:
+ vimc_rm_subdevs(vimc);
+ kfree(vimc->ent_devs);
err_v4l2_unregister:
v4l2_device_unregister(&vimc->v4l2_dev);
return ret;
}
-static void vimc_comp_unbind(struct device *master)
+static void vimc_unregister(struct vimc_device *vimc)
{
- struct vimc_device *vimc = container_of(to_platform_device(master),
- struct vimc_device, pdev);
-
- dev_dbg(master, "unbind");
-
media_device_unregister(&vimc->mdev);
media_device_cleanup(&vimc->mdev);
- component_unbind_all(master, NULL);
v4l2_device_unregister(&vimc->v4l2_dev);
+ kfree(vimc->ent_devs);
}
-static int vimc_comp_compare(struct device *comp, void *data)
-{
- return comp == data;
-}
-
-static struct component_match *vimc_add_subdevs(struct vimc_device *vimc)
-{
- struct component_match *match = NULL;
- struct vimc_platform_data pdata;
- int i;
-
- for (i = 0; i < vimc->pipe_cfg->num_ents; i++) {
- dev_dbg(&vimc->pdev.dev, "new pdev for %s\n",
- vimc->pipe_cfg->ents[i].drv);
-
- strscpy(pdata.entity_name, vimc->pipe_cfg->ents[i].name,
- sizeof(pdata.entity_name));
-
- vimc->subdevs[i] = platform_device_register_data(&vimc->pdev.dev,
- vimc->pipe_cfg->ents[i].drv,
- PLATFORM_DEVID_AUTO,
- &pdata,
- sizeof(pdata));
- if (IS_ERR(vimc->subdevs[i])) {
- match = ERR_CAST(vimc->subdevs[i]);
- while (--i >= 0)
- platform_device_unregister(vimc->subdevs[i]);
-
- return match;
- }
-
- component_match_add(&vimc->pdev.dev, &match, vimc_comp_compare,
- &vimc->subdevs[i]->dev);
- }
-
- return match;
-}
-
-static void vimc_rm_subdevs(struct vimc_device *vimc)
-{
- unsigned int i;
-
- for (i = 0; i < vimc->pipe_cfg->num_ents; i++)
- platform_device_unregister(vimc->subdevs[i]);
-}
-
-static const struct component_master_ops vimc_comp_ops = {
- .bind = vimc_comp_bind,
- .unbind = vimc_comp_unbind,
-};
-
static int vimc_probe(struct platform_device *pdev)
{
struct vimc_device *vimc = container_of(pdev, struct vimc_device, pdev);
- struct component_match *match = NULL;
int ret;
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);
- if (!vimc->subdevs)
- return -ENOMEM;
-
- match = vimc_add_subdevs(vimc);
- if (IS_ERR(match))
- return PTR_ERR(match);
-
/* Link the media device within the v4l2_device */
vimc->v4l2_dev.mdev = &vimc->mdev;
@@ -314,12 +274,9 @@ static int vimc_probe(struct platform_device *pdev)
vimc->mdev.dev = &pdev->dev;
media_device_init(&vimc->mdev);
- /* Add self to the component system */
- ret = component_master_add_with_match(&pdev->dev, &vimc_comp_ops,
- match);
+ ret = vimc_register_devices(vimc);
if (ret) {
media_device_cleanup(&vimc->mdev);
- vimc_rm_subdevs(vimc);
return ret;
}
@@ -332,8 +289,8 @@ static int vimc_remove(struct platform_device *pdev)
dev_dbg(&pdev->dev, "remove");
- component_master_del(&pdev->dev, &vimc_comp_ops);
vimc_rm_subdevs(vimc);
+ vimc_unregister(vimc);
return 0;
}
diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c
index 00598fbf3cba..5d1b67d684bb 100644
--- a/drivers/media/platform/vimc/vimc-debayer.c
+++ b/drivers/media/platform/vimc/vimc-debayer.c
@@ -5,33 +5,16 @@
* Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
*/
-#include <linux/component.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
+#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/vmalloc.h>
#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
#include <media/v4l2-subdev.h>
#include "vimc-common.h"
-#define VIMC_DEB_DRV_NAME "vimc-debayer"
-/* This module only supports transforming 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);
-MODULE_PARM_DESC(deb_mean_win_size, " the window size to calculate the mean.\n"
- "NOTE: the window size needs to be an odd number, as the main pixel "
- "stays in the center of the window, otherwise the next odd number "
- "is considered");
-
-#define IS_SINK(pad) (!pad)
-#define IS_SRC(pad) (pad)
-
enum vimc_deb_rgb_colors {
VIMC_DEB_RED = 0,
VIMC_DEB_GREEN = 1,
@@ -39,7 +22,6 @@ enum vimc_deb_rgb_colors {
};
struct vimc_deb_pix_map {
- u32 pixelformat;
u32 code;
enum vimc_deb_rgb_colors order[2][2];
};
@@ -47,7 +29,6 @@ struct vimc_deb_pix_map {
struct vimc_deb_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
- struct device *dev;
/* The active format */
struct v4l2_mbus_framefmt sink_fmt;
u32 src_code;
@@ -57,6 +38,9 @@ struct vimc_deb_device {
u8 *src_frame;
const struct vimc_deb_pix_map *sink_pix_map;
unsigned int sink_bpp;
+ unsigned int mean_win_size;
+ struct v4l2_ctrl_handler hdl;
+ struct media_pad pads[2];
};
static const struct v4l2_mbus_framefmt sink_fmt_default = {
@@ -69,73 +53,61 @@ static const struct v4l2_mbus_framefmt sink_fmt_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 } }
@@ -176,32 +148,41 @@ static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_mbus_code_enum *code)
{
- /* For the sink pad we only support codes in the map_list */
- if (IS_SINK(code->pad)) {
+ /* We only support one format for source pads */
+ if (VIMC_IS_SRC(code->pad)) {
+ struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
+
+ if (code->index)
+ return -EINVAL;
+
+ code->code = vdeb->src_code;
+ } else {
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 vimc_enum_mbus_code(sd, cfg, code);
+ return 0;
}
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)) {
+ if (VIMC_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;
@@ -224,7 +205,7 @@ static int vimc_deb_get_fmt(struct v4l2_subdev *sd,
vdeb->sink_fmt;
/* Set the right code for the source pad */
- if (IS_SRC(fmt->pad))
+ if (VIMC_IS_SRC(fmt->pad))
fmt->format.code = vdeb->src_code;
return 0;
@@ -257,12 +238,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->ved.stream)
+ if (vdeb->src_frame)
return -EBUSY;
sink_fmt = &vdeb->sink_fmt;
@@ -272,17 +250,17 @@ 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 (except for the code)
+ * it is propagated from the sink
*/
- if (IS_SRC(fmt->pad)) {
- vdeb->src_code = fmt->format.code;
+ if (VIMC_IS_SRC(fmt->pad)) {
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 */
vimc_deb_adjust_sink_fmt(&fmt->format);
- dev_dbg(vdeb->dev, "%s: sink format update: "
+ dev_dbg(vdeb->ved.dev, "%s: sink format update: "
"old:%dx%d (0x%x, %d, %d, %d, %d) "
"new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdeb->sd.name,
/* old */
@@ -308,7 +286,7 @@ static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = {
.set_fmt = vimc_deb_set_fmt,
};
-static void vimc_deb_set_rgb_pix_rgb24(struct vimc_deb_device *vdeb,
+static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb,
unsigned int lin,
unsigned int col,
unsigned int rgb[3])
@@ -325,35 +303,25 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable)
struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
if (enable) {
- u32 src_pixelformat = vdeb->ved.stream->producer_pixfmt;
- const struct v4l2_format_info *pix_info;
+ const struct vimc_pix_map *vpix;
unsigned int frame_size;
- /* 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;
- }
+ 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;
/* 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
@@ -373,11 +341,18 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
+static const struct v4l2_subdev_core_ops vimc_deb_core_ops = {
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
static const struct v4l2_subdev_video_ops vimc_deb_video_ops = {
.s_stream = vimc_deb_s_stream,
};
static const struct v4l2_subdev_ops vimc_deb_ops = {
+ .core = &vimc_deb_core_ops,
.pad = &vimc_deb_pad_ops,
.video = &vimc_deb_video_ops,
};
@@ -411,11 +386,11 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb,
* the top left corner of the mean window (considering the current
* pixel as the center)
*/
- seek = deb_mean_win_size / 2;
+ seek = vdeb->mean_win_size / 2;
/* Sum the values of the colors in the mean window */
- dev_dbg(vdeb->dev,
+ dev_dbg(vdeb->ved.dev,
"deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n",
vdeb->sd.name, lin, col, vdeb->sink_fmt.height, seek);
@@ -448,7 +423,7 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb,
vdeb->sink_fmt.width,
vdeb->sink_bpp);
- dev_dbg(vdeb->dev,
+ dev_dbg(vdeb->ved.dev,
"deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n",
vdeb->sd.name, index, wlin, wcol, color);
@@ -459,21 +434,21 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb,
/* Save how many values we already added */
n_rgb[color]++;
- dev_dbg(vdeb->dev, "deb: %s: RGB CALC: val %d, n %d\n",
+ dev_dbg(vdeb->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n",
vdeb->sd.name, rgb[color], n_rgb[color]);
}
}
/* Calculate the mean */
for (i = 0; i < 3; i++) {
- dev_dbg(vdeb->dev,
+ dev_dbg(vdeb->ved.dev,
"deb: %s: PRE CALC: %dx%d Color %d, val %d, n %d\n",
vdeb->sd.name, lin, col, i, rgb[i], n_rgb[i]);
if (n_rgb[i])
rgb[i] = rgb[i] / n_rgb[i];
- dev_dbg(vdeb->dev,
+ dev_dbg(vdeb->ved.dev,
"deb: %s: FINAL CALC: %dx%d Color %d, val %d\n",
vdeb->sd.name, lin, col, i, rgb[i]);
}
@@ -498,14 +473,34 @@ static void *vimc_deb_process_frame(struct vimc_ent_device *ved,
}
return vdeb->src_frame;
+}
+
+static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vimc_deb_device *vdeb =
+ container_of(ctrl->handler, struct vimc_deb_device, hdl);
+ switch (ctrl->id) {
+ case VIMC_CID_MEAN_WIN_SIZE:
+ vdeb->mean_win_size = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
}
+static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = {
+ .s_ctrl = vimc_deb_s_ctrl,
+};
+
static void vimc_deb_release(struct v4l2_subdev *sd)
{
struct vimc_deb_device *vdeb =
container_of(sd, struct vimc_deb_device, sd);
+ v4l2_ctrl_handler_free(&vdeb->hdl);
+ media_entity_cleanup(vdeb->ved.ent);
kfree(vdeb);
}
@@ -513,96 +508,87 @@ 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)
+void vimc_deb_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
{
- struct vimc_ent_device *ved = dev_get_drvdata(comp);
- struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device,
- ved);
+ struct vimc_deb_device *vdeb;
- vimc_ent_sd_unregister(ved, &vdeb->sd);
+ vdeb = container_of(ved, struct vimc_deb_device, ved);
+ v4l2_device_unregister_subdev(&vdeb->sd);
}
-static int vimc_deb_comp_bind(struct device *comp, struct device *master,
- void *master_data)
+static const struct v4l2_ctrl_config vimc_deb_ctrl_class = {
+ .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY,
+ .id = VIMC_CID_VIMC_CLASS,
+ .name = "VIMC Controls",
+ .type = V4L2_CTRL_TYPE_CTRL_CLASS,
+};
+
+static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = {
+ .ops = &vimc_deb_ctrl_ops,
+ .id = VIMC_CID_MEAN_WIN_SIZE,
+ .name = "Debayer Mean Window Size",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 25,
+ .step = 2,
+ .def = 3,
+};
+
+struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc,
+ const char *vcfg_name)
{
- struct v4l2_device *v4l2_dev = master_data;
- struct vimc_platform_data *pdata = comp->platform_data;
+ struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
struct vimc_deb_device *vdeb;
int ret;
/* Allocate the vdeb struct */
vdeb = kzalloc(sizeof(*vdeb), GFP_KERNEL);
if (!vdeb)
- return -ENOMEM;
+ return NULL;
+
+ /* Create controls: */
+ v4l2_ctrl_handler_init(&vdeb->hdl, 2);
+ v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_class, NULL);
+ v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_mean_win_size, NULL);
+ vdeb->sd.ctrl_handler = &vdeb->hdl;
+ if (vdeb->hdl.error) {
+ ret = vdeb->hdl.error;
+ goto err_free_vdeb;
+ }
/* Initialize ved and sd */
+ vdeb->pads[0].flags = MEDIA_PAD_FL_SINK;
+ vdeb->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+
ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev,
- pdata->entity_name,
+ vcfg_name,
MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2,
- (const unsigned long[2]) {MEDIA_PAD_FL_SINK,
- MEDIA_PAD_FL_SOURCE},
+ vdeb->pads,
&vimc_deb_int_ops, &vimc_deb_ops);
- if (ret) {
- kfree(vdeb);
- return ret;
- }
+ if (ret)
+ goto err_free_hdl;
vdeb->ved.process_frame = vimc_deb_process_frame;
- dev_set_drvdata(comp, &vdeb->ved);
- vdeb->dev = comp;
+ vdeb->ved.dev = &vimc->pdev.dev;
+ vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def;
/* 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
- * RGB24 for now.
+ * RGB888 for now
* NOTE: the src format is always the same as the sink, except
* for the code
*/
- vdeb->set_rgb_src = vimc_deb_set_rgb_pix_rgb24;
-
- return 0;
-}
-
-static const struct component_ops vimc_deb_comp_ops = {
- .bind = vimc_deb_comp_bind,
- .unbind = vimc_deb_comp_unbind,
-};
+ vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24;
+ vdeb->set_rgb_src = vimc_deb_set_rgb_mbus_fmt_rgb888_1x24;
-static int vimc_deb_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &vimc_deb_comp_ops);
-}
+ return &vdeb->ved;
-static int vimc_deb_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &vimc_deb_comp_ops);
+err_free_hdl:
+ v4l2_ctrl_handler_free(&vdeb->hdl);
+err_free_vdeb:
+ kfree(vdeb);
- return 0;
+ return NULL;
}
-
-static const struct platform_device_id vimc_deb_driver_ids[] = {
- {
- .name = VIMC_DEB_DRV_NAME,
- },
- { }
-};
-
-static struct platform_driver vimc_deb_pdrv = {
- .probe = vimc_deb_probe,
- .remove = vimc_deb_remove,
- .id_table = vimc_deb_driver_ids,
- .driver = {
- .name = VIMC_DEB_DRV_NAME,
- },
-};
-
-module_platform_driver(vimc_deb_pdrv);
-
-MODULE_DEVICE_TABLE(platform, vimc_deb_driver_ids);
-
-MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Debayer");
-MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c
index c7123a45c55b..e2e551bc3ded 100644
--- a/drivers/media/platform/vimc/vimc-scaler.c
+++ b/drivers/media/platform/vimc/vimc-scaler.c
@@ -5,73 +5,97 @@
* Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
*/
-#include <linux/component.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/platform_device.h>
+#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
#include <linux/v4l2-mediabus.h>
+#include <media/v4l2-rect.h>
#include <media/v4l2-subdev.h>
#include "vimc-common.h"
-#define VIMC_SCA_DRV_NAME "vimc-scaler"
-
static unsigned int sca_mult = 3;
module_param(sca_mult, uint, 0000);
MODULE_PARM_DESC(sca_mult, " the image size multiplier");
-#define IS_SINK(pad) (!pad)
-#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,
-};
+#define VIMC_SCA_FMT_WIDTH_DEFAULT 640
+#define VIMC_SCA_FMT_HEIGHT_DEFAULT 480
struct vimc_sca_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
- struct device *dev;
/* NOTE: the source fmt is the same as the sink
* with the width and hight multiplied by mult
*/
struct v4l2_mbus_framefmt sink_fmt;
+ struct v4l2_rect crop_rect;
/* Values calculated when the stream starts */
u8 *src_frame;
unsigned int src_line_size;
unsigned int bpp;
+ struct media_pad pads[2];
};
static const struct v4l2_mbus_framefmt sink_fmt_default = {
- .width = 640,
- .height = 480,
+ .width = VIMC_SCA_FMT_WIDTH_DEFAULT,
+ .height = VIMC_SCA_FMT_HEIGHT_DEFAULT,
.code = MEDIA_BUS_FMT_RGB888_1X24,
.field = V4L2_FIELD_NONE,
.colorspace = V4L2_COLORSPACE_DEFAULT,
};
-static bool vimc_sca_is_pixfmt_supported(u32 pixelformat)
+static const struct v4l2_rect crop_rect_default = {
+ .width = VIMC_SCA_FMT_WIDTH_DEFAULT,
+ .height = VIMC_SCA_FMT_HEIGHT_DEFAULT,
+ .top = 0,
+ .left = 0,
+};
+
+static const struct v4l2_rect crop_rect_min = {
+ .width = VIMC_FRAME_MIN_WIDTH,
+ .height = VIMC_FRAME_MIN_HEIGHT,
+ .top = 0,
+ .left = 0,
+};
+
+static struct v4l2_rect
+vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt)
{
- unsigned int i;
+ /* Get the crop bounds to clamp the crop rectangle correctly */
+ struct v4l2_rect r = {
+ .left = 0,
+ .top = 0,
+ .width = sink_fmt->width,
+ .height = sink_fmt->height,
+ };
+ return r;
+}
+
+static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r,
+ const struct v4l2_mbus_framefmt *sink_fmt)
+{
+ const struct v4l2_rect sink_rect =
+ vimc_sca_get_crop_bound_sink(sink_fmt);
- for (i = 0; i < ARRAY_SIZE(vimc_sca_supported_pixfmt); i++)
- if (vimc_sca_supported_pixfmt[i] == pixelformat)
- return true;
- return false;
+ /* Disallow rectangles smaller than the minimal one. */
+ v4l2_rect_set_min_size(r, &crop_rect_min);
+ v4l2_rect_map_inside(r, &sink_rect);
}
static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_pad_config *cfg)
{
struct v4l2_mbus_framefmt *mf;
+ struct v4l2_rect *r;
unsigned int i;
mf = v4l2_subdev_get_try_format(sd, cfg, 0);
*mf = sink_fmt_default;
+ r = v4l2_subdev_get_try_crop(sd, cfg, 0);
+ *r = crop_rect_default;
+
for (i = 1; i < sd->entity.num_pads; i++) {
mf = v4l2_subdev_get_try_format(sd, cfg, i);
*mf = sink_fmt_default;
@@ -82,17 +106,39 @@ 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;
- if (IS_SINK(fse->pad)) {
+ if (VIMC_IS_SINK(fse->pad)) {
fse->max_width = VIMC_FRAME_MAX_WIDTH;
fse->max_height = VIMC_FRAME_MAX_HEIGHT;
} else {
@@ -108,16 +154,21 @@ static int vimc_sca_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *format)
{
struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
+ struct v4l2_rect *crop_rect;
/* Get the current sink format */
- format->format = (format->which == V4L2_SUBDEV_FORMAT_TRY) ?
- *v4l2_subdev_get_try_format(sd, cfg, 0) :
- vsca->sink_fmt;
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ format->format = *v4l2_subdev_get_try_format(sd, cfg, 0);
+ crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
+ } else {
+ format->format = vsca->sink_fmt;
+ crop_rect = &vsca->crop_rect;
+ }
/* Scale the frame size for the source pad */
- if (IS_SRC(format->pad)) {
- format->format.width = vsca->sink_fmt.width * sca_mult;
- format->format.height = vsca->sink_fmt.height * sca_mult;
+ if (VIMC_IS_SRC(format->pad)) {
+ format->format.width = crop_rect->width * sca_mult;
+ format->format.height = crop_rect->height * sca_mult;
}
return 0;
@@ -125,6 +176,13 @@ 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,
@@ -142,33 +200,33 @@ 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;
+ struct v4l2_rect *crop_rect;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Do not change the format while stream is on */
- if (vsca->ved.stream)
+ if (vsca->src_frame)
return -EBUSY;
sink_fmt = &vsca->sink_fmt;
+ crop_rect = &vsca->crop_rect;
} else {
sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
}
/*
* Do not change the format of the source pad,
* it is propagated from the sink
*/
- if (IS_SRC(fmt->pad)) {
+ if (VIMC_IS_SRC(fmt->pad)) {
fmt->format = *sink_fmt;
- fmt->format.width = sink_fmt->width * sca_mult;
- fmt->format.height = sink_fmt->height * sca_mult;
+ fmt->format.width = crop_rect->width * sca_mult;
+ fmt->format.height = crop_rect->height * sca_mult;
} else {
/* Set the new format in the sink pad */
vimc_sca_adjust_sink_fmt(&fmt->format);
- dev_dbg(vsca->dev, "%s: sink format update: "
+ dev_dbg(vsca->ved.dev, "%s: sink format update: "
"old:%dx%d (0x%x, %d, %d, %d, %d) "
"new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsca->sd.name,
/* old */
@@ -181,6 +239,78 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
fmt->format.xfer_func, fmt->format.ycbcr_enc);
*sink_fmt = fmt->format;
+
+ /* Do the crop, but respect the current bounds */
+ vimc_sca_adjust_sink_crop(crop_rect, sink_fmt);
+ }
+
+ return 0;
+}
+
+static int vimc_sca_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *sink_fmt;
+ struct v4l2_rect *crop_rect;
+
+ if (VIMC_IS_SRC(sel->pad))
+ return -EINVAL;
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sink_fmt = &vsca->sink_fmt;
+ crop_rect = &vsca->crop_rect;
+ } else {
+ sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
+ }
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *crop_rect;
+ break;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r = vimc_sca_get_crop_bound_sink(sink_fmt);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vimc_sca_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_selection *sel)
+{
+ struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
+ struct v4l2_mbus_framefmt *sink_fmt;
+ struct v4l2_rect *crop_rect;
+
+ if (VIMC_IS_SRC(sel->pad))
+ return -EINVAL;
+
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ /* Do not change the format while stream is on */
+ if (vsca->src_frame)
+ return -EBUSY;
+
+ crop_rect = &vsca->crop_rect;
+ sink_fmt = &vsca->sink_fmt;
+ } else {
+ crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0);
+ sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+ }
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP:
+ /* Do the crop, but respect the current bounds */
+ vimc_sca_adjust_sink_crop(&sel->r, sink_fmt);
+ *crop_rect = sel->r;
+ break;
+ default:
+ return -EINVAL;
}
return 0;
@@ -188,10 +318,12 @@ 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_enum_mbus_code,
+ .enum_mbus_code = vimc_sca_enum_mbus_code,
.enum_frame_size = vimc_sca_enum_frame_size,
.get_fmt = vimc_sca_get_fmt,
.set_fmt = vimc_sca_set_fmt,
+ .get_selection = vimc_sca_get_selection,
+ .set_selection = vimc_sca_set_selection,
};
static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
@@ -199,26 +331,22 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
if (enable) {
- u32 pixelformat = vsca->ved.stream->producer_pixfmt;
- const struct v4l2_format_info *pix_info;
+ const struct vimc_pix_map *vpix;
unsigned int frame_size;
- if (!vimc_sca_is_pixfmt_supported(pixelformat)) {
- dev_err(vsca->dev, "pixfmt (0x%08x) is not supported\n",
- pixelformat);
- return -EINVAL;
- }
+ if (vsca->src_frame)
+ return 0;
/* Save the bytes per pixel of the sink */
- pix_info = v4l2_format_info(pixelformat);
- vsca->bpp = pix_info->bpp[0];
+ vpix = vimc_pix_map_by_code(vsca->sink_fmt.code);
+ vsca->bpp = vpix->bpp;
/* Calculate the width in bytes of the src frame */
- vsca->src_line_size = vsca->sink_fmt.width *
+ vsca->src_line_size = vsca->crop_rect.width *
sca_mult * vsca->bpp;
/* Calculate the frame size of the source pad */
- frame_size = vsca->src_line_size * vsca->sink_fmt.height *
+ frame_size = vsca->src_line_size * vsca->crop_rect.height *
sca_mult;
/* Allocate the frame buffer. Use vmalloc to be able to
@@ -260,9 +388,10 @@ static void vimc_sca_fill_pix(u8 *const ptr,
}
static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca,
- const unsigned int lin, const unsigned int col,
+ unsigned int lin, unsigned int col,
const u8 *const sink_frame)
{
+ const struct v4l2_rect crop_rect = vsca->crop_rect;
unsigned int i, j, index;
const u8 *pixel;
@@ -272,17 +401,19 @@ static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca,
vsca->bpp);
pixel = &sink_frame[index];
- dev_dbg(vsca->dev,
+ dev_dbg(vsca->ved.dev,
"sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n",
vsca->sd.name, lin, col, index);
/* point to the place we are going to put the first pixel
* in the scaled src frame
*/
+ lin -= crop_rect.top;
+ col -= crop_rect.left;
index = VIMC_FRAME_INDEX(lin * sca_mult, col * sca_mult,
- vsca->sink_fmt.width * sca_mult, vsca->bpp);
+ crop_rect.width * sca_mult, vsca->bpp);
- dev_dbg(vsca->dev, "sca: %s: scale_pix src pos %dx%d, index %d\n",
+ dev_dbg(vsca->ved.dev, "sca: %s: scale_pix src pos %dx%d, index %d\n",
vsca->sd.name, lin * sca_mult, col * sca_mult, index);
/* Repeat this pixel mult times */
@@ -291,7 +422,7 @@ static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca,
* pixel repetition in a line
*/
for (j = 0; j < sca_mult * vsca->bpp; j += vsca->bpp) {
- dev_dbg(vsca->dev,
+ dev_dbg(vsca->ved.dev,
"sca: %s: sca: scale_pix src pos %d\n",
vsca->sd.name, index + j);
@@ -308,12 +439,13 @@ static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca,
static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca,
const u8 *const sink_frame)
{
+ const struct v4l2_rect r = vsca->crop_rect;
unsigned int i, j;
/* Scale each pixel from the original sink frame */
/* TODO: implement scale down, only scale up is supported for now */
- for (i = 0; i < vsca->sink_fmt.height; i++)
- for (j = 0; j < vsca->sink_fmt.width; j++)
+ for (i = r.top; i < r.top + r.height; i++)
+ for (j = r.left; j < r.left + r.width; j++)
vimc_sca_scale_pix(vsca, i, j, sink_frame);
}
@@ -324,7 +456,7 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved,
ved);
/* If the stream in this node is not active, just return */
- if (!ved->stream)
+ if (!vsca->src_frame)
return ERR_PTR(-EINVAL);
vimc_sca_fill_src_frame(vsca, sink_frame);
@@ -337,6 +469,7 @@ static void vimc_sca_release(struct v4l2_subdev *sd)
struct vimc_sca_device *vsca =
container_of(sd, struct vimc_sca_device, sd);
+ media_entity_cleanup(vsca->ved.ent);
kfree(vsca);
}
@@ -344,89 +477,48 @@ 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)
+void vimc_sca_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
{
- struct vimc_ent_device *ved = dev_get_drvdata(comp);
- struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device,
- ved);
+ struct vimc_sca_device *vsca;
- vimc_ent_sd_unregister(ved, &vsca->sd);
+ vsca = container_of(ved, struct vimc_sca_device, ved);
+ v4l2_device_unregister_subdev(&vsca->sd);
}
-
-static int vimc_sca_comp_bind(struct device *comp, struct device *master,
- void *master_data)
+struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc,
+ const char *vcfg_name)
{
- struct v4l2_device *v4l2_dev = master_data;
- struct vimc_platform_data *pdata = comp->platform_data;
+ struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
struct vimc_sca_device *vsca;
int ret;
/* Allocate the vsca struct */
vsca = kzalloc(sizeof(*vsca), GFP_KERNEL);
if (!vsca)
- return -ENOMEM;
+ return NULL;
/* Initialize ved and sd */
+ vsca->pads[0].flags = MEDIA_PAD_FL_SINK;
+ vsca->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+
ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev,
- pdata->entity_name,
+ vcfg_name,
MEDIA_ENT_F_PROC_VIDEO_SCALER, 2,
- (const unsigned long[2]) {MEDIA_PAD_FL_SINK,
- MEDIA_PAD_FL_SOURCE},
+ vsca->pads,
&vimc_sca_int_ops, &vimc_sca_ops);
if (ret) {
kfree(vsca);
- return ret;
+ return NULL;
}
vsca->ved.process_frame = vimc_sca_process_frame;
- dev_set_drvdata(comp, &vsca->ved);
- vsca->dev = comp;
+ vsca->ved.dev = &vimc->pdev.dev;
/* Initialize the frame format */
vsca->sink_fmt = sink_fmt_default;
- return 0;
-}
-
-static const struct component_ops vimc_sca_comp_ops = {
- .bind = vimc_sca_comp_bind,
- .unbind = vimc_sca_comp_unbind,
-};
-
-static int vimc_sca_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &vimc_sca_comp_ops);
-}
-
-static int vimc_sca_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &vimc_sca_comp_ops);
+ /* Initialize the crop selection */
+ vsca->crop_rect = crop_rect_default;
- return 0;
+ return &vsca->ved;
}
-
-static const struct platform_device_id vimc_sca_driver_ids[] = {
- {
- .name = VIMC_SCA_DRV_NAME,
- },
- { }
-};
-
-static struct platform_driver vimc_sca_pdrv = {
- .probe = vimc_sca_probe,
- .remove = vimc_sca_remove,
- .id_table = vimc_sca_driver_ids,
- .driver = {
- .name = VIMC_SCA_DRV_NAME,
- },
-};
-
-module_platform_driver(vimc_sca_pdrv);
-
-MODULE_DEVICE_TABLE(platform, vimc_sca_driver_ids);
-
-MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Scaler");
-MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c
index 51359472eef2..32380f504591 100644
--- a/drivers/media/platform/vimc/vimc-sensor.c
+++ b/drivers/media/platform/vimc/vimc-sensor.c
@@ -5,10 +5,6 @@
* Copyright (C) 2015-2017 Helen Koike <helen.fornazier@gmail.com>
*/
-#include <linux/component.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/platform_device.h>
#include <linux/v4l2-mediabus.h>
#include <linux/vmalloc.h>
#include <media/v4l2-ctrls.h>
@@ -18,18 +14,15 @@
#include "vimc-common.h"
-#define VIMC_SEN_DRV_NAME "vimc-sensor"
-
struct vimc_sen_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
- struct device *dev;
struct tpg_data tpg;
- struct task_struct *kthread_sen;
u8 *frame;
/* The active format */
struct v4l2_mbus_framefmt mbus_format;
struct v4l2_ctrl_handler hdl;
+ struct media_pad pad;
};
static const struct v4l2_mbus_framefmt fmt_default = {
@@ -55,13 +48,34 @@ 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;
@@ -86,17 +100,14 @@ static int vimc_sen_get_fmt(struct v4l2_subdev *sd,
static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen)
{
- u32 pixelformat = vsen->ved.stream->producer_pixfmt;
- const struct v4l2_format_info *pix_info;
-
- pix_info = v4l2_format_info(pixelformat);
+ const struct vimc_pix_map *vpix =
+ vimc_pix_map_by_code(vsen->mbus_format.code);
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 * pix_info->bpp[0]);
+ tpg_s_bytesperline(&vsen->tpg, 0, vsen->mbus_format.width * vpix->bpp);
tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height);
- tpg_s_fourcc(&vsen->tpg, pixelformat);
+ tpg_s_fourcc(&vsen->tpg, vpix->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);
@@ -107,6 +118,13 @@ 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,
@@ -126,12 +144,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->ved.stream)
+ if (vsen->frame)
return -EBUSY;
mf = &vsen->mbus_format;
@@ -142,7 +157,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
/* Set the new format */
vimc_sen_adjust_fmt(&fmt->format);
- dev_dbg(vsen->dev, "%s: format update: "
+ dev_dbg(vsen->ved.dev, "%s: format update: "
"old:%dx%d (0x%x, %d, %d, %d, %d) "
"new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name,
/* old */
@@ -161,7 +176,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_enum_mbus_code,
+ .enum_mbus_code = vimc_sen_enum_mbus_code,
.enum_frame_size = vimc_sen_enum_frame_size,
.get_fmt = vimc_sen_get_fmt,
.set_fmt = vimc_sen_set_fmt,
@@ -183,13 +198,12 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
container_of(sd, struct vimc_sen_device, sd);
if (enable) {
- u32 pixelformat = vsen->ved.stream->producer_pixfmt;
- const struct v4l2_format_info *pix_info;
+ const struct vimc_pix_map *vpix;
unsigned int frame_size;
/* Calculate the frame size */
- pix_info = v4l2_format_info(pixelformat);
- frame_size = vsen->mbus_format.width * pix_info->bpp[0] *
+ vpix = vimc_pix_map_by_code(vsen->mbus_format.code);
+ frame_size = vsen->mbus_format.width * vpix->bpp *
vsen->mbus_format.height;
/*
@@ -272,6 +286,7 @@ static void vimc_sen_release(struct v4l2_subdev *sd)
v4l2_ctrl_handler_free(&vsen->hdl);
tpg_free(&vsen->tpg);
+ media_entity_cleanup(vsen->ved.ent);
kfree(vsen);
}
@@ -279,14 +294,12 @@ 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)
+void vimc_sen_rm(struct vimc_device *vimc, struct vimc_ent_device *ved)
{
- struct vimc_ent_device *ved = dev_get_drvdata(comp);
- struct vimc_sen_device *vsen =
- container_of(ved, struct vimc_sen_device, ved);
+ struct vimc_sen_device *vsen;
- vimc_ent_sd_unregister(ved, &vsen->sd);
+ vsen = container_of(ved, struct vimc_sen_device, ved);
+ v4l2_device_unregister_subdev(&vsen->sd);
}
/* Image Processing Controls */
@@ -306,18 +319,17 @@ static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern = {
.qmenu = tpg_pattern_strings,
};
-static int vimc_sen_comp_bind(struct device *comp, struct device *master,
- void *master_data)
+struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc,
+ const char *vcfg_name)
{
- struct v4l2_device *v4l2_dev = master_data;
- struct vimc_platform_data *pdata = comp->platform_data;
+ struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
struct vimc_sen_device *vsen;
int ret;
/* Allocate the vsen struct */
vsen = kzalloc(sizeof(*vsen), GFP_KERNEL);
if (!vsen)
- return -ENOMEM;
+ return NULL;
v4l2_ctrl_handler_init(&vsen->hdl, 4);
@@ -341,78 +353,36 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master,
goto err_free_vsen;
}
+ /* Initialize the test pattern generator */
+ tpg_init(&vsen->tpg, vsen->mbus_format.width,
+ vsen->mbus_format.height);
+ ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH);
+ if (ret)
+ goto err_free_hdl;
+
/* Initialize ved and sd */
+ vsen->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev,
- pdata->entity_name,
- MEDIA_ENT_F_CAM_SENSOR, 1,
- (const unsigned long[1]) {MEDIA_PAD_FL_SOURCE},
+ vcfg_name,
+ MEDIA_ENT_F_CAM_SENSOR, 1, &vsen->pad,
&vimc_sen_int_ops, &vimc_sen_ops);
if (ret)
- goto err_free_hdl;
+ goto err_free_tpg;
vsen->ved.process_frame = vimc_sen_process_frame;
- dev_set_drvdata(comp, &vsen->ved);
- vsen->dev = comp;
+ vsen->ved.dev = &vimc->pdev.dev;
/* Initialize the frame format */
vsen->mbus_format = fmt_default;
- /* Initialize the test pattern generator */
- tpg_init(&vsen->tpg, vsen->mbus_format.width,
- vsen->mbus_format.height);
- ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH);
- if (ret)
- goto err_unregister_ent_sd;
-
- return 0;
+ return &vsen->ved;
-err_unregister_ent_sd:
- vimc_ent_sd_unregister(&vsen->ved, &vsen->sd);
+err_free_tpg:
+ tpg_free(&vsen->tpg);
err_free_hdl:
v4l2_ctrl_handler_free(&vsen->hdl);
err_free_vsen:
kfree(vsen);
- return ret;
-}
-
-static const struct component_ops vimc_sen_comp_ops = {
- .bind = vimc_sen_comp_bind,
- .unbind = vimc_sen_comp_unbind,
-};
-
-static int vimc_sen_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &vimc_sen_comp_ops);
+ return NULL;
}
-
-static int vimc_sen_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &vimc_sen_comp_ops);
-
- return 0;
-}
-
-static const struct platform_device_id vimc_sen_driver_ids[] = {
- {
- .name = VIMC_SEN_DRV_NAME,
- },
- { }
-};
-
-static struct platform_driver vimc_sen_pdrv = {
- .probe = vimc_sen_probe,
- .remove = vimc_sen_remove,
- .id_table = vimc_sen_driver_ids,
- .driver = {
- .name = VIMC_SEN_DRV_NAME,
- },
-};
-
-module_platform_driver(vimc_sen_pdrv);
-
-MODULE_DEVICE_TABLE(platform, vimc_sen_driver_ids);
-
-MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Sensor");
-MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c
index 3b3f36357a0e..cd6b55433c9e 100644
--- a/drivers/media/platform/vimc/vimc-streamer.c
+++ b/drivers/media/platform/vimc/vimc-streamer.c
@@ -7,7 +7,6 @@
*/
#include <linux/init.h>
-#include <linux/module.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
@@ -20,6 +19,8 @@
*
* Helper function that returns the media entity containing the source pad
* linked with the first sink pad from the given media entity pad list.
+ *
+ * Return: The source pad or NULL, if it wasn't found.
*/
static struct media_entity *vimc_get_source_entity(struct media_entity *ent)
{
@@ -35,7 +36,7 @@ static struct media_entity *vimc_get_source_entity(struct media_entity *ent)
return NULL;
}
-/*
+/**
* vimc_streamer_pipeline_terminate - Disable stream in all ved in stream
*
* @stream: the pointer to the stream structure with the pipeline to be
@@ -52,7 +53,6 @@ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream)
while (stream->pipe_size) {
stream->pipe_size--;
ved = stream->ved_pipeline[stream->pipe_size];
- ved->stream = NULL;
stream->ved_pipeline[stream->pipe_size] = NULL;
if (!is_media_entity_v4l2_subdev(ved->ent))
@@ -63,15 +63,18 @@ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream)
}
}
-/*
- * vimc_streamer_pipeline_init - initializes the stream structure
+/**
+ * vimc_streamer_pipeline_init - Initializes the stream structure
*
* @stream: the pointer to the stream structure to be initialized
* @ved: the pointer to the vimc entity initializing the stream
*
* Initializes the stream structure. Walks through the entity graph to
* construct the pipeline used later on the streamer thread.
- * Calls s_stream to enable stream in all entities of the pipeline.
+ * Calls vimc_streamer_s_stream() to enable stream in all entities of
+ * the pipeline.
+ *
+ * Return: 0 if success, error code otherwise.
*/
static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
struct vimc_ent_device *ved)
@@ -88,23 +91,31 @@ 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);
+ dev_err(ved->dev, "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)
+ /* Check if the end of the pipeline was reached */
+ if (!entity) {
+ /* the first entity of the pipe should be source only */
+ if (!vimc_is_source(ved->ent)) {
+ dev_err(ved->dev,
+ "first entity in the pipe '%s' is not a source\n",
+ ved->ent->name);
+ vimc_streamer_pipeline_terminate(stream);
+ return -EPIPE;
+ }
return 0;
+ }
/* Get the next device in the pipeline */
if (is_media_entity_v4l2_subdev(entity)) {
@@ -122,13 +133,17 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream,
return -EINVAL;
}
-/*
- * vimc_streamer_thread - process frames through the pipeline
+/**
+ * vimc_streamer_thread - Process frames through the pipeline
*
* @data: vimc_stream struct of the current stream
*
* From the source to the sink, gets a frame from each subdevice and send to
* the next one of the pipeline at a fixed framerate.
+ *
+ * Return:
+ * Always zero (created as ``int`` instead of ``void`` to comply with
+ * kthread API).
*/
static int vimc_streamer_thread(void *data)
{
@@ -157,19 +172,20 @@ static int vimc_streamer_thread(void *data)
return 0;
}
-/*
- * vimc_streamer_s_stream - start/stop the streaming on the media pipeline
+/**
+ * vimc_streamer_s_stream - Start/stop the streaming on the media pipeline
*
* @stream: the pointer to the stream structure of the current stream
* @ved: pointer to the vimc entity of the entity of the stream
* @enable: flag to determine if stream should start/stop
*
- * When starting, check if there is no stream->kthread allocated. This should
- * indicate that a stream is already running. Then, it initializes
- * the pipeline, creates and runs a kthread to consume buffers through the
- * pipeline.
- * When stopping, analogously check if there is a stream running, stop
- * the thread and terminates the pipeline.
+ * When starting, check if there is no ``stream->kthread`` allocated. This
+ * should indicate that a stream is already running. Then, it initializes the
+ * pipeline, creates and runs a kthread to consume buffers through the pipeline.
+ * When stopping, analogously check if there is a stream running, stop the
+ * thread and terminates the pipeline.
+ *
+ * Return: 0 if success, error code otherwise.
*/
int vimc_streamer_s_stream(struct vimc_stream *stream,
struct vimc_ent_device *ved,
@@ -209,4 +225,3 @@ int vimc_streamer_s_stream(struct vimc_stream *stream,
return 0;
}
-EXPORT_SYMBOL_GPL(vimc_streamer_s_stream);
diff --git a/drivers/media/platform/vimc/vimc-streamer.h b/drivers/media/platform/vimc/vimc-streamer.h
index 2b3667408794..fe3c51f15fad 100644
--- a/drivers/media/platform/vimc/vimc-streamer.h
+++ b/drivers/media/platform/vimc/vimc-streamer.h
@@ -25,11 +25,6 @@
* 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
@@ -40,17 +35,8 @@ struct vimc_stream {
struct vimc_ent_device *ved_pipeline[VIMC_STREAMER_PIPELINE_MAX_SIZE];
unsigned int pipe_size;
struct task_struct *kthread;
- u32 producer_pixfmt;
};
-/**
- * vimc_streamer_s_streamer - start/stop the stream
- *
- * @stream: the pointer to the stream to start or stop
- * @ved: The last entity of the streamer pipeline
- * @enable: any non-zero number start the stream, zero stop
- *
- */
int vimc_streamer_s_stream(struct vimc_stream *stream,
struct vimc_ent_device *ved,
int enable);
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
index 2f5762e3309a..b12ad0152a3e 100644
--- a/drivers/media/platform/vivid/Makefile
+++ b/drivers/media/platform/vivid/Makefile
@@ -3,7 +3,8 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \
vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \
vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \
vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
- vivid-osd.o
+ vivid-osd.o vivid-meta-cap.o vivid-meta-out.o \
+ vivid-kthread-touch.o vivid-touch-cap.o
ifeq ($(CONFIG_VIDEO_VIVID_CEC),y)
vivid-objs += vivid-cec.o
endif
diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c
index 4d822dbed972..4d2413e87730 100644
--- a/drivers/media/platform/vivid/vivid-cec.c
+++ b/drivers/media/platform/vivid/vivid-cec.c
@@ -276,12 +276,11 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
unsigned int idx,
bool is_source)
{
- char name[sizeof(dev->vid_out_dev.name) + 2];
u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN;
+ char name[32];
- snprintf(name, sizeof(name), "%s%d",
- is_source ? dev->vid_out_dev.name : dev->vid_cap_dev.name,
- idx);
+ snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d",
+ dev->inst, is_source ? "out" : "cap", idx);
return cec_allocate_adapter(&vivid_cec_adap_ops, dev,
name, caps, 1);
}
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index d535aac68ce1..15091cbf6de7 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -37,6 +37,9 @@
#include "vivid-osd.h"
#include "vivid-cec.h"
#include "vivid-ctrls.h"
+#include "vivid-meta-cap.h"
+#include "vivid-meta-out.h"
+#include "vivid-touch-cap.h"
#define VIVID_MODULE_NAME "vivid"
@@ -79,6 +82,18 @@ static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(radio_tx_nr, int, NULL, 0444);
MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect");
+static int meta_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(meta_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(meta_cap_nr, " videoX start number, -1 is autodetect");
+
+static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(meta_out_nr, int, NULL, 0444);
+MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect");
+
+static int touch_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(touch_cap_nr, int, NULL, 0444);
+MODULE_PARM_DESC(touch_cap_nr, " v4l-touchX start number, -1 is autodetect");
+
static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(ccs_cap_mode, int, NULL, 0444);
MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n"
@@ -95,10 +110,15 @@ static unsigned multiplanar[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 1
module_param_array(multiplanar, uint, NULL, 0444);
MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 creates a multiplanar device.");
-/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + vbi-out + vid-out */
-static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x1d3d };
+/*
+ * Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr +
+ * vbi-out + vid-out + meta-cap
+ */
+static unsigned int node_types[VIVID_MAX_DEVS] = {
+ [0 ... (VIVID_MAX_DEVS - 1)] = 0xe1d3d
+};
module_param_array(node_types, uint, NULL, 0444);
-MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the following meaning:\n"
+MODULE_PARM_DESC(node_types, " node types, default is 0xe1d3d. Bitmask with the following meaning:\n"
"\t\t bit 0: Video Capture node\n"
"\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
"\t\t bit 4: Radio Receiver node\n"
@@ -106,7 +126,10 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the f
"\t\t bit 8: Video Output node\n"
"\t\t bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
"\t\t bit 12: Radio Transmitter node\n"
- "\t\t bit 16: Framebuffer for testing overlays");
+ "\t\t bit 16: Framebuffer for testing overlays\n"
+ "\t\t bit 17: Metadata Capture node\n"
+ "\t\t bit 18: Metadata Output node\n"
+ "\t\t bit 19: Touch Capture node\n");
/* Default: 4 inputs */
static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 };
@@ -205,7 +228,9 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps |
dev->vbi_cap_caps | dev->vbi_out_caps |
dev->radio_rx_caps | dev->radio_tx_caps |
- dev->sdr_cap_caps | V4L2_CAP_DEVICE_CAPS;
+ dev->sdr_cap_caps | dev->meta_cap_caps |
+ dev->meta_out_caps | dev->touch_cap_caps |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -359,6 +384,8 @@ static int vidioc_g_parm(struct file *file, void *fh,
{
struct video_device *vdev = video_devdata(file);
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_parm_tch(file, fh, parm);
if (vdev->vfl_dir == VFL_DIR_RX)
return vivid_vid_cap_g_parm(file, fh, parm);
return vivid_vid_out_g_parm(file, fh, parm);
@@ -414,6 +441,104 @@ static __poll_t vivid_radio_poll(struct file *file, struct poll_table_struct *wa
return vivid_radio_tx_poll(file, wait);
}
+static int vivid_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_enum_input_tch(file, priv, inp);
+ return vidioc_enum_input(file, priv, inp);
+}
+
+static int vivid_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_input_tch(file, priv, i);
+ return vidioc_g_input(file, priv, i);
+}
+
+static int vivid_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_s_input_tch(file, priv, i);
+ return vidioc_s_input(file, priv, i);
+}
+
+static int vivid_enum_fmt_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_enum_fmt_tch(file, priv, f);
+ return vivid_enum_fmt_vid(file, priv, f);
+}
+
+static int vivid_g_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch(file, priv, f);
+ return vidioc_g_fmt_vid_cap(file, priv, f);
+}
+
+static int vivid_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch(file, priv, f);
+ return vidioc_try_fmt_vid_cap(file, priv, f);
+}
+
+static int vivid_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch(file, priv, f);
+ return vidioc_s_fmt_vid_cap(file, priv, f);
+}
+
+static int vivid_g_fmt_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch_mplane(file, priv, f);
+ return vidioc_g_fmt_vid_cap_mplane(file, priv, f);
+}
+
+static int vivid_try_fmt_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch_mplane(file, priv, f);
+ return vidioc_try_fmt_vid_cap_mplane(file, priv, f);
+}
+
+static int vivid_s_fmt_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_TOUCH)
+ return vivid_g_fmt_tch_mplane(file, priv, f);
+ return vidioc_s_fmt_vid_cap_mplane(file, priv, f);
+}
+
static bool vivid_is_in_use(struct video_device *vdev)
{
unsigned long flags;
@@ -433,7 +558,10 @@ static bool vivid_is_last_user(struct vivid_dev *dev)
vivid_is_in_use(&dev->vbi_out_dev) +
vivid_is_in_use(&dev->sdr_cap_dev) +
vivid_is_in_use(&dev->radio_rx_dev) +
- vivid_is_in_use(&dev->radio_tx_dev);
+ vivid_is_in_use(&dev->radio_tx_dev) +
+ vivid_is_in_use(&dev->meta_cap_dev) +
+ vivid_is_in_use(&dev->meta_out_dev) +
+ vivid_is_in_use(&dev->touch_cap_dev);
return uses == 1;
}
@@ -459,6 +587,9 @@ static int vivid_fop_release(struct file *file)
set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
+ set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
+ set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags);
+ set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags);
}
mutex_unlock(&dev->mutex);
if (file->private_data == dev->overlay_cap_owner)
@@ -500,13 +631,13 @@ static const struct v4l2_file_operations vivid_radio_fops = {
static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_vid,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane,
- .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane,
- .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane,
+ .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_cap,
+ .vidioc_g_fmt_vid_cap = vivid_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap = vivid_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = vivid_s_fmt_cap,
+ .vidioc_g_fmt_vid_cap_mplane = vivid_g_fmt_cap_mplane,
+ .vidioc_try_fmt_vid_cap_mplane = vivid_try_fmt_cap_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = vivid_s_fmt_cap_mplane,
.vidioc_enum_fmt_vid_out = vivid_enum_fmt_vid,
.vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out,
@@ -568,9 +699,9 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
+ .vidioc_enum_input = vivid_enum_input,
+ .vidioc_g_input = vivid_g_input,
+ .vidioc_s_input = vivid_s_input,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_enumaudio = vidioc_enumaudio,
@@ -604,6 +735,16 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_log_status = vidioc_log_status,
.vidioc_subscribe_event = vidioc_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+ .vidioc_enum_fmt_meta_cap = vidioc_enum_fmt_meta_cap,
+ .vidioc_g_fmt_meta_cap = vidioc_g_fmt_meta_cap,
+ .vidioc_s_fmt_meta_cap = vidioc_g_fmt_meta_cap,
+ .vidioc_try_fmt_meta_cap = vidioc_g_fmt_meta_cap,
+
+ .vidioc_enum_fmt_meta_out = vidioc_enum_fmt_meta_out,
+ .vidioc_g_fmt_meta_out = vidioc_g_fmt_meta_out,
+ .vidioc_s_fmt_meta_out = vidioc_g_fmt_meta_out,
+ .vidioc_try_fmt_meta_out = vidioc_g_fmt_meta_out,
};
/* -----------------------------------------------------------------
@@ -616,6 +757,9 @@ static void vivid_dev_release(struct v4l2_device *v4l2_dev)
vivid_free_controls(dev);
v4l2_device_unregister(&dev->v4l2_dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ media_device_cleanup(&dev->mdev);
+#endif
vfree(dev->scaled_line);
vfree(dev->blended_line);
vfree(dev->edid);
@@ -645,14 +789,44 @@ static const struct media_device_ops vivid_media_ops = {
};
#endif
+static int vivid_create_queue(struct vivid_dev *dev,
+ struct vb2_queue *q,
+ u32 buf_type,
+ unsigned int min_buffers_needed,
+ const struct vb2_ops *ops)
+{
+ if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->multiplanar)
+ buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ else if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT && dev->multiplanar)
+ buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ else if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE && !dev->has_raw_vbi_cap)
+ buf_type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ else if (buf_type == V4L2_BUF_TYPE_VBI_OUTPUT && !dev->has_raw_vbi_out)
+ buf_type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
+
+ q->type = buf_type;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->io_modes |= V4L2_TYPE_IS_OUTPUT(buf_type) ? VB2_WRITE : VB2_READ;
+ if (allocators[dev->inst] != 1)
+ q->io_modes |= VB2_USERPTR;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct vivid_buffer);
+ q->ops = ops;
+ q->mem_ops = allocators[dev->inst] == 1 ? &vb2_dma_contig_memops :
+ &vb2_vmalloc_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = min_buffers_needed;
+ q->lock = &dev->mutex;
+ q->dev = dev->v4l2_dev.dev;
+ q->supports_requests = true;
+
+ return vb2_queue_init(q);
+}
+
static int vivid_create_instance(struct platform_device *pdev, int inst)
{
static const struct v4l2_dv_timings def_dv_timings =
V4L2_DV_BT_CEA_1280X720P60;
- static const struct vb2_mem_ops * const vivid_mem_ops[2] = {
- &vb2_vmalloc_memops,
- &vb2_dma_contig_memops,
- };
unsigned in_type_counter[4] = { 0, 0, 0, 0 };
unsigned out_type_counter[4] = { 0, 0, 0, 0 };
int ccs_cap = ccs_cap_mode[inst];
@@ -661,9 +835,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
bool has_modulator;
struct vivid_dev *dev;
struct video_device *vfd;
- struct vb2_queue *q;
unsigned node_type = node_types[inst];
- unsigned int allocator = allocators[inst];
v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
int ret;
int i;
@@ -758,6 +930,25 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap;
}
+ /* do we create a meta capture device */
+ dev->has_meta_cap = node_type & 0x20000;
+
+ /* sanity checks */
+ if ((in_type_counter[WEBCAM] || in_type_counter[HDMI]) &&
+ !dev->has_vid_cap && !dev->has_meta_cap) {
+ v4l2_warn(&dev->v4l2_dev,
+ "Webcam or HDMI input without video or metadata nodes\n");
+ kfree(dev);
+ return -EINVAL;
+ }
+ if ((in_type_counter[TV] || in_type_counter[SVID]) &&
+ !dev->has_vid_cap && !dev->has_vbi_cap && !dev->has_meta_cap) {
+ v4l2_warn(&dev->v4l2_dev,
+ "TV or S-Video input without video, VBI or metadata nodes\n");
+ kfree(dev);
+ return -EINVAL;
+ }
+
/* do we create a video output device? */
dev->has_vid_out = node_type & 0x0100;
@@ -768,6 +959,24 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out;
}
+ /* do we create a metadata output device */
+ dev->has_meta_out = node_type & 0x40000;
+
+ /* sanity checks */
+ if (out_type_counter[SVID] &&
+ !dev->has_vid_out && !dev->has_vbi_out && !dev->has_meta_out) {
+ v4l2_warn(&dev->v4l2_dev,
+ "S-Video output without video, VBI or metadata nodes\n");
+ kfree(dev);
+ return -EINVAL;
+ }
+ if (out_type_counter[HDMI] && !dev->has_vid_out && !dev->has_meta_out) {
+ v4l2_warn(&dev->v4l2_dev,
+ "HDMI output without video or metadata nodes\n");
+ kfree(dev);
+ return -EINVAL;
+ }
+
/* do we create a radio receiver device? */
dev->has_radio_rx = node_type & 0x0010;
@@ -777,6 +986,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
/* do we create a software defined radio capture device? */
dev->has_sdr_cap = node_type & 0x0020;
+ /* do we have a TV tuner? */
+ dev->has_tv_tuner = in_type_counter[TV];
+
/* do we have a tuner? */
has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) ||
dev->has_radio_rx || dev->has_sdr_cap;
@@ -792,7 +1004,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (no_error_inj && ccs_cap == -1)
ccs_cap = 7;
- /* if ccs_cap == -1, then the use can select it using controls */
+ /* if ccs_cap == -1, then the user can select it using controls */
if (ccs_cap != -1) {
dev->has_crop_cap = ccs_cap & 1;
dev->has_compose_cap = ccs_cap & 2;
@@ -807,7 +1019,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (no_error_inj && ccs_out == -1)
ccs_out = 7;
- /* if ccs_out == -1, then the use can select it using controls */
+ /* if ccs_out == -1, then the user can select it using controls */
if (ccs_out != -1) {
dev->has_crop_out = ccs_out & 1;
dev->has_compose_out = ccs_out & 2;
@@ -818,6 +1030,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->has_scaler_out ? 'Y' : 'N');
}
+ /* do we create a touch capture device */
+ dev->has_touch_cap = node_type & 0x80000;
+
/* end detecting feature set */
if (dev->has_vid_cap) {
@@ -828,7 +1043,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
if (dev->has_audio_inputs)
dev->vid_cap_caps |= V4L2_CAP_AUDIO;
- if (in_type_counter[TV])
+ if (dev->has_tv_tuner)
dev->vid_cap_caps |= V4L2_CAP_TUNER;
}
if (dev->has_vid_out) {
@@ -849,7 +1064,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
if (dev->has_audio_inputs)
dev->vbi_cap_caps |= V4L2_CAP_AUDIO;
- if (in_type_counter[TV])
+ if (dev->has_tv_tuner)
dev->vbi_cap_caps |= V4L2_CAP_TUNER;
}
if (dev->has_vbi_out) {
@@ -875,6 +1090,30 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR |
V4L2_CAP_READWRITE;
+ /* set up the capabilities of meta capture device */
+ if (dev->has_meta_cap) {
+ dev->meta_cap_caps = V4L2_CAP_META_CAPTURE |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ if (dev->has_audio_inputs)
+ dev->meta_cap_caps |= V4L2_CAP_AUDIO;
+ if (dev->has_tv_tuner)
+ dev->meta_cap_caps |= V4L2_CAP_TUNER;
+ }
+ /* set up the capabilities of meta output device */
+ if (dev->has_meta_out) {
+ dev->meta_out_caps = V4L2_CAP_META_OUTPUT |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ if (dev->has_audio_outputs)
+ dev->meta_out_caps |= V4L2_CAP_AUDIO;
+ }
+ /* set up the capabilities of the touch capture device */
+ if (dev->has_touch_cap) {
+ dev->touch_cap_caps = V4L2_CAP_TOUCH | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ dev->touch_cap_caps |= dev->multiplanar ?
+ V4L2_CAP_VIDEO_CAPTURE_MPLANE : V4L2_CAP_VIDEO_CAPTURE;
+ }
+
ret = -ENOMEM;
/* initialize the test pattern generator */
tpg_init(&dev->tpg, 640, 360);
@@ -934,6 +1173,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO);
+ v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO);
}
if (!dev->has_audio_outputs) {
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
@@ -942,6 +1184,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT);
v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT);
v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT);
+ v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_AUDOUT);
+ v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_AUDOUT);
+ v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_ENUMAUDOUT);
}
if (!in_type_counter[TV] && !in_type_counter[SVID]) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD);
@@ -959,12 +1204,16 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_FREQUENCY);
}
if (!has_tuner) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_TUNER);
}
if (in_type_counter[HDMI] == 0) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
@@ -990,12 +1239,18 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
+ v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS);
v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY);
v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMESIZES);
+ v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMEINTERVALS);
/* configure internal data */
dev->fmt_cap = &vivid_formats[0];
@@ -1068,6 +1323,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+ /* update touch configuration */
+ dev->timeperframe_tch_cap.numerator = 1;
+ dev->timeperframe_tch_cap.denominator = 10;
+ vivid_set_touch(dev, 0);
+
/* initialize locks */
spin_lock_init(&dev->slock);
mutex_init(&dev->mutex);
@@ -1078,6 +1338,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
INIT_LIST_HEAD(&dev->vbi_cap_active);
INIT_LIST_HEAD(&dev->vbi_out_active);
INIT_LIST_HEAD(&dev->sdr_cap_active);
+ INIT_LIST_HEAD(&dev->meta_cap_active);
+ INIT_LIST_HEAD(&dev->meta_out_active);
+ INIT_LIST_HEAD(&dev->touch_cap_active);
INIT_LIST_HEAD(&dev->cec_work_list);
spin_lock_init(&dev->cec_slock);
@@ -1092,126 +1355,78 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
goto unreg_dev;
}
- if (allocator == 1)
+ if (allocators[inst] == 1)
dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
- else if (allocator >= ARRAY_SIZE(vivid_mem_ops))
- allocator = 0;
/* start creating the vb2 queues */
if (dev->has_vid_cap) {
- snprintf(dev->vid_cap_dev.name, sizeof(dev->vid_cap_dev.name),
- "vivid-%03d-vid-cap", inst);
/* initialize vid_cap queue */
- q = &dev->vb_vid_cap_q;
- q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
- V4L2_BUF_TYPE_VIDEO_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
- if (!allocator)
- q->io_modes |= VB2_USERPTR;
- q->drv_priv = dev;
- q->buf_struct_size = sizeof(struct vivid_buffer);
- q->ops = &vivid_vid_cap_qops;
- q->mem_ops = vivid_mem_ops[allocator];
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
- q->supports_requests = true;
-
- ret = vb2_queue_init(q);
+ ret = vivid_create_queue(dev, &dev->vb_vid_cap_q,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, 2,
+ &vivid_vid_cap_qops);
if (ret)
goto unreg_dev;
}
if (dev->has_vid_out) {
- snprintf(dev->vid_out_dev.name, sizeof(dev->vid_out_dev.name),
- "vivid-%03d-vid-out", inst);
/* initialize vid_out queue */
- q = &dev->vb_vid_out_q;
- q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
- V4L2_BUF_TYPE_VIDEO_OUTPUT;
- q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE;
- if (!allocator)
- q->io_modes |= VB2_USERPTR;
- q->drv_priv = dev;
- q->buf_struct_size = sizeof(struct vivid_buffer);
- q->ops = &vivid_vid_out_qops;
- q->mem_ops = vivid_mem_ops[allocator];
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
- q->supports_requests = true;
-
- ret = vb2_queue_init(q);
+ ret = vivid_create_queue(dev, &dev->vb_vid_out_q,
+ V4L2_BUF_TYPE_VIDEO_OUTPUT, 2,
+ &vivid_vid_out_qops);
if (ret)
goto unreg_dev;
}
if (dev->has_vbi_cap) {
/* initialize vbi_cap queue */
- q = &dev->vb_vbi_cap_q;
- q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE :
- V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
- if (!allocator)
- q->io_modes |= VB2_USERPTR;
- q->drv_priv = dev;
- q->buf_struct_size = sizeof(struct vivid_buffer);
- q->ops = &vivid_vbi_cap_qops;
- q->mem_ops = vivid_mem_ops[allocator];
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
- q->supports_requests = true;
-
- ret = vb2_queue_init(q);
+ ret = vivid_create_queue(dev, &dev->vb_vbi_cap_q,
+ V4L2_BUF_TYPE_VBI_CAPTURE, 2,
+ &vivid_vbi_cap_qops);
if (ret)
goto unreg_dev;
}
if (dev->has_vbi_out) {
/* initialize vbi_out queue */
- q = &dev->vb_vbi_out_q;
- q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT :
- V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
- q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE;
- if (!allocator)
- q->io_modes |= VB2_USERPTR;
- q->drv_priv = dev;
- q->buf_struct_size = sizeof(struct vivid_buffer);
- q->ops = &vivid_vbi_out_qops;
- q->mem_ops = vivid_mem_ops[allocator];
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 2;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
- q->supports_requests = true;
-
- ret = vb2_queue_init(q);
+ ret = vivid_create_queue(dev, &dev->vb_vbi_out_q,
+ V4L2_BUF_TYPE_VBI_OUTPUT, 2,
+ &vivid_vbi_out_qops);
if (ret)
goto unreg_dev;
}
if (dev->has_sdr_cap) {
/* initialize sdr_cap queue */
- q = &dev->vb_sdr_cap_q;
- q->type = V4L2_BUF_TYPE_SDR_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
- if (!allocator)
- q->io_modes |= VB2_USERPTR;
- q->drv_priv = dev;
- q->buf_struct_size = sizeof(struct vivid_buffer);
- q->ops = &vivid_sdr_cap_qops;
- q->mem_ops = vivid_mem_ops[allocator];
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 8;
- q->lock = &dev->mutex;
- q->dev = dev->v4l2_dev.dev;
- q->supports_requests = true;
-
- ret = vb2_queue_init(q);
+ ret = vivid_create_queue(dev, &dev->vb_sdr_cap_q,
+ V4L2_BUF_TYPE_SDR_CAPTURE, 8,
+ &vivid_sdr_cap_qops);
+ if (ret)
+ goto unreg_dev;
+ }
+
+ if (dev->has_meta_cap) {
+ /* initialize meta_cap queue */
+ ret = vivid_create_queue(dev, &dev->vb_meta_cap_q,
+ V4L2_BUF_TYPE_META_CAPTURE, 2,
+ &vivid_meta_cap_qops);
+ if (ret)
+ goto unreg_dev;
+ }
+
+ if (dev->has_meta_out) {
+ /* initialize meta_out queue */
+ ret = vivid_create_queue(dev, &dev->vb_meta_out_q,
+ V4L2_BUF_TYPE_META_OUTPUT, 1,
+ &vivid_meta_out_qops);
+ if (ret)
+ goto unreg_dev;
+ }
+
+ if (dev->has_touch_cap) {
+ /* initialize touch_cap queue */
+ ret = vivid_create_queue(dev, &dev->vb_touch_cap_q,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, 1,
+ &vivid_touch_cap_qops);
if (ret)
goto unreg_dev;
}
@@ -1222,7 +1437,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (ret)
goto unreg_dev;
v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n",
- dev->fb_info.node);
+ dev->fb_info.node);
}
#ifdef CONFIG_VIDEO_VIVID_CEC
@@ -1265,10 +1480,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap);
/* finally start creating the device nodes */
if (dev->has_vid_cap) {
vfd = &dev->vid_cap_dev;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-vid-cap", inst);
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->vid_cap_caps;
@@ -1314,6 +1534,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_vid_out) {
vfd = &dev->vid_out_dev;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-vid-out", inst);
vfd->vfl_dir = VFL_DIR_TX;
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
@@ -1492,6 +1714,94 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
video_device_node_name(vfd));
}
+ if (dev->has_meta_cap) {
+ vfd = &dev->meta_cap_dev;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-meta-cap", inst);
+ vfd->fops = &vivid_fops;
+ vfd->ioctl_ops = &vivid_ioctl_ops;
+ vfd->device_caps = dev->meta_cap_caps;
+ vfd->release = video_device_release_empty;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->queue = &dev->vb_meta_cap_q;
+ vfd->lock = &dev->mutex;
+ vfd->tvnorms = tvnorms_cap;
+ video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->meta_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vfd->entity, 1,
+ &dev->meta_cap_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER,
+ meta_cap_nr[inst]);
+ if (ret < 0)
+ goto unreg_dev;
+ v4l2_info(&dev->v4l2_dev,
+ "V4L2 metadata capture device registered as %s\n",
+ video_device_node_name(vfd));
+ }
+
+ if (dev->has_meta_out) {
+ vfd = &dev->meta_out_dev;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-meta-out", inst);
+ vfd->vfl_dir = VFL_DIR_TX;
+ vfd->fops = &vivid_fops;
+ vfd->ioctl_ops = &vivid_ioctl_ops;
+ vfd->device_caps = dev->meta_out_caps;
+ vfd->release = video_device_release_empty;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->queue = &dev->vb_meta_out_q;
+ vfd->lock = &dev->mutex;
+ vfd->tvnorms = tvnorms_out;
+ video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->meta_out_pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_pads_init(&vfd->entity, 1,
+ &dev->meta_out_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER,
+ meta_out_nr[inst]);
+ if (ret < 0)
+ goto unreg_dev;
+ v4l2_info(&dev->v4l2_dev,
+ "V4L2 metadata output device registered as %s\n",
+ video_device_node_name(vfd));
+ }
+
+ if (dev->has_touch_cap) {
+ vfd = &dev->touch_cap_dev;
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-touch-cap", inst);
+ vfd->fops = &vivid_fops;
+ vfd->ioctl_ops = &vivid_ioctl_ops;
+ vfd->device_caps = dev->touch_cap_caps;
+ vfd->release = video_device_release_empty;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->queue = &dev->vb_touch_cap_q;
+ vfd->tvnorms = tvnorms_cap;
+ vfd->lock = &dev->mutex;
+ video_set_drvdata(vfd, dev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->touch_cap_pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vfd->entity, 1,
+ &dev->touch_cap_pad);
+ if (ret)
+ goto unreg_dev;
+#endif
+ ret = video_register_device(vfd, VFL_TYPE_TOUCH,
+ touch_cap_nr[inst]);
+ if (ret < 0)
+ goto unreg_dev;
+ v4l2_info(&dev->v4l2_dev,
+ "V4L2 touch capture device registered as %s\n",
+ video_device_node_name(vfd));
+ }
+
#ifdef CONFIG_MEDIA_CONTROLLER
/* Register the media device */
ret = media_device_register(&dev->mdev);
@@ -1508,6 +1818,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
return 0;
unreg_dev:
+ video_unregister_device(&dev->touch_cap_dev);
+ video_unregister_device(&dev->meta_out_dev);
+ video_unregister_device(&dev->meta_cap_dev);
video_unregister_device(&dev->radio_tx_dev);
video_unregister_device(&dev->radio_rx_dev);
video_unregister_device(&dev->sdr_cap_dev);
@@ -1580,7 +1893,6 @@ static int vivid_remove(struct platform_device *pdev)
#ifdef CONFIG_MEDIA_CONTROLLER
media_device_unregister(&dev->mdev);
- media_device_cleanup(&dev->mdev);
#endif
if (dev->has_vid_cap) {
@@ -1624,6 +1936,21 @@ static int vivid_remove(struct platform_device *pdev)
unregister_framebuffer(&dev->fb_info);
vivid_fb_release_buffers(dev);
}
+ if (dev->has_meta_cap) {
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->meta_cap_dev));
+ video_unregister_device(&dev->meta_cap_dev);
+ }
+ if (dev->has_meta_out) {
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->meta_out_dev));
+ video_unregister_device(&dev->meta_out_dev);
+ }
+ if (dev->has_touch_cap) {
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->touch_cap_dev));
+ video_unregister_device(&dev->touch_cap_dev);
+ }
cec_unregister_adapter(dev->cec_rx_adap);
for (j = 0; j < MAX_OUTPUTS; j++)
cec_unregister_adapter(dev->cec_tx_adap[j]);
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index 7ebb14673c75..99e69b8f770f 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -131,6 +131,9 @@ struct vivid_dev {
struct media_pad vbi_cap_pad;
struct media_pad vbi_out_pad;
struct media_pad sdr_cap_pad;
+ struct media_pad meta_cap_pad;
+ struct media_pad meta_out_pad;
+ struct media_pad touch_cap_pad;
#endif
struct v4l2_ctrl_handler ctrl_hdl_user_gen;
struct v4l2_ctrl_handler ctrl_hdl_user_vid;
@@ -153,6 +156,13 @@ struct vivid_dev {
struct v4l2_ctrl_handler ctrl_hdl_radio_tx;
struct video_device sdr_cap_dev;
struct v4l2_ctrl_handler ctrl_hdl_sdr_cap;
+ struct video_device meta_cap_dev;
+ struct v4l2_ctrl_handler ctrl_hdl_meta_cap;
+ struct video_device meta_out_dev;
+ struct v4l2_ctrl_handler ctrl_hdl_meta_out;
+ struct video_device touch_cap_dev;
+ struct v4l2_ctrl_handler ctrl_hdl_touch_cap;
+
spinlock_t slock;
struct mutex mutex;
@@ -164,6 +174,9 @@ struct vivid_dev {
u32 sdr_cap_caps;
u32 radio_rx_caps;
u32 radio_tx_caps;
+ u32 meta_cap_caps;
+ u32 meta_out_caps;
+ u32 touch_cap_caps;
/* supported features */
bool multiplanar;
@@ -189,6 +202,10 @@ struct vivid_dev {
bool has_radio_tx;
bool has_sdr_cap;
bool has_fb;
+ bool has_meta_cap;
+ bool has_meta_out;
+ bool has_tv_tuner;
+ bool has_touch_cap;
bool can_loop_video;
@@ -390,6 +407,10 @@ struct vivid_dev {
struct list_head vid_cap_active;
struct vb2_queue vb_vbi_cap_q;
struct list_head vbi_cap_active;
+ struct vb2_queue vb_meta_cap_q;
+ struct list_head meta_cap_active;
+ struct vb2_queue vb_touch_cap_q;
+ struct list_head touch_cap_active;
/* thread for generating video capture stream */
struct task_struct *kthread_vid_cap;
@@ -407,6 +428,22 @@ struct vivid_dev {
u32 vbi_cap_seq_count;
bool vbi_cap_streaming;
bool stream_sliced_vbi_cap;
+ u32 meta_cap_seq_start;
+ u32 meta_cap_seq_count;
+ bool meta_cap_streaming;
+
+ /* Touch capture */
+ struct task_struct *kthread_touch_cap;
+ unsigned long jiffies_touch_cap;
+ u64 touch_cap_stream_start;
+ u32 touch_cap_seq_offset;
+ bool touch_cap_seq_resync;
+ u32 touch_cap_seq_start;
+ u32 touch_cap_seq_count;
+ bool touch_cap_streaming;
+ struct v4l2_fract timeperframe_tch_cap;
+ struct v4l2_pix_format tch_format;
+ int tch_pat_random;
/* video output */
const struct vivid_fmt *fmt_out;
@@ -421,6 +458,8 @@ struct vivid_dev {
struct list_head vid_out_active;
struct vb2_queue vb_vbi_out_q;
struct list_head vbi_out_active;
+ struct vb2_queue vb_meta_out_q;
+ struct list_head meta_out_active;
/* video loop precalculated rectangles */
@@ -461,6 +500,9 @@ struct vivid_dev {
u32 vbi_out_seq_count;
bool vbi_out_streaming;
bool stream_sliced_vbi_out;
+ u32 meta_out_seq_start;
+ u32 meta_out_seq_count;
+ bool meta_out_streaming;
/* SDR capture */
struct vb2_queue vb_sdr_cap_q;
@@ -527,6 +569,9 @@ struct vivid_dev {
/* CEC OSD String */
char osd[14];
unsigned long osd_jiffies;
+
+ bool meta_pts;
+ bool meta_scr;
};
static inline bool vivid_is_webcam(const struct vivid_dev *dev)
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index 3e916c8befb7..334130568dcb 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -32,6 +32,7 @@
#define VIVID_CID_U32_ARRAY (VIVID_CID_CUSTOM_BASE + 8)
#define VIVID_CID_U16_MATRIX (VIVID_CID_CUSTOM_BASE + 9)
#define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10)
+#define VIVID_CID_AREA (VIVID_CID_CUSTOM_BASE + 11)
#define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000)
#define VIVID_CID_VIVID_CLASS (0x00f00000 | 1)
@@ -94,6 +95,9 @@
#define VIVID_CID_SDR_CAP_FM_DEVIATION (VIVID_CID_VIVID_BASE + 110)
+#define VIVID_CID_META_CAP_GENERATE_PTS (VIVID_CID_VIVID_BASE + 111)
+#define VIVID_CID_META_CAP_GENERATE_SCR (VIVID_CID_VIVID_BASE + 112)
+
/* General User Controls */
static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -110,6 +114,7 @@ static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl)
clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
+ clear_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags);
break;
case VIVID_CID_BUTTON:
dev->button_pressed = 30;
@@ -262,6 +267,18 @@ static const struct v4l2_ctrl_config vivid_ctrl_disconnect = {
.type = V4L2_CTRL_TYPE_BUTTON,
};
+static const struct v4l2_area area = {
+ .width = 1000,
+ .height = 2000,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_area = {
+ .ops = &vivid_user_gen_ctrl_ops,
+ .id = VIVID_CID_AREA,
+ .name = "Area",
+ .type = V4L2_CTRL_TYPE_AREA,
+ .p_def.p_const = &area,
+};
/* Framebuffer Controls */
@@ -1421,6 +1438,47 @@ static const struct v4l2_ctrl_config vivid_ctrl_sdr_cap_fm_deviation = {
.step = 1,
};
+/* Metadata Capture Control */
+
+static int vivid_meta_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev,
+ ctrl_hdl_meta_cap);
+
+ switch (ctrl->id) {
+ case VIVID_CID_META_CAP_GENERATE_PTS:
+ dev->meta_pts = ctrl->val;
+ break;
+ case VIVID_CID_META_CAP_GENERATE_SCR:
+ dev->meta_scr = ctrl->val;
+ break;
+ }
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops vivid_meta_cap_ctrl_ops = {
+ .s_ctrl = vivid_meta_cap_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_meta_has_pts = {
+ .ops = &vivid_meta_cap_ctrl_ops,
+ .id = VIVID_CID_META_CAP_GENERATE_PTS,
+ .name = "Generate PTS",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .max = 1,
+ .def = 1,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_meta_has_src_clk = {
+ .ops = &vivid_meta_cap_ctrl_ops,
+ .id = VIVID_CID_META_CAP_GENERATE_SCR,
+ .name = "Generate SCR",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .max = 1,
+ .def = 1,
+ .step = 1,
+};
static const struct v4l2_ctrl_config vivid_ctrl_class = {
.ops = &vivid_user_gen_ctrl_ops,
@@ -1448,6 +1506,10 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx;
struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx;
struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap;
+ struct v4l2_ctrl_handler *hdl_meta_cap = &dev->ctrl_hdl_meta_cap;
+ struct v4l2_ctrl_handler *hdl_meta_out = &dev->ctrl_hdl_meta_out;
+ struct v4l2_ctrl_handler *hdl_tch_cap = &dev->ctrl_hdl_touch_cap;
+
struct v4l2_ctrl_config vivid_ctrl_dv_timings = {
.ops = &vivid_vid_cap_ctrl_ops,
.id = VIVID_CID_DV_TIMINGS,
@@ -1473,7 +1535,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_handler_init(hdl_vid_cap, 55);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_vid_out, 26);
- if (!no_error_inj || dev->has_fb)
+ if (!no_error_inj || dev->has_fb || dev->num_hdmi_outputs)
v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_vbi_cap, 21);
v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL);
@@ -1486,6 +1548,12 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_sdr_cap, 19);
v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL);
+ v4l2_ctrl_handler_init(hdl_meta_cap, 2);
+ v4l2_ctrl_new_custom(hdl_meta_cap, &vivid_ctrl_class, NULL);
+ v4l2_ctrl_handler_init(hdl_meta_out, 2);
+ v4l2_ctrl_new_custom(hdl_meta_out, &vivid_ctrl_class, NULL);
+ v4l2_ctrl_handler_init(hdl_tch_cap, 2);
+ v4l2_ctrl_new_custom(hdl_tch_cap, &vivid_ctrl_class, NULL);
/* User Controls */
dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL,
@@ -1522,6 +1590,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL);
dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL);
dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL);
+ v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_area, NULL);
v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL);
v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL);
v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL);
@@ -1613,6 +1682,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
}
if (dev->num_hdmi_inputs) {
+ s64 hdmi_input_mask = GENMASK(dev->num_hdmi_inputs - 1, 0);
+
dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap,
&vivid_ctrl_dv_timings_signal_mode, NULL);
@@ -1633,12 +1704,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
0, V4L2_DV_RGB_RANGE_AUTO);
dev->ctrl_rx_power_present = v4l2_ctrl_new_std(hdl_vid_cap,
- NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0,
- (2 << (dev->num_hdmi_inputs - 1)) - 1, 0,
- (2 << (dev->num_hdmi_inputs - 1)) - 1);
+ NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0, hdmi_input_mask,
+ 0, hdmi_input_mask);
}
if (dev->num_hdmi_outputs) {
+ s64 hdmi_output_mask = GENMASK(dev->num_hdmi_outputs - 1, 0);
+
/*
* We aren't doing anything with this at the moment, but
* HDMI outputs typically have this controls.
@@ -1652,17 +1724,14 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out,
&vivid_ctrl_display_present, NULL);
dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out,
- NULL, V4L2_CID_DV_TX_HOTPLUG, 0,
- (2 << (dev->num_hdmi_outputs - 1)) - 1, 0,
- (2 << (dev->num_hdmi_outputs - 1)) - 1);
+ NULL, V4L2_CID_DV_TX_HOTPLUG, 0, hdmi_output_mask,
+ 0, hdmi_output_mask);
dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out,
- NULL, V4L2_CID_DV_TX_RXSENSE, 0,
- (2 << (dev->num_hdmi_outputs - 1)) - 1, 0,
- (2 << (dev->num_hdmi_outputs - 1)) - 1);
+ NULL, V4L2_CID_DV_TX_RXSENSE, 0, hdmi_output_mask,
+ 0, hdmi_output_mask);
dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out,
- NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0,
- (2 << (dev->num_hdmi_outputs - 1)) - 1, 0,
- (2 << (dev->num_hdmi_outputs - 1)) - 1);
+ NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0, hdmi_output_mask,
+ 0, hdmi_output_mask);
}
if ((dev->has_vid_cap && dev->has_vid_out) ||
(dev->has_vbi_cap && dev->has_vbi_out))
@@ -1743,6 +1812,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_sdr_cap,
&vivid_ctrl_sdr_cap_fm_deviation, NULL);
}
+ if (dev->has_meta_cap) {
+ v4l2_ctrl_new_custom(hdl_meta_cap,
+ &vivid_ctrl_meta_has_pts, NULL);
+ v4l2_ctrl_new_custom(hdl_meta_cap,
+ &vivid_ctrl_meta_has_src_clk, NULL);
+ }
+
if (hdl_user_gen->error)
return hdl_user_gen->error;
if (hdl_user_vid->error)
@@ -1817,6 +1893,27 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
return hdl_sdr_cap->error;
dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap;
}
+ if (dev->has_meta_cap) {
+ v4l2_ctrl_add_handler(hdl_meta_cap, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_meta_cap, hdl_streaming, NULL, false);
+ if (hdl_meta_cap->error)
+ return hdl_meta_cap->error;
+ dev->meta_cap_dev.ctrl_handler = hdl_meta_cap;
+ }
+ if (dev->has_meta_out) {
+ v4l2_ctrl_add_handler(hdl_meta_out, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_meta_out, hdl_streaming, NULL, false);
+ if (hdl_meta_out->error)
+ return hdl_meta_out->error;
+ dev->meta_out_dev.ctrl_handler = hdl_meta_out;
+ }
+ if (dev->has_touch_cap) {
+ v4l2_ctrl_add_handler(hdl_tch_cap, hdl_user_gen, NULL, false);
+ v4l2_ctrl_add_handler(hdl_tch_cap, hdl_streaming, NULL, false);
+ if (hdl_tch_cap->error)
+ return hdl_tch_cap->error;
+ dev->touch_cap_dev.ctrl_handler = hdl_tch_cap;
+ }
return 0;
}
@@ -1836,4 +1933,7 @@ void vivid_free_controls(struct vivid_dev *dev)
v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap);
v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap);
v4l2_ctrl_handler_free(&dev->ctrl_hdl_fb);
+ v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_cap);
+ v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_out);
+ v4l2_ctrl_handler_free(&dev->ctrl_hdl_touch_cap);
}
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 6cf495a7d5cc..01a9d671b947 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -39,6 +39,7 @@
#include "vivid-osd.h"
#include "vivid-ctrls.h"
#include "vivid-kthread-cap.h"
+#include "vivid-meta-cap.h"
static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev)
{
@@ -232,8 +233,8 @@ static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf,
return vbuf;
}
-static int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, u8 *vcapbuf,
- struct vivid_buffer *vid_cap_buf)
+static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned p,
+ u8 *vcapbuf, struct vivid_buffer *vid_cap_buf)
{
bool blank = dev->must_blank[vid_cap_buf->vb.vb2_buf.index];
struct tpg_data *tpg = &dev->tpg;
@@ -658,6 +659,8 @@ static void vivid_cap_update_frame_period(struct vivid_dev *dev)
u64 f_period;
f_period = (u64)dev->timeperframe_vid_cap.numerator * 1000000000;
+ if (WARN_ON(dev->timeperframe_vid_cap.denominator == 0))
+ dev->timeperframe_vid_cap.denominator = 1;
do_div(f_period, dev->timeperframe_vid_cap.denominator);
if (dev->field_cap == V4L2_FIELD_ALTERNATE)
f_period >>= 1;
@@ -670,10 +673,12 @@ static void vivid_cap_update_frame_period(struct vivid_dev *dev)
dev->cap_frame_period = f_period;
}
-static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
+static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev,
+ int dropped_bufs)
{
struct vivid_buffer *vid_cap_buf = NULL;
struct vivid_buffer *vbi_cap_buf = NULL;
+ struct vivid_buffer *meta_cap_buf = NULL;
u64 f_time = 0;
dprintk(dev, 1, "Video Capture Thread Tick\n");
@@ -701,15 +706,19 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
list_del(&vbi_cap_buf->list);
}
}
+ if (!list_empty(&dev->meta_cap_active)) {
+ meta_cap_buf = list_entry(dev->meta_cap_active.next,
+ struct vivid_buffer, list);
+ list_del(&meta_cap_buf->list);
+ }
+
spin_unlock(&dev->slock);
- if (!vid_cap_buf && !vbi_cap_buf)
+ if (!vid_cap_buf && !vbi_cap_buf && !meta_cap_buf)
goto update_mv;
f_time = dev->cap_frame_period * dev->vid_cap_seq_count +
dev->cap_stream_start + dev->time_wrap_offset;
- if (!dev->tstamp_src_is_soe)
- f_time += dev->cap_frame_eof_offset;
if (vid_cap_buf) {
v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req,
@@ -732,6 +741,8 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
vid_cap_buf->vb.vb2_buf.index);
vid_cap_buf->vb.vb2_buf.timestamp = f_time;
+ if (!dev->tstamp_src_is_soe)
+ vid_cap_buf->vb.vb2_buf.timestamp += dev->cap_frame_eof_offset;
}
if (vbi_cap_buf) {
@@ -753,8 +764,22 @@ static void vivid_thread_vid_cap_tick(struct vivid_dev *dev, int dropped_bufs)
/* If capturing a VBI, offset by 0.05 */
vbi_period = dev->cap_frame_period * 5;
do_div(vbi_period, 100);
- vbi_cap_buf->vb.vb2_buf.timestamp = f_time + vbi_period;
+ vbi_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset + vbi_period;
+ }
+
+ if (meta_cap_buf) {
+ v4l2_ctrl_request_setup(meta_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_meta_cap);
+ vivid_meta_cap_fillbuff(dev, meta_cap_buf, f_time);
+ v4l2_ctrl_request_complete(meta_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_meta_cap);
+ vb2_buffer_done(&meta_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
+ VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+ dprintk(dev, 2, "meta_cap %d done\n",
+ meta_cap_buf->vb.vb2_buf.index);
+ meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset;
}
+
dev->dqbuf_error = false;
update_mv:
@@ -793,7 +818,11 @@ static int vivid_thread_vid_cap(void *data)
if (kthread_should_stop())
break;
- mutex_lock(&dev->mutex);
+ if (!mutex_trylock(&dev->mutex)) {
+ schedule_timeout_uninterruptible(1);
+ continue;
+ }
+
cur_jiffies = jiffies;
if (dev->cap_seq_resync) {
dev->jiffies_vid_cap = cur_jiffies;
@@ -832,6 +861,7 @@ static int vivid_thread_vid_cap(void *data)
dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset;
dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start;
dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start;
+ dev->meta_cap_seq_count = dev->cap_seq_count - dev->meta_cap_seq_start;
vivid_thread_vid_cap_tick(dev, dropped_bufs);
@@ -880,8 +910,10 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
if (pstreaming == &dev->vid_cap_streaming)
dev->vid_cap_seq_start = seq_count;
- else
+ else if (pstreaming == &dev->vbi_cap_streaming)
dev->vbi_cap_seq_start = seq_count;
+ else
+ dev->meta_cap_seq_start = seq_count;
*pstreaming = true;
return 0;
}
@@ -891,6 +923,7 @@ int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
dev->vid_cap_seq_start = dev->seq_wrap * 128;
dev->vbi_cap_seq_start = dev->seq_wrap * 128;
+ dev->meta_cap_seq_start = dev->seq_wrap * 128;
dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev,
"%s-vid-cap", dev->v4l2_dev.name);
@@ -948,13 +981,27 @@ void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming)
}
}
- if (dev->vid_cap_streaming || dev->vbi_cap_streaming)
+ if (pstreaming == &dev->meta_cap_streaming) {
+ while (!list_empty(&dev->meta_cap_active)) {
+ struct vivid_buffer *buf;
+
+ buf = list_entry(dev->meta_cap_active.next,
+ struct vivid_buffer, list);
+ list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_meta_cap);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ dprintk(dev, 2, "meta_cap buffer %d done\n",
+ buf->vb.vb2_buf.index);
+ }
+ }
+
+ if (dev->vid_cap_streaming || dev->vbi_cap_streaming ||
+ dev->meta_cap_streaming)
return;
/* shutdown control thread */
vivid_grab_controls(dev, false);
- mutex_unlock(&dev->mutex);
kthread_stop(dev->kthread_vid_cap);
dev->kthread_vid_cap = NULL;
- mutex_lock(&dev->mutex);
}
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c
index ce5bcda2348c..6780687978f9 100644
--- a/drivers/media/platform/vivid/vivid-kthread-out.c
+++ b/drivers/media/platform/vivid/vivid-kthread-out.c
@@ -38,11 +38,13 @@
#include "vivid-osd.h"
#include "vivid-ctrls.h"
#include "vivid-kthread-out.h"
+#include "vivid-meta-out.h"
static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
{
struct vivid_buffer *vid_out_buf = NULL;
struct vivid_buffer *vbi_out_buf = NULL;
+ struct vivid_buffer *meta_out_buf = NULL;
dprintk(dev, 1, "Video Output Thread Tick\n");
@@ -69,9 +71,14 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
struct vivid_buffer, list);
list_del(&vbi_out_buf->list);
}
+ if (!list_empty(&dev->meta_out_active)) {
+ meta_out_buf = list_entry(dev->meta_out_active.next,
+ struct vivid_buffer, list);
+ list_del(&meta_out_buf->list);
+ }
spin_unlock(&dev->slock);
- if (!vid_out_buf && !vbi_out_buf)
+ if (!vid_out_buf && !vbi_out_buf && !meta_out_buf)
return;
if (vid_out_buf) {
@@ -111,6 +118,21 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
dprintk(dev, 2, "vbi_out buffer %d done\n",
vbi_out_buf->vb.vb2_buf.index);
}
+ if (meta_out_buf) {
+ v4l2_ctrl_request_setup(meta_out_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_meta_out);
+ v4l2_ctrl_request_complete(meta_out_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_meta_out);
+ vivid_meta_out_process(dev, meta_out_buf);
+ meta_out_buf->vb.sequence = dev->meta_out_seq_count;
+ meta_out_buf->vb.vb2_buf.timestamp =
+ ktime_get_ns() + dev->time_wrap_offset;
+ vb2_buffer_done(&meta_out_buf->vb.vb2_buf, dev->dqbuf_error ?
+ VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+ dprintk(dev, 2, "meta_out buffer %d done\n",
+ meta_out_buf->vb.vb2_buf.index);
+ }
+
dev->dqbuf_error = false;
}
@@ -136,6 +158,7 @@ static int vivid_thread_vid_out(void *data)
dev->out_seq_count = 0xffffff80U;
dev->jiffies_vid_out = jiffies;
dev->vid_out_seq_start = dev->vbi_out_seq_start = 0;
+ dev->meta_out_seq_start = 0;
dev->out_seq_resync = false;
for (;;) {
@@ -143,7 +166,11 @@ static int vivid_thread_vid_out(void *data)
if (kthread_should_stop())
break;
- mutex_lock(&dev->mutex);
+ if (!mutex_trylock(&dev->mutex)) {
+ schedule_timeout_uninterruptible(1);
+ continue;
+ }
+
cur_jiffies = jiffies;
if (dev->out_seq_resync) {
dev->jiffies_vid_out = cur_jiffies;
@@ -178,6 +205,7 @@ static int vivid_thread_vid_out(void *data)
dev->out_seq_count = buffers_since_start + dev->out_seq_offset;
dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start;
dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start;
+ dev->meta_out_seq_count = dev->out_seq_count - dev->meta_out_seq_start;
vivid_thread_vid_out_tick(dev);
mutex_unlock(&dev->mutex);
@@ -229,8 +257,10 @@ int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
if (pstreaming == &dev->vid_out_streaming)
dev->vid_out_seq_start = seq_count;
- else
+ else if (pstreaming == &dev->vbi_out_streaming)
dev->vbi_out_seq_start = seq_count;
+ else
+ dev->meta_out_seq_start = seq_count;
*pstreaming = true;
return 0;
}
@@ -239,6 +269,7 @@ int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
dev->jiffies_vid_out = jiffies;
dev->vid_out_seq_start = dev->seq_wrap * 128;
dev->vbi_out_seq_start = dev->seq_wrap * 128;
+ dev->meta_out_seq_start = dev->seq_wrap * 128;
dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev,
"%s-vid-out", dev->v4l2_dev.name);
@@ -296,13 +327,27 @@ void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming)
}
}
- if (dev->vid_out_streaming || dev->vbi_out_streaming)
+ if (pstreaming == &dev->meta_out_streaming) {
+ while (!list_empty(&dev->meta_out_active)) {
+ struct vivid_buffer *buf;
+
+ buf = list_entry(dev->meta_out_active.next,
+ struct vivid_buffer, list);
+ list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_meta_out);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ dprintk(dev, 2, "meta_out buffer %d done\n",
+ buf->vb.vb2_buf.index);
+ }
+ }
+
+ if (dev->vid_out_streaming || dev->vbi_out_streaming ||
+ dev->meta_out_streaming)
return;
/* shutdown control thread */
vivid_grab_controls(dev, false);
- mutex_unlock(&dev->mutex);
kthread_stop(dev->kthread_vid_out);
dev->kthread_vid_out = NULL;
- mutex_lock(&dev->mutex);
}
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.c b/drivers/media/platform/vivid/vivid-kthread-touch.c
new file mode 100644
index 000000000000..674507b5ccb5
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-kthread-touch.c - touch capture thread support functions.
+ *
+ */
+
+#include <linux/freezer.h>
+#include "vivid-core.h"
+#include "vivid-kthread-touch.h"
+#include "vivid-touch-cap.h"
+
+static noinline_for_stack void vivid_thread_tch_cap_tick(struct vivid_dev *dev,
+ int dropped_bufs)
+{
+ struct vivid_buffer *tch_cap_buf = NULL;
+
+ spin_lock(&dev->slock);
+ if (!list_empty(&dev->touch_cap_active)) {
+ tch_cap_buf = list_entry(dev->touch_cap_active.next,
+ struct vivid_buffer, list);
+ list_del(&tch_cap_buf->list);
+ }
+
+ spin_unlock(&dev->slock);
+
+ if (tch_cap_buf) {
+ v4l2_ctrl_request_setup(tch_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_touch_cap);
+
+ vivid_fillbuff_tch(dev, tch_cap_buf);
+ v4l2_ctrl_request_complete(tch_cap_buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_touch_cap);
+ vb2_buffer_done(&tch_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
+ VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+ dprintk(dev, 2, "touch_cap buffer %d done\n",
+ tch_cap_buf->vb.vb2_buf.index);
+
+ tch_cap_buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset;
+ }
+ dev->dqbuf_error = false;
+}
+
+static int vivid_thread_touch_cap(void *data)
+{
+ struct vivid_dev *dev = data;
+ u64 numerators_since_start;
+ u64 buffers_since_start;
+ u64 next_jiffies_since_start;
+ unsigned long jiffies_since_start;
+ unsigned long cur_jiffies;
+ unsigned int wait_jiffies;
+ unsigned int numerator;
+ unsigned int denominator;
+ int dropped_bufs;
+
+ dprintk(dev, 1, "Touch Capture Thread Start\n");
+
+ set_freezable();
+
+ /* Resets frame counters */
+ dev->touch_cap_seq_offset = 0;
+ dev->touch_cap_seq_count = 0;
+ dev->touch_cap_seq_resync = false;
+ dev->jiffies_touch_cap = jiffies;
+
+ for (;;) {
+ try_to_freeze();
+ if (kthread_should_stop())
+ break;
+
+ if (!mutex_trylock(&dev->mutex)) {
+ schedule_timeout_uninterruptible(1);
+ continue;
+ }
+ cur_jiffies = jiffies;
+ if (dev->touch_cap_seq_resync) {
+ dev->jiffies_touch_cap = cur_jiffies;
+ dev->touch_cap_seq_offset = dev->touch_cap_seq_count + 1;
+ dev->touch_cap_seq_count = 0;
+ dev->cap_seq_resync = false;
+ }
+ denominator = dev->timeperframe_tch_cap.denominator;
+ numerator = dev->timeperframe_tch_cap.numerator;
+
+ /* Calculate the number of jiffies since we started streaming */
+ jiffies_since_start = cur_jiffies - dev->jiffies_touch_cap;
+ /* Get the number of buffers streamed since the start */
+ buffers_since_start = (u64)jiffies_since_start * denominator +
+ (HZ * numerator) / 2;
+ do_div(buffers_since_start, HZ * numerator);
+
+ /*
+ * After more than 0xf0000000 (rounded down to a multiple of
+ * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+ * jiffies have passed since we started streaming reset the
+ * counters and keep track of the sequence offset.
+ */
+ if (jiffies_since_start > JIFFIES_RESYNC) {
+ dev->jiffies_touch_cap = cur_jiffies;
+ dev->cap_seq_offset = buffers_since_start;
+ buffers_since_start = 0;
+ }
+ dropped_bufs = buffers_since_start + dev->touch_cap_seq_offset - dev->touch_cap_seq_count;
+ dev->touch_cap_seq_count = buffers_since_start + dev->touch_cap_seq_offset;
+
+ vivid_thread_tch_cap_tick(dev, dropped_bufs);
+
+ /*
+ * Calculate the number of 'numerators' streamed
+ * since we started, including the current buffer.
+ */
+ numerators_since_start = ++buffers_since_start * numerator;
+
+ /* And the number of jiffies since we started */
+ jiffies_since_start = jiffies - dev->jiffies_touch_cap;
+
+ mutex_unlock(&dev->mutex);
+
+ /*
+ * Calculate when that next buffer is supposed to start
+ * in jiffies since we started streaming.
+ */
+ next_jiffies_since_start = numerators_since_start * HZ +
+ denominator / 2;
+ do_div(next_jiffies_since_start, denominator);
+ /* If it is in the past, then just schedule asap */
+ if (next_jiffies_since_start < jiffies_since_start)
+ next_jiffies_since_start = jiffies_since_start;
+
+ wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+ schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+ }
+ dprintk(dev, 1, "Touch Capture Thread End\n");
+ return 0;
+}
+
+int vivid_start_generating_touch_cap(struct vivid_dev *dev)
+{
+ if (dev->kthread_touch_cap) {
+ dev->touch_cap_streaming = true;
+ return 0;
+ }
+
+ dev->kthread_touch_cap = kthread_run(vivid_thread_touch_cap, dev,
+ "%s-tch-cap", dev->v4l2_dev.name);
+
+ if (IS_ERR(dev->kthread_touch_cap)) {
+ int err = PTR_ERR(dev->kthread_touch_cap);
+
+ dev->kthread_touch_cap = NULL;
+ v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+ return err;
+ }
+ dev->touch_cap_streaming = true;
+ dprintk(dev, 1, "returning from %s\n", __func__);
+ return 0;
+}
+
+void vivid_stop_generating_touch_cap(struct vivid_dev *dev)
+{
+ if (!dev->kthread_touch_cap)
+ return;
+
+ dev->touch_cap_streaming = false;
+
+ while (!list_empty(&dev->touch_cap_active)) {
+ struct vivid_buffer *buf;
+
+ buf = list_entry(dev->touch_cap_active.next,
+ struct vivid_buffer, list);
+ list_del(&buf->list);
+ v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req,
+ &dev->ctrl_hdl_touch_cap);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ dprintk(dev, 2, "touch_cap buffer %d done\n",
+ buf->vb.vb2_buf.index);
+ }
+
+ kthread_stop(dev->kthread_touch_cap);
+ dev->kthread_touch_cap = NULL;
+}
diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.h b/drivers/media/platform/vivid/vivid-kthread-touch.h
new file mode 100644
index 000000000000..ecf79b46209e
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-kthread-touch.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * vivid-kthread-cap.h - video/vbi capture thread support functions.
+ *
+ */
+
+#ifndef _VIVID_KTHREAD_CAP_H_
+#define _VIVID_KTHREAD_CAP_H_
+
+int vivid_start_generating_touch_cap(struct vivid_dev *dev);
+void vivid_stop_generating_touch_cap(struct vivid_dev *dev);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-meta-cap.c b/drivers/media/platform/vivid/vivid-meta-cap.c
new file mode 100644
index 000000000000..780f96860a6d
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-meta-cap.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-meta-cap.c - meta capture support functions.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/usb/video.h>
+
+#include "vivid-core.h"
+#include "vivid-kthread-cap.h"
+#include "vivid-meta-cap.h"
+
+static int meta_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+ unsigned int size = sizeof(struct vivid_uvc_meta_buf);
+
+ if (!vivid_is_webcam(dev))
+ return -EINVAL;
+
+ if (*nplanes) {
+ if (sizes[0] < size)
+ return -EINVAL;
+ } else {
+ sizes[0] = size;
+ }
+
+ if (vq->num_buffers + *nbuffers < 2)
+ *nbuffers = 2 - vq->num_buffers;
+
+ *nplanes = 1;
+ return 0;
+}
+
+static int meta_cap_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned int size = sizeof(struct vivid_uvc_meta_buf);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (dev->buf_prepare_error) {
+ /*
+ * Error injection: test what happens if buf_prepare() returns
+ * an error.
+ */
+ dev->buf_prepare_error = false;
+ return -EINVAL;
+ }
+ if (vb2_plane_size(vb, 0) < size) {
+ dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(vb, 0, size);
+
+ return 0;
+}
+
+static void meta_cap_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ spin_lock(&dev->slock);
+ list_add_tail(&buf->list, &dev->meta_cap_active);
+ spin_unlock(&dev->slock);
+}
+
+static int meta_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+ int err;
+
+ dprintk(dev, 1, "%s\n", __func__);
+ dev->meta_cap_seq_count = 0;
+ if (dev->start_streaming_error) {
+ dev->start_streaming_error = false;
+ err = -EINVAL;
+ } else {
+ err = vivid_start_generating_vid_cap(dev,
+ &dev->meta_cap_streaming);
+ }
+ if (err) {
+ struct vivid_buffer *buf, *tmp;
+
+ list_for_each_entry_safe(buf, tmp,
+ &dev->meta_cap_active, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf,
+ VB2_BUF_STATE_QUEUED);
+ }
+ }
+ return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void meta_cap_stop_streaming(struct vb2_queue *vq)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+ dprintk(dev, 1, "%s\n", __func__);
+ vivid_stop_generating_vid_cap(dev, &dev->meta_cap_streaming);
+}
+
+static void meta_cap_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_meta_cap);
+}
+
+const struct vb2_ops vivid_meta_cap_qops = {
+ .queue_setup = meta_cap_queue_setup,
+ .buf_prepare = meta_cap_buf_prepare,
+ .buf_queue = meta_cap_buf_queue,
+ .start_streaming = meta_cap_start_streaming,
+ .stop_streaming = meta_cap_stop_streaming,
+ .buf_request_complete = meta_cap_buf_request_complete,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+int vidioc_enum_fmt_meta_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ if (!vivid_is_webcam(dev))
+ return -EINVAL;
+
+ if (f->index > 0)
+ return -EINVAL;
+
+ f->type = V4L2_BUF_TYPE_META_CAPTURE;
+ f->pixelformat = V4L2_META_FMT_UVC;
+ return 0;
+}
+
+int vidioc_g_fmt_meta_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+ struct v4l2_meta_format *meta = &f->fmt.meta;
+
+ if (!vivid_is_webcam(dev) || !dev->has_meta_cap)
+ return -EINVAL;
+
+ meta->dataformat = V4L2_META_FMT_UVC;
+ meta->buffersize = sizeof(struct vivid_uvc_meta_buf);
+ return 0;
+}
+
+void vivid_meta_cap_fillbuff(struct vivid_dev *dev,
+ struct vivid_buffer *buf, u64 soe)
+{
+ struct vivid_uvc_meta_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+ int buf_off = 0;
+
+ buf->vb.sequence = dev->meta_cap_seq_count;
+ if (dev->field_cap == V4L2_FIELD_ALTERNATE)
+ buf->vb.sequence /= 2;
+ memset(meta, 1, vb2_plane_size(&buf->vb.vb2_buf, 0));
+
+ meta->ns = ktime_get_ns();
+ meta->sof = buf->vb.sequence * 30;
+ meta->length = sizeof(*meta) - offsetof(struct vivid_uvc_meta_buf, length);
+ meta->flags = UVC_STREAM_EOH | UVC_STREAM_EOF;
+
+ if ((buf->vb.sequence % 2) == 0)
+ meta->flags |= UVC_STREAM_FID;
+
+ dprintk(dev, 2, "%s ns:%llu sof:%4d len:%u flags: 0x%02x",
+ __func__, meta->ns, meta->sof, meta->length, meta->flags);
+ if (dev->meta_pts) {
+ meta->flags |= UVC_STREAM_PTS;
+ meta->buf[0] = div_u64(soe, VIVID_META_CLOCK_UNIT);
+ buf_off = 4;
+ dprintk(dev, 2, " pts: %u\n", *(__u32 *)(meta->buf));
+ }
+
+ if (dev->meta_scr) {
+ meta->flags |= UVC_STREAM_SCR;
+ meta->buf[buf_off] = div_u64((soe + dev->cap_frame_eof_offset),
+ VIVID_META_CLOCK_UNIT);
+
+ meta->buf[buf_off + 4] = (buf->vb.sequence * 30) % 1000;
+ dprintk(dev, 2, " stc: %u, sof counter: %u\n",
+ *(__u32 *)(meta->buf + buf_off),
+ *(__u16 *)(meta->buf + buf_off + 4));
+ }
+ dprintk(dev, 2, "\n");
+}
diff --git a/drivers/media/platform/vivid/vivid-meta-cap.h b/drivers/media/platform/vivid/vivid-meta-cap.h
new file mode 100644
index 000000000000..4670d00d1576
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-meta-cap.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * vivid-meta-cap.h - meta capture support functions.
+ */
+#ifndef _VIVID_META_CAP_H_
+#define _VIVID_META_CAP_H_
+
+#define VIVID_META_CLOCK_UNIT 10 /* 100 MHz */
+
+struct vivid_uvc_meta_buf {
+ __u64 ns;
+ __u16 sof;
+ __u8 length;
+ __u8 flags;
+ __u8 buf[10]; /* PTS(4)+STC(4)+SOF(2) */
+} __packed;
+
+void vivid_meta_cap_fillbuff(struct vivid_dev *dev,
+ struct vivid_buffer *buf, u64 soe);
+
+int vidioc_enum_fmt_meta_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f);
+
+int vidioc_g_fmt_meta_cap(struct file *file, void *priv,
+ struct v4l2_format *f);
+
+extern const struct vb2_ops vivid_meta_cap_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-meta-out.c b/drivers/media/platform/vivid/vivid-meta-out.c
new file mode 100644
index 000000000000..ff8a039aba72
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-meta-out.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-meta-out.c - meta output support functions.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/usb/video.h>
+
+#include "vivid-core.h"
+#include "vivid-kthread-out.h"
+#include "vivid-meta-out.h"
+
+static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+ unsigned int size = sizeof(struct vivid_meta_out_buf);
+
+ if (!vivid_is_webcam(dev))
+ return -EINVAL;
+
+ if (*nplanes) {
+ if (sizes[0] < size)
+ return -EINVAL;
+ } else {
+ sizes[0] = size;
+ }
+
+ if (vq->num_buffers + *nbuffers < 2)
+ *nbuffers = 2 - vq->num_buffers;
+
+ *nplanes = 1;
+ return 0;
+}
+
+static int meta_out_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned int size = sizeof(struct vivid_meta_out_buf);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (dev->buf_prepare_error) {
+ /*
+ * Error injection: test what happens if buf_prepare() returns
+ * an error.
+ */
+ dev->buf_prepare_error = false;
+ return -EINVAL;
+ }
+ if (vb2_plane_size(vb, 0) < size) {
+ dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(vb, 0, size);
+
+ return 0;
+}
+
+static void meta_out_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ spin_lock(&dev->slock);
+ list_add_tail(&buf->list, &dev->meta_out_active);
+ spin_unlock(&dev->slock);
+}
+
+static int meta_out_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+ int err;
+
+ dprintk(dev, 1, "%s\n", __func__);
+ dev->meta_out_seq_count = 0;
+ if (dev->start_streaming_error) {
+ dev->start_streaming_error = false;
+ err = -EINVAL;
+ } else {
+ err = vivid_start_generating_vid_out(dev,
+ &dev->meta_out_streaming);
+ }
+ if (err) {
+ struct vivid_buffer *buf, *tmp;
+
+ list_for_each_entry_safe(buf, tmp,
+ &dev->meta_out_active, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf,
+ VB2_BUF_STATE_QUEUED);
+ }
+ }
+ return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void meta_out_stop_streaming(struct vb2_queue *vq)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+ dprintk(dev, 1, "%s\n", __func__);
+ vivid_stop_generating_vid_out(dev, &dev->meta_out_streaming);
+}
+
+static void meta_out_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_meta_out);
+}
+
+const struct vb2_ops vivid_meta_out_qops = {
+ .queue_setup = meta_out_queue_setup,
+ .buf_prepare = meta_out_buf_prepare,
+ .buf_queue = meta_out_buf_queue,
+ .start_streaming = meta_out_start_streaming,
+ .stop_streaming = meta_out_stop_streaming,
+ .buf_request_complete = meta_out_buf_request_complete,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+int vidioc_enum_fmt_meta_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ if (!vivid_is_webcam(dev))
+ return -EINVAL;
+
+ if (f->index > 0)
+ return -EINVAL;
+
+ f->type = V4L2_BUF_TYPE_META_OUTPUT;
+ f->pixelformat = V4L2_META_FMT_VIVID;
+ return 0;
+}
+
+int vidioc_g_fmt_meta_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+ struct v4l2_meta_format *meta = &f->fmt.meta;
+
+ if (!vivid_is_webcam(dev) || !dev->has_meta_out)
+ return -EINVAL;
+
+ meta->dataformat = V4L2_META_FMT_VIVID;
+ meta->buffersize = sizeof(struct vivid_meta_out_buf);
+ return 0;
+}
+
+void vivid_meta_out_process(struct vivid_dev *dev,
+ struct vivid_buffer *buf)
+{
+ struct vivid_meta_out_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+
+ tpg_s_brightness(&dev->tpg, meta->brightness);
+ tpg_s_contrast(&dev->tpg, meta->contrast);
+ tpg_s_saturation(&dev->tpg, meta->saturation);
+ tpg_s_hue(&dev->tpg, meta->hue);
+ dprintk(dev, 2, " %s brightness %u contrast %u saturation %u hue %d\n",
+ __func__, meta->brightness, meta->contrast,
+ meta->saturation, meta->hue);
+}
diff --git a/drivers/media/platform/vivid/vivid-meta-out.h b/drivers/media/platform/vivid/vivid-meta-out.h
new file mode 100644
index 000000000000..0c639b7c2842
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-meta-out.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * vivid-meta-out.h - meta output support functions.
+ */
+#ifndef _VIVID_META_OUT_H_
+#define _VIVID_META_OUT_H_
+
+struct vivid_meta_out_buf {
+ u16 brightness;
+ u16 contrast;
+ u16 saturation;
+ s16 hue;
+};
+
+void vivid_meta_out_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+int vidioc_enum_fmt_meta_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f);
+int vidioc_g_fmt_meta_out(struct file *file, void *priv,
+ struct v4l2_format *f);
+int vidioc_s_fmt_meta_out(struct file *file, void *priv,
+ struct v4l2_format *f);
+
+extern const struct vb2_ops vivid_meta_out_qops;
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c
index f2e789bdf4a6..fbaec8acc161 100644
--- a/drivers/media/platform/vivid/vivid-osd.c
+++ b/drivers/media/platform/vivid/vivid-osd.c
@@ -244,7 +244,7 @@ static int vivid_fb_blank(int blank_mode, struct fb_info *info)
return 0;
}
-static struct fb_ops vivid_fb_ops = {
+static const struct fb_ops vivid_fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = vivid_fb_check_var,
.fb_set_par = vivid_fb_set_par,
@@ -311,7 +311,6 @@ static int vivid_fb_init_vidmode(struct vivid_dev *dev)
dev->fb_info.node = -1;
dev->fb_info.flags = FBINFO_FLAG_DEFAULT;
- dev->fb_info.fbops = &vivid_fb_ops;
dev->fb_info.par = dev;
dev->fb_info.var = dev->fb_defined;
dev->fb_info.fix = dev->fb_fix;
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
index 9acc709b0740..2b7522e16efc 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -141,7 +141,11 @@ static int vivid_thread_sdr_cap(void *data)
if (kthread_should_stop())
break;
- mutex_lock(&dev->mutex);
+ if (!mutex_trylock(&dev->mutex)) {
+ schedule_timeout_uninterruptible(1);
+ continue;
+ }
+
cur_jiffies = jiffies;
if (dev->sdr_cap_seq_resync) {
dev->jiffies_sdr_cap = cur_jiffies;
@@ -303,10 +307,8 @@ static void sdr_cap_stop_streaming(struct vb2_queue *vq)
}
/* shutdown control thread */
- mutex_unlock(&dev->mutex);
kthread_stop(dev->kthread_sdr_cap);
dev->kthread_sdr_cap = NULL;
- mutex_lock(&dev->mutex);
}
static void sdr_cap_buf_request_complete(struct vb2_buffer *vb)
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.c b/drivers/media/platform/vivid/vivid-touch-cap.c
new file mode 100644
index 000000000000..ebb00b128030
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.c
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * vivid-touch-cap.c - touch support functions.
+ */
+
+#include "vivid-core.h"
+#include "vivid-kthread-touch.h"
+#include "vivid-vid-common.h"
+#include "vivid-touch-cap.h"
+
+static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+ struct v4l2_pix_format *f = &dev->tch_format;
+ unsigned int size = f->sizeimage;
+
+ if (*nplanes) {
+ if (sizes[0] < size)
+ return -EINVAL;
+ } else {
+ sizes[0] = size;
+ }
+
+ if (vq->num_buffers + *nbuffers < 2)
+ *nbuffers = 2 - vq->num_buffers;
+
+ *nplanes = 1;
+ return 0;
+}
+
+static int touch_cap_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct v4l2_pix_format *f = &dev->tch_format;
+ unsigned int size = f->sizeimage;
+
+ if (dev->buf_prepare_error) {
+ /*
+ * Error injection: test what happens if buf_prepare() returns
+ * an error.
+ */
+ dev->buf_prepare_error = false;
+ return -EINVAL;
+ }
+ if (vb2_plane_size(vb, 0) < size) {
+ dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(vb, 0, size);
+
+ return 0;
+}
+
+static void touch_cap_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb);
+
+ vbuf->field = V4L2_FIELD_NONE;
+ spin_lock(&dev->slock);
+ list_add_tail(&buf->list, &dev->touch_cap_active);
+ spin_unlock(&dev->slock);
+}
+
+static int touch_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+ int err;
+
+ dev->touch_cap_seq_count = 0;
+ if (dev->start_streaming_error) {
+ dev->start_streaming_error = false;
+ err = -EINVAL;
+ } else {
+ err = vivid_start_generating_touch_cap(dev);
+ }
+ if (err) {
+ struct vivid_buffer *buf, *tmp;
+
+ list_for_each_entry_safe(buf, tmp,
+ &dev->touch_cap_active, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf,
+ VB2_BUF_STATE_QUEUED);
+ }
+ }
+ return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void touch_cap_stop_streaming(struct vb2_queue *vq)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+ vivid_stop_generating_touch_cap(dev);
+}
+
+static void touch_cap_buf_request_complete(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+
+ v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_touch_cap);
+}
+
+const struct vb2_ops vivid_touch_cap_qops = {
+ .queue_setup = touch_cap_queue_setup,
+ .buf_prepare = touch_cap_buf_prepare,
+ .buf_queue = touch_cap_buf_queue,
+ .start_streaming = touch_cap_start_streaming,
+ .stop_streaming = touch_cap_stop_streaming,
+ .buf_request_complete = touch_cap_buf_request_complete,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+ if (f->index)
+ return -EINVAL;
+
+ f->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
+ return 0;
+}
+
+int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ if (dev->multiplanar)
+ return -ENOTTY;
+ f->fmt.pix = dev->tch_format;
+ return 0;
+}
+
+int vivid_g_fmt_tch_mplane(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+ struct v4l2_format sp_fmt;
+
+ if (!dev->multiplanar)
+ return -ENOTTY;
+ sp_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ sp_fmt.fmt.pix = dev->tch_format;
+ fmt_sp2mp(&sp_fmt, f);
+ return 0;
+}
+
+int vivid_g_parm_tch(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ if (parm->type != (dev->multiplanar ?
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE))
+ return -EINVAL;
+
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.timeperframe = dev->timeperframe_tch_cap;
+ parm->parm.capture.readbuffers = 1;
+ return 0;
+}
+
+int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp)
+{
+ if (inp->index)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_TOUCH;
+ strscpy(inp->name, "Vivid Touch", sizeof(inp->name));
+ inp->capabilities = 0;
+ return 0;
+}
+
+int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+int vivid_set_touch(struct vivid_dev *dev, unsigned int i)
+{
+ struct v4l2_pix_format *f = &dev->tch_format;
+
+ if (i)
+ return -EINVAL;
+
+ f->pixelformat = V4L2_TCH_FMT_DELTA_TD16;
+ f->width = VIVID_TCH_WIDTH;
+ f->height = VIVID_TCH_HEIGHT;
+ f->field = V4L2_FIELD_NONE;
+ f->colorspace = V4L2_COLORSPACE_RAW;
+ f->bytesperline = f->width * sizeof(s16);
+ f->sizeimage = f->width * f->height * sizeof(s16);
+ return 0;
+}
+
+int vivid_s_input_tch(struct file *file, void *priv, unsigned int i)
+{
+ return vivid_set_touch(video_drvdata(file), i);
+}
+
+static void vivid_fill_buff_noise(__s16 *tch_buf, int size)
+{
+ int i;
+
+ /* Fill 10% of the values within range -3 and 3, zero the others */
+ for (i = 0; i < size; i++) {
+ unsigned int rand = get_random_int();
+
+ if (rand % 10)
+ tch_buf[i] = 0;
+ else
+ tch_buf[i] = (rand / 10) % 7 - 3;
+ }
+}
+
+static inline int get_random_pressure(void)
+{
+ return get_random_int() % VIVID_PRESSURE_LIMIT;
+}
+
+static void vivid_tch_buf_set(struct v4l2_pix_format *f,
+ __s16 *tch_buf,
+ int index)
+{
+ unsigned int x = index % f->width;
+ unsigned int y = index / f->width;
+ unsigned int offset = VIVID_MIN_PRESSURE;
+
+ tch_buf[index] = offset + get_random_pressure();
+ offset /= 2;
+ if (x)
+ tch_buf[index - 1] = offset + get_random_pressure();
+ if (x < f->width - 1)
+ tch_buf[index + 1] = offset + get_random_pressure();
+ if (y)
+ tch_buf[index - f->width] = offset + get_random_pressure();
+ if (y < f->height - 1)
+ tch_buf[index + f->width] = offset + get_random_pressure();
+ offset /= 2;
+ if (x && y)
+ tch_buf[index - 1 - f->width] = offset + get_random_pressure();
+ if (x < f->width - 1 && y)
+ tch_buf[index + 1 - f->width] = offset + get_random_pressure();
+ if (x && y < f->height - 1)
+ tch_buf[index - 1 + f->width] = offset + get_random_pressure();
+ if (x < f->width - 1 && y < f->height - 1)
+ tch_buf[index + 1 + f->width] = offset + get_random_pressure();
+}
+
+void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+ struct v4l2_pix_format *f = &dev->tch_format;
+ int size = f->width * f->height;
+ int x, y, xstart, ystart, offset_x, offset_y;
+ unsigned int test_pattern, test_pat_idx, rand;
+
+ __s16 *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+
+ buf->vb.sequence = dev->touch_cap_seq_count;
+ test_pattern = (buf->vb.sequence / TCH_SEQ_COUNT) % TEST_CASE_MAX;
+ test_pat_idx = buf->vb.sequence % TCH_SEQ_COUNT;
+
+ vivid_fill_buff_noise(tch_buf, size);
+
+ if (test_pat_idx >= TCH_PATTERN_COUNT)
+ return;
+
+ if (test_pat_idx == 0)
+ dev->tch_pat_random = get_random_int();
+ rand = dev->tch_pat_random;
+
+ switch (test_pattern) {
+ case SINGLE_TAP:
+ if (test_pat_idx == 2)
+ vivid_tch_buf_set(f, tch_buf, rand % size);
+ break;
+ case DOUBLE_TAP:
+ if (test_pat_idx == 2 || test_pat_idx == 4)
+ vivid_tch_buf_set(f, tch_buf, rand % size);
+ break;
+ case TRIPLE_TAP:
+ if (test_pat_idx == 2 || test_pat_idx == 4 || test_pat_idx == 6)
+ vivid_tch_buf_set(f, tch_buf, rand % size);
+ break;
+ case MOVE_LEFT_TO_RIGHT:
+ vivid_tch_buf_set(f, tch_buf,
+ (rand % f->height) * f->width +
+ test_pat_idx *
+ (f->width / TCH_PATTERN_COUNT));
+ break;
+ case ZOOM_IN:
+ x = f->width / 2;
+ y = f->height / 2;
+ offset_x = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * x) /
+ TCH_PATTERN_COUNT;
+ offset_y = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * y) /
+ TCH_PATTERN_COUNT;
+ vivid_tch_buf_set(f, tch_buf,
+ (x - offset_x) + f->width * (y - offset_y));
+ vivid_tch_buf_set(f, tch_buf,
+ (x + offset_x) + f->width * (y + offset_y));
+ break;
+ case ZOOM_OUT:
+ x = f->width / 2;
+ y = f->height / 2;
+ offset_x = (test_pat_idx * x) / TCH_PATTERN_COUNT;
+ offset_y = (test_pat_idx * y) / TCH_PATTERN_COUNT;
+ vivid_tch_buf_set(f, tch_buf,
+ (x - offset_x) + f->width * (y - offset_y));
+ vivid_tch_buf_set(f, tch_buf,
+ (x + offset_x) + f->width * (y + offset_y));
+ break;
+ case PALM_PRESS:
+ for (x = 0; x < f->width; x++)
+ for (y = f->height / 2; y < f->height; y++)
+ tch_buf[x + f->width * y] = VIVID_MIN_PRESSURE +
+ get_random_pressure();
+ break;
+ case MULTIPLE_PRESS:
+ /* 16 pressure points */
+ for (y = 0; y < 4; y++) {
+ for (x = 0; x < 4; x++) {
+ ystart = (y * f->height) / 4 + f->height / 8;
+ xstart = (x * f->width) / 4 + f->width / 8;
+ vivid_tch_buf_set(f, tch_buf,
+ ystart * f->width + xstart);
+ }
+ }
+ break;
+ }
+#ifdef __BIG_ENDIAN__
+ for (x = 0; x < size; x++)
+ tch_buf[x] = (__force s16)__cpu_to_le16((u16)tch_buf[x]);
+#endif
+}
diff --git a/drivers/media/platform/vivid/vivid-touch-cap.h b/drivers/media/platform/vivid/vivid-touch-cap.h
new file mode 100644
index 000000000000..07e514046ae8
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-touch-cap.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * vivid-touch-cap.h - touch support functions.
+ */
+#ifndef _VIVID_TOUCH_CAP_H_
+#define _VIVID_TOUCH_CAP_H_
+
+#define VIVID_TCH_HEIGHT 12
+#define VIVID_TCH_WIDTH 21
+#define VIVID_MIN_PRESSURE 180
+#define VIVID_PRESSURE_LIMIT 40
+#define TCH_SEQ_COUNT 16
+#define TCH_PATTERN_COUNT 12
+
+enum vivid_tch_test {
+ SINGLE_TAP,
+ DOUBLE_TAP,
+ TRIPLE_TAP,
+ MOVE_LEFT_TO_RIGHT,
+ ZOOM_IN,
+ ZOOM_OUT,
+ PALM_PRESS,
+ MULTIPLE_PRESS,
+ TEST_CASE_MAX
+};
+
+extern const struct vb2_ops vivid_touch_cap_qops;
+
+int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f);
+int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_g_fmt_tch_mplane(struct file *file, void *priv, struct v4l2_format *f);
+int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp);
+int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i);
+int vivid_s_input_tch(struct file *file, void *priv, unsigned int i);
+void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf);
+int vivid_set_touch(struct vivid_dev *dev, unsigned int i);
+int vivid_g_parm_tch(struct file *file, void *priv,
+ struct v4l2_streamparm *parm);
+#endif
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 8cbaa0c998ed..e94beef008c8 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -223,9 +223,6 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
if (vb2_is_streaming(&dev->vb_vid_out_q))
dev->can_loop_video = vivid_vid_can_loop(dev);
- if (dev->kthread_vid_cap)
- return 0;
-
dev->vid_cap_seq_count = 0;
dprintk(dev, 1, "%s\n", __func__);
for (i = 0; i < VIDEO_MAX_FRAME; i++)
@@ -1359,7 +1356,9 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
if (i == dev->input)
return 0;
- if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q))
+ if (vb2_is_busy(&dev->vb_vid_cap_q) ||
+ vb2_is_busy(&dev->vb_vbi_cap_q) ||
+ vb2_is_busy(&dev->vb_meta_cap_q))
return -EBUSY;
dev->input = i;
@@ -1369,6 +1368,7 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
dev->vid_cap_dev.tvnorms = V4L2_STD_ALL;
}
dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms;
+ dev->meta_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms;
vivid_update_format_cap(dev, false);
if (dev->colorspace) {
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index 1f33eb1a76b6..76b0be670ebb 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -262,21 +262,66 @@ struct vivid_fmt vivid_formats[] = {
.can_do_overlay = true,
},
{
- .fourcc = V4L2_PIX_FMT_RGB444, /* xxxxrrrr ggggbbbb */
+ .fourcc = V4L2_PIX_FMT_RGB444, /* ggggbbbb xxxxrrrr */
.vdownsampling = { 1 },
.bit_depth = { 16 },
.planes = 1,
.buffers = 1,
},
{
- .fourcc = V4L2_PIX_FMT_XRGB444, /* xxxxrrrr ggggbbbb */
+ .fourcc = V4L2_PIX_FMT_XRGB444, /* ggggbbbb xxxxrrrr */
.vdownsampling = { 1 },
.bit_depth = { 16 },
.planes = 1,
.buffers = 1,
},
{
- .fourcc = V4L2_PIX_FMT_ARGB444, /* aaaarrrr ggggbbbb */
+ .fourcc = V4L2_PIX_FMT_ARGB444, /* ggggbbbb aaaarrrr */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x00f0,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGBX444, /* bbbbxxxx rrrrgggg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGBA444, /* bbbbaaaa rrrrgggg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x00f0,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XBGR444, /* ggggrrrr xxxxbbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ABGR444, /* ggggrrrr aaaabbbb */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x00f0,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRX444, /* rrrrxxxx bbbbgggg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRA444, /* rrrraaaa bbbbgggg */
.vdownsampling = { 1 },
.bit_depth = { 16 },
.planes = 1,
@@ -309,6 +354,57 @@ struct vivid_fmt vivid_formats[] = {
.alpha_mask = 0x8000,
},
{
+ .fourcc = V4L2_PIX_FMT_RGBX555, /* ggbbbbbx rrrrrggg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .can_do_overlay = true,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGBA555, /* ggbbbbba rrrrrggg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .can_do_overlay = true,
+ .alpha_mask = 0x8000,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XBGR555, /* gggrrrrr xbbbbbgg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .can_do_overlay = true,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_ABGR555, /* gggrrrrr abbbbbgg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .can_do_overlay = true,
+ .alpha_mask = 0x8000,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRX555, /* ggrrrrrx bbbbbggg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .can_do_overlay = true,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRA555, /* ggrrrrra bbbbbggg */
+ .vdownsampling = { 1 },
+ .bit_depth = { 16 },
+ .planes = 1,
+ .buffers = 1,
+ .can_do_overlay = true,
+ .alpha_mask = 0x8000,
+ },
+ {
.fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */
.vdownsampling = { 1 },
.bit_depth = { 16 },
@@ -396,6 +492,36 @@ struct vivid_fmt vivid_formats[] = {
.alpha_mask = 0xff000000,
},
{
+ .fourcc = V4L2_PIX_FMT_RGBX32, /* rgbx */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRX32, /* xbgr */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGBA32, /* rgba */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0x000000ff,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGRA32, /* abgr */
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0xff000000,
+ },
+ {
.fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */
.vdownsampling = { 1 },
.bit_depth = { 8 },
@@ -687,7 +813,7 @@ void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt)
memset(mp->reserved, 0, sizeof(mp->reserved));
mp_fmt->type = is_out ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
- V4L2_CAP_VIDEO_CAPTURE_MPLANE;
+ V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
mp->width = pix->width;
mp->height = pix->height;
mp->pixelformat = pix->pixelformat;
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index 148b663a6075..ee3446e3217c 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -161,9 +161,6 @@ static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count)
if (vb2_is_streaming(&dev->vb_vid_cap_q))
dev->can_loop_video = vivid_vid_can_loop(dev);
- if (dev->kthread_vid_out)
- return 0;
-
dev->vid_out_seq_count = 0;
dprintk(dev, 1, "%s\n", __func__);
if (dev->start_streaming_error) {
@@ -1082,7 +1079,9 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o)
if (o == dev->output)
return 0;
- if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q))
+ if (vb2_is_busy(&dev->vb_vid_out_q) ||
+ vb2_is_busy(&dev->vb_vbi_out_q) ||
+ vb2_is_busy(&dev->vb_meta_out_q))
return -EBUSY;
dev->output = o;
@@ -1093,6 +1092,7 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o)
dev->vid_out_dev.tvnorms = 0;
dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms;
+ dev->meta_out_dev.tvnorms = dev->vid_out_dev.tvnorms;
vivid_update_format_out(dev);
v4l2_ctrl_activate(dev->ctrl_display_present, vivid_is_hdmi_out(dev));
diff --git a/drivers/media/platform/vsp1/vsp1_dl.c b/drivers/media/platform/vsp1/vsp1_dl.c
index 104b6f514536..d7b43037e500 100644
--- a/drivers/media/platform/vsp1/vsp1_dl.c
+++ b/drivers/media/platform/vsp1/vsp1_dl.c
@@ -557,8 +557,10 @@ static struct vsp1_dl_list *vsp1_dl_list_alloc(struct vsp1_dl_manager *dlm)
/* Get a default body for our list. */
dl->body0 = vsp1_dl_body_get(dlm->pool);
- if (!dl->body0)
+ if (!dl->body0) {
+ kfree(dl);
return NULL;
+ }
header_offset = dl->body0->max_entries * sizeof(*dl->body0->entries);
diff --git a/drivers/media/platform/vsp1/vsp1_histo.c b/drivers/media/platform/vsp1/vsp1_histo.c
index 8b01e99acd20..30d751f2cccf 100644
--- a/drivers/media/platform/vsp1/vsp1_histo.c
+++ b/drivers/media/platform/vsp1/vsp1_histo.c
@@ -426,8 +426,6 @@ static int histo_v4l2_querycap(struct file *file, void *fh,
| V4L2_CAP_VIDEO_CAPTURE_MPLANE
| V4L2_CAP_VIDEO_OUTPUT_MPLANE
| V4L2_CAP_META_CAPTURE;
- cap->device_caps = V4L2_CAP_META_CAPTURE
- | V4L2_CAP_STREAMING;
strscpy(cap->driver, "vsp1", sizeof(cap->driver));
strscpy(cap->card, histo->video.name, sizeof(cap->card));
@@ -556,6 +554,7 @@ int vsp1_histogram_init(struct vsp1_device *vsp1, struct vsp1_histogram *histo,
histo->video.vfl_type = VFL_TYPE_GRABBER;
histo->video.release = video_device_release_empty;
histo->video.ioctl_ops = &histo_v4l2_ioctl_ops;
+ histo->video.device_caps = V4L2_CAP_META_CAPTURE | V4L2_CAP_STREAMING;
video_set_drvdata(&histo->video, histo);
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 1bb1d39c60d9..5c67ff92d97a 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -15,8 +15,8 @@
*/
#define VI6_CMD(n) (0x0000 + (n) * 4)
-#define VI6_CMD_UPDHDR (1 << 4)
-#define VI6_CMD_STRCMD (1 << 0)
+#define VI6_CMD_UPDHDR BIT(4)
+#define VI6_CMD_STRCMD BIT(0)
#define VI6_CLK_DCSWT 0x0018
#define VI6_CLK_DCSWT_CSTPW_MASK (0xff << 8)
@@ -25,29 +25,29 @@
#define VI6_CLK_DCSWT_CSTRW_SHIFT 0
#define VI6_SRESET 0x0028
-#define VI6_SRESET_SRTS(n) (1 << (n))
+#define VI6_SRESET_SRTS(n) BIT(n)
#define VI6_STATUS 0x0038
-#define VI6_STATUS_FLD_STD(n) (1 << ((n) + 28))
-#define VI6_STATUS_SYS_ACT(n) (1 << ((n) + 8))
+#define VI6_STATUS_FLD_STD(n) BIT((n) + 28)
+#define VI6_STATUS_SYS_ACT(n) BIT((n) + 8)
#define VI6_WPF_IRQ_ENB(n) (0x0048 + (n) * 12)
-#define VI6_WFP_IRQ_ENB_DFEE (1 << 1)
-#define VI6_WFP_IRQ_ENB_FREE (1 << 0)
+#define VI6_WFP_IRQ_ENB_DFEE BIT(1)
+#define VI6_WFP_IRQ_ENB_FREE BIT(0)
#define VI6_WPF_IRQ_STA(n) (0x004c + (n) * 12)
-#define VI6_WFP_IRQ_STA_DFE (1 << 1)
-#define VI6_WFP_IRQ_STA_FRE (1 << 0)
+#define VI6_WFP_IRQ_STA_DFE BIT(1)
+#define VI6_WFP_IRQ_STA_FRE BIT(0)
#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_ENB_DSTE BIT(8)
+#define VI6_DISP_IRQ_ENB_MAEE BIT(5)
+#define VI6_DISP_IRQ_ENB_LNEE(n) BIT(n)
#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))
+#define VI6_DISP_IRQ_STA_DST BIT(8)
+#define VI6_DISP_IRQ_STA_MAE BIT(5)
+#define VI6_DISP_IRQ_STA_LNE(n) BIT(n)
#define VI6_WPF_LINE_COUNT(n) (0x0084 + (n) * 4)
#define VI6_WPF_LINE_COUNT_MASK (0x1fffff << 0)
@@ -59,32 +59,32 @@
#define VI6_DL_CTRL 0x0100
#define VI6_DL_CTRL_AR_WAIT_MASK (0xffff << 16)
#define VI6_DL_CTRL_AR_WAIT_SHIFT 16
-#define VI6_DL_CTRL_DC2 (1 << 12)
-#define VI6_DL_CTRL_DC1 (1 << 8)
-#define VI6_DL_CTRL_DC0 (1 << 4)
-#define VI6_DL_CTRL_CFM0 (1 << 2)
-#define VI6_DL_CTRL_NH0 (1 << 1)
-#define VI6_DL_CTRL_DLE (1 << 0)
+#define VI6_DL_CTRL_DC2 BIT(12)
+#define VI6_DL_CTRL_DC1 BIT(8)
+#define VI6_DL_CTRL_DC0 BIT(4)
+#define VI6_DL_CTRL_CFM0 BIT(2)
+#define VI6_DL_CTRL_NH0 BIT(1)
+#define VI6_DL_CTRL_DLE BIT(0)
#define VI6_DL_HDR_ADDR(n) (0x0104 + (n) * 4)
#define VI6_DL_SWAP 0x0114
-#define VI6_DL_SWAP_LWS (1 << 2)
-#define VI6_DL_SWAP_WDS (1 << 1)
-#define VI6_DL_SWAP_BTS (1 << 0)
+#define VI6_DL_SWAP_LWS BIT(2)
+#define VI6_DL_SWAP_WDS BIT(1)
+#define VI6_DL_SWAP_BTS BIT(0)
#define VI6_DL_EXT_CTRL(n) (0x011c + (n) * 36)
-#define VI6_DL_EXT_CTRL_NWE (1 << 16)
+#define VI6_DL_EXT_CTRL_NWE BIT(16)
#define VI6_DL_EXT_CTRL_POLINT_MASK (0x3f << 8)
#define VI6_DL_EXT_CTRL_POLINT_SHIFT 8
-#define VI6_DL_EXT_CTRL_DLPRI (1 << 5)
-#define VI6_DL_EXT_CTRL_EXPRI (1 << 4)
-#define VI6_DL_EXT_CTRL_EXT (1 << 0)
+#define VI6_DL_EXT_CTRL_DLPRI BIT(5)
+#define VI6_DL_EXT_CTRL_EXPRI BIT(4)
+#define VI6_DL_EXT_CTRL_EXT BIT(0)
#define VI6_DL_EXT_AUTOFLD_INT BIT(0)
#define VI6_DL_BODY_SIZE 0x0120
-#define VI6_DL_BODY_SIZE_UPD (1 << 24)
+#define VI6_DL_BODY_SIZE_UPD BIT(24)
#define VI6_DL_BODY_SIZE_BS_MASK (0x1ffff << 0)
#define VI6_DL_BODY_SIZE_BS_SHIFT 0
@@ -107,10 +107,10 @@
#define VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT 0
#define VI6_RPF_INFMT 0x0308
-#define VI6_RPF_INFMT_VIR (1 << 28)
-#define VI6_RPF_INFMT_CIPM (1 << 16)
-#define VI6_RPF_INFMT_SPYCS (1 << 15)
-#define VI6_RPF_INFMT_SPUVS (1 << 14)
+#define VI6_RPF_INFMT_VIR BIT(28)
+#define VI6_RPF_INFMT_CIPM BIT(16)
+#define VI6_RPF_INFMT_SPYCS BIT(15)
+#define VI6_RPF_INFMT_SPUVS BIT(14)
#define VI6_RPF_INFMT_CEXT_ZERO (0 << 12)
#define VI6_RPF_INFMT_CEXT_EXT (1 << 12)
#define VI6_RPF_INFMT_CEXT_ONE (2 << 12)
@@ -120,19 +120,19 @@
#define VI6_RPF_INFMT_RDTM_BT709 (2 << 9)
#define VI6_RPF_INFMT_RDTM_BT709_EXT (3 << 9)
#define VI6_RPF_INFMT_RDTM_MASK (7 << 9)
-#define VI6_RPF_INFMT_CSC (1 << 8)
+#define VI6_RPF_INFMT_CSC BIT(8)
#define VI6_RPF_INFMT_RDFMT_MASK (0x7f << 0)
#define VI6_RPF_INFMT_RDFMT_SHIFT 0
#define VI6_RPF_DSWAP 0x030c
-#define VI6_RPF_DSWAP_A_LLS (1 << 11)
-#define VI6_RPF_DSWAP_A_LWS (1 << 10)
-#define VI6_RPF_DSWAP_A_WDS (1 << 9)
-#define VI6_RPF_DSWAP_A_BTS (1 << 8)
-#define VI6_RPF_DSWAP_P_LLS (1 << 3)
-#define VI6_RPF_DSWAP_P_LWS (1 << 2)
-#define VI6_RPF_DSWAP_P_WDS (1 << 1)
-#define VI6_RPF_DSWAP_P_BTS (1 << 0)
+#define VI6_RPF_DSWAP_A_LLS BIT(11)
+#define VI6_RPF_DSWAP_A_LWS BIT(10)
+#define VI6_RPF_DSWAP_A_WDS BIT(9)
+#define VI6_RPF_DSWAP_A_BTS BIT(8)
+#define VI6_RPF_DSWAP_P_LLS BIT(3)
+#define VI6_RPF_DSWAP_P_LWS BIT(2)
+#define VI6_RPF_DSWAP_P_WDS BIT(1)
+#define VI6_RPF_DSWAP_P_BTS BIT(0)
#define VI6_RPF_LOC 0x0310
#define VI6_RPF_LOC_HCOORD_MASK (0x1fff << 16)
@@ -150,7 +150,7 @@
#define VI6_RPF_ALPH_SEL_ASEL_SHIFT 28
#define VI6_RPF_ALPH_SEL_IROP_MASK (0xf << 24)
#define VI6_RPF_ALPH_SEL_IROP_SHIFT 24
-#define VI6_RPF_ALPH_SEL_BSEL (1 << 23)
+#define VI6_RPF_ALPH_SEL_BSEL BIT(23)
#define VI6_RPF_ALPH_SEL_AEXT_ZERO (0 << 18)
#define VI6_RPF_ALPH_SEL_AEXT_EXT (1 << 18)
#define VI6_RPF_ALPH_SEL_AEXT_ONE (2 << 18)
@@ -171,7 +171,7 @@
#define VI6_RPF_VRTCOL_SET_LAYB_SHIFT 0
#define VI6_RPF_MSK_CTRL 0x031c
-#define VI6_RPF_MSK_CTRL_MSK_EN (1 << 24)
+#define VI6_RPF_MSK_CTRL_MSK_EN BIT(24)
#define VI6_RPF_MSK_CTRL_MGR_MASK (0xff << 16)
#define VI6_RPF_MSK_CTRL_MGR_SHIFT 16
#define VI6_RPF_MSK_CTRL_MGG_MASK (0xff << 8)
@@ -191,9 +191,9 @@
#define VI6_RPF_MSK_SET_MSB_SHIFT 0
#define VI6_RPF_CKEY_CTRL 0x0328
-#define VI6_RPF_CKEY_CTRL_CV (1 << 4)
-#define VI6_RPF_CKEY_CTRL_SAPE1 (1 << 1)
-#define VI6_RPF_CKEY_CTRL_SAPE0 (1 << 0)
+#define VI6_RPF_CKEY_CTRL_CV BIT(4)
+#define VI6_RPF_CKEY_CTRL_SAPE1 BIT(1)
+#define VI6_RPF_CKEY_CTRL_SAPE0 BIT(0)
#define VI6_RPF_CKEY_SET0 0x032c
#define VI6_RPF_CKEY_SET1 0x0330
@@ -250,7 +250,7 @@
#define VI6_WPF_HSZCLIP 0x1004
#define VI6_WPF_VSZCLIP 0x1008
-#define VI6_WPF_SZCLIP_EN (1 << 28)
+#define VI6_WPF_SZCLIP_EN BIT(28)
#define VI6_WPF_SZCLIP_OFST_MASK (0xff << 16)
#define VI6_WPF_SZCLIP_OFST_SHIFT 16
#define VI6_WPF_SZCLIP_SIZE_MASK (0xfff << 0)
@@ -259,12 +259,12 @@
#define VI6_WPF_OUTFMT 0x100c
#define VI6_WPF_OUTFMT_PDV_MASK (0xff << 24)
#define VI6_WPF_OUTFMT_PDV_SHIFT 24
-#define VI6_WPF_OUTFMT_PXA (1 << 23)
-#define VI6_WPF_OUTFMT_ROT (1 << 18)
-#define VI6_WPF_OUTFMT_HFLP (1 << 17)
-#define VI6_WPF_OUTFMT_FLP (1 << 16)
-#define VI6_WPF_OUTFMT_SPYCS (1 << 15)
-#define VI6_WPF_OUTFMT_SPUVS (1 << 14)
+#define VI6_WPF_OUTFMT_PXA BIT(23)
+#define VI6_WPF_OUTFMT_ROT BIT(18)
+#define VI6_WPF_OUTFMT_HFLP BIT(17)
+#define VI6_WPF_OUTFMT_FLP BIT(16)
+#define VI6_WPF_OUTFMT_SPYCS BIT(15)
+#define VI6_WPF_OUTFMT_SPUVS BIT(14)
#define VI6_WPF_OUTFMT_DITH_DIS (0 << 12)
#define VI6_WPF_OUTFMT_DITH_EN (3 << 12)
#define VI6_WPF_OUTFMT_DITH_MASK (3 << 12)
@@ -273,18 +273,18 @@
#define VI6_WPF_OUTFMT_WRTM_BT709 (2 << 9)
#define VI6_WPF_OUTFMT_WRTM_BT709_EXT (3 << 9)
#define VI6_WPF_OUTFMT_WRTM_MASK (7 << 9)
-#define VI6_WPF_OUTFMT_CSC (1 << 8)
+#define VI6_WPF_OUTFMT_CSC BIT(8)
#define VI6_WPF_OUTFMT_WRFMT_MASK (0x7f << 0)
#define VI6_WPF_OUTFMT_WRFMT_SHIFT 0
#define VI6_WPF_DSWAP 0x1010
-#define VI6_WPF_DSWAP_P_LLS (1 << 3)
-#define VI6_WPF_DSWAP_P_LWS (1 << 2)
-#define VI6_WPF_DSWAP_P_WDS (1 << 1)
-#define VI6_WPF_DSWAP_P_BTS (1 << 0)
+#define VI6_WPF_DSWAP_P_LLS BIT(3)
+#define VI6_WPF_DSWAP_P_LWS BIT(2)
+#define VI6_WPF_DSWAP_P_WDS BIT(1)
+#define VI6_WPF_DSWAP_P_BTS BIT(0)
#define VI6_WPF_RNDCTRL 0x1014
-#define VI6_WPF_RNDCTRL_CBRM (1 << 28)
+#define VI6_WPF_RNDCTRL_CBRM BIT(28)
#define VI6_WPF_RNDCTRL_ABRM_TRUNC (0 << 24)
#define VI6_WPF_RNDCTRL_ABRM_ROUND (1 << 24)
#define VI6_WPF_RNDCTRL_ABRM_THRESH (2 << 24)
@@ -297,7 +297,7 @@
#define VI6_WPF_RNDCTRL_CLMD_MASK (3 << 12)
#define VI6_WPF_ROT_CTRL 0x1018
-#define VI6_WPF_ROT_CTRL_LN16 (1 << 17)
+#define VI6_WPF_ROT_CTRL_LN16 BIT(17)
#define VI6_WPF_ROT_CTRL_LMEM_WD_MASK (0x1fff << 0)
#define VI6_WPF_ROT_CTRL_LMEM_WD_SHIFT 0
@@ -308,7 +308,7 @@
#define VI6_WPF_DSTM_ADDR_C1 0x102c
#define VI6_WPF_WRBCK_CTRL(n) (0x1034 + (n) * 0x100)
-#define VI6_WPF_WRBCK_CTRL_WBMD (1 << 0)
+#define VI6_WPF_WRBCK_CTRL_WBMD BIT(0)
/* -----------------------------------------------------------------------------
* UIF Control Registers
@@ -317,20 +317,20 @@
#define VI6_UIF_OFFSET 0x100
#define VI6_UIF_DISCOM_DOCMCR 0x1c00
-#define VI6_UIF_DISCOM_DOCMCR_CMPRU (1 << 16)
-#define VI6_UIF_DISCOM_DOCMCR_CMPR (1 << 0)
+#define VI6_UIF_DISCOM_DOCMCR_CMPRU BIT(16)
+#define VI6_UIF_DISCOM_DOCMCR_CMPR BIT(0)
#define VI6_UIF_DISCOM_DOCMSTR 0x1c04
-#define VI6_UIF_DISCOM_DOCMSTR_CMPPRE (1 << 1)
-#define VI6_UIF_DISCOM_DOCMSTR_CMPST (1 << 0)
+#define VI6_UIF_DISCOM_DOCMSTR_CMPPRE BIT(1)
+#define VI6_UIF_DISCOM_DOCMSTR_CMPST BIT(0)
#define VI6_UIF_DISCOM_DOCMCLSTR 0x1c08
-#define VI6_UIF_DISCOM_DOCMCLSTR_CMPCLPRE (1 << 1)
-#define VI6_UIF_DISCOM_DOCMCLSTR_CMPCLST (1 << 0)
+#define VI6_UIF_DISCOM_DOCMCLSTR_CMPCLPRE BIT(1)
+#define VI6_UIF_DISCOM_DOCMCLSTR_CMPCLST BIT(0)
#define VI6_UIF_DISCOM_DOCMIENR 0x1c0c
-#define VI6_UIF_DISCOM_DOCMIENR_CMPPREIEN (1 << 1)
-#define VI6_UIF_DISCOM_DOCMIENR_CMPIEN (1 << 0)
+#define VI6_UIF_DISCOM_DOCMIENR_CMPPREIEN BIT(1)
+#define VI6_UIF_DISCOM_DOCMIENR_CMPIEN BIT(0)
#define VI6_UIF_DISCOM_DOCMMDR 0x1c10
#define VI6_UIF_DISCOM_DOCMMDR_INTHRH(n) ((n) << 16)
@@ -338,7 +338,7 @@
#define VI6_UIF_DISCOM_DOCMPMR 0x1c14
#define VI6_UIF_DISCOM_DOCMPMR_CMPDFF(n) ((n) << 17)
#define VI6_UIF_DISCOM_DOCMPMR_CMPDFA(n) ((n) << 8)
-#define VI6_UIF_DISCOM_DOCMPMR_CMPDAUF (1 << 7)
+#define VI6_UIF_DISCOM_DOCMPMR_CMPDAUF BIT(7)
#define VI6_UIF_DISCOM_DOCMPMR_SEL(n) ((n) << 0)
#define VI6_UIF_DISCOM_DOCMECRCR 0x1c18
@@ -365,7 +365,7 @@
#define VI6_DPR_HSI_ROUTE 0x2048
#define VI6_DPR_BRU_ROUTE 0x204c
#define VI6_DPR_ILV_BRS_ROUTE 0x2050
-#define VI6_DPR_ROUTE_BRSSEL (1 << 28)
+#define VI6_DPR_ROUTE_BRSSEL BIT(28)
#define VI6_DPR_ROUTE_FXA_MASK (0xff << 16)
#define VI6_DPR_ROUTE_FXA_SHIFT 16
#define VI6_DPR_ROUTE_FP_MASK (0x3f << 8)
@@ -407,10 +407,10 @@
#define VI6_SRU_CTRL0_PARAM1_MASK (0x1f << 8)
#define VI6_SRU_CTRL0_PARAM1_SHIFT 8
#define VI6_SRU_CTRL0_MODE_UPSCALE (4 << 4)
-#define VI6_SRU_CTRL0_PARAM2 (1 << 3)
-#define VI6_SRU_CTRL0_PARAM3 (1 << 2)
-#define VI6_SRU_CTRL0_PARAM4 (1 << 1)
-#define VI6_SRU_CTRL0_EN (1 << 0)
+#define VI6_SRU_CTRL0_PARAM2 BIT(3)
+#define VI6_SRU_CTRL0_PARAM3 BIT(2)
+#define VI6_SRU_CTRL0_PARAM4 BIT(1)
+#define VI6_SRU_CTRL0_EN BIT(0)
#define VI6_SRU_CTRL1 0x2204
#define VI6_SRU_CTRL1_PARAM5 0x7ff
@@ -427,18 +427,18 @@
#define VI6_UDS_OFFSET 0x100
#define VI6_UDS_CTRL 0x2300
-#define VI6_UDS_CTRL_AMD (1 << 30)
-#define VI6_UDS_CTRL_FMD (1 << 29)
-#define VI6_UDS_CTRL_BLADV (1 << 28)
-#define VI6_UDS_CTRL_AON (1 << 25)
-#define VI6_UDS_CTRL_ATHON (1 << 24)
-#define VI6_UDS_CTRL_BC (1 << 20)
-#define VI6_UDS_CTRL_NE_A (1 << 19)
-#define VI6_UDS_CTRL_NE_RCR (1 << 18)
-#define VI6_UDS_CTRL_NE_GY (1 << 17)
-#define VI6_UDS_CTRL_NE_BCB (1 << 16)
-#define VI6_UDS_CTRL_AMDSLH (1 << 2)
-#define VI6_UDS_CTRL_TDIPC (1 << 1)
+#define VI6_UDS_CTRL_AMD BIT(30)
+#define VI6_UDS_CTRL_FMD BIT(29)
+#define VI6_UDS_CTRL_BLADV BIT(28)
+#define VI6_UDS_CTRL_AON BIT(25)
+#define VI6_UDS_CTRL_ATHON BIT(24)
+#define VI6_UDS_CTRL_BC BIT(20)
+#define VI6_UDS_CTRL_NE_A BIT(19)
+#define VI6_UDS_CTRL_NE_RCR BIT(18)
+#define VI6_UDS_CTRL_NE_GY BIT(17)
+#define VI6_UDS_CTRL_NE_BCB BIT(16)
+#define VI6_UDS_CTRL_AMDSLH BIT(2)
+#define VI6_UDS_CTRL_TDIPC BIT(1)
#define VI6_UDS_SCALE 0x2304
#define VI6_UDS_SCALE_HMANT_MASK (0xf << 28)
@@ -477,12 +477,12 @@
#define VI6_UDS_HPHASE_HEDP_SHIFT 0
#define VI6_UDS_IPC 0x2318
-#define VI6_UDS_IPC_FIELD (1 << 27)
+#define VI6_UDS_IPC_FIELD BIT(27)
#define VI6_UDS_IPC_VEDP_MASK (0xfff << 0)
#define VI6_UDS_IPC_VEDP_SHIFT 0
#define VI6_UDS_HSZCLIP 0x231c
-#define VI6_UDS_HSZCLIP_HCEN (1 << 28)
+#define VI6_UDS_HSZCLIP_HCEN BIT(28)
#define VI6_UDS_HSZCLIP_HCL_OFST_MASK (0xff << 16)
#define VI6_UDS_HSZCLIP_HCL_OFST_SHIFT 16
#define VI6_UDS_HSZCLIP_HCL_SIZE_MASK (0x1fff << 0)
@@ -507,36 +507,36 @@
*/
#define VI6_LUT_CTRL 0x2800
-#define VI6_LUT_CTRL_EN (1 << 0)
+#define VI6_LUT_CTRL_EN BIT(0)
/* -----------------------------------------------------------------------------
* CLU Control Registers
*/
#define VI6_CLU_CTRL 0x2900
-#define VI6_CLU_CTRL_AAI (1 << 28)
-#define VI6_CLU_CTRL_MVS (1 << 24)
+#define VI6_CLU_CTRL_AAI BIT(28)
+#define VI6_CLU_CTRL_MVS BIT(24)
#define VI6_CLU_CTRL_AX1I_2D (3 << 14)
#define VI6_CLU_CTRL_AX2I_2D (1 << 12)
#define VI6_CLU_CTRL_OS0_2D (3 << 8)
#define VI6_CLU_CTRL_OS1_2D (1 << 6)
#define VI6_CLU_CTRL_OS2_2D (3 << 4)
-#define VI6_CLU_CTRL_M2D (1 << 1)
-#define VI6_CLU_CTRL_EN (1 << 0)
+#define VI6_CLU_CTRL_M2D BIT(1)
+#define VI6_CLU_CTRL_EN BIT(0)
/* -----------------------------------------------------------------------------
* HST Control Registers
*/
#define VI6_HST_CTRL 0x2a00
-#define VI6_HST_CTRL_EN (1 << 0)
+#define VI6_HST_CTRL_EN BIT(0)
/* -----------------------------------------------------------------------------
* HSI Control Registers
*/
#define VI6_HSI_CTRL 0x2b00
-#define VI6_HSI_CTRL_EN (1 << 0)
+#define VI6_HSI_CTRL_EN BIT(0)
/* -----------------------------------------------------------------------------
* BRS and BRU Control Registers
@@ -563,7 +563,7 @@
#define VI6_BRS_BASE 0x3900
#define VI6_BRU_INCTRL 0x0000
-#define VI6_BRU_INCTRL_NRM (1 << 28)
+#define VI6_BRU_INCTRL_NRM BIT(28)
#define VI6_BRU_INCTRL_DnON (1 << (16 + (n)))
#define VI6_BRU_INCTRL_DITHn_OFF (0 << ((n) * 4))
#define VI6_BRU_INCTRL_DITHn_18BPP (1 << ((n) * 4))
@@ -597,7 +597,7 @@
#define VI6_BRU_VIRRPF_COL_BCB_SHIFT 0
#define VI6_BRU_CTRL(n) (0x0010 + (n) * 8 + ((n) <= 3 ? 0 : 4))
-#define VI6_BRU_CTRL_RBC (1 << 31)
+#define VI6_BRU_CTRL_RBC BIT(31)
#define VI6_BRU_CTRL_DSTSEL_BRUIN(n) (((n) <= 3 ? (n) : (n)+1) << 20)
#define VI6_BRU_CTRL_DSTSEL_VRPF (4 << 20)
#define VI6_BRU_CTRL_DSTSEL_MASK (7 << 20)
@@ -610,7 +610,7 @@
#define VI6_BRU_CTRL_AROP_MASK (0xf << 0)
#define VI6_BRU_BLD(n) (0x0014 + (n) * 8 + ((n) <= 3 ? 0 : 4))
-#define VI6_BRU_BLD_CBES (1 << 31)
+#define VI6_BRU_BLD_CBES BIT(31)
#define VI6_BRU_BLD_CCMDX_DST_A (0 << 28)
#define VI6_BRU_BLD_CCMDX_255_DST_A (1 << 28)
#define VI6_BRU_BLD_CCMDX_SRC_A (2 << 28)
@@ -624,7 +624,7 @@
#define VI6_BRU_BLD_CCMDY_COEFY (4 << 24)
#define VI6_BRU_BLD_CCMDY_MASK (7 << 24)
#define VI6_BRU_BLD_CCMDY_SHIFT 24
-#define VI6_BRU_BLD_ABES (1 << 23)
+#define VI6_BRU_BLD_ABES BIT(23)
#define VI6_BRU_BLD_ACMDX_DST_A (0 << 20)
#define VI6_BRU_BLD_ACMDX_255_DST_A (1 << 20)
#define VI6_BRU_BLD_ACMDX_SRC_A (2 << 20)
@@ -662,11 +662,11 @@
#define VI6_HGO_SIZE_HSIZE_SHIFT 16
#define VI6_HGO_SIZE_VSIZE_SHIFT 0
#define VI6_HGO_MODE 0x3008
-#define VI6_HGO_MODE_STEP (1 << 10)
-#define VI6_HGO_MODE_MAXRGB (1 << 7)
-#define VI6_HGO_MODE_OFSB_R (1 << 6)
-#define VI6_HGO_MODE_OFSB_G (1 << 5)
-#define VI6_HGO_MODE_OFSB_B (1 << 4)
+#define VI6_HGO_MODE_STEP BIT(10)
+#define VI6_HGO_MODE_MAXRGB BIT(7)
+#define VI6_HGO_MODE_OFSB_R BIT(6)
+#define VI6_HGO_MODE_OFSB_G BIT(5)
+#define VI6_HGO_MODE_OFSB_B BIT(4)
#define VI6_HGO_MODE_HRATIO_SHIFT 2
#define VI6_HGO_MODE_VRATIO_SHIFT 0
#define VI6_HGO_LB_TH 0x300c
@@ -687,7 +687,7 @@
#define VI6_HGO_EXT_HIST_ADDR 0x335c
#define VI6_HGO_EXT_HIST_DATA 0x3360
#define VI6_HGO_REGRST 0x33fc
-#define VI6_HGO_REGRST_RCLEA (1 << 0)
+#define VI6_HGO_REGRST_RCLEA BIT(0)
/* -----------------------------------------------------------------------------
* HGT Control Registers
@@ -713,7 +713,7 @@
#define VI6_HGT_SUM 0x3754
#define VI6_HGT_LB_DET 0x3758
#define VI6_HGT_REGRST 0x37fc
-#define VI6_HGT_REGRST_RCLEA (1 << 0)
+#define VI6_HGT_REGRST_RCLEA BIT(0)
/* -----------------------------------------------------------------------------
* LIF Control Registers
@@ -724,9 +724,9 @@
#define VI6_LIF_CTRL 0x3b00
#define VI6_LIF_CTRL_OBTH_MASK (0x7ff << 16)
#define VI6_LIF_CTRL_OBTH_SHIFT 16
-#define VI6_LIF_CTRL_CFMT (1 << 4)
-#define VI6_LIF_CTRL_REQSEL (1 << 1)
-#define VI6_LIF_CTRL_LIF_EN (1 << 0)
+#define VI6_LIF_CTRL_CFMT BIT(4)
+#define VI6_LIF_CTRL_REQSEL BIT(1)
+#define VI6_LIF_CTRL_LIF_EN BIT(0)
#define VI6_LIF_CSBTH 0x3b04
#define VI6_LIF_CSBTH_HBTH_MASK (0x7ff << 16)
@@ -735,7 +735,7 @@
#define VI6_LIF_CSBTH_LBTH_SHIFT 0
#define VI6_LIF_LBA 0x3b0c
-#define VI6_LIF_LBA_LBA0 (1 << 31)
+#define VI6_LIF_LBA_LBA0 BIT(31)
#define VI6_LIF_LBA_LBA1_MASK (0xfff << 16)
#define VI6_LIF_LBA_LBA1_SHIFT 16
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index fd98e483b2f4..5e59ed2c3614 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -956,12 +956,6 @@ vsp1_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
| V4L2_CAP_VIDEO_CAPTURE_MPLANE
| V4L2_CAP_VIDEO_OUTPUT_MPLANE;
- if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE
- | V4L2_CAP_STREAMING;
- else
- cap->device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE
- | V4L2_CAP_STREAMING;
strscpy(cap->driver, "vsp1", sizeof(cap->driver));
strscpy(cap->card, video->video.name, sizeof(cap->card));
@@ -1268,11 +1262,15 @@ struct vsp1_video *vsp1_video_create(struct vsp1_device *vsp1,
video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
video->pad.flags = MEDIA_PAD_FL_SOURCE;
video->video.vfl_dir = VFL_DIR_TX;
+ video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING;
} else {
direction = "output";
video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
video->pad.flags = MEDIA_PAD_FL_SINK;
video->video.vfl_dir = VFL_DIR_RX;
+ video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_STREAMING;
}
mutex_init(&video->lock);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index c9d5fdb2d407..b211380a11f2 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -491,15 +491,8 @@ xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
struct v4l2_fh *vfh = file->private_data;
struct xvip_dma *dma = to_xvip_dma(vfh->vdev);
- cap->device_caps = V4L2_CAP_STREAMING;
-
- if (dma->queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
- else
- cap->device_caps |= V4L2_CAP_VIDEO_OUTPUT;
-
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS
- | dma->xdev->v4l2_caps;
+ cap->capabilities = dma->xdev->v4l2_caps | V4L2_CAP_STREAMING |
+ V4L2_CAP_DEVICE_CAPS;
strscpy(cap->driver, "xilinx-vipp", sizeof(cap->driver));
strscpy(cap->card, dma->video.name, sizeof(cap->card));
@@ -524,8 +517,6 @@ xvip_dma_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
return -EINVAL;
f->pixelformat = dma->format.pixelformat;
- strscpy(f->description, dma->fmtinfo->description,
- sizeof(f->description));
return 0;
}
@@ -700,6 +691,11 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma,
dma->video.release = video_device_release_empty;
dma->video.ioctl_ops = &xvip_dma_ioctl_ops;
dma->video.lock = &dma->lock;
+ dma->video.device_caps = V4L2_CAP_STREAMING;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ dma->video.device_caps |= V4L2_CAP_VIDEO_CAPTURE;
+ else
+ dma->video.device_caps |= V4L2_CAP_VIDEO_OUTPUT;
video_set_drvdata(&dma->video, dma);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
index 5aec4d17eb21..2378bdae57ae 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.h
+++ b/drivers/media/platform/xilinx/xilinx-dma.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Xilinx Video DMA
*
diff --git a/drivers/media/platform/xilinx/xilinx-vip.c b/drivers/media/platform/xilinx/xilinx-vip.c
index 08a825c3a3f6..6ad61b08a31a 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.c
+++ b/drivers/media/platform/xilinx/xilinx-vip.c
@@ -25,21 +25,21 @@
static const struct xvip_video_format xvip_video_formats[] = {
{ XVIP_VF_YUV_422, 8, NULL, MEDIA_BUS_FMT_UYVY8_1X16,
- 2, V4L2_PIX_FMT_YUYV, "4:2:2, packed, YUYV" },
+ 2, V4L2_PIX_FMT_YUYV },
{ XVIP_VF_YUV_444, 8, NULL, MEDIA_BUS_FMT_VUY8_1X24,
- 3, V4L2_PIX_FMT_YUV444, "4:4:4, packed, YUYV" },
+ 3, V4L2_PIX_FMT_YUV444 },
{ XVIP_VF_RBG, 8, NULL, MEDIA_BUS_FMT_RBG888_1X24,
- 3, 0, NULL },
+ 3, 0 },
{ XVIP_VF_MONO_SENSOR, 8, "mono", MEDIA_BUS_FMT_Y8_1X8,
- 1, V4L2_PIX_FMT_GREY, "Greyscale 8-bit" },
+ 1, V4L2_PIX_FMT_GREY },
{ XVIP_VF_MONO_SENSOR, 8, "rggb", MEDIA_BUS_FMT_SRGGB8_1X8,
- 1, V4L2_PIX_FMT_SRGGB8, "Bayer 8-bit RGGB" },
+ 1, V4L2_PIX_FMT_SRGGB8 },
{ XVIP_VF_MONO_SENSOR, 8, "grbg", MEDIA_BUS_FMT_SGRBG8_1X8,
- 1, V4L2_PIX_FMT_SGRBG8, "Bayer 8-bit GRBG" },
+ 1, V4L2_PIX_FMT_SGRBG8 },
{ XVIP_VF_MONO_SENSOR, 8, "gbrg", MEDIA_BUS_FMT_SGBRG8_1X8,
- 1, V4L2_PIX_FMT_SGBRG8, "Bayer 8-bit GBRG" },
+ 1, V4L2_PIX_FMT_SGBRG8 },
{ XVIP_VF_MONO_SENSOR, 8, "bggr", MEDIA_BUS_FMT_SBGGR8_1X8,
- 1, V4L2_PIX_FMT_SBGGR8, "Bayer 8-bit BGGR" },
+ 1, V4L2_PIX_FMT_SBGGR8 },
};
/**
diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h
index ba939dd52818..a528a32ea1dc 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.h
+++ b/drivers/media/platform/xilinx/xilinx-vip.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Xilinx Video IP Core
*
@@ -12,6 +12,7 @@
#ifndef __XILINX_VIP_H__
#define __XILINX_VIP_H__
+#include <linux/bitops.h>
#include <linux/io.h>
#include <media/v4l2-subdev.h>
@@ -35,23 +36,23 @@ struct clk;
/* Xilinx Video IP Control Registers */
#define XVIP_CTRL_CONTROL 0x0000
-#define XVIP_CTRL_CONTROL_SW_ENABLE (1 << 0)
-#define XVIP_CTRL_CONTROL_REG_UPDATE (1 << 1)
-#define XVIP_CTRL_CONTROL_BYPASS (1 << 4)
-#define XVIP_CTRL_CONTROL_TEST_PATTERN (1 << 5)
-#define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET (1 << 30)
-#define XVIP_CTRL_CONTROL_SW_RESET (1 << 31)
+#define XVIP_CTRL_CONTROL_SW_ENABLE BIT(0)
+#define XVIP_CTRL_CONTROL_REG_UPDATE BIT(1)
+#define XVIP_CTRL_CONTROL_BYPASS BIT(4)
+#define XVIP_CTRL_CONTROL_TEST_PATTERN BIT(5)
+#define XVIP_CTRL_CONTROL_FRAME_SYNC_RESET BIT(30)
+#define XVIP_CTRL_CONTROL_SW_RESET BIT(31)
#define XVIP_CTRL_STATUS 0x0004
-#define XVIP_CTRL_STATUS_PROC_STARTED (1 << 0)
-#define XVIP_CTRL_STATUS_EOF (1 << 1)
+#define XVIP_CTRL_STATUS_PROC_STARTED BIT(0)
+#define XVIP_CTRL_STATUS_EOF BIT(1)
#define XVIP_CTRL_ERROR 0x0008
-#define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY (1 << 0)
-#define XVIP_CTRL_ERROR_SLAVE_EOL_LATE (1 << 1)
-#define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY (1 << 2)
-#define XVIP_CTRL_ERROR_SLAVE_SOF_LATE (1 << 3)
+#define XVIP_CTRL_ERROR_SLAVE_EOL_EARLY BIT(0)
+#define XVIP_CTRL_ERROR_SLAVE_EOL_LATE BIT(1)
+#define XVIP_CTRL_ERROR_SLAVE_SOF_EARLY BIT(2)
+#define XVIP_CTRL_ERROR_SLAVE_SOF_LATE BIT(3)
#define XVIP_CTRL_IRQ_ENABLE 0x000c
-#define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED (1 << 0)
-#define XVIP_CTRL_IRQ_EOF (1 << 1)
+#define XVIP_CTRL_IRQ_ENABLE_PROC_STARTED BIT(0)
+#define XVIP_CTRL_IRQ_EOF BIT(1)
#define XVIP_CTRL_VERSION 0x0010
#define XVIP_CTRL_VERSION_MAJOR_MASK (0xff << 24)
#define XVIP_CTRL_VERSION_MAJOR_SHIFT 24
@@ -108,7 +109,6 @@ struct xvip_device {
* @code: media bus format code
* @bpp: bytes per pixel (when stored in memory)
* @fourcc: V4L2 pixel format FCC identifier
- * @description: format description, suitable for userspace
*/
struct xvip_video_format {
unsigned int vf_code;
@@ -117,7 +117,6 @@ struct xvip_video_format {
unsigned int code;
unsigned int bpp;
u32 fourcc;
- const char *description;
};
const struct xvip_video_format *xvip_get_format_by_code(unsigned int code);
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index edce0402155d..cc2856efea59 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -385,9 +385,9 @@ static int xvip_graph_parse_one(struct xvip_composite_device *xdev,
asd = v4l2_async_notifier_add_fwnode_subdev(
&xdev->notifier, remote,
sizeof(struct xvip_graph_entity));
+ fwnode_handle_put(remote);
if (IS_ERR(asd)) {
ret = PTR_ERR(asd);
- fwnode_handle_put(remote);
goto err_notifier_cleanup;
}
}
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.h b/drivers/media/platform/xilinx/xilinx-vipp.h
index e65fce9538f9..cc52c1854dbd 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.h
+++ b/drivers/media/platform/xilinx/xilinx-vipp.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Xilinx Video IP Composite Device
*
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.h b/drivers/media/platform/xilinx/xilinx-vtc.h
index 90cf44245283..855845911ffc 100644
--- a/drivers/media/platform/xilinx/xilinx-vtc.h
+++ b/drivers/media/platform/xilinx/xilinx-vtc.h
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
/*
* Xilinx Video Timing Controller
*
OpenPOWER on IntegriCloud