summaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/cec/core/cec-adap.c5
-rw-r--r--drivers/media/cec/platform/cros-ec/cros-ec-cec.c4
-rw-r--r--drivers/media/common/v4l2-tpg/v4l2-tpg-core.c44
-rw-r--r--drivers/media/common/videobuf2/videobuf2-v4l2.c12
-rw-r--r--drivers/media/i2c/Kconfig18
-rw-r--r--drivers/media/i2c/Makefile1
-rw-r--r--drivers/media/i2c/adv7180.c5
-rw-r--r--drivers/media/i2c/adv7343_regs.h10
-rw-r--r--drivers/media/i2c/adv7393_regs.h10
-rw-r--r--drivers/media/i2c/adv748x/adv748x.h2
-rw-r--r--drivers/media/i2c/adv7604.c5
-rw-r--r--drivers/media/i2c/ar0521.c1061
-rw-r--r--drivers/media/i2c/mt9p031.c93
-rw-r--r--drivers/media/i2c/ov5640.c1650
-rw-r--r--drivers/media/i2c/ov5693.c57
-rw-r--r--drivers/media/i2c/ov7251.c7
-rw-r--r--drivers/media/i2c/st-mipid02.c30
-rw-r--r--drivers/media/i2c/tda1997x.c1
-rw-r--r--drivers/media/i2c/tvp5150.c2
-rw-r--r--drivers/media/mc/mc-entity.c96
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c2
-rw-r--r--drivers/media/pci/cx88/cx88-core.c22
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-ci.c9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-ci.h9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-hw.c9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-hw.h11
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-i2c.c9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-i2c.h9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-io.h9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-main.c9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-max.c9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-max.h11
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-mci.c9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-mci.h9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-regs.h9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-sx8.c9
-rw-r--r--drivers/media/pci/ddbridge/ddbridge.h11
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2-main.c2
-rw-r--r--drivers/media/pci/saa7164/saa7164-api.c2
-rw-r--r--drivers/media/pci/sta2x11/Kconfig2
-rw-r--r--drivers/media/pci/tw5864/tw5864-core.c30
-rw-r--r--drivers/media/pci/tw686x/tw686x-core.c21
-rw-r--r--drivers/media/pci/tw686x/tw686x-video.c4
-rw-r--r--drivers/media/platform/amphion/vdec.c50
-rw-r--r--drivers/media/platform/amphion/venc.c3
-rw-r--r--drivers/media/platform/amphion/vpu.h1
-rw-r--r--drivers/media/platform/amphion/vpu_cmds.c3
-rw-r--r--drivers/media/platform/amphion/vpu_core.c18
-rw-r--r--drivers/media/platform/amphion/vpu_dbg.c2
-rw-r--r--drivers/media/platform/amphion/vpu_malone.c20
-rw-r--r--drivers/media/platform/amphion/vpu_malone.h1
-rw-r--r--drivers/media/platform/amphion/vpu_msgs.c7
-rw-r--r--drivers/media/platform/amphion/vpu_rpc.c2
-rw-r--r--drivers/media/platform/amphion/vpu_rpc.h7
-rw-r--r--drivers/media/platform/amphion/vpu_v4l2.c6
-rw-r--r--drivers/media/platform/atmel/Kconfig4
-rw-r--r--drivers/media/platform/atmel/atmel-isc-base.c20
-rw-r--r--drivers/media/platform/atmel/atmel-sama7g5-isc.c2
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c3
-rw-r--r--drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h2
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c133
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c13
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c12
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h2
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c50
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c29
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c30
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h36
-rw-r--r--drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c37
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c7
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c25
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c7
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c210
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec_drv_if.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c5
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/h264.c9
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c16
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h10
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c328
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h4
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c41
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.c8
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.c2
-rw-r--r--drivers/media/platform/qcom/camss/camss-ispif.c43
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.c36
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.h3
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.c6
-rw-r--r--drivers/media/platform/qcom/camss/camss.c73
-rw-r--r--drivers/media/platform/qcom/camss/camss.h7
-rw-r--r--drivers/media/platform/qcom/venus/core.c20
-rw-r--r--drivers/media/platform/qcom/venus/core.h2
-rw-r--r--drivers/media/platform/qcom/venus/dbgfs.c9
-rw-r--r--drivers/media/platform/qcom/venus/dbgfs.h13
-rw-r--r--drivers/media/platform/qcom/venus/helpers.c6
-rw-r--r--drivers/media/platform/qcom/venus/hfi_cmds.c9
-rw-r--r--drivers/media/platform/qcom/venus/hfi_cmds.h1
-rw-r--r--drivers/media/platform/qcom/venus/hfi_helper.h20
-rw-r--r--drivers/media/platform/qcom/venus/hfi_parser.c6
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform.c22
-rw-r--r--drivers/media/platform/qcom/venus/hfi_platform.h2
-rw-r--r--drivers/media/platform/qcom/venus/hfi_venus.c26
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-core.c4
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-csi2.c2
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-dma.c2
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c2
-rw-r--r--drivers/media/platform/renesas/rcar_drif.c7
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_entity.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_video.c2
-rw-r--r--drivers/media/platform/rockchip/rkisp1/Kconfig2
-rw-r--r--drivers/media/platform/rockchip/rkisp1/Makefile18
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c181
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-common.c143
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-common.h157
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c536
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h28
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c243
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c504
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c691
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-params.c713
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h190
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c218
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c17
-rw-r--r--drivers/media/platform/samsung/exynos-gsc/gsc-core.c3
-rw-r--r--drivers/media/platform/samsung/exynos-gsc/gsc-core.h2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/common.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-capture.c6
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-lite.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/media-dev.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/mipi-csis.c2
-rw-r--r--drivers/media/platform/samsung/s3c-camif/camif-capture.c2
-rw-r--r--drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c2
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c3
-rw-r--r--drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c33
-rw-r--r--drivers/media/platform/st/sti/delta/delta-v4l2.c24
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmi.c91
-rw-r--r--drivers/media/platform/sunxi/Kconfig2
-rw-r--r--drivers/media/platform/sunxi/Makefile2
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c4
-rw-r--r--drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig15
-rw-r--r--drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile4
-rw-r--r--drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c750
-rw-r--r--drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h52
-rw-r--r--drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h76
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig13
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile4
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c72
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h39
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c816
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h55
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h151
-rw-r--r--drivers/media/platform/ti/cal/cal-camerarx.c4
-rw-r--r--drivers/media/platform/ti/cal/cal-video.c2
-rw-r--r--drivers/media/platform/ti/davinci/vpif.c1
-rw-r--r--drivers/media/platform/ti/davinci/vpif.h11
-rw-r--r--drivers/media/platform/ti/davinci/vpif_display.h10
-rw-r--r--drivers/media/platform/ti/omap/omap_voutlib.c4
-rw-r--r--drivers/media/platform/ti/omap3isp/isp.c6
-rw-r--r--drivers/media/platform/ti/omap3isp/ispccdc.c2
-rw-r--r--drivers/media/platform/ti/omap3isp/ispccp2.c2
-rw-r--r--drivers/media/platform/ti/omap3isp/ispcsi2.c2
-rw-r--r--drivers/media/platform/ti/omap3isp/ispvideo.c4
-rw-r--r--drivers/media/platform/video-mux.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-csi2rxss.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c4
-rw-r--r--drivers/media/platform/xilinx/xilinx-vip.h4
-rw-r--r--drivers/media/rc/ati_remote.c11
-rw-r--r--drivers/media/rc/igorplugusb.c23
-rw-r--r--drivers/media/rc/iguanair.c5
-rw-r--r--drivers/media/rc/imon_raw.c16
-rw-r--r--drivers/media/rc/lirc_dev.c6
-rw-r--r--drivers/media/rc/rc-main.c9
-rw-r--r--drivers/media/rc/redrat3.c4
-rw-r--r--drivers/media/rc/streamzap.c2
-rw-r--r--drivers/media/rc/ttusbir.c4
-rw-r--r--drivers/media/rc/xbox_remote.c10
-rw-r--r--drivers/media/test-drivers/vicodec/vicodec-core.c8
-rw-r--r--drivers/media/test-drivers/vimc/Makefile2
-rw-r--r--drivers/media/test-drivers/vimc/vimc-capture.c270
-rw-r--r--drivers/media/test-drivers/vimc/vimc-common.h9
-rw-r--r--drivers/media/test-drivers/vimc/vimc-core.c142
-rw-r--r--drivers/media/test-drivers/vimc/vimc-debayer.c393
-rw-r--r--drivers/media/test-drivers/vimc/vimc-lens.c102
-rw-r--r--drivers/media/test-drivers/vimc/vimc-scaler.c216
-rw-r--r--drivers/media/test-drivers/vimc/vimc-sensor.c307
-rw-r--r--drivers/media/test-drivers/vimc/vimc-streamer.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-ctrls.c29
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-common.c15
-rw-r--r--drivers/media/usb/Kconfig1
-rw-r--r--drivers/media/usb/Makefile1
-rw-r--r--drivers/media/usb/airspy/airspy.c17
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx-v4l.h9
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx.h10
-rw-r--r--drivers/media/usb/gspca/spca501.c2
-rw-r--r--drivers/media/usb/gspca/xirlink_cit.c2
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c3
-rw-r--r--drivers/media/usb/stkwebcam/Kconfig14
-rw-r--r--drivers/media/usb/stkwebcam/Makefile5
-rw-r--r--drivers/media/usb/stkwebcam/stk-sensor.c587
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c1434
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.h123
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c5
-rw-r--r--drivers/media/usb/usbtv/usbtv.h3
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c120
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c143
-rw-r--r--drivers/media/usb/uvc/uvc_isight.c13
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c6
-rw-r--r--drivers/media/usb/uvc/uvc_status.c6
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c18
-rw-r--r--drivers/media/usb/uvc/uvc_video.c96
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h16
-rw-r--r--drivers/media/v4l2-core/Kconfig6
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c45
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-api.c103
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-core.c212
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-defs.c38
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-priv.h3
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-request.c13
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c71
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c2
233 files changed, 9612 insertions, 5964 deletions
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c
index 8bf91b5a7d0e..41a79293ee02 100644
--- a/drivers/media/cec/core/cec-adap.c
+++ b/drivers/media/cec/core/cec-adap.c
@@ -1309,8 +1309,11 @@ static int cec_config_log_addr(struct cec_adapter *adap,
* we assume that something is really weird and that it is not a
* good idea to try and claim this logical address.
*/
- if (i == max_retries)
+ if (i == max_retries) {
+ dprintk(0, "polling for LA %u failed with tx_status=0x%04x\n",
+ log_addr, msg.tx_status);
return 0;
+ }
/*
* Message not acknowledged, so this logical
diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
index 8c8d8fc5e63e..3b583ed4da9d 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -217,6 +217,10 @@ static const struct cec_dmi_match cec_dmi_match_table[] = {
{ "Google", "Fizz", "0000:00:02.0", "Port B" },
/* Google Brask */
{ "Google", "Brask", "0000:00:02.0", "Port B" },
+ /* Google Moli */
+ { "Google", "Moli", "0000:00:02.0", "Port B" },
+ /* Google Kinox */
+ { "Google", "Kinox", "0000:00:02.0", "Port B" },
};
static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev,
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
index 7607b516a7c4..9b7bcdce6e44 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
@@ -266,6 +266,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_XYUV32:
case V4L2_PIX_FMT_VUYA32:
case V4L2_PIX_FMT_VUYX32:
+ case V4L2_PIX_FMT_YUVA32:
+ case V4L2_PIX_FMT_YUVX32:
tpg->color_enc = TGP_COLOR_ENC_YCBCR;
break;
case V4L2_PIX_FMT_YUV420M:
@@ -412,6 +414,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
case V4L2_PIX_FMT_XYUV32:
case V4L2_PIX_FMT_VUYA32:
case V4L2_PIX_FMT_VUYX32:
+ case V4L2_PIX_FMT_YUVA32:
+ case V4L2_PIX_FMT_YUVX32:
case V4L2_PIX_FMT_HSV32:
tpg->twopixelsize[0] = 2 * 4;
break;
@@ -1376,9 +1380,11 @@ static void gen_twopix(struct tpg_data *tpg,
buf[0][offset + 3] = b_v;
break;
case V4L2_PIX_FMT_RGBX32:
+ case V4L2_PIX_FMT_YUVX32:
alpha = 0;
fallthrough;
case V4L2_PIX_FMT_RGBA32:
+ case V4L2_PIX_FMT_YUVA32:
buf[0][offset] = r_y_h;
buf[0][offset + 1] = g_u_s;
buf[0][offset + 2] = b_v;
@@ -2402,6 +2408,44 @@ static void tpg_fill_plane_extras(const struct tpg_data *tpg,
((params->sav_eav_f ^ vact) << 1) |
(hact ^ vact ^ params->sav_eav_f);
}
+ if (tpg->insert_hdmi_video_guard_band) {
+ unsigned int i;
+
+ switch (tpg->fourcc) {
+ case V4L2_PIX_FMT_BGR24:
+ case V4L2_PIX_FMT_RGB24:
+ for (i = 0; i < 3 * 4; i += 3) {
+ vbuf[i] = 0xab;
+ vbuf[i + 1] = 0x55;
+ vbuf[i + 2] = 0xab;
+ }
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ case V4L2_PIX_FMT_ARGB32:
+ case V4L2_PIX_FMT_XRGB32:
+ case V4L2_PIX_FMT_BGRX32:
+ case V4L2_PIX_FMT_BGRA32:
+ for (i = 0; i < 4 * 4; i += 4) {
+ vbuf[i] = 0x00;
+ vbuf[i + 1] = 0xab;
+ vbuf[i + 2] = 0x55;
+ vbuf[i + 3] = 0xab;
+ }
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ case V4L2_PIX_FMT_XBGR32:
+ case V4L2_PIX_FMT_ABGR32:
+ case V4L2_PIX_FMT_RGBX32:
+ case V4L2_PIX_FMT_RGBA32:
+ for (i = 0; i < 4 * 4; i += 4) {
+ vbuf[i] = 0xab;
+ vbuf[i + 1] = 0x55;
+ vbuf[i + 2] = 0xab;
+ vbuf[i + 3] = 0x00;
+ }
+ break;
+ }
+ }
}
static void tpg_fill_plane_pattern(const struct tpg_data *tpg,
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index 075d24ebf44c..f26cb8586bd4 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -638,6 +638,18 @@ int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp,
}
EXPORT_SYMBOL_GPL(vb2_find_timestamp);
+struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp)
+{
+ unsigned int i;
+
+ for (i = 0; i < q->num_buffers; i++)
+ if (q->bufs[i]->copied_timestamp &&
+ q->bufs[i]->timestamp == timestamp)
+ return vb2_get_buffer(q, i);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(vb2_find_buffer);
+
/*
* vb2_querybuf() - query video buffer information
* @q: videobuf queue
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 2b20aa6c37b1..7806d4b81716 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -34,6 +34,19 @@ config VIDEO_APTINA_PLL
config VIDEO_CCS_PLL
tristate
+config VIDEO_AR0521
+ tristate "ON Semiconductor AR0521 sensor support"
+ depends on I2C && VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ help
+ This is a Video4Linux2 sensor driver for the ON Semiconductor
+ AR0521 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ar0521.
+
config VIDEO_HI556
tristate "Hynix Hi-556 sensor support"
depends on I2C && VIDEO_DEV
@@ -75,8 +88,10 @@ config VIDEO_HI847
config VIDEO_IMX208
tristate "Sony IMX208 sensor support"
- depends on I2C && VIDEO_DEV && VIDEO_V4L2_SUBDEV_API
+ depends on I2C && VIDEO_DEV
depends on MEDIA_CAMERA_SUPPORT
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
help
This is a Video4Linux2 sensor driver for the Sony
IMX208 camera.
@@ -1178,6 +1193,7 @@ config VIDEO_ISL7998X
depends on OF_GPIO
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
help
Support for Intersil ISL7998x analog to MIPI-CSI2 or
BT.656 decoder.
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 3e1696963e7f..0a2933103dd9 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o
obj-$(CONFIG_VIDEO_AK7375) += ak7375.o
obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o
+obj-$(CONFIG_VIDEO_AR0521) += ar0521.o
obj-$(CONFIG_VIDEO_BT819) += bt819.o
obj-$(CONFIG_VIDEO_BT856) += bt856.o
obj-$(CONFIG_VIDEO_BT866) += bt866.o
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index e3a57c178c6b..5fde5243722d 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -43,6 +43,7 @@
#define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f
#define ADV7182_REG_INPUT_VIDSEL 0x0002
+#define ADV7182_REG_INPUT_RESERVED BIT(2)
#define ADV7180_REG_OUTPUT_CONTROL 0x0003
#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004
@@ -1060,7 +1061,9 @@ static int adv7182_init(struct adv7180_state *state)
static int adv7182_set_std(struct adv7180_state *state, unsigned int std)
{
- return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4);
+ /* Failing to set the reserved bit can result in increased video noise */
+ return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL,
+ (std << 4) | ADV7182_REG_INPUT_RESERVED);
}
enum adv7182_input_type {
diff --git a/drivers/media/i2c/adv7343_regs.h b/drivers/media/i2c/adv7343_regs.h
index 2f04ce4b9118..e0357e6272e3 100644
--- a/drivers/media/i2c/adv7343_regs.h
+++ b/drivers/media/i2c/adv7343_regs.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ADV7343 encoder related structure and register definitions
*
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * 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 ADV7343_REGS_H
diff --git a/drivers/media/i2c/adv7393_regs.h b/drivers/media/i2c/adv7393_regs.h
index 78968330f0be..6eb8732b5324 100644
--- a/drivers/media/i2c/adv7393_regs.h
+++ b/drivers/media/i2c/adv7393_regs.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ADV7393 encoder related structure and register definitions
*
@@ -7,15 +8,6 @@
* Based on ADV7343 driver,
*
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * 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 ADV7393_REGS_H
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index 31bac06d46b5..d75eb3d8be5a 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -417,7 +417,7 @@ int adv748x_write_block(struct adv748x_state *state, int client_page,
static inline struct v4l2_subdev *adv748x_get_remote_sd(struct media_pad *pad)
{
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad)
return NULL;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index bb0c8fc6d383..497419a5cfdd 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -2505,9 +2505,8 @@ static void adv76xx_log_infoframes(struct v4l2_subdev *sd)
union hdmi_infoframe frame;
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (adv76xx_read_infoframe(sd, i, &frame))
- return;
- hdmi_infoframe_log(KERN_INFO, &client->dev, &frame);
+ if (!adv76xx_read_infoframe(sd, i, &frame))
+ hdmi_infoframe_log(KERN_INFO, &client->dev, &frame);
}
}
diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c
new file mode 100644
index 000000000000..c7bdfc69b9be
--- /dev/null
+++ b/drivers/media/i2c/ar0521.c
@@ -0,0 +1,1061 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Sieć Badawcza Łukasiewicz
+ * - Przemysłowy Instytut Automatyki i Pomiarów PIAP
+ * Written by Krzysztof Hałasa
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+/* External clock (extclk) frequencies */
+#define AR0521_EXTCLK_MIN (10 * 1000 * 1000)
+#define AR0521_EXTCLK_MAX (48 * 1000 * 1000)
+
+/* PLL and PLL2 */
+#define AR0521_PLL_MIN (320 * 1000 * 1000)
+#define AR0521_PLL_MAX (1280 * 1000 * 1000)
+
+/* Effective pixel clocks, the registers may be DDR */
+#define AR0521_PIXEL_CLOCK_RATE (184 * 1000 * 1000)
+#define AR0521_PIXEL_CLOCK_MIN (168 * 1000 * 1000)
+#define AR0521_PIXEL_CLOCK_MAX (414 * 1000 * 1000)
+
+#define AR0521_WIDTH_MIN 8u
+#define AR0521_WIDTH_MAX 2608u
+#define AR0521_HEIGHT_MIN 8u
+#define AR0521_HEIGHT_MAX 1958u
+
+#define AR0521_WIDTH_BLANKING_MIN 572u
+#define AR0521_HEIGHT_BLANKING_MIN 38u /* must be even */
+#define AR0521_TOTAL_WIDTH_MIN 2968u
+
+/* AR0521 registers */
+#define AR0521_REG_VT_PIX_CLK_DIV 0x0300
+#define AR0521_REG_FRAME_LENGTH_LINES 0x0340
+
+#define AR0521_REG_CHIP_ID 0x3000
+#define AR0521_REG_COARSE_INTEGRATION_TIME 0x3012
+#define AR0521_REG_ROW_SPEED 0x3016
+#define AR0521_REG_EXTRA_DELAY 0x3018
+#define AR0521_REG_RESET 0x301A
+#define AR0521_REG_RESET_DEFAULTS 0x0238
+#define AR0521_REG_RESET_GROUP_PARAM_HOLD 0x8000
+#define AR0521_REG_RESET_STREAM BIT(2)
+#define AR0521_REG_RESET_RESTART BIT(1)
+#define AR0521_REG_RESET_INIT BIT(0)
+
+#define AR0521_REG_GREEN1_GAIN 0x3056
+#define AR0521_REG_BLUE_GAIN 0x3058
+#define AR0521_REG_RED_GAIN 0x305A
+#define AR0521_REG_GREEN2_GAIN 0x305C
+#define AR0521_REG_GLOBAL_GAIN 0x305E
+
+#define AR0521_REG_HISPI_TEST_MODE 0x3066
+#define AR0521_REG_HISPI_TEST_MODE_LP11 0x0004
+
+#define AR0521_REG_TEST_PATTERN_MODE 0x3070
+
+#define AR0521_REG_SERIAL_FORMAT 0x31AE
+#define AR0521_REG_SERIAL_FORMAT_MIPI 0x0200
+
+#define AR0521_REG_HISPI_CONTROL_STATUS 0x31C6
+#define AR0521_REG_HISPI_CONTROL_STATUS_FRAMER_TEST_MODE_ENABLE 0x80
+
+#define be cpu_to_be16
+
+static const char * const ar0521_supply_names[] = {
+ "vdd_io", /* I/O (1.8V) supply */
+ "vdd", /* Core, PLL and MIPI (1.2V) supply */
+ "vaa", /* Analog (2.7V) supply */
+};
+
+struct ar0521_ctrls {
+ struct v4l2_ctrl_handler handler;
+ struct {
+ struct v4l2_ctrl *gain;
+ struct v4l2_ctrl *red_balance;
+ struct v4l2_ctrl *blue_balance;
+ };
+ struct {
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
+ };
+ struct v4l2_ctrl *pixrate;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *test_pattern;
+};
+
+struct ar0521_dev {
+ struct i2c_client *i2c_client;
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct clk *extclk;
+ u32 extclk_freq;
+
+ struct regulator *supplies[ARRAY_SIZE(ar0521_supply_names)];
+ struct gpio_desc *reset_gpio;
+
+ /* lock to protect all members below */
+ struct mutex lock;
+
+ struct v4l2_mbus_framefmt fmt;
+ struct ar0521_ctrls ctrls;
+ unsigned int lane_count;
+ u16 total_width;
+ u16 total_height;
+ u16 pll_pre;
+ u16 pll_mult;
+ u16 pll_pre2;
+ u16 pll_mult2;
+ bool streaming;
+};
+
+static inline struct ar0521_dev *to_ar0521_dev(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ar0521_dev, sd);
+}
+
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct ar0521_dev,
+ ctrls.handler)->sd;
+}
+
+static u32 div64_round(u64 v, u32 d)
+{
+ return div_u64(v + (d >> 1), d);
+}
+
+static u32 div64_round_up(u64 v, u32 d)
+{
+ return div_u64(v + d - 1, d);
+}
+
+/* Data must be BE16, the first value is the register address */
+static int ar0521_write_regs(struct ar0521_dev *sensor, const __be16 *data,
+ unsigned int count)
+{
+ struct i2c_client *client = sensor->i2c_client;
+ struct i2c_msg msg;
+ int ret;
+
+ msg.addr = client->addr;
+ msg.flags = client->flags;
+ msg.buf = (u8 *)data;
+ msg.len = count * sizeof(*data);
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ if (ret < 0) {
+ v4l2_err(&sensor->sd, "%s: I2C write error\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ar0521_write_reg(struct ar0521_dev *sensor, u16 reg, u16 val)
+{
+ __be16 buf[2] = {be(reg), be(val)};
+
+ return ar0521_write_regs(sensor, buf, 2);
+}
+
+static int ar0521_set_geometry(struct ar0521_dev *sensor)
+{
+ /* All dimensions are unsigned 12-bit integers */
+ u16 x = (AR0521_WIDTH_MAX - sensor->fmt.width) / 2;
+ u16 y = ((AR0521_HEIGHT_MAX - sensor->fmt.height) / 2) & ~1;
+ __be16 regs[] = {
+ be(AR0521_REG_FRAME_LENGTH_LINES),
+ be(sensor->total_height),
+ be(sensor->total_width),
+ be(x),
+ be(y),
+ be(x + sensor->fmt.width - 1),
+ be(y + sensor->fmt.height - 1),
+ be(sensor->fmt.width),
+ be(sensor->fmt.height)
+ };
+
+ return ar0521_write_regs(sensor, regs, ARRAY_SIZE(regs));
+}
+
+static int ar0521_set_gains(struct ar0521_dev *sensor)
+{
+ int green = sensor->ctrls.gain->val;
+ int red = max(green + sensor->ctrls.red_balance->val, 0);
+ int blue = max(green + sensor->ctrls.blue_balance->val, 0);
+ unsigned int gain = min(red, min(green, blue));
+ unsigned int analog = min(gain, 64u); /* range is 0 - 127 */
+ __be16 regs[5];
+
+ red = min(red - analog + 64, 511u);
+ green = min(green - analog + 64, 511u);
+ blue = min(blue - analog + 64, 511u);
+ regs[0] = be(AR0521_REG_GREEN1_GAIN);
+ regs[1] = be(green << 7 | analog);
+ regs[2] = be(blue << 7 | analog);
+ regs[3] = be(red << 7 | analog);
+ regs[4] = be(green << 7 | analog);
+
+ return ar0521_write_regs(sensor, regs, ARRAY_SIZE(regs));
+}
+
+static u32 calc_pll(struct ar0521_dev *sensor, int num, u32 freq, u16 *pre_ptr,
+ u16 *mult_ptr)
+{
+ u16 pre = 1, mult = 1, new_pre;
+ u32 pll = AR0521_PLL_MAX + 1;
+
+ for (new_pre = 1; new_pre < 64; new_pre++) {
+ u32 new_pll;
+ u32 new_mult = div64_round_up((u64)freq * new_pre,
+ sensor->extclk_freq);
+
+ if (new_mult < 32)
+ continue; /* Minimum value */
+ if (new_mult > 254)
+ break; /* Maximum, larger pre won't work either */
+ if (sensor->extclk_freq * (u64)new_mult < AR0521_PLL_MIN *
+ new_pre)
+ continue;
+ if (sensor->extclk_freq * (u64)new_mult > AR0521_PLL_MAX *
+ new_pre)
+ break; /* Larger pre won't work either */
+ new_pll = div64_round_up(sensor->extclk_freq * (u64)new_mult,
+ new_pre);
+ if (new_pll < pll) {
+ pll = new_pll;
+ pre = new_pre;
+ mult = new_mult;
+ }
+ }
+
+ pll = div64_round(sensor->extclk_freq * (u64)mult, pre);
+ *pre_ptr = pre;
+ *mult_ptr = mult;
+ return pll;
+}
+
+#define DIV 4
+static void ar0521_calc_mode(struct ar0521_dev *sensor)
+{
+ unsigned int speed_mod = 4 / sensor->lane_count; /* 1 with 4 DDR lanes */
+ u16 total_width = max(sensor->fmt.width + AR0521_WIDTH_BLANKING_MIN,
+ AR0521_TOTAL_WIDTH_MIN);
+ u16 total_height = sensor->fmt.height + AR0521_HEIGHT_BLANKING_MIN;
+
+ /* Calculate approximate pixel clock first */
+ u64 pix_clk = AR0521_PIXEL_CLOCK_RATE;
+
+ /* PLL1 drives pixel clock - dual rate */
+ pix_clk = calc_pll(sensor, 1, pix_clk * (DIV / 2), &sensor->pll_pre,
+ &sensor->pll_mult);
+ pix_clk = div64_round(pix_clk, (DIV / 2));
+ calc_pll(sensor, 2, pix_clk * (DIV / 2) * speed_mod, &sensor->pll_pre2,
+ &sensor->pll_mult2);
+
+ sensor->total_width = total_width;
+ sensor->total_height = total_height;
+}
+
+static int ar0521_write_mode(struct ar0521_dev *sensor)
+{
+ __be16 pll_regs[] = {
+ be(AR0521_REG_VT_PIX_CLK_DIV),
+ /* 0x300 */ be(4), /* vt_pix_clk_div = number of bits / 2 */
+ /* 0x302 */ be(1), /* vt_sys_clk_div */
+ /* 0x304 */ be((sensor->pll_pre2 << 8) | sensor->pll_pre),
+ /* 0x306 */ be((sensor->pll_mult2 << 8) | sensor->pll_mult),
+ /* 0x308 */ be(8), /* op_pix_clk_div = 2 * vt_pix_clk_div */
+ /* 0x30A */ be(1) /* op_sys_clk_div */
+ };
+ int ret;
+
+ /* Stop streaming for just a moment */
+ ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
+ AR0521_REG_RESET_DEFAULTS);
+ if (ret)
+ return ret;
+
+ ret = ar0521_set_geometry(sensor);
+ if (ret)
+ return ret;
+
+ ret = ar0521_write_regs(sensor, pll_regs, ARRAY_SIZE(pll_regs));
+ if (ret)
+ return ret;
+
+ ret = ar0521_write_reg(sensor, AR0521_REG_COARSE_INTEGRATION_TIME,
+ sensor->ctrls.exposure->val);
+ if (ret)
+ return ret;
+
+ ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
+ AR0521_REG_RESET_DEFAULTS |
+ AR0521_REG_RESET_STREAM);
+ if (ret)
+ return ret;
+
+ ret = ar0521_write_reg(sensor, AR0521_REG_TEST_PATTERN_MODE,
+ sensor->ctrls.test_pattern->val);
+ return ret;
+}
+
+static int ar0521_set_stream(struct ar0521_dev *sensor, bool on)
+{
+ int ret;
+
+ if (on) {
+ ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev);
+ if (ret < 0)
+ return ret;
+
+ ar0521_calc_mode(sensor);
+ ret = ar0521_write_mode(sensor);
+ if (ret)
+ goto err;
+
+ ret = ar0521_set_gains(sensor);
+ if (ret)
+ goto err;
+
+ /* Exit LP-11 mode on clock and data lanes */
+ ret = ar0521_write_reg(sensor, AR0521_REG_HISPI_CONTROL_STATUS,
+ 0);
+ if (ret)
+ goto err;
+
+ /* Start streaming */
+ ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
+ AR0521_REG_RESET_DEFAULTS |
+ AR0521_REG_RESET_STREAM);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ pm_runtime_put(&sensor->i2c_client->dev);
+ return ret;
+
+ } else {
+ /*
+ * Reset gain, the sensor may produce all white pixels without
+ * this
+ */
+ ret = ar0521_write_reg(sensor, AR0521_REG_GLOBAL_GAIN, 0x2000);
+ if (ret)
+ return ret;
+
+ /* Stop streaming */
+ ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
+ AR0521_REG_RESET_DEFAULTS);
+ if (ret)
+ return ret;
+
+ pm_runtime_put(&sensor->i2c_client->dev);
+ return 0;
+ }
+}
+
+static void ar0521_adj_fmt(struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->width = clamp(ALIGN(fmt->width, 4), AR0521_WIDTH_MIN,
+ AR0521_WIDTH_MAX);
+ fmt->height = clamp(ALIGN(fmt->height, 4), AR0521_HEIGHT_MIN,
+ AR0521_HEIGHT_MAX);
+ fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int ar0521_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *format)
+{
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+ struct v4l2_mbus_framefmt *fmt;
+
+ mutex_lock(&sensor->lock);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ fmt = v4l2_subdev_get_try_format(&sensor->sd, sd_state, 0
+ /* pad */);
+ else
+ fmt = &sensor->fmt;
+
+ format->format = *fmt;
+
+ mutex_unlock(&sensor->lock);
+ return 0;
+}
+
+static int ar0521_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *format)
+{
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+ int ret = 0;
+
+ ar0521_adj_fmt(&format->format);
+
+ mutex_lock(&sensor->lock);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_get_try_format(sd, sd_state, 0 /* pad */);
+ *fmt = format->format;
+ } else {
+ sensor->fmt = format->format;
+ ar0521_calc_mode(sensor);
+ }
+
+ mutex_unlock(&sensor->lock);
+ return ret;
+}
+
+static int ar0521_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+ int ret;
+
+ /* v4l2_ctrl_lock() locks our own mutex */
+
+ switch (ctrl->id) {
+ case V4L2_CID_HBLANK:
+ case V4L2_CID_VBLANK:
+ sensor->total_width = sensor->fmt.width +
+ sensor->ctrls.hblank->val;
+ sensor->total_height = sensor->fmt.width +
+ sensor->ctrls.vblank->val;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ /* access the sensor only if it's powered up */
+ if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_HBLANK:
+ case V4L2_CID_VBLANK:
+ ret = ar0521_set_geometry(sensor);
+ break;
+ case V4L2_CID_GAIN:
+ case V4L2_CID_RED_BALANCE:
+ case V4L2_CID_BLUE_BALANCE:
+ ret = ar0521_set_gains(sensor);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = ar0521_write_reg(sensor,
+ AR0521_REG_COARSE_INTEGRATION_TIME,
+ ctrl->val);
+ break;
+ case V4L2_CID_TEST_PATTERN:
+ ret = ar0521_write_reg(sensor, AR0521_REG_TEST_PATTERN_MODE,
+ ctrl->val);
+ break;
+ }
+
+ pm_runtime_put(&sensor->i2c_client->dev);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops ar0521_ctrl_ops = {
+ .s_ctrl = ar0521_s_ctrl,
+};
+
+static const char * const test_pattern_menu[] = {
+ "Disabled",
+ "Solid color",
+ "Color bars",
+ "Faded color bars"
+};
+
+static int ar0521_init_controls(struct ar0521_dev *sensor)
+{
+ const struct v4l2_ctrl_ops *ops = &ar0521_ctrl_ops;
+ struct ar0521_ctrls *ctrls = &sensor->ctrls;
+ struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+ int ret;
+
+ v4l2_ctrl_handler_init(hdl, 32);
+
+ /* We can use our own mutex for the ctrl lock */
+ hdl->lock = &sensor->lock;
+
+ /* Manual gain */
+ ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN, 0, 511, 1, 0);
+ ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
+ -512, 511, 1, 0);
+ ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
+ -512, 511, 1, 0);
+ v4l2_ctrl_cluster(3, &ctrls->gain);
+
+ ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK,
+ AR0521_WIDTH_BLANKING_MIN, 4094, 1,
+ AR0521_WIDTH_BLANKING_MIN);
+ ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
+ AR0521_HEIGHT_BLANKING_MIN, 4094, 2,
+ AR0521_HEIGHT_BLANKING_MIN);
+ v4l2_ctrl_cluster(2, &ctrls->hblank);
+
+ /* Read-only */
+ ctrls->pixrate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
+ AR0521_PIXEL_CLOCK_MIN,
+ AR0521_PIXEL_CLOCK_MAX, 1,
+ AR0521_PIXEL_CLOCK_RATE);
+
+ /* Manual exposure time */
+ ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE, 0,
+ 65535, 1, 360);
+
+ ctrls->test_pattern = v4l2_ctrl_new_std_menu_items(hdl, ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(test_pattern_menu) - 1,
+ 0, 0, test_pattern_menu);
+
+ if (hdl->error) {
+ ret = hdl->error;
+ goto free_ctrls;
+ }
+
+ sensor->sd.ctrl_handler = hdl;
+ return 0;
+
+free_ctrls:
+ v4l2_ctrl_handler_free(hdl);
+ return ret;
+}
+
+#define REGS_ENTRY(a) {(a), ARRAY_SIZE(a)}
+#define REGS(...) REGS_ENTRY(((const __be16[]){__VA_ARGS__}))
+
+static const struct initial_reg {
+ const __be16 *data; /* data[0] is register address */
+ unsigned int count;
+} initial_regs[] = {
+ REGS(be(0x0112), be(0x0808)), /* 8-bit/8-bit mode */
+
+ /* PEDESTAL+2 :+2 is a workaround for 10bit mode +0.5 rounding */
+ REGS(be(0x301E), be(0x00AA)),
+
+ /* corrections_recommended_bayer */
+ REGS(be(0x3042),
+ be(0x0004), /* 3042: RNC: enable b/w rnc mode */
+ be(0x4580)), /* 3044: RNC: enable row noise correction */
+
+ REGS(be(0x30D2),
+ be(0x0000), /* 30D2: CRM/CC: enable crm on Visible and CC rows */
+ be(0x0000), /* 30D4: CC: CC enabled with 16 samples per column */
+ /* 30D6: CC: bw mode enabled/12 bit data resolution/bw mode */
+ be(0x2FFF)),
+
+ REGS(be(0x30DA),
+ be(0x0FFF), /* 30DA: CC: column correction clip level 2 is 0 */
+ be(0x0FFF), /* 30DC: CC: column correction clip level 3 is 0 */
+ be(0x0000)), /* 30DE: CC: Group FPN correction */
+
+ /* RNC: rnc scaling factor = * 54 / 64 (32 / 38 * 64 = 53.9) */
+ REGS(be(0x30EE), be(0x1136)),
+ REGS(be(0x30FA), be(0xFD00)), /* GPIO0 = flash, GPIO1 = shutter */
+ REGS(be(0x3120), be(0x0005)), /* p1 dither enabled for 10bit mode */
+ REGS(be(0x3172), be(0x0206)), /* txlo clk divider options */
+ /* FDOC:fdoc settings with fdoc every frame turned of */
+ REGS(be(0x3180), be(0x9434)),
+
+ REGS(be(0x31B0),
+ be(0x008B), /* 31B0: frame_preamble - FIXME check WRT lanes# */
+ be(0x0050)), /* 31B2: line_preamble - FIXME check WRT lanes# */
+
+ /* don't use continuous clock mode while shut down */
+ REGS(be(0x31BC), be(0x068C)),
+ REGS(be(0x31E0), be(0x0781)), /* Fuse/2DDC: enable 2ddc */
+
+ /* analog_setup_recommended_10bit */
+ REGS(be(0x341A), be(0x4735)), /* Samp&Hold pulse in ADC */
+ REGS(be(0x3420), be(0x4735)), /* Samp&Hold pulse in ADC */
+ REGS(be(0x3426), be(0x8A1A)), /* ADC offset distribution pulse */
+ REGS(be(0x342A), be(0x0018)), /* pulse_config */
+
+ /* pixel_timing_recommended */
+ REGS(be(0x3D00),
+ /* 3D00 */ be(0x043E), be(0x4760), be(0xFFFF), be(0xFFFF),
+ /* 3D08 */ be(0x8000), be(0x0510), be(0xAF08), be(0x0252),
+ /* 3D10 */ be(0x486F), be(0x5D5D), be(0x8056), be(0x8313),
+ /* 3D18 */ be(0x0087), be(0x6A48), be(0x6982), be(0x0280),
+ /* 3D20 */ be(0x8359), be(0x8D02), be(0x8020), be(0x4882),
+ /* 3D28 */ be(0x4269), be(0x6A95), be(0x5988), be(0x5A83),
+ /* 3D30 */ be(0x5885), be(0x6280), be(0x6289), be(0x6097),
+ /* 3D38 */ be(0x5782), be(0x605C), be(0xBF18), be(0x0961),
+ /* 3D40 */ be(0x5080), be(0x2090), be(0x4390), be(0x4382),
+ /* 3D48 */ be(0x5F8A), be(0x5D5D), be(0x9C63), be(0x8063),
+ /* 3D50 */ be(0xA960), be(0x9757), be(0x8260), be(0x5CFF),
+ /* 3D58 */ be(0xBF10), be(0x1681), be(0x0802), be(0x8000),
+ /* 3D60 */ be(0x141C), be(0x6000), be(0x6022), be(0x4D80),
+ /* 3D68 */ be(0x5C97), be(0x6A69), be(0xAC6F), be(0x4645),
+ /* 3D70 */ be(0x4400), be(0x0513), be(0x8069), be(0x6AC6),
+ /* 3D78 */ be(0x5F95), be(0x5F70), be(0x8040), be(0x4A81),
+ /* 3D80 */ be(0x0300), be(0xE703), be(0x0088), be(0x4A83),
+ /* 3D88 */ be(0x40FF), be(0xFFFF), be(0xFD70), be(0x8040),
+ /* 3D90 */ be(0x4A85), be(0x4FA8), be(0x4F8C), be(0x0070),
+ /* 3D98 */ be(0xBE47), be(0x8847), be(0xBC78), be(0x6B89),
+ /* 3DA0 */ be(0x6A80), be(0x6986), be(0x6B8E), be(0x6B80),
+ /* 3DA8 */ be(0x6980), be(0x6A88), be(0x7C9F), be(0x866B),
+ /* 3DB0 */ be(0x8765), be(0x46FF), be(0xE365), be(0xA679),
+ /* 3DB8 */ be(0x4A40), be(0x4580), be(0x44BC), be(0x7000),
+ /* 3DC0 */ be(0x8040), be(0x0802), be(0x10EF), be(0x0104),
+ /* 3DC8 */ be(0x3860), be(0x5D5D), be(0x5682), be(0x1300),
+ /* 3DD0 */ be(0x8648), be(0x8202), be(0x8082), be(0x598A),
+ /* 3DD8 */ be(0x0280), be(0x2048), be(0x3060), be(0x8042),
+ /* 3DE0 */ be(0x9259), be(0x865A), be(0x8258), be(0x8562),
+ /* 3DE8 */ be(0x8062), be(0x8560), be(0x9257), be(0x8221),
+ /* 3DF0 */ be(0x10FF), be(0xB757), be(0x9361), be(0x1019),
+ /* 3DF8 */ be(0x8020), be(0x9043), be(0x8E43), be(0x845F),
+ /* 3E00 */ be(0x835D), be(0x805D), be(0x8163), be(0x8063),
+ /* 3E08 */ be(0xA060), be(0x9157), be(0x8260), be(0x5CFF),
+ /* 3E10 */ be(0xFFFF), be(0xFFE5), be(0x1016), be(0x2048),
+ /* 3E18 */ be(0x0802), be(0x1C60), be(0x0014), be(0x0060),
+ /* 3E20 */ be(0x2205), be(0x8120), be(0x908F), be(0x6A80),
+ /* 3E28 */ be(0x6982), be(0x5F9F), be(0x6F46), be(0x4544),
+ /* 3E30 */ be(0x0005), be(0x8013), be(0x8069), be(0x6A80),
+ /* 3E38 */ be(0x7000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E40 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E48 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E50 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E58 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E60 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E68 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E70 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E78 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E80 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E88 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E90 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3E98 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3EA0 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3EA8 */ be(0x0000), be(0x0000), be(0x0000), be(0x0000),
+ /* 3EB0 */ be(0x0000), be(0x0000), be(0x0000)),
+
+ REGS(be(0x3EB6), be(0x004C)), /* ECL */
+
+ REGS(be(0x3EBA),
+ be(0xAAAD), /* 3EBA */
+ be(0x0086)), /* 3EBC: Bias currents for FSC/ECL */
+
+ REGS(be(0x3EC0),
+ be(0x1E00), /* 3EC0: SFbin/SH mode settings */
+ be(0x100A), /* 3EC2: CLK divider for ramp for 10 bit 400MH */
+ /* 3EC4: FSC clamps for HDR mode and adc comp power down co */
+ be(0x3300),
+ be(0xEA44), /* 3EC6: VLN and clk gating controls */
+ be(0x6F6F), /* 3EC8: Txl0 and Txlo1 settings for normal mode */
+ be(0x2F4A), /* 3ECA: CDAC/Txlo2/RSTGHI/RSTGLO settings */
+ be(0x0506), /* 3ECC: RSTDHI/RSTDLO/CDAC/TXHI settings */
+ /* 3ECE: Ramp buffer settings and Booster enable (bits 0-5) */
+ be(0x203B),
+ be(0x13F0), /* 3ED0: TXLO from atest/sf bin settings */
+ be(0xA53D), /* 3ED2: Ramp offset */
+ be(0x862F), /* 3ED4: TXLO open loop/row driver settings */
+ be(0x4081), /* 3ED6: Txlatch fr cfpn rows/vln bias */
+ be(0x8003), /* 3ED8: Ramp step setting for 10 bit 400 Mhz */
+ be(0xA580), /* 3EDA: Ramp Offset */
+ be(0xC000), /* 3EDC: over range for rst and under range for sig */
+ be(0xC103)), /* 3EDE: over range for sig and col dec clk settings */
+
+ /* corrections_recommended_bayer */
+ REGS(be(0x3F00),
+ be(0x0017), /* 3F00: BM_T0 */
+ be(0x02DD), /* 3F02: BM_T1 */
+ /* 3F04: if Ana_gain less than 2, use noise_floor0, multipl */
+ be(0x0020),
+ /* 3F06: if Ana_gain between 4 and 7, use noise_floor2 and */
+ be(0x0040),
+ /* 3F08: if Ana_gain between 4 and 7, use noise_floor2 and */
+ be(0x0070),
+ /* 3F0A: Define noise_floor0(low address) and noise_floor1 */
+ be(0x0101),
+ be(0x0302)), /* 3F0C: Define noise_floor2 and noise_floor3 */
+
+ REGS(be(0x3F10),
+ be(0x0505), /* 3F10: single k factor 0 */
+ be(0x0505), /* 3F12: single k factor 1 */
+ be(0x0505), /* 3F14: single k factor 2 */
+ be(0x01FF), /* 3F16: cross factor 0 */
+ be(0x01FF), /* 3F18: cross factor 1 */
+ be(0x01FF), /* 3F1A: cross factor 2 */
+ be(0x0022)), /* 3F1E */
+
+ /* GTH_THRES_RTN: 4max,4min filtered out of every 46 samples and */
+ REGS(be(0x3F2C), be(0x442E)),
+
+ REGS(be(0x3F3E),
+ be(0x0000), /* 3F3E: Switch ADC from 12 bit to 10 bit mode */
+ be(0x1511), /* 3F40: couple k factor 0 */
+ be(0x1511), /* 3F42: couple k factor 1 */
+ be(0x0707)), /* 3F44: couple k factor 2 */
+};
+
+static int ar0521_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+ int i;
+
+ clk_disable_unprepare(sensor->extclk);
+
+ if (sensor->reset_gpio)
+ gpiod_set_value(sensor->reset_gpio, 1); /* assert RESET signal */
+
+ for (i = ARRAY_SIZE(ar0521_supply_names) - 1; i >= 0; i--) {
+ if (sensor->supplies[i])
+ regulator_disable(sensor->supplies[i]);
+ }
+ return 0;
+}
+
+static int ar0521_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+ unsigned int cnt;
+ int ret;
+
+ for (cnt = 0; cnt < ARRAY_SIZE(ar0521_supply_names); cnt++)
+ if (sensor->supplies[cnt]) {
+ ret = regulator_enable(sensor->supplies[cnt]);
+ if (ret < 0)
+ goto off;
+
+ usleep_range(1000, 1500); /* min 1 ms */
+ }
+
+ ret = clk_prepare_enable(sensor->extclk);
+ if (ret < 0) {
+ v4l2_err(&sensor->sd, "error enabling sensor clock\n");
+ goto off;
+ }
+ usleep_range(1000, 1500); /* min 1 ms */
+
+ if (sensor->reset_gpio)
+ /* deassert RESET signal */
+ gpiod_set_value(sensor->reset_gpio, 0);
+ usleep_range(4500, 5000); /* min 45000 clocks */
+
+ for (cnt = 0; cnt < ARRAY_SIZE(initial_regs); cnt++)
+ if (ar0521_write_regs(sensor, initial_regs[cnt].data,
+ initial_regs[cnt].count))
+ goto off;
+
+ ret = ar0521_write_reg(sensor, AR0521_REG_SERIAL_FORMAT,
+ AR0521_REG_SERIAL_FORMAT_MIPI |
+ sensor->lane_count);
+ if (ret)
+ goto off;
+
+ /* set MIPI test mode - disabled for now */
+ ret = ar0521_write_reg(sensor, AR0521_REG_HISPI_TEST_MODE,
+ ((0x40 << sensor->lane_count) - 0x40) |
+ AR0521_REG_HISPI_TEST_MODE_LP11);
+ if (ret)
+ goto off;
+
+ ret = ar0521_write_reg(sensor, AR0521_REG_ROW_SPEED, 0x110 |
+ 4 / sensor->lane_count);
+ if (ret)
+ goto off;
+
+ return 0;
+off:
+ ar0521_power_off(dev);
+ return ret;
+}
+
+static int ar0521_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+
+ if (code->index)
+ return -EINVAL;
+
+ code->code = sensor->fmt.code;
+ return 0;
+}
+
+static int ar0521_pre_streamon(struct v4l2_subdev *sd, u32 flags)
+{
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+ int ret;
+
+ if (!(flags & V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP))
+ return -EACCES;
+
+ ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev);
+ if (ret < 0)
+ return ret;
+
+ /* Set LP-11 on clock and data lanes */
+ ret = ar0521_write_reg(sensor, AR0521_REG_HISPI_CONTROL_STATUS,
+ AR0521_REG_HISPI_CONTROL_STATUS_FRAMER_TEST_MODE_ENABLE);
+ if (ret)
+ goto err;
+
+ /* Start streaming LP-11 */
+ ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
+ AR0521_REG_RESET_DEFAULTS |
+ AR0521_REG_RESET_STREAM);
+ if (ret)
+ goto err;
+ return 0;
+
+err:
+ pm_runtime_put(&sensor->i2c_client->dev);
+ return ret;
+}
+
+static int ar0521_post_streamoff(struct v4l2_subdev *sd)
+{
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+
+ pm_runtime_put(&sensor->i2c_client->dev);
+ return 0;
+}
+
+static int ar0521_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+ int ret;
+
+ mutex_lock(&sensor->lock);
+
+ ret = ar0521_set_stream(sensor, enable);
+ if (!ret)
+ sensor->streaming = enable;
+
+ mutex_unlock(&sensor->lock);
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops ar0521_core_ops = {
+ .log_status = v4l2_ctrl_subdev_log_status,
+};
+
+static const struct v4l2_subdev_video_ops ar0521_video_ops = {
+ .s_stream = ar0521_s_stream,
+ .pre_streamon = ar0521_pre_streamon,
+ .post_streamoff = ar0521_post_streamoff,
+};
+
+static const struct v4l2_subdev_pad_ops ar0521_pad_ops = {
+ .enum_mbus_code = ar0521_enum_mbus_code,
+ .get_fmt = ar0521_get_fmt,
+ .set_fmt = ar0521_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ar0521_subdev_ops = {
+ .core = &ar0521_core_ops,
+ .video = &ar0521_video_ops,
+ .pad = &ar0521_pad_ops,
+};
+
+static int __maybe_unused ar0521_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+
+ if (sensor->streaming)
+ ar0521_set_stream(sensor, 0);
+
+ return 0;
+}
+
+static int __maybe_unused ar0521_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+
+ if (sensor->streaming)
+ return ar0521_set_stream(sensor, 1);
+
+ return 0;
+}
+
+static int ar0521_probe(struct i2c_client *client)
+{
+ struct v4l2_fwnode_endpoint ep = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ struct device *dev = &client->dev;
+ struct fwnode_handle *endpoint;
+ struct ar0521_dev *sensor;
+ unsigned int cnt;
+ int ret;
+
+ sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
+ if (!sensor)
+ return -ENOMEM;
+
+ sensor->i2c_client = client;
+ sensor->fmt.width = AR0521_WIDTH_MAX;
+ sensor->fmt.height = AR0521_HEIGHT_MAX;
+
+ endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!endpoint) {
+ dev_err(dev, "endpoint node not found\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_fwnode_endpoint_parse(endpoint, &ep);
+ fwnode_handle_put(endpoint);
+ if (ret) {
+ dev_err(dev, "could not parse endpoint\n");
+ return ret;
+ }
+
+ if (ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
+ dev_err(dev, "invalid bus type, must be MIPI CSI2\n");
+ return -EINVAL;
+ }
+
+ sensor->lane_count = ep.bus.mipi_csi2.num_data_lanes;
+ switch (sensor->lane_count) {
+ case 1:
+ case 2:
+ case 4:
+ break;
+ default:
+ dev_err(dev, "invalid number of MIPI data lanes\n");
+ return -EINVAL;
+ }
+
+ /* Get master clock (extclk) */
+ sensor->extclk = devm_clk_get(dev, "extclk");
+ if (IS_ERR(sensor->extclk)) {
+ dev_err(dev, "failed to get extclk\n");
+ return PTR_ERR(sensor->extclk);
+ }
+
+ sensor->extclk_freq = clk_get_rate(sensor->extclk);
+
+ if (sensor->extclk_freq < AR0521_EXTCLK_MIN ||
+ sensor->extclk_freq > AR0521_EXTCLK_MAX) {
+ dev_err(dev, "extclk frequency out of range: %u Hz\n",
+ sensor->extclk_freq);
+ return -EINVAL;
+ }
+
+ /* Request optional reset pin (usually active low) and assert it */
+ sensor->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_HIGH);
+
+ v4l2_i2c_subdev_init(&sensor->sd, client, &ar0521_subdev_ops);
+
+ sensor->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
+ if (ret)
+ return ret;
+
+ for (cnt = 0; cnt < ARRAY_SIZE(ar0521_supply_names); cnt++) {
+ struct regulator *supply = devm_regulator_get(dev,
+ ar0521_supply_names[cnt]);
+
+ if (IS_ERR(supply)) {
+ dev_info(dev, "no %s regulator found: %li\n",
+ ar0521_supply_names[cnt], PTR_ERR(supply));
+ return PTR_ERR(supply);
+ }
+ sensor->supplies[cnt] = supply;
+ }
+
+ mutex_init(&sensor->lock);
+
+ ret = ar0521_init_controls(sensor);
+ if (ret)
+ goto entity_cleanup;
+
+ ar0521_adj_fmt(&sensor->fmt);
+
+ ret = v4l2_async_register_subdev(&sensor->sd);
+ if (ret)
+ goto free_ctrls;
+
+ /* Turn on the device and enable runtime PM */
+ ret = ar0521_power_on(&client->dev);
+ if (ret)
+ goto disable;
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+ pm_runtime_idle(&client->dev);
+ return 0;
+
+disable:
+ v4l2_async_unregister_subdev(&sensor->sd);
+ media_entity_cleanup(&sensor->sd.entity);
+free_ctrls:
+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
+entity_cleanup:
+ media_entity_cleanup(&sensor->sd.entity);
+ mutex_destroy(&sensor->lock);
+ return ret;
+}
+
+static int ar0521_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ar0521_dev *sensor = to_ar0521_dev(sd);
+
+ v4l2_async_unregister_subdev(&sensor->sd);
+ media_entity_cleanup(&sensor->sd.entity);
+ v4l2_ctrl_handler_free(&sensor->ctrls.handler);
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ ar0521_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ mutex_destroy(&sensor->lock);
+ return 0;
+}
+
+static const struct dev_pm_ops ar0521_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ar0521_suspend, ar0521_resume)
+ SET_RUNTIME_PM_OPS(ar0521_power_off, ar0521_power_on, NULL)
+};
+static const struct of_device_id ar0521_dt_ids[] = {
+ {.compatible = "onnn,ar0521"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, ar0521_dt_ids);
+
+static struct i2c_driver ar0521_i2c_driver = {
+ .driver = {
+ .name = "ar0521",
+ .pm = &ar0521_pm_ops,
+ .of_match_table = ar0521_dt_ids,
+ },
+ .probe_new = ar0521_probe,
+ .remove = ar0521_remove,
+};
+
+module_i2c_driver(ar0521_i2c_driver);
+
+MODULE_DESCRIPTION("AR0521 MIPI Camera subdev driver");
+MODULE_AUTHOR("Krzysztof Hałasa <khalasa@piap.pl>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index cbce8b88dbcf..1fd4dc6e4726 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -623,12 +623,22 @@ static int mt9p031_get_selection(struct v4l2_subdev *subdev,
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
- if (sel->target != V4L2_SEL_TGT_CROP)
- return -EINVAL;
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = MT9P031_COLUMN_START_MIN;
+ sel->r.top = MT9P031_ROW_START_MIN;
+ sel->r.width = MT9P031_WINDOW_WIDTH_MAX;
+ sel->r.height = MT9P031_WINDOW_HEIGHT_MAX;
+ return 0;
- sel->r = *__mt9p031_get_pad_crop(mt9p031, sd_state, sel->pad,
- sel->which);
- return 0;
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *__mt9p031_get_pad_crop(mt9p031, sd_state,
+ sel->pad, sel->which);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
}
static int mt9p031_set_selection(struct v4l2_subdev *subdev,
@@ -682,6 +692,37 @@ static int mt9p031_set_selection(struct v4l2_subdev *subdev,
return 0;
}
+static int mt9p031_init_cfg(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct mt9p031 *mt9p031 = to_mt9p031(subdev);
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+ const int which = sd_state == NULL ? V4L2_SUBDEV_FORMAT_ACTIVE :
+ V4L2_SUBDEV_FORMAT_TRY;
+
+ crop = __mt9p031_get_pad_crop(mt9p031, sd_state, 0, which);
+ v4l2_subdev_get_try_crop(subdev, sd_state, 0);
+ crop->left = MT9P031_COLUMN_START_DEF;
+ crop->top = MT9P031_ROW_START_DEF;
+ crop->width = MT9P031_WINDOW_WIDTH_DEF;
+ crop->height = MT9P031_WINDOW_HEIGHT_DEF;
+
+ format = __mt9p031_get_pad_format(mt9p031, sd_state, 0, which);
+
+ if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
+ format->code = MEDIA_BUS_FMT_Y12_1X12;
+ else
+ format->code = MEDIA_BUS_FMT_SGRBG12_1X12;
+
+ format->width = MT9P031_WINDOW_WIDTH_DEF;
+ format->height = MT9P031_WINDOW_HEIGHT_DEF;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return 0;
+}
+
/* -----------------------------------------------------------------------------
* V4L2 subdev control operations
*/
@@ -980,28 +1021,6 @@ static int mt9p031_registered(struct v4l2_subdev *subdev)
static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
{
- struct mt9p031 *mt9p031 = to_mt9p031(subdev);
- struct v4l2_mbus_framefmt *format;
- struct v4l2_rect *crop;
-
- crop = v4l2_subdev_get_try_crop(subdev, fh->state, 0);
- crop->left = MT9P031_COLUMN_START_DEF;
- crop->top = MT9P031_ROW_START_DEF;
- crop->width = MT9P031_WINDOW_WIDTH_DEF;
- crop->height = MT9P031_WINDOW_HEIGHT_DEF;
-
- format = v4l2_subdev_get_try_format(subdev, fh->state, 0);
-
- if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
- format->code = MEDIA_BUS_FMT_Y12_1X12;
- else
- format->code = MEDIA_BUS_FMT_SGRBG12_1X12;
-
- format->width = MT9P031_WINDOW_WIDTH_DEF;
- format->height = MT9P031_WINDOW_HEIGHT_DEF;
- format->field = V4L2_FIELD_NONE;
- format->colorspace = V4L2_COLORSPACE_SRGB;
-
return mt9p031_set_power(subdev, 1);
}
@@ -1019,6 +1038,7 @@ static const struct v4l2_subdev_video_ops mt9p031_subdev_video_ops = {
};
static const struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
+ .init_cfg = mt9p031_init_cfg,
.enum_mbus_code = mt9p031_enum_mbus_code,
.enum_frame_size = mt9p031_enum_frame_size,
.get_fmt = mt9p031_get_format,
@@ -1166,20 +1186,9 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- mt9p031->crop.width = MT9P031_WINDOW_WIDTH_DEF;
- mt9p031->crop.height = MT9P031_WINDOW_HEIGHT_DEF;
- mt9p031->crop.left = MT9P031_COLUMN_START_DEF;
- mt9p031->crop.top = MT9P031_ROW_START_DEF;
-
- if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
- mt9p031->format.code = MEDIA_BUS_FMT_Y12_1X12;
- else
- mt9p031->format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
-
- mt9p031->format.width = MT9P031_WINDOW_WIDTH_DEF;
- mt9p031->format.height = MT9P031_WINDOW_HEIGHT_DEF;
- mt9p031->format.field = V4L2_FIELD_NONE;
- mt9p031->format.colorspace = V4L2_COLORSPACE_SRGB;
+ ret = mt9p031_init_cfg(&mt9p031->subdev, NULL);
+ if (ret)
+ goto done;
mt9p031->reset = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_HIGH);
@@ -1214,6 +1223,7 @@ static int mt9p031_remove(struct i2c_client *client)
}
static const struct i2c_device_id mt9p031_id[] = {
+ { "mt9p006", MT9P031_MODEL_COLOR },
{ "mt9p031", MT9P031_MODEL_COLOR },
{ "mt9p031m", MT9P031_MODEL_MONOCHROME },
{ }
@@ -1222,6 +1232,7 @@ MODULE_DEVICE_TABLE(i2c, mt9p031_id);
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id mt9p031_of_match[] = {
+ { .compatible = "aptina,mt9p006", },
{ .compatible = "aptina,mt9p031", },
{ .compatible = "aptina,mt9p031m", },
{ /* sentinel */ },
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index db5a19babe67..502f0b62e950 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -29,8 +29,21 @@
#define OV5640_XCLK_MIN 6000000
#define OV5640_XCLK_MAX 54000000
+#define OV5640_NATIVE_WIDTH 2624
+#define OV5640_NATIVE_HEIGHT 1964
+#define OV5640_PIXEL_ARRAY_TOP 14
+#define OV5640_PIXEL_ARRAY_LEFT 16
+#define OV5640_PIXEL_ARRAY_WIDTH 2592
+#define OV5640_PIXEL_ARRAY_HEIGHT 1944
+
+/* FIXME: not documented. */
+#define OV5640_MIN_VBLANK 24
+#define OV5640_MAX_VTS 3375
+
#define OV5640_DEFAULT_SLAVE_ID 0x3c
+#define OV5640_LINK_RATE_MAX 490000000U
+
#define OV5640_REG_SYS_RESET02 0x3002
#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006
#define OV5640_REG_SYS_CTRL0 0x3008
@@ -59,10 +72,16 @@
#define OV5640_REG_AEC_PK_MANUAL 0x3503
#define OV5640_REG_AEC_PK_REAL_GAIN 0x350a
#define OV5640_REG_AEC_PK_VTS 0x350c
+#define OV5640_REG_TIMING_HS 0x3800
+#define OV5640_REG_TIMING_VS 0x3802
+#define OV5640_REG_TIMING_HW 0x3804
+#define OV5640_REG_TIMING_VH 0x3806
#define OV5640_REG_TIMING_DVPHO 0x3808
#define OV5640_REG_TIMING_DVPVO 0x380a
#define OV5640_REG_TIMING_HTS 0x380c
#define OV5640_REG_TIMING_VTS 0x380e
+#define OV5640_REG_TIMING_HOFFS 0x3810
+#define OV5640_REG_TIMING_VOFFS 0x3812
#define OV5640_REG_TIMING_TC_REG20 0x3820
#define OV5640_REG_TIMING_TC_REG21 0x3821
#define OV5640_REG_AEC_CTRL00 0x3a00
@@ -88,6 +107,7 @@
#define OV5640_REG_POLARITY_CTRL00 0x4740
#define OV5640_REG_MIPI_CTRL00 0x4800
#define OV5640_REG_DEBUG_MODE 0x4814
+#define OV5640_REG_PCLK_PERIOD 0x4837
#define OV5640_REG_ISP_FORMAT_MUX_CTRL 0x501f
#define OV5640_REG_PRE_ISP_TEST_SET1 0x503d
#define OV5640_REG_SDE_CTRL0 0x5580
@@ -118,6 +138,47 @@ enum ov5640_frame_rate {
OV5640_NUM_FRAMERATES,
};
+enum ov5640_pixel_rate_id {
+ OV5640_PIXEL_RATE_168M,
+ OV5640_PIXEL_RATE_148M,
+ OV5640_PIXEL_RATE_124M,
+ OV5640_PIXEL_RATE_96M,
+ OV5640_PIXEL_RATE_48M,
+ OV5640_NUM_PIXEL_RATES,
+};
+
+/*
+ * The chip manual suggests 24/48/96/192 MHz pixel clocks.
+ *
+ * 192MHz exceeds the sysclk limits; use 168MHz as maximum pixel rate for
+ * full resolution mode @15 FPS.
+ */
+static const u32 ov5640_pixel_rates[] = {
+ [OV5640_PIXEL_RATE_168M] = 168000000,
+ [OV5640_PIXEL_RATE_148M] = 148000000,
+ [OV5640_PIXEL_RATE_124M] = 124000000,
+ [OV5640_PIXEL_RATE_96M] = 96000000,
+ [OV5640_PIXEL_RATE_48M] = 48000000,
+};
+
+/*
+ * MIPI CSI-2 link frequencies.
+ *
+ * Derived from the above defined pixel rate for bpp = (8, 16, 24) and
+ * data_lanes = (1, 2)
+ *
+ * link_freq = (pixel_rate * bpp) / (2 * data_lanes)
+ */
+static const s64 ov5640_csi2_link_freqs[] = {
+ 992000000, 888000000, 768000000, 744000000, 672000000, 672000000,
+ 592000000, 592000000, 576000000, 576000000, 496000000, 496000000,
+ 384000000, 384000000, 384000000, 336000000, 296000000, 288000000,
+ 248000000, 192000000, 192000000, 192000000, 96000000,
+};
+
+/* Link freq for default mode: UYVY 16 bpp, 2 data lanes. */
+#define OV5640_DEFAULT_LINK_FREQ 13
+
enum ov5640_format_mux {
OV5640_FMT_MUX_YUV422 = 0,
OV5640_FMT_MUX_RGB,
@@ -130,20 +191,145 @@ enum ov5640_format_mux {
struct ov5640_pixfmt {
u32 code;
u32 colorspace;
+ u8 bpp;
+ u8 ctrl00;
+ enum ov5640_format_mux mux;
+};
+
+static const struct ov5640_pixfmt ov5640_dvp_formats[] = {
+ {
+ /* YUV422, YUYV */
+ .code = MEDIA_BUS_FMT_JPEG_1X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .bpp = 16,
+ .ctrl00 = 0x30,
+ .mux = OV5640_FMT_MUX_YUV422,
+ }, {
+ /* YUV422, UYVY */
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 16,
+ .ctrl00 = 0x3f,
+ .mux = OV5640_FMT_MUX_YUV422,
+ }, {
+ /* YUV422, YUYV */
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 16,
+ .ctrl00 = 0x30,
+ .mux = OV5640_FMT_MUX_YUV422,
+ }, {
+ /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 16,
+ .ctrl00 = 0x6f,
+ .mux = OV5640_FMT_MUX_RGB,
+ }, {
+ /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 16,
+ .ctrl00 = 0x61,
+ .mux = OV5640_FMT_MUX_RGB,
+ }, {
+ /* Raw, BGBG... / GRGR... */
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 8,
+ .ctrl00 = 0x00,
+ .mux = OV5640_FMT_MUX_RAW_DPC,
+ }, {
+ /* Raw bayer, GBGB... / RGRG... */
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 8,
+ .ctrl00 = 0x01,
+ .mux = OV5640_FMT_MUX_RAW_DPC,
+ }, {
+ /* Raw bayer, GRGR... / BGBG... */
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 8,
+ .ctrl00 = 0x02,
+ .mux = OV5640_FMT_MUX_RAW_DPC,
+ }, {
+ /* Raw bayer, RGRG... / GBGB... */
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 8,
+ .ctrl00 = 0x03,
+ .mux = OV5640_FMT_MUX_RAW_DPC,
+ },
+ { /* sentinel */ }
};
-static const struct ov5640_pixfmt ov5640_formats[] = {
- { MEDIA_BUS_FMT_JPEG_1X8, V4L2_COLORSPACE_JPEG, },
- { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, },
- { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_COLORSPACE_SRGB, },
- { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, },
- { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_COLORSPACE_SRGB, },
- { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, },
- { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, },
- { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB, },
- { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_COLORSPACE_SRGB, },
- { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_COLORSPACE_SRGB, },
- { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB, },
+static const struct ov5640_pixfmt ov5640_csi2_formats[] = {
+ {
+ /* YUV422, YUYV */
+ .code = MEDIA_BUS_FMT_JPEG_1X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .bpp = 16,
+ .ctrl00 = 0x30,
+ .mux = OV5640_FMT_MUX_YUV422,
+ }, {
+ /* YUV422, UYVY */
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 16,
+ .ctrl00 = 0x3f,
+ .mux = OV5640_FMT_MUX_YUV422,
+ }, {
+ /* YUV422, YUYV */
+ .code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 16,
+ .ctrl00 = 0x30,
+ .mux = OV5640_FMT_MUX_YUV422,
+ }, {
+ /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
+ .code = MEDIA_BUS_FMT_RGB565_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 16,
+ .ctrl00 = 0x6f,
+ .mux = OV5640_FMT_MUX_RGB,
+ }, {
+ /* BGR888: RGB */
+ .code = MEDIA_BUS_FMT_BGR888_1X24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 24,
+ .ctrl00 = 0x23,
+ .mux = OV5640_FMT_MUX_RGB,
+ }, {
+ /* Raw, BGBG... / GRGR... */
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 8,
+ .ctrl00 = 0x00,
+ .mux = OV5640_FMT_MUX_RAW_DPC,
+ }, {
+ /* Raw bayer, GBGB... / RGRG... */
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 8,
+ .ctrl00 = 0x01,
+ .mux = OV5640_FMT_MUX_RAW_DPC,
+ }, {
+ /* Raw bayer, GRGR... / BGBG... */
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 8,
+ .ctrl00 = 0x02,
+ .mux = OV5640_FMT_MUX_RAW_DPC,
+ }, {
+ /* Raw bayer, RGRG... / GBGB... */
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .bpp = 8,
+ .ctrl00 = 0x03,
+ .mux = OV5640_FMT_MUX_RAW_DPC,
+ },
+ { /* sentinel */ }
};
/*
@@ -186,21 +372,42 @@ struct reg_value {
u32 delay_ms;
};
+struct ov5640_timings {
+ /* Analog crop rectangle. */
+ struct v4l2_rect analog_crop;
+ /* Visibile crop: from analog crop top-left corner. */
+ struct v4l2_rect crop;
+ /* Total pixels per line: width + fixed hblank. */
+ u32 htot;
+ /* Default vertical blanking: frame height = height + vblank. */
+ u32 vblank_def;
+};
+
struct ov5640_mode_info {
enum ov5640_mode_id id;
enum ov5640_downsize_mode dn_mode;
- u32 hact;
- u32 htot;
- u32 vact;
- u32 vtot;
+ enum ov5640_pixel_rate_id pixel_rate;
+
+ unsigned int width;
+ unsigned int height;
+
+ struct ov5640_timings dvp_timings;
+ struct ov5640_timings csi2_timings;
+
const struct reg_value *reg_data;
u32 reg_data_size;
+
+ /* Used by s_frame_interval only. */
u32 max_fps;
+ u32 def_fps;
};
struct ov5640_ctrls {
struct v4l2_ctrl_handler handler;
struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vblank;
struct {
struct v4l2_ctrl *auto_exp;
struct v4l2_ctrl *exposure;
@@ -249,6 +456,7 @@ struct ov5640_dev {
const struct ov5640_mode_info *last_mode;
enum ov5640_frame_rate current_fr;
struct v4l2_fract frame_interval;
+ s64 current_link_freq;
struct ov5640_ctrls ctrls;
@@ -270,6 +478,40 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
ctrls.handler)->sd;
}
+static inline bool ov5640_is_csi2(const struct ov5640_dev *sensor)
+{
+ return sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY;
+}
+
+static inline const struct ov5640_pixfmt *
+ov5640_formats(struct ov5640_dev *sensor)
+{
+ return ov5640_is_csi2(sensor) ? ov5640_csi2_formats
+ : ov5640_dvp_formats;
+}
+
+static const struct ov5640_pixfmt *
+ov5640_code_to_pixfmt(struct ov5640_dev *sensor, u32 code)
+{
+ const struct ov5640_pixfmt *formats = ov5640_formats(sensor);
+ unsigned int i;
+
+ for (i = 0; formats[i].code; ++i) {
+ if (formats[i].code == code)
+ return &formats[i];
+ }
+
+ return &formats[0];
+}
+
+static u32 ov5640_code_to_bpp(struct ov5640_dev *sensor, u32 code)
+{
+ const struct ov5640_pixfmt *format = ov5640_code_to_pixfmt(sensor,
+ code);
+
+ return format->bpp;
+}
+
/*
* FIXME: all of these register tables are likely filled with
* entries that set the register to their power-on default values,
@@ -278,7 +520,19 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
* over i2c.
*/
/* YUV422 UYVY VGA@30fps */
-static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
+
+static const struct v4l2_mbus_framefmt ov5640_default_fmt = {
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .width = 640,
+ .height = 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),
+ .quantization = V4L2_QUANTIZATION_FULL_RANGE,
+ .xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),
+ .field = V4L2_FIELD_NONE,
+};
+
+static const struct reg_value ov5640_init_setting[] = {
{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
{0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
@@ -294,11 +548,7 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
{0x3c06, 0x00, 0, 0}, {0x3c07, 0x08, 0, 0}, {0x3c08, 0x00, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3820, 0x41, 0, 0}, {0x3821, 0x07, 0, 0}, {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3815, 0x31, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
@@ -362,72 +612,11 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
{0x3a1f, 0x14, 0, 0}, {0x3008, 0x02, 0, 0}, {0x3c00, 0x04, 0, 300},
};
-static const struct reg_value ov5640_setting_VGA_640_480[] = {
- {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_XGA_1024_768[] = {
- {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_QVGA_320_240[] = {
- {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_QQVGA_160_120[] = {
+static const struct reg_value ov5640_setting_low_res[] = {
{0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
+ {0x3815, 0x31, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
@@ -437,72 +626,11 @@ static const struct reg_value ov5640_setting_QQVGA_160_120[] = {
{0x4407, 0x04, 0, 0}, {0x5001, 0xa3, 0, 0},
};
-static const struct reg_value ov5640_setting_QCIF_176_144[] = {
- {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_NTSC_720_480[] = {
- {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
-static const struct reg_value ov5640_setting_PAL_720_576[] = {
- {0x3c07, 0x08, 0, 0},
- {0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
- {0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
- {0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
- {0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
- {0x3a0a, 0x00, 0, 0}, {0x3a0b, 0xf6, 0, 0}, {0x3a0e, 0x03, 0, 0},
- {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
- {0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0},
- {0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
- {0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
-};
-
static const struct reg_value ov5640_setting_720P_1280_720[] = {
{0x3c07, 0x07, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x31, 0, 0},
- {0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3815, 0x31, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
{0x3a03, 0xe4, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0xbc, 0, 0},
@@ -517,11 +645,7 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
{0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x11, 0, 0},
- {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3815, 0x11, 0, 0},
{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
@@ -532,9 +656,6 @@ static const struct reg_value ov5640_setting_1080P_1920_1080[] = {
{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 0},
{0x3c07, 0x07, 0, 0}, {0x3c08, 0x00, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
- {0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
- {0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
- {0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0},
{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
@@ -548,11 +669,7 @@ static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
{0x3c07, 0x08, 0, 0},
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3814, 0x11, 0, 0},
- {0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
- {0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
- {0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
- {0x3810, 0x00, 0, 0},
- {0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
+ {0x3815, 0x11, 0, 0},
{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
{0x3a03, 0xd8, 0, 0}, {0x3a08, 0x01, 0, 0}, {0x3a09, 0x27, 0, 0},
@@ -563,67 +680,462 @@ static const struct reg_value ov5640_setting_QSXGA_2592_1944[] = {
{0x3824, 0x02, 0, 0}, {0x5001, 0x83, 0, 70},
};
-/* power-on sensor init reg table */
-static const struct ov5640_mode_info ov5640_mode_init_data = {
- 0, SUBSAMPLING, 640, 1896, 480, 984,
- ov5640_init_setting_30fps_VGA,
- ARRAY_SIZE(ov5640_init_setting_30fps_VGA),
- OV5640_30_FPS,
+static const struct ov5640_mode_info ov5640_mode_data[OV5640_NUM_MODES] = {
+ {
+ /* 160x120 */
+ .id = OV5640_MODE_QQVGA_160_120,
+ .dn_mode = SUBSAMPLING,
+ .pixel_rate = OV5640_PIXEL_RATE_48M,
+ .width = 160,
+ .height = 120,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 4,
+ .width = 2624,
+ .height = 1944,
+ },
+ .crop = {
+ .left = 16,
+ .top = 6,
+ .width = 160,
+ .height = 120,
+ },
+ .htot = 1896,
+ .vblank_def = 864,
+ },
+ .csi2_timings = {
+ /* Feed the full valid pixel array to the ISP. */
+ .analog_crop = {
+ .left = OV5640_PIXEL_ARRAY_LEFT,
+ .top = OV5640_PIXEL_ARRAY_TOP,
+ .width = OV5640_PIXEL_ARRAY_WIDTH,
+ .height = OV5640_PIXEL_ARRAY_HEIGHT,
+ },
+ /* Maintain a minimum processing margin. */
+ .crop = {
+ .left = 2,
+ .top = 4,
+ .width = 160,
+ .height = 120,
+ },
+ .htot = 1600,
+ .vblank_def = 878,
+ },
+ .reg_data = ov5640_setting_low_res,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res),
+ .max_fps = OV5640_30_FPS,
+ .def_fps = OV5640_30_FPS
+ }, {
+ /* 176x144 */
+ .id = OV5640_MODE_QCIF_176_144,
+ .dn_mode = SUBSAMPLING,
+ .pixel_rate = OV5640_PIXEL_RATE_48M,
+ .width = 176,
+ .height = 144,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 4,
+ .width = 2624,
+ .height = 1944,
+ },
+ .crop = {
+ .left = 16,
+ .top = 6,
+ .width = 176,
+ .height = 144,
+ },
+ .htot = 1896,
+ .vblank_def = 840,
+ },
+ .csi2_timings = {
+ /* Feed the full valid pixel array to the ISP. */
+ .analog_crop = {
+ .left = OV5640_PIXEL_ARRAY_LEFT,
+ .top = OV5640_PIXEL_ARRAY_TOP,
+ .width = OV5640_PIXEL_ARRAY_WIDTH,
+ .height = OV5640_PIXEL_ARRAY_HEIGHT,
+ },
+ /* Maintain a minimum processing margin. */
+ .crop = {
+ .left = 2,
+ .top = 4,
+ .width = 176,
+ .height = 144,
+ },
+ .htot = 1600,
+ .vblank_def = 854,
+ },
+ .reg_data = ov5640_setting_low_res,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res),
+ .max_fps = OV5640_30_FPS,
+ .def_fps = OV5640_30_FPS
+ }, {
+ /* 320x240 */
+ .id = OV5640_MODE_QVGA_320_240,
+ .dn_mode = SUBSAMPLING,
+ .width = 320,
+ .height = 240,
+ .pixel_rate = OV5640_PIXEL_RATE_48M,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 4,
+ .width = 2624,
+ .height = 1944,
+ },
+ .crop = {
+ .left = 16,
+ .top = 6,
+ .width = 320,
+ .height = 240,
+ },
+ .htot = 1896,
+ .vblank_def = 744,
+ },
+ .csi2_timings = {
+ /* Feed the full valid pixel array to the ISP. */
+ .analog_crop = {
+ .left = OV5640_PIXEL_ARRAY_LEFT,
+ .top = OV5640_PIXEL_ARRAY_TOP,
+ .width = OV5640_PIXEL_ARRAY_WIDTH,
+ .height = OV5640_PIXEL_ARRAY_HEIGHT,
+ },
+ /* Maintain a minimum processing margin. */
+ .crop = {
+ .left = 2,
+ .top = 4,
+ .width = 320,
+ .height = 240,
+ },
+ .htot = 1600,
+ .vblank_def = 760,
+ },
+ .reg_data = ov5640_setting_low_res,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res),
+ .max_fps = OV5640_30_FPS,
+ .def_fps = OV5640_30_FPS
+ }, {
+ /* 640x480 */
+ .id = OV5640_MODE_VGA_640_480,
+ .dn_mode = SUBSAMPLING,
+ .pixel_rate = OV5640_PIXEL_RATE_48M,
+ .width = 640,
+ .height = 480,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 4,
+ .width = 2624,
+ .height = 1944,
+ },
+ .crop = {
+ .left = 16,
+ .top = 6,
+ .width = 640,
+ .height = 480,
+ },
+ .htot = 1896,
+ .vblank_def = 600,
+ },
+ .csi2_timings = {
+ /* Feed the full valid pixel array to the ISP. */
+ .analog_crop = {
+ .left = OV5640_PIXEL_ARRAY_LEFT,
+ .top = OV5640_PIXEL_ARRAY_TOP,
+ .width = OV5640_PIXEL_ARRAY_WIDTH,
+ .height = OV5640_PIXEL_ARRAY_HEIGHT,
+ },
+ /* Maintain a minimum processing margin. */
+ .crop = {
+ .left = 2,
+ .top = 4,
+ .width = 640,
+ .height = 480,
+ },
+ .htot = 1600,
+ .vblank_def = 520,
+ },
+ .reg_data = ov5640_setting_low_res,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res),
+ .max_fps = OV5640_60_FPS,
+ .def_fps = OV5640_30_FPS
+ }, {
+ /* 720x480 */
+ .id = OV5640_MODE_NTSC_720_480,
+ .dn_mode = SUBSAMPLING,
+ .width = 720,
+ .height = 480,
+ .pixel_rate = OV5640_PIXEL_RATE_96M,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 4,
+ .width = 2624,
+ .height = 1944,
+ },
+ .crop = {
+ .left = 56,
+ .top = 60,
+ .width = 720,
+ .height = 480,
+ },
+ .htot = 1896,
+ .vblank_def = 504,
+ },
+ .csi2_timings = {
+ /* Feed the full valid pixel array to the ISP. */
+ .analog_crop = {
+ .left = OV5640_PIXEL_ARRAY_LEFT,
+ .top = OV5640_PIXEL_ARRAY_TOP,
+ .width = OV5640_PIXEL_ARRAY_WIDTH,
+ .height = OV5640_PIXEL_ARRAY_HEIGHT,
+ },
+ .crop = {
+ .left = 56,
+ .top = 60,
+ .width = 720,
+ .height = 480,
+ },
+ .htot = 1896,
+ .vblank_def = 1206,
+ },
+ .reg_data = ov5640_setting_low_res,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res),
+ .max_fps = OV5640_30_FPS,
+ .def_fps = OV5640_30_FPS
+ }, {
+ /* 720x576 */
+ .id = OV5640_MODE_PAL_720_576,
+ .dn_mode = SUBSAMPLING,
+ .width = 720,
+ .height = 576,
+ .pixel_rate = OV5640_PIXEL_RATE_96M,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 4,
+ .width = 2624,
+ .height = 1944,
+ },
+ .crop = {
+ .left = 56,
+ .top = 6,
+ .width = 720,
+ .height = 576,
+ },
+ .htot = 1896,
+ .vblank_def = 408,
+ },
+ .csi2_timings = {
+ /* Feed the full valid pixel array to the ISP. */
+ .analog_crop = {
+ .left = OV5640_PIXEL_ARRAY_LEFT,
+ .top = OV5640_PIXEL_ARRAY_TOP,
+ .width = OV5640_PIXEL_ARRAY_WIDTH,
+ .height = OV5640_PIXEL_ARRAY_HEIGHT,
+ },
+ .crop = {
+ .left = 56,
+ .top = 6,
+ .width = 720,
+ .height = 576,
+ },
+ .htot = 1896,
+ .vblank_def = 1110,
+ },
+ .reg_data = ov5640_setting_low_res,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res),
+ .max_fps = OV5640_30_FPS,
+ .def_fps = OV5640_30_FPS
+ }, {
+ /* 1024x768 */
+ .id = OV5640_MODE_XGA_1024_768,
+ .dn_mode = SUBSAMPLING,
+ .pixel_rate = OV5640_PIXEL_RATE_96M,
+ .width = 1024,
+ .height = 768,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 4,
+ .width = 2624,
+ .height = 1944,
+ },
+ .crop = {
+ .left = 16,
+ .top = 6,
+ .width = 1024,
+ .height = 768,
+ },
+ .htot = 1896,
+ .vblank_def = 312,
+ },
+ .csi2_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 4,
+ .width = OV5640_NATIVE_WIDTH,
+ .height = OV5640_PIXEL_ARRAY_HEIGHT,
+ },
+ .crop = {
+ .left = 16,
+ .top = 6,
+ .width = 1024,
+ .height = 768,
+ },
+ .htot = 1896,
+ .vblank_def = 918,
+ },
+ .reg_data = ov5640_setting_low_res,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_low_res),
+ .max_fps = OV5640_30_FPS,
+ .def_fps = OV5640_30_FPS
+ }, {
+ /* 1280x720 */
+ .id = OV5640_MODE_720P_1280_720,
+ .dn_mode = SUBSAMPLING,
+ .pixel_rate = OV5640_PIXEL_RATE_124M,
+ .width = 1280,
+ .height = 720,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 250,
+ .width = 2624,
+ .height = 1456,
+ },
+ .crop = {
+ .left = 16,
+ .top = 4,
+ .width = 1280,
+ .height = 720,
+ },
+ .htot = 1892,
+ .vblank_def = 20,
+ },
+ .csi2_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 250,
+ .width = 2624,
+ .height = 1456,
+ },
+ .crop = {
+ .left = 16,
+ .top = 4,
+ .width = 1280,
+ .height = 720,
+ },
+ .htot = 1600,
+ .vblank_def = 560,
+ },
+ .reg_data = ov5640_setting_720P_1280_720,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_720P_1280_720),
+ .max_fps = OV5640_30_FPS,
+ .def_fps = OV5640_30_FPS
+ }, {
+ /* 1920x1080 */
+ .id = OV5640_MODE_1080P_1920_1080,
+ .dn_mode = SCALING,
+ .pixel_rate = OV5640_PIXEL_RATE_148M,
+ .width = 1920,
+ .height = 1080,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 336,
+ .top = 434,
+ .width = 1952,
+ .height = 1088,
+ },
+ .crop = {
+ .left = 16,
+ .top = 4,
+ .width = 1920,
+ .height = 1080,
+ },
+ .htot = 2500,
+ .vblank_def = 40,
+ },
+ .csi2_timings = {
+ /* Crop the full valid pixel array in the center. */
+ .analog_crop = {
+ .left = 336,
+ .top = 434,
+ .width = 1952,
+ .height = 1088,
+ },
+ /* Maintain a larger processing margins. */
+ .crop = {
+ .left = 16,
+ .top = 4,
+ .width = 1920,
+ .height = 1080,
+ },
+ .htot = 2234,
+ .vblank_def = 24,
+ },
+ .reg_data = ov5640_setting_1080P_1920_1080,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
+ .max_fps = OV5640_30_FPS,
+ .def_fps = OV5640_30_FPS
+ }, {
+ /* 2592x1944 */
+ .id = OV5640_MODE_QSXGA_2592_1944,
+ .dn_mode = SCALING,
+ .pixel_rate = OV5640_PIXEL_RATE_168M,
+ .width = OV5640_PIXEL_ARRAY_WIDTH,
+ .height = OV5640_PIXEL_ARRAY_HEIGHT,
+ .dvp_timings = {
+ .analog_crop = {
+ .left = 0,
+ .top = 0,
+ .width = 2624,
+ .height = 1952,
+ },
+ .crop = {
+ .left = 16,
+ .top = 4,
+ .width = 2592,
+ .height = 1944,
+ },
+ .htot = 2844,
+ .vblank_def = 24,
+ },
+ .csi2_timings = {
+ /* Give more processing margin to full resolution. */
+ .analog_crop = {
+ .left = 0,
+ .top = 0,
+ .width = OV5640_NATIVE_WIDTH,
+ .height = 1952,
+ },
+ .crop = {
+ .left = 16,
+ .top = 4,
+ .width = 2592,
+ .height = 1944,
+ },
+ .htot = 2844,
+ .vblank_def = 24,
+ },
+ .reg_data = ov5640_setting_QSXGA_2592_1944,
+ .reg_data_size = ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
+ .max_fps = OV5640_15_FPS,
+ .def_fps = OV5640_15_FPS
+ },
};
-static const struct ov5640_mode_info
-ov5640_mode_data[OV5640_NUM_MODES] = {
- {OV5640_MODE_QQVGA_160_120, SUBSAMPLING,
- 160, 1896, 120, 984,
- ov5640_setting_QQVGA_160_120,
- ARRAY_SIZE(ov5640_setting_QQVGA_160_120),
- OV5640_30_FPS},
- {OV5640_MODE_QCIF_176_144, SUBSAMPLING,
- 176, 1896, 144, 984,
- ov5640_setting_QCIF_176_144,
- ARRAY_SIZE(ov5640_setting_QCIF_176_144),
- OV5640_30_FPS},
- {OV5640_MODE_QVGA_320_240, SUBSAMPLING,
- 320, 1896, 240, 984,
- ov5640_setting_QVGA_320_240,
- ARRAY_SIZE(ov5640_setting_QVGA_320_240),
- OV5640_30_FPS},
- {OV5640_MODE_VGA_640_480, SUBSAMPLING,
- 640, 1896, 480, 1080,
- ov5640_setting_VGA_640_480,
- ARRAY_SIZE(ov5640_setting_VGA_640_480),
- OV5640_60_FPS},
- {OV5640_MODE_NTSC_720_480, SUBSAMPLING,
- 720, 1896, 480, 984,
- ov5640_setting_NTSC_720_480,
- ARRAY_SIZE(ov5640_setting_NTSC_720_480),
- OV5640_30_FPS},
- {OV5640_MODE_PAL_720_576, SUBSAMPLING,
- 720, 1896, 576, 984,
- ov5640_setting_PAL_720_576,
- ARRAY_SIZE(ov5640_setting_PAL_720_576),
- OV5640_30_FPS},
- {OV5640_MODE_XGA_1024_768, SUBSAMPLING,
- 1024, 1896, 768, 1080,
- ov5640_setting_XGA_1024_768,
- ARRAY_SIZE(ov5640_setting_XGA_1024_768),
- OV5640_30_FPS},
- {OV5640_MODE_720P_1280_720, SUBSAMPLING,
- 1280, 1892, 720, 740,
- ov5640_setting_720P_1280_720,
- ARRAY_SIZE(ov5640_setting_720P_1280_720),
- OV5640_30_FPS},
- {OV5640_MODE_1080P_1920_1080, SCALING,
- 1920, 2500, 1080, 1120,
- ov5640_setting_1080P_1920_1080,
- ARRAY_SIZE(ov5640_setting_1080P_1920_1080),
- OV5640_30_FPS},
- {OV5640_MODE_QSXGA_2592_1944, SCALING,
- 2592, 2844, 1944, 1968,
- ov5640_setting_QSXGA_2592_1944,
- ARRAY_SIZE(ov5640_setting_QSXGA_2592_1944),
- OV5640_15_FPS},
-};
+static const struct ov5640_timings *
+ov5640_timings(const struct ov5640_dev *sensor,
+ const struct ov5640_mode_info *mode)
+{
+ if (ov5640_is_csi2(sensor))
+ return &mode->csi2_timings;
+
+ return &mode->dvp_timings;
+}
static int ov5640_init_slave_id(struct ov5640_dev *sensor)
{
@@ -797,20 +1309,10 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
* +-----+-----+
* +------------> PCLK
*
- * This is deviating from the datasheet at least for the register
- * 0x3108, since it's said here that the PCLK would be clocked from
- * the PLL.
- *
- * There seems to be also (unverified) constraints:
+ * There seems to be also constraints:
* - the PLL pre-divider output rate should be in the 4-27MHz range
* - the PLL multiplier output rate should be in the 500-1000MHz range
* - PCLK >= SCLK * 2 in YUV, >= SCLK in Raw or JPEG
- *
- * In the two latter cases, these constraints are met since our
- * factors are hardcoded. If we were to change that, we would need to
- * take this into account. The only varying parts are the PLL
- * multiplier and the system clock divider, which are shared between
- * all these clocks so won't cause any issue.
*/
/*
@@ -830,13 +1332,6 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
#define OV5640_SYSDIV_MAX 16
/*
- * Hardcode these values for scaler and non-scaler modes.
- * FIXME: to be re-calcualted for 1 data lanes setups
- */
-#define OV5640_MIPI_DIV_PCLK 2
-#define OV5640_MIPI_DIV_SCLK 1
-
-/*
* This is supposed to be ranging from 1 to 2, but the value is always
* set to 2 in the vendor kernels.
*/
@@ -945,70 +1440,83 @@ out:
/*
* ov5640_set_mipi_pclk() - Calculate the clock tree configuration values
* for the MIPI CSI-2 output.
- *
- * @rate: The requested bandwidth per lane in bytes per second.
- * 'Bandwidth Per Lane' is calculated as:
- * bpl = HTOT * VTOT * FPS * bpp / num_lanes;
- *
- * This function use the requested bandwidth to calculate:
- * - sample_rate = bpl / (bpp / num_lanes);
- * = bpl / (PLL_RDIV * BIT_DIV * PCLK_DIV * MIPI_DIV / num_lanes);
- *
- * - mipi_sclk = bpl / MIPI_DIV / 2; ( / 2 is for CSI-2 DDR)
- *
- * with these fixed parameters:
- * PLL_RDIV = 2;
- * BIT_DIVIDER = 2; (MIPI_BIT_MODE == 8 ? 2 : 2,5);
- * PCLK_DIV = 1;
- *
- * The MIPI clock generation differs for modes that use the scaler and modes
- * that do not. In case the scaler is in use, the MIPI_SCLK generates the MIPI
- * BIT CLk, and thus:
- *
- * - mipi_sclk = bpl / MIPI_DIV / 2;
- * MIPI_DIV = 1;
- *
- * For modes that do not go through the scaler, the MIPI BIT CLOCK is generated
- * from the pixel clock, and thus:
- *
- * - sample_rate = bpl / (bpp / num_lanes);
- * = bpl / (2 * 2 * 1 * MIPI_DIV / num_lanes);
- * = bpl / (4 * MIPI_DIV / num_lanes);
- * - MIPI_DIV = bpp / (4 * num_lanes);
- *
- * FIXME: this have been tested with 16bpp and 2 lanes setup only.
- * MIPI_DIV is fixed to value 2, but it -might- be changed according to the
- * above formula for setups with 1 lane or image formats with different bpp.
- *
- * FIXME: this deviates from the sensor manual documentation which is quite
- * thin on the MIPI clock tree generation part.
*/
-static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor,
- unsigned long rate)
+static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor)
{
- const struct ov5640_mode_info *mode = sensor->current_mode;
+ u8 bit_div, mipi_div, pclk_div, sclk_div, sclk2x_div, root_div;
u8 prediv, mult, sysdiv;
- u8 mipi_div;
+ unsigned long link_freq;
+ unsigned long sysclk;
+ u8 pclk_period;
+ u32 sample_rate;
+ u32 num_lanes;
int ret;
+ /* Use the link freq computed at ov5640_update_pixel_rate() time. */
+ link_freq = sensor->current_link_freq;
+
/*
- * 1280x720 is reported to use 'SUBSAMPLING' only,
- * but according to the sensor manual it goes through the
- * scaler before subsampling.
+ * - mipi_div - Additional divider for the MIPI lane clock.
+ *
+ * Higher link frequencies would make sysclk > 1GHz.
+ * Keep the sysclk low and do not divide in the MIPI domain.
*/
- if (mode->dn_mode == SCALING ||
- (mode->id == OV5640_MODE_720P_1280_720))
- mipi_div = OV5640_MIPI_DIV_SCLK;
+ if (link_freq > OV5640_LINK_RATE_MAX)
+ mipi_div = 1;
else
- mipi_div = OV5640_MIPI_DIV_PCLK;
+ mipi_div = 2;
- ov5640_calc_sys_clk(sensor, rate, &prediv, &mult, &sysdiv);
+ sysclk = link_freq * mipi_div;
+ ov5640_calc_sys_clk(sensor, sysclk, &prediv, &mult, &sysdiv);
- ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0,
- 0x0f, OV5640_PLL_CTRL0_MIPI_MODE_8BIT);
+ /*
+ * Adjust PLL parameters to maintain the MIPI_SCLK-to-PCLK ratio.
+ *
+ * - root_div = 2 (fixed)
+ * - bit_div : MIPI 8-bit = 2; MIPI 10-bit = 2.5
+ * - pclk_div = 1 (fixed)
+ * - p_div = (2 lanes ? mipi_div : 2 * mipi_div)
+ *
+ * This results in the following MIPI_SCLK depending on the number
+ * of lanes:
+ *
+ * - 2 lanes: MIPI_SCLK = (4 or 5) * PCLK
+ * - 1 lanes: MIPI_SCLK = (8 or 10) * PCLK
+ */
+ root_div = OV5640_PLL_CTRL3_PLL_ROOT_DIV_2;
+ bit_div = OV5640_PLL_CTRL0_MIPI_MODE_8BIT;
+ pclk_div = ilog2(OV5640_PCLK_ROOT_DIV);
- ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1,
- 0xff, sysdiv << 4 | mipi_div);
+ /*
+ * Scaler clock:
+ * - YUV: PCLK >= 2 * SCLK
+ * - RAW or JPEG: PCLK >= SCLK
+ * - sclk2x_div = sclk_div / 2
+ */
+ sclk_div = ilog2(OV5640_SCLK_ROOT_DIV);
+ sclk2x_div = ilog2(OV5640_SCLK2X_ROOT_DIV);
+
+ /*
+ * Set the pixel clock period expressed in ns with 1-bit decimal
+ * (0x01=0.5ns).
+ *
+ * The register is very briefly documented. In the OV5645 datasheet it
+ * is described as (2 * pclk period), and from testing it seems the
+ * actual definition is 2 * 8-bit sample period.
+ *
+ * 2 * sample_period = (mipi_clk * 2 * num_lanes / bpp) * (bpp / 8) / 2
+ */
+ num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
+ sample_rate = (link_freq * mipi_div * num_lanes * 2) / 16;
+ pclk_period = 2000000000UL / sample_rate;
+
+ /* Program the clock tree registers. */
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL0, 0x0f, bit_div);
+ if (ret)
+ return ret;
+
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0xff,
+ (sysdiv << 4) | mipi_div);
if (ret)
return ret;
@@ -1016,13 +1524,29 @@ static int ov5640_set_mipi_pclk(struct ov5640_dev *sensor,
if (ret)
return ret;
- ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3,
- 0x1f, OV5640_PLL_CTRL3_PLL_ROOT_DIV_2 | prediv);
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL3, 0x1f,
+ root_div | prediv);
if (ret)
return ret;
- return ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER,
- 0x30, OV5640_PLL_SYS_ROOT_DIVIDER_BYPASS);
+ ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
+ (pclk_div << 4) | (sclk2x_div << 2) | sclk_div);
+ if (ret)
+ return ret;
+
+ return ov5640_write_reg(sensor, OV5640_REG_PCLK_PERIOD, pclk_period);
+}
+
+static u32 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
+{
+ const struct ov5640_mode_info *mode = sensor->current_mode;
+ const struct ov5640_timings *timings = &mode->dvp_timings;
+ u32 rate;
+
+ rate = timings->htot * (timings->crop.height + timings->vblank_def);
+ rate *= ov5640_framerates[sensor->current_fr];
+
+ return rate;
}
static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
@@ -1042,11 +1566,16 @@ static unsigned long ov5640_calc_pclk(struct ov5640_dev *sensor,
return _rate / *pll_rdiv / *bit_div / *pclk_div;
}
-static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor, unsigned long rate)
+static int ov5640_set_dvp_pclk(struct ov5640_dev *sensor)
{
u8 prediv, mult, sysdiv, pll_rdiv, bit_div, pclk_div;
+ u32 rate;
int ret;
+ rate = ov5640_calc_pixel_rate(sensor);
+ rate *= ov5640_code_to_bpp(sensor, sensor->fmt.code);
+ rate /= sensor->ep.bus.parallel.bus_width;
+
ov5640_calc_pclk(sensor, rate, &prediv, &mult, &sysdiv, &pll_rdiv,
&bit_div, &pclk_div);
@@ -1098,17 +1627,20 @@ static int ov5640_set_jpeg_timings(struct ov5640_dev *sensor,
if (ret < 0)
return ret;
- ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->hact);
+ ret = ov5640_write_reg16(sensor, OV5640_REG_VFIFO_HSIZE, mode->width);
if (ret < 0)
return ret;
- return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->vact);
+ return ov5640_write_reg16(sensor, OV5640_REG_VFIFO_VSIZE, mode->height);
}
/* download ov5640 settings to sensor through i2c */
static int ov5640_set_timings(struct ov5640_dev *sensor,
const struct ov5640_mode_info *mode)
{
+ const struct ov5640_timings *timings;
+ const struct v4l2_rect *analog_crop;
+ const struct v4l2_rect *crop;
int ret;
if (sensor->fmt.code == MEDIA_BUS_FMT_JPEG_1X8) {
@@ -1117,32 +1649,68 @@ static int ov5640_set_timings(struct ov5640_dev *sensor,
return ret;
}
- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact);
+ timings = ov5640_timings(sensor, mode);
+ analog_crop = &timings->analog_crop;
+ crop = &timings->crop;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HS,
+ analog_crop->left);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VS,
+ analog_crop->top);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HW,
+ analog_crop->left + analog_crop->width - 1);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VH,
+ analog_crop->top + analog_crop->height - 1);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HOFFS, crop->left);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VOFFS, crop->top);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->width);
+ if (ret < 0)
+ return ret;
+
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->height);
if (ret < 0)
return ret;
- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact);
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, timings->htot);
if (ret < 0)
return ret;
- ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot);
+ ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
+ mode->height + timings->vblank_def);
if (ret < 0)
return ret;
- return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot);
+ return 0;
}
-static int ov5640_load_regs(struct ov5640_dev *sensor,
- const struct ov5640_mode_info *mode)
+static void ov5640_load_regs(struct ov5640_dev *sensor,
+ const struct reg_value *regs, unsigned int regnum)
{
- const struct reg_value *regs = mode->reg_data;
unsigned int i;
u32 delay_ms;
u16 reg_addr;
u8 mask, val;
int ret = 0;
- for (i = 0; i < mode->reg_data_size; ++i, ++regs) {
+ for (i = 0; i < regnum; ++i, ++regs) {
delay_ms = regs->delay_ms;
reg_addr = regs->reg_addr;
val = regs->val;
@@ -1151,7 +1719,7 @@ static int ov5640_load_regs(struct ov5640_dev *sensor,
/* remain in power down mode for DVP */
if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
- sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY)
+ !ov5640_is_csi2(sensor))
continue;
if (mask)
@@ -1164,8 +1732,6 @@ static int ov5640_load_regs(struct ov5640_dev *sensor,
if (delay_ms)
usleep_range(1000 * delay_ms, 1000 * delay_ms + 100);
}
-
- return ov5640_set_timings(sensor, mode);
}
static int ov5640_set_autoexposure(struct ov5640_dev *sensor, bool on)
@@ -1550,37 +2116,22 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
}
static const struct ov5640_mode_info *
-ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
- int width, int height, bool nearest)
+ov5640_find_mode(struct ov5640_dev *sensor, int width, int height, bool nearest)
{
const struct ov5640_mode_info *mode;
mode = v4l2_find_nearest_size(ov5640_mode_data,
ARRAY_SIZE(ov5640_mode_data),
- hact, vact,
- width, height);
+ width, height, width, height);
if (!mode ||
- (!nearest && (mode->hact != width || mode->vact != height)))
- return NULL;
-
- /* Check to see if the current mode exceeds the max frame rate */
- if (ov5640_framerates[fr] > ov5640_framerates[mode->max_fps])
+ (!nearest &&
+ (mode->width != width || mode->height != height)))
return NULL;
return mode;
}
-static u64 ov5640_calc_pixel_rate(struct ov5640_dev *sensor)
-{
- u64 rate;
-
- rate = sensor->current_mode->vtot * sensor->current_mode->htot;
- rate *= ov5640_framerates[sensor->current_fr];
-
- return rate;
-}
-
/*
* sensor changes between scaling and subsampling, go through
* exposure calculation
@@ -1628,7 +2179,8 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
return ret;
/* Write capture setting */
- ret = ov5640_load_regs(sensor, mode);
+ ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
+ ret = ov5640_set_timings(sensor, mode);
if (ret < 0)
return ret;
@@ -1752,7 +2304,8 @@ static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
return -EINVAL;
/* Write capture setting */
- return ov5640_load_regs(sensor, mode);
+ ov5640_load_regs(sensor, mode->reg_data, mode->reg_data_size);
+ return ov5640_set_timings(sensor, mode);
}
static int ov5640_set_mode(struct ov5640_dev *sensor)
@@ -1762,7 +2315,6 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
enum ov5640_downsize_mode dn_mode, orig_dn_mode;
bool auto_gain = sensor->ctrls.auto_gain->val == 1;
bool auto_exp = sensor->ctrls.auto_exp->val == V4L2_EXPOSURE_AUTO;
- unsigned long rate;
int ret;
dn_mode = mode->dn_mode;
@@ -1781,19 +2333,10 @@ static int ov5640_set_mode(struct ov5640_dev *sensor)
goto restore_auto_gain;
}
- /*
- * All the formats we support have 16 bits per pixel, seems to require
- * the same rate than YUV, so we can just use 16 bpp all the time.
- */
- rate = ov5640_calc_pixel_rate(sensor) * 16;
- if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
- rate = rate / sensor->ep.bus.mipi_csi2.num_data_lanes;
- ret = ov5640_set_mipi_pclk(sensor, rate);
- } else {
- rate = rate / sensor->ep.bus.parallel.bus_width;
- ret = ov5640_set_dvp_pclk(sensor, rate);
- }
-
+ if (ov5640_is_csi2(sensor))
+ ret = ov5640_set_mipi_pclk(sensor);
+ else
+ ret = ov5640_set_dvp_pclk(sensor);
if (ret < 0)
return 0;
@@ -1860,10 +2403,8 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor)
int ret;
/* first load the initial register values */
- ret = ov5640_load_regs(sensor, &ov5640_mode_init_data);
- if (ret < 0)
- return ret;
- sensor->last_mode = &ov5640_mode_init_data;
+ ov5640_load_regs(sensor, ov5640_init_setting,
+ ARRAY_SIZE(ov5640_init_setting));
ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
(ilog2(OV5640_SCLK2X_ROOT_DIV) << 2) |
@@ -2224,7 +2765,7 @@ static int ov5640_try_frame_interval(struct ov5640_dev *sensor,
fi->denominator = best_fps;
find_mode:
- mode = ov5640_find_mode(sensor, rate, width, height, false);
+ mode = ov5640_find_mode(sensor, width, height, false);
return mode ? rate : -EINVAL;
}
@@ -2260,25 +2801,34 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
{
struct ov5640_dev *sensor = to_ov5640_dev(sd);
const struct ov5640_mode_info *mode;
- int i;
+ const struct ov5640_pixfmt *pixfmt;
+ unsigned int bpp;
- mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
+ mode = ov5640_find_mode(sensor, fmt->width, fmt->height, true);
if (!mode)
return -EINVAL;
- fmt->width = mode->hact;
- fmt->height = mode->vact;
+
+ pixfmt = ov5640_code_to_pixfmt(sensor, fmt->code);
+ bpp = pixfmt->bpp;
+
+ /*
+ * Adjust mode according to bpp:
+ * - 8bpp modes work for resolution >= 1280x720
+ * - 24bpp modes work resolution < 1280x720
+ */
+ if (bpp == 8 && mode->width < 1280)
+ mode = &ov5640_mode_data[OV5640_MODE_720P_1280_720];
+ else if (bpp == 24 && mode->width > 1024)
+ mode = &ov5640_mode_data[OV5640_MODE_XGA_1024_768];
+
+ fmt->width = mode->width;
+ fmt->height = mode->height;
if (new_mode)
*new_mode = mode;
- for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++)
- if (ov5640_formats[i].code == fmt->code)
- break;
- if (i >= ARRAY_SIZE(ov5640_formats))
- i = 0;
-
- fmt->code = ov5640_formats[i].code;
- fmt->colorspace = ov5640_formats[i].colorspace;
+ fmt->code = pixfmt->code;
+ fmt->colorspace = pixfmt->colorspace;
fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
@@ -2286,6 +2836,107 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
return 0;
}
+static int ov5640_update_pixel_rate(struct ov5640_dev *sensor)
+{
+ const struct ov5640_mode_info *mode = sensor->current_mode;
+ enum ov5640_pixel_rate_id pixel_rate_id = mode->pixel_rate;
+ struct v4l2_mbus_framefmt *fmt = &sensor->fmt;
+ const struct ov5640_timings *timings;
+ s32 exposure_val, exposure_max;
+ unsigned int hblank;
+ unsigned int i = 0;
+ u32 pixel_rate;
+ s64 link_freq;
+ u32 num_lanes;
+ u32 vblank;
+ u32 bpp;
+
+ /*
+ * Update the pixel rate control value.
+ *
+ * For DVP mode, maintain the pixel rate calculation using fixed FPS.
+ */
+ if (!ov5640_is_csi2(sensor)) {
+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
+ ov5640_calc_pixel_rate(sensor));
+
+ return 0;
+ }
+
+ /*
+ * The MIPI CSI-2 link frequency should comply with the CSI-2
+ * specification and be lower than 1GHz.
+ *
+ * Start from the suggested pixel_rate for the current mode and
+ * progressively slow it down if it exceeds 1GHz.
+ */
+ num_lanes = sensor->ep.bus.mipi_csi2.num_data_lanes;
+ bpp = ov5640_code_to_bpp(sensor, fmt->code);
+ do {
+ pixel_rate = ov5640_pixel_rates[pixel_rate_id];
+ link_freq = pixel_rate * bpp / (2 * num_lanes);
+ } while (link_freq >= 1000000000U &&
+ ++pixel_rate_id < OV5640_NUM_PIXEL_RATES);
+
+ sensor->current_link_freq = link_freq;
+
+ /*
+ * Higher link rates require the clock tree to be programmed with
+ * 'mipi_div' = 1; this has the effect of halving the actual output
+ * pixel rate in the MIPI domain.
+ *
+ * Adjust the pixel rate and link frequency control value to report it
+ * correctly to userspace.
+ */
+ if (link_freq > OV5640_LINK_RATE_MAX) {
+ pixel_rate /= 2;
+ link_freq /= 2;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(ov5640_csi2_link_freqs); ++i) {
+ if (ov5640_csi2_link_freqs[i] == link_freq)
+ break;
+ }
+ WARN_ON(i == ARRAY_SIZE(ov5640_csi2_link_freqs));
+
+ __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate, pixel_rate);
+ __v4l2_ctrl_s_ctrl(sensor->ctrls.link_freq, i);
+
+ timings = ov5640_timings(sensor, mode);
+ hblank = timings->htot - mode->width;
+ __v4l2_ctrl_modify_range(sensor->ctrls.hblank,
+ hblank, hblank, 1, hblank);
+
+ vblank = timings->vblank_def;
+
+ if (sensor->current_fr != mode->def_fps) {
+ /*
+ * Compute the vertical blanking according to the framerate
+ * configured with s_frame_interval.
+ */
+ int fie_num = sensor->frame_interval.numerator;
+ int fie_denom = sensor->frame_interval.denominator;
+
+ vblank = ((fie_num * pixel_rate / fie_denom) / timings->htot) -
+ mode->height;
+ }
+
+ __v4l2_ctrl_modify_range(sensor->ctrls.vblank, OV5640_MIN_VBLANK,
+ OV5640_MAX_VTS - mode->height, 1, vblank);
+ __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank, vblank);
+
+ exposure_max = timings->crop.height + vblank - 4;
+ exposure_val = clamp_t(s32, sensor->ctrls.exposure->val,
+ sensor->ctrls.exposure->minimum,
+ exposure_max);
+
+ __v4l2_ctrl_modify_range(sensor->ctrls.exposure,
+ sensor->ctrls.exposure->minimum,
+ exposure_max, 1, exposure_val);
+
+ return 0;
+}
+
static int ov5640_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
@@ -2316,6 +2967,7 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
}
if (new_mode != sensor->current_mode) {
+ sensor->current_fr = new_mode->def_fps;
sensor->current_mode = new_mode;
sensor->pending_mode_change = true;
}
@@ -2325,80 +2977,70 @@ static int ov5640_set_fmt(struct v4l2_subdev *sd,
/* update format even if code is unchanged, resolution might change */
sensor->fmt = *mbus_fmt;
- __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
- ov5640_calc_pixel_rate(sensor));
+ ov5640_update_pixel_rate(sensor);
+
out:
mutex_unlock(&sensor->lock);
return ret;
}
+static int ov5640_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
+ const struct ov5640_mode_info *mode = sensor->current_mode;
+ const struct ov5640_timings *timings;
+
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ mutex_lock(&sensor->lock);
+ timings = ov5640_timings(sensor, mode);
+ sel->r = timings->analog_crop;
+ mutex_unlock(&sensor->lock);
+
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = OV5640_NATIVE_WIDTH;
+ sel->r.height = OV5640_NATIVE_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ sel->r.top = OV5640_PIXEL_ARRAY_TOP;
+ sel->r.left = OV5640_PIXEL_ARRAY_LEFT;
+ sel->r.width = OV5640_PIXEL_ARRAY_WIDTH;
+ sel->r.height = OV5640_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static int ov5640_set_framefmt(struct ov5640_dev *sensor,
struct v4l2_mbus_framefmt *format)
{
+ bool is_jpeg = format->code == MEDIA_BUS_FMT_JPEG_1X8;
+ const struct ov5640_pixfmt *pixfmt;
int ret = 0;
- bool is_jpeg = false;
- u8 fmt, mux;
- switch (format->code) {
- case MEDIA_BUS_FMT_UYVY8_1X16:
- case MEDIA_BUS_FMT_UYVY8_2X8:
- /* YUV422, UYVY */
- fmt = 0x3f;
- mux = OV5640_FMT_MUX_YUV422;
- break;
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_YUYV8_2X8:
- /* YUV422, YUYV */
- fmt = 0x30;
- mux = OV5640_FMT_MUX_YUV422;
- break;
- case MEDIA_BUS_FMT_RGB565_2X8_LE:
- /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */
- fmt = 0x6F;
- mux = OV5640_FMT_MUX_RGB;
- break;
- case MEDIA_BUS_FMT_RGB565_2X8_BE:
- /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */
- fmt = 0x61;
- mux = OV5640_FMT_MUX_RGB;
- break;
- case MEDIA_BUS_FMT_JPEG_1X8:
- /* YUV422, YUYV */
- fmt = 0x30;
- mux = OV5640_FMT_MUX_YUV422;
- is_jpeg = true;
- break;
- case MEDIA_BUS_FMT_SBGGR8_1X8:
- /* Raw, BGBG... / GRGR... */
- fmt = 0x00;
- mux = OV5640_FMT_MUX_RAW_DPC;
- break;
- case MEDIA_BUS_FMT_SGBRG8_1X8:
- /* Raw bayer, GBGB... / RGRG... */
- fmt = 0x01;
- mux = OV5640_FMT_MUX_RAW_DPC;
- break;
- case MEDIA_BUS_FMT_SGRBG8_1X8:
- /* Raw bayer, GRGR... / BGBG... */
- fmt = 0x02;
- mux = OV5640_FMT_MUX_RAW_DPC;
- break;
- case MEDIA_BUS_FMT_SRGGB8_1X8:
- /* Raw bayer, RGRG... / GBGB... */
- fmt = 0x03;
- mux = OV5640_FMT_MUX_RAW_DPC;
- break;
- default:
- return -EINVAL;
- }
+ pixfmt = ov5640_code_to_pixfmt(sensor, format->code);
/* FORMAT CONTROL00: YUV and RGB formatting */
- ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, fmt);
+ ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00,
+ pixfmt->ctrl00);
if (ret)
return ret;
/* FORMAT MUX CONTROL: ISP YUV or RGB */
- ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, mux);
+ ret = ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL,
+ pixfmt->mux);
if (ret)
return ret;
@@ -2655,6 +3297,15 @@ static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
(BIT(2) | BIT(1)) : 0);
}
+static int ov5640_set_ctrl_vblank(struct ov5640_dev *sensor, int value)
+{
+ const struct ov5640_mode_info *mode = sensor->current_mode;
+
+ /* Update the VTOT timing register value. */
+ return ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS,
+ mode->height + value);
+}
+
static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
@@ -2685,10 +3336,25 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
struct ov5640_dev *sensor = to_ov5640_dev(sd);
+ const struct ov5640_mode_info *mode = sensor->current_mode;
+ const struct ov5640_timings *timings;
+ unsigned int exp_max;
int ret;
/* v4l2_ctrl_lock() locks our own mutex */
+ switch (ctrl->id) {
+ case V4L2_CID_VBLANK:
+ /* Update the exposure range to the newly programmed vblank. */
+ timings = ov5640_timings(sensor, mode);
+ exp_max = mode->height + ctrl->val - 4;
+ __v4l2_ctrl_modify_range(sensor->ctrls.exposure,
+ sensor->ctrls.exposure->minimum,
+ exp_max, sensor->ctrls.exposure->step,
+ timings->vblank_def);
+ break;
+ }
+
/*
* If the device is not powered up by the host driver do
* not apply any controls to H/W at this time. Instead
@@ -2728,6 +3394,9 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_VFLIP:
ret = ov5640_set_ctrl_vflip(sensor, ctrl->val);
break;
+ case V4L2_CID_VBLANK:
+ ret = ov5640_set_ctrl_vblank(sensor, ctrl->val);
+ break;
default:
ret = -EINVAL;
break;
@@ -2743,9 +3412,14 @@ static const struct v4l2_ctrl_ops ov5640_ctrl_ops = {
static int ov5640_init_controls(struct ov5640_dev *sensor)
{
+ const struct ov5640_mode_info *mode = sensor->current_mode;
const struct v4l2_ctrl_ops *ops = &ov5640_ctrl_ops;
struct ov5640_ctrls *ctrls = &sensor->ctrls;
struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+ struct v4l2_fwnode_device_properties props;
+ const struct ov5640_timings *timings;
+ unsigned int max_vblank;
+ unsigned int hblank;
int ret;
v4l2_ctrl_handler_init(hdl, 32);
@@ -2755,8 +3429,25 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
/* Clock related controls */
ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_PIXEL_RATE,
- 0, INT_MAX, 1,
- ov5640_calc_pixel_rate(sensor));
+ ov5640_pixel_rates[OV5640_NUM_PIXEL_RATES - 1],
+ ov5640_pixel_rates[0], 1,
+ ov5640_pixel_rates[mode->pixel_rate]);
+
+ ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(ov5640_csi2_link_freqs) - 1,
+ OV5640_DEFAULT_LINK_FREQ,
+ ov5640_csi2_link_freqs);
+
+ timings = ov5640_timings(sensor, mode);
+ hblank = timings->htot - mode->width;
+ ctrls->hblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HBLANK, hblank,
+ hblank, 1, hblank);
+
+ max_vblank = OV5640_MAX_VTS - mode->height;
+ ctrls->vblank = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VBLANK,
+ OV5640_MIN_VBLANK, max_vblank,
+ 1, timings->vblank_def);
/* Auto/manual white balance */
ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,
@@ -2805,7 +3496,20 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
goto free_ctrls;
}
+ ret = v4l2_fwnode_device_parse(&sensor->i2c_client->dev, &props);
+ if (ret)
+ goto free_ctrls;
+
+ if (props.rotation == 180)
+ sensor->upside_down = true;
+
+ ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);
+ if (ret)
+ goto free_ctrls;
+
ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ ctrls->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
@@ -2825,16 +3529,29 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
+ u32 bpp = ov5640_code_to_bpp(sensor, fse->code);
+ unsigned int index = fse->index;
+
if (fse->pad != 0)
return -EINVAL;
- if (fse->index >= OV5640_NUM_MODES)
+ if (!bpp)
+ return -EINVAL;
+
+ /* Only low-resolution modes are supported for 24bpp formats. */
+ if (bpp == 24 && index >= OV5640_MODE_720P_1280_720)
+ return -EINVAL;
+
+ /* FIXME: Low resolution modes don't work in 8bpp formats. */
+ if (bpp == 8)
+ index += OV5640_MODE_720P_1280_720;
+
+ if (index >= OV5640_NUM_MODES)
return -EINVAL;
- fse->min_width =
- ov5640_mode_data[fse->index].hact;
+ fse->min_width = ov5640_mode_data[index].width;
fse->max_width = fse->min_width;
- fse->min_height =
- ov5640_mode_data[fse->index].vact;
+ fse->min_height = ov5640_mode_data[index].height;
fse->max_height = fse->min_height;
return 0;
@@ -2898,20 +3615,25 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
mode = sensor->current_mode;
frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
- mode->hact, mode->vact);
+ mode->width,
+ mode->height);
if (frame_rate < 0) {
/* Always return a valid frame interval value */
fi->interval = sensor->frame_interval;
goto out;
}
- mode = ov5640_find_mode(sensor, frame_rate, mode->hact,
- mode->vact, true);
+ mode = ov5640_find_mode(sensor, mode->width, mode->height, true);
if (!mode) {
ret = -EINVAL;
goto out;
}
+ if (ov5640_framerates[frame_rate] > ov5640_framerates[mode->max_fps]) {
+ ret = -EINVAL;
+ goto out;
+ }
+
if (mode != sensor->current_mode ||
frame_rate != sensor->current_fr) {
sensor->current_fr = frame_rate;
@@ -2919,8 +3641,7 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
sensor->current_mode = mode;
sensor->pending_mode_change = true;
- __v4l2_ctrl_s_ctrl_int64(sensor->ctrls.pixel_rate,
- ov5640_calc_pixel_rate(sensor));
+ ov5640_update_pixel_rate(sensor);
}
out:
mutex_unlock(&sensor->lock);
@@ -2931,12 +3652,23 @@ static int ov5640_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- if (code->pad != 0)
- return -EINVAL;
- if (code->index >= ARRAY_SIZE(ov5640_formats))
+ struct ov5640_dev *sensor = to_ov5640_dev(sd);
+ const struct ov5640_pixfmt *formats;
+ unsigned int num_formats;
+
+ if (ov5640_is_csi2(sensor)) {
+ formats = ov5640_csi2_formats;
+ num_formats = ARRAY_SIZE(ov5640_csi2_formats) - 1;
+ } else {
+ formats = ov5640_dvp_formats;
+ num_formats = ARRAY_SIZE(ov5640_dvp_formats) - 1;
+ }
+
+ if (code->index >= num_formats)
return -EINVAL;
- code->code = ov5640_formats[code->index].code;
+ code->code = formats[code->index].code;
+
return 0;
}
@@ -2961,7 +3693,7 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
sensor->pending_fmt_change = false;
}
- if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
+ if (ov5640_is_csi2(sensor))
ret = ov5640_set_stream_mipi(sensor, enable);
else
ret = ov5640_set_stream_dvp(sensor, enable);
@@ -2974,6 +3706,23 @@ out:
return ret;
}
+static int ov5640_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *fmt =
+ v4l2_subdev_get_try_format(sd, state, 0);
+ struct v4l2_rect *crop = v4l2_subdev_get_try_crop(sd, state, 0);
+
+ *fmt = ov5640_default_fmt;
+
+ crop->left = OV5640_PIXEL_ARRAY_LEFT;
+ crop->top = OV5640_PIXEL_ARRAY_TOP;
+ crop->width = OV5640_PIXEL_ARRAY_WIDTH;
+ crop->height = OV5640_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+}
+
static const struct v4l2_subdev_core_ops ov5640_core_ops = {
.s_power = ov5640_s_power,
.log_status = v4l2_ctrl_subdev_log_status,
@@ -2988,9 +3737,11 @@ static const struct v4l2_subdev_video_ops ov5640_video_ops = {
};
static const struct v4l2_subdev_pad_ops ov5640_pad_ops = {
+ .init_cfg = ov5640_init_cfg,
.enum_mbus_code = ov5640_enum_mbus_code,
.get_fmt = ov5640_get_fmt,
.set_fmt = ov5640_set_fmt,
+ .get_selection = ov5640_get_selection,
.enum_frame_size = ov5640_enum_frame_size,
.enum_frame_interval = ov5640_enum_frame_interval,
};
@@ -3046,8 +3797,6 @@ static int ov5640_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct fwnode_handle *endpoint;
struct ov5640_dev *sensor;
- struct v4l2_mbus_framefmt *fmt;
- u32 rotation;
int ret;
sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
@@ -3060,40 +3809,17 @@ static int ov5640_probe(struct i2c_client *client)
* default init sequence initialize sensor to
* YUV422 UYVY VGA@30fps
*/
- fmt = &sensor->fmt;
- fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
- fmt->colorspace = V4L2_COLORSPACE_SRGB;
- fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
- fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
- fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(fmt->colorspace);
- fmt->width = 640;
- fmt->height = 480;
- fmt->field = V4L2_FIELD_NONE;
+ sensor->fmt = ov5640_default_fmt;
sensor->frame_interval.numerator = 1;
sensor->frame_interval.denominator = ov5640_framerates[OV5640_30_FPS];
sensor->current_fr = OV5640_30_FPS;
sensor->current_mode =
&ov5640_mode_data[OV5640_MODE_VGA_640_480];
sensor->last_mode = sensor->current_mode;
+ sensor->current_link_freq = OV5640_DEFAULT_LINK_FREQ;
sensor->ae_target = 52;
- /* optional indication of physical rotation of sensor */
- ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
- &rotation);
- if (!ret) {
- switch (rotation) {
- case 180:
- sensor->upside_down = true;
- fallthrough;
- case 0:
- break;
- default:
- dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
- rotation);
- }
- }
-
endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
NULL);
if (!endpoint) {
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 117ff5403312..82a9b2de7735 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -127,11 +127,16 @@
#define OV5693_LINK_FREQ_419_2MHZ 419200000
#define OV5693_PIXEL_RATE 167680000
-/* Miscellaneous */
-#define OV5693_NUM_SUPPLIES 2
-
#define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd)
+static const char * const ov5693_supply_names[] = {
+ "avdd", /* Analog power */
+ "dovdd", /* Digital I/O power */
+ "dvdd", /* Digital circuit power */
+};
+
+#define OV5693_NUM_SUPPLIES ARRAY_SIZE(ov5693_supply_names)
+
struct ov5693_reg {
u32 reg;
u8 val;
@@ -152,7 +157,7 @@ struct ov5693_device {
struct gpio_desc *reset;
struct gpio_desc *powerdown;
struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES];
- struct clk *clk;
+ struct clk *xvclk;
struct ov5693_mode {
struct v4l2_rect crop;
@@ -352,11 +357,6 @@ static const s64 link_freq_menu_items[] = {
OV5693_LINK_FREQ_419_2MHZ
};
-static const char * const ov5693_supply_names[] = {
- "avdd",
- "dovdd",
-};
-
static const char * const ov5693_test_pattern_menu[] = {
"Disabled",
"Random Data",
@@ -794,7 +794,7 @@ static void ov5693_sensor_powerdown(struct ov5693_device *ov5693)
regulator_bulk_disable(OV5693_NUM_SUPPLIES, ov5693->supplies);
- clk_disable_unprepare(ov5693->clk);
+ clk_disable_unprepare(ov5693->xvclk);
}
static int ov5693_sensor_powerup(struct ov5693_device *ov5693)
@@ -804,7 +804,7 @@ static int ov5693_sensor_powerup(struct ov5693_device *ov5693)
gpiod_set_value_cansleep(ov5693->reset, 1);
gpiod_set_value_cansleep(ov5693->powerdown, 1);
- ret = clk_prepare_enable(ov5693->clk);
+ ret = clk_prepare_enable(ov5693->xvclk);
if (ret) {
dev_err(ov5693->dev, "Failed to enable clk\n");
goto fail_power;
@@ -1390,7 +1390,7 @@ out_free_bus_cfg:
static int ov5693_probe(struct i2c_client *client)
{
struct ov5693_device *ov5693;
- u32 clk_rate;
+ u32 xvclk_rate;
int ret = 0;
ov5693 = devm_kzalloc(&client->dev, sizeof(*ov5693), GFP_KERNEL);
@@ -1408,16 +1408,28 @@ static int ov5693_probe(struct i2c_client *client)
v4l2_i2c_subdev_init(&ov5693->sd, client, &ov5693_ops);
- ov5693->clk = devm_clk_get(&client->dev, "xvclk");
- if (IS_ERR(ov5693->clk)) {
- dev_err(&client->dev, "Error getting clock\n");
- return PTR_ERR(ov5693->clk);
+ ov5693->xvclk = devm_clk_get_optional(&client->dev, "xvclk");
+ if (IS_ERR(ov5693->xvclk))
+ return dev_err_probe(&client->dev, PTR_ERR(ov5693->xvclk),
+ "failed to get xvclk: %ld\n",
+ PTR_ERR(ov5693->xvclk));
+
+ if (ov5693->xvclk) {
+ xvclk_rate = clk_get_rate(ov5693->xvclk);
+ } else {
+ ret = fwnode_property_read_u32(dev_fwnode(&client->dev),
+ "clock-frequency",
+ &xvclk_rate);
+
+ if (ret) {
+ dev_err(&client->dev, "can't get clock frequency");
+ return ret;
+ }
}
- clk_rate = clk_get_rate(ov5693->clk);
- if (clk_rate != OV5693_XVCLK_FREQ)
+ if (xvclk_rate != OV5693_XVCLK_FREQ)
dev_warn(&client->dev, "Found clk freq %u, expected %u\n",
- clk_rate, OV5693_XVCLK_FREQ);
+ xvclk_rate, OV5693_XVCLK_FREQ);
ret = ov5693_configure_gpios(ov5693);
if (ret)
@@ -1521,10 +1533,17 @@ static const struct acpi_device_id ov5693_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match);
+static const struct of_device_id ov5693_of_match[] = {
+ { .compatible = "ovti,ov5693", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov5693_of_match);
+
static struct i2c_driver ov5693_driver = {
.driver = {
.name = "ov5693",
.acpi_match_table = ov5693_acpi_match,
+ .of_match_table = ov5693_of_match,
.pm = &ov5693_pm_ops,
},
.probe_new = ov5693_probe,
diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c
index 0e7be15bc20a..1bd797c7926b 100644
--- a/drivers/media/i2c/ov7251.c
+++ b/drivers/media/i2c/ov7251.c
@@ -934,6 +934,8 @@ static int ov7251_set_power_on(struct device *dev)
ARRAY_SIZE(ov7251_global_init_setting));
if (ret < 0) {
dev_err(ov7251->dev, "error during global init\n");
+ gpiod_set_value_cansleep(ov7251->enable_gpio, 0);
+ clk_disable_unprepare(ov7251->xclk);
ov7251_regulators_disable(ov7251);
return ret;
}
@@ -1340,7 +1342,7 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable)
if (enable) {
ret = pm_runtime_get_sync(ov7251->dev);
if (ret < 0)
- goto unlock_out;
+ goto err_power_down;
ret = ov7251_pll_configure(ov7251);
if (ret) {
@@ -1372,12 +1374,11 @@ static int ov7251_s_stream(struct v4l2_subdev *subdev, int enable)
pm_runtime_put(ov7251->dev);
}
-unlock_out:
mutex_unlock(&ov7251->lock);
return ret;
err_power_down:
- pm_runtime_put_noidle(ov7251->dev);
+ pm_runtime_put(ov7251->dev);
mutex_unlock(&ov7251->lock);
return ret;
}
diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c
index ef976d085d72..16cc547976dd 100644
--- a/drivers/media/i2c/st-mipid02.c
+++ b/drivers/media/i2c/st-mipid02.c
@@ -50,6 +50,7 @@
/* Bits definition for MIPID02_MODE_REG2 */
#define MODE_HSYNC_ACTIVE_HIGH BIT(1)
#define MODE_VSYNC_ACTIVE_HIGH BIT(2)
+#define MODE_PCLK_SAMPLE_RISING BIT(3)
/* Bits definition for MIPID02_DATA_SELECTION_CTRL */
#define SELECTION_MANUAL_DATA BIT(2)
#define SELECTION_MANUAL_WIDTH BIT(3)
@@ -61,9 +62,12 @@ static const u32 mipid02_supported_fmt_codes[] = {
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_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24,
+ MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16,
+ MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16,
+ MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR888_1X24,
MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE,
- MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8,
+ MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8,
MEDIA_BUS_FMT_JPEG_1X8
};
@@ -130,9 +134,15 @@ static int bpp_from_code(__u32 code)
case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SRGGB12_1X12:
return 12;
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YVYU8_1X16:
case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_VYUY8_1X16:
+ case MEDIA_BUS_FMT_RGB565_1X16:
case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
case MEDIA_BUS_FMT_RGB565_2X8_LE:
case MEDIA_BUS_FMT_RGB565_2X8_BE:
return 16;
@@ -161,12 +171,18 @@ static u8 data_type_from_code(__u32 code)
case MEDIA_BUS_FMT_SGRBG12_1X12:
case MEDIA_BUS_FMT_SRGGB12_1X12:
return 0x2c;
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YVYU8_1X16:
case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_VYUY8_1X16:
case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
return 0x1e;
case MEDIA_BUS_FMT_BGR888_1X24:
return 0x24;
+ case MEDIA_BUS_FMT_RGB565_1X16:
case MEDIA_BUS_FMT_RGB565_2X8_LE:
case MEDIA_BUS_FMT_RGB565_2X8_BE:
return 0x22;
@@ -201,8 +217,16 @@ static __u32 get_fmt_code(__u32 code)
static __u32 serial_to_parallel_code(__u32 serial)
{
+ if (serial == MEDIA_BUS_FMT_RGB565_1X16)
+ return MEDIA_BUS_FMT_RGB565_2X8_LE;
+ if (serial == MEDIA_BUS_FMT_YUYV8_1X16)
+ return MEDIA_BUS_FMT_YUYV8_2X8;
+ if (serial == MEDIA_BUS_FMT_YVYU8_1X16)
+ return MEDIA_BUS_FMT_YVYU8_2X8;
if (serial == MEDIA_BUS_FMT_UYVY8_1X16)
return MEDIA_BUS_FMT_UYVY8_2X8;
+ if (serial == MEDIA_BUS_FMT_VYUY8_1X16)
+ return MEDIA_BUS_FMT_VYUY8_2X8;
if (serial == MEDIA_BUS_FMT_BGR888_1X24)
return MEDIA_BUS_FMT_BGR888_3X8;
@@ -494,6 +518,8 @@ static int mipid02_configure_from_tx(struct mipid02_dev *bridge)
bridge->r.mode_reg2 |= MODE_HSYNC_ACTIVE_HIGH;
if (ep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
bridge->r.mode_reg2 |= MODE_VSYNC_ACTIVE_HIGH;
+ if (ep->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ bridge->r.mode_reg2 |= MODE_PCLK_SAMPLE_RISING;
return 0;
}
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
index 965c7afec57d..f66ac14cffad 100644
--- a/drivers/media/i2c/tda1997x.c
+++ b/drivers/media/i2c/tda1997x.c
@@ -2797,6 +2797,7 @@ err_free_mutex:
cancel_delayed_work(&state->delayed_work_enable_hpd);
mutex_destroy(&state->page_lock);
mutex_destroy(&state->lock);
+ tda1997x_set_power(state, 0);
err_free_state:
kfree(state);
dev_err(&client->dev, "%s failed: %d\n", __func__, ret);
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 65472438444b..93a980c4e899 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -1285,7 +1285,7 @@ static int tvp5150_disable_all_input_links(struct tvp5150 *decoder)
int err;
for (i = 0; i < TVP5150_NUM_PADS - 1; i++) {
- connector_pad = media_entity_remote_pad(&decoder->pads[i]);
+ connector_pad = media_pad_remote_pad_first(&decoder->pads[i]);
if (!connector_pad)
continue;
diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
index 11f5207f73aa..afd1bd7ff7b6 100644
--- a/drivers/media/mc/mc-entity.c
+++ b/drivers/media/mc/mc-entity.c
@@ -9,6 +9,7 @@
*/
#include <linux/bitmap.h>
+#include <linux/list.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <media/media-entity.h>
@@ -449,7 +450,7 @@ __must_check int __media_pipeline_start(struct media_entity *entity,
bitmap_zero(active, entity->num_pads);
bitmap_fill(has_no_links, entity->num_pads);
- list_for_each_entry(link, &entity->links, list) {
+ for_each_media_entity_data_link(entity, link) {
struct media_pad *pad = link->sink->entity == entity
? link->sink : link->source;
@@ -888,7 +889,7 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink)
{
struct media_link *link;
- list_for_each_entry(link, &source->entity->links, list) {
+ for_each_media_entity_data_link(source->entity, link) {
if (link->source->entity == source->entity &&
link->source->index == source->index &&
link->sink->entity == sink->entity &&
@@ -900,11 +901,11 @@ media_entity_find_link(struct media_pad *source, struct media_pad *sink)
}
EXPORT_SYMBOL_GPL(media_entity_find_link);
-struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
+struct media_pad *media_pad_remote_pad_first(const struct media_pad *pad)
{
struct media_link *link;
- list_for_each_entry(link, &pad->entity->links, list) {
+ for_each_media_entity_data_link(pad->entity, link) {
if (!(link->flags & MEDIA_LNK_FL_ENABLED))
continue;
@@ -918,7 +919,77 @@ struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
return NULL;
}
-EXPORT_SYMBOL_GPL(media_entity_remote_pad);
+EXPORT_SYMBOL_GPL(media_pad_remote_pad_first);
+
+struct media_pad *
+media_entity_remote_pad_unique(const struct media_entity *entity,
+ unsigned int type)
+{
+ struct media_pad *pad = NULL;
+ struct media_link *link;
+
+ list_for_each_entry(link, &entity->links, list) {
+ struct media_pad *local_pad;
+ struct media_pad *remote_pad;
+
+ if (((link->flags & MEDIA_LNK_FL_LINK_TYPE) !=
+ MEDIA_LNK_FL_DATA_LINK) ||
+ !(link->flags & MEDIA_LNK_FL_ENABLED))
+ continue;
+
+ if (type == MEDIA_PAD_FL_SOURCE) {
+ local_pad = link->sink;
+ remote_pad = link->source;
+ } else {
+ local_pad = link->source;
+ remote_pad = link->sink;
+ }
+
+ if (local_pad->entity == entity) {
+ if (pad)
+ return ERR_PTR(-ENOTUNIQ);
+
+ pad = remote_pad;
+ }
+ }
+
+ if (!pad)
+ return ERR_PTR(-ENOLINK);
+
+ return pad;
+}
+EXPORT_SYMBOL_GPL(media_entity_remote_pad_unique);
+
+struct media_pad *media_pad_remote_pad_unique(const struct media_pad *pad)
+{
+ struct media_pad *found_pad = NULL;
+ struct media_link *link;
+
+ list_for_each_entry(link, &pad->entity->links, list) {
+ struct media_pad *remote_pad;
+
+ if (!(link->flags & MEDIA_LNK_FL_ENABLED))
+ continue;
+
+ if (link->sink == pad)
+ remote_pad = link->source;
+ else if (link->source == pad)
+ remote_pad = link->sink;
+ else
+ continue;
+
+ if (found_pad)
+ return ERR_PTR(-ENOTUNIQ);
+
+ found_pad = remote_pad;
+ }
+
+ if (!found_pad)
+ return ERR_PTR(-ENOLINK);
+
+ return found_pad;
+}
+EXPORT_SYMBOL_GPL(media_pad_remote_pad_unique);
static void media_interface_init(struct media_device *mdev,
struct media_interface *intf,
@@ -1051,3 +1122,18 @@ struct media_link *media_create_ancillary_link(struct media_entity *primary,
return link;
}
EXPORT_SYMBOL_GPL(media_create_ancillary_link);
+
+struct media_link *__media_entity_next_link(struct media_entity *entity,
+ struct media_link *link,
+ unsigned long link_type)
+{
+ link = link ? list_next_entry(link, list)
+ : list_first_entry(&entity->links, typeof(*link), list);
+
+ list_for_each_entry_from(link, &entity->links, list)
+ if ((link->flags & MEDIA_LNK_FL_LINK_TYPE) == link_type)
+ return link;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(__media_entity_next_link);
diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
index 76e5a504df8c..d3358643fb7d 100644
--- a/drivers/media/pci/cx18/cx18-av-core.c
+++ b/drivers/media/pci/cx18/cx18-av-core.c
@@ -180,7 +180,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
*/
cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000);
- /* Setup the Video and and Aux/Audio PLLs */
+ /* Setup the Video and Aux/Audio PLLs */
cx18_av_init(cx);
/* set video to auto-detect */
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index 89d4d5a3ba34..52be42f9a7fa 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -618,12 +618,24 @@ EXPORT_SYMBOL(cx88_reset);
static inline unsigned int norm_swidth(v4l2_std_id norm)
{
- return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
+ if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL_M))
+ return 754;
+
+ if (norm & V4L2_STD_PAL_Nc)
+ return 745;
+
+ return 922;
}
static inline unsigned int norm_hdelay(v4l2_std_id norm)
{
- return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
+ if (norm & (V4L2_STD_NTSC | V4L2_STD_PAL_M))
+ return 135;
+
+ if (norm & V4L2_STD_PAL_Nc)
+ return 149;
+
+ return 186;
}
static inline unsigned int norm_vdelay(v4l2_std_id norm)
@@ -636,7 +648,7 @@ static inline unsigned int norm_fsc8(v4l2_std_id norm)
if (norm & V4L2_STD_PAL_M)
return 28604892; // 3.575611 MHz
- if (norm & (V4L2_STD_PAL_Nc))
+ if (norm & V4L2_STD_PAL_Nc)
return 28656448; // 3.582056 MHz
if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
@@ -841,8 +853,8 @@ static int set_tvaudio(struct cx88_core *core)
} else if (V4L2_STD_SECAM_DK & norm) {
core->tvaudio = WW_DK;
- } else if ((V4L2_STD_NTSC_M & norm) ||
- (V4L2_STD_PAL_M & norm)) {
+ } else if ((V4L2_STD_NTSC_M | V4L2_STD_PAL_M | V4L2_STD_PAL_Nc) &
+ norm) {
core->tvaudio = WW_BTSC;
} else if (V4L2_STD_NTSC_M_JP & norm) {
diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c
index 377991095aba..ee20813c33ff 100644
--- a/drivers/media/pci/ddbridge/ddbridge-ci.c
+++ b/drivers/media/pci/ddbridge/ddbridge-ci.c
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include "ddbridge.h"
diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.h b/drivers/media/pci/ddbridge/ddbridge-ci.h
index cc98656af349..41cd97e52aa1 100644
--- a/drivers/media/pci/ddbridge/ddbridge-ci.h
+++ b/drivers/media/pci/ddbridge/ddbridge-ci.h
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef __DDBRIDGE_CI_H__
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 92fe051c672f..fe833f39698a 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/module.h>
diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.c b/drivers/media/pci/ddbridge/ddbridge-hw.c
index f9c91bdbd041..d7d9cd0dad23 100644
--- a/drivers/media/pci/ddbridge/ddbridge-hw.c
+++ b/drivers/media/pci/ddbridge/ddbridge-hw.c
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include "ddbridge.h"
diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.h b/drivers/media/pci/ddbridge/ddbridge-hw.h
index e34bd94c266b..934f296f48c0 100644
--- a/drivers/media/pci/ddbridge/ddbridge-hw.h
+++ b/drivers/media/pci/ddbridge/ddbridge-hw.h
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef _DDBRIDGE_HW_H_
@@ -40,4 +31,4 @@ struct ddb_device_id {
const struct ddb_info *get_ddb_info(u16 vendor, u16 device,
u16 subvendor, u16 subdevice);
-#endif /* _DDBRIDGE_HW_H */
+#endif /* _DDBRIDGE_HW_H_ */
diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.c b/drivers/media/pci/ddbridge/ddbridge-i2c.c
index aafa6030c8cc..c894be180446 100644
--- a/drivers/media/pci/ddbridge/ddbridge-i2c.c
+++ b/drivers/media/pci/ddbridge/ddbridge-i2c.c
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/module.h>
diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.h b/drivers/media/pci/ddbridge/ddbridge-i2c.h
index 90830f7b1638..48555d41aa48 100644
--- a/drivers/media/pci/ddbridge/ddbridge-i2c.h
+++ b/drivers/media/pci/ddbridge/ddbridge-i2c.h
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef __DDBRIDGE_I2C_H__
diff --git a/drivers/media/pci/ddbridge/ddbridge-io.h b/drivers/media/pci/ddbridge/ddbridge-io.h
index 1a5b31b52494..991246cecee2 100644
--- a/drivers/media/pci/ddbridge/ddbridge-io.h
+++ b/drivers/media/pci/ddbridge/ddbridge-io.h
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef __DDBRIDGE_IO_H__
diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index 25d0d6745b52..91733ab9f58c 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/media/pci/ddbridge/ddbridge-max.c b/drivers/media/pci/ddbridge/ddbridge-max.c
index 576dd2318e4d..0582b86bb869 100644
--- a/drivers/media/pci/ddbridge/ddbridge-max.c
+++ b/drivers/media/pci/ddbridge/ddbridge-max.c
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/module.h>
diff --git a/drivers/media/pci/ddbridge/ddbridge-max.h b/drivers/media/pci/ddbridge/ddbridge-max.h
index 6543dfc77138..da1553fe8695 100644
--- a/drivers/media/pci/ddbridge/ddbridge-max.h
+++ b/drivers/media/pci/ddbridge/ddbridge-max.h
@@ -5,15 +5,6 @@
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef _DDBRIDGE_MAX_H_
@@ -27,4 +18,4 @@ int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm);
int ddb_fe_attach_mxl5xx(struct ddb_input *input);
int ddb_fe_attach_mci(struct ddb_input *input, u32 type);
-#endif /* _DDBRIDGE_MAX_H */
+#endif /* _DDBRIDGE_MAX_H_ */
diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.c b/drivers/media/pci/ddbridge/ddbridge-mci.c
index 97384ae9ad27..a006cb0fa199 100644
--- a/drivers/media/pci/ddbridge/ddbridge-mci.c
+++ b/drivers/media/pci/ddbridge/ddbridge-mci.c
@@ -5,15 +5,6 @@
* Copyright (C) 2017-2018 Digital Devices GmbH
* Ralph Metzler <rjkm@metzlerbros.de>
* Marcus Metzler <mocm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include "ddbridge.h"
diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.h b/drivers/media/pci/ddbridge/ddbridge-mci.h
index 24241111c634..d9799fbf59d4 100644
--- a/drivers/media/pci/ddbridge/ddbridge-mci.h
+++ b/drivers/media/pci/ddbridge/ddbridge-mci.h
@@ -5,15 +5,6 @@
* Copyright (C) 2017-2018 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef _DDBRIDGE_MCI_H_
diff --git a/drivers/media/pci/ddbridge/ddbridge-regs.h b/drivers/media/pci/ddbridge/ddbridge-regs.h
index 2942a7f35099..42256fc9695d 100644
--- a/drivers/media/pci/ddbridge/ddbridge-regs.h
+++ b/drivers/media/pci/ddbridge/ddbridge-regs.h
@@ -3,15 +3,6 @@
* ddbridge-regs.h: Digital Devices PCIe bridge driver
*
* Copyright (C) 2010-2017 Digital Devices GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef __DDBRIDGE_REGS_H__
diff --git a/drivers/media/pci/ddbridge/ddbridge-sx8.c b/drivers/media/pci/ddbridge/ddbridge-sx8.c
index 374fcee94960..c8de8d283f85 100644
--- a/drivers/media/pci/ddbridge/ddbridge-sx8.c
+++ b/drivers/media/pci/ddbridge/ddbridge-sx8.c
@@ -5,15 +5,6 @@
* Copyright (C) 2018 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include "ddbridge.h"
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index b834449e78f8..f3699dbd193f 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -4,15 +4,6 @@
*
* Copyright (C) 2010-2017 Digital Devices GmbH
* Ralph Metzler <rmetzler@digitaldevices.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 only, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef _DDBRIDGE_H_
@@ -379,4 +370,4 @@ void ddb_unmap(struct ddb *dev);
int ddb_exit_ddbridge(int stage, int error);
int ddb_init_ddbridge(void);
-#endif /* DDBRIDGE_H */
+#endif /* _DDBRIDGE_H_ */
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
index dbdbdb648a0d..a3fe547b7fce 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
@@ -1323,7 +1323,7 @@ static int cio2_video_link_validate(struct media_link *link)
struct v4l2_subdev_format source_fmt;
int ret;
- if (!media_entity_remote_pad(entity->pads)) {
+ if (!media_pad_remote_pad_first(entity->pads)) {
dev_info(dev, "video node %s pad not connected\n", vd->name);
return -ENOTCONN;
}
diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c
index 5526bcc7a9bd..965d285a9240 100644
--- a/drivers/media/pci/saa7164/saa7164-api.c
+++ b/drivers/media/pci/saa7164/saa7164-api.c
@@ -801,7 +801,7 @@ int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen)
if (buflen < 128)
return -ENOMEM;
- /* Assumption: Hauppauge eeprom is at 0xa0 on on bus 0 */
+ /* Assumption: Hauppauge eeprom is at 0xa0 on bus 0 */
/* TODO: Pull the details from the boards struct */
return saa7164_api_i2c_read(&dev->i2c_bus[0], 0xa0 >> 1, sizeof(reg),
&reg[0], 128, buf);
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
index a96e170ab04e..118b922c08c3 100644
--- a/drivers/media/pci/sta2x11/Kconfig
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config STA2X11_VIP
tristate "STA2X11 VIP Video For Linux"
- depends on PCI && VIDEO_DEV && VIRT_TO_BUS && I2C
+ depends on PCI && VIDEO_DEV && I2C
depends on STA2X11 || COMPILE_TEST
select GPIOLIB if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/pci/tw5864/tw5864-core.c b/drivers/media/pci/tw5864/tw5864-core.c
index 5cae73e6fb9c..560ff1ddcc83 100644
--- a/drivers/media/pci/tw5864/tw5864-core.c
+++ b/drivers/media/pci/tw5864/tw5864-core.c
@@ -254,9 +254,9 @@ static int tw5864_initdev(struct pci_dev *pci_dev,
/* pci init */
dev->pci = pci_dev;
- err = pci_enable_device(pci_dev);
+ err = pcim_enable_device(pci_dev);
if (err) {
- dev_err(&dev->pci->dev, "pci_enable_device() failed\n");
+ dev_err(&dev->pci->dev, "pcim_enable_device() failed\n");
goto unreg_v4l2;
}
@@ -265,21 +265,16 @@ static int tw5864_initdev(struct pci_dev *pci_dev,
err = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32));
if (err) {
dev_err(&dev->pci->dev, "32 bit PCI DMA is not supported\n");
- goto disable_pci;
+ goto unreg_v4l2;
}
/* get mmio */
- err = pci_request_regions(pci_dev, dev->name);
+ err = pcim_iomap_regions(pci_dev, BIT(0), dev->name);
if (err) {
dev_err(&dev->pci->dev, "Cannot request regions for MMIO\n");
- goto disable_pci;
- }
- dev->mmio = pci_ioremap_bar(pci_dev, 0);
- if (!dev->mmio) {
- err = -EIO;
- dev_err(&dev->pci->dev, "can't ioremap() MMIO memory\n");
- goto release_mmio;
+ goto unreg_v4l2;
}
+ dev->mmio = pcim_iomap_table(pci_dev)[0];
spin_lock_init(&dev->slock);
@@ -291,7 +286,7 @@ static int tw5864_initdev(struct pci_dev *pci_dev,
err = tw5864_video_init(dev, video_nr);
if (err)
- goto unmap_mmio;
+ goto unreg_v4l2;
/* get irq */
err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw5864_isr,
@@ -308,12 +303,6 @@ static int tw5864_initdev(struct pci_dev *pci_dev,
fini_video:
tw5864_video_fini(dev);
-unmap_mmio:
- iounmap(dev->mmio);
-release_mmio:
- pci_release_regions(pci_dev);
-disable_pci:
- pci_disable_device(pci_dev);
unreg_v4l2:
v4l2_device_unregister(&dev->v4l2_dev);
return err;
@@ -331,11 +320,6 @@ static void tw5864_finidev(struct pci_dev *pci_dev)
/* unregister */
tw5864_video_fini(dev);
- /* release resources */
- iounmap(dev->mmio);
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
-
v4l2_device_unregister(&dev->v4l2_dev);
}
diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c
index 6676e069b515..c53099c958ca 100644
--- a/drivers/media/pci/tw686x/tw686x-core.c
+++ b/drivers/media/pci/tw686x/tw686x-core.c
@@ -315,13 +315,6 @@ static int tw686x_probe(struct pci_dev *pci_dev,
spin_lock_init(&dev->lock);
- err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED,
- dev->name, dev);
- if (err < 0) {
- dev_err(&pci_dev->dev, "unable to request interrupt\n");
- goto iounmap;
- }
-
timer_setup(&dev->dma_delay_timer, tw686x_dma_delay, 0);
/*
@@ -333,18 +326,26 @@ static int tw686x_probe(struct pci_dev *pci_dev,
err = tw686x_video_init(dev);
if (err) {
dev_err(&pci_dev->dev, "can't register video\n");
- goto free_irq;
+ goto iounmap;
}
err = tw686x_audio_init(dev);
if (err)
dev_warn(&pci_dev->dev, "can't register audio\n");
+ err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED,
+ dev->name, dev);
+ if (err < 0) {
+ dev_err(&pci_dev->dev, "unable to request interrupt\n");
+ goto tw686x_free;
+ }
+
pci_set_drvdata(pci_dev, dev);
return 0;
-free_irq:
- free_irq(pci_dev->irq, dev);
+tw686x_free:
+ tw686x_video_free(dev);
+ tw686x_audio_free(dev);
iounmap:
pci_iounmap(pci_dev, dev->mmio);
free_region:
diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c
index 6344a479119f..3ebf7a2c95f0 100644
--- a/drivers/media/pci/tw686x/tw686x-video.c
+++ b/drivers/media/pci/tw686x/tw686x-video.c
@@ -1280,8 +1280,10 @@ int tw686x_video_init(struct tw686x_dev *dev)
video_set_drvdata(vdev, vc);
err = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
- if (err < 0)
+ if (err < 0) {
+ video_device_release(vdev);
goto error;
+ }
vc->num = vdev->num;
}
diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
index 3c02aa2a54aa..9e64041cc1c1 100644
--- a/drivers/media/platform/amphion/vdec.c
+++ b/drivers/media/platform/amphion/vdec.c
@@ -63,6 +63,7 @@ struct vdec_t {
bool is_source_changed;
u32 source_change;
u32 drain;
+ bool aborting;
};
static const struct vpu_format vdec_formats[] = {
@@ -104,7 +105,6 @@ static const struct vpu_format vdec_formats[] = {
.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_MPEG2,
@@ -178,16 +178,6 @@ static int vdec_ctrl_init(struct vpu_inst *inst)
return 0;
}
-static void vdec_set_last_buffer_dequeued(struct vpu_inst *inst)
-{
- struct vdec_t *vdec = inst->priv;
-
- if (vdec->eos_received) {
- if (!vpu_set_last_buffer_dequeued(inst))
- vdec->eos_received--;
- }
-}
-
static void vdec_handle_resolution_change(struct vpu_inst *inst)
{
struct vdec_t *vdec = inst->priv;
@@ -234,6 +224,21 @@ static int vdec_update_state(struct vpu_inst *inst, enum vpu_codec_state state,
return 0;
}
+static void vdec_set_last_buffer_dequeued(struct vpu_inst *inst)
+{
+ struct vdec_t *vdec = inst->priv;
+
+ if (inst->state == VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE)
+ return;
+
+ if (vdec->eos_received) {
+ if (!vpu_set_last_buffer_dequeued(inst)) {
+ vdec->eos_received--;
+ vdec_update_state(inst, VPU_CODEC_STATE_DRAIN, 0);
+ }
+ }
+}
+
static int vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
{
strscpy(cap->driver, "amphion-vpu", sizeof(cap->driver));
@@ -493,6 +498,8 @@ static int vdec_drain(struct vpu_inst *inst)
static int vdec_cmd_start(struct vpu_inst *inst)
{
+ struct vdec_t *vdec = inst->priv;
+
switch (inst->state) {
case VPU_CODEC_STATE_STARTED:
case VPU_CODEC_STATE_DRAIN:
@@ -503,6 +510,8 @@ static int vdec_cmd_start(struct vpu_inst *inst)
break;
}
vpu_process_capture_buffer(inst);
+ if (vdec->eos_received)
+ vdec_set_last_buffer_dequeued(inst);
return 0;
}
@@ -731,6 +740,7 @@ static void vdec_stop_done(struct vpu_inst *inst)
vdec->eos_received = 0;
vdec->is_source_changed = false;
vdec->source_change = 0;
+ inst->total_input_count = 0;
vpu_inst_unlock(inst);
}
@@ -939,6 +949,9 @@ static int vdec_response_frame(struct vpu_inst *inst, struct vb2_v4l2_buffer *vb
if (inst->state != VPU_CODEC_STATE_ACTIVE)
return -EINVAL;
+ if (vdec->aborting)
+ return -EINVAL;
+
if (!vdec->req_frame_count)
return -EINVAL;
@@ -1048,6 +1061,8 @@ static void vdec_clear_slots(struct vpu_inst *inst)
vpu_buf = vdec->slots[i];
vbuf = &vpu_buf->m2m_buf.vb;
+ vpu_trace(inst->dev, "clear slot %d\n", i);
+ vdec_response_fs_release(inst, i, vpu_buf->tag);
vdec_recycle_buffer(inst, vbuf);
vdec->slots[i]->state = VPU_BUF_STATE_IDLE;
vdec->slots[i] = NULL;
@@ -1203,7 +1218,6 @@ static void vdec_event_eos(struct vpu_inst *inst)
vdec->eos_received++;
vdec->fixed_fmt = false;
inst->min_buffer_cap = VDEC_MIN_BUFFER_CAP;
- vdec_update_state(inst, VPU_CODEC_STATE_DRAIN, 0);
vdec_set_last_buffer_dequeued(inst);
vpu_inst_unlock(inst);
}
@@ -1310,6 +1324,8 @@ static void vdec_abort(struct vpu_inst *inst)
int ret;
vpu_trace(inst->dev, "[%d] state = %d\n", inst->id, inst->state);
+
+ vdec->aborting = true;
vpu_iface_add_scode(inst, SCODE_PADDING_ABORT);
vdec->params.end_flag = 1;
vpu_iface_set_decode_params(inst, &vdec->params, 1);
@@ -1333,6 +1349,7 @@ static void vdec_abort(struct vpu_inst *inst)
vdec->decoded_frame_count = 0;
vdec->display_frame_count = 0;
vdec->sequence = 0;
+ vdec->aborting = false;
}
static void vdec_stop(struct vpu_inst *inst, bool free)
@@ -1369,8 +1386,7 @@ static void vdec_cleanup(struct vpu_inst *inst)
return;
vdec = inst->priv;
- if (vdec)
- vfree(vdec);
+ vfree(vdec);
inst->priv = NULL;
vfree(inst);
}
@@ -1480,10 +1496,10 @@ static int vdec_stop_session(struct vpu_inst *inst, u32 type)
vdec_update_state(inst, VPU_CODEC_STATE_SEEK, 0);
vdec->drain = 0;
} else {
- if (inst->state != VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE)
+ if (inst->state != VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE) {
vdec_abort(inst);
-
- vdec->eos_received = 0;
+ vdec->eos_received = 0;
+ }
vdec_clear_slots(inst);
}
diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
index 43d61d82f58c..461524dd1e44 100644
--- a/drivers/media/platform/amphion/venc.c
+++ b/drivers/media/platform/amphion/venc.c
@@ -919,8 +919,7 @@ static void venc_cleanup(struct vpu_inst *inst)
return;
venc = inst->priv;
- if (venc)
- vfree(venc);
+ vfree(venc);
inst->priv = NULL;
vfree(inst);
}
diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h
index e56b96a7e5d3..f914de6ed81e 100644
--- a/drivers/media/platform/amphion/vpu.h
+++ b/drivers/media/platform/amphion/vpu.h
@@ -258,6 +258,7 @@ struct vpu_inst {
struct vpu_format cap_format;
u32 min_buffer_cap;
u32 min_buffer_out;
+ u32 total_input_count;
struct v4l2_rect crop;
u32 colorspace;
diff --git a/drivers/media/platform/amphion/vpu_cmds.c b/drivers/media/platform/amphion/vpu_cmds.c
index 9b39d77a178d..f4d7ca78a621 100644
--- a/drivers/media/platform/amphion/vpu_cmds.c
+++ b/drivers/media/platform/amphion/vpu_cmds.c
@@ -117,8 +117,7 @@ static void vpu_free_cmd(struct vpu_cmd_t *cmd)
{
if (!cmd)
return;
- if (cmd->pkt)
- vfree(cmd->pkt);
+ vfree(cmd->pkt);
vfree(cmd);
}
diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c
index 68ad183925fd..73faa50d2865 100644
--- a/drivers/media/platform/amphion/vpu_core.c
+++ b/drivers/media/platform/amphion/vpu_core.c
@@ -257,14 +257,8 @@ static int vpu_core_register(struct device *dev, struct vpu_core *core)
}
list_add_tail(&core->list, &vpu->cores);
-
vpu_core_get_vpu(core);
- if (vpu_iface_get_power_state(core))
- ret = vpu_core_restore(core);
- if (ret)
- goto error;
-
return 0;
error:
if (core->msg_buffer) {
@@ -362,7 +356,10 @@ struct vpu_core *vpu_request_core(struct vpu_dev *vpu, enum vpu_core_type type)
pm_runtime_resume_and_get(core->dev);
if (core->state == VPU_CORE_DEINIT) {
- ret = vpu_core_boot(core, true);
+ if (vpu_iface_get_power_state(core))
+ ret = vpu_core_restore(core);
+ else
+ ret = vpu_core_boot(core, true);
if (ret) {
pm_runtime_put_sync(core->dev);
mutex_unlock(&core->lock);
@@ -455,8 +452,13 @@ int vpu_inst_unregister(struct vpu_inst *inst)
}
vpu_core_check_hang(core);
if (core->state == VPU_CORE_HANG && !core->instance_mask) {
+ int err;
+
dev_info(core->dev, "reset hang core\n");
- if (!vpu_core_sw_reset(core)) {
+ mutex_unlock(&core->lock);
+ err = vpu_core_sw_reset(core);
+ mutex_lock(&core->lock);
+ if (!err) {
core->state = VPU_CORE_ACTIVE;
core->hang_mask = 0;
}
diff --git a/drivers/media/platform/amphion/vpu_dbg.c b/drivers/media/platform/amphion/vpu_dbg.c
index da62bd718fb8..f72c8a506b22 100644
--- a/drivers/media/platform/amphion/vpu_dbg.c
+++ b/drivers/media/platform/amphion/vpu_dbg.c
@@ -27,7 +27,7 @@ struct print_buf_desc {
u32 bytes;
u32 read;
u32 write;
- char buffer[0];
+ char buffer[];
};
static char *vb2_stat_name[] = {
diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c
index f29c223eefce..f4a488bf9880 100644
--- a/drivers/media/platform/amphion/vpu_malone.c
+++ b/drivers/media/platform/amphion/vpu_malone.c
@@ -309,6 +309,7 @@ struct malone_padding_scode {
struct malone_fmt_mapping {
u32 pixelformat;
enum vpu_malone_format malone_format;
+ u32 is_disabled;
};
struct malone_scode_t {
@@ -568,6 +569,8 @@ static enum vpu_malone_format vpu_malone_format_remap(u32 pixelformat)
u32 i;
for (i = 0; i < ARRAY_SIZE(fmt_mappings); i++) {
+ if (fmt_mappings[i].is_disabled)
+ continue;
if (pixelformat == fmt_mappings[i].pixelformat)
return fmt_mappings[i].malone_format;
}
@@ -575,6 +578,19 @@ static enum vpu_malone_format vpu_malone_format_remap(u32 pixelformat)
return MALONE_FMT_NULL;
}
+bool vpu_malone_check_fmt(enum vpu_core_type type, u32 pixelfmt)
+{
+ if (!vpu_imx8q_check_fmt(type, pixelfmt))
+ return false;
+
+ if (pixelfmt == V4L2_PIX_FMT_NV12M_8L128 || pixelfmt == V4L2_PIX_FMT_NV12M_10BE_8L128)
+ return true;
+ if (vpu_malone_format_remap(pixelfmt) == MALONE_FMT_NULL)
+ return false;
+
+ return true;
+}
+
static void vpu_malone_set_stream_cfg(struct vpu_shared_addr *shared,
u32 instance,
enum vpu_malone_format malone_format)
@@ -610,6 +626,8 @@ static int vpu_malone_set_params(struct vpu_shared_addr *shared,
enum vpu_malone_format malone_format;
malone_format = vpu_malone_format_remap(params->codec_format);
+ if (WARN_ON(malone_format == MALONE_FMT_NULL))
+ return -EINVAL;
iface->udata_buffer[instance].base = params->udata.base;
iface->udata_buffer[instance].slot_size = params->udata.size;
@@ -1296,6 +1314,8 @@ static int vpu_malone_insert_scode_vc1_l_seq(struct malone_scode_t *scode)
int size = 0;
u8 rcv_seqhdr[MALONE_VC1_RCV_SEQ_HEADER_LEN];
+ if (scode->inst->total_input_count)
+ return 0;
scode->need_data = 0;
ret = vpu_malone_insert_scode_seq(scode, MALONE_CODEC_ID_VC1_SIMPLE, sizeof(rcv_seqhdr));
diff --git a/drivers/media/platform/amphion/vpu_malone.h b/drivers/media/platform/amphion/vpu_malone.h
index e5a5cbe9843e..02a9d9530970 100644
--- a/drivers/media/platform/amphion/vpu_malone.h
+++ b/drivers/media/platform/amphion/vpu_malone.h
@@ -40,5 +40,6 @@ int vpu_malone_pre_cmd(struct vpu_shared_addr *shared, u32 instance);
int vpu_malone_post_cmd(struct vpu_shared_addr *shared, u32 instance);
int vpu_malone_init_instance(struct vpu_shared_addr *shared, u32 instance);
u32 vpu_malone_get_max_instance_count(struct vpu_shared_addr *shared);
+bool vpu_malone_check_fmt(enum vpu_core_type type, u32 pixelfmt);
#endif
diff --git a/drivers/media/platform/amphion/vpu_msgs.c b/drivers/media/platform/amphion/vpu_msgs.c
index d5850df8f1d5..d8247f36d84b 100644
--- a/drivers/media/platform/amphion/vpu_msgs.c
+++ b/drivers/media/platform/amphion/vpu_msgs.c
@@ -150,7 +150,12 @@ static void vpu_session_handle_eos(struct vpu_inst *inst, struct vpu_rpc_event *
static void vpu_session_handle_error(struct vpu_inst *inst, struct vpu_rpc_event *pkt)
{
- dev_err(inst->dev, "unsupported stream\n");
+ char *str = (char *)pkt->data;
+
+ if (strlen(str))
+ dev_err(inst->dev, "instance %d firmware error : %s\n", inst->id, str);
+ else
+ dev_err(inst->dev, "instance %d is unsupported stream\n", inst->id);
call_void_vop(inst, event_notify, VPU_MSG_ID_UNSUPPORTED, NULL);
vpu_v4l2_set_error(inst);
}
diff --git a/drivers/media/platform/amphion/vpu_rpc.c b/drivers/media/platform/amphion/vpu_rpc.c
index 18a164766409..676f7da041bd 100644
--- a/drivers/media/platform/amphion/vpu_rpc.c
+++ b/drivers/media/platform/amphion/vpu_rpc.c
@@ -195,7 +195,7 @@ static struct vpu_iface_ops imx8q_rpc_ops[] = {
},
[VPU_CORE_TYPE_DEC] = {
.check_codec = vpu_imx8q_check_codec,
- .check_fmt = vpu_imx8q_check_fmt,
+ .check_fmt = vpu_malone_check_fmt,
.boot_core = vpu_imx8q_boot_core,
.get_power_state = vpu_imx8q_get_power_state,
.on_firmware_loaded = vpu_imx8q_on_firmware_loaded,
diff --git a/drivers/media/platform/amphion/vpu_rpc.h b/drivers/media/platform/amphion/vpu_rpc.h
index 25119e5e807e..7eb6f01e6ab5 100644
--- a/drivers/media/platform/amphion/vpu_rpc.h
+++ b/drivers/media/platform/amphion/vpu_rpc.h
@@ -312,11 +312,16 @@ static inline int vpu_iface_input_frame(struct vpu_inst *inst,
struct vb2_buffer *vb)
{
struct vpu_iface_ops *ops = vpu_core_get_iface(inst->core);
+ int ret;
if (!ops || !ops->input_frame)
return -EINVAL;
- return ops->input_frame(inst->core->iface, inst, vb);
+ ret = ops->input_frame(inst->core->iface, inst, vb);
+ if (ret < 0)
+ return ret;
+ inst->total_input_count++;
+ return ret;
}
static inline int vpu_iface_config_memory_resource(struct vpu_inst *inst,
diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
index 446f07d09d0b..8a3eed957ae6 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.c
+++ b/drivers/media/platform/amphion/vpu_v4l2.c
@@ -500,10 +500,12 @@ static int vpu_vb2_start_streaming(struct vb2_queue *q, unsigned int count)
fmt->sizeimage[1], fmt->bytesperline[1],
fmt->sizeimage[2], fmt->bytesperline[2],
q->num_buffers);
- call_void_vop(inst, start, q->type);
vb2_clear_last_buffer_dequeued(q);
+ ret = call_vop(inst, start, q->type);
+ if (ret)
+ vpu_vb2_buffers_return(inst, q->type, VB2_BUF_STATE_QUEUED);
- return 0;
+ return ret;
}
static void vpu_vb2_stop_streaming(struct vb2_queue *q)
diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig
index 83aebee0c8eb..f399dba62e17 100644
--- a/drivers/media/platform/atmel/Kconfig
+++ b/drivers/media/platform/atmel/Kconfig
@@ -20,12 +20,14 @@ config VIDEO_ATMEL_ISC
config VIDEO_ATMEL_XISC
tristate "ATMEL eXtended Image Sensor Controller (XISC) support"
depends on V4L_PLATFORM_DRIVERS
- depends on VIDEO_DEV && COMMON_CLK && VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_DEV && COMMON_CLK
depends on ARCH_AT91 || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select REGMAP_MMIO
select V4L2_FWNODE
select VIDEO_ATMEL_ISC_BASE
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
help
This module makes the ATMEL eXtended Image Sensor Controller
available as a v4l2 device.
diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c
index 2f07a50035c8..9e5317a7d516 100644
--- a/drivers/media/platform/atmel/atmel-isc-base.c
+++ b/drivers/media/platform/atmel/atmel-isc-base.c
@@ -132,12 +132,9 @@ static int isc_buffer_prepare(struct vb2_buffer *vb)
return 0;
}
-static void isc_start_dma(struct isc_device *isc)
+static void isc_crop_pfe(struct isc_device *isc)
{
struct regmap *regmap = isc->regmap;
- u32 sizeimage = isc->fmt.fmt.pix.sizeimage;
- u32 dctrl_dview;
- dma_addr_t addr0;
u32 h, w;
h = isc->fmt.fmt.pix.height;
@@ -172,6 +169,14 @@ static void isc_start_dma(struct isc_device *isc)
regmap_update_bits(regmap, ISC_PFE_CFG0,
ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN,
ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN);
+}
+
+static void isc_start_dma(struct isc_device *isc)
+{
+ struct regmap *regmap = isc->regmap;
+ u32 sizeimage = isc->fmt.fmt.pix.sizeimage;
+ u32 dctrl_dview;
+ dma_addr_t addr0;
addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0);
regmap_write(regmap, ISC_DAD0 + isc->offsets.dma, addr0);
@@ -369,6 +374,7 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count)
struct isc_buffer, list);
list_del(&isc->cur_frm->list);
+ isc_crop_pfe(isc);
isc_start_dma(isc);
spin_unlock_irqrestore(&isc->dma_queue_lock, flags);
@@ -1466,7 +1472,7 @@ static void isc_awb_work(struct work_struct *w)
if (isc->stop) {
mutex_unlock(&isc->awb_mutex);
return;
- };
+ }
isc_update_profile(isc);
@@ -1525,10 +1531,6 @@ static int isc_s_awb_ctrl(struct v4l2_ctrl *ctrl)
else
ctrls->awb = ISC_WB_NONE;
- /* we did not configure ISC yet */
- if (!isc->config.sd_format)
- break;
-
/* configure the controls with new values from v4l2 */
if (ctrl->cluster[ISC_CTRL_R_GAIN]->is_new)
ctrls->gain[ISC_HIS_CFG_MODE_R] = isc->r_gain_ctrl->val;
diff --git a/drivers/media/platform/atmel/atmel-sama7g5-isc.c b/drivers/media/platform/atmel/atmel-sama7g5-isc.c
index 83b175070c06..8b11aa8340d7 100644
--- a/drivers/media/platform/atmel/atmel-sama7g5-isc.c
+++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c
@@ -591,11 +591,13 @@ static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
};
+#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id microchip_xisc_of_match[] = {
{ .compatible = "microchip,sama7g5-isc" },
{ }
};
MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
+#endif
static struct platform_driver microchip_xisc_driver = {
.probe = microchip_xisc_probe,
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index bc5b0a0168ec..87685a62a5c2 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -1369,6 +1369,9 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
jpeg->vdev->device_caps = V4L2_CAP_STREAMING |
V4L2_CAP_VIDEO_M2M_MPLANE;
+ if (of_get_property(pdev->dev.of_node, "dma-ranges", NULL))
+ dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
+
ret = video_register_device(jpeg->vdev, VFL_TYPE_VIDEO, -1);
if (ret) {
v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h b/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h
index 2cb8cecb3077..b810c96695c8 100644
--- a/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h
+++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h
@@ -40,12 +40,14 @@ struct mdp_ipi_init {
* @ipi_id : IPI_MDP
* @ap_inst : AP mtk_mdp_vpu address
* @vpu_inst_addr : VPU MDP instance address
+ * @padding : Alignment padding
*/
struct mdp_ipi_comm {
uint32_t msg_id;
uint32_t ipi_id;
uint64_t ap_inst;
uint32_t vpu_inst_addr;
+ uint32_t padding;
};
/**
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c
index 52e5d36aa912..7d194a476713 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c
@@ -35,6 +35,44 @@ mtk_vdec_find_format(struct v4l2_format *f,
return NULL;
}
+static bool mtk_vdec_get_cap_fmt(struct mtk_vcodec_ctx *ctx, int format_index)
+{
+ const struct mtk_vcodec_dec_pdata *dec_pdata = ctx->dev->vdec_pdata;
+ const struct mtk_video_fmt *fmt;
+ struct mtk_q_data *q_data;
+ int num_frame_count = 0, i;
+ bool ret = true;
+
+ for (i = 0; i < *dec_pdata->num_formats; i++) {
+ if (dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME)
+ continue;
+
+ num_frame_count++;
+ }
+
+ if (num_frame_count == 1)
+ return true;
+
+ fmt = &dec_pdata->vdec_formats[format_index];
+ q_data = &ctx->q_data[MTK_Q_DATA_SRC];
+ switch (q_data->fmt->fourcc) {
+ case V4L2_PIX_FMT_VP8_FRAME:
+ if (fmt->fourcc == V4L2_PIX_FMT_MM21)
+ ret = true;
+ break;
+ case V4L2_PIX_FMT_H264_SLICE:
+ case V4L2_PIX_FMT_VP9_FRAME:
+ if (fmt->fourcc == V4L2_PIX_FMT_MM21)
+ ret = false;
+ break;
+ default:
+ ret = true;
+ break;
+ }
+
+ return ret;
+}
+
static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx,
enum v4l2_buf_type type)
{
@@ -112,8 +150,6 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx)
{
struct mtk_q_data *q_data;
- ctx->dev->vdec_pdata->init_vdec_params(ctx);
-
ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex;
ctx->fh.m2m_ctx = ctx->m2m_ctx;
ctx->fh.ctrl_handler = &ctx->ctrl_hdl;
@@ -141,15 +177,6 @@ void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx)
q_data->coded_height = DFT_CFG_HEIGHT;
q_data->fmt = ctx->dev->vdec_pdata->default_cap_fmt;
q_data->field = V4L2_FIELD_NONE;
- ctx->max_width = MTK_VDEC_MAX_W;
- ctx->max_height = MTK_VDEC_MAX_H;
-
- v4l_bound_align_image(&q_data->coded_width,
- MTK_VDEC_MIN_W,
- ctx->max_width, 4,
- &q_data->coded_height,
- MTK_VDEC_MIN_H,
- ctx->max_height, 5, 6);
q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height;
q_data->bytesperline[0] = q_data->coded_width;
@@ -185,12 +212,34 @@ static int vidioc_vdec_dqbuf(struct file *file, void *priv,
return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
}
+static int mtk_vcodec_dec_get_chip_name(void *priv)
+{
+ struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ struct device *dev = &ctx->dev->plat_dev->dev;
+
+ if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-dec"))
+ return 8173;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-dec"))
+ return 8183;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-dec"))
+ return 8192;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-dec"))
+ return 8195;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8186-vcodec-dec"))
+ return 8186;
+ else
+ return 8173;
+}
+
static int vidioc_vdec_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strscpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver));
- strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
- strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
+ struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ struct device *dev = &ctx->dev->plat_dev->dev;
+ int platform_name = mtk_vcodec_dec_get_chip_name(priv);
+
+ strscpy(cap->driver, dev->driver->name, sizeof(cap->driver));
+ snprintf(cap->card, sizeof(cap->card), "MT%d video decoder", platform_name);
return 0;
}
@@ -198,6 +247,11 @@ static int vidioc_vdec_querycap(struct file *file, void *priv,
static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
+ struct mtk_vcodec_ctx *ctx = fh_to_ctx(fh);
+
+ if (ctx->dev->vdec_pdata->uses_stateless_api)
+ return v4l2_ctrl_subscribe_event(fh, sub);
+
switch (sub->type) {
case V4L2_EVENT_EOS:
return v4l2_event_subscribe(fh, sub, 2, NULL);
@@ -212,13 +266,18 @@ static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f,
const struct mtk_video_fmt *fmt)
{
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
+ const struct v4l2_frmsize_stepwise *frmsize;
pix_fmt_mp->field = V4L2_FIELD_NONE;
- pix_fmt_mp->width =
- clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, ctx->max_width);
- pix_fmt_mp->height =
- clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, ctx->max_height);
+ /* Always apply frame size constraints from the coded side */
+ if (V4L2_TYPE_IS_OUTPUT(f->type))
+ frmsize = &fmt->frmsize;
+ else
+ frmsize = &ctx->q_data[MTK_Q_DATA_SRC].fmt->frmsize;
+
+ pix_fmt_mp->width = clamp(pix_fmt_mp->width, MTK_VDEC_MIN_W, frmsize->max_width);
+ pix_fmt_mp->height = clamp(pix_fmt_mp->height, MTK_VDEC_MIN_H, frmsize->max_height);
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
pix_fmt_mp->num_planes = 1;
@@ -234,18 +293,15 @@ static int vidioc_try_fmt(struct mtk_vcodec_ctx *ctx, struct v4l2_format *f,
*/
tmp_w = pix_fmt_mp->width;
tmp_h = pix_fmt_mp->height;
- v4l_bound_align_image(&pix_fmt_mp->width,
- MTK_VDEC_MIN_W,
- ctx->max_width, 6,
- &pix_fmt_mp->height,
- MTK_VDEC_MIN_H,
- ctx->max_height, 6, 9);
+ v4l_bound_align_image(&pix_fmt_mp->width, MTK_VDEC_MIN_W, frmsize->max_width, 6,
+ &pix_fmt_mp->height, MTK_VDEC_MIN_H, frmsize->max_height, 6,
+ 9);
if (pix_fmt_mp->width < tmp_w &&
- (pix_fmt_mp->width + 64) <= ctx->max_width)
+ (pix_fmt_mp->width + 64) <= frmsize->max_width)
pix_fmt_mp->width += 64;
if (pix_fmt_mp->height < tmp_h &&
- (pix_fmt_mp->height + 64) <= ctx->max_height)
+ (pix_fmt_mp->height + 64) <= frmsize->max_height)
pix_fmt_mp->height += 64;
mtk_v4l2_debug(0,
@@ -435,13 +491,6 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv,
if (fmt == NULL)
return -EINVAL;
- if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED) &&
- fmt->fourcc != V4L2_PIX_FMT_VP8_FRAME) {
- mtk_v4l2_debug(3, "4K is enabled");
- ctx->max_width = VCODEC_DEC_4K_CODED_WIDTH;
- ctx->max_height = VCODEC_DEC_4K_CODED_HEIGHT;
- }
-
q_data->fmt = fmt;
vidioc_try_fmt(ctx, f, q_data->fmt);
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
@@ -526,15 +575,17 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
if (fsize->index != 0)
return -EINVAL;
- for (i = 0; i < *dec_pdata->num_framesizes; ++i) {
- if (fsize->pixel_format != dec_pdata->vdec_framesizes[i].fourcc)
+ for (i = 0; i < *dec_pdata->num_formats; i++) {
+ if (fsize->pixel_format != dec_pdata->vdec_formats[i].fourcc)
continue;
+ /* Only coded formats have frame sizes set */
+ if (!dec_pdata->vdec_formats[i].frmsize.max_width)
+ return -ENOTTY;
+
fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
- fsize->stepwise = dec_pdata->vdec_framesizes[i].stepwise;
+ fsize->stepwise = dec_pdata->vdec_formats[i].frmsize;
- fsize->stepwise.max_width = ctx->max_width;
- fsize->stepwise.max_height = ctx->max_height;
mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d",
ctx->dev->dec_capability,
fsize->stepwise.min_width,
@@ -566,6 +617,9 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, void *priv,
dec_pdata->vdec_formats[i].type != MTK_FMT_FRAME)
continue;
+ if (!output_queue && !mtk_vdec_get_cap_fmt(ctx, i))
+ continue;
+
if (j == f->index)
break;
++j;
@@ -735,6 +789,7 @@ int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb)
mtk_v4l2_err("data will not fit into plane %d (%lu < %d)",
i, vb2_plane_size(vb, i),
q_data->sizeimage[i]);
+ return -EINVAL;
}
if (!V4L2_TYPE_IS_OUTPUT(vb->type))
vb2_set_plane_payload(vb, i, q_data->sizeimage[i]);
@@ -938,6 +993,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->dev->dev_mutex;
src_vq->dev = &ctx->dev->plat_dev->dev;
+ src_vq->allow_cache_hints = 1;
ret = vb2_queue_init(src_vq);
if (ret) {
@@ -953,6 +1009,7 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->dev->dev_mutex;
dst_vq->dev = &ctx->dev->plat_dev->dev;
+ dst_vq->allow_cache_hints = 1;
ret = vb2_queue_init(dst_vq);
if (ret)
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c
index 995e6e2fb1ab..e0b6ae9d6caa 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c
@@ -208,9 +208,12 @@ static int fops_vcodec_open(struct file *file)
dev->dec_capability =
mtk_vcodec_fw_get_vdec_capa(dev->fw_handler);
+
mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability);
}
+ ctx->dev->vdec_pdata->init_vdec_params(ctx);
+
list_add(&ctx->list, &dev->ctx_list);
mutex_unlock(&dev->dev_mutex);
@@ -386,8 +389,14 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
mtk_v4l2_err("Main device of_platform_populate failed.");
goto err_reg_cont;
}
+ } else {
+ set_bit(MTK_VDEC_CORE, dev->subdev_bitmap);
}
+ atomic_set(&dev->dec_active_cnt, 0);
+ memset(dev->vdec_racing_info, 0, sizeof(dev->vdec_racing_info));
+ mutex_init(&dev->dec_racing_info_mutex);
+
ret = video_register_device(vfd_dec, VFL_TYPE_VIDEO, -1);
if (ret) {
mtk_v4l2_err("Failed to register video device");
@@ -465,6 +474,10 @@ static const struct of_device_id mtk_vcodec_match[] = {
.compatible = "mediatek,mt8186-vcodec-dec",
.data = &mtk_vdec_single_core_pdata,
},
+ {
+ .compatible = "mediatek,mt8195-vcodec-dec",
+ .data = &mtk_lat_sig_core_pdata,
+ },
{},
};
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c
index 14bed2bd4283..376db0e433d7 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c
@@ -28,6 +28,10 @@ static const struct of_device_id mtk_vdec_hw_match[] = {
.compatible = "mediatek,mtk-vcodec-core",
.data = (void *)MTK_VDEC_CORE,
},
+ {
+ .compatible = "mediatek,mtk-vcodec-lat-soc",
+ .data = (void *)MTK_VDEC_LAT_SOC,
+ },
{},
};
MODULE_DEVICE_TABLE(of, mtk_vdec_hw_match);
@@ -166,9 +170,11 @@ static int mtk_vdec_hw_probe(struct platform_device *pdev)
subdev_dev->reg_base[VDEC_HW_SYS] = main_dev->reg_base[VDEC_HW_SYS];
set_bit(subdev_dev->hw_idx, main_dev->subdev_bitmap);
- ret = mtk_vdec_hw_init_irq(subdev_dev);
- if (ret)
- goto err;
+ if (IS_SUPPORT_VDEC_HW_IRQ(hw_idx)) {
+ ret = mtk_vdec_hw_init_irq(subdev_dev);
+ if (ret)
+ goto err;
+ }
subdev_dev->reg_base[VDEC_HW_MISC] =
devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h
index a63e4b1b81c3..36faa8d9d681 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h
@@ -17,6 +17,8 @@
#define VDEC_IRQ_CLR 0x10
#define VDEC_IRQ_CFG_REG 0xa4
+#define IS_SUPPORT_VDEC_HW_IRQ(hw_idx) ((hw_idx) != MTK_VDEC_LAT_SOC)
+
/**
* enum mtk_vdec_hw_reg_idx - subdev hardware register base index
* @VDEC_HW_SYS : vdec soc register index
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
index 0fb7e5ba635b..4305e4eb9900 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
@@ -144,6 +144,34 @@ static void mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dev *vdec_dev, int hw_i
}
}
+static void mtk_vcodec_load_racing_info(struct mtk_vcodec_ctx *ctx)
+{
+ void __iomem *vdec_racing_addr;
+ int j;
+
+ mutex_lock(&ctx->dev->dec_racing_info_mutex);
+ if (atomic_inc_return(&ctx->dev->dec_active_cnt) == 1) {
+ vdec_racing_addr = ctx->dev->reg_base[VDEC_MISC] + 0x100;
+ for (j = 0; j < 132; j++)
+ writel(ctx->dev->vdec_racing_info[j], vdec_racing_addr + j * 4);
+ }
+ mutex_unlock(&ctx->dev->dec_racing_info_mutex);
+}
+
+static void mtk_vcodec_record_racing_info(struct mtk_vcodec_ctx *ctx)
+{
+ void __iomem *vdec_racing_addr;
+ int j;
+
+ mutex_lock(&ctx->dev->dec_racing_info_mutex);
+ if (atomic_dec_and_test(&ctx->dev->dec_active_cnt)) {
+ vdec_racing_addr = ctx->dev->reg_base[VDEC_MISC] + 0x100;
+ for (j = 0; j < 132; j++)
+ ctx->dev->vdec_racing_info[j] = readl(vdec_racing_addr + j * 4);
+ }
+ mutex_unlock(&ctx->dev->dec_racing_info_mutex);
+}
+
static struct mtk_vcodec_pm *mtk_vcodec_dec_get_pm(struct mtk_vcodec_dev *vdec_dev,
int hw_idx)
{
@@ -174,6 +202,14 @@ static void mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dev *vdec_dev,
mtk_vcodec_dec_pw_on(pm);
mtk_vcodec_dec_clock_on(pm);
}
+
+ if (hw_idx == MTK_VDEC_LAT0) {
+ pm = mtk_vcodec_dec_get_pm(vdec_dev, MTK_VDEC_LAT_SOC);
+ if (pm) {
+ mtk_vcodec_dec_pw_on(pm);
+ mtk_vcodec_dec_clock_on(pm);
+ }
+ }
}
static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev,
@@ -186,6 +222,14 @@ static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dev *vdec_dev,
mtk_vcodec_dec_clock_off(pm);
mtk_vcodec_dec_pw_off(pm);
}
+
+ if (hw_idx == MTK_VDEC_LAT0) {
+ pm = mtk_vcodec_dec_get_pm(vdec_dev, MTK_VDEC_LAT_SOC);
+ if (pm) {
+ mtk_vcodec_dec_clock_off(pm);
+ mtk_vcodec_dec_pw_off(pm);
+ }
+ }
}
void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx)
@@ -198,11 +242,17 @@ void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx)
mtk_vcodec_dec_child_dev_on(ctx->dev, hw_idx);
mtk_vcodec_dec_enable_irq(ctx->dev, hw_idx);
+
+ if (IS_VDEC_INNER_RACING(ctx->dev->dec_capability))
+ mtk_vcodec_load_racing_info(ctx);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dec_enable_hardware);
void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_ctx *ctx, int hw_idx)
{
+ if (IS_VDEC_INNER_RACING(ctx->dev->dec_capability))
+ mtk_vcodec_record_racing_info(ctx);
+
mtk_vcodec_dec_disable_irq(ctx->dev, hw_idx);
mtk_vcodec_dec_child_dev_off(ctx->dev, hw_idx);
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c
index 9c7e6145cebb..035c86e7809f 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c
@@ -17,18 +17,24 @@ static const struct mtk_video_fmt mtk_video_formats[] = {
.type = MTK_FMT_DEC,
.num_planes = 1,
.flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
+ .frmsize = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+ MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
},
{
.fourcc = V4L2_PIX_FMT_VP8,
.type = MTK_FMT_DEC,
.num_planes = 1,
.flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
+ .frmsize = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+ MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
},
{
.fourcc = V4L2_PIX_FMT_VP9,
.type = MTK_FMT_DEC,
.num_planes = 1,
.flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
+ .frmsize = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
+ MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
},
{
.fourcc = V4L2_PIX_FMT_MT21C,
@@ -43,27 +49,6 @@ static const unsigned int num_supported_formats =
#define DEFAULT_OUT_FMT_IDX 0
#define DEFAULT_CAP_FMT_IDX 3
-static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = {
- {
- .fourcc = V4L2_PIX_FMT_H264,
- .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
- MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
- },
- {
- .fourcc = V4L2_PIX_FMT_VP8,
- .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
- MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
- },
- {
- .fourcc = V4L2_PIX_FMT_VP9,
- .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16,
- MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 },
- },
-};
-
-static const unsigned int num_supported_framesize =
- ARRAY_SIZE(mtk_vdec_framesizes);
-
/*
* This function tries to clean all display buffers, the buffers will return
* in display order.
@@ -618,8 +603,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8173_pdata = {
.num_formats = &num_supported_formats,
.default_out_fmt = &mtk_video_formats[DEFAULT_OUT_FMT_IDX],
.default_cap_fmt = &mtk_video_formats[DEFAULT_CAP_FMT_IDX],
- .vdec_framesizes = mtk_vdec_framesizes,
- .num_framesizes = &num_supported_framesize,
.worker = mtk_vdec_worker,
.flush_decoder = mtk_vdec_flush_decoder,
.is_subdev_supported = false,
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
index 16d55785d84b..c45bd2599bb2 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
@@ -112,14 +112,12 @@ static const struct mtk_stateless_control mtk_stateless_controls[] = {
#define NUM_CTRLS ARRAY_SIZE(mtk_stateless_controls)
static struct mtk_video_fmt mtk_video_formats[5];
-static struct mtk_codec_framesizes mtk_vdec_framesizes[3];
static struct mtk_video_fmt default_out_format;
static struct mtk_video_fmt default_cap_format;
static unsigned int num_formats;
-static unsigned int num_framesizes;
-static struct v4l2_frmsize_stepwise stepwise_fhd = {
+static const struct v4l2_frmsize_stepwise stepwise_fhd = {
.min_width = MTK_VDEC_MIN_W,
.max_width = MTK_VDEC_MAX_W,
.step_width = 16,
@@ -348,7 +346,6 @@ static void mtk_vcodec_add_formats(unsigned int fourcc,
struct mtk_vcodec_dev *dev = ctx->dev;
const struct mtk_vcodec_dec_pdata *pdata = dev->vdec_pdata;
int count_formats = *pdata->num_formats;
- int count_framesizes = *pdata->num_framesizes;
switch (fourcc) {
case V4L2_PIX_FMT_H264_SLICE:
@@ -357,10 +354,15 @@ static void mtk_vcodec_add_formats(unsigned int fourcc,
mtk_video_formats[count_formats].fourcc = fourcc;
mtk_video_formats[count_formats].type = MTK_FMT_DEC;
mtk_video_formats[count_formats].num_planes = 1;
-
- mtk_vdec_framesizes[count_framesizes].fourcc = fourcc;
- mtk_vdec_framesizes[count_framesizes].stepwise = stepwise_fhd;
- num_framesizes++;
+ mtk_video_formats[count_formats].frmsize = stepwise_fhd;
+
+ if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED) &&
+ fourcc != V4L2_PIX_FMT_VP8_FRAME) {
+ mtk_video_formats[count_formats].frmsize.max_width =
+ VCODEC_DEC_4K_CODED_WIDTH;
+ mtk_video_formats[count_formats].frmsize.max_height =
+ VCODEC_DEC_4K_CODED_HEIGHT;
+ }
break;
case V4L2_PIX_FMT_MM21:
case V4L2_PIX_FMT_MT21C:
@@ -374,15 +376,15 @@ static void mtk_vcodec_add_formats(unsigned int fourcc,
}
num_formats++;
- mtk_v4l2_debug(3, "num_formats: %d num_frames:%d dec_capability: 0x%x",
- count_formats, count_framesizes, ctx->dev->dec_capability);
+ mtk_v4l2_debug(3, "num_formats: %d dec_capability: 0x%x",
+ count_formats, ctx->dev->dec_capability);
}
static void mtk_vcodec_get_supported_formats(struct mtk_vcodec_ctx *ctx)
{
int cap_format_count = 0, out_format_count = 0;
- if (num_formats && num_framesizes)
+ if (num_formats)
return;
if (ctx->dev->dec_capability & MTK_VDEC_FORMAT_MM21) {
@@ -461,8 +463,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_8183_pdata = {
.num_formats = &num_formats,
.default_out_fmt = &default_out_format,
.default_cap_fmt = &default_cap_format,
- .vdec_framesizes = mtk_vdec_framesizes,
- .num_framesizes = &num_framesizes,
.uses_stateless_api = true,
.worker = mtk_vdec_worker,
.flush_decoder = mtk_vdec_flush_decoder,
@@ -481,8 +481,6 @@ const struct mtk_vcodec_dec_pdata mtk_lat_sig_core_pdata = {
.num_formats = &num_formats,
.default_out_fmt = &default_out_format,
.default_cap_fmt = &default_cap_format,
- .vdec_framesizes = mtk_vdec_framesizes,
- .num_framesizes = &num_framesizes,
.uses_stateless_api = true,
.worker = mtk_vdec_worker,
.flush_decoder = mtk_vdec_flush_decoder,
@@ -500,8 +498,6 @@ const struct mtk_vcodec_dec_pdata mtk_vdec_single_core_pdata = {
.num_formats = &num_formats,
.default_out_fmt = &default_out_format,
.default_cap_fmt = &default_cap_format,
- .vdec_framesizes = mtk_vdec_framesizes,
- .num_framesizes = &num_framesizes,
.uses_stateless_api = true,
.worker = mtk_vdec_worker,
.flush_decoder = mtk_vdec_flush_decoder,
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h
index a29041a0b7e0..ef4584a46417 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h
@@ -19,15 +19,14 @@
#include "mtk_vcodec_util.h"
#include "vdec_msg_queue.h"
-#define MTK_VCODEC_DRV_NAME "mtk_vcodec_drv"
#define MTK_VCODEC_DEC_NAME "mtk-vcodec-dec"
#define MTK_VCODEC_ENC_NAME "mtk-vcodec-enc"
-#define MTK_PLATFORM_STR "platform:mt8173"
#define MTK_VCODEC_MAX_PLANES 3
#define MTK_V4L2_BENCHMARK 0
#define WAIT_INTR_TIMEOUT_MS 1000
#define IS_VDEC_LAT_ARCH(hw_arch) ((hw_arch) >= MTK_VDEC_LAT_SINGLE_CORE)
+#define IS_VDEC_INNER_RACING(capability) ((capability) & MTK_VCODEC_INNER_RACING)
/*
* enum mtk_hw_reg_idx - MTK hw register base index
@@ -104,6 +103,7 @@ enum mtk_vdec_hw_id {
MTK_VDEC_CORE,
MTK_VDEC_LAT0,
MTK_VDEC_LAT1,
+ MTK_VDEC_LAT_SOC,
MTK_VDEC_HW_MAX,
};
@@ -125,15 +125,7 @@ struct mtk_video_fmt {
enum mtk_fmt_type type;
u32 num_planes;
u32 flags;
-};
-
-/*
- * struct mtk_codec_framesizes - Structure used to store information about
- * framesizes
- */
-struct mtk_codec_framesizes {
- u32 fourcc;
- struct v4l2_frmsize_stepwise stepwise;
+ struct v4l2_frmsize_stepwise frmsize;
};
/*
@@ -255,7 +247,7 @@ struct vdec_pic_info {
* @param_change: indicate encode parameter type
* @enc_params: encoding parameters
* @dec_if: hooked decoder driver interface
- * @enc_if: hoooked encoder driver interface
+ * @enc_if: hooked encoder driver interface
* @drv_handle: driver handle for specific decode/encode instance
*
* @picinfo: store picture info after header parsing
@@ -285,8 +277,6 @@ struct vdec_pic_info {
* mtk_video_dec_buf.
* @hw_id: hardware index used to identify different hardware.
*
- * @max_width: hardware supported max width
- * @max_height: hardware supported max height
* @msg_queue: msg queue used to store lat buffer information.
*/
struct mtk_vcodec_ctx {
@@ -333,8 +323,6 @@ struct mtk_vcodec_ctx {
struct mutex lock;
int hw_id;
- unsigned int max_width;
- unsigned int max_height;
struct vdec_msg_queue msg_queue;
};
@@ -356,6 +344,7 @@ enum mtk_vdec_format_types {
MTK_VDEC_FORMAT_H264_SLICE = 0x100,
MTK_VDEC_FORMAT_VP8_FRAME = 0x200,
MTK_VDEC_FORMAT_VP9_FRAME = 0x400,
+ MTK_VCODEC_INNER_RACING = 0x20000,
};
/**
@@ -373,9 +362,6 @@ enum mtk_vdec_format_types {
* @default_out_fmt: default output buffer format
* @default_cap_fmt: default capture buffer format
*
- * @vdec_framesizes: supported video decoder frame sizes
- * @num_framesizes: count of video decoder frame sizes
- *
* @hw_arch: hardware arch is used to separate pure_sin_core and lat_sin_core
*
* @is_subdev_supported: whether support parent-node architecture(subdev)
@@ -398,9 +384,6 @@ struct mtk_vcodec_dec_pdata {
const struct mtk_video_fmt *default_out_fmt;
const struct mtk_video_fmt *default_cap_fmt;
- const struct mtk_codec_framesizes *vdec_framesizes;
- const int *num_framesizes;
-
enum mtk_vdec_hw_arch hw_arch;
bool is_subdev_supported;
@@ -477,6 +460,10 @@ struct mtk_vcodec_enc_pdata {
* @subdev_dev: subdev hardware device
* @subdev_prob_done: check whether all used hw device is prob done
* @subdev_bitmap: used to record hardware is ready or not
+ *
+ * @dec_active_cnt: used to mark whether need to record register value
+ * @vdec_racing_info: record register value
+ * @dec_racing_info_mutex: mutex lock used for inner racing mode
*/
struct mtk_vcodec_dev {
struct v4l2_device v4l2_dev;
@@ -522,6 +509,11 @@ struct mtk_vcodec_dev {
void *subdev_dev[MTK_VDEC_HW_MAX];
int (*subdev_prob_done)(struct mtk_vcodec_dev *vdec_dev);
DECLARE_BITMAP(subdev_bitmap, MTK_VDEC_HW_MAX);
+
+ atomic_t dec_active_cnt;
+ u32 vdec_racing_info[132];
+ /* Protects access to vdec_racing_info data */
+ struct mutex dec_racing_info_mutex;
};
static inline struct mtk_vcodec_ctx *fh_to_ctx(struct v4l2_fh *fh)
diff --git a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
index c21367038c34..25e816863597 100644
--- a/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
@@ -50,6 +50,14 @@ static int vidioc_venc_s_ctrl(struct v4l2_ctrl *ctrl)
int ret = 0;
switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE_MODE val= %d",
+ ctrl->val);
+ if (ctrl->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) {
+ mtk_v4l2_err("Unsupported bitrate mode =%d", ctrl->val);
+ ret = -EINVAL;
+ }
+ break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
mtk_v4l2_debug(2, "V4L2_CID_MPEG_VIDEO_BITRATE val = %d",
ctrl->val);
@@ -204,12 +212,32 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
pdata->num_output_formats);
}
+static int mtk_vcodec_enc_get_chip_name(void *priv)
+{
+ struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ struct device *dev = &ctx->dev->plat_dev->dev;
+
+ if (of_device_is_compatible(dev->of_node, "mediatek,mt8173-vcodec-enc"))
+ return 8173;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8183-vcodec-enc"))
+ return 8183;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8192-vcodec-enc"))
+ return 8192;
+ else if (of_device_is_compatible(dev->of_node, "mediatek,mt8195-vcodec-enc"))
+ return 8195;
+ else
+ return 8173;
+}
+
static int vidioc_venc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- strscpy(cap->driver, MTK_VCODEC_ENC_NAME, sizeof(cap->driver));
- strscpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info));
- strscpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card));
+ struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ struct device *dev = &ctx->dev->plat_dev->dev;
+ int platform_name = mtk_vcodec_enc_get_chip_name(priv);
+
+ strscpy(cap->driver, dev->driver->name, sizeof(cap->driver));
+ snprintf(cap->card, sizeof(cap->card), "MT%d video encoder", platform_name);
return 0;
}
@@ -1373,6 +1401,9 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_VP8_PROFILE,
V4L2_MPEG_VIDEO_VP8_PROFILE_0, 0, V4L2_MPEG_VIDEO_VP8_PROFILE_0);
+ v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
if (handler->error) {
diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c
index ca628321d272..580ce979e2a3 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c
@@ -51,7 +51,7 @@ void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx,
struct vb2_queue *vq;
struct vb2_buffer *vb;
struct vb2_v4l2_buffer *vb2_v4l2;
- int index, vb2_index;
+ int index;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
@@ -62,8 +62,8 @@ void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx,
continue;
}
- vb2_index = vb2_find_timestamp(vq, dpb->reference_ts, 0);
- if (vb2_index < 0) {
+ vb = vb2_find_buffer(vq, dpb->reference_ts);
+ if (!vb) {
dev_err(&ctx->dev->plat_dev->dev,
"Reference invalid: dpb_index(%d) reference_ts(%lld)",
index, dpb->reference_ts);
@@ -76,7 +76,6 @@ void mtk_vdec_h264_fill_dpb_info(struct mtk_vcodec_ctx *ctx,
else
h264_dpb_info[index].reference_flag = 2;
- vb = vq->bufs[vb2_index];
vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
h264_dpb_info[index].field = vb2_v4l2->field;
diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
index 784d01f8bd50..4cc92700692b 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
@@ -633,6 +633,17 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
goto err_scp_decode;
}
+ share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr +
+ inst->vsi->wdma_end_addr_offset;
+ share_info->trans_start = inst->ctx->msg_queue.wdma_wptr_addr;
+ share_info->nal_info = inst->vsi->dec.nal_info;
+
+ if (IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability)) {
+ memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params,
+ sizeof(share_info->h264_slice_params));
+ vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf);
+ }
+
/* wait decoder done interrupt */
timeout = mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED,
WAIT_INTR_TIMEOUT_MS, MTK_VDEC_LAT0);
@@ -646,18 +657,22 @@ static int vdec_h264_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
share_info->trans_end = inst->ctx->msg_queue.wdma_addr.dma_addr +
inst->vsi->wdma_end_addr_offset;
- share_info->trans_start = inst->ctx->msg_queue.wdma_wptr_addr;
- share_info->nal_info = inst->vsi->dec.nal_info;
vdec_msg_queue_update_ube_wptr(&lat_buf->ctx->msg_queue, share_info->trans_end);
- memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params,
- sizeof(share_info->h264_slice_params));
- vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf);
+ if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability)) {
+ memcpy(&share_info->h264_slice_params, &inst->vsi->h264_slice_params,
+ sizeof(share_info->h264_slice_params));
+ vdec_msg_queue_qbuf(&inst->ctx->dev->msg_queue_core_ctx, lat_buf);
+ }
+ mtk_vcodec_debug(inst, "dec num: %d lat crc: 0x%x 0x%x 0x%x", inst->slice_dec_num,
+ inst->vsi->dec.crc[0], inst->vsi->dec.crc[1], inst->vsi->dec.crc[2]);
inst->slice_dec_num++;
return 0;
err_scp_decode:
+ if (!IS_VDEC_INNER_RACING(inst->ctx->dev->dec_capability))
+ vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf);
err_free_fb_out:
vdec_msg_queue_qbuf(&inst->ctx->msg_queue.lat_ctx, lat_buf);
mtk_vcodec_err(inst, "slice dec number: %d err: %d", inst->slice_dec_num, err);
diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c
index eef102f3f4f3..e1fe2603e92e 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c
@@ -237,7 +237,7 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst
struct vb2_queue *vq;
struct vb2_buffer *vb;
u64 referenct_ts;
- int index, vb2_index;
+ int index;
frame_header = vdec_vp8_slice_get_ctrl_ptr(inst->ctx, V4L2_CID_STATELESS_VP8_FRAME);
if (IS_ERR(frame_header))
@@ -246,8 +246,8 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
for (index = 0; index < 3; index++) {
referenct_ts = vdec_vp8_slice_get_ref_by_ts(frame_header, index);
- vb2_index = vb2_find_timestamp(vq, referenct_ts, 0);
- if (vb2_index < 0) {
+ vb = vb2_find_buffer(vq, referenct_ts);
+ if (!vb) {
if (!V4L2_VP8_FRAME_IS_KEY_FRAME(frame_header))
mtk_vcodec_err(inst, "reference invalid: index(%d) ts(%lld)",
index, referenct_ts);
@@ -256,7 +256,6 @@ static int vdec_vp8_slice_get_decode_parameters(struct vdec_vp8_slice_inst *inst
}
inst->vsi->vp8_dpb_info[index].reference_flag = 1;
- vb = vq->bufs[vb2_index];
inst->vsi->vp8_dpb_info[index].y_dma_addr =
vb2_dma_contig_plane_dma_addr(vb, 0);
if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2)
diff --git a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
index 023aba4ec2c4..fb1c36a3592d 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
@@ -439,6 +439,8 @@ struct vdec_vp9_slice_ref {
* @init_vsi: vsi used for initialized VP9 instance
* @vsi: vsi used for decoding/flush ...
* @core_vsi: vsi used for Core stage
+ *
+ * @sc_pfc: per frame context single core
* @counts_map: used map to counts_helper
* @counts_helper: counts table according to newest kernel spec
*/
@@ -487,6 +489,7 @@ struct vdec_vp9_slice_instance {
};
struct vdec_vp9_slice_vsi *core_vsi;
+ struct vdec_vp9_slice_pfc sc_pfc;
struct vdec_vp9_slice_counts_map counts_map;
struct v4l2_vp9_frame_symbol_counts counts_helper;
};
@@ -523,13 +526,12 @@ static int vdec_vp9_slice_init_default_frame_ctx(struct vdec_vp9_slice_instance
if (vdec_vp9_slice_default_frame_ctx)
goto out;
- frame_ctx = kmalloc(sizeof(*frame_ctx), GFP_KERNEL);
+ frame_ctx = kmemdup(remote_frame_ctx, sizeof(*frame_ctx), GFP_KERNEL);
if (!frame_ctx) {
ret = -ENOMEM;
goto out;
}
- memcpy(frame_ctx, remote_frame_ctx, sizeof(*frame_ctx));
vdec_vp9_slice_default_frame_ctx = frame_ctx;
out:
@@ -689,7 +691,26 @@ static int vdec_vp9_slice_tile_offset(int idx, int mi_num, int tile_log2)
int sbs = (mi_num + 7) >> 3;
int offset = ((idx * sbs) >> tile_log2) << 3;
- return offset < mi_num ? offset : mi_num;
+ return min(offset, mi_num);
+}
+
+static
+int vdec_vp9_slice_setup_single_from_src_to_dst(struct vdec_vp9_slice_instance *instance)
+{
+ struct vb2_v4l2_buffer *src;
+ struct vb2_v4l2_buffer *dst;
+
+ src = v4l2_m2m_next_src_buf(instance->ctx->m2m_ctx);
+ if (!src)
+ return -EINVAL;
+
+ dst = v4l2_m2m_next_dst_buf(instance->ctx->m2m_ctx);
+ if (!dst)
+ return -EINVAL;
+
+ v4l2_m2m_buf_copy_metadata(src, dst, true);
+
+ return 0;
}
static int vdec_vp9_slice_setup_lat_from_src_buf(struct vdec_vp9_slice_instance *instance,
@@ -1567,6 +1588,33 @@ static int vdec_vp9_slice_update_prob(struct vdec_vp9_slice_instance *instance,
return 0;
}
+static int vdec_vp9_slice_update_single(struct vdec_vp9_slice_instance *instance,
+ struct vdec_vp9_slice_pfc *pfc)
+{
+ struct vdec_vp9_slice_vsi *vsi;
+
+ vsi = &pfc->vsi;
+ memcpy(&pfc->state[0], &vsi->state, sizeof(vsi->state));
+
+ mtk_vcodec_debug(instance, "Frame %u Y_CRC %08x %08x %08x %08x\n",
+ pfc->seq,
+ vsi->state.crc[0], vsi->state.crc[1],
+ vsi->state.crc[2], vsi->state.crc[3]);
+ mtk_vcodec_debug(instance, "Frame %u C_CRC %08x %08x %08x %08x\n",
+ pfc->seq,
+ vsi->state.crc[4], vsi->state.crc[5],
+ vsi->state.crc[6], vsi->state.crc[7]);
+
+ vdec_vp9_slice_update_prob(instance, vsi);
+
+ instance->width = vsi->frame.uh.frame_width;
+ instance->height = vsi->frame.uh.frame_height;
+ instance->frame_type = vsi->frame.uh.frame_type;
+ instance->show_frame = vsi->frame.uh.show_frame;
+
+ return 0;
+}
+
static int vdec_vp9_slice_update_lat(struct vdec_vp9_slice_instance *instance,
struct vdec_lat_buf *lat_buf,
struct vdec_vp9_slice_pfc *pfc)
@@ -1624,7 +1672,6 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
struct vdec_vp9_slice_reference *ref;
int plane;
int size;
- int idx;
int w;
int h;
int i;
@@ -1667,15 +1714,16 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
*/
for (i = 0; i < 3; i++) {
ref = &vsi->frame.ref[i];
- idx = vb2_find_timestamp(vq, pfc->ref_idx[i], 0);
- if (idx < 0) {
+ vb = vb2_find_buffer(vq, pfc->ref_idx[i]);
+ if (!vb) {
ref->frame_width = w;
ref->frame_height = h;
memset(&vsi->ref[i], 0, sizeof(vsi->ref[i]));
} else {
+ int idx = vb->index;
+
ref->frame_width = instance->dpb[idx].width;
ref->frame_height = instance->dpb[idx].height;
- vb = vq->bufs[idx];
vsi->ref[i].y.dma_addr =
vb2_dma_contig_plane_dma_addr(vb, 0);
if (plane == 1)
@@ -1690,6 +1738,40 @@ static int vdec_vp9_slice_setup_core_buffer(struct vdec_vp9_slice_instance *inst
return 0;
}
+static void vdec_vp9_slice_setup_single_buffer(struct vdec_vp9_slice_instance *instance,
+ struct vdec_vp9_slice_pfc *pfc,
+ struct vdec_vp9_slice_vsi *vsi,
+ struct mtk_vcodec_mem *bs,
+ struct vdec_fb *fb)
+{
+ int i;
+
+ vsi->bs.buf.dma_addr = bs->dma_addr;
+ vsi->bs.buf.size = bs->size;
+ vsi->bs.frame.dma_addr = bs->dma_addr;
+ vsi->bs.frame.size = bs->size;
+
+ for (i = 0; i < 2; i++) {
+ vsi->mv[i].dma_addr = instance->mv[i].dma_addr;
+ vsi->mv[i].size = instance->mv[i].size;
+ }
+ for (i = 0; i < 2; i++) {
+ vsi->seg[i].dma_addr = instance->seg[i].dma_addr;
+ vsi->seg[i].size = instance->seg[i].size;
+ }
+ vsi->tile.dma_addr = instance->tile.dma_addr;
+ vsi->tile.size = instance->tile.size;
+ vsi->prob.dma_addr = instance->prob.dma_addr;
+ vsi->prob.size = instance->prob.size;
+ vsi->counts.dma_addr = instance->counts.dma_addr;
+ vsi->counts.size = instance->counts.size;
+
+ vsi->row_info.buf = 0;
+ vsi->row_info.size = 0;
+
+ vdec_vp9_slice_setup_core_buffer(instance, pfc, vsi, fb, NULL);
+}
+
static int vdec_vp9_slice_setup_core(struct vdec_vp9_slice_instance *instance,
struct vdec_fb *fb,
struct vdec_lat_buf *lat_buf,
@@ -1716,6 +1798,43 @@ err:
return ret;
}
+static int vdec_vp9_slice_setup_single(struct vdec_vp9_slice_instance *instance,
+ struct mtk_vcodec_mem *bs,
+ struct vdec_fb *fb,
+ struct vdec_vp9_slice_pfc *pfc)
+{
+ struct vdec_vp9_slice_vsi *vsi = &pfc->vsi;
+ int ret;
+
+ ret = vdec_vp9_slice_setup_single_from_src_to_dst(instance);
+ if (ret)
+ goto err;
+
+ ret = vdec_vp9_slice_setup_pfc(instance, pfc);
+ if (ret)
+ goto err;
+
+ ret = vdec_vp9_slice_alloc_working_buffer(instance, vsi);
+ if (ret)
+ goto err;
+
+ vdec_vp9_slice_setup_single_buffer(instance, pfc, vsi, bs, fb);
+ vdec_vp9_slice_setup_seg_buffer(instance, vsi, &instance->seg[0]);
+
+ ret = vdec_vp9_slice_setup_prob_buffer(instance, vsi);
+ if (ret)
+ goto err;
+
+ ret = vdec_vp9_slice_setup_tile_buffer(instance, vsi, bs);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ return ret;
+}
+
static int vdec_vp9_slice_update_core(struct vdec_vp9_slice_instance *instance,
struct vdec_lat_buf *lat_buf,
struct vdec_vp9_slice_pfc *pfc)
@@ -1813,8 +1932,8 @@ static int vdec_vp9_slice_flush(void *h_vdec, struct mtk_vcodec_mem *bs,
struct vdec_vp9_slice_instance *instance = h_vdec;
mtk_vcodec_debug(instance, "flush ...\n");
-
- vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue);
+ if (instance->ctx->dev->vdec_pdata->hw_arch != MTK_VDEC_PURE_SINGLE_CORE)
+ vdec_msg_queue_wait_lat_buf_full(&instance->ctx->msg_queue);
return vpu_dec_reset(&instance->vpu);
}
@@ -1867,6 +1986,63 @@ static int vdec_vp9_slice_get_param(void *h_vdec, enum vdec_get_param_type type,
return 0;
}
+static int vdec_vp9_slice_single_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
+ struct vdec_fb *fb, bool *res_chg)
+{
+ struct vdec_vp9_slice_instance *instance = h_vdec;
+ struct vdec_vp9_slice_pfc *pfc = &instance->sc_pfc;
+ struct vdec_vp9_slice_vsi *vsi;
+ struct mtk_vcodec_ctx *ctx;
+ int ret;
+
+ if (!instance || !instance->ctx)
+ return -EINVAL;
+ ctx = instance->ctx;
+
+ /* bs NULL means flush decoder */
+ if (!bs)
+ return vdec_vp9_slice_flush(h_vdec, bs, fb, res_chg);
+
+ fb = ctx->dev->vdec_pdata->get_cap_buffer(ctx);
+ if (!fb)
+ return -EBUSY;
+
+ vsi = &pfc->vsi;
+
+ ret = vdec_vp9_slice_setup_single(instance, bs, fb, pfc);
+ if (ret) {
+ mtk_vcodec_err(instance, "Failed to setup VP9 single ret %d\n", ret);
+ return ret;
+ }
+ vdec_vp9_slice_vsi_to_remote(vsi, instance->vsi);
+
+ ret = vpu_dec_start(&instance->vpu, NULL, 0);
+ if (ret) {
+ mtk_vcodec_err(instance, "Failed to dec VP9 ret %d\n", ret);
+ return ret;
+ }
+
+ ret = mtk_vcodec_wait_for_done_ctx(ctx, MTK_INST_IRQ_RECEIVED,
+ WAIT_INTR_TIMEOUT_MS, MTK_VDEC_CORE);
+ /* update remote vsi if decode timeout */
+ if (ret) {
+ mtk_vcodec_err(instance, "VP9 decode timeout %d\n", ret);
+ WRITE_ONCE(instance->vsi->state.timeout, 1);
+ }
+
+ vpu_dec_end(&instance->vpu);
+
+ vdec_vp9_slice_vsi_from_remote(vsi, instance->vsi, 0);
+ ret = vdec_vp9_slice_update_single(instance, pfc);
+ if (ret) {
+ mtk_vcodec_err(instance, "VP9 decode error: %d\n", ret);
+ return ret;
+ }
+
+ instance->ctx->decoded_frame_cnt++;
+ return 0;
+}
+
static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
struct vdec_fb *fb, bool *res_chg)
{
@@ -1946,6 +2122,20 @@ static int vdec_vp9_slice_lat_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
return 0;
}
+static int vdec_vp9_slice_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
+ struct vdec_fb *fb, bool *res_chg)
+{
+ struct vdec_vp9_slice_instance *instance = h_vdec;
+ int ret;
+
+ if (instance->ctx->dev->vdec_pdata->hw_arch == MTK_VDEC_PURE_SINGLE_CORE)
+ ret = vdec_vp9_slice_single_decode(h_vdec, bs, fb, res_chg);
+ else
+ ret = vdec_vp9_slice_lat_decode(h_vdec, bs, fb, res_chg);
+
+ return ret;
+}
+
static int vdec_vp9_slice_core_decode(struct vdec_lat_buf *lat_buf)
{
struct vdec_vp9_slice_instance *instance;
@@ -2024,7 +2214,7 @@ err:
const struct vdec_common_if vdec_vp9_slice_lat_if = {
.init = vdec_vp9_slice_init,
- .decode = vdec_vp9_slice_lat_decode,
+ .decode = vdec_vp9_slice_decode,
.get_param = vdec_vp9_slice_get_param,
.deinit = vdec_vp9_slice_deinit,
};
diff --git a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c
index 27b4b35039cf..f3807f03d880 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec_drv_if.c
@@ -47,7 +47,7 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
break;
case V4L2_PIX_FMT_VP9_FRAME:
ctx->dec_if = &vdec_vp9_slice_lat_if;
- ctx->hw_id = MTK_VDEC_LAT0;
+ ctx->hw_id = IS_VDEC_LAT_ARCH(hw_arch) ? MTK_VDEC_LAT0 : MTK_VDEC_CORE;
break;
default:
return -EINVAL;
diff --git a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c
index 35f4d5583084..df309e8e9379 100644
--- a/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c
+++ b/drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c
@@ -91,6 +91,11 @@ static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
(unsigned long)msg->ap_inst_addr;
+ if (!vpu) {
+ mtk_v4l2_err("ap_inst_addr is NULL, did the SCP hang or crash?");
+ return;
+ }
+
mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id);
vpu->failure = msg->status;
diff --git a/drivers/media/platform/nvidia/tegra-vde/h264.c b/drivers/media/platform/nvidia/tegra-vde/h264.c
index 88f81a134ba0..204e474d57f7 100644
--- a/drivers/media/platform/nvidia/tegra-vde/h264.c
+++ b/drivers/media/platform/nvidia/tegra-vde/h264.c
@@ -659,20 +659,19 @@ static struct vb2_buffer *get_ref_buf(struct tegra_ctx *ctx,
{
const struct v4l2_h264_dpb_entry *dpb = ctx->h264.decode_params->dpb;
struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
- int buf_idx = -1;
+ struct vb2_buffer *vb = NULL;
if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
- buf_idx = vb2_find_timestamp(cap_q,
- dpb[dpb_idx].reference_ts, 0);
+ vb = vb2_find_buffer(cap_q, dpb[dpb_idx].reference_ts);
/*
* If a DPB entry is unused or invalid, address of current destination
* buffer is returned.
*/
- if (buf_idx < 0)
+ if (!vb)
return &dst->vb2_buf;
- return vb2_get_buffer(cap_q, buf_idx);
+ return vb;
}
static int tegra_vde_validate_vb_size(struct tegra_ctx *ctx,
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
index 29c604b1b179..9418fcf740a8 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
@@ -79,6 +79,11 @@ void mxc_jpeg_enable_irq(void __iomem *reg, int slot)
writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
}
+void mxc_jpeg_disable_irq(void __iomem *reg, int slot)
+{
+ writel(0x0, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
+}
+
void mxc_jpeg_sw_reset(void __iomem *reg)
{
/*
@@ -100,9 +105,6 @@ void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg)
/* all markers and segments */
writel(0x3ff, reg + CAST_CFG_MODE);
-
- /* quality factor */
- writel(0x4b, reg + CAST_QUALITY);
}
void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg)
@@ -114,6 +116,14 @@ void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg)
writel(0x140, reg + CAST_MODE);
}
+void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality)
+{
+ dev_dbg(dev, "CAST Encoder Quality %d...\n", quality);
+
+ /* quality factor */
+ writel(quality, reg + CAST_QUALITY);
+}
+
void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg)
{
dev_dbg(dev, "CAST Decoder GO...\n");
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
index d838e875616c..ecf3b6562ba2 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
@@ -53,10 +53,10 @@
#define CAST_REC_REGS_SEL CAST_STATUS4
#define CAST_LUMTH CAST_STATUS5
#define CAST_CHRTH CAST_STATUS6
-#define CAST_NOMFRSIZE_LO CAST_STATUS7
-#define CAST_NOMFRSIZE_HI CAST_STATUS8
-#define CAST_OFBSIZE_LO CAST_STATUS9
-#define CAST_OFBSIZE_HI CAST_STATUS10
+#define CAST_NOMFRSIZE_LO CAST_STATUS16
+#define CAST_NOMFRSIZE_HI CAST_STATUS17
+#define CAST_OFBSIZE_LO CAST_STATUS18
+#define CAST_OFBSIZE_HI CAST_STATUS19
#define MXC_MAX_SLOTS 1 /* TODO use all 4 slots*/
/* JPEG-Decoder Wrapper Slot Registers 0..3 */
@@ -119,12 +119,14 @@ int mxc_jpeg_enable(void __iomem *reg);
void wait_frmdone(struct device *dev, void __iomem *reg);
void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg);
void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg);
+void mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality);
void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg);
int mxc_jpeg_get_slot(void __iomem *reg);
u32 mxc_jpeg_get_offset(void __iomem *reg, int slot);
void mxc_jpeg_enable_slot(void __iomem *reg, int slot);
void mxc_jpeg_set_l_endian(void __iomem *reg, int le);
void mxc_jpeg_enable_irq(void __iomem *reg, int slot);
+void mxc_jpeg_disable_irq(void __iomem *reg, int slot);
int mxc_jpeg_set_input(void __iomem *reg, u32 in_buf, u32 bufsize);
int mxc_jpeg_set_output(void __iomem *reg, u16 out_pitch, u32 out_buf,
u16 w, u16 h);
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index f36b512bae51..32fd04a3d8bb 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -389,7 +389,6 @@ static int enum_fmt(const struct mxc_jpeg_fmt *mxc_formats, int n,
if (i >= n)
return -EINVAL;
- strscpy(f->description, mxc_formats[i].name, sizeof(f->description));
f->pixelformat = mxc_formats[i].fourcc;
return 0;
@@ -520,6 +519,7 @@ static bool mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg,
GFP_ATOMIC);
if (!cfg_stm)
goto err;
+ memset(cfg_stm, 0, MXC_JPEG_MAX_CFG_STREAM);
jpeg->slot_data[slot].cfg_stream_vaddr = cfg_stm;
skip_alloc:
@@ -558,6 +558,18 @@ static void mxc_jpeg_free_slot_data(struct mxc_jpeg_dev *jpeg,
jpeg->slot_data[slot].used = false;
}
+static void mxc_jpeg_check_and_set_last_buffer(struct mxc_jpeg_ctx *ctx,
+ struct vb2_v4l2_buffer *src_buf,
+ struct vb2_v4l2_buffer *dst_buf)
+{
+ if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) {
+ dst_buf->flags |= V4L2_BUF_FLAG_LAST;
+ v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
+ notify_eos(ctx);
+ ctx->header_parsed = false;
+ }
+}
+
static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
{
struct mxc_jpeg_dev *jpeg = priv;
@@ -580,15 +592,8 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
dev_dbg(dev, "Irq %d on slot %d.\n", irq, slot);
ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
- if (!ctx) {
- dev_err(dev,
- "Instance released before the end of transaction.\n");
- /* soft reset only resets internal state, not registers */
- mxc_jpeg_sw_reset(reg);
- /* clear all interrupts */
- writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
+ if (WARN_ON(!ctx))
goto job_unlock;
- }
if (slot != ctx->slot) {
/* TODO investigate when adding multi-instance support */
@@ -624,6 +629,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
ctx->enc_state == MXC_JPEG_ENC_CONF) {
ctx->enc_state = MXC_JPEG_ENCODING;
dev_dbg(dev, "Encoder config finished. Start encoding...\n");
+ mxc_jpeg_enc_set_quality(dev, reg, ctx->jpeg_quality);
mxc_jpeg_enc_mode_go(dev, reg);
goto job_unlock;
}
@@ -632,6 +638,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
dev_dbg(dev, "Decoder DHT cfg finished. Start decoding...\n");
goto job_unlock;
}
+
if (jpeg->mode == MXC_JPEG_ENCODE) {
payload = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR));
vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload);
@@ -659,7 +666,9 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
buf_state = VB2_BUF_STATE_DONE;
buffers_done:
+ mxc_jpeg_disable_irq(reg, ctx->slot);
jpeg->slot_data[slot].used = false; /* unused, but don't free */
+ mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf);
v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_buf_done(src_buf, buf_state);
@@ -755,7 +764,13 @@ static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr,
u32 fourcc,
u16 w, u16 h)
{
- unsigned int offset = 0;
+ /*
+ * There is a hardware issue that first 128 bytes of configuration data
+ * can't be loaded correctly.
+ * To avoid this issue, we need to write the configuration from
+ * an offset which should be no less than 0x80 (128 bytes).
+ */
+ unsigned int offset = 0x80;
u8 *cfg = (u8 *)cfg_stream_vaddr;
struct mxc_jpeg_sof *sof;
struct mxc_jpeg_sos *sos;
@@ -887,8 +902,8 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
jpeg->slot_data[slot].cfg_stream_size =
mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr,
q_data->fmt->fourcc,
- q_data->w_adjusted,
- q_data->h_adjusted);
+ q_data->w,
+ q_data->h);
/* chain the config descriptor with the encoding descriptor */
cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN;
@@ -970,7 +985,7 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx,
&q_data_cap->h_adjusted,
q_data_cap->h_adjusted, /* adjust up */
MXC_JPEG_MAX_HEIGHT,
- q_data_cap->fmt->v_align,
+ 0,
0);
/* setup bytesperline/sizeimage for capture queue */
@@ -1027,6 +1042,7 @@ static void mxc_jpeg_device_run(void *priv)
jpeg_src_buf->jpeg_parse_error = true;
}
if (jpeg_src_buf->jpeg_parse_error) {
+ mxc_jpeg_check_and_set_last_buffer(ctx, src_buf, dst_buf);
v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
@@ -1077,45 +1093,33 @@ end:
spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
}
-static void mxc_jpeg_set_last_buffer_dequeued(struct mxc_jpeg_ctx *ctx)
-{
- struct vb2_queue *q;
-
- ctx->stopped = 1;
- q = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx);
- if (!list_empty(&q->done_list))
- return;
-
- q->last_buffer_dequeued = true;
- wake_up(&q->done_wq);
- ctx->stopped = 0;
- ctx->header_parsed = false;
-}
-
static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
struct v4l2_decoder_cmd *cmd)
{
struct v4l2_fh *fh = file->private_data;
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
- struct device *dev = ctx->mxc_jpeg->dev;
int ret;
ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd);
if (ret < 0)
return ret;
- if (cmd->cmd == V4L2_DEC_CMD_STOP) {
- dev_dbg(dev, "Received V4L2_DEC_CMD_STOP");
- if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) {
- /* No more src bufs, notify app EOS */
- notify_eos(ctx);
- mxc_jpeg_set_last_buffer_dequeued(ctx);
- } else {
- /* will send EOS later*/
- ctx->stopping = 1;
- }
+ if (!vb2_is_streaming(v4l2_m2m_get_src_vq(fh->m2m_ctx)))
+ return 0;
+
+ ret = v4l2_m2m_ioctl_decoder_cmd(file, priv, cmd);
+ if (ret < 0)
+ return ret;
+
+ if (cmd->cmd == V4L2_DEC_CMD_STOP &&
+ v4l2_m2m_has_stopped(fh->m2m_ctx)) {
+ notify_eos(ctx);
+ ctx->header_parsed = false;
}
+ if (cmd->cmd == V4L2_DEC_CMD_START &&
+ v4l2_m2m_has_stopped(fh->m2m_ctx))
+ vb2_clear_last_buffer_dequeued(&fh->m2m_ctx->cap_q_ctx.q);
return 0;
}
@@ -1124,24 +1128,27 @@ static int mxc_jpeg_encoder_cmd(struct file *file, void *priv,
{
struct v4l2_fh *fh = file->private_data;
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(fh);
- struct device *dev = ctx->mxc_jpeg->dev;
int ret;
ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd);
if (ret < 0)
return ret;
- if (cmd->cmd == V4L2_ENC_CMD_STOP) {
- dev_dbg(dev, "Received V4L2_ENC_CMD_STOP");
- if (v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx) == 0) {
- /* No more src bufs, notify app EOS */
- notify_eos(ctx);
- mxc_jpeg_set_last_buffer_dequeued(ctx);
- } else {
- /* will send EOS later*/
- ctx->stopping = 1;
- }
- }
+ if (!vb2_is_streaming(v4l2_m2m_get_src_vq(fh->m2m_ctx)) ||
+ !vb2_is_streaming(v4l2_m2m_get_dst_vq(fh->m2m_ctx)))
+ return 0;
+
+ ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, cmd);
+ if (ret < 0)
+ return 0;
+
+ if (cmd->cmd == V4L2_ENC_CMD_STOP &&
+ v4l2_m2m_has_stopped(fh->m2m_ctx))
+ notify_eos(ctx);
+
+ if (cmd->cmd == V4L2_ENC_CMD_START &&
+ v4l2_m2m_has_stopped(fh->m2m_ctx))
+ vb2_clear_last_buffer_dequeued(&fh->m2m_ctx->cap_q_ctx.q);
return 0;
}
@@ -1154,18 +1161,30 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q,
{
struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(q);
struct mxc_jpeg_q_data *q_data = NULL;
+ struct mxc_jpeg_q_data tmp_q;
int i;
q_data = mxc_jpeg_get_q_data(ctx, q->type);
if (!q_data)
return -EINVAL;
+ tmp_q.fmt = q_data->fmt;
+ tmp_q.w = q_data->w_adjusted;
+ tmp_q.h = q_data->h_adjusted;
+ for (i = 0; i < MXC_JPEG_MAX_PLANES; i++) {
+ tmp_q.bytesperline[i] = q_data->bytesperline[i];
+ tmp_q.sizeimage[i] = q_data->sizeimage[i];
+ }
+ mxc_jpeg_sizeimage(&tmp_q);
+ for (i = 0; i < MXC_JPEG_MAX_PLANES; i++)
+ tmp_q.sizeimage[i] = max(tmp_q.sizeimage[i], q_data->sizeimage[i]);
+
/* Handle CREATE_BUFS situation - *nplanes != 0 */
if (*nplanes) {
if (*nplanes != q_data->fmt->colplanes)
return -EINVAL;
for (i = 0; i < *nplanes; i++) {
- if (sizes[i] < q_data->sizeimage[i])
+ if (sizes[i] < tmp_q.sizeimage[i])
return -EINVAL;
}
return 0;
@@ -1174,7 +1193,7 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q,
/* Handle REQBUFS situation */
*nplanes = q_data->fmt->colplanes;
for (i = 0; i < *nplanes; i++)
- sizes[i] = q_data->sizeimage[i];
+ sizes[i] = tmp_q.sizeimage[i];
return 0;
}
@@ -1185,6 +1204,8 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, q->type);
int ret;
+ v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);
+
if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(q->type))
ctx->source_change = 0;
dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx);
@@ -1216,11 +1237,15 @@ static void mxc_jpeg_stop_streaming(struct vb2_queue *q)
break;
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
}
- pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev);
- if (V4L2_TYPE_IS_OUTPUT(q->type)) {
- ctx->stopping = 0;
- ctx->stopped = 0;
+
+ v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
+ if (V4L2_TYPE_IS_OUTPUT(q->type) &&
+ v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) {
+ notify_eos(ctx);
+ ctx->header_parsed = false;
}
+
+ pm_runtime_put_sync(&ctx->mxc_jpeg->pdev->dev);
}
static int mxc_jpeg_valid_comp_id(struct device *dev,
@@ -1374,11 +1399,6 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb)
}
q_data_out->w = header.frame.width;
q_data_out->h = header.frame.height;
- if (header.frame.width % 8 != 0 || header.frame.height % 8 != 0) {
- dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n",
- header.frame.width, header.frame.height);
- return -EINVAL;
- }
if (header.frame.width > MXC_JPEG_MAX_WIDTH ||
header.frame.height > MXC_JPEG_MAX_HEIGHT) {
dev_err(dev, "JPEG width or height should be <= 8192: %dx%d\n",
@@ -1424,6 +1444,20 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb)
struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct mxc_jpeg_src_buf *jpeg_src_buf;
+ if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) &&
+ vb2_is_streaming(vb->vb2_queue) &&
+ v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) {
+ struct mxc_jpeg_q_data *q_data;
+
+ q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type);
+ vbuf->field = V4L2_FIELD_NONE;
+ vbuf->sequence = q_data->sequence++;
+ v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf);
+ notify_eos(ctx);
+ ctx->header_parsed = false;
+ return;
+ }
+
if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
goto end;
@@ -1472,24 +1506,11 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb)
return -EINVAL;
}
}
- return 0;
-}
-
-static void mxc_jpeg_buf_finish(struct vb2_buffer *vb)
-{
- struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
- struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct vb2_queue *q = vb->vb2_queue;
-
- if (V4L2_TYPE_IS_OUTPUT(vb->type))
- return;
- if (!ctx->stopped)
- return;
- if (list_empty(&q->done_list)) {
- vbuf->flags |= V4L2_BUF_FLAG_LAST;
- ctx->stopped = 0;
- ctx->header_parsed = false;
+ if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) {
+ vb2_set_plane_payload(vb, 0, 0);
+ vb2_set_plane_payload(vb, 1, 0);
}
+ return 0;
}
static const struct vb2_ops mxc_jpeg_qops = {
@@ -1498,7 +1519,6 @@ static const struct vb2_ops mxc_jpeg_qops = {
.wait_finish = vb2_ops_wait_finish,
.buf_out_validate = mxc_jpeg_buf_out_validate,
.buf_prepare = mxc_jpeg_buf_prepare,
- .buf_finish = mxc_jpeg_buf_finish,
.start_streaming = mxc_jpeg_start_streaming,
.stop_streaming = mxc_jpeg_stop_streaming,
.buf_queue = mxc_jpeg_buf_queue,
@@ -1563,6 +1583,56 @@ static void mxc_jpeg_set_default_params(struct mxc_jpeg_ctx *ctx)
}
}
+static int mxc_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mxc_jpeg_ctx *ctx =
+ container_of(ctrl->handler, struct mxc_jpeg_ctx, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ ctx->jpeg_quality = ctrl->val;
+ break;
+ default:
+ dev_err(ctx->mxc_jpeg->dev, "Invalid control, id = %d, val = %d\n",
+ ctrl->id, ctrl->val);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops mxc_jpeg_ctrl_ops = {
+ .s_ctrl = mxc_jpeg_s_ctrl,
+};
+
+static void mxc_jpeg_encode_ctrls(struct mxc_jpeg_ctx *ctx)
+{
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &mxc_jpeg_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 75);
+}
+
+static int mxc_jpeg_ctrls_setup(struct mxc_jpeg_ctx *ctx)
+{
+ int err;
+
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 2);
+
+ if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE)
+ mxc_jpeg_encode_ctrls(ctx);
+
+ if (ctx->ctrl_handler.error) {
+ err = ctx->ctrl_handler.error;
+
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ return err;
+ }
+
+ err = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+ if (err)
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+ return err;
+}
+
static int mxc_jpeg_open(struct file *file)
{
struct mxc_jpeg_dev *mxc_jpeg = video_drvdata(file);
@@ -1594,6 +1664,12 @@ static int mxc_jpeg_open(struct file *file)
goto error;
}
+ ret = mxc_jpeg_ctrls_setup(ctx);
+ if (ret) {
+ dev_err(ctx->mxc_jpeg->dev, "failed to setup mxc jpeg controls\n");
+ goto err_ctrls_setup;
+ }
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
mxc_jpeg_set_default_params(ctx);
ctx->slot = MXC_MAX_SLOTS; /* slot not allocated yet */
@@ -1605,6 +1681,8 @@ static int mxc_jpeg_open(struct file *file)
return 0;
+err_ctrls_setup:
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
error:
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
@@ -1646,7 +1724,6 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index)
return -EINVAL;
f->pixelformat = q_data->fmt->fourcc;
- strscpy(f->description, q_data->fmt->name, sizeof(f->description));
return 0;
}
}
@@ -1684,22 +1761,17 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fm
pix_mp->num_planes = fmt->colplanes;
pix_mp->pixelformat = fmt->fourcc;
- /*
- * use MXC_JPEG_H_ALIGN instead of fmt->v_align, for vertical
- * alignment, to loosen up the alignment to multiple of 8,
- * otherwise NV12-1080p fails as 1080 is not a multiple of 16
- */
+ pix_mp->width = w;
+ pix_mp->height = h;
v4l_bound_align_image(&w,
- MXC_JPEG_MIN_WIDTH,
- w, /* adjust downwards*/
+ w, /* adjust upwards*/
+ MXC_JPEG_MAX_WIDTH,
fmt->h_align,
&h,
- MXC_JPEG_MIN_HEIGHT,
- h, /* adjust downwards*/
- MXC_JPEG_H_ALIGN,
+ h, /* adjust upwards*/
+ MXC_JPEG_MAX_HEIGHT,
+ 0,
0);
- pix_mp->width = w; /* negotiate the width */
- pix_mp->height = h; /* negotiate the height */
/* get user input into the tmp_q */
tmp_q.w = w;
@@ -1825,35 +1897,19 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
q_data->w_adjusted = q_data->w;
q_data->h_adjusted = q_data->h;
- if (jpeg->mode == MXC_JPEG_DECODE) {
- /*
- * align up the resolution for CAST IP,
- * but leave the buffer resolution unchanged
- */
- v4l_bound_align_image(&q_data->w_adjusted,
- q_data->w_adjusted, /* adjust upwards */
- MXC_JPEG_MAX_WIDTH,
- q_data->fmt->h_align,
- &q_data->h_adjusted,
- q_data->h_adjusted, /* adjust upwards */
- MXC_JPEG_MAX_HEIGHT,
- q_data->fmt->v_align,
- 0);
- } else {
- /*
- * align down the resolution for CAST IP,
- * but leave the buffer resolution unchanged
- */
- v4l_bound_align_image(&q_data->w_adjusted,
- MXC_JPEG_MIN_WIDTH,
- q_data->w_adjusted, /* adjust downwards*/
- q_data->fmt->h_align,
- &q_data->h_adjusted,
- MXC_JPEG_MIN_HEIGHT,
- q_data->h_adjusted, /* adjust downwards*/
- q_data->fmt->v_align,
- 0);
- }
+ /*
+ * align up the resolution for CAST IP,
+ * but leave the buffer resolution unchanged
+ */
+ v4l_bound_align_image(&q_data->w_adjusted,
+ q_data->w_adjusted, /* adjust upwards */
+ MXC_JPEG_MAX_WIDTH,
+ q_data->fmt->h_align,
+ &q_data->h_adjusted,
+ q_data->h_adjusted, /* adjust upwards */
+ MXC_JPEG_MAX_HEIGHT,
+ q_data->fmt->v_align,
+ 0);
for (i = 0; i < pix_mp->num_planes; i++) {
q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
@@ -1958,32 +2014,13 @@ static int mxc_jpeg_subscribe_event(struct v4l2_fh *fh,
return v4l2_event_subscribe(fh, sub, 0, NULL);
case V4L2_EVENT_SOURCE_CHANGE:
return v4l2_src_change_event_subscribe(fh, sub);
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subscribe_event(fh, sub);
default:
return -EINVAL;
}
}
-static int mxc_jpeg_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct v4l2_fh *fh = file->private_data;
- struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
- struct device *dev = ctx->mxc_jpeg->dev;
- int num_src_ready = v4l2_m2m_num_src_bufs_ready(fh->m2m_ctx);
- int ret;
-
- dev_dbg(dev, "DQBUF type=%d, index=%d", buf->type, buf->index);
- if (ctx->stopping == 1 && num_src_ready == 0) {
- /* No more src bufs, notify app EOS */
- notify_eos(ctx);
- ctx->stopping = 0;
- mxc_jpeg_set_last_buffer_dequeued(ctx);
- }
-
- ret = v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf);
- return ret;
-}
-
static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = {
.vidioc_querycap = mxc_jpeg_querycap,
.vidioc_enum_fmt_vid_cap = mxc_jpeg_enum_fmt_vid_cap,
@@ -2007,7 +2044,7 @@ static const struct v4l2_ioctl_ops mxc_jpeg_ioctl_ops = {
.vidioc_encoder_cmd = mxc_jpeg_encoder_cmd,
.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
- .vidioc_dqbuf = mxc_jpeg_dqbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
@@ -2031,6 +2068,7 @@ static int mxc_jpeg_release(struct file *file)
else
dev_dbg(dev, "Release JPEG encoder instance on slot %d.",
ctx->slot);
+ v4l2_ctrl_handler_free(&ctx->ctrl_handler);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
@@ -2167,12 +2205,14 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
jpeg->clk_ipg = devm_clk_get(dev, "ipg");
if (IS_ERR(jpeg->clk_ipg)) {
dev_err(dev, "failed to get clock: ipg\n");
+ ret = PTR_ERR(jpeg->clk_ipg);
goto err_clk;
}
jpeg->clk_per = devm_clk_get(dev, "per");
if (IS_ERR(jpeg->clk_per)) {
dev_err(dev, "failed to get clock: per\n");
+ ret = PTR_ERR(jpeg->clk_per);
goto err_clk;
}
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
index 760eaf5387a1..c508d41a906f 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
@@ -92,11 +92,11 @@ struct mxc_jpeg_ctx {
struct mxc_jpeg_q_data cap_q;
struct v4l2_fh fh;
enum mxc_jpeg_enc_state enc_state;
- unsigned int stopping;
- unsigned int stopped;
unsigned int slot;
unsigned int source_change;
bool header_parsed;
+ struct v4l2_ctrl_handler ctrl_handler;
+ u8 jpeg_quality;
};
struct mxc_jpeg_slot_data {
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 80b1c021d14a..905072871ed2 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -46,6 +46,11 @@
/* Register map definition */
+/* CSIS version */
+#define MIPI_CSIS_VERSION 0x00
+#define MIPI_CSIS_VERSION_IMX7D 0x03030505
+#define MIPI_CSIS_VERSION_IMX8MP 0x03060301
+
/* CSIS common control */
#define MIPI_CSIS_CMN_CTRL 0x04
#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW BIT(16)
@@ -1155,6 +1160,32 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd,
return 0;
}
+static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
+ struct v4l2_mbus_frame_desc_entry *entry = &fd->entry[0];
+
+ if (pad != CSIS_PAD_SOURCE)
+ return -EINVAL;
+
+ fd->type = V4L2_MBUS_FRAME_DESC_TYPE_PARALLEL;
+ fd->num_entries = 1;
+
+ memset(entry, 0, sizeof(*entry));
+
+ mutex_lock(&csis->lock);
+
+ entry->flags = 0;
+ entry->pixelcode = csis->csis_fmt->code;
+ entry->bus.csi2.vc = 0;
+ entry->bus.csi2.dt = csis->csis_fmt->data_type;
+
+ mutex_unlock(&csis->lock);
+
+ return 0;
+}
+
static int mipi_csis_log_status(struct v4l2_subdev *sd)
{
struct mipi_csis_device *csis = sd_to_mipi_csis_device(sd);
@@ -1179,6 +1210,7 @@ static const struct v4l2_subdev_pad_ops mipi_csis_pad_ops = {
.enum_mbus_code = mipi_csis_enum_mbus_code,
.get_fmt = mipi_csis_get_fmt,
.set_fmt = mipi_csis_set_fmt,
+ .get_frame_desc = mipi_csis_get_frame_desc,
};
static const struct v4l2_subdev_ops mipi_csis_subdev_ops = {
@@ -1378,6 +1410,13 @@ static int mipi_csis_subdev_init(struct mipi_csis_device *csis)
sd->dev = csis->dev;
+ sd->fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev),
+ 1, 0, 0);
+ if (!sd->fwnode) {
+ dev_err(csis->dev, "Unable to retrieve endpoint for port@1\n");
+ return -ENOENT;
+ }
+
csis->csis_fmt = &mipi_csis_formats[0];
mipi_csis_init_cfg(sd, NULL);
@@ -1498,6 +1537,7 @@ cleanup:
v4l2_async_unregister_subdev(&csis->sd);
disable_clock:
mipi_csis_clk_disable(csis);
+ fwnode_handle_put(csis->sd.fwnode);
mutex_destroy(&csis->lock);
return ret;
@@ -1517,6 +1557,7 @@ static int mipi_csis_remove(struct platform_device *pdev)
mipi_csis_runtime_suspend(&pdev->dev);
mipi_csis_clk_disable(csis);
media_entity_cleanup(&csis->sd.entity);
+ fwnode_handle_put(csis->sd.fwnode);
mutex_destroy(&csis->lock);
pm_runtime_set_suspended(&pdev->dev);
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index f993f349b66b..88f188e0f750 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -245,7 +245,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
}
if (!csid->testgen.enabled &&
- !media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))
+ !media_pad_remote_pad_first(&csid->pads[MSM_CSID_PAD_SINK]))
return -ENOLINK;
}
@@ -518,7 +518,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value)
struct csid_testgen_config *tg = &csid->testgen;
/* If CSID is linked to CSIPHY, do not allow to enable test generator */
- if (value && media_entity_remote_pad(&csid->pads[MSM_CSID_PAD_SINK]))
+ if (value && media_pad_remote_pad_first(&csid->pads[MSM_CSID_PAD_SINK]))
return -EBUSY;
tg->enabled = !!value;
@@ -666,7 +666,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
if (csid->num_supplies) {
csid->supplies = devm_kmalloc_array(camss->dev,
csid->num_supplies,
- sizeof(csid->supplies),
+ sizeof(*csid->supplies),
GFP_KERNEL);
if (!csid->supplies)
return -ENOMEM;
@@ -729,7 +729,7 @@ static int csid_link_setup(struct media_entity *entity,
const struct media_pad *remote, u32 flags)
{
if (flags & MEDIA_LNK_FL_ENABLED)
- if (media_entity_remote_pad(local))
+ if (media_pad_remote_pad_first(local))
return -EBUSY;
if ((local->flags & MEDIA_PAD_FL_SINK) &&
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index 75fcfc627400..3f726a7237f5 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -693,7 +693,7 @@ static int csiphy_link_setup(struct media_entity *entity,
struct csiphy_device *csiphy;
struct csid_device *csid;
- if (media_entity_remote_pad(local))
+ if (media_pad_remote_pad_first(local))
return -EBUSY;
sd = media_entity_to_v4l2_subdev(entity);
diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index 4ee11bb979cd..b713f5b86aba 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -812,7 +812,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
int ret;
if (enable) {
- if (!media_entity_remote_pad(&line->pads[MSM_ISPIF_PAD_SINK]))
+ if (!media_pad_remote_pad_first(&line->pads[MSM_ISPIF_PAD_SINK]))
return -ENOLINK;
/* Config */
@@ -1253,6 +1253,41 @@ static enum ispif_intf ispif_get_intf(enum vfe_line_id line_id)
}
/*
+ * ispif_get_vfe_id - Get VFE HW module id
+ * @entity: Pointer to VFE media entity structure
+ * @id: Return CSID HW module id here
+ */
+static void ispif_get_vfe_id(struct media_entity *entity, u8 *id)
+{
+ struct v4l2_subdev *sd;
+ struct vfe_line *line;
+ struct vfe_device *vfe;
+
+ sd = media_entity_to_v4l2_subdev(entity);
+ line = v4l2_get_subdevdata(sd);
+ vfe = to_vfe(line);
+
+ *id = vfe->id;
+}
+
+/*
+ * ispif_get_vfe_line_id - Get VFE line id by media entity
+ * @entity: Pointer to VFE media entity structure
+ * @id: Return VFE line id here
+ */
+static void ispif_get_vfe_line_id(struct media_entity *entity,
+ enum vfe_line_id *id)
+{
+ struct v4l2_subdev *sd;
+ struct vfe_line *line;
+
+ sd = media_entity_to_v4l2_subdev(entity);
+ line = v4l2_get_subdevdata(sd);
+
+ *id = line->id;
+}
+
+/*
* ispif_link_setup - Setup ISPIF connections
* @entity: Pointer to media entity structure
* @local: Pointer to local pad
@@ -1266,7 +1301,7 @@ static int ispif_link_setup(struct media_entity *entity,
const struct media_pad *remote, u32 flags)
{
if (flags & MEDIA_LNK_FL_ENABLED) {
- if (media_entity_remote_pad(local))
+ if (media_pad_remote_pad_first(local))
return -EBUSY;
if (local->flags & MEDIA_PAD_FL_SINK) {
@@ -1285,8 +1320,8 @@ static int ispif_link_setup(struct media_entity *entity,
sd = media_entity_to_v4l2_subdev(entity);
line = v4l2_get_subdevdata(sd);
- msm_vfe_get_vfe_id(remote->entity, &line->vfe_id);
- msm_vfe_get_vfe_line_id(remote->entity, &id);
+ ispif_get_vfe_id(remote->entity, &line->vfe_id);
+ ispif_get_vfe_line_id(remote->entity, &id);
line->interface = ispif_get_intf(id);
}
}
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 5b148e9f8134..a26e4a5d87b6 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -1423,40 +1423,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
}
/*
- * msm_vfe_get_vfe_id - Get VFE HW module id
- * @entity: Pointer to VFE media entity structure
- * @id: Return CSID HW module id here
- */
-void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id)
-{
- struct v4l2_subdev *sd;
- struct vfe_line *line;
- struct vfe_device *vfe;
-
- sd = media_entity_to_v4l2_subdev(entity);
- line = v4l2_get_subdevdata(sd);
- vfe = to_vfe(line);
-
- *id = vfe->id;
-}
-
-/*
- * msm_vfe_get_vfe_line_id - Get VFE line id by media entity
- * @entity: Pointer to VFE media entity structure
- * @id: Return VFE line id here
- */
-void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id)
-{
- struct v4l2_subdev *sd;
- struct vfe_line *line;
-
- sd = media_entity_to_v4l2_subdev(entity);
- line = v4l2_get_subdevdata(sd);
-
- *id = line->id;
-}
-
-/*
* vfe_link_setup - Setup VFE connections
* @entity: Pointer to media entity structure
* @local: Pointer to local pad
@@ -1470,7 +1436,7 @@ static int vfe_link_setup(struct media_entity *entity,
const struct media_pad *remote, u32 flags)
{
if (flags & MEDIA_LNK_FL_ENABLED)
- if (media_entity_remote_pad(local))
+ if (media_pad_remote_pad_first(local))
return -EBUSY;
return 0;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 0eba04eb9b77..cbc314c4e244 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -163,9 +163,6 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
void msm_vfe_unregister_entities(struct vfe_device *vfe);
-void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id);
-void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id);
-
/*
* vfe_buf_add_pending - Add output buffer to list of pending
* @output: VFE output
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index 307bb1dc4589..290df04c4d02 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -328,7 +328,7 @@ static struct v4l2_subdev *video_remote_subdev(struct camss_video *video,
{
struct media_pad *remote;
- remote = media_entity_remote_pad(&video->pad);
+ remote = media_pad_remote_pad_first(&video->pad);
if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
@@ -507,7 +507,7 @@ static int video_start_streaming(struct vb2_queue *q, unsigned int count)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
@@ -543,7 +543,7 @@ static void video_stop_streaming(struct vb2_queue *q)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 79ad82e233cb..1118c40886d5 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -937,7 +937,7 @@ struct media_entity *camss_find_sensor(struct media_entity *entity)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
return NULL;
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
return NULL;
@@ -1452,19 +1452,31 @@ static const struct media_device_ops camss_media_ops = {
static int camss_configure_pd(struct camss *camss)
{
- int nbr_pm_domains = 0;
+ struct device *dev = camss->dev;
int last_pm_domain = 0;
int i;
int ret;
- if (camss->version == CAMSS_8x96 ||
- camss->version == CAMSS_660)
- nbr_pm_domains = PM_DOMAIN_GEN1_COUNT;
- else if (camss->version == CAMSS_845 ||
- camss->version == CAMSS_8250)
- nbr_pm_domains = PM_DOMAIN_GEN2_COUNT;
+ camss->genpd_num = of_count_phandle_with_args(dev->of_node,
+ "power-domains",
+ "#power-domain-cells");
+ if (camss->genpd_num < 0) {
+ dev_err(dev, "Power domains are not defined for camss\n");
+ return camss->genpd_num;
+ }
+
+ camss->genpd = devm_kmalloc_array(dev, camss->genpd_num,
+ sizeof(*camss->genpd), GFP_KERNEL);
+ if (!camss->genpd)
+ return -ENOMEM;
+
+ camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num,
+ sizeof(*camss->genpd_link),
+ GFP_KERNEL);
+ if (!camss->genpd_link)
+ return -ENOMEM;
- for (i = 0; i < nbr_pm_domains; i++) {
+ for (i = 0; i < camss->genpd_num; i++) {
camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
if (IS_ERR(camss->genpd[i])) {
ret = PTR_ERR(camss->genpd[i]);
@@ -1529,7 +1541,7 @@ static int camss_probe(struct platform_device *pdev)
struct camss *camss;
int num_subdevs, ret;
- camss = kzalloc(sizeof(*camss), GFP_KERNEL);
+ camss = devm_kzalloc(dev, sizeof(*camss), GFP_KERNEL);
if (!camss)
return -ENOMEM;
@@ -1567,39 +1579,30 @@ static int camss_probe(struct platform_device *pdev)
camss->csid_num = 4;
camss->vfe_num = 4;
} else {
- ret = -EINVAL;
- goto err_free;
+ return -EINVAL;
}
camss->csiphy = devm_kcalloc(dev, camss->csiphy_num,
sizeof(*camss->csiphy), GFP_KERNEL);
- if (!camss->csiphy) {
- ret = -ENOMEM;
- goto err_free;
- }
+ if (!camss->csiphy)
+ return -ENOMEM;
camss->csid = devm_kcalloc(dev, camss->csid_num, sizeof(*camss->csid),
GFP_KERNEL);
- if (!camss->csid) {
- ret = -ENOMEM;
- goto err_free;
- }
+ if (!camss->csid)
+ return -ENOMEM;
if (camss->version == CAMSS_8x16 ||
camss->version == CAMSS_8x96) {
camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL);
- if (!camss->ispif) {
- ret = -ENOMEM;
- goto err_free;
- }
+ if (!camss->ispif)
+ return -ENOMEM;
}
camss->vfe = devm_kcalloc(dev, camss->vfe_num, sizeof(*camss->vfe),
GFP_KERNEL);
- if (!camss->vfe) {
- ret = -ENOMEM;
- goto err_free;
- }
+ if (!camss->vfe)
+ return -ENOMEM;
v4l2_async_nf_init(&camss->notifier);
@@ -1681,15 +1684,12 @@ err_register_entities:
v4l2_device_unregister(&camss->v4l2_dev);
err_cleanup:
v4l2_async_nf_cleanup(&camss->notifier);
-err_free:
- kfree(camss);
return ret;
}
void camss_delete(struct camss *camss)
{
- int nbr_pm_domains = 0;
int i;
v4l2_device_unregister(&camss->v4l2_dev);
@@ -1698,19 +1698,10 @@ void camss_delete(struct camss *camss)
pm_runtime_disable(camss->dev);
- if (camss->version == CAMSS_8x96 ||
- camss->version == CAMSS_660)
- nbr_pm_domains = PM_DOMAIN_GEN1_COUNT;
- else if (camss->version == CAMSS_845 ||
- camss->version == CAMSS_8250)
- nbr_pm_domains = PM_DOMAIN_GEN2_COUNT;
-
- for (i = 0; i < nbr_pm_domains; i++) {
+ for (i = 0; i < camss->genpd_num; i++) {
device_link_del(camss->genpd_link[i]);
dev_pm_domain_detach(camss->genpd[i], true);
}
-
- kfree(camss);
}
/*
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index c9b3e0df5be8..0db80cadbbaa 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -69,9 +69,7 @@ struct resources_icc {
enum pm_domain {
PM_DOMAIN_VFE0 = 0,
PM_DOMAIN_VFE1 = 1,
- PM_DOMAIN_GEN1_COUNT = 2, /* CAMSS series of ISPs */
PM_DOMAIN_VFELITE = 2, /* VFELITE / TOP GDSC */
- PM_DOMAIN_GEN2_COUNT = 3, /* Titan series of ISPs */
};
enum camss_version {
@@ -101,8 +99,9 @@ struct camss {
int vfe_num;
struct vfe_device *vfe;
atomic_t ref_count;
- struct device *genpd[PM_DOMAIN_GEN2_COUNT];
- struct device_link *genpd_link[PM_DOMAIN_GEN2_COUNT];
+ int genpd_num;
+ struct device **genpd;
+ struct device_link **genpd_link;
struct icc_path *icc_path[ICC_SM8250_COUNT];
struct icc_bw_tbl icc_bw_tbl[ICC_SM8250_COUNT];
};
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 877eca125803..990a1519f968 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -265,6 +265,19 @@ static void venus_assign_register_offsets(struct venus_core *core)
}
}
+static irqreturn_t venus_isr_thread(int irq, void *dev_id)
+{
+ struct venus_core *core = dev_id;
+ irqreturn_t ret;
+
+ ret = hfi_isr_thread(irq, dev_id);
+
+ if (ret == IRQ_HANDLED && venus_fault_inject_ssr())
+ hfi_core_trigger_ssr(core, HFI_TEST_SSR_SW_ERR_FATAL);
+
+ return ret;
+}
+
static int venus_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -320,7 +333,7 @@ static int venus_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&core->work, venus_sys_error_handler);
init_waitqueue_head(&core->sys_err_done);
- ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, hfi_isr_thread,
+ ret = devm_request_threaded_irq(dev, core->irq, hfi_isr, venus_isr_thread,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"venus", core);
if (ret)
@@ -832,6 +845,10 @@ static const struct reg_val sm7280_reg_preset[] = {
{ 0xb0088, 0 },
};
+static const struct hfi_ubwc_config sc7280_ubwc_config = {
+ 0, 0, {1, 1, 1, 0, 0, 0}, 8, 32, 14, 0, 0, {0, 0}
+};
+
static const struct venus_resources sc7280_res = {
.freq_tbl = sc7280_freq_table,
.freq_tbl_size = ARRAY_SIZE(sc7280_freq_table),
@@ -841,6 +858,7 @@ static const struct venus_resources sc7280_res = {
.bw_tbl_enc_size = ARRAY_SIZE(sc7280_bw_table_enc),
.bw_tbl_dec = sc7280_bw_table_dec,
.bw_tbl_dec_size = ARRAY_SIZE(sc7280_bw_table_dec),
+ .ubwc_conf = &sc7280_ubwc_config,
.clks = {"core", "bus", "iface"},
.clks_num = 3,
.vcodec0_clks = {"vcodec_core", "vcodec_bus"},
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index d33825553edc..32551c2602a9 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -16,6 +16,7 @@
#include "dbgfs.h"
#include "hfi.h"
#include "hfi_platform.h"
+#include "hfi_helper.h"
#define VDBGL "VenusLow : "
#define VDBGM "VenusMed : "
@@ -57,6 +58,7 @@ struct venus_resources {
unsigned int bw_tbl_dec_size;
const struct reg_val *reg_tbl;
unsigned int reg_tbl_size;
+ const struct hfi_ubwc_config *ubwc_conf;
const char * const clks[VIDC_CLKS_NUM_MAX];
unsigned int clks_num;
const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX];
diff --git a/drivers/media/platform/qcom/venus/dbgfs.c b/drivers/media/platform/qcom/venus/dbgfs.c
index 52de47f2ca88..726f4b730e69 100644
--- a/drivers/media/platform/qcom/venus/dbgfs.c
+++ b/drivers/media/platform/qcom/venus/dbgfs.c
@@ -4,13 +4,22 @@
*/
#include <linux/debugfs.h>
+#include <linux/fault-inject.h>
#include "core.h"
+#ifdef CONFIG_FAULT_INJECTION
+DECLARE_FAULT_ATTR(venus_ssr_attr);
+#endif
+
void venus_dbgfs_init(struct venus_core *core)
{
core->root = debugfs_create_dir("venus", NULL);
debugfs_create_x32("fw_level", 0644, core->root, &venus_fw_debug);
+
+#ifdef CONFIG_FAULT_INJECTION
+ fault_create_debugfs_attr("fail_ssr", core->root, &venus_ssr_attr);
+#endif
}
void venus_dbgfs_deinit(struct venus_core *core)
diff --git a/drivers/media/platform/qcom/venus/dbgfs.h b/drivers/media/platform/qcom/venus/dbgfs.h
index b7b621a8472f..c87c1355d039 100644
--- a/drivers/media/platform/qcom/venus/dbgfs.h
+++ b/drivers/media/platform/qcom/venus/dbgfs.h
@@ -4,8 +4,21 @@
#ifndef __VENUS_DBGFS_H__
#define __VENUS_DBGFS_H__
+#include <linux/fault-inject.h>
+
struct venus_core;
+#ifdef CONFIG_FAULT_INJECTION
+extern struct fault_attr venus_ssr_attr;
+static inline bool venus_fault_inject_ssr(void)
+{
+ return should_fail(&venus_ssr_attr, 1);
+}
+#else
+static inline bool venus_fault_inject_ssr(void) { return false; }
+#endif
+
+
void venus_dbgfs_init(struct venus_core *core);
void venus_dbgfs_deinit(struct venus_core *core);
diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index 5c1104379c49..60de4200375d 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -671,8 +671,7 @@ int venus_helper_get_bufreq(struct venus_inst *inst, u32 type,
unsigned int i;
int ret;
- if (req)
- memset(req, 0, sizeof(*req));
+ memset(req, 0, sizeof(*req));
if (type == HFI_BUFFER_OUTPUT || type == HFI_BUFFER_OUTPUT2)
req->count_min = inst->fw_min_cnt;
@@ -694,8 +693,7 @@ int venus_helper_get_bufreq(struct venus_inst *inst, u32 type,
if (hprop.bufreq[i].type != type)
continue;
- if (req)
- memcpy(req, &hprop.bufreq[i], sizeof(*req));
+ memcpy(req, &hprop.bufreq[i], sizeof(*req));
ret = 0;
break;
}
diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c
index 4ecd444050bb..930b743f225e 100644
--- a/drivers/media/platform/qcom/venus/hfi_cmds.c
+++ b/drivers/media/platform/qcom/venus/hfi_cmds.c
@@ -58,6 +58,15 @@ void pkt_sys_coverage_config(struct hfi_sys_set_property_pkt *pkt, u32 mode)
pkt->data[1] = mode;
}
+void pkt_sys_ubwc_config(struct hfi_sys_set_property_pkt *pkt, const struct hfi_ubwc_config *hfi)
+{
+ pkt->hdr.size = struct_size(pkt, data, 1) + sizeof(*hfi);
+ pkt->hdr.pkt_type = HFI_CMD_SYS_SET_PROPERTY;
+ pkt->num_properties = 1;
+ pkt->data[0] = HFI_PROPERTY_SYS_UBWC_CONFIG;
+ memcpy(&pkt->data[1], hfi, sizeof(*hfi));
+}
+
int pkt_sys_set_resource(struct hfi_sys_set_resource_pkt *pkt, u32 id, u32 size,
u32 addr, void *cookie)
{
diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.h b/drivers/media/platform/qcom/venus/hfi_cmds.h
index 327ed90a2788..99bc0b6db67c 100644
--- a/drivers/media/platform/qcom/venus/hfi_cmds.h
+++ b/drivers/media/platform/qcom/venus/hfi_cmds.h
@@ -256,6 +256,7 @@ void pkt_sys_init(struct hfi_sys_init_pkt *pkt, u32 arch_type);
void pkt_sys_pc_prep(struct hfi_sys_pc_prep_pkt *pkt);
void pkt_sys_idle_indicator(struct hfi_sys_set_property_pkt *pkt, u32 enable);
void pkt_sys_power_control(struct hfi_sys_set_property_pkt *pkt, u32 enable);
+void pkt_sys_ubwc_config(struct hfi_sys_set_property_pkt *pkt, const struct hfi_ubwc_config *hfi);
int pkt_sys_set_resource(struct hfi_sys_set_resource_pkt *pkt, u32 id, u32 size,
u32 addr, void *cookie);
int pkt_sys_unset_resource(struct hfi_sys_release_resource_pkt *pkt, u32 id,
diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h
index 2daa88e3df9f..d2d6719a2ba4 100644
--- a/drivers/media/platform/qcom/venus/hfi_helper.h
+++ b/drivers/media/platform/qcom/venus/hfi_helper.h
@@ -427,6 +427,7 @@
#define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL 0x5
#define HFI_PROPERTY_SYS_IMAGE_VERSION 0x6
#define HFI_PROPERTY_SYS_CONFIG_COVERAGE 0x7
+#define HFI_PROPERTY_SYS_UBWC_CONFIG 0x8
/*
* HFI_PROPERTY_PARAM_COMMON_START
@@ -626,6 +627,25 @@ struct hfi_debug_config {
u32 mode;
};
+struct hfi_ubwc_config {
+ u32 size;
+ u32 packet_type;
+ struct {
+ u32 max_channel_override : 1;
+ u32 mal_length_override : 1;
+ u32 hb_override : 1;
+ u32 bank_swzl_level_override : 1;
+ u32 bank_spreading_override : 1;
+ u32 reserved : 27;
+ } override_bit_info;
+ u32 max_channels;
+ u32 mal_length;
+ u32 highest_bank_bit;
+ u32 bank_swzl_level;
+ u32 bank_spreading;
+ u32 reserved[2];
+};
+
struct hfi_enable {
u32 enable;
};
diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c
index 5b8389b98299..6cf74b2bc5ae 100644
--- a/drivers/media/platform/qcom/venus/hfi_parser.c
+++ b/drivers/media/platform/qcom/venus/hfi_parser.c
@@ -234,6 +234,7 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)
const struct hfi_plat_caps *caps = NULL;
u32 enc_codecs, dec_codecs, count = 0;
unsigned int entries;
+ int ret;
plat = hfi_platform_get(core->res->hfi_version);
if (!plat)
@@ -242,8 +243,9 @@ static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)
if (inst)
return 0;
- if (plat->codecs)
- plat->codecs(&enc_codecs, &dec_codecs, &count);
+ ret = hfi_platform_get_codecs(core, &enc_codecs, &dec_codecs, &count);
+ if (ret)
+ return ret;
if (plat->capabilities)
caps = plat->capabilities(&entries);
diff --git a/drivers/media/platform/qcom/venus/hfi_platform.c b/drivers/media/platform/qcom/venus/hfi_platform.c
index f16f8962273c..f07f554bc5fe 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform.c
+++ b/drivers/media/platform/qcom/venus/hfi_platform.c
@@ -2,7 +2,9 @@
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
+#include <linux/of_device.h>
#include "hfi_platform.h"
+#include "core.h"
const struct hfi_platform *hfi_platform_get(enum hfi_version version)
{
@@ -66,3 +68,23 @@ hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec, u32 session_
return freq;
}
+int
+hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, u32 *dec_codecs, u32 *count)
+{
+ const struct hfi_platform *plat;
+
+ plat = hfi_platform_get(core->res->hfi_version);
+ if (!plat)
+ return -EINVAL;
+
+ if (plat->codecs)
+ plat->codecs(enc_codecs, dec_codecs, count);
+
+ if (of_device_is_compatible(core->dev->of_node, "qcom,sc7280-venus")) {
+ *enc_codecs &= ~HFI_VIDEO_CODEC_VP8;
+ *dec_codecs &= ~HFI_VIDEO_CODEC_VP8;
+ }
+
+ return 0;
+}
+
diff --git a/drivers/media/platform/qcom/venus/hfi_platform.h b/drivers/media/platform/qcom/venus/hfi_platform.h
index 1dcf4085928c..ec89a90a8129 100644
--- a/drivers/media/platform/qcom/venus/hfi_platform.h
+++ b/drivers/media/platform/qcom/venus/hfi_platform.h
@@ -66,4 +66,6 @@ unsigned long hfi_platform_get_codec_vsp_freq(enum hfi_version version, u32 code
u32 session_type);
unsigned long hfi_platform_get_codec_lp_freq(enum hfi_version version, u32 codec,
u32 session_type);
+int hfi_platform_get_codecs(struct venus_core *core, u32 *enc_codecs, u32 *dec_codecs,
+ u32 *count);
#endif
diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c
index 9a34662fea38..2ad40b3945b0 100644
--- a/drivers/media/platform/qcom/venus/hfi_venus.c
+++ b/drivers/media/platform/qcom/venus/hfi_venus.c
@@ -904,6 +904,24 @@ static int venus_sys_set_power_control(struct venus_hfi_device *hdev,
return 0;
}
+static int venus_sys_set_ubwc_config(struct venus_hfi_device *hdev)
+{
+ struct hfi_sys_set_property_pkt *pkt;
+ u8 packet[IFACEQ_VAR_SMALL_PKT_SIZE];
+ const struct venus_resources *res = hdev->core->res;
+ int ret;
+
+ pkt = (struct hfi_sys_set_property_pkt *)packet;
+
+ pkt_sys_ubwc_config(pkt, res->ubwc_conf);
+
+ ret = venus_iface_cmdq_write(hdev, pkt, false);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int venus_get_queue_size(struct venus_hfi_device *hdev,
unsigned int index)
{
@@ -922,6 +940,7 @@ static int venus_get_queue_size(struct venus_hfi_device *hdev,
static int venus_sys_set_default_properties(struct venus_hfi_device *hdev)
{
struct device *dev = hdev->core->dev;
+ const struct venus_resources *res = hdev->core->res;
int ret;
ret = venus_sys_set_debug(hdev, venus_fw_debug);
@@ -945,6 +964,13 @@ static int venus_sys_set_default_properties(struct venus_hfi_device *hdev)
dev_warn(dev, "setting hw power collapse ON failed (%d)\n",
ret);
+ /* For specific venus core, it is mandatory to set the UBWC configuration */
+ if (res->ubwc_conf) {
+ ret = venus_sys_set_ubwc_config(hdev);
+ if (ret)
+ dev_warn(dev, "setting ubwc config failed (%d)\n", ret);
+ }
+
return ret;
}
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
index 49bdcfba010b..968a74234e92 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
@@ -845,7 +845,7 @@ static int rvin_csi2_link_notify(struct media_link *link, u32 flags,
continue;
/* Get remote CSI-2, if any. */
- csi_pad = media_entity_remote_pad(
+ csi_pad = media_pad_remote_pad_first(
&group->vin[i]->vdev.entity.pads[0]);
if (!csi_pad)
continue;
@@ -1261,7 +1261,7 @@ static const struct rvin_info rcar_info_r8a77980 = {
};
static const struct rvin_group_route rcar_info_r8a77990_routes[] = {
- { .master = 0, .csi = RVIN_CSI40, .chsel = 0x03 },
+ { .master = 4, .csi = RVIN_CSI40, .chsel = 0x03 },
{ /* Sentinel */ }
};
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
index fea8f00a9152..174aa6176f54 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
@@ -1313,7 +1313,7 @@ static int rcsi2_link_setup(struct media_entity *entity,
channel = id % 4;
if (flags & MEDIA_LNK_FL_ENABLED) {
- if (media_entity_remote_pad(local)) {
+ if (media_pad_remote_pad_first(local)) {
dev_dbg(priv->dev,
"Each VC can only be routed to one output channel\n");
return -EINVAL;
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
index 6644b498929d..8d37fbdc266a 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
@@ -1258,7 +1258,7 @@ static int rvin_set_stream(struct rvin_dev *vin, int on)
return ret == -ENOIOCTLCMD ? 0 : ret;
}
- pad = media_entity_remote_pad(&vin->pad);
+ pad = media_pad_remote_pad_first(&vin->pad);
if (!pad)
return -EPIPE;
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
index 2e2aa9d746ee..576059f9bbe3 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
@@ -1032,7 +1032,7 @@ static void rvin_notify(struct v4l2_subdev *sd,
if (!vin)
continue;
- pad = media_entity_remote_pad(&vin->pad);
+ pad = media_pad_remote_pad_first(&vin->pad);
if (!pad)
continue;
diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c
index 9a0982fa5c6b..3fec41f6e964 100644
--- a/drivers/media/platform/renesas/rcar_drif.c
+++ b/drivers/media/platform/renesas/rcar_drif.c
@@ -3,11 +3,6 @@
* R-Car Gen3 Digital Radio Interface (DRIF) driver
*
* Copyright (C) 2017 Renesas Electronics Corporation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
/*
@@ -1477,7 +1472,7 @@ MODULE_DEVICE_TABLE(of, rcar_drif_of_table);
static struct platform_driver rcar_drif_driver = {
.driver = {
.name = RCAR_DRIF_DRV_NAME,
- .of_match_table = of_match_ptr(rcar_drif_of_table),
+ .of_match_table = rcar_drif_of_table,
.pm = &rcar_drif_pm_ops,
},
.probe = rcar_drif_probe,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
index a116a3362f9e..4c3bd2b1ca28 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
@@ -516,8 +516,8 @@ int vsp1_entity_link_setup(struct media_entity *entity,
* higher than one for the data pipelines, except for the links to the HGO and
* HGT that can be enabled in addition to a regular data link. When traversing
* outgoing links this function ignores HGO and HGT entities and should thus be
- * used in place of the generic media_entity_remote_pad() function to traverse
- * data pipelines.
+ * used in place of the generic media_pad_remote_pad_first() function to
+ * traverse data pipelines.
*
* Return a pointer to the pad at the remote end of the first found enabled
* link, or NULL if no enabled link has been found.
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c
index 51219b1b6ea9..e8e0ee5f2277 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_video.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c
@@ -50,7 +50,7 @@ vsp1_video_remote_subdev(struct media_pad *local, u32 *pad)
{
struct media_pad *remote;
- remote = media_entity_remote_pad(local);
+ remote = media_pad_remote_pad_first(local);
if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
diff --git a/drivers/media/platform/rockchip/rkisp1/Kconfig b/drivers/media/platform/rockchip/rkisp1/Kconfig
index dabd7e42c193..731c9acbf6ef 100644
--- a/drivers/media/platform/rockchip/rkisp1/Kconfig
+++ b/drivers/media/platform/rockchip/rkisp1/Kconfig
@@ -3,7 +3,7 @@ config VIDEO_ROCKCHIP_ISP1
tristate "Rockchip Image Signal Processing v1 Unit driver"
depends on V4L_PLATFORM_DRIVERS
depends on VIDEO_DEV && OF
- depends on ARCH_ROCKCHIP || COMPILE_TEST
+ depends on ARCH_ROCKCHIP || ARCH_MXC || COMPILE_TEST
select MEDIA_CONTROLLER
select VIDEO_V4L2_SUBDEV_API
select VIDEOBUF2_DMA_CONTIG
diff --git a/drivers/media/platform/rockchip/rkisp1/Makefile b/drivers/media/platform/rockchip/rkisp1/Makefile
index ab32a77db8f7..b3844c4f7623 100644
--- a/drivers/media/platform/rockchip/rkisp1/Makefile
+++ b/drivers/media/platform/rockchip/rkisp1/Makefile
@@ -1,10 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
+rockchip-isp1-y := rkisp1-capture.o \
+ rkisp1-common.o \
+ rkisp1-csi.o \
+ rkisp1-dev.o \
+ rkisp1-isp.o \
+ rkisp1-resizer.o \
+ rkisp1-stats.o \
+ rkisp1-params.o
+
+rockchip-isp1-$(CONFIG_DEBUG_FS) += rkisp1-debug.o
+
obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip-isp1.o
-rockchip-isp1-objs += rkisp1-capture.o \
- rkisp1-common.o \
- rkisp1-dev.o \
- rkisp1-isp.o \
- rkisp1-resizer.o \
- rkisp1-stats.o \
- rkisp1-params.o
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
index fee2aaacb26b..d5904c96ff3f 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
@@ -383,7 +383,7 @@ static void rkisp1_mi_config_ctrl(struct rkisp1_capture *cap)
mi_ctrl |= RKISP1_CIF_MI_CTRL_INIT_BASE_EN |
RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN;
- rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL);
+ rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
}
static u32 rkisp1_pixfmt_comp_size(const struct v4l2_pix_format_mplane *pixm,
@@ -404,7 +404,7 @@ static void rkisp1_irq_frame_end_enable(struct rkisp1_capture *cap)
u32 mi_imsc = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_IMSC);
mi_imsc |= RKISP1_CIF_MI_FRAME(cap);
- rkisp1_write(cap->rkisp1, mi_imsc, RKISP1_CIF_MI_IMSC);
+ rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_IMSC, mi_imsc);
}
static void rkisp1_mp_config(struct rkisp1_capture *cap)
@@ -413,12 +413,12 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap)
struct rkisp1_device *rkisp1 = cap->rkisp1;
u32 reg;
- rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y),
- cap->config->mi.y_size_init);
- rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB),
- cap->config->mi.cb_size_init);
- rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR),
- cap->config->mi.cr_size_init);
+ rkisp1_write(rkisp1, cap->config->mi.y_size_init,
+ rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y));
+ rkisp1_write(rkisp1, cap->config->mi.cb_size_init,
+ rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB));
+ rkisp1_write(rkisp1, cap->config->mi.cr_size_init,
+ rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
rkisp1_irq_frame_end_enable(cap);
@@ -429,7 +429,7 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap)
reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP;
else
reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_MP_CB_CR_SWAP;
- rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg);
}
rkisp1_mi_config_ctrl(cap);
@@ -437,11 +437,11 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap)
reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
reg &= ~RKISP1_MI_CTRL_MP_FMT_MASK;
reg |= cap->pix.cfg->write_format;
- rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg);
reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL);
reg |= RKISP1_CIF_MI_MP_AUTOUPDATE_ENABLE;
- rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, reg);
}
static void rkisp1_sp_config(struct rkisp1_capture *cap)
@@ -450,16 +450,16 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap)
struct rkisp1_device *rkisp1 = cap->rkisp1;
u32 mi_ctrl, reg;
- rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y),
- cap->config->mi.y_size_init);
- rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB),
- cap->config->mi.cb_size_init);
- rkisp1_write(rkisp1, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR),
- cap->config->mi.cr_size_init);
+ rkisp1_write(rkisp1, cap->config->mi.y_size_init,
+ rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_Y));
+ rkisp1_write(rkisp1, cap->config->mi.cb_size_init,
+ rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CB));
+ rkisp1_write(rkisp1, cap->config->mi.cr_size_init,
+ rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR));
- rkisp1_write(rkisp1, pixm->width, RKISP1_CIF_MI_SP_Y_PIC_WIDTH);
- rkisp1_write(rkisp1, pixm->height, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT);
- rkisp1_write(rkisp1, cap->sp_y_stride, RKISP1_CIF_MI_SP_Y_LLENGTH);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_WIDTH, pixm->width);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT, pixm->height);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride);
rkisp1_irq_frame_end_enable(cap);
@@ -470,7 +470,7 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap)
reg |= RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP;
else
reg &= ~RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP;
- rkisp1_write(rkisp1, reg, RKISP1_CIF_MI_XTD_FORMAT_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg);
}
rkisp1_mi_config_ctrl(cap);
@@ -481,7 +481,7 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap)
RKISP1_MI_CTRL_SP_INPUT_YUV422 |
cap->pix.cfg->output_format |
RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE;
- rkisp1_write(rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
}
static void rkisp1_mp_disable(struct rkisp1_capture *cap)
@@ -490,7 +490,7 @@ static void rkisp1_mp_disable(struct rkisp1_capture *cap)
mi_ctrl &= ~(RKISP1_CIF_MI_CTRL_MP_ENABLE |
RKISP1_CIF_MI_CTRL_RAW_ENABLE);
- rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL);
+ rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
}
static void rkisp1_sp_disable(struct rkisp1_capture *cap)
@@ -498,7 +498,7 @@ static void rkisp1_sp_disable(struct rkisp1_capture *cap)
u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
mi_ctrl &= ~RKISP1_CIF_MI_CTRL_SP_ENABLE;
- rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL);
+ rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
}
static void rkisp1_mp_enable(struct rkisp1_capture *cap)
@@ -514,7 +514,7 @@ static void rkisp1_mp_enable(struct rkisp1_capture *cap)
else
mi_ctrl |= RKISP1_CIF_MI_CTRL_MP_ENABLE;
- rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL);
+ rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
}
static void rkisp1_sp_enable(struct rkisp1_capture *cap)
@@ -522,15 +522,14 @@ static void rkisp1_sp_enable(struct rkisp1_capture *cap)
u32 mi_ctrl = rkisp1_read(cap->rkisp1, RKISP1_CIF_MI_CTRL);
mi_ctrl |= RKISP1_CIF_MI_CTRL_SP_ENABLE;
- rkisp1_write(cap->rkisp1, mi_ctrl, RKISP1_CIF_MI_CTRL);
+ rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_CTRL, mi_ctrl);
}
static void rkisp1_mp_sp_stop(struct rkisp1_capture *cap)
{
if (!cap->is_streaming)
return;
- rkisp1_write(cap->rkisp1,
- RKISP1_CIF_MI_FRAME(cap), RKISP1_CIF_MI_ICR);
+ rkisp1_write(cap->rkisp1, RKISP1_CIF_MI_ICR, RKISP1_CIF_MI_FRAME(cap));
cap->ops->disable(cap);
}
@@ -554,7 +553,7 @@ static void rkisp1_mp_set_data_path(struct rkisp1_capture *cap)
dpcl = dpcl | RKISP1_CIF_VI_DPCL_CHAN_MODE_MP |
RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI;
- rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL);
+ rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl);
}
static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap)
@@ -562,7 +561,7 @@ static void rkisp1_sp_set_data_path(struct rkisp1_capture *cap)
u32 dpcl = rkisp1_read(cap->rkisp1, RKISP1_CIF_VI_DPCL);
dpcl |= RKISP1_CIF_VI_DPCL_CHAN_MODE_SP;
- rkisp1_write(cap->rkisp1, dpcl, RKISP1_CIF_VI_DPCL);
+ rkisp1_write(cap->rkisp1, RKISP1_CIF_VI_DPCL, dpcl);
}
static const struct rkisp1_capture_ops rkisp1_capture_ops_mp = {
@@ -628,9 +627,8 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap)
buff_addr = cap->buf.next->buff_addr;
- rkisp1_write(cap->rkisp1,
- buff_addr[RKISP1_PLANE_Y],
- cap->config->mi.y_base_ad_init);
+ rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init,
+ buff_addr[RKISP1_PLANE_Y]);
/*
* In order to support grey format we capture
* YUV422 planar format from the camera and
@@ -638,39 +636,36 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap)
*/
if (cap->pix.cfg->fourcc == V4L2_PIX_FMT_GREY) {
rkisp1_write(cap->rkisp1,
- cap->buf.dummy.dma_addr,
- cap->config->mi.cb_base_ad_init);
+ cap->config->mi.cb_base_ad_init,
+ cap->buf.dummy.dma_addr);
rkisp1_write(cap->rkisp1,
- cap->buf.dummy.dma_addr,
- cap->config->mi.cr_base_ad_init);
+ cap->config->mi.cr_base_ad_init,
+ cap->buf.dummy.dma_addr);
} else {
rkisp1_write(cap->rkisp1,
- buff_addr[RKISP1_PLANE_CB],
- cap->config->mi.cb_base_ad_init);
+ cap->config->mi.cb_base_ad_init,
+ buff_addr[RKISP1_PLANE_CB]);
rkisp1_write(cap->rkisp1,
- buff_addr[RKISP1_PLANE_CR],
- cap->config->mi.cr_base_ad_init);
+ cap->config->mi.cr_base_ad_init,
+ buff_addr[RKISP1_PLANE_CR]);
}
} else {
/*
* Use the dummy space allocated by dma_alloc_coherent to
* throw data if there is no available buffer.
*/
- rkisp1_write(cap->rkisp1,
- cap->buf.dummy.dma_addr,
- cap->config->mi.y_base_ad_init);
- rkisp1_write(cap->rkisp1,
- cap->buf.dummy.dma_addr,
- cap->config->mi.cb_base_ad_init);
- rkisp1_write(cap->rkisp1,
- cap->buf.dummy.dma_addr,
- cap->config->mi.cr_base_ad_init);
+ rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init,
+ cap->buf.dummy.dma_addr);
+ rkisp1_write(cap->rkisp1, cap->config->mi.cb_base_ad_init,
+ cap->buf.dummy.dma_addr);
+ rkisp1_write(cap->rkisp1, cap->config->mi.cr_base_ad_init,
+ cap->buf.dummy.dma_addr);
}
/* Set plane offsets */
- rkisp1_write(cap->rkisp1, 0, cap->config->mi.y_offs_cnt_init);
- rkisp1_write(cap->rkisp1, 0, cap->config->mi.cb_offs_cnt_init);
- rkisp1_write(cap->rkisp1, 0, cap->config->mi.cr_offs_cnt_init);
+ rkisp1_write(cap->rkisp1, cap->config->mi.y_offs_cnt_init, 0);
+ rkisp1_write(cap->rkisp1, cap->config->mi.cb_offs_cnt_init, 0);
+ rkisp1_write(cap->rkisp1, cap->config->mi.cr_offs_cnt_init, 0);
}
/*
@@ -710,7 +705,7 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx)
if (!status)
return IRQ_NONE;
- rkisp1_write(rkisp1, status, RKISP1_CIF_MI_ICR);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, status);
for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) {
struct rkisp1_capture *cap = &rkisp1->capture_devs[i];
@@ -888,8 +883,8 @@ static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap)
*/
if (!other->is_streaming) {
/* force cfg update */
- rkisp1_write(rkisp1,
- RKISP1_CIF_MI_INIT_SOFT_UPD, RKISP1_CIF_MI_INIT);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT,
+ RKISP1_CIF_MI_INIT_SOFT_UPD);
rkisp1_set_next_buf(cap);
}
spin_unlock_irq(&cap->buf.lock);
@@ -931,11 +926,8 @@ static void rkisp1_pipeline_stream_disable(struct rkisp1_capture *cap)
* If the other capture is streaming, isp and sensor nodes shouldn't
* be disabled, skip them.
*/
- if (rkisp1->pipe.streaming_count < 2) {
- v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream,
- false);
+ if (rkisp1->pipe.streaming_count < 2)
v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false);
- }
v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream,
false);
@@ -971,15 +963,8 @@ static int rkisp1_pipeline_stream_enable(struct rkisp1_capture *cap)
if (ret)
goto err_disable_rsz;
- ret = v4l2_subdev_call(rkisp1->active_sensor->sd, video, s_stream,
- true);
- if (ret)
- goto err_disable_isp;
-
return 0;
-err_disable_isp:
- v4l2_subdev_call(&rkisp1->isp.sd, video, s_stream, false);
err_disable_rsz:
v4l2_subdev_call(&rkisp1->resizer_devs[cap->id].sd, video, s_stream,
false);
@@ -1253,11 +1238,8 @@ static int rkisp1_g_fmt_vid_cap_mplane(struct file *file, void *fh,
static int
rkisp1_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
{
- struct rkisp1_capture *cap_dev = video_drvdata(file);
- struct rkisp1_device *rkisp1 = cap_dev->rkisp1;
-
- strscpy(cap->driver, rkisp1->dev->driver->name, sizeof(cap->driver));
- strscpy(cap->card, rkisp1->dev->driver->name, sizeof(cap->card));
+ strscpy(cap->driver, RKISP1_DRIVER_NAME, sizeof(cap->driver));
+ strscpy(cap->card, RKISP1_DRIVER_NAME, sizeof(cap->card));
strscpy(cap->bus_info, RKISP1_BUS_INFO, sizeof(cap->bus_info));
return 0;
@@ -1302,8 +1284,16 @@ static int rkisp1_capture_link_validate(struct media_link *link)
if (sd_fmt.format.height != cap->pix.fmt.height ||
sd_fmt.format.width != cap->pix.fmt.width ||
- sd_fmt.format.code != fmt->mbus)
+ sd_fmt.format.code != fmt->mbus) {
+ dev_dbg(cap->rkisp1->dev,
+ "link '%s':%u -> '%s':%u not valid: 0x%04x/%ux%u != 0x%04x/%ux%u\n",
+ link->source->entity->name, link->source->index,
+ link->sink->entity->name, link->sink->index,
+ sd_fmt.format.code, sd_fmt.format.width,
+ sd_fmt.format.height, fmt->mbus, cap->pix.fmt.width,
+ cap->pix.fmt.height);
return -EPIPE;
+ }
return 0;
}
@@ -1326,8 +1316,12 @@ static const struct v4l2_file_operations rkisp1_fops = {
static void rkisp1_unregister_capture(struct rkisp1_capture *cap)
{
+ if (!video_is_registered(&cap->vnode.vdev))
+ return;
+
media_entity_cleanup(&cap->vnode.vdev.entity);
vb2_video_unregister_device(&cap->vnode.vdev);
+ mutex_destroy(&cap->vnode.vlock);
}
void rkisp1_capture_devs_unregister(struct rkisp1_device *rkisp1)
@@ -1381,27 +1375,31 @@ static int rkisp1_register_capture(struct rkisp1_capture *cap)
if (ret) {
dev_err(cap->rkisp1->dev,
"vb2 queue init failed (err=%d)\n", ret);
- return ret;
+ goto error;
}
vdev->queue = q;
+ ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
+ if (ret)
+ goto error;
+
ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (ret) {
dev_err(cap->rkisp1->dev,
"failed to register %s, ret=%d\n", vdev->name, ret);
- return ret;
+ goto error;
}
+
v4l2_info(v4l2_dev, "registered %s as /dev/video%d\n", vdev->name,
vdev->num);
- ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
- if (ret) {
- video_unregister_device(vdev);
- return ret;
- }
-
return 0;
+
+error:
+ media_entity_cleanup(&vdev->entity);
+ mutex_destroy(&node->vlock);
+ return ret;
}
static void
@@ -1436,26 +1434,21 @@ rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id)
int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1)
{
- struct rkisp1_capture *cap;
- unsigned int i, j;
+ unsigned int i;
int ret;
for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); i++) {
+ struct rkisp1_capture *cap = &rkisp1->capture_devs[i];
+
rkisp1_capture_init(rkisp1, i);
- cap = &rkisp1->capture_devs[i];
- cap->rkisp1 = rkisp1;
+
ret = rkisp1_register_capture(cap);
- if (ret)
- goto err_unreg_capture_devs;
+ if (ret) {
+ rkisp1_capture_devs_unregister(rkisp1);
+ return ret;
+ }
}
return 0;
-err_unreg_capture_devs:
- for (j = 0; j < i; j++) {
- cap = &rkisp1->capture_devs[j];
- rkisp1_unregister_capture(cap);
- }
-
- return ret;
}
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c
index cf889666e166..f956b90a407a 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.c
@@ -5,10 +5,153 @@
* Copyright (C) 2019 Collabora, Ltd.
*/
+#include <media/mipi-csi2.h>
#include <media/v4l2-rect.h>
#include "rkisp1-common.h"
+static const struct rkisp1_mbus_info rkisp1_formats[] = {
+ {
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .pixel_enc = V4L2_PIXEL_ENC_YUV,
+ .direction = RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW10,
+ .bayer_pat = RKISP1_RAW_RGGB,
+ .bus_width = 10,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW10,
+ .bayer_pat = RKISP1_RAW_BGGR,
+ .bus_width = 10,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW10,
+ .bayer_pat = RKISP1_RAW_GBRG,
+ .bus_width = 10,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW10,
+ .bayer_pat = RKISP1_RAW_GRBG,
+ .bus_width = 10,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW12,
+ .bayer_pat = RKISP1_RAW_RGGB,
+ .bus_width = 12,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW12,
+ .bayer_pat = RKISP1_RAW_BGGR,
+ .bus_width = 12,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW12,
+ .bayer_pat = RKISP1_RAW_GBRG,
+ .bus_width = 12,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW12,
+ .bayer_pat = RKISP1_RAW_GRBG,
+ .bus_width = 12,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW8,
+ .bayer_pat = RKISP1_RAW_RGGB,
+ .bus_width = 8,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW8,
+ .bayer_pat = RKISP1_RAW_BGGR,
+ .bus_width = 8,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW8,
+ .bayer_pat = RKISP1_RAW_GBRG,
+ .bus_width = 8,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .pixel_enc = V4L2_PIXEL_ENC_BAYER,
+ .mipi_dt = MIPI_CSI2_DT_RAW8,
+ .bayer_pat = RKISP1_RAW_GRBG,
+ .bus_width = 8,
+ .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .pixel_enc = V4L2_PIXEL_ENC_YUV,
+ .mipi_dt = MIPI_CSI2_DT_YUV422_8B,
+ .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR,
+ .bus_width = 16,
+ .direction = RKISP1_ISP_SD_SINK,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16,
+ .pixel_enc = V4L2_PIXEL_ENC_YUV,
+ .mipi_dt = MIPI_CSI2_DT_YUV422_8B,
+ .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB,
+ .bus_width = 16,
+ .direction = RKISP1_ISP_SD_SINK,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .pixel_enc = V4L2_PIXEL_ENC_YUV,
+ .mipi_dt = MIPI_CSI2_DT_YUV422_8B,
+ .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY,
+ .bus_width = 16,
+ .direction = RKISP1_ISP_SD_SINK,
+ }, {
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16,
+ .pixel_enc = V4L2_PIXEL_ENC_YUV,
+ .mipi_dt = MIPI_CSI2_DT_YUV422_8B,
+ .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY,
+ .bus_width = 16,
+ .direction = RKISP1_ISP_SD_SINK,
+ },
+};
+
+const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_index(unsigned int index)
+{
+ if (index >= ARRAY_SIZE(rkisp1_formats))
+ return NULL;
+
+ return &rkisp1_formats[index];
+}
+
+const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_code(u32 mbus_code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rkisp1_formats); i++) {
+ const struct rkisp1_mbus_info *fmt = &rkisp1_formats[i];
+
+ if (fmt->mbus_code == mbus_code)
+ return fmt;
+ }
+
+ return NULL;
+}
+
static const struct v4l2_rect rkisp1_sd_min_crop = {
.width = RKISP1_ISP_MIN_WIDTH,
.height = RKISP1_ISP_MIN_HEIGHT,
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
index d8fa3f1a5a85..8056997d5c29 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
@@ -23,18 +23,20 @@
#include "rkisp1-regs.h"
+struct dentry;
+
/*
- * flags on the 'direction' field in struct 'rkisp1_isp_mbus_info' that indicate
+ * flags on the 'direction' field in struct rkisp1_mbus_info' that indicate
* on which pad the media bus format is supported
*/
-#define RKISP1_ISP_SD_SRC BIT(0)
-#define RKISP1_ISP_SD_SINK BIT(1)
+#define RKISP1_ISP_SD_SRC BIT(0)
+#define RKISP1_ISP_SD_SINK BIT(1)
/* min and max values for the widths and heights of the entities */
-#define RKISP1_ISP_MAX_WIDTH 4032
-#define RKISP1_ISP_MAX_HEIGHT 3024
-#define RKISP1_ISP_MIN_WIDTH 32
-#define RKISP1_ISP_MIN_HEIGHT 32
+#define RKISP1_ISP_MAX_WIDTH 4032
+#define RKISP1_ISP_MAX_HEIGHT 3024
+#define RKISP1_ISP_MIN_WIDTH 32
+#define RKISP1_ISP_MIN_HEIGHT 32
#define RKISP1_RSZ_MP_SRC_MAX_WIDTH 4416
#define RKISP1_RSZ_MP_SRC_MAX_HEIGHT 3312
@@ -44,20 +46,20 @@
#define RKISP1_RSZ_SRC_MIN_HEIGHT 16
/* the default width and height of all the entities */
-#define RKISP1_DEFAULT_WIDTH 800
-#define RKISP1_DEFAULT_HEIGHT 600
+#define RKISP1_DEFAULT_WIDTH 800
+#define RKISP1_DEFAULT_HEIGHT 600
-#define RKISP1_DRIVER_NAME "rkisp1"
-#define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME
+#define RKISP1_DRIVER_NAME "rkisp1"
+#define RKISP1_BUS_INFO "platform:" RKISP1_DRIVER_NAME
/* maximum number of clocks */
-#define RKISP1_MAX_BUS_CLK 8
+#define RKISP1_MAX_BUS_CLK 8
/* a bitmask of the ready stats */
-#define RKISP1_STATS_MEAS_MASK (RKISP1_CIF_ISP_AWB_DONE | \
- RKISP1_CIF_ISP_AFM_FIN | \
- RKISP1_CIF_ISP_EXP_END | \
- RKISP1_CIF_ISP_HIST_MEASURE_RDY)
+#define RKISP1_STATS_MEAS_MASK (RKISP1_CIF_ISP_AWB_DONE | \
+ RKISP1_CIF_ISP_AFM_FIN | \
+ RKISP1_CIF_ISP_EXP_END | \
+ RKISP1_CIF_ISP_HIST_MEASURE_RDY)
/* enum for the resizer pads */
enum rkisp1_rsz_pad {
@@ -66,6 +68,13 @@ enum rkisp1_rsz_pad {
RKISP1_RSZ_PAD_MAX
};
+/* enum for the csi receiver pads */
+enum rkisp1_csi_pad {
+ RKISP1_CSI_PAD_SINK,
+ RKISP1_CSI_PAD_SRC,
+ RKISP1_CSI_PAD_NUM
+};
+
/* enum for the capture id */
enum rkisp1_stream_id {
RKISP1_MAINPATH,
@@ -90,25 +99,89 @@ enum rkisp1_isp_pad {
};
/*
+ * enum rkisp1_feature - ISP features
+ *
+ * @RKISP1_FEATURE_MIPI_CSI2: The ISP has an internal MIPI CSI-2 receiver
+ *
+ * The ISP features are stored in a bitmask in &rkisp1_info.features and allow
+ * the driver to implement support for features present in some ISP versions
+ * only.
+ */
+enum rkisp1_feature {
+ RKISP1_FEATURE_MIPI_CSI2 = BIT(0),
+};
+
+/*
+ * struct rkisp1_info - Model-specific ISP Information
+ *
+ * @clks: array of ISP clock names
+ * @clk_size: number of entries in the @clks array
+ * @isrs: array of ISP interrupt descriptors
+ * @isr_size: number of entries in the @isrs array
+ * @isp_ver: ISP version
+ * @features: bitmask of rkisp1_feature features implemented by the ISP
+ *
+ * This structure contains information about the ISP specific to a particular
+ * ISP model, version, or integration in a particular SoC.
+ */
+struct rkisp1_info {
+ const char * const *clks;
+ unsigned int clk_size;
+ const struct rkisp1_isr_data *isrs;
+ unsigned int isr_size;
+ enum rkisp1_cif_isp_version isp_ver;
+ unsigned int features;
+};
+
+/*
* struct rkisp1_sensor_async - A container for the v4l2_async_subdev to add to the notifier
* of the v4l2-async API
*
* @asd: async_subdev variable for the sensor
+ * @index: index of the sensor (counting sensor found in DT)
+ * @source_ep: fwnode for the sensor source endpoint
* @lanes: number of lanes
* @mbus_type: type of bus (currently only CSI2 is supported)
* @mbus_flags: media bus (V4L2_MBUS_*) flags
* @sd: a pointer to v4l2_subdev struct of the sensor
* @pixel_rate_ctrl: pixel rate of the sensor, used to initialize the phy
- * @dphy: a pointer to the phy
+ * @port: port number (0: MIPI, 1: Parallel)
*/
struct rkisp1_sensor_async {
struct v4l2_async_subdev asd;
+ unsigned int index;
+ struct fwnode_handle *source_ep;
unsigned int lanes;
enum v4l2_mbus_type mbus_type;
unsigned int mbus_flags;
struct v4l2_subdev *sd;
struct v4l2_ctrl *pixel_rate_ctrl;
+ unsigned int port;
+};
+
+/*
+ * struct rkisp1_csi - CSI receiver subdev
+ *
+ * @rkisp1: pointer to the rkisp1 device
+ * @dphy: a pointer to the phy
+ * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt)
+ * @sd: v4l2_subdev variable
+ * @pads: media pads
+ * @pad_cfg: configurations for the pads
+ * @sink_fmt: input format
+ * @lock: protects pad_cfg and sink_fmt
+ * @source: source in-use, set when starting streaming
+ */
+struct rkisp1_csi {
+ struct rkisp1_device *rkisp1;
struct phy *dphy;
+ bool is_dphy_errctrl_disabled;
+ struct v4l2_subdev sd;
+ struct media_pad pads[RKISP1_CSI_PAD_NUM];
+ struct v4l2_subdev_pad_config pad_cfg[RKISP1_CSI_PAD_NUM];
+ const struct rkisp1_mbus_info *sink_fmt;
+ struct mutex lock;
+ struct v4l2_subdev *source;
};
/*
@@ -121,17 +194,16 @@ struct rkisp1_sensor_async {
* @sink_fmt: input format
* @src_fmt: output format
* @ops_lock: ops serialization
- * @is_dphy_errctrl_disabled: if dphy errctrl is disabled (avoid endless interrupt)
* @frame_sequence: used to synchronize frame_id between video devices.
*/
struct rkisp1_isp {
struct v4l2_subdev sd;
+ struct rkisp1_device *rkisp1;
struct media_pad pads[RKISP1_ISP_PAD_MAX];
struct v4l2_subdev_pad_config pad_cfg[RKISP1_ISP_PAD_MAX];
- const struct rkisp1_isp_mbus_info *sink_fmt;
- const struct rkisp1_isp_mbus_info *src_fmt;
+ const struct rkisp1_mbus_info *sink_fmt;
+ const struct rkisp1_mbus_info *src_fmt;
struct mutex ops_lock; /* serialize the subdevice ops */
- bool is_dphy_errctrl_disabled;
__u32 frame_sequence;
};
@@ -313,6 +385,7 @@ struct rkisp1_params {
* struct rkisp1_resizer - Resizer subdev
*
* @sd: v4l2_subdev variable
+ * @regs_base: base register address offset
* @id: id of the resizer, one of RKISP1_SELFPATH, RKISP1_MAINPATH
* @rkisp1: pointer to the rkisp1 device
* @pads: media pads
@@ -323,6 +396,7 @@ struct rkisp1_params {
*/
struct rkisp1_resizer {
struct v4l2_subdev sd;
+ u32 regs_base;
enum rkisp1_stream_id id;
struct rkisp1_device *rkisp1;
struct media_pad pads[RKISP1_RSZ_PAD_MAX];
@@ -373,7 +447,8 @@ struct rkisp1_debug {
* @v4l2_dev: v4l2_device variable
* @media_dev: media_device variable
* @notifier: a notifier to register on the v4l2-async API to be notified on the sensor
- * @active_sensor: sensor in-use, set when streaming on
+ * @source: source subdev in-use, set when starting streaming
+ * @csi: internal CSI-2 receiver
* @isp: ISP sub-device
* @resizer_devs: resizer sub-devices
* @capture_devs: capture devices
@@ -382,6 +457,7 @@ struct rkisp1_debug {
* @pipe: media pipeline
* @stream_lock: serializes {start/stop}_streaming callbacks between the capture devices.
* @debug: debug params to be exposed on debugfs
+ * @info: version-specific ISP information
*/
struct rkisp1_device {
void __iomem *base_addr;
@@ -391,7 +467,8 @@ struct rkisp1_device {
struct v4l2_device v4l2_dev;
struct media_device media_dev;
struct v4l2_async_notifier notifier;
- struct rkisp1_sensor_async *active_sensor;
+ struct v4l2_subdev *source;
+ struct rkisp1_csi csi;
struct rkisp1_isp isp;
struct rkisp1_resizer resizer_devs[2];
struct rkisp1_capture capture_devs[2];
@@ -400,11 +477,12 @@ struct rkisp1_device {
struct media_pipeline pipe;
struct mutex stream_lock; /* serialize {start/stop}_streaming cb between capture devices */
struct rkisp1_debug debug;
+ const struct rkisp1_info *info;
};
/*
- * struct rkisp1_isp_mbus_info - ISP media bus info, Translates media bus code to hardware
- * format values
+ * struct rkisp1_mbus_info - ISP media bus info, Translates media bus code to hardware
+ * format values
*
* @mbus_code: media bus code
* @pixel_enc: pixel encoding
@@ -414,7 +492,7 @@ struct rkisp1_device {
* @bayer_pat: bayer pattern
* @direction: a bitmask of the flags indicating on which pad the format is supported on
*/
-struct rkisp1_isp_mbus_info {
+struct rkisp1_mbus_info {
u32 mbus_code;
enum v4l2_pixel_encoding pixel_enc;
u32 mipi_dt;
@@ -425,7 +503,7 @@ struct rkisp1_isp_mbus_info {
};
static inline void
-rkisp1_write(struct rkisp1_device *rkisp1, u32 val, unsigned int addr)
+rkisp1_write(struct rkisp1_device *rkisp1, unsigned int addr, u32 val)
{
writel(val, rkisp1->base_addr + addr);
}
@@ -447,6 +525,13 @@ int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap,
struct v4l2_subdev_mbus_code_enum *code);
/*
+ * rkisp1_mbus_info_get_by_index - Retrieve the ith supported mbus info
+ *
+ * @index: index of the mbus info to fetch
+ */
+const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_index(unsigned int index);
+
+/*
* rkisp1_sd_adjust_crop_rect - adjust a rectangle to fit into another rectangle.
*
* @crop: rectangle to adjust.
@@ -465,11 +550,11 @@ void rkisp1_sd_adjust_crop(struct v4l2_rect *crop,
const struct v4l2_mbus_framefmt *bounds);
/*
- * rkisp1_isp_mbus_info - get the isp info of the media bus code
+ * rkisp1_mbus_info_get_by_code - get the isp info of the media bus code
*
* @mbus_code: the media bus code
*/
-const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code);
+const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_code(u32 mbus_code);
/* rkisp1_params_configure - configure the params when stream starts.
* This function is called by the isp entity upon stream starts.
@@ -493,7 +578,7 @@ void rkisp1_params_disable(struct rkisp1_params *params);
/* irq handlers */
irqreturn_t rkisp1_isp_isr(int irq, void *ctx);
-irqreturn_t rkisp1_mipi_isr(int irq, void *ctx);
+irqreturn_t rkisp1_csi_isr(int irq, void *ctx);
irqreturn_t rkisp1_capture_isr(int irq, void *ctx);
void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris);
void rkisp1_params_isr(struct rkisp1_device *rkisp1);
@@ -514,4 +599,16 @@ void rkisp1_stats_unregister(struct rkisp1_device *rkisp1);
int rkisp1_params_register(struct rkisp1_device *rkisp1);
void rkisp1_params_unregister(struct rkisp1_device *rkisp1);
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+void rkisp1_debug_init(struct rkisp1_device *rkisp1);
+void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1);
+#else
+static inline void rkisp1_debug_init(struct rkisp1_device *rkisp1)
+{
+}
+static inline void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1)
+{
+}
+#endif
+
#endif /* _RKISP1_COMMON_H */
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c
new file mode 100644
index 000000000000..d7acc94e10f8
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c
@@ -0,0 +1,536 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Rockchip ISP1 Driver - CSI-2 Receiver
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ * Copyright (C) 2022 Ideas on Board
+ *
+ * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
+ * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/lockdep.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-mipi-dphy.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+
+#include "rkisp1-common.h"
+#include "rkisp1-csi.h"
+
+#define RKISP1_CSI_DEV_NAME RKISP1_DRIVER_NAME "_csi"
+
+#define RKISP1_CSI_DEF_FMT MEDIA_BUS_FMT_SRGGB10_1X10
+
+static inline struct rkisp1_csi *to_rkisp1_csi(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct rkisp1_csi, sd);
+}
+
+static struct v4l2_mbus_framefmt *
+rkisp1_csi_get_pad_fmt(struct rkisp1_csi *csi,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad, u32 which)
+{
+ struct v4l2_subdev_state state = {
+ .pads = csi->pad_cfg
+ };
+
+ lockdep_assert_held(&csi->lock);
+
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad);
+ else
+ return v4l2_subdev_get_try_format(&csi->sd, &state, pad);
+}
+
+int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd,
+ struct rkisp1_sensor_async *s_asd,
+ unsigned int source_pad)
+{
+ struct rkisp1_csi *csi = &rkisp1->csi;
+ int ret;
+
+ s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler,
+ V4L2_CID_PIXEL_RATE);
+ if (!s_asd->pixel_rate_ctrl) {
+ dev_err(rkisp1->dev, "No pixel rate control in subdev %s\n",
+ sd->name);
+ return -EINVAL;
+ }
+
+ /* Create the link from the sensor to the CSI receiver. */
+ ret = media_create_pad_link(&sd->entity, source_pad,
+ &csi->sd.entity, RKISP1_CSI_PAD_SINK,
+ !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0);
+ if (ret) {
+ dev_err(csi->rkisp1->dev, "failed to link src pad of %s\n",
+ sd->name);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rkisp1_csi_config(struct rkisp1_csi *csi,
+ const struct rkisp1_sensor_async *sensor)
+{
+ struct rkisp1_device *rkisp1 = csi->rkisp1;
+ unsigned int lanes = sensor->lanes;
+ u32 mipi_ctrl;
+
+ if (lanes < 1 || lanes > 4)
+ return -EINVAL;
+
+ mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) |
+ RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) |
+ RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP |
+ RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA;
+
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL, mipi_ctrl);
+
+ /* V12 could also use a newer csi2-host, but we don't want that yet */
+ if (rkisp1->info->isp_ver == RKISP1_V12)
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CSI0_CTRL0, 0);
+
+ /* Configure Data Type and Virtual Channel */
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL,
+ RKISP1_CIF_MIPI_DATA_SEL_DT(csi->sink_fmt->mipi_dt) |
+ RKISP1_CIF_MIPI_DATA_SEL_VC(0));
+
+ /* Clear MIPI interrupts */
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0);
+
+ /*
+ * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for
+ * isp bus may be dead when switch isp.
+ */
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC,
+ RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI |
+ RKISP1_CIF_MIPI_ERR_DPHY |
+ RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) |
+ RKISP1_CIF_MIPI_ADD_DATA_OVFLW);
+
+ dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n"
+ " MIPI_IMG_DATA_SEL 0x%08x\n"
+ " MIPI_STATUS 0x%08x\n"
+ " MIPI_IMSC 0x%08x\n",
+ rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL),
+ rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL),
+ rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS),
+ rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC));
+
+ return 0;
+}
+
+static void rkisp1_csi_enable(struct rkisp1_csi *csi)
+{
+ struct rkisp1_device *rkisp1 = csi->rkisp1;
+ u32 val;
+
+ val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL,
+ val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA);
+}
+
+static void rkisp1_csi_disable(struct rkisp1_csi *csi)
+{
+ struct rkisp1_device *rkisp1 = csi->rkisp1;
+ u32 val;
+
+ /* Mask and clear interrupts. */
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, ~0);
+
+ val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_CTRL,
+ val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA));
+}
+
+static int rkisp1_csi_start(struct rkisp1_csi *csi,
+ const struct rkisp1_sensor_async *sensor)
+{
+ struct rkisp1_device *rkisp1 = csi->rkisp1;
+ union phy_configure_opts opts;
+ struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
+ s64 pixel_clock;
+ int ret;
+
+ ret = rkisp1_csi_config(csi, sensor);
+ if (ret)
+ return ret;
+
+ pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl);
+ if (!pixel_clock) {
+ dev_err(rkisp1->dev, "Invalid pixel rate value\n");
+ return -EINVAL;
+ }
+
+ phy_mipi_dphy_get_default_config(pixel_clock, csi->sink_fmt->bus_width,
+ sensor->lanes, cfg);
+ phy_set_mode(csi->dphy, PHY_MODE_MIPI_DPHY);
+ phy_configure(csi->dphy, &opts);
+ phy_power_on(csi->dphy);
+
+ rkisp1_csi_enable(csi);
+
+ /*
+ * CIF spec says to wait for sufficient time after enabling
+ * the MIPI interface and before starting the sensor output.
+ */
+ usleep_range(1000, 1200);
+
+ return 0;
+}
+
+static void rkisp1_csi_stop(struct rkisp1_csi *csi)
+{
+ rkisp1_csi_disable(csi);
+
+ phy_power_off(csi->dphy);
+}
+
+irqreturn_t rkisp1_csi_isr(int irq, void *ctx)
+{
+ struct device *dev = ctx;
+ struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
+ u32 val, status;
+
+ status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS);
+ if (!status)
+ return IRQ_NONE;
+
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_ICR, status);
+
+ /*
+ * Disable DPHY errctrl interrupt, because this dphy
+ * erctrl signal is asserted until the next changes
+ * of line state. This time is may be too long and cpu
+ * is hold in this interrupt.
+ */
+ if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) {
+ val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC,
+ val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f));
+ rkisp1->csi.is_dphy_errctrl_disabled = true;
+ }
+
+ /*
+ * Enable DPHY errctrl interrupt again, if mipi have receive
+ * the whole frame without any error.
+ */
+ if (status == RKISP1_CIF_MIPI_FRAME_END) {
+ /*
+ * Enable DPHY errctrl interrupt again, if mipi have receive
+ * the whole frame without any error.
+ */
+ if (rkisp1->csi.is_dphy_errctrl_disabled) {
+ val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
+ val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f);
+ rkisp1_write(rkisp1, RKISP1_CIF_MIPI_IMSC, val);
+ rkisp1->csi.is_dphy_errctrl_disabled = false;
+ }
+ } else {
+ rkisp1->debug.mipi_error++;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* ----------------------------------------------------------------------------
+ * Subdev pad operations
+ */
+
+static int rkisp1_csi_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ struct rkisp1_csi *csi = to_rkisp1_csi(sd);
+ unsigned int i;
+ int pos = 0;
+
+ if (code->pad == RKISP1_CSI_PAD_SRC) {
+ const struct v4l2_mbus_framefmt *sink_fmt;
+
+ if (code->index)
+ return -EINVAL;
+
+ mutex_lock(&csi->lock);
+
+ sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state,
+ RKISP1_CSI_PAD_SINK,
+ code->which);
+ code->code = sink_fmt->code;
+
+ mutex_unlock(&csi->lock);
+
+ return 0;
+ }
+
+ for (i = 0; ; i++) {
+ const struct rkisp1_mbus_info *fmt =
+ rkisp1_mbus_info_get_by_index(i);
+
+ if (!fmt)
+ return -EINVAL;
+
+ if (!(fmt->direction & RKISP1_ISP_SD_SINK))
+ continue;
+
+ if (code->index == pos) {
+ code->code = fmt->mbus_code;
+ return 0;
+ }
+
+ pos++;
+ }
+
+ return -EINVAL;
+}
+
+static int rkisp1_csi_init_config(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
+{
+ struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+ sink_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+ RKISP1_CSI_PAD_SINK);
+ src_fmt = v4l2_subdev_get_try_format(sd, sd_state,
+ RKISP1_CSI_PAD_SRC);
+
+ sink_fmt->width = RKISP1_DEFAULT_WIDTH;
+ sink_fmt->height = RKISP1_DEFAULT_HEIGHT;
+ sink_fmt->field = V4L2_FIELD_NONE;
+ sink_fmt->code = RKISP1_CSI_DEF_FMT;
+
+ *src_fmt = *sink_fmt;
+
+ return 0;
+}
+
+static int rkisp1_csi_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct rkisp1_csi *csi = to_rkisp1_csi(sd);
+
+ mutex_lock(&csi->lock);
+ fmt->format = *rkisp1_csi_get_pad_fmt(csi, sd_state, fmt->pad,
+ fmt->which);
+ mutex_unlock(&csi->lock);
+
+ return 0;
+}
+
+static int rkisp1_csi_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct rkisp1_csi *csi = to_rkisp1_csi(sd);
+ const struct rkisp1_mbus_info *mbus_info;
+ struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
+
+ /* The format on the source pad always matches the sink pad. */
+ if (fmt->pad == RKISP1_CSI_PAD_SRC)
+ return rkisp1_csi_get_fmt(sd, sd_state, fmt);
+
+ mutex_lock(&csi->lock);
+
+ sink_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SINK,
+ fmt->which);
+
+ sink_fmt->code = fmt->format.code;
+
+ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
+ if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) {
+ sink_fmt->code = RKISP1_CSI_DEF_FMT;
+ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
+ }
+
+ sink_fmt->width = clamp_t(u32, fmt->format.width,
+ RKISP1_ISP_MIN_WIDTH,
+ RKISP1_ISP_MAX_WIDTH);
+ sink_fmt->height = clamp_t(u32, fmt->format.height,
+ RKISP1_ISP_MIN_HEIGHT,
+ RKISP1_ISP_MAX_HEIGHT);
+
+ fmt->format = *sink_fmt;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ csi->sink_fmt = mbus_info;
+
+ /* Propagate the format to the source pad. */
+ src_fmt = rkisp1_csi_get_pad_fmt(csi, sd_state, RKISP1_CSI_PAD_SRC,
+ fmt->which);
+ *src_fmt = *sink_fmt;
+
+ mutex_unlock(&csi->lock);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------------
+ * Subdev video operations
+ */
+
+static int rkisp1_csi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct rkisp1_csi *csi = to_rkisp1_csi(sd);
+ struct rkisp1_device *rkisp1 = csi->rkisp1;
+ struct rkisp1_sensor_async *source_asd;
+ struct media_pad *source_pad;
+ struct v4l2_subdev *source;
+ int ret;
+
+ if (!enable) {
+ v4l2_subdev_call(csi->source, video, s_stream, false);
+
+ rkisp1_csi_stop(csi);
+
+ return 0;
+ }
+
+ source_pad = media_entity_remote_source_pad_unique(&sd->entity);
+ if (IS_ERR(source_pad)) {
+ dev_dbg(rkisp1->dev, "Failed to get source for CSI: %ld\n",
+ PTR_ERR(source_pad));
+ return -EPIPE;
+ }
+
+ source = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (!source) {
+ /* This should really not happen, so is not worth a message. */
+ return -EPIPE;
+ }
+
+ source_asd = container_of(source->asd, struct rkisp1_sensor_async, asd);
+ if (source_asd->mbus_type != V4L2_MBUS_CSI2_DPHY)
+ return -EINVAL;
+
+ mutex_lock(&csi->lock);
+ ret = rkisp1_csi_start(csi, source_asd);
+ mutex_unlock(&csi->lock);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_call(source, video, s_stream, true);
+ if (ret) {
+ rkisp1_csi_stop(csi);
+ return ret;
+ }
+
+ csi->source = source;
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------------
+ * Registration
+ */
+
+static const struct media_entity_operations rkisp1_csi_media_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static const struct v4l2_subdev_video_ops rkisp1_csi_video_ops = {
+ .s_stream = rkisp1_csi_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops rkisp1_csi_pad_ops = {
+ .enum_mbus_code = rkisp1_csi_enum_mbus_code,
+ .init_cfg = rkisp1_csi_init_config,
+ .get_fmt = rkisp1_csi_get_fmt,
+ .set_fmt = rkisp1_csi_set_fmt,
+};
+
+static const struct v4l2_subdev_ops rkisp1_csi_ops = {
+ .video = &rkisp1_csi_video_ops,
+ .pad = &rkisp1_csi_pad_ops,
+};
+
+int rkisp1_csi_register(struct rkisp1_device *rkisp1)
+{
+ struct rkisp1_csi *csi = &rkisp1->csi;
+ struct v4l2_subdev_state state = {};
+ struct media_pad *pads;
+ struct v4l2_subdev *sd;
+ int ret;
+
+ csi->rkisp1 = rkisp1;
+ mutex_init(&csi->lock);
+
+ sd = &csi->sd;
+ v4l2_subdev_init(sd, &rkisp1_csi_ops);
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->entity.ops = &rkisp1_csi_media_ops;
+ sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ sd->owner = THIS_MODULE;
+ strscpy(sd->name, RKISP1_CSI_DEV_NAME, sizeof(sd->name));
+
+ pads = csi->pads;
+ pads[RKISP1_CSI_PAD_SINK].flags = MEDIA_PAD_FL_SINK |
+ MEDIA_PAD_FL_MUST_CONNECT;
+ pads[RKISP1_CSI_PAD_SRC].flags = MEDIA_PAD_FL_SOURCE |
+ MEDIA_PAD_FL_MUST_CONNECT;
+
+ csi->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_CSI_DEF_FMT);
+
+ ret = media_entity_pads_init(&sd->entity, RKISP1_CSI_PAD_NUM, pads);
+ if (ret)
+ goto error;
+
+ state.pads = csi->pad_cfg;
+ rkisp1_csi_init_config(sd, &state);
+
+ ret = v4l2_device_register_subdev(&csi->rkisp1->v4l2_dev, sd);
+ if (ret) {
+ dev_err(sd->dev, "Failed to register csi receiver subdev\n");
+ goto error;
+ }
+
+ return 0;
+
+error:
+ media_entity_cleanup(&sd->entity);
+ mutex_destroy(&csi->lock);
+ csi->rkisp1 = NULL;
+ return ret;
+}
+
+void rkisp1_csi_unregister(struct rkisp1_device *rkisp1)
+{
+ struct rkisp1_csi *csi = &rkisp1->csi;
+
+ if (!csi->rkisp1)
+ return;
+
+ v4l2_device_unregister_subdev(&csi->sd);
+ media_entity_cleanup(&csi->sd.entity);
+ mutex_destroy(&csi->lock);
+}
+
+int rkisp1_csi_init(struct rkisp1_device *rkisp1)
+{
+ struct rkisp1_csi *csi = &rkisp1->csi;
+
+ csi->rkisp1 = rkisp1;
+
+ csi->dphy = devm_phy_get(rkisp1->dev, "dphy");
+ if (IS_ERR(csi->dphy))
+ return dev_err_probe(rkisp1->dev, PTR_ERR(csi->dphy),
+ "Couldn't get the MIPI D-PHY\n");
+
+ phy_init(csi->dphy);
+
+ return 0;
+}
+
+void rkisp1_csi_cleanup(struct rkisp1_device *rkisp1)
+{
+ struct rkisp1_csi *csi = &rkisp1->csi;
+
+ phy_exit(csi->dphy);
+}
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h
new file mode 100644
index 000000000000..1f5f2af31a7d
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Rockchip ISP1 Driver - CSI-2 Receiver
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ * Copyright (C) 2022 Ideas on Board
+ *
+ * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
+ * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
+ */
+#ifndef _RKISP1_CSI_H
+#define _RKISP1_CSI_H
+
+struct rkisp1_csi;
+struct rkisp1_device;
+struct rkisp1_sensor_async;
+
+int rkisp1_csi_init(struct rkisp1_device *rkisp1);
+void rkisp1_csi_cleanup(struct rkisp1_device *rkisp1);
+
+int rkisp1_csi_register(struct rkisp1_device *rkisp1);
+void rkisp1_csi_unregister(struct rkisp1_device *rkisp1);
+
+int rkisp1_csi_link_sensor(struct rkisp1_device *rkisp1, struct v4l2_subdev *sd,
+ struct rkisp1_sensor_async *s_asd,
+ unsigned int source_pad);
+
+#endif /* _RKISP1_CSI_H */
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c
new file mode 100644
index 000000000000..71df3dc95e6f
--- /dev/null
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Rockchip ISP1 Driver - Base driver
+ *
+ * Copyright (C) 2019 Collabora, Ltd.
+ *
+ * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
+ * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/minmax.h>
+#include <linux/pm_runtime.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+
+#include "rkisp1-common.h"
+#include "rkisp1-regs.h"
+
+struct rkisp1_debug_register {
+ u32 reg;
+ u32 shd;
+ const char * const name;
+};
+
+#define RKISP1_DEBUG_REG(name) { RKISP1_CIF_##name, 0, #name }
+#define RKISP1_DEBUG_SHD_REG(name) { \
+ RKISP1_CIF_##name, RKISP1_CIF_##name##_SHD, #name \
+}
+
+/* Keep this up-to-date when adding new registers. */
+#define RKISP1_MAX_REG_LENGTH 21
+
+static int rkisp1_debug_dump_regs(struct rkisp1_device *rkisp1,
+ struct seq_file *m, unsigned int offset,
+ const struct rkisp1_debug_register *regs)
+{
+ const int width = RKISP1_MAX_REG_LENGTH;
+ u32 val, shd;
+ int ret;
+
+ ret = pm_runtime_get_if_in_use(rkisp1->dev);
+ if (ret <= 0)
+ return ret ? : -ENODATA;
+
+ for (; regs->name; ++regs) {
+ val = rkisp1_read(rkisp1, offset + regs->reg);
+
+ if (regs->shd) {
+ shd = rkisp1_read(rkisp1, offset + regs->shd);
+ seq_printf(m, "%*s: 0x%08x/0x%08x\n", width, regs->name,
+ val, shd);
+ } else {
+ seq_printf(m, "%*s: 0x%08x\n", width, regs->name, val);
+ }
+ }
+
+ pm_runtime_put(rkisp1->dev);
+
+ return 0;
+}
+
+static int rkisp1_debug_dump_core_regs_show(struct seq_file *m, void *p)
+{
+ static const struct rkisp1_debug_register registers[] = {
+ RKISP1_DEBUG_REG(VI_CCL),
+ RKISP1_DEBUG_REG(VI_ICCL),
+ RKISP1_DEBUG_REG(VI_IRCL),
+ RKISP1_DEBUG_REG(VI_DPCL),
+ RKISP1_DEBUG_REG(MI_CTRL),
+ RKISP1_DEBUG_REG(MI_BYTE_CNT),
+ RKISP1_DEBUG_REG(MI_CTRL_SHD),
+ RKISP1_DEBUG_REG(MI_RIS),
+ RKISP1_DEBUG_REG(MI_STATUS),
+ RKISP1_DEBUG_REG(MI_DMA_CTRL),
+ RKISP1_DEBUG_REG(MI_DMA_STATUS),
+ { /* Sentinel */ },
+ };
+ struct rkisp1_device *rkisp1 = m->private;
+
+ return rkisp1_debug_dump_regs(rkisp1, m, 0, registers);
+}
+DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_core_regs);
+
+static int rkisp1_debug_dump_isp_regs_show(struct seq_file *m, void *p)
+{
+ static const struct rkisp1_debug_register registers[] = {
+ RKISP1_DEBUG_REG(ISP_CTRL),
+ RKISP1_DEBUG_REG(ISP_ACQ_PROP),
+ RKISP1_DEBUG_REG(ISP_FLAGS_SHD),
+ RKISP1_DEBUG_REG(ISP_RIS),
+ RKISP1_DEBUG_REG(ISP_ERR),
+ { /* Sentinel */ },
+ };
+ struct rkisp1_device *rkisp1 = m->private;
+
+ return rkisp1_debug_dump_regs(rkisp1, m, 0, registers);
+}
+DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_isp_regs);
+
+static int rkisp1_debug_dump_rsz_regs_show(struct seq_file *m, void *p)
+{
+ static const struct rkisp1_debug_register registers[] = {
+ RKISP1_DEBUG_SHD_REG(RSZ_CTRL),
+ RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HY),
+ RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCB),
+ RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCR),
+ RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VY),
+ RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VC),
+ RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HY),
+ RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HC),
+ RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VY),
+ RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VC),
+ { /* Sentinel */ },
+ };
+ struct rkisp1_resizer *rsz = m->private;
+
+ return rkisp1_debug_dump_regs(rsz->rkisp1, m, rsz->regs_base, registers);
+}
+DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_rsz_regs);
+
+static int rkisp1_debug_dump_mi_mp_show(struct seq_file *m, void *p)
+{
+ static const struct rkisp1_debug_register registers[] = {
+ RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT),
+ RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT2),
+ RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_SHD),
+ RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT),
+ RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT),
+ RKISP1_DEBUG_REG(MI_MP_Y_SIZE_SHD),
+ RKISP1_DEBUG_REG(MI_MP_Y_OFFS_CNT_SHD),
+ { /* Sentinel */ },
+ };
+ struct rkisp1_device *rkisp1 = m->private;
+
+ return rkisp1_debug_dump_regs(rkisp1, m, 0, registers);
+}
+DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_mi_mp);
+
+#define RKISP1_DEBUG_DATA_COUNT_BINS 32
+#define RKISP1_DEBUG_DATA_COUNT_STEP (4096 / RKISP1_DEBUG_DATA_COUNT_BINS)
+
+static int rkisp1_debug_input_status_show(struct seq_file *m, void *p)
+{
+ struct rkisp1_device *rkisp1 = m->private;
+ u16 data_count[RKISP1_DEBUG_DATA_COUNT_BINS] = { };
+ unsigned int hsync_count = 0;
+ unsigned int vsync_count = 0;
+ unsigned int i;
+ u32 data;
+ u32 val;
+ int ret;
+
+ ret = pm_runtime_get_if_in_use(rkisp1->dev);
+ if (ret <= 0)
+ return ret ? : -ENODATA;
+
+ /* Sample the ISP input port status 10000 times with a 1µs interval. */
+ for (i = 0; i < 10000; ++i) {
+ val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_FLAGS_SHD);
+
+ data = (val & RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_MASK)
+ >> RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_SHIFT;
+ data_count[data / RKISP1_DEBUG_DATA_COUNT_STEP]++;
+
+ if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_HSYNC)
+ hsync_count++;
+ if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_VSYNC)
+ vsync_count++;
+
+ udelay(1);
+ }
+
+ pm_runtime_put(rkisp1->dev);
+
+ seq_printf(m, "vsync: %u, hsync: %u\n", vsync_count, hsync_count);
+ seq_puts(m, "data:\n");
+ for (i = 0; i < ARRAY_SIZE(data_count); ++i)
+ seq_printf(m, "- [%04u:%04u]: %u\n",
+ i * RKISP1_DEBUG_DATA_COUNT_STEP,
+ (i + 1) * RKISP1_DEBUG_DATA_COUNT_STEP - 1,
+ data_count[i]);
+
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_input_status);
+
+void rkisp1_debug_init(struct rkisp1_device *rkisp1)
+{
+ struct rkisp1_debug *debug = &rkisp1->debug;
+ struct dentry *regs_dir;
+
+ debug->debugfs_dir = debugfs_create_dir(dev_name(rkisp1->dev), NULL);
+
+ debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir,
+ &debug->data_loss);
+ debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir,
+ &debug->outform_size_error);
+ debugfs_create_ulong("img_stabilization_size_error", 0444,
+ debug->debugfs_dir,
+ &debug->img_stabilization_size_error);
+ debugfs_create_ulong("inform_size_error", 0444, debug->debugfs_dir,
+ &debug->inform_size_error);
+ debugfs_create_ulong("irq_delay", 0444, debug->debugfs_dir,
+ &debug->irq_delay);
+ debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir,
+ &debug->mipi_error);
+ debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir,
+ &debug->stats_error);
+ debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir,
+ &debug->stop_timeout[RKISP1_MAINPATH]);
+ debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir,
+ &debug->stop_timeout[RKISP1_SELFPATH]);
+ debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir,
+ &debug->frame_drop[RKISP1_MAINPATH]);
+ debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir,
+ &debug->frame_drop[RKISP1_SELFPATH]);
+ debugfs_create_file("input_status", 0444, debug->debugfs_dir, rkisp1,
+ &rkisp1_debug_input_status_fops);
+
+ regs_dir = debugfs_create_dir("regs", debug->debugfs_dir);
+
+ debugfs_create_file("core", 0444, regs_dir, rkisp1,
+ &rkisp1_debug_dump_core_regs_fops);
+ debugfs_create_file("isp", 0444, regs_dir, rkisp1,
+ &rkisp1_debug_dump_isp_regs_fops);
+ debugfs_create_file("mrsz", 0444, regs_dir,
+ &rkisp1->resizer_devs[RKISP1_MAINPATH],
+ &rkisp1_debug_dump_rsz_regs_fops);
+ debugfs_create_file("srsz", 0444, regs_dir,
+ &rkisp1->resizer_devs[RKISP1_SELFPATH],
+ &rkisp1_debug_dump_rsz_regs_fops);
+
+ debugfs_create_file("mi_mp", 0444, regs_dir, rkisp1,
+ &rkisp1_debug_dump_mi_mp_fops);
+}
+
+void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1)
+{
+ debugfs_remove_recursive(rkisp1->debug.debugfs_dir);
+}
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
index 3f5cfa7eb937..f2475c6235ea 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
@@ -9,18 +9,18 @@
*/
#include <linux/clk.h>
-#include <linux/debugfs.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/pinctrl/consumer.h>
-#include <linux/phy/phy.h>
-#include <linux/phy/phy-mipi-dphy.h>
+#include <linux/pm_runtime.h>
#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
#include "rkisp1-common.h"
+#include "rkisp1-csi.h"
/*
* ISP Details
@@ -68,18 +68,28 @@
*
* Media Topology
* --------------
- * +----------+ +----------+
- * | Sensor 2 | | Sensor X |
- * ------------ ... ------------
- * | 0 | | 0 |
- * +----------+ +----------+ +-----------+
- * \ | | params |
- * \ | | (output) |
- * +----------+ \ | +-----------+
- * | Sensor 1 | v v |
- * ------------ +------+------+ |
- * | 0 |----->| 0 | 1 |<---------+
- * +----------+ |------+------|
+ *
+ * +----------+ +----------+
+ * | Sensor 1 | | Sensor X |
+ * ------------ ... ------------
+ * | 0 | | 0 |
+ * +----------+ +----------+
+ * | |
+ * \----\ /----/
+ * | |
+ * v v
+ * +-------------+
+ * | 0 |
+ * ---------------
+ * | CSI-2 RX |
+ * --------------- +-----------+
+ * | 1 | | params |
+ * +-------------+ | (output) |
+ * | +-----------+
+ * v |
+ * +------+------+ |
+ * | 0 | 1 |<---------+
+ * |------+------|
* | ISP |
* |------+------|
* +-------------| 2 | 3 |----------+
@@ -106,88 +116,10 @@ struct rkisp1_isr_data {
irqreturn_t (*isr)(int irq, void *ctx);
};
-struct rkisp1_match_data {
- const char * const *clks;
- unsigned int clk_size;
- const struct rkisp1_isr_data *isrs;
- unsigned int isr_size;
- enum rkisp1_cif_isp_version isp_ver;
-};
-
/* ----------------------------------------------------------------------------
* Sensor DT bindings
*/
-static int rkisp1_create_links(struct rkisp1_device *rkisp1)
-{
- struct media_entity *source, *sink;
- unsigned int flags, source_pad;
- struct v4l2_subdev *sd;
- unsigned int i;
- int ret;
-
- /* sensor links */
- flags = MEDIA_LNK_FL_ENABLED;
- list_for_each_entry(sd, &rkisp1->v4l2_dev.subdevs, list) {
- if (sd == &rkisp1->isp.sd ||
- sd == &rkisp1->resizer_devs[RKISP1_MAINPATH].sd ||
- sd == &rkisp1->resizer_devs[RKISP1_SELFPATH].sd)
- continue;
-
- ret = media_entity_get_fwnode_pad(&sd->entity, sd->fwnode,
- MEDIA_PAD_FL_SOURCE);
- if (ret < 0) {
- dev_err(rkisp1->dev, "failed to find src pad for %s\n",
- sd->name);
- return ret;
- }
- source_pad = ret;
-
- ret = media_create_pad_link(&sd->entity, source_pad,
- &rkisp1->isp.sd.entity,
- RKISP1_ISP_PAD_SINK_VIDEO,
- flags);
- if (ret)
- return ret;
-
- flags = 0;
- }
-
- flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
-
- /* create ISP->RSZ->CAP links */
- for (i = 0; i < 2; i++) {
- source = &rkisp1->isp.sd.entity;
- sink = &rkisp1->resizer_devs[i].sd.entity;
- ret = media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_VIDEO,
- sink, RKISP1_RSZ_PAD_SINK,
- MEDIA_LNK_FL_ENABLED);
- if (ret)
- return ret;
-
- source = sink;
- sink = &rkisp1->capture_devs[i].vnode.vdev.entity;
- ret = media_create_pad_link(source, RKISP1_RSZ_PAD_SRC,
- sink, 0, flags);
- if (ret)
- return ret;
- }
-
- /* params links */
- source = &rkisp1->params.vnode.vdev.entity;
- sink = &rkisp1->isp.sd.entity;
- ret = media_create_pad_link(source, 0, sink,
- RKISP1_ISP_PAD_SINK_PARAMS, flags);
- if (ret)
- return ret;
-
- /* 3A stats links */
- source = &rkisp1->isp.sd.entity;
- sink = &rkisp1->stats.vnode.vdev.entity;
- return media_create_pad_link(source, RKISP1_ISP_PAD_SOURCE_STATS,
- sink, 0, flags);
-}
-
static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd,
struct v4l2_async_subdev *asd)
@@ -196,116 +128,171 @@ static int rkisp1_subdev_notifier_bound(struct v4l2_async_notifier *notifier,
container_of(notifier, struct rkisp1_device, notifier);
struct rkisp1_sensor_async *s_asd =
container_of(asd, struct rkisp1_sensor_async, asd);
+ int source_pad;
+ int ret;
- s_asd->pixel_rate_ctrl = v4l2_ctrl_find(sd->ctrl_handler,
- V4L2_CID_PIXEL_RATE);
s_asd->sd = sd;
- s_asd->dphy = devm_phy_get(rkisp1->dev, "dphy");
- if (IS_ERR(s_asd->dphy)) {
- if (PTR_ERR(s_asd->dphy) != -EPROBE_DEFER)
- dev_err(rkisp1->dev, "Couldn't get the MIPI D-PHY\n");
- return PTR_ERR(s_asd->dphy);
+
+ source_pad = media_entity_get_fwnode_pad(&sd->entity, s_asd->source_ep,
+ MEDIA_PAD_FL_SOURCE);
+ if (source_pad < 0) {
+ dev_err(rkisp1->dev, "failed to find source pad for %s\n",
+ sd->name);
+ return source_pad;
}
- phy_init(s_asd->dphy);
+ if (s_asd->port == 0)
+ return rkisp1_csi_link_sensor(rkisp1, sd, s_asd, source_pad);
- return 0;
-}
-
-static void rkisp1_subdev_notifier_unbind(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd,
- struct v4l2_async_subdev *asd)
-{
- struct rkisp1_sensor_async *s_asd =
- container_of(asd, struct rkisp1_sensor_async, asd);
+ ret = media_create_pad_link(&sd->entity, source_pad,
+ &rkisp1->isp.sd.entity,
+ RKISP1_ISP_PAD_SINK_VIDEO,
+ !s_asd->index ? MEDIA_LNK_FL_ENABLED : 0);
+ if (ret) {
+ dev_err(rkisp1->dev, "failed to link source pad of %s\n",
+ sd->name);
+ return ret;
+ }
- phy_exit(s_asd->dphy);
+ return 0;
}
static int rkisp1_subdev_notifier_complete(struct v4l2_async_notifier *notifier)
{
struct rkisp1_device *rkisp1 =
container_of(notifier, struct rkisp1_device, notifier);
- int ret;
- ret = rkisp1_create_links(rkisp1);
- if (ret)
- return ret;
-
- ret = v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
- if (ret)
- return ret;
+ return v4l2_device_register_subdev_nodes(&rkisp1->v4l2_dev);
+}
- dev_dbg(rkisp1->dev, "Async subdev notifier completed\n");
+static void rkisp1_subdev_notifier_destroy(struct v4l2_async_subdev *asd)
+{
+ struct rkisp1_sensor_async *rk_asd =
+ container_of(asd, struct rkisp1_sensor_async, asd);
- return 0;
+ fwnode_handle_put(rk_asd->source_ep);
}
static const struct v4l2_async_notifier_operations rkisp1_subdev_notifier_ops = {
.bound = rkisp1_subdev_notifier_bound,
- .unbind = rkisp1_subdev_notifier_unbind,
.complete = rkisp1_subdev_notifier_complete,
+ .destroy = rkisp1_subdev_notifier_destroy,
};
-static int rkisp1_subdev_notifier(struct rkisp1_device *rkisp1)
+static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1)
{
struct v4l2_async_notifier *ntf = &rkisp1->notifier;
- unsigned int next_id = 0;
- int ret;
+ struct fwnode_handle *fwnode = dev_fwnode(rkisp1->dev);
+ struct fwnode_handle *ep;
+ unsigned int index = 0;
+ int ret = 0;
v4l2_async_nf_init(ntf);
- while (1) {
- struct v4l2_fwnode_endpoint vep = {
- .bus_type = V4L2_MBUS_CSI2_DPHY
- };
+ ntf->ops = &rkisp1_subdev_notifier_ops;
+
+ fwnode_graph_for_each_endpoint(fwnode, ep) {
+ struct fwnode_handle *port;
+ struct v4l2_fwnode_endpoint vep = { };
struct rkisp1_sensor_async *rk_asd;
- struct fwnode_handle *ep;
+ struct fwnode_handle *source;
+ u32 reg = 0;
+
+ /* Select the bus type based on the port. */
+ port = fwnode_get_parent(ep);
+ fwnode_property_read_u32(port, "reg", &reg);
+ fwnode_handle_put(port);
+
+ switch (reg) {
+ case 0:
+ /* MIPI CSI-2 port */
+ if (!(rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)) {
+ dev_err(rkisp1->dev,
+ "internal CSI must be available for port 0\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ vep.bus_type = V4L2_MBUS_CSI2_DPHY;
+ break;
- ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(rkisp1->dev),
- 0, next_id,
- FWNODE_GRAPH_ENDPOINT_NEXT);
- if (!ep)
+ case 1:
+ /*
+ * Parallel port. The bus-type property in DT is
+ * mandatory for port 1, it will be used to determine if
+ * it's PARALLEL or BT656.
+ */
+ vep.bus_type = V4L2_MBUS_UNKNOWN;
break;
+ }
+ /* Parse the endpoint and validate the bus type. */
ret = v4l2_fwnode_endpoint_parse(ep, &vep);
- if (ret)
- goto err_parse;
+ if (ret) {
+ dev_err(rkisp1->dev, "failed to parse endpoint %pfw\n",
+ ep);
+ break;
+ }
- rk_asd = v4l2_async_nf_add_fwnode_remote(ntf, ep,
- struct
- rkisp1_sensor_async);
+ if (vep.base.port == 1) {
+ if (vep.bus_type != V4L2_MBUS_PARALLEL &&
+ vep.bus_type != V4L2_MBUS_BT656) {
+ dev_err(rkisp1->dev,
+ "port 1 must be parallel or BT656\n");
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ /* Add the async subdev to the notifier. */
+ source = fwnode_graph_get_remote_endpoint(ep);
+ if (!source) {
+ dev_err(rkisp1->dev,
+ "endpoint %pfw has no remote endpoint\n",
+ ep);
+ ret = -ENODEV;
+ break;
+ }
+
+ rk_asd = v4l2_async_nf_add_fwnode(ntf, source,
+ struct rkisp1_sensor_async);
if (IS_ERR(rk_asd)) {
+ fwnode_handle_put(source);
ret = PTR_ERR(rk_asd);
- goto err_parse;
+ break;
}
+ rk_asd->index = index++;
+ rk_asd->source_ep = source;
rk_asd->mbus_type = vep.bus_type;
- rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
- rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
-
- dev_dbg(rkisp1->dev, "registered ep id %d with %d lanes\n",
- vep.base.id, rk_asd->lanes);
+ rk_asd->port = vep.base.port;
- next_id = vep.base.id + 1;
+ if (vep.bus_type == V4L2_MBUS_CSI2_DPHY) {
+ rk_asd->mbus_flags = vep.bus.mipi_csi2.flags;
+ rk_asd->lanes = vep.bus.mipi_csi2.num_data_lanes;
+ } else {
+ rk_asd->mbus_flags = vep.bus.parallel.flags;
+ }
- fwnode_handle_put(ep);
+ dev_dbg(rkisp1->dev, "registered ep id %d, bus type %u, %u lanes\n",
+ vep.base.id, rk_asd->mbus_type, rk_asd->lanes);
+ }
- continue;
-err_parse:
+ if (ret) {
fwnode_handle_put(ep);
v4l2_async_nf_cleanup(ntf);
return ret;
}
- if (next_id == 0)
+ if (!index)
dev_dbg(rkisp1->dev, "no remote subdevice found\n");
- ntf->ops = &rkisp1_subdev_notifier_ops;
+
ret = v4l2_async_nf_register(&rkisp1->v4l2_dev, ntf);
if (ret) {
v4l2_async_nf_cleanup(ntf);
return ret;
}
+
return 0;
}
@@ -346,48 +333,110 @@ static const struct dev_pm_ops rkisp1_pm_ops = {
* Core
*/
+static int rkisp1_create_links(struct rkisp1_device *rkisp1)
+{
+ unsigned int i;
+ int ret;
+
+ if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) {
+ /* Link the CSI receiver to the ISP. */
+ ret = media_create_pad_link(&rkisp1->csi.sd.entity,
+ RKISP1_CSI_PAD_SRC,
+ &rkisp1->isp.sd.entity,
+ RKISP1_ISP_PAD_SINK_VIDEO,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+ }
+
+ /* create ISP->RSZ->CAP links */
+ for (i = 0; i < 2; i++) {
+ struct media_entity *resizer =
+ &rkisp1->resizer_devs[i].sd.entity;
+ struct media_entity *capture =
+ &rkisp1->capture_devs[i].vnode.vdev.entity;
+
+ ret = media_create_pad_link(&rkisp1->isp.sd.entity,
+ RKISP1_ISP_PAD_SOURCE_VIDEO,
+ resizer, RKISP1_RSZ_PAD_SINK,
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ return ret;
+
+ ret = media_create_pad_link(resizer, RKISP1_RSZ_PAD_SRC,
+ capture, 0,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret)
+ return ret;
+ }
+
+ /* params links */
+ ret = media_create_pad_link(&rkisp1->params.vnode.vdev.entity, 0,
+ &rkisp1->isp.sd.entity,
+ RKISP1_ISP_PAD_SINK_PARAMS,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret)
+ return ret;
+
+ /* 3A stats links */
+ return media_create_pad_link(&rkisp1->isp.sd.entity,
+ RKISP1_ISP_PAD_SOURCE_STATS,
+ &rkisp1->stats.vnode.vdev.entity, 0,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+}
+
+static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1)
+{
+ if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)
+ rkisp1_csi_unregister(rkisp1);
+ rkisp1_params_unregister(rkisp1);
+ rkisp1_stats_unregister(rkisp1);
+ rkisp1_capture_devs_unregister(rkisp1);
+ rkisp1_resizer_devs_unregister(rkisp1);
+ rkisp1_isp_unregister(rkisp1);
+}
+
static int rkisp1_entities_register(struct rkisp1_device *rkisp1)
{
int ret;
ret = rkisp1_isp_register(rkisp1);
if (ret)
- return ret;
+ goto error;
ret = rkisp1_resizer_devs_register(rkisp1);
if (ret)
- goto err_unreg_isp_subdev;
+ goto error;
ret = rkisp1_capture_devs_register(rkisp1);
if (ret)
- goto err_unreg_resizer_devs;
+ goto error;
ret = rkisp1_stats_register(rkisp1);
if (ret)
- goto err_unreg_capture_devs;
+ goto error;
ret = rkisp1_params_register(rkisp1);
if (ret)
- goto err_unreg_stats;
+ goto error;
- ret = rkisp1_subdev_notifier(rkisp1);
- if (ret) {
- dev_err(rkisp1->dev,
- "Failed to register subdev notifier(%d)\n", ret);
- goto err_unreg_params;
+ if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) {
+ ret = rkisp1_csi_register(rkisp1);
+ if (ret)
+ goto error;
}
+ ret = rkisp1_create_links(rkisp1);
+ if (ret)
+ goto error;
+
return 0;
-err_unreg_params:
- rkisp1_params_unregister(rkisp1);
-err_unreg_stats:
- rkisp1_stats_unregister(rkisp1);
-err_unreg_capture_devs:
- rkisp1_capture_devs_unregister(rkisp1);
-err_unreg_resizer_devs:
- rkisp1_resizer_devs_unregister(rkisp1);
-err_unreg_isp_subdev:
- rkisp1_isp_unregister(rkisp1);
+
+error:
+ rkisp1_entities_unregister(rkisp1);
return ret;
}
@@ -401,7 +450,7 @@ static irqreturn_t rkisp1_isr(int irq, void *ctx)
*/
rkisp1_capture_isr(irq, ctx);
rkisp1_isp_isr(irq, ctx);
- rkisp1_mipi_isr(irq, ctx);
+ rkisp1_csi_isr(irq, ctx);
return IRQ_HANDLED;
}
@@ -416,15 +465,16 @@ static const char * const px30_isp_clks[] = {
static const struct rkisp1_isr_data px30_isp_isrs[] = {
{ "isp", rkisp1_isp_isr },
{ "mi", rkisp1_capture_isr },
- { "mipi", rkisp1_mipi_isr },
+ { "mipi", rkisp1_csi_isr },
};
-static const struct rkisp1_match_data px30_isp_match_data = {
+static const struct rkisp1_info px30_isp_info = {
.clks = px30_isp_clks,
.clk_size = ARRAY_SIZE(px30_isp_clks),
.isrs = px30_isp_isrs,
.isr_size = ARRAY_SIZE(px30_isp_isrs),
.isp_ver = RKISP1_V12,
+ .features = RKISP1_FEATURE_MIPI_CSI2,
};
static const char * const rk3399_isp_clks[] = {
@@ -437,74 +487,45 @@ static const struct rkisp1_isr_data rk3399_isp_isrs[] = {
{ NULL, rkisp1_isr },
};
-static const struct rkisp1_match_data rk3399_isp_match_data = {
+static const struct rkisp1_info rk3399_isp_info = {
.clks = rk3399_isp_clks,
.clk_size = ARRAY_SIZE(rk3399_isp_clks),
.isrs = rk3399_isp_isrs,
.isr_size = ARRAY_SIZE(rk3399_isp_isrs),
.isp_ver = RKISP1_V10,
+ .features = RKISP1_FEATURE_MIPI_CSI2,
};
static const struct of_device_id rkisp1_of_match[] = {
{
.compatible = "rockchip,px30-cif-isp",
- .data = &px30_isp_match_data,
+ .data = &px30_isp_info,
},
{
.compatible = "rockchip,rk3399-cif-isp",
- .data = &rk3399_isp_match_data,
+ .data = &rk3399_isp_info,
},
{},
};
MODULE_DEVICE_TABLE(of, rkisp1_of_match);
-static void rkisp1_debug_init(struct rkisp1_device *rkisp1)
-{
- struct rkisp1_debug *debug = &rkisp1->debug;
-
- debug->debugfs_dir = debugfs_create_dir(dev_name(rkisp1->dev), NULL);
- debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir,
- &debug->data_loss);
- debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir,
- &debug->outform_size_error);
- debugfs_create_ulong("img_stabilization_size_error", 0444,
- debug->debugfs_dir,
- &debug->img_stabilization_size_error);
- debugfs_create_ulong("inform_size_error", 0444, debug->debugfs_dir,
- &debug->inform_size_error);
- debugfs_create_ulong("irq_delay", 0444, debug->debugfs_dir,
- &debug->irq_delay);
- debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir,
- &debug->mipi_error);
- debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir,
- &debug->stats_error);
- debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir,
- &debug->stop_timeout[RKISP1_MAINPATH]);
- debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir,
- &debug->stop_timeout[RKISP1_SELFPATH]);
- debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir,
- &debug->frame_drop[RKISP1_MAINPATH]);
- debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir,
- &debug->frame_drop[RKISP1_SELFPATH]);
-}
-
static int rkisp1_probe(struct platform_device *pdev)
{
- const struct rkisp1_match_data *match_data;
+ const struct rkisp1_info *info;
struct device *dev = &pdev->dev;
struct rkisp1_device *rkisp1;
struct v4l2_device *v4l2_dev;
unsigned int i;
int ret, irq;
-
- match_data = of_device_get_match_data(&pdev->dev);
- if (!match_data)
- return -ENODEV;
+ u32 cif_id;
rkisp1 = devm_kzalloc(dev, sizeof(*rkisp1), GFP_KERNEL);
if (!rkisp1)
return -ENOMEM;
+ info = of_device_get_match_data(dev);
+ rkisp1->info = info;
+
dev_set_drvdata(dev, rkisp1);
rkisp1->dev = dev;
@@ -514,14 +535,14 @@ static int rkisp1_probe(struct platform_device *pdev)
if (IS_ERR(rkisp1->base_addr))
return PTR_ERR(rkisp1->base_addr);
- for (i = 0; i < match_data->isr_size; i++) {
- irq = (match_data->isrs[i].name) ?
- platform_get_irq_byname(pdev, match_data->isrs[i].name) :
- platform_get_irq(pdev, i);
+ for (i = 0; i < info->isr_size; i++) {
+ irq = info->isrs[i].name
+ ? platform_get_irq_byname(pdev, info->isrs[i].name)
+ : platform_get_irq(pdev, i);
if (irq < 0)
return irq;
- ret = devm_request_irq(dev, irq, match_data->isrs[i].isr, IRQF_SHARED,
+ ret = devm_request_irq(dev, irq, info->isrs[i].isr, IRQF_SHARED,
dev_driver_string(dev), dev);
if (ret) {
dev_err(dev, "request irq failed: %d\n", ret);
@@ -529,16 +550,25 @@ static int rkisp1_probe(struct platform_device *pdev)
}
}
- for (i = 0; i < match_data->clk_size; i++)
- rkisp1->clks[i].id = match_data->clks[i];
- ret = devm_clk_bulk_get(dev, match_data->clk_size, rkisp1->clks);
+ for (i = 0; i < info->clk_size; i++)
+ rkisp1->clks[i].id = info->clks[i];
+ ret = devm_clk_bulk_get(dev, info->clk_size, rkisp1->clks);
if (ret)
return ret;
- rkisp1->clk_size = match_data->clk_size;
+ rkisp1->clk_size = info->clk_size;
pm_runtime_enable(&pdev->dev);
- rkisp1->media_dev.hw_revision = match_data->isp_ver;
+ ret = pm_runtime_resume_and_get(&pdev->dev);
+ if (ret)
+ goto err_pm_runtime_disable;
+
+ cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID);
+ dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id);
+
+ pm_runtime_put(&pdev->dev);
+
+ rkisp1->media_dev.hw_revision = info->isp_ver;
strscpy(rkisp1->media_dev.model, RKISP1_DRIVER_NAME,
sizeof(rkisp1->media_dev.model));
rkisp1->media_dev.dev = &pdev->dev;
@@ -552,7 +582,7 @@ static int rkisp1_probe(struct platform_device *pdev)
ret = v4l2_device_register(rkisp1->dev, &rkisp1->v4l2_dev);
if (ret)
- return ret;
+ goto err_pm_runtime_disable;
ret = media_device_register(&rkisp1->media_dev);
if (ret) {
@@ -560,18 +590,34 @@ static int rkisp1_probe(struct platform_device *pdev)
goto err_unreg_v4l2_dev;
}
+ if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) {
+ ret = rkisp1_csi_init(rkisp1);
+ if (ret)
+ goto err_unreg_media_dev;
+ }
+
ret = rkisp1_entities_register(rkisp1);
if (ret)
- goto err_unreg_media_dev;
+ goto err_cleanup_csi;
+
+ ret = rkisp1_subdev_notifier_register(rkisp1);
+ if (ret)
+ goto err_unreg_entities;
rkisp1_debug_init(rkisp1);
return 0;
+err_unreg_entities:
+ rkisp1_entities_unregister(rkisp1);
+err_cleanup_csi:
+ if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)
+ rkisp1_csi_cleanup(rkisp1);
err_unreg_media_dev:
media_device_unregister(&rkisp1->media_dev);
err_unreg_v4l2_dev:
v4l2_device_unregister(&rkisp1->v4l2_dev);
+err_pm_runtime_disable:
pm_runtime_disable(&pdev->dev);
return ret;
}
@@ -583,18 +629,16 @@ static int rkisp1_remove(struct platform_device *pdev)
v4l2_async_nf_unregister(&rkisp1->notifier);
v4l2_async_nf_cleanup(&rkisp1->notifier);
- rkisp1_params_unregister(rkisp1);
- rkisp1_stats_unregister(rkisp1);
- rkisp1_capture_devs_unregister(rkisp1);
- rkisp1_resizer_devs_unregister(rkisp1);
- rkisp1_isp_unregister(rkisp1);
+ rkisp1_entities_unregister(rkisp1);
+ if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)
+ rkisp1_csi_cleanup(rkisp1);
+ rkisp1_debug_cleanup(rkisp1);
media_device_unregister(&rkisp1->media_dev);
v4l2_device_unregister(&rkisp1->v4l2_dev);
pm_runtime_disable(&pdev->dev);
- debugfs_remove_recursive(rkisp1->debug.debugfs_dir);
return 0;
}
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index 4415c7248c2f..383a3ec83ca9 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -9,13 +9,10 @@
*/
#include <linux/iopoll.h>
-#include <linux/phy/phy.h>
-#include <linux/phy/phy-mipi-dphy.h>
#include <linux/pm_runtime.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
-#include <media/mipi-csi2.h>
#include <media/v4l2-event.h>
#include "rkisp1-common.h"
@@ -56,158 +53,10 @@
* +---------------------------------------------------------+
*/
-static const struct rkisp1_isp_mbus_info rkisp1_isp_formats[] = {
- {
- .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .direction = RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW10,
- .bayer_pat = RKISP1_RAW_RGGB,
- .bus_width = 10,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW10,
- .bayer_pat = RKISP1_RAW_BGGR,
- .bus_width = 10,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW10,
- .bayer_pat = RKISP1_RAW_GBRG,
- .bus_width = 10,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW10,
- .bayer_pat = RKISP1_RAW_GRBG,
- .bus_width = 10,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW12,
- .bayer_pat = RKISP1_RAW_RGGB,
- .bus_width = 12,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW12,
- .bayer_pat = RKISP1_RAW_BGGR,
- .bus_width = 12,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW12,
- .bayer_pat = RKISP1_RAW_GBRG,
- .bus_width = 12,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW12,
- .bayer_pat = RKISP1_RAW_GRBG,
- .bus_width = 12,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW8,
- .bayer_pat = RKISP1_RAW_RGGB,
- .bus_width = 8,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW8,
- .bayer_pat = RKISP1_RAW_BGGR,
- .bus_width = 8,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW8,
- .bayer_pat = RKISP1_RAW_GBRG,
- .bus_width = 8,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
- .pixel_enc = V4L2_PIXEL_ENC_BAYER,
- .mipi_dt = MIPI_CSI2_DT_RAW8,
- .bayer_pat = RKISP1_RAW_GRBG,
- .bus_width = 8,
- .direction = RKISP1_ISP_SD_SINK | RKISP1_ISP_SD_SRC,
- }, {
- .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .mipi_dt = MIPI_CSI2_DT_YUV422_8B,
- .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCBYCR,
- .bus_width = 16,
- .direction = RKISP1_ISP_SD_SINK,
- }, {
- .mbus_code = MEDIA_BUS_FMT_YVYU8_1X16,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .mipi_dt = MIPI_CSI2_DT_YUV422_8B,
- .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_YCRYCB,
- .bus_width = 16,
- .direction = RKISP1_ISP_SD_SINK,
- }, {
- .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .mipi_dt = MIPI_CSI2_DT_YUV422_8B,
- .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CBYCRY,
- .bus_width = 16,
- .direction = RKISP1_ISP_SD_SINK,
- }, {
- .mbus_code = MEDIA_BUS_FMT_VYUY8_1X16,
- .pixel_enc = V4L2_PIXEL_ENC_YUV,
- .mipi_dt = MIPI_CSI2_DT_YUV422_8B,
- .yuv_seq = RKISP1_CIF_ISP_ACQ_PROP_CRYCBY,
- .bus_width = 16,
- .direction = RKISP1_ISP_SD_SINK,
- },
-};
-
/* ----------------------------------------------------------------------------
* Helpers
*/
-const struct rkisp1_isp_mbus_info *rkisp1_isp_mbus_info_get(u32 mbus_code)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) {
- const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i];
-
- if (fmt->mbus_code == mbus_code)
- return fmt;
- }
-
- return NULL;
-}
-
-static struct v4l2_subdev *rkisp1_get_remote_sensor(struct v4l2_subdev *sd)
-{
- struct media_pad *local, *remote;
- struct media_entity *sensor_me;
-
- local = &sd->entity.pads[RKISP1_ISP_PAD_SINK_VIDEO];
- remote = media_entity_remote_pad(local);
- if (!remote)
- return NULL;
-
- sensor_me = remote->entity;
- return media_entity_to_v4l2_subdev(sensor_me);
-}
-
static struct v4l2_mbus_framefmt *
rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp,
struct v4l2_subdev_state *sd_state,
@@ -215,7 +64,8 @@ rkisp1_isp_get_pad_fmt(struct rkisp1_isp *isp,
{
struct v4l2_subdev_state state = {
.pads = isp->pad_cfg
- };
+ };
+
if (which == V4L2_SUBDEV_FORMAT_TRY)
return v4l2_subdev_get_try_format(&isp->sd, sd_state, pad);
else
@@ -229,7 +79,8 @@ rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp,
{
struct v4l2_subdev_state state = {
.pads = isp->pad_cfg
- };
+ };
+
if (which == V4L2_SUBDEV_FORMAT_TRY)
return v4l2_subdev_get_try_crop(&isp->sd, sd_state, pad);
else
@@ -245,73 +96,73 @@ rkisp1_isp_get_pad_crop(struct rkisp1_isp *isp,
* This should only be called when configuring CIF
* or at the frame end interrupt
*/
-static void rkisp1_config_ism(struct rkisp1_device *rkisp1)
+static void rkisp1_config_ism(struct rkisp1_isp *isp)
{
- struct v4l2_rect *src_crop =
- rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL,
+ const struct v4l2_rect *src_crop =
+ rkisp1_isp_get_pad_crop(isp, NULL,
RKISP1_ISP_PAD_SOURCE_VIDEO,
V4L2_SUBDEV_FORMAT_ACTIVE);
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
u32 val;
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_RECENTER);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DX);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_MAX_DY);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IS_DISPLACE);
- rkisp1_write(rkisp1, src_crop->left, RKISP1_CIF_ISP_IS_H_OFFS);
- rkisp1_write(rkisp1, src_crop->top, RKISP1_CIF_ISP_IS_V_OFFS);
- rkisp1_write(rkisp1, src_crop->width, RKISP1_CIF_ISP_IS_H_SIZE);
- rkisp1_write(rkisp1, src_crop->height, RKISP1_CIF_ISP_IS_V_SIZE);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_RECENTER, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DX, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_MAX_DY, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_DISPLACE, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_OFFS, src_crop->left);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_OFFS, src_crop->top);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_H_SIZE, src_crop->width);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_V_SIZE, src_crop->height);
/* IS(Image Stabilization) is always on, working as output crop */
- rkisp1_write(rkisp1, 1, RKISP1_CIF_ISP_IS_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IS_CTRL, 1);
val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD;
- rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val);
}
/*
* configure ISP blocks with input format, size......
*/
-static int rkisp1_config_isp(struct rkisp1_device *rkisp1)
-{
- u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, signal = 0;
- const struct rkisp1_isp_mbus_info *src_fmt, *sink_fmt;
- struct rkisp1_sensor_async *sensor;
- struct v4l2_mbus_framefmt *sink_frm;
- struct v4l2_rect *sink_crop;
+static int rkisp1_config_isp(struct rkisp1_isp *isp,
+ enum v4l2_mbus_type mbus_type, u32 mbus_flags)
+{
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
+ u32 isp_ctrl = 0, irq_mask = 0, acq_mult = 0, acq_prop = 0;
+ const struct rkisp1_mbus_info *sink_fmt = isp->sink_fmt;
+ const struct rkisp1_mbus_info *src_fmt = isp->src_fmt;
+ const struct v4l2_mbus_framefmt *sink_frm;
+ const struct v4l2_rect *sink_crop;
- sensor = rkisp1->active_sensor;
- sink_fmt = rkisp1->isp.sink_fmt;
- src_fmt = rkisp1->isp.src_fmt;
- sink_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL,
+ sink_frm = rkisp1_isp_get_pad_fmt(isp, NULL,
RKISP1_ISP_PAD_SINK_VIDEO,
V4L2_SUBDEV_FORMAT_ACTIVE);
- sink_crop = rkisp1_isp_get_pad_crop(&rkisp1->isp, NULL,
+ sink_crop = rkisp1_isp_get_pad_crop(isp, NULL,
RKISP1_ISP_PAD_SINK_VIDEO,
V4L2_SUBDEV_FORMAT_ACTIVE);
if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
acq_mult = 1;
if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
- if (sensor->mbus_type == V4L2_MBUS_BT656)
+ if (mbus_type == V4L2_MBUS_BT656)
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT_ITU656;
else
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT;
} else {
- rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC_TH(0xc),
- RKISP1_CIF_ISP_DEMOSAIC);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_DEMOSAIC,
+ RKISP1_CIF_ISP_DEMOSAIC_TH(0xc));
- if (sensor->mbus_type == V4L2_MBUS_BT656)
+ if (mbus_type == V4L2_MBUS_BT656)
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU656;
else
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601;
}
} else if (sink_fmt->pixel_enc == V4L2_PIXEL_ENC_YUV) {
acq_mult = 2;
- if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) {
+ if (mbus_type == V4L2_MBUS_CSI2_DPHY) {
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601;
} else {
- if (sensor->mbus_type == V4L2_MBUS_BT656)
+ if (mbus_type == V4L2_MBUS_BT656)
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656;
else
isp_ctrl = RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601;
@@ -321,50 +172,65 @@ static int rkisp1_config_isp(struct rkisp1_device *rkisp1)
}
/* Set up input acquisition properties */
- if (sensor->mbus_type == V4L2_MBUS_BT656 ||
- sensor->mbus_type == V4L2_MBUS_PARALLEL) {
- if (sensor->mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
- signal = RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE;
+ if (mbus_type == V4L2_MBUS_BT656 || mbus_type == V4L2_MBUS_PARALLEL) {
+ if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_POS_EDGE;
+
+ switch (sink_fmt->bus_width) {
+ case 8:
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO;
+ break;
+ case 10:
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO;
+ break;
+ case 12:
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B;
+ break;
+ default:
+ dev_err(rkisp1->dev, "Invalid bus width %u\n",
+ sink_fmt->bus_width);
+ return -EINVAL;
+ }
}
- if (sensor->mbus_type == V4L2_MBUS_PARALLEL) {
- if (sensor->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- signal |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW;
+ if (mbus_type == V4L2_MBUS_PARALLEL) {
+ if (mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW;
- if (sensor->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- signal |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW;
+ if (mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ acq_prop |= RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW;
}
- rkisp1_write(rkisp1, isp_ctrl, RKISP1_CIF_ISP_CTRL);
- rkisp1_write(rkisp1, signal | sink_fmt->yuv_seq |
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, isp_ctrl);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_PROP,
+ acq_prop | sink_fmt->yuv_seq |
RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(sink_fmt->bayer_pat) |
- RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL,
- RKISP1_CIF_ISP_ACQ_PROP);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_NR_FRAMES);
+ RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_NR_FRAMES, 0);
/* Acquisition Size */
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_H_OFFS);
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_ACQ_V_OFFS);
- rkisp1_write(rkisp1,
- acq_mult * sink_frm->width, RKISP1_CIF_ISP_ACQ_H_SIZE);
- rkisp1_write(rkisp1, sink_frm->height, RKISP1_CIF_ISP_ACQ_V_SIZE);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_H_OFFS, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_V_OFFS, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_H_SIZE,
+ acq_mult * sink_frm->width);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ACQ_V_SIZE, sink_frm->height);
/* ISP Out Area */
- rkisp1_write(rkisp1, sink_crop->left, RKISP1_CIF_ISP_OUT_H_OFFS);
- rkisp1_write(rkisp1, sink_crop->top, RKISP1_CIF_ISP_OUT_V_OFFS);
- rkisp1_write(rkisp1, sink_crop->width, RKISP1_CIF_ISP_OUT_H_SIZE);
- rkisp1_write(rkisp1, sink_crop->height, RKISP1_CIF_ISP_OUT_V_SIZE);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_H_OFFS, sink_crop->left);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_V_OFFS, sink_crop->top);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_H_SIZE, sink_crop->width);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_OUT_V_SIZE, sink_crop->height);
irq_mask |= RKISP1_CIF_ISP_FRAME | RKISP1_CIF_ISP_V_START |
RKISP1_CIF_ISP_PIC_SIZE_ERROR;
- rkisp1_write(rkisp1, irq_mask, RKISP1_CIF_ISP_IMSC);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, irq_mask);
if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
rkisp1_params_disable(&rkisp1->params);
} else {
struct v4l2_mbus_framefmt *src_frm;
- src_frm = rkisp1_isp_get_pad_fmt(&rkisp1->isp, NULL,
+ src_frm = rkisp1_isp_get_pad_fmt(isp, NULL,
RKISP1_ISP_PAD_SINK_VIDEO,
V4L2_SUBDEV_FORMAT_ACTIVE);
rkisp1_params_configure(&rkisp1->params, sink_fmt->bayer_pat,
@@ -374,213 +240,117 @@ static int rkisp1_config_isp(struct rkisp1_device *rkisp1)
return 0;
}
-static int rkisp1_config_dvp(struct rkisp1_device *rkisp1)
-{
- const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt;
- u32 val, input_sel;
-
- switch (sink_fmt->bus_width) {
- case 8:
- input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO;
- break;
- case 10:
- input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO;
- break;
- case 12:
- input_sel = RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B;
- break;
- default:
- dev_err(rkisp1->dev, "Invalid bus width\n");
- return -EINVAL;
- }
-
- val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_ACQ_PROP);
- rkisp1_write(rkisp1, val | input_sel, RKISP1_CIF_ISP_ACQ_PROP);
-
- return 0;
-}
-
-static int rkisp1_config_mipi(struct rkisp1_device *rkisp1)
-{
- const struct rkisp1_isp_mbus_info *sink_fmt = rkisp1->isp.sink_fmt;
- unsigned int lanes = rkisp1->active_sensor->lanes;
- u32 mipi_ctrl;
-
- if (lanes < 1 || lanes > 4)
- return -EINVAL;
-
- mipi_ctrl = RKISP1_CIF_MIPI_CTRL_NUM_LANES(lanes - 1) |
- RKISP1_CIF_MIPI_CTRL_SHUTDOWNLANES(0xf) |
- RKISP1_CIF_MIPI_CTRL_ERR_SOT_SYNC_HS_SKIP |
- RKISP1_CIF_MIPI_CTRL_CLOCKLANE_ENA;
-
- rkisp1_write(rkisp1, mipi_ctrl, RKISP1_CIF_MIPI_CTRL);
-
- /* V12 could also use a newer csi2-host, but we don't want that yet */
- if (rkisp1->media_dev.hw_revision == RKISP1_V12)
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_CSI0_CTRL0);
-
- /* Configure Data Type and Virtual Channel */
- rkisp1_write(rkisp1,
- RKISP1_CIF_MIPI_DATA_SEL_DT(sink_fmt->mipi_dt) |
- RKISP1_CIF_MIPI_DATA_SEL_VC(0),
- RKISP1_CIF_MIPI_IMG_DATA_SEL);
-
- /* Clear MIPI interrupts */
- rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR);
- /*
- * Disable RKISP1_CIF_MIPI_ERR_DPHY interrupt here temporary for
- * isp bus may be dead when switch isp.
- */
- rkisp1_write(rkisp1,
- RKISP1_CIF_MIPI_FRAME_END | RKISP1_CIF_MIPI_ERR_CSI |
- RKISP1_CIF_MIPI_ERR_DPHY |
- RKISP1_CIF_MIPI_SYNC_FIFO_OVFLW(0x03) |
- RKISP1_CIF_MIPI_ADD_DATA_OVFLW,
- RKISP1_CIF_MIPI_IMSC);
-
- dev_dbg(rkisp1->dev, "\n MIPI_CTRL 0x%08x\n"
- " MIPI_IMG_DATA_SEL 0x%08x\n"
- " MIPI_STATUS 0x%08x\n"
- " MIPI_IMSC 0x%08x\n",
- rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL),
- rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMG_DATA_SEL),
- rkisp1_read(rkisp1, RKISP1_CIF_MIPI_STATUS),
- rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC));
-
- return 0;
-}
-
/* Configure MUX */
-static int rkisp1_config_path(struct rkisp1_device *rkisp1)
+static void rkisp1_config_path(struct rkisp1_isp *isp,
+ enum v4l2_mbus_type mbus_type)
{
- struct rkisp1_sensor_async *sensor = rkisp1->active_sensor;
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
u32 dpcl = rkisp1_read(rkisp1, RKISP1_CIF_VI_DPCL);
- int ret = 0;
- if (sensor->mbus_type == V4L2_MBUS_BT656 ||
- sensor->mbus_type == V4L2_MBUS_PARALLEL) {
- ret = rkisp1_config_dvp(rkisp1);
+ if (mbus_type == V4L2_MBUS_BT656 || mbus_type == V4L2_MBUS_PARALLEL)
dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL;
- } else if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) {
- ret = rkisp1_config_mipi(rkisp1);
+ else if (mbus_type == V4L2_MBUS_CSI2_DPHY)
dpcl |= RKISP1_CIF_VI_DPCL_IF_SEL_MIPI;
- }
-
- rkisp1_write(rkisp1, dpcl, RKISP1_CIF_VI_DPCL);
- return ret;
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_DPCL, dpcl);
}
/* Hardware configure Entry */
-static int rkisp1_config_cif(struct rkisp1_device *rkisp1)
+static int rkisp1_config_cif(struct rkisp1_isp *isp,
+ enum v4l2_mbus_type mbus_type, u32 mbus_flags)
{
- u32 cif_id;
int ret;
- cif_id = rkisp1_read(rkisp1, RKISP1_CIF_VI_ID);
- dev_dbg(rkisp1->dev, "CIF_ID 0x%08x\n", cif_id);
-
- ret = rkisp1_config_isp(rkisp1);
+ ret = rkisp1_config_isp(isp, mbus_type, mbus_flags);
if (ret)
return ret;
- ret = rkisp1_config_path(rkisp1);
- if (ret)
- return ret;
- rkisp1_config_ism(rkisp1);
+
+ rkisp1_config_path(isp, mbus_type);
+ rkisp1_config_ism(isp);
return 0;
}
-static void rkisp1_isp_stop(struct rkisp1_device *rkisp1)
+static void rkisp1_isp_stop(struct rkisp1_isp *isp)
{
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
u32 val;
/*
* ISP(mi) stop in mi frame end -> Stop ISP(mipi) ->
* Stop ISP(isp) ->wait for ISP isp off
*/
- /* stop and clear MI, MIPI, and ISP interrupts */
- rkisp1_write(rkisp1, 0, RKISP1_CIF_MIPI_IMSC);
- rkisp1_write(rkisp1, ~0, RKISP1_CIF_MIPI_ICR);
-
- rkisp1_write(rkisp1, 0, RKISP1_CIF_ISP_IMSC);
- rkisp1_write(rkisp1, ~0, RKISP1_CIF_ISP_ICR);
-
- rkisp1_write(rkisp1, 0, RKISP1_CIF_MI_IMSC);
- rkisp1_write(rkisp1, ~0, RKISP1_CIF_MI_ICR);
- val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
- rkisp1_write(rkisp1, val & (~RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA),
- RKISP1_CIF_MIPI_CTRL);
+ /* stop and clear MI and ISP interrupts */
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_IMSC, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, ~0);
+
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_IMSC, 0);
+ rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, ~0);
+
/* stop ISP */
val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
val &= ~(RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE |
RKISP1_CIF_ISP_CTRL_ISP_ENABLE);
- rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val);
val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
- rkisp1_write(rkisp1, val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD,
- RKISP1_CIF_ISP_CTRL);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL,
+ val | RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD);
readx_poll_timeout(readl, rkisp1->base_addr + RKISP1_CIF_ISP_RIS,
val, val & RKISP1_CIF_ISP_OFF, 20, 100);
- rkisp1_write(rkisp1,
- RKISP1_CIF_IRCL_MIPI_SW_RST | RKISP1_CIF_IRCL_ISP_SW_RST,
- RKISP1_CIF_IRCL);
- rkisp1_write(rkisp1, 0x0, RKISP1_CIF_IRCL);
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL,
+ RKISP1_CIF_VI_IRCL_MIPI_SW_RST |
+ RKISP1_CIF_VI_IRCL_ISP_SW_RST);
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL, 0x0);
}
-static void rkisp1_config_clk(struct rkisp1_device *rkisp1)
+static void rkisp1_config_clk(struct rkisp1_isp *isp)
{
- u32 val = RKISP1_CIF_ICCL_ISP_CLK | RKISP1_CIF_ICCL_CP_CLK |
- RKISP1_CIF_ICCL_MRSZ_CLK | RKISP1_CIF_ICCL_SRSZ_CLK |
- RKISP1_CIF_ICCL_JPEG_CLK | RKISP1_CIF_ICCL_MI_CLK |
- RKISP1_CIF_ICCL_IE_CLK | RKISP1_CIF_ICCL_MIPI_CLK |
- RKISP1_CIF_ICCL_DCROP_CLK;
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
+
+ u32 val = RKISP1_CIF_VI_ICCL_ISP_CLK | RKISP1_CIF_VI_ICCL_CP_CLK |
+ RKISP1_CIF_VI_ICCL_MRSZ_CLK | RKISP1_CIF_VI_ICCL_SRSZ_CLK |
+ RKISP1_CIF_VI_ICCL_JPEG_CLK | RKISP1_CIF_VI_ICCL_MI_CLK |
+ RKISP1_CIF_VI_ICCL_IE_CLK | RKISP1_CIF_VI_ICCL_MIPI_CLK |
+ RKISP1_CIF_VI_ICCL_DCROP_CLK;
- rkisp1_write(rkisp1, val, RKISP1_CIF_ICCL);
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_ICCL, val);
/* ensure sp and mp can run at the same time in V12 */
- if (rkisp1->media_dev.hw_revision == RKISP1_V12) {
+ if (rkisp1->info->isp_ver == RKISP1_V12) {
val = RKISP1_CIF_CLK_CTRL_MI_Y12 | RKISP1_CIF_CLK_CTRL_MI_SP |
RKISP1_CIF_CLK_CTRL_MI_RAW0 | RKISP1_CIF_CLK_CTRL_MI_RAW1 |
RKISP1_CIF_CLK_CTRL_MI_READ | RKISP1_CIF_CLK_CTRL_MI_RAWRD |
RKISP1_CIF_CLK_CTRL_CP | RKISP1_CIF_CLK_CTRL_IE;
- rkisp1_write(rkisp1, val, RKISP1_CIF_VI_ISP_CLK_CTRL_V12);
+ rkisp1_write(rkisp1, RKISP1_CIF_VI_ISP_CLK_CTRL_V12, val);
}
}
-static void rkisp1_isp_start(struct rkisp1_device *rkisp1)
+static void rkisp1_isp_start(struct rkisp1_isp *isp)
{
- struct rkisp1_sensor_async *sensor = rkisp1->active_sensor;
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
u32 val;
- rkisp1_config_clk(rkisp1);
+ rkisp1_config_clk(isp);
- /* Activate MIPI */
- if (sensor->mbus_type == V4L2_MBUS_CSI2_DPHY) {
- val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_CTRL);
- rkisp1_write(rkisp1, val | RKISP1_CIF_MIPI_CTRL_OUTPUT_ENA,
- RKISP1_CIF_MIPI_CTRL);
- }
/* Activate ISP */
val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL);
val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD |
RKISP1_CIF_ISP_CTRL_ISP_ENABLE |
RKISP1_CIF_ISP_CTRL_ISP_INFORM_ENABLE;
- rkisp1_write(rkisp1, val, RKISP1_CIF_ISP_CTRL);
-
- /*
- * CIF spec says to wait for sufficient time after enabling
- * the MIPI interface and before starting the sensor output.
- */
- usleep_range(1000, 1200);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_CTRL, val);
}
/* ----------------------------------------------------------------------------
* Subdev pad operations
*/
+static inline struct rkisp1_isp *to_rkisp1_isp(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct rkisp1_isp, sd);
+}
+
static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
@@ -599,11 +369,12 @@ static int rkisp1_isp_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
- if (code->index >= ARRAY_SIZE(rkisp1_isp_formats))
- return -EINVAL;
+ for (i = 0; ; i++) {
+ const struct rkisp1_mbus_info *fmt =
+ rkisp1_mbus_info_get_by_index(i);
- for (i = 0; i < ARRAY_SIZE(rkisp1_isp_formats); i++) {
- const struct rkisp1_isp_mbus_info *fmt = &rkisp1_isp_formats[i];
+ if (!fmt)
+ return -EINVAL;
if (fmt->direction & dir)
pos++;
@@ -625,7 +396,7 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
- const struct rkisp1_isp_mbus_info *mbus_info;
+ const struct rkisp1_mbus_info *mbus_info;
if (fse->pad == RKISP1_ISP_PAD_SINK_PARAMS ||
fse->pad == RKISP1_ISP_PAD_SOURCE_STATS)
@@ -634,7 +405,7 @@ static int rkisp1_isp_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index > 0)
return -EINVAL;
- mbus_info = rkisp1_isp_mbus_info_get(fse->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(fse->code);
if (!mbus_info)
return -EINVAL;
@@ -701,7 +472,7 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
struct v4l2_mbus_framefmt *format,
unsigned int which)
{
- const struct rkisp1_isp_mbus_info *mbus_info;
+ const struct rkisp1_mbus_info *mbus_info;
struct v4l2_mbus_framefmt *src_fmt;
const struct v4l2_rect *src_crop;
@@ -711,10 +482,10 @@ static void rkisp1_isp_set_src_fmt(struct rkisp1_isp *isp,
RKISP1_ISP_PAD_SOURCE_VIDEO, which);
src_fmt->code = format->code;
- mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code);
if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) {
src_fmt->code = RKISP1_DEF_SRC_PAD_FMT;
- mbus_info = rkisp1_isp_mbus_info_get(src_fmt->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(src_fmt->code);
}
if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
isp->src_fmt = mbus_info;
@@ -771,7 +542,7 @@ static void rkisp1_isp_set_sink_crop(struct rkisp1_isp *isp,
struct v4l2_rect *r, unsigned int which)
{
struct v4l2_rect *sink_crop, *src_crop;
- struct v4l2_mbus_framefmt *sink_fmt;
+ const struct v4l2_mbus_framefmt *sink_fmt;
sink_crop = rkisp1_isp_get_pad_crop(isp, sd_state,
RKISP1_ISP_PAD_SINK_VIDEO,
@@ -799,7 +570,7 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
struct v4l2_mbus_framefmt *format,
unsigned int which)
{
- const struct rkisp1_isp_mbus_info *mbus_info;
+ const struct rkisp1_mbus_info *mbus_info;
struct v4l2_mbus_framefmt *sink_fmt;
struct v4l2_rect *sink_crop;
@@ -807,10 +578,10 @@ static void rkisp1_isp_set_sink_fmt(struct rkisp1_isp *isp,
RKISP1_ISP_PAD_SINK_VIDEO,
which);
sink_fmt->code = format->code;
- mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SINK)) {
sink_fmt->code = RKISP1_DEF_SINK_PAD_FMT;
- mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
}
if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
isp->sink_fmt = mbus_info;
@@ -835,7 +606,7 @@ static int rkisp1_isp_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+ struct rkisp1_isp *isp = to_rkisp1_isp(sd);
mutex_lock(&isp->ops_lock);
fmt->format = *rkisp1_isp_get_pad_fmt(isp, sd_state, fmt->pad,
@@ -848,7 +619,7 @@ static int rkisp1_isp_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
- struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+ struct rkisp1_isp *isp = to_rkisp1_isp(sd);
mutex_lock(&isp->ops_lock);
if (fmt->pad == RKISP1_ISP_PAD_SINK_VIDEO)
@@ -869,7 +640,7 @@ static int rkisp1_isp_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+ struct rkisp1_isp *isp = to_rkisp1_isp(sd);
int ret = 0;
if (sel->pad != RKISP1_ISP_PAD_SOURCE_VIDEO &&
@@ -909,15 +680,13 @@ static int rkisp1_isp_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct rkisp1_device *rkisp1 =
- container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev);
- struct rkisp1_isp *isp = container_of(sd, struct rkisp1_isp, sd);
+ struct rkisp1_isp *isp = to_rkisp1_isp(sd);
int ret = 0;
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- dev_dbg(rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__,
+ dev_dbg(isp->rkisp1->dev, "%s: pad: %d sel(%d,%d)/%dx%d\n", __func__,
sel->pad, sel->r.left, sel->r.top, sel->r.width, sel->r.height);
mutex_lock(&isp->ops_lock);
if (sel->pad == RKISP1_ISP_PAD_SINK_VIDEO)
@@ -954,77 +723,62 @@ static const struct v4l2_subdev_pad_ops rkisp1_isp_pad_ops = {
* Stream operations
*/
-static int rkisp1_mipi_csi2_start(struct rkisp1_isp *isp,
- struct rkisp1_sensor_async *sensor)
-{
- struct rkisp1_device *rkisp1 =
- container_of(isp->sd.v4l2_dev, struct rkisp1_device, v4l2_dev);
- union phy_configure_opts opts;
- struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
- s64 pixel_clock;
-
- if (!sensor->pixel_rate_ctrl) {
- dev_warn(rkisp1->dev, "No pixel rate control in sensor subdev\n");
- return -EPIPE;
- }
-
- pixel_clock = v4l2_ctrl_g_ctrl_int64(sensor->pixel_rate_ctrl);
- if (!pixel_clock) {
- dev_err(rkisp1->dev, "Invalid pixel rate value\n");
- return -EINVAL;
- }
-
- phy_mipi_dphy_get_default_config(pixel_clock, isp->sink_fmt->bus_width,
- sensor->lanes, cfg);
- phy_set_mode(sensor->dphy, PHY_MODE_MIPI_DPHY);
- phy_configure(sensor->dphy, &opts);
- phy_power_on(sensor->dphy);
-
- return 0;
-}
-
-static void rkisp1_mipi_csi2_stop(struct rkisp1_sensor_async *sensor)
-{
- phy_power_off(sensor->dphy);
-}
-
static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct rkisp1_device *rkisp1 =
- container_of(sd->v4l2_dev, struct rkisp1_device, v4l2_dev);
- struct rkisp1_isp *isp = &rkisp1->isp;
- struct v4l2_subdev *sensor_sd;
- int ret = 0;
+ struct rkisp1_isp *isp = to_rkisp1_isp(sd);
+ struct rkisp1_device *rkisp1 = isp->rkisp1;
+ struct media_pad *source_pad;
+ struct media_pad *sink_pad;
+ enum v4l2_mbus_type mbus_type;
+ u32 mbus_flags;
+ int ret;
if (!enable) {
- rkisp1_isp_stop(rkisp1);
- rkisp1_mipi_csi2_stop(rkisp1->active_sensor);
+ v4l2_subdev_call(rkisp1->source, video, s_stream, false);
+ rkisp1_isp_stop(isp);
return 0;
}
- sensor_sd = rkisp1_get_remote_sensor(sd);
- if (!sensor_sd) {
- dev_warn(rkisp1->dev, "No link between isp and sensor\n");
- return -ENODEV;
+ sink_pad = &isp->pads[RKISP1_ISP_PAD_SINK_VIDEO];
+ source_pad = media_pad_remote_pad_unique(sink_pad);
+ if (IS_ERR(source_pad)) {
+ dev_dbg(rkisp1->dev, "Failed to get source for ISP: %ld\n",
+ PTR_ERR(source_pad));
+ return -EPIPE;
}
- rkisp1->active_sensor = container_of(sensor_sd->asd,
- struct rkisp1_sensor_async, asd);
+ rkisp1->source = media_entity_to_v4l2_subdev(source_pad->entity);
+ if (!rkisp1->source) {
+ /* This should really not happen, so is not worth a message. */
+ return -EPIPE;
+ }
- if (rkisp1->active_sensor->mbus_type != V4L2_MBUS_CSI2_DPHY)
- return -EINVAL;
+ if (rkisp1->source == &rkisp1->csi.sd) {
+ mbus_type = V4L2_MBUS_CSI2_DPHY;
+ mbus_flags = 0;
+ } else {
+ const struct rkisp1_sensor_async *asd;
- rkisp1->isp.frame_sequence = -1;
+ asd = container_of(rkisp1->source->asd,
+ struct rkisp1_sensor_async, asd);
+
+ mbus_type = asd->mbus_type;
+ mbus_flags = asd->mbus_flags;
+ }
+
+ isp->frame_sequence = -1;
mutex_lock(&isp->ops_lock);
- ret = rkisp1_config_cif(rkisp1);
+ ret = rkisp1_config_cif(isp, mbus_type, mbus_flags);
if (ret)
goto mutex_unlock;
- ret = rkisp1_mipi_csi2_start(&rkisp1->isp, rkisp1->active_sensor);
- if (ret)
- goto mutex_unlock;
+ rkisp1_isp_start(isp);
- rkisp1_isp_start(rkisp1);
+ ret = v4l2_subdev_call(rkisp1->source, video, s_stream, true);
+ if (ret) {
+ rkisp1_isp_stop(isp);
+ goto mutex_unlock;
+ }
mutex_unlock:
mutex_unlock(&isp->ops_lock);
@@ -1067,12 +821,14 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1)
{
struct v4l2_subdev_state state = {
.pads = rkisp1->isp.pad_cfg
- };
+ };
struct rkisp1_isp *isp = &rkisp1->isp;
struct media_pad *pads = isp->pads;
struct v4l2_subdev *sd = &isp->sd;
int ret;
+ isp->rkisp1 = rkisp1;
+
v4l2_subdev_init(sd, &rkisp1_isp_ops);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
sd->entity.ops = &rkisp1_isp_media_ops;
@@ -1086,95 +842,54 @@ int rkisp1_isp_register(struct rkisp1_device *rkisp1)
pads[RKISP1_ISP_PAD_SOURCE_VIDEO].flags = MEDIA_PAD_FL_SOURCE;
pads[RKISP1_ISP_PAD_SOURCE_STATS].flags = MEDIA_PAD_FL_SOURCE;
- isp->sink_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SINK_PAD_FMT);
- isp->src_fmt = rkisp1_isp_mbus_info_get(RKISP1_DEF_SRC_PAD_FMT);
+ isp->sink_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SINK_PAD_FMT);
+ isp->src_fmt = rkisp1_mbus_info_get_by_code(RKISP1_DEF_SRC_PAD_FMT);
mutex_init(&isp->ops_lock);
ret = media_entity_pads_init(&sd->entity, RKISP1_ISP_PAD_MAX, pads);
if (ret)
- return ret;
+ goto error;
ret = v4l2_device_register_subdev(&rkisp1->v4l2_dev, sd);
if (ret) {
dev_err(rkisp1->dev, "Failed to register isp subdev\n");
- goto err_cleanup_media_entity;
+ goto error;
}
rkisp1_isp_init_config(sd, &state);
+
return 0;
-err_cleanup_media_entity:
+error:
media_entity_cleanup(&sd->entity);
-
+ mutex_destroy(&isp->ops_lock);
+ isp->sd.v4l2_dev = NULL;
return ret;
}
void rkisp1_isp_unregister(struct rkisp1_device *rkisp1)
{
- struct v4l2_subdev *sd = &rkisp1->isp.sd;
+ struct rkisp1_isp *isp = &rkisp1->isp;
- v4l2_device_unregister_subdev(sd);
- media_entity_cleanup(&sd->entity);
+ if (!isp->sd.v4l2_dev)
+ return;
+
+ v4l2_device_unregister_subdev(&isp->sd);
+ media_entity_cleanup(&isp->sd.entity);
+ mutex_destroy(&isp->ops_lock);
}
/* ----------------------------------------------------------------------------
* Interrupt handlers
*/
-irqreturn_t rkisp1_mipi_isr(int irq, void *ctx)
-{
- struct device *dev = ctx;
- struct rkisp1_device *rkisp1 = dev_get_drvdata(dev);
- u32 val, status;
-
- status = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_MIS);
- if (!status)
- return IRQ_NONE;
-
- rkisp1_write(rkisp1, status, RKISP1_CIF_MIPI_ICR);
-
- /*
- * Disable DPHY errctrl interrupt, because this dphy
- * erctrl signal is asserted until the next changes
- * of line state. This time is may be too long and cpu
- * is hold in this interrupt.
- */
- if (status & RKISP1_CIF_MIPI_ERR_CTRL(0x0f)) {
- val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
- rkisp1_write(rkisp1, val & ~RKISP1_CIF_MIPI_ERR_CTRL(0x0f),
- RKISP1_CIF_MIPI_IMSC);
- rkisp1->isp.is_dphy_errctrl_disabled = true;
- }
-
- /*
- * Enable DPHY errctrl interrupt again, if mipi have receive
- * the whole frame without any error.
- */
- if (status == RKISP1_CIF_MIPI_FRAME_END) {
- /*
- * Enable DPHY errctrl interrupt again, if mipi have receive
- * the whole frame without any error.
- */
- if (rkisp1->isp.is_dphy_errctrl_disabled) {
- val = rkisp1_read(rkisp1, RKISP1_CIF_MIPI_IMSC);
- val |= RKISP1_CIF_MIPI_ERR_CTRL(0x0f);
- rkisp1_write(rkisp1, val, RKISP1_CIF_MIPI_IMSC);
- rkisp1->isp.is_dphy_errctrl_disabled = false;
- }
- } else {
- rkisp1->debug.mipi_error++;
- }
-
- return IRQ_HANDLED;
-}
-
static void rkisp1_isp_queue_event_sof(struct rkisp1_isp *isp)
{
struct v4l2_event event = {
.type = V4L2_EVENT_FRAME_SYNC,
};
- event.u.frame_sync.frame_sequence = isp->frame_sequence;
+ event.u.frame_sync.frame_sequence = isp->frame_sequence;
v4l2_event_queue(isp->sd.devnode, &event);
}
@@ -1188,7 +903,7 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx)
if (!status)
return IRQ_NONE;
- rkisp1_write(rkisp1, status, RKISP1_CIF_ISP_ICR);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, status);
/* Vertical sync signal, starting generating new frame */
if (status & RKISP1_CIF_ISP_V_START) {
@@ -1208,7 +923,7 @@ irqreturn_t rkisp1_isp_isr(int irq, void *ctx)
rkisp1->debug.img_stabilization_size_error++;
if (isp_err & RKISP1_CIF_ISP_ERR_OUTFORM_SIZE)
rkisp1->debug.outform_size_error++;
- rkisp1_write(rkisp1, isp_err, RKISP1_CIF_ISP_ERR_CLR);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ERR_CLR, isp_err);
} else if (status & RKISP1_CIF_ISP_DATA_LOSS) {
/* keep track of data_loss in debugfs */
rkisp1->debug.data_loss++;
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
index 8f62f09e635f..9da7dc1bc690 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
@@ -37,7 +37,7 @@ rkisp1_param_set_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask)
u32 val;
val = rkisp1_read(params->rkisp1, reg);
- rkisp1_write(params->rkisp1, val | bit_mask, reg);
+ rkisp1_write(params->rkisp1, reg, val | bit_mask);
}
static inline void
@@ -46,7 +46,7 @@ rkisp1_param_clear_bits(struct rkisp1_params *params, u32 reg, u32 bit_mask)
u32 val;
val = rkisp1_read(params->rkisp1, reg);
- rkisp1_write(params->rkisp1, val & ~bit_mask, reg);
+ rkisp1_write(params->rkisp1, reg, val & ~bit_mask);
}
/* ISP BP interface function */
@@ -60,35 +60,35 @@ static void rkisp1_dpcc_config(struct rkisp1_params *params,
mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE);
mode &= RKISP1_CIF_ISP_DPCC_ENA;
mode |= arg->mode & ~RKISP1_CIF_ISP_DPCC_ENA;
- rkisp1_write(params->rkisp1, mode, RKISP1_CIF_ISP_DPCC_MODE);
- rkisp1_write(params->rkisp1, arg->output_mode,
- RKISP1_CIF_ISP_DPCC_OUTPUT_MODE);
- rkisp1_write(params->rkisp1, arg->set_use,
- RKISP1_CIF_ISP_DPCC_SET_USE);
-
- rkisp1_write(params->rkisp1, arg->methods[0].method,
- RKISP1_CIF_ISP_DPCC_METHODS_SET_1);
- rkisp1_write(params->rkisp1, arg->methods[1].method,
- RKISP1_CIF_ISP_DPCC_METHODS_SET_2);
- rkisp1_write(params->rkisp1, arg->methods[2].method,
- RKISP1_CIF_ISP_DPCC_METHODS_SET_3);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_MODE, mode);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_OUTPUT_MODE,
+ arg->output_mode);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_SET_USE,
+ arg->set_use);
+
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_1,
+ arg->methods[0].method);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_2,
+ arg->methods[1].method);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_METHODS_SET_3,
+ arg->methods[2].method);
for (i = 0; i < RKISP1_CIF_ISP_DPCC_METHODS_MAX; i++) {
- rkisp1_write(params->rkisp1, arg->methods[i].line_thresh,
- RKISP1_ISP_DPCC_LINE_THRESH(i));
- rkisp1_write(params->rkisp1, arg->methods[i].line_mad_fac,
- RKISP1_ISP_DPCC_LINE_MAD_FAC(i));
- rkisp1_write(params->rkisp1, arg->methods[i].pg_fac,
- RKISP1_ISP_DPCC_PG_FAC(i));
- rkisp1_write(params->rkisp1, arg->methods[i].rnd_thresh,
- RKISP1_ISP_DPCC_RND_THRESH(i));
- rkisp1_write(params->rkisp1, arg->methods[i].rg_fac,
- RKISP1_ISP_DPCC_RG_FAC(i));
+ rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_THRESH(i),
+ arg->methods[i].line_thresh);
+ rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_LINE_MAD_FAC(i),
+ arg->methods[i].line_mad_fac);
+ rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_PG_FAC(i),
+ arg->methods[i].pg_fac);
+ rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RND_THRESH(i),
+ arg->methods[i].rnd_thresh);
+ rkisp1_write(params->rkisp1, RKISP1_ISP_DPCC_RG_FAC(i),
+ arg->methods[i].rg_fac);
}
- rkisp1_write(params->rkisp1, arg->rnd_offs,
- RKISP1_CIF_ISP_DPCC_RND_OFFS);
- rkisp1_write(params->rkisp1, arg->ro_limits,
- RKISP1_CIF_ISP_DPCC_RO_LIMITS);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RND_OFFS,
+ arg->rnd_offs);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPCC_RO_LIMITS,
+ arg->ro_limits);
}
/* ISP black level subtraction interface function */
@@ -107,44 +107,44 @@ static void rkisp1_bls_config(struct rkisp1_params *params,
switch (params->raw_type) {
case RKISP1_RAW_BGGR:
- rkisp1_write(params->rkisp1,
- pval->r, RKISP1_CIF_ISP_BLS_D_FIXED);
- rkisp1_write(params->rkisp1,
- pval->gr, RKISP1_CIF_ISP_BLS_C_FIXED);
- rkisp1_write(params->rkisp1,
- pval->gb, RKISP1_CIF_ISP_BLS_B_FIXED);
- rkisp1_write(params->rkisp1,
- pval->b, RKISP1_CIF_ISP_BLS_A_FIXED);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED,
+ pval->r);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED,
+ pval->gr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED,
+ pval->gb);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED,
+ pval->b);
break;
case RKISP1_RAW_GBRG:
- rkisp1_write(params->rkisp1,
- pval->r, RKISP1_CIF_ISP_BLS_C_FIXED);
- rkisp1_write(params->rkisp1,
- pval->gr, RKISP1_CIF_ISP_BLS_D_FIXED);
- rkisp1_write(params->rkisp1,
- pval->gb, RKISP1_CIF_ISP_BLS_A_FIXED);
- rkisp1_write(params->rkisp1,
- pval->b, RKISP1_CIF_ISP_BLS_B_FIXED);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED,
+ pval->r);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED,
+ pval->gr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED,
+ pval->gb);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED,
+ pval->b);
break;
case RKISP1_RAW_GRBG:
- rkisp1_write(params->rkisp1,
- pval->r, RKISP1_CIF_ISP_BLS_B_FIXED);
- rkisp1_write(params->rkisp1,
- pval->gr, RKISP1_CIF_ISP_BLS_A_FIXED);
- rkisp1_write(params->rkisp1,
- pval->gb, RKISP1_CIF_ISP_BLS_D_FIXED);
- rkisp1_write(params->rkisp1,
- pval->b, RKISP1_CIF_ISP_BLS_C_FIXED);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED,
+ pval->r);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED,
+ pval->gr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED,
+ pval->gb);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED,
+ pval->b);
break;
case RKISP1_RAW_RGGB:
- rkisp1_write(params->rkisp1,
- pval->r, RKISP1_CIF_ISP_BLS_A_FIXED);
- rkisp1_write(params->rkisp1,
- pval->gr, RKISP1_CIF_ISP_BLS_B_FIXED);
- rkisp1_write(params->rkisp1,
- pval->gb, RKISP1_CIF_ISP_BLS_C_FIXED);
- rkisp1_write(params->rkisp1,
- pval->b, RKISP1_CIF_ISP_BLS_D_FIXED);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_A_FIXED,
+ pval->r);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_B_FIXED,
+ pval->gr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_C_FIXED,
+ pval->gb);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_D_FIXED,
+ pval->b);
break;
default:
break;
@@ -152,35 +152,35 @@ static void rkisp1_bls_config(struct rkisp1_params *params,
} else {
if (arg->en_windows & BIT(1)) {
- rkisp1_write(params->rkisp1, arg->bls_window2.h_offs,
- RKISP1_CIF_ISP_BLS_H2_START);
- rkisp1_write(params->rkisp1, arg->bls_window2.h_size,
- RKISP1_CIF_ISP_BLS_H2_STOP);
- rkisp1_write(params->rkisp1, arg->bls_window2.v_offs,
- RKISP1_CIF_ISP_BLS_V2_START);
- rkisp1_write(params->rkisp1, arg->bls_window2.v_size,
- RKISP1_CIF_ISP_BLS_V2_STOP);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H2_START,
+ arg->bls_window2.h_offs);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H2_STOP,
+ arg->bls_window2.h_size);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V2_START,
+ arg->bls_window2.v_offs);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V2_STOP,
+ arg->bls_window2.v_size);
new_control |= RKISP1_CIF_ISP_BLS_WINDOW_2;
}
if (arg->en_windows & BIT(0)) {
- rkisp1_write(params->rkisp1, arg->bls_window1.h_offs,
- RKISP1_CIF_ISP_BLS_H1_START);
- rkisp1_write(params->rkisp1, arg->bls_window1.h_size,
- RKISP1_CIF_ISP_BLS_H1_STOP);
- rkisp1_write(params->rkisp1, arg->bls_window1.v_offs,
- RKISP1_CIF_ISP_BLS_V1_START);
- rkisp1_write(params->rkisp1, arg->bls_window1.v_size,
- RKISP1_CIF_ISP_BLS_V1_STOP);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H1_START,
+ arg->bls_window1.h_offs);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_H1_STOP,
+ arg->bls_window1.h_size);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V1_START,
+ arg->bls_window1.v_offs);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_V1_STOP,
+ arg->bls_window1.v_size);
new_control |= RKISP1_CIF_ISP_BLS_WINDOW_1;
}
- rkisp1_write(params->rkisp1, arg->bls_samples,
- RKISP1_CIF_ISP_BLS_SAMPLES);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_SAMPLES,
+ arg->bls_samples);
new_control |= RKISP1_CIF_ISP_BLS_MODE_MEASURED;
}
- rkisp1_write(params->rkisp1, new_control, RKISP1_CIF_ISP_BLS_CTRL);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_BLS_CTRL, new_control);
}
/* ISP LS correction interface function */
@@ -196,14 +196,10 @@ rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params,
sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ?
RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 :
RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153;
- rkisp1_write(params->rkisp1, sram_addr,
- RKISP1_CIF_ISP_LSC_R_TABLE_ADDR);
- rkisp1_write(params->rkisp1, sram_addr,
- RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR);
- rkisp1_write(params->rkisp1, sram_addr,
- RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR);
- rkisp1_write(params->rkisp1, sram_addr,
- RKISP1_CIF_ISP_LSC_B_TABLE_ADDR);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr);
/* program data tables (table size is 9 * 17 = 153) */
for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) {
@@ -214,45 +210,45 @@ rkisp1_lsc_matrix_config_v10(struct rkisp1_params *params,
for (j = 0; j < RKISP1_CIF_ISP_LSC_SAMPLES_MAX - 1; j += 2) {
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j],
pconfig->r_data_tbl[i][j + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_R_TABLE_DATA);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j],
pconfig->gr_data_tbl[i][j + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_GR_TABLE_DATA);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j],
pconfig->gb_data_tbl[i][j + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_GB_TABLE_DATA);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j],
pconfig->b_data_tbl[i][j + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_B_TABLE_DATA);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data);
}
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->r_data_tbl[i][j], 0);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_R_TABLE_DATA);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA,
+ data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gr_data_tbl[i][j], 0);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_GR_TABLE_DATA);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA,
+ data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->gb_data_tbl[i][j], 0);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_GB_TABLE_DATA);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA,
+ data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V10(pconfig->b_data_tbl[i][j], 0);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_B_TABLE_DATA);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA,
+ data);
}
isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ?
RKISP1_CIF_ISP_LSC_TABLE_0 :
RKISP1_CIF_ISP_LSC_TABLE_1;
- rkisp1_write(params->rkisp1, isp_lsc_table_sel,
- RKISP1_CIF_ISP_LSC_TABLE_SEL);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL,
+ isp_lsc_table_sel);
}
static void
@@ -267,10 +263,10 @@ rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params,
sram_addr = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ?
RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_0 :
RKISP1_CIF_ISP_LSC_TABLE_ADDRESS_153;
- rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR);
- rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR);
- rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR);
- rkisp1_write(params->rkisp1, sram_addr, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_ADDR, sram_addr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_ADDR, sram_addr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_ADDR, sram_addr);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_ADDR, sram_addr);
/* program data tables (table size is 9 * 17 = 153) */
for (i = 0; i < RKISP1_CIF_ISP_LSC_SAMPLES_MAX; i++) {
@@ -282,49 +278,49 @@ rkisp1_lsc_matrix_config_v12(struct rkisp1_params *params,
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(
pconfig->r_data_tbl[i][j],
pconfig->r_data_tbl[i][j + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_R_TABLE_DATA);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_R_TABLE_DATA, data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(
pconfig->gr_data_tbl[i][j],
pconfig->gr_data_tbl[i][j + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_GR_TABLE_DATA);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_GR_TABLE_DATA, data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(
pconfig->gb_data_tbl[i][j],
pconfig->gb_data_tbl[i][j + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_GB_TABLE_DATA);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_GB_TABLE_DATA, data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(
pconfig->b_data_tbl[i][j],
pconfig->b_data_tbl[i][j + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_B_TABLE_DATA);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_B_TABLE_DATA, data);
}
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->r_data_tbl[i][j], 0);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_R_TABLE_DATA);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_R_TABLE_DATA,
+ data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gr_data_tbl[i][j], 0);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_GR_TABLE_DATA);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GR_TABLE_DATA,
+ data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->gb_data_tbl[i][j], 0);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_GB_TABLE_DATA);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_GB_TABLE_DATA,
+ data);
data = RKISP1_CIF_ISP_LSC_TABLE_DATA_V12(pconfig->b_data_tbl[i][j], 0);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_B_TABLE_DATA);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_B_TABLE_DATA,
+ data);
}
isp_lsc_table_sel = (isp_lsc_status & RKISP1_CIF_ISP_LSC_ACTIVE_TABLE) ?
RKISP1_CIF_ISP_LSC_TABLE_0 :
RKISP1_CIF_ISP_LSC_TABLE_1;
- rkisp1_write(params->rkisp1, isp_lsc_table_sel,
- RKISP1_CIF_ISP_LSC_TABLE_SEL);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_LSC_TABLE_SEL,
+ isp_lsc_table_sel);
}
static void rkisp1_lsc_config(struct rkisp1_params *params,
@@ -343,26 +339,26 @@ static void rkisp1_lsc_config(struct rkisp1_params *params,
/* program x size tables */
data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_size_tbl[i * 2],
arg->x_size_tbl[i * 2 + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_XSIZE_01 + i * 4, data);
/* program x grad tables */
data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->x_grad_tbl[i * 2],
arg->x_grad_tbl[i * 2 + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_XGRAD_01 + i * 4, data);
/* program y size tables */
data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_size_tbl[i * 2],
arg->y_size_tbl[i * 2 + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_YSIZE_01 + i * 4, data);
/* program y grad tables */
data = RKISP1_CIF_ISP_LSC_SECT_SIZE(arg->y_grad_tbl[i * 2],
arg->y_grad_tbl[i * 2 + 1]);
- rkisp1_write(params->rkisp1, data,
- RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_LSC_YGRAD_01 + i * 4, data);
}
/* restore the lsc ctrl status */
@@ -383,28 +379,32 @@ static void rkisp1_flt_config(struct rkisp1_params *params,
{
u32 filt_mode;
- rkisp1_write(params->rkisp1,
- arg->thresh_bl0, RKISP1_CIF_ISP_FILT_THRESH_BL0);
- rkisp1_write(params->rkisp1,
- arg->thresh_bl1, RKISP1_CIF_ISP_FILT_THRESH_BL1);
- rkisp1_write(params->rkisp1,
- arg->thresh_sh0, RKISP1_CIF_ISP_FILT_THRESH_SH0);
- rkisp1_write(params->rkisp1,
- arg->thresh_sh1, RKISP1_CIF_ISP_FILT_THRESH_SH1);
- rkisp1_write(params->rkisp1, arg->fac_bl0, RKISP1_CIF_ISP_FILT_FAC_BL0);
- rkisp1_write(params->rkisp1, arg->fac_bl1, RKISP1_CIF_ISP_FILT_FAC_BL1);
- rkisp1_write(params->rkisp1, arg->fac_mid, RKISP1_CIF_ISP_FILT_FAC_MID);
- rkisp1_write(params->rkisp1, arg->fac_sh0, RKISP1_CIF_ISP_FILT_FAC_SH0);
- rkisp1_write(params->rkisp1, arg->fac_sh1, RKISP1_CIF_ISP_FILT_FAC_SH1);
- rkisp1_write(params->rkisp1,
- arg->lum_weight, RKISP1_CIF_ISP_FILT_LUM_WEIGHT);
-
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_BL0,
+ arg->thresh_bl0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_BL1,
+ arg->thresh_bl1);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_SH0,
+ arg->thresh_sh0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_THRESH_SH1,
+ arg->thresh_sh1);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_BL0,
+ arg->fac_bl0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_BL1,
+ arg->fac_bl1);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_MID,
+ arg->fac_mid);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_SH0,
+ arg->fac_sh0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_FAC_SH1,
+ arg->fac_sh1);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_LUM_WEIGHT,
+ arg->lum_weight);
+
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE,
(arg->mode ? RKISP1_CIF_ISP_FLT_MODE_DNR : 0) |
RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) |
RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) |
- RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1),
- RKISP1_CIF_ISP_FILT_MODE);
+ RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1));
/* avoid to override the old enable value */
filt_mode = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE);
@@ -414,7 +414,7 @@ static void rkisp1_flt_config(struct rkisp1_params *params,
filt_mode |= RKISP1_CIF_ISP_FLT_CHROMA_V_MODE(arg->chr_v_mode) |
RKISP1_CIF_ISP_FLT_CHROMA_H_MODE(arg->chr_h_mode) |
RKISP1_CIF_ISP_FLT_GREEN_STAGE1(arg->grn_stage1);
- rkisp1_write(params->rkisp1, filt_mode, RKISP1_CIF_ISP_FILT_MODE);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_FILT_MODE, filt_mode);
}
/* ISP demosaic interface function */
@@ -428,7 +428,7 @@ static int rkisp1_bdm_config(struct rkisp1_params *params,
bdm_th &= RKISP1_CIF_ISP_DEMOSAIC_BYPASS;
bdm_th |= arg->demosaic_th & ~RKISP1_CIF_ISP_DEMOSAIC_BYPASS;
/* set demosaic threshold */
- rkisp1_write(params->rkisp1, bdm_th, RKISP1_CIF_ISP_DEMOSAIC);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DEMOSAIC, bdm_th);
return 0;
}
@@ -438,18 +438,21 @@ static void rkisp1_sdg_config(struct rkisp1_params *params,
{
unsigned int i;
- rkisp1_write(params->rkisp1,
- arg->xa_pnts.gamma_dx0, RKISP1_CIF_ISP_GAMMA_DX_LO);
- rkisp1_write(params->rkisp1,
- arg->xa_pnts.gamma_dx1, RKISP1_CIF_ISP_GAMMA_DX_HI);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_DX_LO,
+ arg->xa_pnts.gamma_dx0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_DX_HI,
+ arg->xa_pnts.gamma_dx1);
for (i = 0; i < RKISP1_CIF_ISP_DEGAMMA_CURVE_SIZE; i++) {
- rkisp1_write(params->rkisp1, arg->curve_r.gamma_y[i],
- RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4);
- rkisp1_write(params->rkisp1, arg->curve_g.gamma_y[i],
- RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4);
- rkisp1_write(params->rkisp1, arg->curve_b.gamma_y[i],
- RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_GAMMA_R_Y0 + i * 4,
+ arg->curve_r.gamma_y[i]);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_GAMMA_G_Y0 + i * 4,
+ arg->curve_g.gamma_y[i]);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_GAMMA_B_Y0 + i * 4,
+ arg->curve_b.gamma_y[i]);
}
}
@@ -461,11 +464,13 @@ static void rkisp1_goc_config_v10(struct rkisp1_params *params,
rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL,
RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA);
- rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V10,
+ arg->mode);
for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V10; i++)
- rkisp1_write(params->rkisp1, arg->gamma_y[i],
- RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V10 + i * 4,
+ arg->gamma_y[i]);
}
static void rkisp1_goc_config_v12(struct rkisp1_params *params,
@@ -476,14 +481,15 @@ static void rkisp1_goc_config_v12(struct rkisp1_params *params,
rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL,
RKISP1_CIF_ISP_CTRL_ISP_GAMMA_OUT_ENA);
- rkisp1_write(params->rkisp1, arg->mode, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_GAMMA_OUT_MODE_V12,
+ arg->mode);
for (i = 0; i < RKISP1_CIF_ISP_GAMMA_OUT_MAX_SAMPLES_V12 / 2; i++) {
value = RKISP1_CIF_ISP_GAMMA_VALUE_V12(
arg->gamma_y[2 * i + 1],
arg->gamma_y[2 * i]);
- rkisp1_write(params->rkisp1, value,
- RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_GAMMA_OUT_Y_0_V12 + i * 4, value);
}
}
@@ -495,11 +501,13 @@ static void rkisp1_ctk_config(struct rkisp1_params *params,
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
- rkisp1_write(params->rkisp1, arg->coeff[i][j],
- RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_CT_COEFF_0 + 4 * k++,
+ arg->coeff[i][j]);
for (i = 0; i < 3; i++)
- rkisp1_write(params->rkisp1, arg->ct_offset[i],
- RKISP1_CIF_ISP_CT_OFFSET_R + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_CT_OFFSET_R + i * 4,
+ arg->ct_offset[i]);
}
static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en)
@@ -508,19 +516,19 @@ static void rkisp1_ctk_enable(struct rkisp1_params *params, bool en)
return;
/* Write back the default values. */
- rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_0);
- rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_1);
- rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_2);
- rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_3);
- rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_4);
- rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_5);
- rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_6);
- rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_COEFF_7);
- rkisp1_write(params->rkisp1, 0x80, RKISP1_CIF_ISP_CT_COEFF_8);
-
- rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_R);
- rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_G);
- rkisp1_write(params->rkisp1, 0, RKISP1_CIF_ISP_CT_OFFSET_B);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_0, 0x80);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_1, 0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_2, 0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_3, 0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_4, 0x80);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_5, 0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_6, 0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_7, 0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_COEFF_8, 0x80);
+
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_R, 0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_G, 0);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_CT_OFFSET_B, 0);
}
/* ISP White Balance Mode */
@@ -531,15 +539,15 @@ static void rkisp1_awb_meas_config_v10(struct rkisp1_params *params,
/* based on the mode,configure the awb module */
if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) {
/* Reference Cb and Cr */
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_REF_V10,
RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) |
- arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF_V10);
+ arg->awb_ref_cb);
/* Yc Threshold */
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_THRESH_V10,
RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) |
RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) |
RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) |
- arg->min_c, RKISP1_CIF_ISP_AWB_THRESH_V10);
+ arg->min_c);
}
reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10);
@@ -547,21 +555,21 @@ static void rkisp1_awb_meas_config_v10(struct rkisp1_params *params,
reg_val |= RKISP1_CIF_ISP_AWB_YMAX_CMP_EN;
else
reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN;
- rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10, reg_val);
/* window offset */
- rkisp1_write(params->rkisp1,
- arg->awb_wnd.v_offs, RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10);
- rkisp1_write(params->rkisp1,
- arg->awb_wnd.h_offs, RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_V_OFFS_V10,
+ arg->awb_wnd.v_offs);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_H_OFFS_V10,
+ arg->awb_wnd.h_offs);
/* AWB window size */
- rkisp1_write(params->rkisp1,
- arg->awb_wnd.v_size, RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10);
- rkisp1_write(params->rkisp1,
- arg->awb_wnd.h_size, RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_V_SIZE_V10,
+ arg->awb_wnd.v_size);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_WND_H_SIZE_V10,
+ arg->awb_wnd.h_size);
/* Number of frames */
- rkisp1_write(params->rkisp1,
- arg->frames, RKISP1_CIF_ISP_AWB_FRAMES_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_FRAMES_V10,
+ arg->frames);
}
static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params,
@@ -571,15 +579,15 @@ static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params,
/* based on the mode,configure the awb module */
if (arg->awb_mode == RKISP1_CIF_ISP_AWB_MODE_YCBCR) {
/* Reference Cb and Cr */
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_REF_V12,
RKISP1_CIF_ISP_AWB_REF_CR_SET(arg->awb_ref_cr) |
- arg->awb_ref_cb, RKISP1_CIF_ISP_AWB_REF_V12);
+ arg->awb_ref_cb);
/* Yc Threshold */
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_THRESH_V12,
RKISP1_CIF_ISP_AWB_MAX_Y_SET(arg->max_y) |
RKISP1_CIF_ISP_AWB_MIN_Y_SET(arg->min_y) |
RKISP1_CIF_ISP_AWB_MAX_CS_SET(arg->max_csum) |
- arg->min_c, RKISP1_CIF_ISP_AWB_THRESH_V12);
+ arg->min_c);
}
reg_val = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12);
@@ -589,18 +597,14 @@ static void rkisp1_awb_meas_config_v12(struct rkisp1_params *params,
reg_val &= ~RKISP1_CIF_ISP_AWB_YMAX_CMP_EN;
reg_val &= ~RKISP1_CIF_ISP_AWB_SET_FRAMES_MASK_V12;
reg_val |= RKISP1_CIF_ISP_AWB_SET_FRAMES_V12(arg->frames);
- rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V12);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12, reg_val);
/* window offset */
- rkisp1_write(params->rkisp1,
- arg->awb_wnd.v_offs << 16 |
- arg->awb_wnd.h_offs,
- RKISP1_CIF_ISP_AWB_OFFS_V12);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_OFFS_V12,
+ arg->awb_wnd.v_offs << 16 | arg->awb_wnd.h_offs);
/* AWB window size */
- rkisp1_write(params->rkisp1,
- arg->awb_wnd.v_size << 16 |
- arg->awb_wnd.h_size,
- RKISP1_CIF_ISP_AWB_SIZE_V12);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_SIZE_V12,
+ arg->awb_wnd.v_size << 16 | arg->awb_wnd.h_size);
}
static void
@@ -619,14 +623,15 @@ rkisp1_awb_meas_enable_v10(struct rkisp1_params *params,
else
reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN;
- rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10,
+ reg_val);
/* Measurements require AWB block be active. */
rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL,
RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA);
} else {
- rkisp1_write(params->rkisp1,
- reg_val, RKISP1_CIF_ISP_AWB_PROP_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V10,
+ reg_val);
rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL,
RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA);
}
@@ -648,14 +653,15 @@ rkisp1_awb_meas_enable_v12(struct rkisp1_params *params,
else
reg_val |= RKISP1_CIF_ISP_AWB_MODE_YCBCR_EN;
- rkisp1_write(params->rkisp1, reg_val, RKISP1_CIF_ISP_AWB_PROP_V12);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12,
+ reg_val);
/* Measurements require AWB block be active. */
rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL,
RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA);
} else {
- rkisp1_write(params->rkisp1,
- reg_val, RKISP1_CIF_ISP_AWB_PROP_V12);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_PROP_V12,
+ reg_val);
rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL,
RKISP1_CIF_ISP_CTRL_ISP_AWB_ENA);
}
@@ -665,26 +671,26 @@ static void
rkisp1_awb_gain_config_v10(struct rkisp1_params *params,
const struct rkisp1_cif_isp_awb_gain_config *arg)
{
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_G_V10,
RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) |
- arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G_V10);
+ arg->gain_green_b);
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_RB_V10,
RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) |
- arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB_V10);
+ arg->gain_blue);
}
static void
rkisp1_awb_gain_config_v12(struct rkisp1_params *params,
const struct rkisp1_cif_isp_awb_gain_config *arg)
{
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_G_V12,
RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_green_r) |
- arg->gain_green_b, RKISP1_CIF_ISP_AWB_GAIN_G_V12);
+ arg->gain_green_b);
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AWB_GAIN_RB_V12,
RKISP1_CIF_ISP_AWB_GAIN_R_SET(arg->gain_red) |
- arg->gain_blue, RKISP1_CIF_ISP_AWB_GAIN_RB_V12);
+ arg->gain_blue);
}
static void rkisp1_aec_config_v10(struct rkisp1_params *params,
@@ -700,24 +706,22 @@ static void rkisp1_aec_config_v10(struct rkisp1_params *params,
exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_AUTOSTOP;
if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1)
exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1;
- rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL, exp_ctrl);
- rkisp1_write(params->rkisp1,
- arg->meas_window.h_offs, RKISP1_CIF_ISP_EXP_H_OFFSET_V10);
- rkisp1_write(params->rkisp1,
- arg->meas_window.v_offs, RKISP1_CIF_ISP_EXP_V_OFFSET_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_H_OFFSET_V10,
+ arg->meas_window.h_offs);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_V_OFFSET_V10,
+ arg->meas_window.v_offs);
block_hsize = arg->meas_window.h_size /
RKISP1_CIF_ISP_EXP_COLUMN_NUM_V10 - 1;
block_vsize = arg->meas_window.v_size /
RKISP1_CIF_ISP_EXP_ROW_NUM_V10 - 1;
- rkisp1_write(params->rkisp1,
- RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(block_hsize),
- RKISP1_CIF_ISP_EXP_H_SIZE_V10);
- rkisp1_write(params->rkisp1,
- RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(block_vsize),
- RKISP1_CIF_ISP_EXP_V_SIZE_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_H_SIZE_V10,
+ RKISP1_CIF_ISP_EXP_H_SIZE_SET_V10(block_hsize));
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_V_SIZE_V10,
+ RKISP1_CIF_ISP_EXP_V_SIZE_SET_V10(block_vsize));
}
static void rkisp1_aec_config_v12(struct rkisp1_params *params,
@@ -736,20 +740,18 @@ static void rkisp1_aec_config_v12(struct rkisp1_params *params,
if (arg->mode == RKISP1_CIF_ISP_EXP_MEASURING_MODE_1)
exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_MEASMODE_1;
exp_ctrl |= RKISP1_CIF_ISP_EXP_CTRL_WNDNUM_SET_V12(wnd_num_idx);
- rkisp1_write(params->rkisp1, exp_ctrl, RKISP1_CIF_ISP_EXP_CTRL);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_CTRL, exp_ctrl);
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_OFFS_V12,
RKISP1_CIF_ISP_EXP_V_OFFSET_SET_V12(arg->meas_window.v_offs) |
- RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(arg->meas_window.h_offs),
- RKISP1_CIF_ISP_EXP_OFFS_V12);
+ RKISP1_CIF_ISP_EXP_H_OFFSET_SET_V12(arg->meas_window.h_offs));
block_hsize = arg->meas_window.h_size / ae_wnd_num[wnd_num_idx] - 1;
block_vsize = arg->meas_window.v_size / ae_wnd_num[wnd_num_idx] - 1;
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_EXP_SIZE_V12,
RKISP1_CIF_ISP_EXP_V_SIZE_SET_V12(block_vsize) |
- RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(block_hsize),
- RKISP1_CIF_ISP_EXP_SIZE_V12);
+ RKISP1_CIF_ISP_EXP_H_SIZE_SET_V12(block_hsize));
}
static void rkisp1_cproc_config(struct rkisp1_params *params,
@@ -762,11 +764,12 @@ static void rkisp1_cproc_config(struct rkisp1_params *params,
u32 effect = cur_ie_config->effect;
u32 quantization = params->quantization;
- rkisp1_write(params->rkisp1, arg->contrast, RKISP1_CIF_C_PROC_CONTRAST);
- rkisp1_write(params->rkisp1, arg->hue, RKISP1_CIF_C_PROC_HUE);
- rkisp1_write(params->rkisp1, arg->sat, RKISP1_CIF_C_PROC_SATURATION);
- rkisp1_write(params->rkisp1, arg->brightness,
- RKISP1_CIF_C_PROC_BRIGHTNESS);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_CONTRAST,
+ arg->contrast);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_HUE, arg->hue);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_SATURATION, arg->sat);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_C_PROC_BRIGHTNESS,
+ arg->brightness);
if (quantization != V4L2_QUANTIZATION_FULL_RANGE ||
effect != V4L2_COLORFX_NONE) {
@@ -802,31 +805,29 @@ static void rkisp1_hst_config_v10(struct rkisp1_params *params,
hist_prop = rkisp1_read(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP_V10);
hist_prop &= RKISP1_CIF_ISP_HIST_PROP_MODE_MASK_V10;
hist_prop |= RKISP1_CIF_ISP_HIST_PREDIV_SET_V10(arg->histogram_predivider);
- rkisp1_write(params->rkisp1, hist_prop, RKISP1_CIF_ISP_HIST_PROP_V10);
- rkisp1_write(params->rkisp1,
- arg->meas_window.h_offs,
- RKISP1_CIF_ISP_HIST_H_OFFS_V10);
- rkisp1_write(params->rkisp1,
- arg->meas_window.v_offs,
- RKISP1_CIF_ISP_HIST_V_OFFS_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_PROP_V10, hist_prop);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_H_OFFS_V10,
+ arg->meas_window.h_offs);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_V_OFFS_V10,
+ arg->meas_window.v_offs);
block_hsize = arg->meas_window.h_size /
RKISP1_CIF_ISP_HIST_COLUMN_NUM_V10 - 1;
block_vsize = arg->meas_window.v_size / RKISP1_CIF_ISP_HIST_ROW_NUM_V10 - 1;
- rkisp1_write(params->rkisp1, block_hsize, RKISP1_CIF_ISP_HIST_H_SIZE_V10);
- rkisp1_write(params->rkisp1, block_vsize, RKISP1_CIF_ISP_HIST_V_SIZE_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_H_SIZE_V10,
+ block_hsize);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_V_SIZE_V10,
+ block_vsize);
weight = arg->hist_weight;
for (i = 0; i < ARRAY_SIZE(hist_weight_regs); ++i, weight += 4)
- rkisp1_write(params->rkisp1,
- RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(weight[0],
- weight[1],
- weight[2],
- weight[3]),
- hist_weight_regs[i]);
+ rkisp1_write(params->rkisp1, hist_weight_regs[i],
+ RKISP1_CIF_ISP_HIST_WEIGHT_SET_V10(weight[0], weight[1],
+ weight[2], weight[3]));
- rkisp1_write(params->rkisp1, weight[0] & 0x1F, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_44_V10,
+ weight[0] & 0x1F);
}
static void rkisp1_hst_config_v12(struct rkisp1_params *params,
@@ -852,18 +853,16 @@ static void rkisp1_hst_config_v12(struct rkisp1_params *params,
RKISP1_CIF_ISP_HIST_CTRL_AUTOSTOP_SET_V12(0) |
RKISP1_CIF_ISP_HIST_CTRL_WNDNUM_SET_V12(1) |
RKISP1_CIF_ISP_HIST_CTRL_STEPSIZE_SET_V12(arg->histogram_predivider);
- rkisp1_write(params->rkisp1, hist_ctrl, RKISP1_CIF_ISP_HIST_CTRL_V12);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_CTRL_V12, hist_ctrl);
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_OFFS_V12,
RKISP1_CIF_ISP_HIST_OFFS_SET_V12(arg->meas_window.h_offs,
- arg->meas_window.v_offs),
- RKISP1_CIF_ISP_HIST_OFFS_V12);
+ arg->meas_window.v_offs));
block_hsize = arg->meas_window.h_size / hist_wnd_num[wnd_num_idx] - 1;
block_vsize = arg->meas_window.v_size / hist_wnd_num[wnd_num_idx] - 1;
- rkisp1_write(params->rkisp1,
- RKISP1_CIF_ISP_HIST_SIZE_SET_V12(block_hsize, block_vsize),
- RKISP1_CIF_ISP_HIST_SIZE_V12);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_SIZE_V12,
+ RKISP1_CIF_ISP_HIST_SIZE_SET_V12(block_hsize, block_vsize));
for (i = 0; i < hist_wnd_num[wnd_num_idx]; i++) {
for (j = 0; j < hist_wnd_num[wnd_num_idx]; j++) {
@@ -879,12 +878,12 @@ static void rkisp1_hst_config_v12(struct rkisp1_params *params,
weight15x15[4 * i + 1],
weight15x15[4 * i + 2],
weight15x15[4 * i + 3]);
- rkisp1_write(params->rkisp1, value,
- RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i, value);
}
value = RKISP1_CIF_ISP_HIST_WEIGHT_SET_V12(weight15x15[4 * i + 0], 0, 0, 0);
- rkisp1_write(params->rkisp1, value,
- RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_HIST_WEIGHT_V12 + 4 * i,
+ value);
}
static void
@@ -938,22 +937,20 @@ static void rkisp1_afm_config_v10(struct rkisp1_params *params,
RKISP1_CIF_ISP_AFM_ENA);
for (i = 0; i < num_of_win; i++) {
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_LT_A + i * 8,
RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) |
- RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs),
- RKISP1_CIF_ISP_AFM_LT_A + i * 8);
- rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs));
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_RB_A + i * 8,
RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size +
arg->afm_win[i].h_offs) |
RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size +
- arg->afm_win[i].v_offs),
- RKISP1_CIF_ISP_AFM_RB_A + i * 8);
+ arg->afm_win[i].v_offs));
}
- rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES);
- rkisp1_write(params->rkisp1, arg->var_shift,
- RKISP1_CIF_ISP_AFM_VAR_SHIFT);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_THRES, arg->thres);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_VAR_SHIFT,
+ arg->var_shift);
/* restore afm status */
- rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL, afm_ctrl);
}
static void rkisp1_afm_config_v12(struct rkisp1_params *params,
@@ -970,29 +967,26 @@ static void rkisp1_afm_config_v12(struct rkisp1_params *params,
RKISP1_CIF_ISP_AFM_ENA);
for (i = 0; i < num_of_win; i++) {
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_LT_A + i * 8,
RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_offs) |
- RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs),
- RKISP1_CIF_ISP_AFM_LT_A + i * 8);
- rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_offs));
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_RB_A + i * 8,
RKISP1_CIF_ISP_AFM_WINDOW_X(arg->afm_win[i].h_size +
arg->afm_win[i].h_offs) |
RKISP1_CIF_ISP_AFM_WINDOW_Y(arg->afm_win[i].v_size +
- arg->afm_win[i].v_offs),
- RKISP1_CIF_ISP_AFM_RB_A + i * 8);
+ arg->afm_win[i].v_offs));
}
- rkisp1_write(params->rkisp1, arg->thres, RKISP1_CIF_ISP_AFM_THRES);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_THRES, arg->thres);
lum_var_shift = RKISP1_CIF_ISP_AFM_GET_LUM_SHIFT_a_V12(arg->var_shift);
afm_var_shift = RKISP1_CIF_ISP_AFM_GET_AFM_SHIFT_a_V12(arg->var_shift);
- rkisp1_write(params->rkisp1,
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_VAR_SHIFT,
RKISP1_CIF_ISP_AFM_SET_SHIFT_a_V12(lum_var_shift, afm_var_shift) |
RKISP1_CIF_ISP_AFM_SET_SHIFT_b_V12(lum_var_shift, afm_var_shift) |
- RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(lum_var_shift, afm_var_shift),
- RKISP1_CIF_ISP_AFM_VAR_SHIFT);
+ RKISP1_CIF_ISP_AFM_SET_SHIFT_c_V12(lum_var_shift, afm_var_shift));
/* restore afm status */
- rkisp1_write(params->rkisp1, afm_ctrl, RKISP1_CIF_ISP_AFM_CTRL);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_AFM_CTRL, afm_ctrl);
}
static void rkisp1_ie_config(struct rkisp1_params *params,
@@ -1011,8 +1005,8 @@ static void rkisp1_ie_config(struct rkisp1_params *params,
eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA;
break;
case V4L2_COLORFX_SET_CBCR:
- rkisp1_write(params->rkisp1, arg->eff_tint,
- RKISP1_CIF_IMG_EFF_TINT);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_TINT,
+ arg->eff_tint);
eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA;
break;
/*
@@ -1021,26 +1015,26 @@ static void rkisp1_ie_config(struct rkisp1_params *params,
*/
case V4L2_COLORFX_AQUA:
eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL;
- rkisp1_write(params->rkisp1, arg->color_sel,
- RKISP1_CIF_IMG_EFF_COLOR_SEL);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_COLOR_SEL,
+ arg->color_sel);
break;
case V4L2_COLORFX_EMBOSS:
eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS;
- rkisp1_write(params->rkisp1, arg->eff_mat_1,
- RKISP1_CIF_IMG_EFF_MAT_1);
- rkisp1_write(params->rkisp1, arg->eff_mat_2,
- RKISP1_CIF_IMG_EFF_MAT_2);
- rkisp1_write(params->rkisp1, arg->eff_mat_3,
- RKISP1_CIF_IMG_EFF_MAT_3);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_1,
+ arg->eff_mat_1);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_2,
+ arg->eff_mat_2);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_3,
+ arg->eff_mat_3);
break;
case V4L2_COLORFX_SKETCH:
eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_SKETCH;
- rkisp1_write(params->rkisp1, arg->eff_mat_3,
- RKISP1_CIF_IMG_EFF_MAT_3);
- rkisp1_write(params->rkisp1, arg->eff_mat_4,
- RKISP1_CIF_IMG_EFF_MAT_4);
- rkisp1_write(params->rkisp1, arg->eff_mat_5,
- RKISP1_CIF_IMG_EFF_MAT_5);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_3,
+ arg->eff_mat_3);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_4,
+ arg->eff_mat_4);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_MAT_5,
+ arg->eff_mat_5);
break;
case V4L2_COLORFX_BW:
eff_ctrl |= RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE;
@@ -1052,23 +1046,23 @@ static void rkisp1_ie_config(struct rkisp1_params *params,
break;
}
- rkisp1_write(params->rkisp1, eff_ctrl, RKISP1_CIF_IMG_EFF_CTRL);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL, eff_ctrl);
}
static void rkisp1_ie_enable(struct rkisp1_params *params, bool en)
{
if (en) {
- rkisp1_param_set_bits(params, RKISP1_CIF_ICCL,
- RKISP1_CIF_ICCL_IE_CLK);
- rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL_ENABLE,
- RKISP1_CIF_IMG_EFF_CTRL);
+ rkisp1_param_set_bits(params, RKISP1_CIF_VI_ICCL,
+ RKISP1_CIF_VI_ICCL_IE_CLK);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_IMG_EFF_CTRL,
+ RKISP1_CIF_IMG_EFF_CTRL_ENABLE);
rkisp1_param_set_bits(params, RKISP1_CIF_IMG_EFF_CTRL,
RKISP1_CIF_IMG_EFF_CTRL_CFG_UPD);
} else {
rkisp1_param_clear_bits(params, RKISP1_CIF_IMG_EFF_CTRL,
RKISP1_CIF_IMG_EFF_CTRL_ENABLE);
- rkisp1_param_clear_bits(params, RKISP1_CIF_ICCL,
- RKISP1_CIF_ICCL_IE_CLK);
+ rkisp1_param_clear_bits(params, RKISP1_CIF_VI_ICCL,
+ RKISP1_CIF_VI_ICCL_IE_CLK);
}
}
@@ -1088,16 +1082,18 @@ static void rkisp1_csm_config(struct rkisp1_params *params, bool full_range)
if (full_range) {
for (i = 0; i < ARRAY_SIZE(full_range_coeff); i++)
- rkisp1_write(params->rkisp1, full_range_coeff[i],
- RKISP1_CIF_ISP_CC_COEFF_0 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_CC_COEFF_0 + i * 4,
+ full_range_coeff[i]);
rkisp1_param_set_bits(params, RKISP1_CIF_ISP_CTRL,
RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA |
RKISP1_CIF_ISP_CTRL_ISP_CSM_C_FULL_ENA);
} else {
for (i = 0; i < ARRAY_SIZE(limited_range_coeff); i++)
- rkisp1_write(params->rkisp1, limited_range_coeff[i],
- RKISP1_CIF_ISP_CC_COEFF_0 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_CC_COEFF_0 + i * 4,
+ limited_range_coeff[i]);
rkisp1_param_clear_bits(params, RKISP1_CIF_ISP_CTRL,
RKISP1_CIF_ISP_CTRL_ISP_CSM_Y_FULL_ENA |
@@ -1152,52 +1148,53 @@ static void rkisp1_dpf_config(struct rkisp1_params *params,
rkisp1_param_set_bits(params, RKISP1_CIF_ISP_DPF_MODE,
isp_dpf_mode);
- rkisp1_write(params->rkisp1, arg->gain.nf_b_gain,
- RKISP1_CIF_ISP_DPF_NF_GAIN_B);
- rkisp1_write(params->rkisp1, arg->gain.nf_r_gain,
- RKISP1_CIF_ISP_DPF_NF_GAIN_R);
- rkisp1_write(params->rkisp1, arg->gain.nf_gb_gain,
- RKISP1_CIF_ISP_DPF_NF_GAIN_GB);
- rkisp1_write(params->rkisp1, arg->gain.nf_gr_gain,
- RKISP1_CIF_ISP_DPF_NF_GAIN_GR);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_B,
+ arg->gain.nf_b_gain);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_R,
+ arg->gain.nf_r_gain);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_GB,
+ arg->gain.nf_gb_gain);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_NF_GAIN_GR,
+ arg->gain.nf_gr_gain);
for (i = 0; i < RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS; i++) {
- rkisp1_write(params->rkisp1, arg->nll.coeff[i],
- RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4);
+ rkisp1_write(params->rkisp1,
+ RKISP1_CIF_ISP_DPF_NULL_COEFF_0 + i * 4,
+ arg->nll.coeff[i]);
}
spatial_coeff = arg->g_flt.spatial_coeff[0] |
(arg->g_flt.spatial_coeff[1] << 8) |
(arg->g_flt.spatial_coeff[2] << 16) |
(arg->g_flt.spatial_coeff[3] << 24);
- rkisp1_write(params->rkisp1, spatial_coeff,
- RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_G_1_4,
+ spatial_coeff);
spatial_coeff = arg->g_flt.spatial_coeff[4] |
(arg->g_flt.spatial_coeff[5] << 8);
- rkisp1_write(params->rkisp1, spatial_coeff,
- RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_G_5_6,
+ spatial_coeff);
spatial_coeff = arg->rb_flt.spatial_coeff[0] |
(arg->rb_flt.spatial_coeff[1] << 8) |
(arg->rb_flt.spatial_coeff[2] << 16) |
(arg->rb_flt.spatial_coeff[3] << 24);
- rkisp1_write(params->rkisp1, spatial_coeff,
- RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_1_4,
+ spatial_coeff);
spatial_coeff = arg->rb_flt.spatial_coeff[4] |
(arg->rb_flt.spatial_coeff[5] << 8);
- rkisp1_write(params->rkisp1, spatial_coeff,
- RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_S_WEIGHT_RB_5_6,
+ spatial_coeff);
}
static void
rkisp1_dpf_strength_config(struct rkisp1_params *params,
const struct rkisp1_cif_isp_dpf_strength_config *arg)
{
- rkisp1_write(params->rkisp1, arg->b, RKISP1_CIF_ISP_DPF_STRENGTH_B);
- rkisp1_write(params->rkisp1, arg->g, RKISP1_CIF_ISP_DPF_STRENGTH_G);
- rkisp1_write(params->rkisp1, arg->r, RKISP1_CIF_ISP_DPF_STRENGTH_R);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_B, arg->b);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_G, arg->g);
+ rkisp1_write(params->rkisp1, RKISP1_CIF_ISP_DPF_STRENGTH_R, arg->r);
}
static void
@@ -1804,7 +1801,7 @@ static void rkisp1_init_params(struct rkisp1_params *params)
params->vdev_fmt.fmt.meta.buffersize =
sizeof(struct rkisp1_params_cfg);
- if (params->rkisp1->media_dev.hw_revision == RKISP1_V12)
+ if (params->rkisp1->info->isp_ver == RKISP1_V12)
params->ops = &rkisp1_v12_params_ops;
else
params->ops = &rkisp1_v10_params_ops;
@@ -1844,16 +1841,20 @@ int rkisp1_params_register(struct rkisp1_device *rkisp1)
node->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
if (ret)
- return ret;
+ goto error;
+
ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (ret) {
dev_err(rkisp1->dev,
"failed to register %s, ret=%d\n", vdev->name, ret);
- goto err_cleanup_media_entity;
+ goto error;
}
+
return 0;
-err_cleanup_media_entity:
+
+error:
media_entity_cleanup(&vdev->entity);
+ mutex_destroy(&node->vlock);
return ret;
}
@@ -1863,6 +1864,10 @@ void rkisp1_params_unregister(struct rkisp1_device *rkisp1)
struct rkisp1_vdev_node *node = &params->vnode;
struct video_device *vdev = &node->vdev;
+ if (!video_is_registered(vdev))
+ return;
+
vb2_video_unregister_device(vdev);
media_entity_cleanup(&vdev->entity);
+ mutex_destroy(&node->vlock);
}
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
index 82f8d33d98b3..dd3e6c38be67 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
@@ -11,7 +11,7 @@
/* ISP_CTRL */
#define RKISP1_CIF_ISP_CTRL_ISP_ENABLE BIT(0)
#define RKISP1_CIF_ISP_CTRL_ISP_MODE_RAW_PICT (0 << 1)
-#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656 BIT(1)
+#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU656 (1 << 1)
#define RKISP1_CIF_ISP_CTRL_ISP_MODE_ITU601 (2 << 1)
#define RKISP1_CIF_ISP_CTRL_ISP_MODE_BAYER_ITU601 (3 << 1)
#define RKISP1_CIF_ISP_CTRL_ISP_MODE_DATA_MODE (4 << 1)
@@ -33,37 +33,37 @@
#define RKISP1_CIF_ISP_ACQ_PROP_HSYNC_LOW BIT(1)
#define RKISP1_CIF_ISP_ACQ_PROP_VSYNC_LOW BIT(2)
#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_RGGB (0 << 3)
-#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG BIT(3)
+#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GRBG (1 << 3)
#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_GBRG (2 << 3)
#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT_BGGR (3 << 3)
#define RKISP1_CIF_ISP_ACQ_PROP_BAYER_PAT(pat) ((pat) << 3)
#define RKISP1_CIF_ISP_ACQ_PROP_YCBYCR (0 << 7)
-#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB BIT(7)
+#define RKISP1_CIF_ISP_ACQ_PROP_YCRYCB (1 << 7)
#define RKISP1_CIF_ISP_ACQ_PROP_CBYCRY (2 << 7)
#define RKISP1_CIF_ISP_ACQ_PROP_CRYCBY (3 << 7)
#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ALL (0 << 9)
-#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN BIT(9)
+#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_EVEN (1 << 9)
#define RKISP1_CIF_ISP_ACQ_PROP_FIELD_SEL_ODD (2 << 9)
#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_12B (0 << 12)
-#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO BIT(12)
+#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_ZERO (1 << 12)
#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_10B_MSB (2 << 12)
#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_ZERO (3 << 12)
#define RKISP1_CIF_ISP_ACQ_PROP_IN_SEL_8B_MSB (4 << 12)
/* VI_DPCL */
#define RKISP1_CIF_VI_DPCL_DMA_JPEG (0 << 0)
-#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI BIT(0)
+#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_MI (1 << 0)
#define RKISP1_CIF_VI_DPCL_MP_MUX_MRSZ_JPEG (2 << 0)
-#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP BIT(2)
+#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MP (1 << 2)
#define RKISP1_CIF_VI_DPCL_CHAN_MODE_SP (2 << 2)
#define RKISP1_CIF_VI_DPCL_CHAN_MODE_MPSP (3 << 2)
#define RKISP1_CIF_VI_DPCL_DMA_SW_SPMUX (0 << 4)
-#define RKISP1_CIF_VI_DPCL_DMA_SW_SI BIT(4)
+#define RKISP1_CIF_VI_DPCL_DMA_SW_SI (1 << 4)
#define RKISP1_CIF_VI_DPCL_DMA_SW_IE (2 << 4)
#define RKISP1_CIF_VI_DPCL_DMA_SW_JPEG (3 << 4)
#define RKISP1_CIF_VI_DPCL_DMA_SW_ISP (4 << 4)
#define RKISP1_CIF_VI_DPCL_IF_SEL_PARALLEL (0 << 8)
-#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA BIT(8)
+#define RKISP1_CIF_VI_DPCL_IF_SEL_SMIA (1 << 8)
#define RKISP1_CIF_VI_DPCL_IF_SEL_MIPI (2 << 8)
#define RKISP1_CIF_VI_DPCL_DMA_IE_MUX_DMA BIT(10)
#define RKISP1_CIF_VI_DPCL_DMA_SP_MUX_DMA BIT(11)
@@ -112,26 +112,26 @@
#define RKISP1_CIF_MI_SP_AUTOUPDATE_ENABLE BIT(14)
#define RKISP1_CIF_MI_LAST_PIXEL_SIG_ENABLE BIT(15)
#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_16 (0 << 16)
-#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32 BIT(16)
+#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_32 (1 << 16)
#define RKISP1_CIF_MI_CTRL_BURST_LEN_LUM_64 (2 << 16)
#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_16 (0 << 18)
-#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32 BIT(18)
+#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_32 (1 << 18)
#define RKISP1_CIF_MI_CTRL_BURST_LEN_CHROM_64 (2 << 18)
#define RKISP1_CIF_MI_CTRL_INIT_BASE_EN BIT(20)
#define RKISP1_CIF_MI_CTRL_INIT_OFFSET_EN BIT(21)
#define RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8 (0 << 22)
-#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA BIT(22)
+#define RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA (1 << 22)
#define RKISP1_MI_CTRL_MP_WRITE_YUVINT (2 << 22)
#define RKISP1_MI_CTRL_MP_WRITE_RAW12 (2 << 22)
#define RKISP1_MI_CTRL_SP_WRITE_PLA (0 << 24)
-#define RKISP1_MI_CTRL_SP_WRITE_SPLA BIT(24)
+#define RKISP1_MI_CTRL_SP_WRITE_SPLA (1 << 24)
#define RKISP1_MI_CTRL_SP_WRITE_INT (2 << 24)
#define RKISP1_MI_CTRL_SP_INPUT_YUV400 (0 << 26)
-#define RKISP1_MI_CTRL_SP_INPUT_YUV420 BIT(26)
+#define RKISP1_MI_CTRL_SP_INPUT_YUV420 (1 << 26)
#define RKISP1_MI_CTRL_SP_INPUT_YUV422 (2 << 26)
#define RKISP1_MI_CTRL_SP_INPUT_YUV444 (3 << 26)
#define RKISP1_MI_CTRL_SP_OUTPUT_YUV400 (0 << 28)
-#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420 BIT(28)
+#define RKISP1_MI_CTRL_SP_OUTPUT_YUV420 (1 << 28)
#define RKISP1_MI_CTRL_SP_OUTPUT_YUV422 (2 << 28)
#define RKISP1_MI_CTRL_SP_OUTPUT_YUV444 (3 << 28)
#define RKISP1_MI_CTRL_SP_OUTPUT_RGB565 (4 << 28)
@@ -186,22 +186,22 @@
/* MI_DMA_CTRL */
#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_16 (0 << 0)
-#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 BIT(0)
+#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_32 (1 << 0)
#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_LUM_64 (2 << 0)
#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_16 (0 << 2)
-#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 BIT(2)
+#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_32 (1 << 2)
#define RKISP1_CIF_MI_DMA_CTRL_BURST_LEN_CHROM_64 (2 << 2)
#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PLANAR (0 << 4)
-#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR BIT(4)
-#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6)
-#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420 BIT(6)
+#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_SPLANAR (1 << 4)
#define RKISP1_CIF_MI_DMA_CTRL_READ_FMT_PACKED (2 << 4)
+#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV400 (0 << 6)
+#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV420 (1 << 6)
#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV422 (2 << 6)
#define RKISP1_CIF_MI_DMA_CTRL_FMT_YUV444 (3 << 6)
#define RKISP1_CIF_MI_DMA_CTRL_BYTE_SWAP BIT(8)
#define RKISP1_CIF_MI_DMA_CTRL_CONTINUOUS_ENA BIT(9)
#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_NO (0 << 12)
-#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT BIT(12)
+#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_8BIT (1 << 12)
#define RKISP1_CIF_MI_DMA_CTRL_RGB_BAYER_16BIT (2 << 12)
/* MI_DMA_START */
#define RKISP1_CIF_MI_DMA_START_ENABLE BIT(0)
@@ -210,7 +210,7 @@
#define RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP BIT(1)
#define RKISP1_CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP BIT(2)
-/* CCL */
+/* VI_CCL */
#define RKISP1_CIF_CCL_CIF_CLK_DIS BIT(2)
/* VI_ISP_CLK_CTRL */
#define RKISP1_CIF_CLK_CTRL_ISP_RAW BIT(0)
@@ -241,32 +241,32 @@
#define RKISP1_CIF_CLK_CTRL_RSZS BIT(25)
#define RKISP1_CIF_CLK_CTRL_MIPI BIT(26)
#define RKISP1_CIF_CLK_CTRL_MARVINMI BIT(27)
-/* ICCL */
-#define RKISP1_CIF_ICCL_ISP_CLK BIT(0)
-#define RKISP1_CIF_ICCL_CP_CLK BIT(1)
-#define RKISP1_CIF_ICCL_RES_2 BIT(2)
-#define RKISP1_CIF_ICCL_MRSZ_CLK BIT(3)
-#define RKISP1_CIF_ICCL_SRSZ_CLK BIT(4)
-#define RKISP1_CIF_ICCL_JPEG_CLK BIT(5)
-#define RKISP1_CIF_ICCL_MI_CLK BIT(6)
-#define RKISP1_CIF_ICCL_RES_7 BIT(7)
-#define RKISP1_CIF_ICCL_IE_CLK BIT(8)
-#define RKISP1_CIF_ICCL_SIMP_CLK BIT(9)
-#define RKISP1_CIF_ICCL_SMIA_CLK BIT(10)
-#define RKISP1_CIF_ICCL_MIPI_CLK BIT(11)
-#define RKISP1_CIF_ICCL_DCROP_CLK BIT(12)
-/* IRCL */
-#define RKISP1_CIF_IRCL_ISP_SW_RST BIT(0)
-#define RKISP1_CIF_IRCL_CP_SW_RST BIT(1)
-#define RKISP1_CIF_IRCL_YCS_SW_RST BIT(2)
-#define RKISP1_CIF_IRCL_MRSZ_SW_RST BIT(3)
-#define RKISP1_CIF_IRCL_SRSZ_SW_RST BIT(4)
-#define RKISP1_CIF_IRCL_JPEG_SW_RST BIT(5)
-#define RKISP1_CIF_IRCL_MI_SW_RST BIT(6)
-#define RKISP1_CIF_IRCL_CIF_SW_RST BIT(7)
-#define RKISP1_CIF_IRCL_IE_SW_RST BIT(8)
-#define RKISP1_CIF_IRCL_SI_SW_RST BIT(9)
-#define RKISP1_CIF_IRCL_MIPI_SW_RST BIT(11)
+/* VI_ICCL */
+#define RKISP1_CIF_VI_ICCL_ISP_CLK BIT(0)
+#define RKISP1_CIF_VI_ICCL_CP_CLK BIT(1)
+#define RKISP1_CIF_VI_ICCL_RES_2 BIT(2)
+#define RKISP1_CIF_VI_ICCL_MRSZ_CLK BIT(3)
+#define RKISP1_CIF_VI_ICCL_SRSZ_CLK BIT(4)
+#define RKISP1_CIF_VI_ICCL_JPEG_CLK BIT(5)
+#define RKISP1_CIF_VI_ICCL_MI_CLK BIT(6)
+#define RKISP1_CIF_VI_ICCL_RES_7 BIT(7)
+#define RKISP1_CIF_VI_ICCL_IE_CLK BIT(8)
+#define RKISP1_CIF_VI_ICCL_SIMP_CLK BIT(9)
+#define RKISP1_CIF_VI_ICCL_SMIA_CLK BIT(10)
+#define RKISP1_CIF_VI_ICCL_MIPI_CLK BIT(11)
+#define RKISP1_CIF_VI_ICCL_DCROP_CLK BIT(12)
+/* VI_IRCL */
+#define RKISP1_CIF_VI_IRCL_ISP_SW_RST BIT(0)
+#define RKISP1_CIF_VI_IRCL_CP_SW_RST BIT(1)
+#define RKISP1_CIF_VI_IRCL_YCS_SW_RST BIT(2)
+#define RKISP1_CIF_VI_IRCL_MRSZ_SW_RST BIT(3)
+#define RKISP1_CIF_VI_IRCL_SRSZ_SW_RST BIT(4)
+#define RKISP1_CIF_VI_IRCL_JPEG_SW_RST BIT(5)
+#define RKISP1_CIF_VI_IRCL_MI_SW_RST BIT(6)
+#define RKISP1_CIF_VI_IRCL_CIF_SW_RST BIT(7)
+#define RKISP1_CIF_VI_IRCL_IE_SW_RST BIT(8)
+#define RKISP1_CIF_VI_IRCL_SI_SW_RST BIT(9)
+#define RKISP1_CIF_VI_IRCL_MIPI_SW_RST BIT(11)
/* C_PROC_CTR */
#define RKISP1_CIF_C_PROC_CTR_ENABLE BIT(0)
@@ -282,10 +282,10 @@
#define RKISP1_CIF_C_PROC_TONE_RESERVED 0xF000
/* DUAL_CROP_CTRL */
#define RKISP1_CIF_DUAL_CROP_MP_MODE_BYPASS (0 << 0)
-#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV BIT(0)
+#define RKISP1_CIF_DUAL_CROP_MP_MODE_YUV (1 << 0)
#define RKISP1_CIF_DUAL_CROP_MP_MODE_RAW (2 << 0)
#define RKISP1_CIF_DUAL_CROP_SP_MODE_BYPASS (0 << 2)
-#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV BIT(2)
+#define RKISP1_CIF_DUAL_CROP_SP_MODE_YUV (1 << 2)
#define RKISP1_CIF_DUAL_CROP_SP_MODE_RAW (2 << 2)
#define RKISP1_CIF_DUAL_CROP_CFG_UPD_PERMANENT BIT(4)
#define RKISP1_CIF_DUAL_CROP_CFG_UPD BIT(5)
@@ -294,7 +294,7 @@
/* IMG_EFF_CTRL */
#define RKISP1_CIF_IMG_EFF_CTRL_ENABLE BIT(0)
#define RKISP1_CIF_IMG_EFF_CTRL_MODE_BLACKWHITE (0 << 1)
-#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE BIT(1)
+#define RKISP1_CIF_IMG_EFF_CTRL_MODE_NEGATIVE (1 << 1)
#define RKISP1_CIF_IMG_EFF_CTRL_MODE_SEPIA (2 << 1)
#define RKISP1_CIF_IMG_EFF_CTRL_MODE_COLOR_SEL (3 << 1)
#define RKISP1_CIF_IMG_EFF_CTRL_MODE_EMBOSS (4 << 1)
@@ -314,7 +314,7 @@
/* IMG_EFF_COLOR_SEL */
#define RKISP1_CIF_IMG_EFF_COLOR_RGB 0
-#define RKISP1_CIF_IMG_EFF_COLOR_B BIT(0)
+#define RKISP1_CIF_IMG_EFF_COLOR_B (1 << 0)
#define RKISP1_CIF_IMG_EFF_COLOR_G (2 << 0)
#define RKISP1_CIF_IMG_EFF_COLOR_GB (3 << 0)
#define RKISP1_CIF_IMG_EFF_COLOR_R (4 << 0)
@@ -365,7 +365,7 @@
/* ISP HISTOGRAM CALCULATION : ISP_HIST_PROP */
#define RKISP1_CIF_ISP_HIST_PROP_MODE_DIS_V10 (0 << 0)
-#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB_V10 BIT(0)
+#define RKISP1_CIF_ISP_HIST_PROP_MODE_RGB_V10 (1 << 0)
#define RKISP1_CIF_ISP_HIST_PROP_MODE_RED_V10 (2 << 0)
#define RKISP1_CIF_ISP_HIST_PROP_MODE_GREEN_V10 (3 << 0)
#define RKISP1_CIF_ISP_HIST_PROP_MODE_BLUE_V10 (4 << 0)
@@ -443,6 +443,15 @@
#define RKISP1_CIF_ISP_DEMOSAIC_BYPASS BIT(10)
#define RKISP1_CIF_ISP_DEMOSAIC_TH(x) ((x) & 0xFF)
+/* ISP_FLAGS_SHD */
+#define RKISP1_CIF_ISP_FLAGS_SHD_ISP_ENABLE_SHD BIT(0)
+#define RKISP1_CIF_ISP_FLAGS_SHD_ISP_ENABLE_INFORM_SHD BIT(1)
+#define RKISP1_CIF_ISP_FLAGS_SHD_INFORM_FIELD BIT(2)
+#define RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_MASK GENMASK(27, 16)
+#define RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_SHIFT 16
+#define RKISP1_CIF_ISP_FLAGS_SHD_S_VSYNC BIT(30)
+#define RKISP1_CIF_ISP_FLAGS_SHD_S_HSYNC BIT(31)
+
/* AWB */
/* ISP_AWB_PROP */
#define RKISP1_CIF_ISP_AWB_YMAX_CMP_EN BIT(2)
@@ -628,7 +637,7 @@
#define RKISP1_CIF_ISP_BLS_ENA BIT(0)
#define RKISP1_CIF_ISP_BLS_MODE_MEASURED BIT(1)
#define RKISP1_CIF_ISP_BLS_MODE_FIXED 0
-#define RKISP1_CIF_ISP_BLS_WINDOW_1 BIT(2)
+#define RKISP1_CIF_ISP_BLS_WINDOW_1 (1 << 2)
#define RKISP1_CIF_ISP_BLS_WINDOW_2 (2 << 2)
/* GAMMA-IN */
@@ -676,11 +685,11 @@
/* CIF Registers */
/* =================================================================== */
#define RKISP1_CIF_CTRL_BASE 0x00000000
-#define RKISP1_CIF_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000)
+#define RKISP1_CIF_VI_CCL (RKISP1_CIF_CTRL_BASE + 0x00000000)
#define RKISP1_CIF_VI_ID (RKISP1_CIF_CTRL_BASE + 0x00000008)
#define RKISP1_CIF_VI_ISP_CLK_CTRL_V12 (RKISP1_CIF_CTRL_BASE + 0x0000000C)
-#define RKISP1_CIF_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010)
-#define RKISP1_CIF_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014)
+#define RKISP1_CIF_VI_ICCL (RKISP1_CIF_CTRL_BASE + 0x00000010)
+#define RKISP1_CIF_VI_IRCL (RKISP1_CIF_CTRL_BASE + 0x00000014)
#define RKISP1_CIF_VI_DPCL (RKISP1_CIF_CTRL_BASE + 0x00000018)
#define RKISP1_CIF_IMG_EFF_BASE 0x00000200
@@ -894,52 +903,29 @@
#define RKISP1_CIF_DUAL_CROP_S_V_SIZE_SHD (RKISP1_CIF_DUAL_CROP_BASE + 0x00000040)
#define RKISP1_CIF_MRSZ_BASE 0x00000C00
-#define RKISP1_CIF_MRSZ_CTRL (RKISP1_CIF_MRSZ_BASE + 0x00000000)
-#define RKISP1_CIF_MRSZ_SCALE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000004)
-#define RKISP1_CIF_MRSZ_SCALE_HCB (RKISP1_CIF_MRSZ_BASE + 0x00000008)
-#define RKISP1_CIF_MRSZ_SCALE_HCR (RKISP1_CIF_MRSZ_BASE + 0x0000000C)
-#define RKISP1_CIF_MRSZ_SCALE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000010)
-#define RKISP1_CIF_MRSZ_SCALE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000014)
-#define RKISP1_CIF_MRSZ_PHASE_HY (RKISP1_CIF_MRSZ_BASE + 0x00000018)
-#define RKISP1_CIF_MRSZ_PHASE_HC (RKISP1_CIF_MRSZ_BASE + 0x0000001C)
-#define RKISP1_CIF_MRSZ_PHASE_VY (RKISP1_CIF_MRSZ_BASE + 0x00000020)
-#define RKISP1_CIF_MRSZ_PHASE_VC (RKISP1_CIF_MRSZ_BASE + 0x00000024)
-#define RKISP1_CIF_MRSZ_SCALE_LUT_ADDR (RKISP1_CIF_MRSZ_BASE + 0x00000028)
-#define RKISP1_CIF_MRSZ_SCALE_LUT (RKISP1_CIF_MRSZ_BASE + 0x0000002C)
-#define RKISP1_CIF_MRSZ_CTRL_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000030)
-#define RKISP1_CIF_MRSZ_SCALE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000034)
-#define RKISP1_CIF_MRSZ_SCALE_HCB_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000038)
-#define RKISP1_CIF_MRSZ_SCALE_HCR_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000003C)
-#define RKISP1_CIF_MRSZ_SCALE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000040)
-#define RKISP1_CIF_MRSZ_SCALE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000044)
-#define RKISP1_CIF_MRSZ_PHASE_HY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000048)
-#define RKISP1_CIF_MRSZ_PHASE_HC_SHD (RKISP1_CIF_MRSZ_BASE + 0x0000004C)
-#define RKISP1_CIF_MRSZ_PHASE_VY_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000050)
-#define RKISP1_CIF_MRSZ_PHASE_VC_SHD (RKISP1_CIF_MRSZ_BASE + 0x00000054)
-
#define RKISP1_CIF_SRSZ_BASE 0x00001000
-#define RKISP1_CIF_SRSZ_CTRL (RKISP1_CIF_SRSZ_BASE + 0x00000000)
-#define RKISP1_CIF_SRSZ_SCALE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000004)
-#define RKISP1_CIF_SRSZ_SCALE_HCB (RKISP1_CIF_SRSZ_BASE + 0x00000008)
-#define RKISP1_CIF_SRSZ_SCALE_HCR (RKISP1_CIF_SRSZ_BASE + 0x0000000C)
-#define RKISP1_CIF_SRSZ_SCALE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000010)
-#define RKISP1_CIF_SRSZ_SCALE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000014)
-#define RKISP1_CIF_SRSZ_PHASE_HY (RKISP1_CIF_SRSZ_BASE + 0x00000018)
-#define RKISP1_CIF_SRSZ_PHASE_HC (RKISP1_CIF_SRSZ_BASE + 0x0000001C)
-#define RKISP1_CIF_SRSZ_PHASE_VY (RKISP1_CIF_SRSZ_BASE + 0x00000020)
-#define RKISP1_CIF_SRSZ_PHASE_VC (RKISP1_CIF_SRSZ_BASE + 0x00000024)
-#define RKISP1_CIF_SRSZ_SCALE_LUT_ADDR (RKISP1_CIF_SRSZ_BASE + 0x00000028)
-#define RKISP1_CIF_SRSZ_SCALE_LUT (RKISP1_CIF_SRSZ_BASE + 0x0000002C)
-#define RKISP1_CIF_SRSZ_CTRL_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000030)
-#define RKISP1_CIF_SRSZ_SCALE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000034)
-#define RKISP1_CIF_SRSZ_SCALE_HCB_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000038)
-#define RKISP1_CIF_SRSZ_SCALE_HCR_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000003C)
-#define RKISP1_CIF_SRSZ_SCALE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000040)
-#define RKISP1_CIF_SRSZ_SCALE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000044)
-#define RKISP1_CIF_SRSZ_PHASE_HY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000048)
-#define RKISP1_CIF_SRSZ_PHASE_HC_SHD (RKISP1_CIF_SRSZ_BASE + 0x0000004C)
-#define RKISP1_CIF_SRSZ_PHASE_VY_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000050)
-#define RKISP1_CIF_SRSZ_PHASE_VC_SHD (RKISP1_CIF_SRSZ_BASE + 0x00000054)
+#define RKISP1_CIF_RSZ_CTRL 0x0000
+#define RKISP1_CIF_RSZ_SCALE_HY 0x0004
+#define RKISP1_CIF_RSZ_SCALE_HCB 0x0008
+#define RKISP1_CIF_RSZ_SCALE_HCR 0x000C
+#define RKISP1_CIF_RSZ_SCALE_VY 0x0010
+#define RKISP1_CIF_RSZ_SCALE_VC 0x0014
+#define RKISP1_CIF_RSZ_PHASE_HY 0x0018
+#define RKISP1_CIF_RSZ_PHASE_HC 0x001C
+#define RKISP1_CIF_RSZ_PHASE_VY 0x0020
+#define RKISP1_CIF_RSZ_PHASE_VC 0x0024
+#define RKISP1_CIF_RSZ_SCALE_LUT_ADDR 0x0028
+#define RKISP1_CIF_RSZ_SCALE_LUT 0x002C
+#define RKISP1_CIF_RSZ_CTRL_SHD 0x0030
+#define RKISP1_CIF_RSZ_SCALE_HY_SHD 0x0034
+#define RKISP1_CIF_RSZ_SCALE_HCB_SHD 0x0038
+#define RKISP1_CIF_RSZ_SCALE_HCR_SHD 0x003C
+#define RKISP1_CIF_RSZ_SCALE_VY_SHD 0x0040
+#define RKISP1_CIF_RSZ_SCALE_VC_SHD 0x0044
+#define RKISP1_CIF_RSZ_PHASE_HY_SHD 0x0048
+#define RKISP1_CIF_RSZ_PHASE_HC_SHD 0x004C
+#define RKISP1_CIF_RSZ_PHASE_VY_SHD 0x0050
+#define RKISP1_CIF_RSZ_PHASE_VC_SHD 0x0054
#define RKISP1_CIF_MI_BASE 0x00001400
#define RKISP1_CIF_MI_CTRL (RKISP1_CIF_MI_BASE + 0x00000000)
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
index 2070f4b06705..f4caa8f684aa 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
@@ -61,30 +61,6 @@ struct rkisp1_rsz_config {
/* registers */
struct {
u32 ctrl;
- u32 ctrl_shd;
- u32 scale_hy;
- u32 scale_hcr;
- u32 scale_hcb;
- u32 scale_vy;
- u32 scale_vc;
- u32 scale_lut;
- u32 scale_lut_addr;
- u32 scale_hy_shd;
- u32 scale_hcr_shd;
- u32 scale_hcb_shd;
- u32 scale_vy_shd;
- u32 scale_vc_shd;
- u32 phase_hy;
- u32 phase_hc;
- u32 phase_vy;
- u32 phase_vc;
- u32 phase_hy_shd;
- u32 phase_hc_shd;
- u32 phase_vy_shd;
- u32 phase_vc_shd;
- } rsz;
- struct {
- u32 ctrl;
u32 yuvmode_mask;
u32 rawmode_mask;
u32 h_offset;
@@ -101,30 +77,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_mp = {
.min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH,
.min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT,
/* registers */
- .rsz = {
- .ctrl = RKISP1_CIF_MRSZ_CTRL,
- .scale_hy = RKISP1_CIF_MRSZ_SCALE_HY,
- .scale_hcr = RKISP1_CIF_MRSZ_SCALE_HCR,
- .scale_hcb = RKISP1_CIF_MRSZ_SCALE_HCB,
- .scale_vy = RKISP1_CIF_MRSZ_SCALE_VY,
- .scale_vc = RKISP1_CIF_MRSZ_SCALE_VC,
- .scale_lut = RKISP1_CIF_MRSZ_SCALE_LUT,
- .scale_lut_addr = RKISP1_CIF_MRSZ_SCALE_LUT_ADDR,
- .scale_hy_shd = RKISP1_CIF_MRSZ_SCALE_HY_SHD,
- .scale_hcr_shd = RKISP1_CIF_MRSZ_SCALE_HCR_SHD,
- .scale_hcb_shd = RKISP1_CIF_MRSZ_SCALE_HCB_SHD,
- .scale_vy_shd = RKISP1_CIF_MRSZ_SCALE_VY_SHD,
- .scale_vc_shd = RKISP1_CIF_MRSZ_SCALE_VC_SHD,
- .phase_hy = RKISP1_CIF_MRSZ_PHASE_HY,
- .phase_hc = RKISP1_CIF_MRSZ_PHASE_HC,
- .phase_vy = RKISP1_CIF_MRSZ_PHASE_VY,
- .phase_vc = RKISP1_CIF_MRSZ_PHASE_VC,
- .ctrl_shd = RKISP1_CIF_MRSZ_CTRL_SHD,
- .phase_hy_shd = RKISP1_CIF_MRSZ_PHASE_HY_SHD,
- .phase_hc_shd = RKISP1_CIF_MRSZ_PHASE_HC_SHD,
- .phase_vy_shd = RKISP1_CIF_MRSZ_PHASE_VY_SHD,
- .phase_vc_shd = RKISP1_CIF_MRSZ_PHASE_VC_SHD,
- },
.dual_crop = {
.ctrl = RKISP1_CIF_DUAL_CROP_CTRL,
.yuvmode_mask = RKISP1_CIF_DUAL_CROP_MP_MODE_YUV,
@@ -143,30 +95,6 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = {
.min_rsz_width = RKISP1_RSZ_SRC_MIN_WIDTH,
.min_rsz_height = RKISP1_RSZ_SRC_MIN_HEIGHT,
/* registers */
- .rsz = {
- .ctrl = RKISP1_CIF_SRSZ_CTRL,
- .scale_hy = RKISP1_CIF_SRSZ_SCALE_HY,
- .scale_hcr = RKISP1_CIF_SRSZ_SCALE_HCR,
- .scale_hcb = RKISP1_CIF_SRSZ_SCALE_HCB,
- .scale_vy = RKISP1_CIF_SRSZ_SCALE_VY,
- .scale_vc = RKISP1_CIF_SRSZ_SCALE_VC,
- .scale_lut = RKISP1_CIF_SRSZ_SCALE_LUT,
- .scale_lut_addr = RKISP1_CIF_SRSZ_SCALE_LUT_ADDR,
- .scale_hy_shd = RKISP1_CIF_SRSZ_SCALE_HY_SHD,
- .scale_hcr_shd = RKISP1_CIF_SRSZ_SCALE_HCR_SHD,
- .scale_hcb_shd = RKISP1_CIF_SRSZ_SCALE_HCB_SHD,
- .scale_vy_shd = RKISP1_CIF_SRSZ_SCALE_VY_SHD,
- .scale_vc_shd = RKISP1_CIF_SRSZ_SCALE_VC_SHD,
- .phase_hy = RKISP1_CIF_SRSZ_PHASE_HY,
- .phase_hc = RKISP1_CIF_SRSZ_PHASE_HC,
- .phase_vy = RKISP1_CIF_SRSZ_PHASE_VY,
- .phase_vc = RKISP1_CIF_SRSZ_PHASE_VC,
- .ctrl_shd = RKISP1_CIF_SRSZ_CTRL_SHD,
- .phase_hy_shd = RKISP1_CIF_SRSZ_PHASE_HY_SHD,
- .phase_hc_shd = RKISP1_CIF_SRSZ_PHASE_HC_SHD,
- .phase_vy_shd = RKISP1_CIF_SRSZ_PHASE_VY_SHD,
- .phase_vc_shd = RKISP1_CIF_SRSZ_PHASE_VC_SHD,
- },
.dual_crop = {
.ctrl = RKISP1_CIF_DUAL_CROP_CTRL,
.yuvmode_mask = RKISP1_CIF_DUAL_CROP_SP_MODE_YUV,
@@ -178,6 +106,17 @@ static const struct rkisp1_rsz_config rkisp1_rsz_config_sp = {
},
};
+static inline u32 rkisp1_rsz_read(struct rkisp1_resizer *rsz, u32 offset)
+{
+ return rkisp1_read(rsz->rkisp1, rsz->regs_base + offset);
+}
+
+static inline void rkisp1_rsz_write(struct rkisp1_resizer *rsz, u32 offset,
+ u32 value)
+{
+ rkisp1_write(rsz->rkisp1, rsz->regs_base + offset, value);
+}
+
static struct v4l2_mbus_framefmt *
rkisp1_rsz_get_pad_fmt(struct rkisp1_resizer *rsz,
struct v4l2_subdev_state *sd_state,
@@ -222,7 +161,7 @@ static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz,
dc_ctrl |= RKISP1_CIF_DUAL_CROP_GEN_CFG_UPD;
else
dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD;
- rkisp1_write(rsz->rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl);
+ rkisp1_write(rsz->rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl);
}
/* configure dual-crop unit */
@@ -247,13 +186,13 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz)
}
dc_ctrl = rkisp1_read(rkisp1, rsz->config->dual_crop.ctrl);
- rkisp1_write(rkisp1, sink_crop->left, rsz->config->dual_crop.h_offset);
- rkisp1_write(rkisp1, sink_crop->top, rsz->config->dual_crop.v_offset);
- rkisp1_write(rkisp1, sink_crop->width, rsz->config->dual_crop.h_size);
- rkisp1_write(rkisp1, sink_crop->height, rsz->config->dual_crop.v_size);
+ rkisp1_write(rkisp1, rsz->config->dual_crop.h_offset, sink_crop->left);
+ rkisp1_write(rkisp1, rsz->config->dual_crop.v_offset, sink_crop->top);
+ rkisp1_write(rkisp1, rsz->config->dual_crop.h_size, sink_crop->width);
+ rkisp1_write(rkisp1, rsz->config->dual_crop.v_size, sink_crop->height);
dc_ctrl |= rsz->config->dual_crop.yuvmode_mask;
dc_ctrl |= RKISP1_CIF_DUAL_CROP_CFG_UPD;
- rkisp1_write(rkisp1, dc_ctrl, rsz->config->dual_crop.ctrl);
+ rkisp1_write(rkisp1, rsz->config->dual_crop.ctrl, dc_ctrl);
dev_dbg(rkisp1->dev, "stream %d crop: %dx%d -> %dx%d\n", rsz->id,
sink_fmt->width, sink_fmt->height,
@@ -264,52 +203,17 @@ static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz)
* Resizer hw configs
*/
-static void rkisp1_rsz_dump_regs(struct rkisp1_resizer *rsz)
-{
- dev_dbg(rsz->rkisp1->dev,
- "RSZ_CTRL 0x%08x/0x%08x\n"
- "RSZ_SCALE_HY %d/%d\n"
- "RSZ_SCALE_HCB %d/%d\n"
- "RSZ_SCALE_HCR %d/%d\n"
- "RSZ_SCALE_VY %d/%d\n"
- "RSZ_SCALE_VC %d/%d\n"
- "RSZ_PHASE_HY %d/%d\n"
- "RSZ_PHASE_HC %d/%d\n"
- "RSZ_PHASE_VY %d/%d\n"
- "RSZ_PHASE_VC %d/%d\n",
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl_shd),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hy_shd),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcb_shd),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_hcr_shd),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vy_shd),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.scale_vc_shd),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hy_shd),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_hc_shd),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vy_shd),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc),
- rkisp1_read(rsz->rkisp1, rsz->config->rsz.phase_vc_shd));
-}
-
static void rkisp1_rsz_update_shadow(struct rkisp1_resizer *rsz,
enum rkisp1_shadow_regs_when when)
{
- u32 ctrl_cfg = rkisp1_read(rsz->rkisp1, rsz->config->rsz.ctrl);
+ u32 ctrl_cfg = rkisp1_rsz_read(rsz, RKISP1_CIF_RSZ_CTRL);
if (when == RKISP1_SHADOW_REGS_ASYNC)
ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD_AUTO;
else
ctrl_cfg |= RKISP1_CIF_RSZ_CTRL_CFG_UPD;
- rkisp1_write(rsz->rkisp1, ctrl_cfg, rsz->config->rsz.ctrl);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, ctrl_cfg);
}
static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src)
@@ -325,7 +229,7 @@ static u32 rkisp1_rsz_calc_ratio(u32 len_sink, u32 len_src)
static void rkisp1_rsz_disable(struct rkisp1_resizer *rsz,
enum rkisp1_shadow_regs_when when)
{
- rkisp1_write(rsz->rkisp1, 0, rsz->config->rsz.ctrl);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, 0);
if (when == RKISP1_SHADOW_REGS_SYNC)
rkisp1_rsz_update_shadow(rsz, when);
@@ -338,20 +242,19 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz,
struct v4l2_rect *src_c,
enum rkisp1_shadow_regs_when when)
{
- struct rkisp1_device *rkisp1 = rsz->rkisp1;
u32 ratio, rsz_ctrl = 0;
unsigned int i;
/* No phase offset */
- rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hy);
- rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_hc);
- rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vy);
- rkisp1_write(rkisp1, 0, rsz->config->rsz.phase_vc);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_HY, 0);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_HC, 0);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_VY, 0);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_PHASE_VC, 0);
/* Linear interpolation */
for (i = 0; i < 64; i++) {
- rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut_addr);
- rkisp1_write(rkisp1, i, rsz->config->rsz.scale_lut);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_LUT_ADDR, i);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_LUT, i);
}
if (sink_y->width != src_y->width) {
@@ -359,7 +262,7 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz,
if (sink_y->width < src_y->width)
rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HY_UP;
ratio = rkisp1_rsz_calc_ratio(sink_y->width, src_y->width);
- rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hy);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HY, ratio);
}
if (sink_c->width != src_c->width) {
@@ -367,8 +270,8 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz,
if (sink_c->width < src_c->width)
rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_HC_UP;
ratio = rkisp1_rsz_calc_ratio(sink_c->width, src_c->width);
- rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcb);
- rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_hcr);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HCB, ratio);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_HCR, ratio);
}
if (sink_y->height != src_y->height) {
@@ -376,7 +279,7 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz,
if (sink_y->height < src_y->height)
rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VY_UP;
ratio = rkisp1_rsz_calc_ratio(sink_y->height, src_y->height);
- rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vy);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_VY, ratio);
}
if (sink_c->height != src_c->height) {
@@ -384,10 +287,10 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz,
if (sink_c->height < src_c->height)
rsz_ctrl |= RKISP1_CIF_RSZ_CTRL_SCALE_VC_UP;
ratio = rkisp1_rsz_calc_ratio(sink_c->height, src_c->height);
- rkisp1_write(rkisp1, ratio, rsz->config->rsz.scale_vc);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_SCALE_VC, ratio);
}
- rkisp1_write(rkisp1, rsz_ctrl, rsz->config->rsz.ctrl);
+ rkisp1_rsz_write(rsz, RKISP1_CIF_RSZ_CTRL, rsz_ctrl);
rkisp1_rsz_update_shadow(rsz, when);
}
@@ -448,8 +351,6 @@ static void rkisp1_rsz_config(struct rkisp1_resizer *rsz,
/* set values in the hw */
rkisp1_rsz_config_regs(rsz, &sink_y, &sink_c, &src_y, &src_c, when);
-
- rkisp1_rsz_dump_regs(rsz);
}
/* ----------------------------------------------------------------------------
@@ -532,14 +433,14 @@ static void rkisp1_rsz_set_src_fmt(struct rkisp1_resizer *rsz,
struct v4l2_mbus_framefmt *format,
unsigned int which)
{
- const struct rkisp1_isp_mbus_info *sink_mbus_info;
+ const struct rkisp1_mbus_info *sink_mbus_info;
struct v4l2_mbus_framefmt *src_fmt, *sink_fmt;
sink_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SINK,
which);
src_fmt = rkisp1_rsz_get_pad_fmt(rsz, sd_state, RKISP1_RSZ_PAD_SRC,
which);
- sink_mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+ sink_mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
/* for YUV formats, userspace can change the mbus code on the src pad if it is supported */
if (sink_mbus_info->pixel_enc == V4L2_PIXEL_ENC_YUV &&
@@ -561,7 +462,7 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
struct v4l2_rect *r,
unsigned int which)
{
- const struct rkisp1_isp_mbus_info *mbus_info;
+ const struct rkisp1_mbus_info *mbus_info;
struct v4l2_mbus_framefmt *sink_fmt;
struct v4l2_rect *sink_crop;
@@ -572,7 +473,7 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz,
which);
/* Not crop for MP bayer raw data */
- mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
if (rsz->id == RKISP1_MAINPATH &&
mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
@@ -599,7 +500,7 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
struct v4l2_mbus_framefmt *format,
unsigned int which)
{
- const struct rkisp1_isp_mbus_info *mbus_info;
+ const struct rkisp1_mbus_info *mbus_info;
struct v4l2_mbus_framefmt *sink_fmt, *src_fmt;
struct v4l2_rect *sink_crop;
@@ -615,10 +516,10 @@ static void rkisp1_rsz_set_sink_fmt(struct rkisp1_resizer *rsz,
else
sink_fmt->code = format->code;
- mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
if (!mbus_info || !(mbus_info->direction & RKISP1_ISP_SD_SRC)) {
sink_fmt->code = RKISP1_DEF_FMT;
- mbus_info = rkisp1_isp_mbus_info_get(sink_fmt->code);
+ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code);
}
if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
rsz->pixel_enc = mbus_info->pixel_enc;
@@ -782,8 +683,12 @@ static const struct v4l2_subdev_ops rkisp1_rsz_ops = {
static void rkisp1_rsz_unregister(struct rkisp1_resizer *rsz)
{
+ if (!rsz->rkisp1)
+ return;
+
v4l2_device_unregister_subdev(&rsz->sd);
media_entity_cleanup(&rsz->sd.entity);
+ mutex_destroy(&rsz->ops_lock);
}
static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
@@ -799,10 +704,13 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
struct v4l2_subdev *sd = &rsz->sd;
int ret;
- if (rsz->id == RKISP1_SELFPATH)
+ if (rsz->id == RKISP1_SELFPATH) {
+ rsz->regs_base = RKISP1_CIF_SRSZ_BASE;
rsz->config = &rkisp1_rsz_config_sp;
- else
+ } else {
+ rsz->regs_base = RKISP1_CIF_MRSZ_BASE;
rsz->config = &rkisp1_rsz_config_mp;
+ }
v4l2_subdev_init(sd, &rkisp1_rsz_ops);
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -821,47 +729,43 @@ static int rkisp1_rsz_register(struct rkisp1_resizer *rsz)
mutex_init(&rsz->ops_lock);
ret = media_entity_pads_init(&sd->entity, RKISP1_RSZ_PAD_MAX, pads);
if (ret)
- return ret;
+ goto error;
ret = v4l2_device_register_subdev(&rsz->rkisp1->v4l2_dev, sd);
if (ret) {
dev_err(sd->dev, "Failed to register resizer subdev\n");
- goto err_cleanup_media_entity;
+ goto error;
}
rkisp1_rsz_init_config(sd, &state);
return 0;
-err_cleanup_media_entity:
+error:
media_entity_cleanup(&sd->entity);
-
+ mutex_destroy(&rsz->ops_lock);
return ret;
}
int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1)
{
- struct rkisp1_resizer *rsz;
- unsigned int i, j;
+ unsigned int i;
int ret;
for (i = 0; i < ARRAY_SIZE(rkisp1->resizer_devs); i++) {
- rsz = &rkisp1->resizer_devs[i];
+ struct rkisp1_resizer *rsz = &rkisp1->resizer_devs[i];
+
rsz->rkisp1 = rkisp1;
rsz->id = i;
+
ret = rkisp1_rsz_register(rsz);
- if (ret)
- goto err_unreg_resizer_devs;
+ if (ret) {
+ rsz->rkisp1 = NULL;
+ rkisp1_resizer_devs_unregister(rkisp1);
+ return ret;
+ }
}
return 0;
-
-err_unreg_resizer_devs:
- for (j = 0; j < i; j++) {
- rsz = &rkisp1->resizer_devs[j];
- rkisp1_rsz_unregister(rsz);
- }
-
- return ret;
}
void rkisp1_resizer_devs_unregister(struct rkisp1_device *rkisp1)
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
index be5777c65bfb..2795eef91bdd 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
@@ -305,7 +305,7 @@ static void rkisp1_stats_get_bls_meas(struct rkisp1_stats *stats,
struct rkisp1_stat_buffer *pbuf)
{
struct rkisp1_device *rkisp1 = stats->rkisp1;
- const struct rkisp1_isp_mbus_info *in_fmt = rkisp1->isp.sink_fmt;
+ const struct rkisp1_mbus_info *in_fmt = rkisp1->isp.sink_fmt;
struct rkisp1_cif_isp_bls_meas_val *bls_val;
bls_val = &pbuf->params.ae.bls_val;
@@ -408,7 +408,7 @@ void rkisp1_stats_isr(struct rkisp1_stats *stats, u32 isp_ris)
spin_lock(&stats->lock);
- rkisp1_write(rkisp1, RKISP1_STATS_MEAS_MASK, RKISP1_CIF_ISP_ICR);
+ rkisp1_write(rkisp1, RKISP1_CIF_ISP_ICR, RKISP1_STATS_MEAS_MASK);
isp_mis_tmp = rkisp1_read(rkisp1, RKISP1_CIF_ISP_MIS);
if (isp_mis_tmp & RKISP1_STATS_MEAS_MASK)
@@ -427,7 +427,7 @@ static void rkisp1_init_stats(struct rkisp1_stats *stats)
stats->vdev_fmt.fmt.meta.buffersize =
sizeof(struct rkisp1_stat_buffer);
- if (stats->rkisp1->media_dev.hw_revision == RKISP1_V12)
+ if (stats->rkisp1->info->isp_ver == RKISP1_V12)
stats->ops = &rkisp1_v12_stats_ops;
else
stats->ops = &rkisp1_v10_stats_ops;
@@ -463,21 +463,21 @@ int rkisp1_stats_register(struct rkisp1_device *rkisp1)
node->pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&vdev->entity, 1, &node->pad);
if (ret)
- goto err_mutex_destroy;
+ goto error;
ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (ret) {
dev_err(&vdev->dev,
"failed to register %s, ret=%d\n", vdev->name, ret);
- goto err_cleanup_media_entity;
+ goto error;
}
return 0;
-err_cleanup_media_entity:
+error:
media_entity_cleanup(&vdev->entity);
-err_mutex_destroy:
mutex_destroy(&node->vlock);
+ stats->rkisp1 = NULL;
return ret;
}
@@ -487,6 +487,9 @@ void rkisp1_stats_unregister(struct rkisp1_device *rkisp1)
struct rkisp1_vdev_node *node = &stats->vnode;
struct video_device *vdev = &node->vdev;
+ if (!stats->rkisp1)
+ return;
+
vb2_video_unregister_device(vdev);
media_entity_cleanup(&vdev->entity);
mutex_destroy(&node->vlock);
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
index e3559b047092..b147c645ae0b 100644
--- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
@@ -339,8 +339,7 @@ static int get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index, u32 *ret_
void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm)
{
- u32 f_chk_addr, f_chk_len, s_chk_addr, s_chk_len;
- f_chk_addr = f_chk_len = s_chk_addr = s_chk_len = 0;
+ u32 f_chk_addr, f_chk_len, s_chk_addr = 0, s_chk_len = 0;
f_chk_addr = frm->addr.y;
f_chk_len = frm->payload[0];
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h
index e894e85e84a4..1ea5fa1bf3c8 100644
--- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.h
+++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.h
@@ -222,7 +222,7 @@ struct gsc_m2m_device {
* @org_scaler_input_w: max pixel width when the scaler is enabled
* @org_scaler_input_h: max pixel height when the scaler is enabled
* @real_rot_dis_w: max pixel src cropped height with the rotator is off
- * @real_rot_dis_h: max pixel src croppped width with the rotator is off
+ * @real_rot_dis_h: max pixel src cropped width with the rotator is off
* @real_rot_en_w: max pixel src cropped width with the rotator is on
* @real_rot_en_h: max pixel src cropped height with the rotator is on
* @target_rot_dis_w: max pixel dst scaled width with the rotator is off
diff --git a/drivers/media/platform/samsung/exynos4-is/common.c b/drivers/media/platform/samsung/exynos4-is/common.c
index 26ee2388edfd..e41333535eac 100644
--- a/drivers/media/platform/samsung/exynos4-is/common.c
+++ b/drivers/media/platform/samsung/exynos4-is/common.c
@@ -21,7 +21,7 @@ struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity)
while (pad->flags & MEDIA_PAD_FL_SINK) {
/* source pad */
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
index 7ff4024003f4..03638c8f772d 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
@@ -737,7 +737,7 @@ static struct media_entity *fimc_pipeline_get_head(struct media_entity *me)
struct media_pad *pad = &me->pads[0];
while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) {
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad)
break;
me = pad->entity;
@@ -810,7 +810,7 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx,
return ret;
}
- pad = media_entity_remote_pad(&me->pads[sfmt.pad]);
+ pad = media_pad_remote_pad_first(&me->pads[sfmt.pad]);
if (!pad)
return -EINVAL;
me = pad->entity;
@@ -1115,7 +1115,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc)
if (p->flags & MEDIA_PAD_FL_SINK) {
sink_pad = p;
- src_pad = media_entity_remote_pad(sink_pad);
+ src_pad = media_pad_remote_pad_first(sink_pad);
if (src_pad)
break;
}
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h
index da36b48b8f9f..9dcbb9853ac0 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h
@@ -116,7 +116,7 @@ enum fimc_is_error {
ERROR_COMMON_PARAMETER = 2, /* Invalid parameter */
/* setfile is not loaded before adjusting */
ERROR_COMMON_SETFILE_LOAD = 3,
- /* setfile is not Adjusted before runnng. */
+ /* setfile is not Adjusted before running. */
ERROR_COMMON_SETFILE_ADJUST = 4,
/* Index of setfile is not valid (0~MAX_SETFILE_NUM-1) */
ERROR_COMMON_SETFILE_INDEX = 5,
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
index 83688a7982f7..8f12240b0eb7 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
@@ -465,7 +465,7 @@ static int isp_video_pipeline_validate(struct fimc_isp *isp)
return -EPIPE;
/* Retrieve format at the source pad */
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
index 1a396b7cd9a9..41b0a4a5929a 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
@@ -789,7 +789,7 @@ static int fimc_pipeline_validate(struct fimc_lite *fimc)
return -EPIPE;
}
/* Retrieve format at the source pad */
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c
index 544b54e428c9..52b43ea04030 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.c
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c
@@ -81,7 +81,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
struct media_pad *spad = &me->pads[i];
if (!(spad->flags & MEDIA_PAD_FL_SINK))
continue;
- pad = media_entity_remote_pad(spad);
+ pad = media_pad_remote_pad_first(spad);
if (pad)
break;
}
diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
index 27a214936cb0..6a0d35f33e8c 100644
--- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
@@ -124,7 +124,7 @@ static char *csi_clock_name[] = {
#define DEFAULT_SCLK_CSIS_FREQ 166000000UL
static const char * const csis_supply_name[] = {
- "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */
+ "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) supply */
"vddio", /* CSIS I/O and PLL (1.8V) supply */
};
#define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name)
diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
index 140854ab4dd8..c2d8f1e425d8 100644
--- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
@@ -811,7 +811,7 @@ static int camif_pipeline_validate(struct camif_dev *camif)
int ret;
/* Retrieve format at the sensor subdev source pad */
- pad = media_entity_remote_pad(&camif->pads[0]);
+ pad = media_pad_remote_pad_first(&camif->pads[0]);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
return -EPIPE;
diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
index 456287186ad8..55814041b8d8 100644
--- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
@@ -1709,7 +1709,7 @@ static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
w_ratio = ctx->out_q.w / r->width;
h_ratio = ctx->out_q.h / r->height;
- scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
+ scale_factor = max(w_ratio, h_ratio);
scale_factor = clamp_val(scale_factor, 1, 8);
/* Align scale ratio to the nearest power of 2 */
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c
index 72a901e99450..187849841a28 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c
@@ -88,7 +88,6 @@ int s5p_mfc_power_on(void)
if (ret < 0) {
mfc_err("clock prepare failed for clock: %s\n",
pm->clk_names[i]);
- i++;
goto err;
}
}
@@ -98,7 +97,7 @@ int s5p_mfc_power_on(void)
return 0;
err:
- while (--i > 0)
+ while (--i >= 0)
clk_disable_unprepare(pm->clocks[i]);
pm_runtime_put(pm->device);
return ret;
diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
index 7bb1384e4bad..cefe6b7bfdc4 100644
--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
+++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
@@ -107,7 +107,7 @@ static void channel_swdemux_tsklet(struct tasklet_struct *t)
size,
DMA_FROM_DEVICE);
- buf = (u8 *) channel->back_buffer_aligned;
+ buf = channel->back_buffer_aligned;
dev_dbg(fei->dev,
"chan=%d channel=%p num_packets = %d, buf = %p, pos = 0x%x\n\trp=0x%lx, wp=0x%lx\n",
@@ -176,7 +176,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
channel = fei->channel_data[stdemux->tsin_index];
- bitmap = (unsigned long *) channel->pid_buffer_aligned;
+ bitmap = channel->pid_buffer_aligned;
/* 8192 is a special PID */
if (dvbdmxfeed->pid == 8192) {
@@ -272,7 +272,7 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
channel = fei->channel_data[stdemux->tsin_index];
- bitmap = (unsigned long *) channel->pid_buffer_aligned;
+ bitmap = channel->pid_buffer_aligned;
if (dvbdmxfeed->pid == 8192) {
tmp = readl(fei->io + C8SECTPFE_IB_PID_SET(channel->tsin_id));
@@ -333,8 +333,7 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
__func__, __LINE__, stdemux, channel->tsin_id);
/* turn off all PIDS in the bitmap */
- memset((void *)channel->pid_buffer_aligned
- , 0x00, PID_TABLE_SIZE);
+ memset(channel->pid_buffer_aligned, 0, PID_TABLE_SIZE);
/* manage cache so data is visible to HW */
dma_sync_single_for_device(fei->dev,
@@ -458,23 +457,19 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei,
init_completion(&tsin->idle_completion);
- tsin->back_buffer_start = kzalloc(FEI_BUFFER_SIZE +
- FEI_ALIGNMENT, GFP_KERNEL);
-
+ tsin->back_buffer_start = kzalloc(FEI_BUFFER_SIZE + FEI_ALIGNMENT, GFP_KERNEL);
if (!tsin->back_buffer_start) {
ret = -ENOMEM;
goto err_unmap;
}
/* Ensure backbuffer is 32byte aligned */
- tsin->back_buffer_aligned = tsin->back_buffer_start
- + FEI_ALIGNMENT;
+ tsin->back_buffer_aligned = tsin->back_buffer_start + FEI_ALIGNMENT;
- tsin->back_buffer_aligned = (void *)
- (((uintptr_t) tsin->back_buffer_aligned) & ~0x1F);
+ tsin->back_buffer_aligned = PTR_ALIGN(tsin->back_buffer_aligned, FEI_ALIGNMENT);
tsin->back_buffer_busaddr = dma_map_single(fei->dev,
- (void *)tsin->back_buffer_aligned,
+ tsin->back_buffer_aligned,
FEI_BUFFER_SIZE,
DMA_BIDIRECTIONAL);
@@ -489,8 +484,7 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei,
* per pid. By powers of deduction we conclude stih407 family
* is configured (at SoC design stage) for bit per pid.
*/
- tsin->pid_buffer_start = kzalloc(2048, GFP_KERNEL);
-
+ tsin->pid_buffer_start = kzalloc(PID_TABLE_SIZE + PID_TABLE_SIZE, GFP_KERNEL);
if (!tsin->pid_buffer_start) {
ret = -ENOMEM;
goto err_unmap;
@@ -503,11 +497,9 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei,
* the register.
*/
- tsin->pid_buffer_aligned = tsin->pid_buffer_start +
- PID_TABLE_SIZE;
+ tsin->pid_buffer_aligned = tsin->pid_buffer_start + PID_TABLE_SIZE;
- tsin->pid_buffer_aligned = (void *)
- (((uintptr_t) tsin->pid_buffer_aligned) & ~0x3ff);
+ tsin->pid_buffer_aligned = PTR_ALIGN(tsin->pid_buffer_aligned, PID_TABLE_SIZE);
tsin->pid_buffer_busaddr = dma_map_single(fei->dev,
tsin->pid_buffer_aligned,
@@ -915,8 +907,7 @@ static int c8sectpfe_remove(struct platform_device *pdev)
if (readl(fei->io + SYS_OTHER_CLKEN))
writel(0, fei->io + SYS_OTHER_CLKEN);
- if (fei->c8sectpfeclk)
- clk_disable_unprepare(fei->c8sectpfeclk);
+ clk_disable_unprepare(fei->c8sectpfeclk);
return 0;
}
diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c
index 420ad4d8df5d..03eaee6d15da 100644
--- a/drivers/media/platform/st/sti/delta/delta-v4l2.c
+++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c
@@ -1669,14 +1669,12 @@ static int delta_open(struct file *file)
set_default_params(ctx);
/* enable ST231 clocks */
- if (delta->clk_st231)
- if (clk_prepare_enable(delta->clk_st231))
- dev_warn(delta->dev, "failed to enable st231 clk\n");
+ if (clk_prepare_enable(delta->clk_st231))
+ dev_warn(delta->dev, "failed to enable st231 clk\n");
/* enable FLASH_PROMIP clock */
- if (delta->clk_flash_promip)
- if (clk_prepare_enable(delta->clk_flash_promip))
- dev_warn(delta->dev, "failed to enable delta promip clk\n");
+ if (clk_prepare_enable(delta->clk_flash_promip))
+ dev_warn(delta->dev, "failed to enable delta promip clk\n");
mutex_unlock(&delta->lock);
@@ -1717,12 +1715,10 @@ static int delta_release(struct file *file)
v4l2_fh_exit(&ctx->fh);
/* disable ST231 clocks */
- if (delta->clk_st231)
- clk_disable_unprepare(delta->clk_st231);
+ clk_disable_unprepare(delta->clk_st231);
/* disable FLASH_PROMIP clock */
- if (delta->clk_flash_promip)
- clk_disable_unprepare(delta->clk_flash_promip);
+ clk_disable_unprepare(delta->clk_flash_promip);
dev_dbg(delta->dev, "%s decoder instance released\n", ctx->name);
@@ -1926,8 +1922,7 @@ static int delta_runtime_suspend(struct device *dev)
{
struct delta_dev *delta = dev_get_drvdata(dev);
- if (delta->clk_delta)
- clk_disable_unprepare(delta->clk_delta);
+ clk_disable_unprepare(delta->clk_delta);
return 0;
}
@@ -1936,9 +1931,8 @@ static int delta_runtime_resume(struct device *dev)
{
struct delta_dev *delta = dev_get_drvdata(dev);
- if (delta->clk_delta)
- if (clk_prepare_enable(delta->clk_delta))
- dev_warn(dev, "failed to prepare/enable delta clk\n");
+ if (clk_prepare_enable(delta->clk_delta))
+ dev_warn(dev, "failed to prepare/enable delta clk\n");
return 0;
}
diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 09a743cd7004..2ca95ab2b0fe 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -611,7 +611,7 @@ static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
@@ -622,7 +622,6 @@ static struct media_entity *dcmi_find_source(struct stm32_dcmi *dcmi)
}
static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi,
- struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
struct media_entity *entity = &dcmi->source->entity;
@@ -664,7 +663,7 @@ static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi,
format->format.width, format->format.height);
fmt.pad = pad->index;
- ret = v4l2_subdev_call(subdev, pad, set_fmt, sd_state, &fmt);
+ ret = v4l2_subdev_call(subdev, pad, set_fmt, NULL, &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,
@@ -682,7 +681,7 @@ static int dcmi_pipeline_s_fmt(struct stm32_dcmi *dcmi,
}
/* Walk to next entity */
- sink_pad = media_entity_remote_pad(src_pad);
+ sink_pad = media_pad_remote_pad_first(src_pad);
if (!sink_pad || !is_media_entity_v4l2_subdev(sink_pad->entity))
break;
@@ -706,7 +705,7 @@ static int dcmi_pipeline_s_stream(struct stm32_dcmi *dcmi, int state)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
@@ -999,10 +998,6 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f,
const struct dcmi_format *sd_fmt;
struct dcmi_framesize sd_fsize;
struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_subdev_pad_config pad_cfg;
- struct v4l2_subdev_state pad_state = {
- .pads = &pad_cfg
- };
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
@@ -1037,8 +1032,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->source, pad, set_fmt,
- &pad_state, &format);
+ ret = v4l2_subdev_call_state_try(dcmi->source, pad, set_fmt, &format);
if (ret < 0)
return ret;
@@ -1115,7 +1109,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 = dcmi_pipeline_s_fmt(dcmi, NULL, &format);
+ ret = dcmi_pipeline_s_fmt(dcmi, &format);
if (ret < 0)
return ret;
@@ -1187,10 +1181,6 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi,
struct v4l2_subdev_format format = {
.which = V4L2_SUBDEV_FORMAT_TRY,
};
- struct v4l2_subdev_pad_config pad_cfg;
- struct v4l2_subdev_state pad_state = {
- .pads = &pad_cfg
- };
int ret;
sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat);
@@ -1203,8 +1193,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->source, pad, set_fmt,
- &pad_state, &format);
+ ret = v4l2_subdev_call_state_try(dcmi->source, pad, set_fmt, &format);
if (ret < 0)
return ret;
@@ -1592,26 +1581,32 @@ 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,
.mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.bpp = 2,
}, {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_1X16,
+ .bpp = 2,
+ }, {
.fourcc = V4L2_PIX_FMT_YUYV,
.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
}, {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .bpp = 2,
+ }, {
.fourcc = V4L2_PIX_FMT_UYVY,
.mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
.bpp = 2,
}, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .bpp = 2,
+ }, {
.fourcc = V4L2_PIX_FMT_JPEG,
.mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
.bpp = 1,
@@ -1631,6 +1626,54 @@ static const struct dcmi_format dcmi_formats[] = {
.fourcc = V4L2_PIX_FMT_SRGGB8,
.mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
.bpp = 1,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR14,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR14_1X14,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG14,
+ .mbus_code = MEDIA_BUS_FMT_SGBRG14_1X14,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG14,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG14_1X14,
+ .bpp = 2,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB14,
+ .mbus_code = MEDIA_BUS_FMT_SRGGB14_1X14,
+ .bpp = 2,
},
};
diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig
index 46b7b9bf989c..2dd15083a1d9 100644
--- a/drivers/media/platform/sunxi/Kconfig
+++ b/drivers/media/platform/sunxi/Kconfig
@@ -4,5 +4,7 @@ comment "Sunxi media platform drivers"
source "drivers/media/platform/sunxi/sun4i-csi/Kconfig"
source "drivers/media/platform/sunxi/sun6i-csi/Kconfig"
+source "drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig"
+source "drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig"
source "drivers/media/platform/sunxi/sun8i-di/Kconfig"
source "drivers/media/platform/sunxi/sun8i-rotate/Kconfig"
diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile
index fc537c9f5ca9..9aa01cb01883 100644
--- a/drivers/media/platform/sunxi/Makefile
+++ b/drivers/media/platform/sunxi/Makefile
@@ -2,5 +2,7 @@
obj-y += sun4i-csi/
obj-y += sun6i-csi/
+obj-y += sun6i-mipi-csi2/
+obj-y += sun8i-a83t-mipi-csi2/
obj-y += sun8i-di/
obj-y += sun8i-rotate/
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
index 682c26536034..1d46e113d01d 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
@@ -77,7 +77,7 @@ sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad)
{
struct media_pad *remote;
- remote = media_entity_remote_pad(&video->pad);
+ remote = media_pad_remote_pad_first(&video->pad);
if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
@@ -560,7 +560,7 @@ static int sun6i_video_link_validate(struct media_link *link)
video->mbus_code = 0;
- if (!media_entity_remote_pad(link->sink->entity->pads)) {
+ if (!media_pad_remote_pad_first(link->sink->entity->pads)) {
dev_info(video->csi->dev,
"video node %s pad not connected\n", vdev->name);
return -ENOLINK;
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig
new file mode 100644
index 000000000000..eb982466abd3
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_SUN6I_MIPI_CSI2
+ tristate "Allwinner A31 MIPI CSI-2 Controller Driver"
+ depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on PM && COMMON_CLK
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ select PHY_SUN6I_MIPI_DPHY
+ select GENERIC_PHY_MIPI_DPHY
+ select REGMAP_MMIO
+ help
+ Support for the Allwinner A31 MIPI CSI-2 controller, also found on
+ other platforms such as the V3/V3s.
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile
new file mode 100644
index 000000000000..14e4e03818b5
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+sun6i-mipi-csi2-y += sun6i_mipi_csi2.o
+
+obj-$(CONFIG_VIDEO_SUN6I_MIPI_CSI2) += sun6i-mipi-csi2.o
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
new file mode 100644
index 000000000000..a4e3f9a6b2ff
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
@@ -0,0 +1,750 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#include "sun6i_mipi_csi2.h"
+#include "sun6i_mipi_csi2_reg.h"
+
+/* Format */
+
+static const struct sun6i_mipi_csi2_format sun6i_mipi_csi2_formats[] = {
+ {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .data_type = MIPI_CSI2_DT_RAW8,
+ .bpp = 8,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .data_type = MIPI_CSI2_DT_RAW8,
+ .bpp = 8,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .data_type = MIPI_CSI2_DT_RAW8,
+ .bpp = 8,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .data_type = MIPI_CSI2_DT_RAW8,
+ .bpp = 8,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .data_type = MIPI_CSI2_DT_RAW10,
+ .bpp = 10,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .data_type = MIPI_CSI2_DT_RAW10,
+ .bpp = 10,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .data_type = MIPI_CSI2_DT_RAW10,
+ .bpp = 10,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .data_type = MIPI_CSI2_DT_RAW10,
+ .bpp = 10,
+ },
+};
+
+static const struct sun6i_mipi_csi2_format *
+sun6i_mipi_csi2_format_find(u32 mbus_code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun6i_mipi_csi2_formats); i++)
+ if (sun6i_mipi_csi2_formats[i].mbus_code == mbus_code)
+ return &sun6i_mipi_csi2_formats[i];
+
+ return NULL;
+}
+
+/* Controller */
+
+static void sun6i_mipi_csi2_enable(struct sun6i_mipi_csi2_device *csi2_dev)
+{
+ struct regmap *regmap = csi2_dev->regmap;
+
+ regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG,
+ SUN6I_MIPI_CSI2_CTL_EN, SUN6I_MIPI_CSI2_CTL_EN);
+}
+
+static void sun6i_mipi_csi2_disable(struct sun6i_mipi_csi2_device *csi2_dev)
+{
+ struct regmap *regmap = csi2_dev->regmap;
+
+ regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG,
+ SUN6I_MIPI_CSI2_CTL_EN, 0);
+}
+
+static void sun6i_mipi_csi2_configure(struct sun6i_mipi_csi2_device *csi2_dev)
+{
+ struct regmap *regmap = csi2_dev->regmap;
+ unsigned int lanes_count =
+ csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes;
+ struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format;
+ const struct sun6i_mipi_csi2_format *format;
+ struct device *dev = csi2_dev->dev;
+ u32 version = 0;
+
+ format = sun6i_mipi_csi2_format_find(mbus_format->code);
+ if (WARN_ON(!format))
+ return;
+
+ /*
+ * The enable flow in the Allwinner BSP is a bit different: the enable
+ * and reset bits are set together before starting the CSI controller.
+ *
+ * In mainline we enable the CSI controller first (due to subdev logic).
+ * One reliable way to make this work is to deassert reset, configure
+ * registers and enable the controller when everything's ready.
+ *
+ * However, setting the version enable bit and removing it afterwards
+ * appears necessary for capture to work reliably, while replacing it
+ * with a delay doesn't do the trick.
+ */
+ regmap_write(regmap, SUN6I_MIPI_CSI2_CTL_REG,
+ SUN6I_MIPI_CSI2_CTL_RESET_N |
+ SUN6I_MIPI_CSI2_CTL_VERSION_EN |
+ SUN6I_MIPI_CSI2_CTL_UNPK_EN);
+
+ regmap_read(regmap, SUN6I_MIPI_CSI2_VERSION_REG, &version);
+
+ regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG,
+ SUN6I_MIPI_CSI2_CTL_VERSION_EN, 0);
+
+ dev_dbg(dev, "A31 MIPI CSI-2 version: %04x\n", version);
+
+ regmap_write(regmap, SUN6I_MIPI_CSI2_CFG_REG,
+ SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(1) |
+ SUN6I_MIPI_CSI2_CFG_LANE_COUNT(lanes_count));
+
+ /*
+ * Only a single virtual channel (index 0) is currently supported.
+ * While the registers do mention multiple physical channels being
+ * available (which can be configured to match a specific virtual
+ * channel or data type), it's unclear whether channels > 0 are actually
+ * connected and available and the reference source code only makes use
+ * of channel 0.
+ *
+ * Using extra channels would also require matching channels to be
+ * available on the CSI (and ISP) side, which is also unsure although
+ * some CSI implementations are said to support multiple channels for
+ * BT656 time-sharing.
+ *
+ * We still configure virtual channel numbers to ensure that virtual
+ * channel 0 only goes to channel 0.
+ */
+
+ regmap_write(regmap, SUN6I_MIPI_CSI2_VCDT_RX_REG,
+ SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(3, 3) |
+ SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(2, 2) |
+ SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(1, 1) |
+ SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(0, 0) |
+ SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(0, format->data_type));
+
+ regmap_write(regmap, SUN6I_MIPI_CSI2_CH_INT_PD_REG,
+ SUN6I_MIPI_CSI2_CH_INT_PD_CLEAR);
+}
+
+/* V4L2 Subdev */
+
+static int sun6i_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on)
+{
+ struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev);
+ struct v4l2_subdev *source_subdev = csi2_dev->bridge.source_subdev;
+ union phy_configure_opts dphy_opts = { 0 };
+ struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy;
+ struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format;
+ const struct sun6i_mipi_csi2_format *format;
+ struct phy *dphy = csi2_dev->dphy;
+ struct device *dev = csi2_dev->dev;
+ struct v4l2_ctrl *ctrl;
+ unsigned int lanes_count =
+ csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes;
+ unsigned long pixel_rate;
+ int ret;
+
+ if (!source_subdev)
+ return -ENODEV;
+
+ if (!on) {
+ ret = v4l2_subdev_call(source_subdev, video, s_stream, 0);
+ goto disable;
+ }
+
+ /* Runtime PM */
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ /* Sensor Pixel Rate */
+
+ ctrl = v4l2_ctrl_find(source_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE);
+ if (!ctrl) {
+ dev_err(dev, "missing sensor pixel rate\n");
+ ret = -ENODEV;
+ goto error_pm;
+ }
+
+ pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl);
+ if (!pixel_rate) {
+ dev_err(dev, "missing (zero) sensor pixel rate\n");
+ ret = -ENODEV;
+ goto error_pm;
+ }
+
+ /* D-PHY */
+
+ if (!lanes_count) {
+ dev_err(dev, "missing (zero) MIPI CSI-2 lanes count\n");
+ ret = -ENODEV;
+ goto error_pm;
+ }
+
+ format = sun6i_mipi_csi2_format_find(mbus_format->code);
+ if (WARN_ON(!format)) {
+ ret = -ENODEV;
+ goto error_pm;
+ }
+
+ phy_mipi_dphy_get_default_config(pixel_rate, format->bpp, lanes_count,
+ dphy_cfg);
+
+ /*
+ * Note that our hardware is using DDR, which is not taken in account by
+ * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from
+ * the pixel rate, lanes count and bpp.
+ *
+ * The resulting clock rate is basically the symbol rate over the whole
+ * link. The actual clock rate is calculated with division by two since
+ * DDR samples both on rising and falling edges.
+ */
+
+ dev_dbg(dev, "A31 MIPI CSI-2 config:\n");
+ dev_dbg(dev, "%ld pixels/s, %u bits/pixel, %u lanes, %lu Hz clock\n",
+ pixel_rate, format->bpp, lanes_count,
+ dphy_cfg->hs_clk_rate / 2);
+
+ ret = phy_reset(dphy);
+ if (ret) {
+ dev_err(dev, "failed to reset MIPI D-PHY\n");
+ goto error_pm;
+ }
+
+ ret = phy_configure(dphy, &dphy_opts);
+ if (ret) {
+ dev_err(dev, "failed to configure MIPI D-PHY\n");
+ goto error_pm;
+ }
+
+ /* Controller */
+
+ sun6i_mipi_csi2_configure(csi2_dev);
+ sun6i_mipi_csi2_enable(csi2_dev);
+
+ /* D-PHY */
+
+ ret = phy_power_on(dphy);
+ if (ret) {
+ dev_err(dev, "failed to power on MIPI D-PHY\n");
+ goto error_pm;
+ }
+
+ /* Source */
+
+ ret = v4l2_subdev_call(source_subdev, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD)
+ goto disable;
+
+ return 0;
+
+disable:
+ if (!on)
+ ret = 0;
+ phy_power_off(dphy);
+ sun6i_mipi_csi2_disable(csi2_dev);
+
+error_pm:
+ pm_runtime_put(dev);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops sun6i_mipi_csi2_video_ops = {
+ .s_stream = sun6i_mipi_csi2_s_stream,
+};
+
+static void
+sun6i_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format)
+{
+ if (!sun6i_mipi_csi2_format_find(mbus_format->code))
+ mbus_format->code = sun6i_mipi_csi2_formats[0].mbus_code;
+
+ mbus_format->field = V4L2_FIELD_NONE;
+ mbus_format->colorspace = V4L2_COLORSPACE_RAW;
+ mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int sun6i_mipi_csi2_init_cfg(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state)
+{
+ struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev);
+ unsigned int pad = SUN6I_MIPI_CSI2_PAD_SINK;
+ struct v4l2_mbus_framefmt *mbus_format =
+ v4l2_subdev_get_try_format(subdev, state, pad);
+ struct mutex *lock = &csi2_dev->bridge.lock;
+
+ mutex_lock(lock);
+
+ mbus_format->code = sun6i_mipi_csi2_formats[0].mbus_code;
+ mbus_format->width = 640;
+ mbus_format->height = 480;
+
+ sun6i_mipi_csi2_mbus_format_prepare(mbus_format);
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static int
+sun6i_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code_enum)
+{
+ if (code_enum->index >= ARRAY_SIZE(sun6i_mipi_csi2_formats))
+ return -EINVAL;
+
+ code_enum->code = sun6i_mipi_csi2_formats[code_enum->index].mbus_code;
+
+ return 0;
+}
+
+static int sun6i_mipi_csi2_get_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev);
+ struct v4l2_mbus_framefmt *mbus_format = &format->format;
+ struct mutex *lock = &csi2_dev->bridge.lock;
+
+ mutex_lock(lock);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ *mbus_format = *v4l2_subdev_get_try_format(subdev, state,
+ format->pad);
+ else
+ *mbus_format = csi2_dev->bridge.mbus_format;
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct sun6i_mipi_csi2_device *csi2_dev = v4l2_get_subdevdata(subdev);
+ struct v4l2_mbus_framefmt *mbus_format = &format->format;
+ struct mutex *lock = &csi2_dev->bridge.lock;
+
+ mutex_lock(lock);
+
+ sun6i_mipi_csi2_mbus_format_prepare(mbus_format);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ *v4l2_subdev_get_try_format(subdev, state, format->pad) =
+ *mbus_format;
+ else
+ csi2_dev->bridge.mbus_format = *mbus_format;
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_pad_ops = {
+ .init_cfg = sun6i_mipi_csi2_init_cfg,
+ .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code,
+ .get_fmt = sun6i_mipi_csi2_get_fmt,
+ .set_fmt = sun6i_mipi_csi2_set_fmt,
+};
+
+static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = {
+ .video = &sun6i_mipi_csi2_video_ops,
+ .pad = &sun6i_mipi_csi2_pad_ops,
+};
+
+/* Media Entity */
+
+static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/* V4L2 Async */
+
+static int
+sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *remote_subdev,
+ struct v4l2_async_subdev *async_subdev)
+{
+ struct v4l2_subdev *subdev = notifier->sd;
+ struct sun6i_mipi_csi2_device *csi2_dev =
+ container_of(notifier, struct sun6i_mipi_csi2_device,
+ bridge.notifier);
+ struct media_entity *sink_entity = &subdev->entity;
+ struct media_entity *source_entity = &remote_subdev->entity;
+ struct device *dev = csi2_dev->dev;
+ int sink_pad_index = 0;
+ int source_pad_index;
+ int ret;
+
+ ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "missing source pad in external entity %s\n",
+ source_entity->name);
+ return -EINVAL;
+ }
+
+ source_pad_index = ret;
+
+ dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name,
+ source_pad_index, sink_entity->name, sink_pad_index);
+
+ ret = media_create_pad_link(source_entity, source_pad_index,
+ sink_entity, sink_pad_index,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(dev, "failed to create %s:%u -> %s:%u link\n",
+ source_entity->name, source_pad_index,
+ sink_entity->name, sink_pad_index);
+ return ret;
+ }
+
+ csi2_dev->bridge.source_subdev = remote_subdev;
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations
+sun6i_mipi_csi2_notifier_ops = {
+ .bound = sun6i_mipi_csi2_notifier_bound,
+};
+
+/* Bridge */
+
+static int
+sun6i_mipi_csi2_bridge_source_setup(struct sun6i_mipi_csi2_device *csi2_dev)
+{
+ struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier;
+ struct v4l2_fwnode_endpoint *endpoint = &csi2_dev->bridge.endpoint;
+ struct v4l2_async_subdev *subdev_async;
+ struct fwnode_handle *handle;
+ struct device *dev = csi2_dev->dev;
+ int ret;
+
+ handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!handle)
+ return -ENODEV;
+
+ endpoint->bus_type = V4L2_MBUS_CSI2_DPHY;
+
+ ret = v4l2_fwnode_endpoint_parse(handle, endpoint);
+ if (ret)
+ goto complete;
+
+ subdev_async =
+ v4l2_async_nf_add_fwnode_remote(notifier, handle,
+ struct v4l2_async_subdev);
+ if (IS_ERR(subdev_async))
+ ret = PTR_ERR(subdev_async);
+
+complete:
+ fwnode_handle_put(handle);
+
+ return ret;
+}
+
+static int sun6i_mipi_csi2_bridge_setup(struct sun6i_mipi_csi2_device *csi2_dev)
+{
+ struct sun6i_mipi_csi2_bridge *bridge = &csi2_dev->bridge;
+ struct v4l2_subdev *subdev = &bridge->subdev;
+ struct v4l2_async_notifier *notifier = &bridge->notifier;
+ struct media_pad *pads = bridge->pads;
+ struct device *dev = csi2_dev->dev;
+ int ret;
+
+ mutex_init(&bridge->lock);
+
+ /* V4L2 Subdev */
+
+ v4l2_subdev_init(subdev, &sun6i_mipi_csi2_subdev_ops);
+ strscpy(subdev->name, SUN6I_MIPI_CSI2_NAME, sizeof(subdev->name));
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ subdev->owner = THIS_MODULE;
+ subdev->dev = dev;
+
+ v4l2_set_subdevdata(subdev, csi2_dev);
+
+ /* Media Entity */
+
+ subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ subdev->entity.ops = &sun6i_mipi_csi2_entity_ops;
+
+ /* Media Pads */
+
+ pads[SUN6I_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pads[SUN6I_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&subdev->entity, SUN6I_MIPI_CSI2_PAD_COUNT,
+ pads);
+ if (ret)
+ return ret;
+
+ /* V4L2 Async */
+
+ v4l2_async_nf_init(notifier);
+ notifier->ops = &sun6i_mipi_csi2_notifier_ops;
+
+ ret = sun6i_mipi_csi2_bridge_source_setup(csi2_dev);
+ if (ret)
+ goto error_v4l2_notifier_cleanup;
+
+ ret = v4l2_async_subdev_nf_register(subdev, notifier);
+ if (ret < 0)
+ goto error_v4l2_notifier_cleanup;
+
+ /* V4L2 Subdev */
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0)
+ goto error_v4l2_notifier_unregister;
+
+ return 0;
+
+error_v4l2_notifier_unregister:
+ v4l2_async_nf_unregister(notifier);
+
+error_v4l2_notifier_cleanup:
+ v4l2_async_nf_cleanup(notifier);
+
+ media_entity_cleanup(&subdev->entity);
+
+ return ret;
+}
+
+static void
+sun6i_mipi_csi2_bridge_cleanup(struct sun6i_mipi_csi2_device *csi2_dev)
+{
+ struct v4l2_subdev *subdev = &csi2_dev->bridge.subdev;
+ struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier;
+
+ v4l2_async_unregister_subdev(subdev);
+ v4l2_async_nf_unregister(notifier);
+ v4l2_async_nf_cleanup(notifier);
+ media_entity_cleanup(&subdev->entity);
+}
+
+/* Platform */
+
+static int sun6i_mipi_csi2_suspend(struct device *dev)
+{
+ struct sun6i_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(csi2_dev->clock_mod);
+ reset_control_assert(csi2_dev->reset);
+
+ return 0;
+}
+
+static int sun6i_mipi_csi2_resume(struct device *dev)
+{
+ struct sun6i_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_deassert(csi2_dev->reset);
+ if (ret) {
+ dev_err(dev, "failed to deassert reset\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(csi2_dev->clock_mod);
+ if (ret) {
+ dev_err(dev, "failed to enable module clock\n");
+ goto error_reset;
+ }
+
+ return 0;
+
+error_reset:
+ reset_control_assert(csi2_dev->reset);
+
+ return ret;
+}
+
+static const struct dev_pm_ops sun6i_mipi_csi2_pm_ops = {
+ .runtime_suspend = sun6i_mipi_csi2_suspend,
+ .runtime_resume = sun6i_mipi_csi2_resume,
+};
+
+static const struct regmap_config sun6i_mipi_csi2_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x400,
+};
+
+static int
+sun6i_mipi_csi2_resources_setup(struct sun6i_mipi_csi2_device *csi2_dev,
+ struct platform_device *platform_dev)
+{
+ struct device *dev = csi2_dev->dev;
+ void __iomem *io_base;
+ int ret;
+
+ /* Registers */
+
+ io_base = devm_platform_ioremap_resource(platform_dev, 0);
+ if (IS_ERR(io_base))
+ return PTR_ERR(io_base);
+
+ csi2_dev->regmap =
+ devm_regmap_init_mmio_clk(dev, "bus", io_base,
+ &sun6i_mipi_csi2_regmap_config);
+ if (IS_ERR(csi2_dev->regmap)) {
+ dev_err(dev, "failed to init register map\n");
+ return PTR_ERR(csi2_dev->regmap);
+ }
+
+ /* Clock */
+
+ csi2_dev->clock_mod = devm_clk_get(dev, "mod");
+ if (IS_ERR(csi2_dev->clock_mod)) {
+ dev_err(dev, "failed to acquire mod clock\n");
+ return PTR_ERR(csi2_dev->clock_mod);
+ }
+
+ ret = clk_set_rate_exclusive(csi2_dev->clock_mod, 297000000);
+ if (ret) {
+ dev_err(dev, "failed to set mod clock rate\n");
+ return ret;
+ }
+
+ /* Reset */
+
+ csi2_dev->reset = devm_reset_control_get_shared(dev, NULL);
+ if (IS_ERR(csi2_dev->reset)) {
+ dev_err(dev, "failed to get reset controller\n");
+ return PTR_ERR(csi2_dev->reset);
+ }
+
+ /* D-PHY */
+
+ csi2_dev->dphy = devm_phy_get(dev, "dphy");
+ if (IS_ERR(csi2_dev->dphy)) {
+ dev_err(dev, "failed to get MIPI D-PHY\n");
+ return PTR_ERR(csi2_dev->dphy);
+ }
+
+ ret = phy_init(csi2_dev->dphy);
+ if (ret) {
+ dev_err(dev, "failed to initialize MIPI D-PHY\n");
+ return ret;
+ }
+
+ /* Runtime PM */
+
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static void
+sun6i_mipi_csi2_resources_cleanup(struct sun6i_mipi_csi2_device *csi2_dev)
+{
+ pm_runtime_disable(csi2_dev->dev);
+ phy_exit(csi2_dev->dphy);
+ clk_rate_exclusive_put(csi2_dev->clock_mod);
+}
+
+static int sun6i_mipi_csi2_probe(struct platform_device *platform_dev)
+{
+ struct sun6i_mipi_csi2_device *csi2_dev;
+ struct device *dev = &platform_dev->dev;
+ int ret;
+
+ csi2_dev = devm_kzalloc(dev, sizeof(*csi2_dev), GFP_KERNEL);
+ if (!csi2_dev)
+ return -ENOMEM;
+
+ csi2_dev->dev = dev;
+ platform_set_drvdata(platform_dev, csi2_dev);
+
+ ret = sun6i_mipi_csi2_resources_setup(csi2_dev, platform_dev);
+ if (ret)
+ return ret;
+
+ ret = sun6i_mipi_csi2_bridge_setup(csi2_dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sun6i_mipi_csi2_remove(struct platform_device *platform_dev)
+{
+ struct sun6i_mipi_csi2_device *csi2_dev =
+ platform_get_drvdata(platform_dev);
+
+ sun6i_mipi_csi2_bridge_cleanup(csi2_dev);
+ sun6i_mipi_csi2_resources_cleanup(csi2_dev);
+
+ return 0;
+}
+
+static const struct of_device_id sun6i_mipi_csi2_of_match[] = {
+ { .compatible = "allwinner,sun6i-a31-mipi-csi2" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match);
+
+static struct platform_driver sun6i_mipi_csi2_platform_driver = {
+ .probe = sun6i_mipi_csi2_probe,
+ .remove = sun6i_mipi_csi2_remove,
+ .driver = {
+ .name = SUN6I_MIPI_CSI2_NAME,
+ .of_match_table = of_match_ptr(sun6i_mipi_csi2_of_match),
+ .pm = &sun6i_mipi_csi2_pm_ops,
+ },
+};
+module_platform_driver(sun6i_mipi_csi2_platform_driver);
+
+MODULE_DESCRIPTION("Allwinner A31 MIPI CSI-2 Controller Driver");
+MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h
new file mode 100644
index 000000000000..24b15e34b5e8
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN6I_MIPI_CSI2_H_
+#define _SUN6I_MIPI_CSI2_H_
+
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define SUN6I_MIPI_CSI2_NAME "sun6i-mipi-csi2"
+
+enum sun6i_mipi_csi2_pad {
+ SUN6I_MIPI_CSI2_PAD_SINK = 0,
+ SUN6I_MIPI_CSI2_PAD_SOURCE = 1,
+ SUN6I_MIPI_CSI2_PAD_COUNT = 2,
+};
+
+struct sun6i_mipi_csi2_format {
+ u32 mbus_code;
+ u8 data_type;
+ u32 bpp;
+};
+
+struct sun6i_mipi_csi2_bridge {
+ struct v4l2_subdev subdev;
+ struct media_pad pads[SUN6I_MIPI_CSI2_PAD_COUNT];
+ struct v4l2_fwnode_endpoint endpoint;
+ struct v4l2_async_notifier notifier;
+ struct v4l2_mbus_framefmt mbus_format;
+ struct mutex lock; /* Mbus format lock. */
+
+ struct v4l2_subdev *source_subdev;
+};
+
+struct sun6i_mipi_csi2_device {
+ struct device *dev;
+
+ struct regmap *regmap;
+ struct clk *clock_mod;
+ struct reset_control *reset;
+ struct phy *dphy;
+
+ struct sun6i_mipi_csi2_bridge bridge;
+};
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h
new file mode 100644
index 000000000000..d9c92cf2b038
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN6I_MIPI_CSI2_REG_H_
+#define _SUN6I_MIPI_CSI2_REG_H_
+
+#define SUN6I_MIPI_CSI2_CTL_REG 0x0
+#define SUN6I_MIPI_CSI2_CTL_RESET_N BIT(31)
+#define SUN6I_MIPI_CSI2_CTL_VERSION_EN BIT(30)
+#define SUN6I_MIPI_CSI2_CTL_UNPK_EN BIT(1)
+#define SUN6I_MIPI_CSI2_CTL_EN BIT(0)
+
+#define SUN6I_MIPI_CSI2_CFG_REG 0x4
+#define SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(v) ((((v) - 1) << 8) & \
+ GENMASK(9, 8))
+#define SUN6I_MIPI_CSI2_CFG_LANE_COUNT(v) (((v) - 1) & GENMASK(1, 0))
+
+#define SUN6I_MIPI_CSI2_VCDT_RX_REG 0x8
+#define SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \
+ ((ch) * 8 + 6))
+#define SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \
+ ((ch) * 8))
+#define SUN6I_MIPI_CSI2_RX_PKT_NUM_REG 0xc
+
+#define SUN6I_MIPI_CSI2_VERSION_REG 0x3c
+
+#define SUN6I_MIPI_CSI2_CH_CFG_REG 0x40
+#define SUN6I_MIPI_CSI2_CH_INT_EN_REG 0x50
+#define SUN6I_MIPI_CSI2_CH_INT_EN_EOT_ERR BIT(29)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_CHKSUM_ERR BIT(28)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_WRN BIT(27)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_ERR BIT(26)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_SYNC_ERR BIT(25)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_SYNC_ERR BIT(24)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_EMB_DATA BIT(18)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_PF BIT(17)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_PH_UPDATE BIT(16)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_START_SYNC BIT(11)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_END_SYNC BIT(10)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_START_SYNC BIT(9)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_END_SYNC BIT(8)
+#define SUN6I_MIPI_CSI2_CH_INT_EN_FIFO_OVER BIT(0)
+
+#define SUN6I_MIPI_CSI2_CH_INT_PD_REG 0x58
+#define SUN6I_MIPI_CSI2_CH_INT_PD_CLEAR 0xff
+#define SUN6I_MIPI_CSI2_CH_INT_PD_EOT_ERR BIT(29)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_CHKSUM_ERR BIT(28)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_WRN BIT(27)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_ERR BIT(26)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_SYNC_ERR BIT(25)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_SYNC_ERR BIT(24)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_EMB_DATA BIT(18)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_PF BIT(17)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_PH_UPDATE BIT(16)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_START_SYNC BIT(11)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_END_SYNC BIT(10)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_START_SYNC BIT(9)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_END_SYNC BIT(8)
+#define SUN6I_MIPI_CSI2_CH_INT_PD_FIFO_OVER BIT(0)
+
+#define SUN6I_MIPI_CSI2_CH_DT_TRIGGER_REG 0x60
+#define SUN6I_MIPI_CSI2_CH_CUR_PH_REG 0x70
+#define SUN6I_MIPI_CSI2_CH_ECC_REG 0x74
+#define SUN6I_MIPI_CSI2_CH_CKS_REG 0x78
+#define SUN6I_MIPI_CSI2_CH_FRAME_NUM_REG 0x7c
+#define SUN6I_MIPI_CSI2_CH_LINE_NUM_REG 0x80
+
+#define SUN6I_MIPI_CSI2_CH_OFFSET 0x100
+
+#define SUN6I_MIPI_CSI2_CH_REG(reg, ch) \
+ (SUN6I_MIPI_CSI2_CH_OFFSET * (ch) + (reg))
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig
new file mode 100644
index 000000000000..789d58ee12ea
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_SUN8I_A83T_MIPI_CSI2
+ tristate "Allwinner A83T MIPI CSI-2 Controller and D-PHY Driver"
+ depends on V4L_PLATFORM_DRIVERS && VIDEO_DEV
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on PM && COMMON_CLK
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ select V4L2_FWNODE
+ select REGMAP_MMIO
+ select GENERIC_PHY_MIPI_DPHY
+ help
+ Support for the Allwinner A83T MIPI CSI-2 controller and D-PHY.
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile
new file mode 100644
index 000000000000..1427d15a879a
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+sun8i-a83t-mipi-csi2-y += sun8i_a83t_mipi_csi2.o sun8i_a83t_dphy.o
+
+obj-$(CONFIG_VIDEO_SUN8I_A83T_MIPI_CSI2) += sun8i-a83t-mipi-csi2.o
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c
new file mode 100644
index 000000000000..24bbcc85013d
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+
+#include "sun8i_a83t_dphy.h"
+#include "sun8i_a83t_mipi_csi2.h"
+
+static int sun8i_a83t_dphy_configure(struct phy *dphy,
+ union phy_configure_opts *opts)
+{
+ return phy_mipi_dphy_config_validate(&opts->mipi_dphy);
+}
+
+static int sun8i_a83t_dphy_power_on(struct phy *dphy)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev = phy_get_drvdata(dphy);
+ struct regmap *regmap = csi2_dev->regmap;
+
+ regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG,
+ SUN8I_A83T_DPHY_CTRL_RESET_N |
+ SUN8I_A83T_DPHY_CTRL_SHUTDOWN_N);
+
+ regmap_write(regmap, SUN8I_A83T_DPHY_ANA0_REG,
+ SUN8I_A83T_DPHY_ANA0_REXT_EN |
+ SUN8I_A83T_DPHY_ANA0_RINT(2) |
+ SUN8I_A83T_DPHY_ANA0_SNK(2));
+
+ return 0;
+};
+
+static int sun8i_a83t_dphy_power_off(struct phy *dphy)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev = phy_get_drvdata(dphy);
+ struct regmap *regmap = csi2_dev->regmap;
+
+ regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, 0);
+
+ return 0;
+};
+
+static const struct phy_ops sun8i_a83t_dphy_ops = {
+ .configure = sun8i_a83t_dphy_configure,
+ .power_on = sun8i_a83t_dphy_power_on,
+ .power_off = sun8i_a83t_dphy_power_off,
+};
+
+int sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
+{
+ struct device *dev = csi2_dev->dev;
+ struct phy_provider *phy_provider;
+
+ csi2_dev->dphy = devm_phy_create(dev, NULL, &sun8i_a83t_dphy_ops);
+ if (IS_ERR(csi2_dev->dphy)) {
+ dev_err(dev, "failed to create D-PHY\n");
+ return PTR_ERR(csi2_dev->dphy);
+ }
+
+ phy_set_drvdata(csi2_dev->dphy, csi2_dev);
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider)) {
+ dev_err(dev, "failed to register D-PHY provider\n");
+ return PTR_ERR(phy_provider);
+ }
+
+ return 0;
+}
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h
new file mode 100644
index 000000000000..9ab709060770
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com>
+ * Copyright 2020-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN8I_A83T_DPHY_H_
+#define _SUN8I_A83T_DPHY_H_
+
+#include "sun8i_a83t_mipi_csi2.h"
+
+#define SUN8I_A83T_DPHY_CTRL_REG 0x10
+#define SUN8I_A83T_DPHY_CTRL_INIT_VALUE 0xb8df698e
+#define SUN8I_A83T_DPHY_CTRL_RESET_N BIT(31)
+#define SUN8I_A83T_DPHY_CTRL_SHUTDOWN_N BIT(15)
+#define SUN8I_A83T_DPHY_CTRL_DEBUG BIT(8)
+#define SUN8I_A83T_DPHY_STATUS_REG 0x14
+#define SUN8I_A83T_DPHY_STATUS_CLK_STOP BIT(10)
+#define SUN8I_A83T_DPHY_STATUS_CLK_ULPS BIT(9)
+#define SUN8I_A83T_DPHY_STATUS_HSCLK BIT(8)
+#define SUN8I_A83T_DPHY_STATUS_D3_STOP BIT(7)
+#define SUN8I_A83T_DPHY_STATUS_D2_STOP BIT(6)
+#define SUN8I_A83T_DPHY_STATUS_D1_STOP BIT(5)
+#define SUN8I_A83T_DPHY_STATUS_D0_STOP BIT(4)
+#define SUN8I_A83T_DPHY_STATUS_D3_ULPS BIT(3)
+#define SUN8I_A83T_DPHY_STATUS_D2_ULPS BIT(2)
+#define SUN8I_A83T_DPHY_STATUS_D1_ULPS BIT(1)
+#define SUN8I_A83T_DPHY_STATUS_D0_ULPS BIT(0)
+
+#define SUN8I_A83T_DPHY_ANA0_REG 0x30
+#define SUN8I_A83T_DPHY_ANA0_REXT_EN BIT(31)
+#define SUN8I_A83T_DPHY_ANA0_REXT BIT(30)
+#define SUN8I_A83T_DPHY_ANA0_RINT(v) (((v) << 28) & GENMASK(29, 28))
+#define SUN8I_A83T_DPHY_ANA0_SNK(v) (((v) << 20) & GENMASK(22, 20))
+
+int sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_device *csi2_dev);
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
new file mode 100644
index 000000000000..d052ee77ef0a
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
@@ -0,0 +1,816 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com>
+ * Copyright 2020-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <media/mipi-csi2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#include "sun8i_a83t_dphy.h"
+#include "sun8i_a83t_mipi_csi2.h"
+#include "sun8i_a83t_mipi_csi2_reg.h"
+
+/* Format */
+
+static const struct sun8i_a83t_mipi_csi2_format
+sun8i_a83t_mipi_csi2_formats[] = {
+ {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .data_type = MIPI_CSI2_DT_RAW8,
+ .bpp = 8,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .data_type = MIPI_CSI2_DT_RAW8,
+ .bpp = 8,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .data_type = MIPI_CSI2_DT_RAW8,
+ .bpp = 8,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .data_type = MIPI_CSI2_DT_RAW8,
+ .bpp = 8,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .data_type = MIPI_CSI2_DT_RAW10,
+ .bpp = 10,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .data_type = MIPI_CSI2_DT_RAW10,
+ .bpp = 10,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .data_type = MIPI_CSI2_DT_RAW10,
+ .bpp = 10,
+ },
+ {
+ .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .data_type = MIPI_CSI2_DT_RAW10,
+ .bpp = 10,
+ },
+};
+
+static const struct sun8i_a83t_mipi_csi2_format *
+sun8i_a83t_mipi_csi2_format_find(u32 mbus_code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(sun8i_a83t_mipi_csi2_formats); i++)
+ if (sun8i_a83t_mipi_csi2_formats[i].mbus_code == mbus_code)
+ return &sun8i_a83t_mipi_csi2_formats[i];
+
+ return NULL;
+}
+
+/* Controller */
+
+static void
+sun8i_a83t_mipi_csi2_init(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
+{
+ struct regmap *regmap = csi2_dev->regmap;
+
+ /*
+ * The Allwinner BSP sets various magic values on a bunch of registers.
+ * This is apparently a necessary initialization process that will cause
+ * the capture to fail with unsolicited interrupts hitting if skipped.
+ *
+ * Most of the registers are set to proper values later, except for the
+ * two reserved registers. They are said to hold a "hardware lock"
+ * value, without more information available.
+ */
+
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, 0);
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG,
+ SUN8I_A83T_MIPI_CSI2_CTRL_INIT_VALUE);
+
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG, 0);
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG,
+ SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_INIT_VALUE);
+
+ regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, 0);
+ regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG,
+ SUN8I_A83T_DPHY_CTRL_INIT_VALUE);
+
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD1_REG, 0);
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD1_REG,
+ SUN8I_A83T_MIPI_CSI2_RSVD1_HW_LOCK_VALUE);
+
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD2_REG, 0);
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD2_REG,
+ SUN8I_A83T_MIPI_CSI2_RSVD2_HW_LOCK_VALUE);
+
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, 0);
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG,
+ SUN8I_A83T_MIPI_CSI2_CFG_INIT_VALUE);
+}
+
+static void
+sun8i_a83t_mipi_csi2_enable(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
+{
+ struct regmap *regmap = csi2_dev->regmap;
+
+ regmap_update_bits(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG,
+ SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN,
+ SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN);
+}
+
+static void
+sun8i_a83t_mipi_csi2_disable(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
+{
+ struct regmap *regmap = csi2_dev->regmap;
+
+ regmap_update_bits(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG,
+ SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN, 0);
+
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, 0);
+}
+
+static void
+sun8i_a83t_mipi_csi2_configure(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
+{
+ struct regmap *regmap = csi2_dev->regmap;
+ unsigned int lanes_count =
+ csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes;
+ struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format;
+ const struct sun8i_a83t_mipi_csi2_format *format;
+ struct device *dev = csi2_dev->dev;
+ u32 version = 0;
+
+ format = sun8i_a83t_mipi_csi2_format_find(mbus_format->code);
+ if (WARN_ON(!format))
+ return;
+
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG,
+ SUN8I_A83T_MIPI_CSI2_CTRL_RESET_N);
+
+ regmap_read(regmap, SUN8I_A83T_MIPI_CSI2_VERSION_REG, &version);
+
+ dev_dbg(dev, "A83T MIPI CSI-2 version: %04x\n", version);
+
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG,
+ SUN8I_A83T_MIPI_CSI2_CFG_UNPKT_EN |
+ SUN8I_A83T_MIPI_CSI2_CFG_SYNC_DLY_CYCLE(8) |
+ SUN8I_A83T_MIPI_CSI2_CFG_N_CHANNEL(1) |
+ SUN8I_A83T_MIPI_CSI2_CFG_N_LANE(lanes_count));
+
+ /*
+ * Only a single virtual channel (index 0) is currently supported.
+ * While the registers do mention multiple physical channels being
+ * available (which can be configured to match a specific virtual
+ * channel or data type), it's unclear whether channels > 0 are actually
+ * connected and available and the reference source code only makes use
+ * of channel 0.
+ *
+ * Using extra channels would also require matching channels to be
+ * available on the CSI (and ISP) side, which is also unsure although
+ * some CSI implementations are said to support multiple channels for
+ * BT656 time-sharing.
+ *
+ * We still configure virtual channel numbers to ensure that virtual
+ * channel 0 only goes to channel 0.
+ */
+
+ regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_VCDT0_REG,
+ SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(3, 3) |
+ SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(2, 2) |
+ SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(1, 1) |
+ SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(0, 0) |
+ SUN8I_A83T_MIPI_CSI2_VCDT0_CH_DT(0, format->data_type));
+}
+
+/* V4L2 Subdev */
+
+static int sun8i_a83t_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev =
+ v4l2_get_subdevdata(subdev);
+ struct v4l2_subdev *source_subdev = csi2_dev->bridge.source_subdev;
+ union phy_configure_opts dphy_opts = { 0 };
+ struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy;
+ struct v4l2_mbus_framefmt *mbus_format = &csi2_dev->bridge.mbus_format;
+ const struct sun8i_a83t_mipi_csi2_format *format;
+ struct phy *dphy = csi2_dev->dphy;
+ struct device *dev = csi2_dev->dev;
+ struct v4l2_ctrl *ctrl;
+ unsigned int lanes_count =
+ csi2_dev->bridge.endpoint.bus.mipi_csi2.num_data_lanes;
+ unsigned long pixel_rate;
+ int ret;
+
+ if (!source_subdev)
+ return -ENODEV;
+
+ if (!on) {
+ ret = v4l2_subdev_call(source_subdev, video, s_stream, 0);
+ goto disable;
+ }
+
+ /* Runtime PM */
+
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ return ret;
+
+ /* Sensor pixel rate */
+
+ ctrl = v4l2_ctrl_find(source_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE);
+ if (!ctrl) {
+ dev_err(dev, "missing sensor pixel rate\n");
+ ret = -ENODEV;
+ goto error_pm;
+ }
+
+ pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl);
+ if (!pixel_rate) {
+ dev_err(dev, "missing (zero) sensor pixel rate\n");
+ ret = -ENODEV;
+ goto error_pm;
+ }
+
+ /* D-PHY */
+
+ if (!lanes_count) {
+ dev_err(dev, "missing (zero) MIPI CSI-2 lanes count\n");
+ ret = -ENODEV;
+ goto error_pm;
+ }
+
+ format = sun8i_a83t_mipi_csi2_format_find(mbus_format->code);
+ if (WARN_ON(!format)) {
+ ret = -ENODEV;
+ goto error_pm;
+ }
+
+ phy_mipi_dphy_get_default_config(pixel_rate, format->bpp, lanes_count,
+ dphy_cfg);
+
+ /*
+ * Note that our hardware is using DDR, which is not taken in account by
+ * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from
+ * the pixel rate, lanes count and bpp.
+ *
+ * The resulting clock rate is basically the symbol rate over the whole
+ * link. The actual clock rate is calculated with division by two since
+ * DDR samples both on rising and falling edges.
+ */
+
+ dev_dbg(dev, "A83T MIPI CSI-2 config:\n");
+ dev_dbg(dev, "%ld pixels/s, %u bits/pixel, %u lanes, %lu Hz clock\n",
+ pixel_rate, format->bpp, lanes_count,
+ dphy_cfg->hs_clk_rate / 2);
+
+ ret = phy_reset(dphy);
+ if (ret) {
+ dev_err(dev, "failed to reset MIPI D-PHY\n");
+ goto error_pm;
+ }
+
+ ret = phy_configure(dphy, &dphy_opts);
+ if (ret) {
+ dev_err(dev, "failed to configure MIPI D-PHY\n");
+ goto error_pm;
+ }
+
+ /* Controller */
+
+ sun8i_a83t_mipi_csi2_configure(csi2_dev);
+ sun8i_a83t_mipi_csi2_enable(csi2_dev);
+
+ /* D-PHY */
+
+ ret = phy_power_on(dphy);
+ if (ret) {
+ dev_err(dev, "failed to power on MIPI D-PHY\n");
+ goto error_pm;
+ }
+
+ /* Source */
+
+ ret = v4l2_subdev_call(source_subdev, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD)
+ goto disable;
+
+ return 0;
+
+disable:
+ if (!on)
+ ret = 0;
+ phy_power_off(dphy);
+ sun8i_a83t_mipi_csi2_disable(csi2_dev);
+
+error_pm:
+ pm_runtime_put(dev);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops
+sun8i_a83t_mipi_csi2_video_ops = {
+ .s_stream = sun8i_a83t_mipi_csi2_s_stream,
+};
+
+static void
+sun8i_a83t_mipi_csi2_mbus_format_prepare(struct v4l2_mbus_framefmt *mbus_format)
+{
+ if (!sun8i_a83t_mipi_csi2_format_find(mbus_format->code))
+ mbus_format->code = sun8i_a83t_mipi_csi2_formats[0].mbus_code;
+
+ mbus_format->field = V4L2_FIELD_NONE;
+ mbus_format->colorspace = V4L2_COLORSPACE_RAW;
+ mbus_format->quantization = V4L2_QUANTIZATION_DEFAULT;
+ mbus_format->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
+static int sun8i_a83t_mipi_csi2_init_cfg(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev =
+ v4l2_get_subdevdata(subdev);
+ unsigned int pad = SUN8I_A83T_MIPI_CSI2_PAD_SINK;
+ struct v4l2_mbus_framefmt *mbus_format =
+ v4l2_subdev_get_try_format(subdev, state, pad);
+ struct mutex *lock = &csi2_dev->bridge.lock;
+
+ mutex_lock(lock);
+
+ mbus_format->code = sun8i_a83t_mipi_csi2_formats[0].mbus_code;
+ mbus_format->width = 640;
+ mbus_format->height = 480;
+
+ sun8i_a83t_mipi_csi2_mbus_format_prepare(mbus_format);
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static int
+sun8i_a83t_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code_enum)
+{
+ if (code_enum->index >= ARRAY_SIZE(sun8i_a83t_mipi_csi2_formats))
+ return -EINVAL;
+
+ code_enum->code =
+ sun8i_a83t_mipi_csi2_formats[code_enum->index].mbus_code;
+
+ return 0;
+}
+
+static int sun8i_a83t_mipi_csi2_get_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev =
+ v4l2_get_subdevdata(subdev);
+ struct v4l2_mbus_framefmt *mbus_format = &format->format;
+ struct mutex *lock = &csi2_dev->bridge.lock;
+
+ mutex_lock(lock);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ *mbus_format = *v4l2_subdev_get_try_format(subdev, state,
+ format->pad);
+ else
+ *mbus_format = csi2_dev->bridge.mbus_format;
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static int sun8i_a83t_mipi_csi2_set_fmt(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev =
+ v4l2_get_subdevdata(subdev);
+ struct v4l2_mbus_framefmt *mbus_format = &format->format;
+ struct mutex *lock = &csi2_dev->bridge.lock;
+
+ mutex_lock(lock);
+
+ sun8i_a83t_mipi_csi2_mbus_format_prepare(mbus_format);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+ *v4l2_subdev_get_try_format(subdev, state, format->pad) =
+ *mbus_format;
+ else
+ csi2_dev->bridge.mbus_format = *mbus_format;
+
+ mutex_unlock(lock);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops sun8i_a83t_mipi_csi2_pad_ops = {
+ .init_cfg = sun8i_a83t_mipi_csi2_init_cfg,
+ .enum_mbus_code = sun8i_a83t_mipi_csi2_enum_mbus_code,
+ .get_fmt = sun8i_a83t_mipi_csi2_get_fmt,
+ .set_fmt = sun8i_a83t_mipi_csi2_set_fmt,
+};
+
+static const struct v4l2_subdev_ops sun8i_a83t_mipi_csi2_subdev_ops = {
+ .video = &sun8i_a83t_mipi_csi2_video_ops,
+ .pad = &sun8i_a83t_mipi_csi2_pad_ops,
+};
+
+/* Media Entity */
+
+static const struct media_entity_operations sun8i_a83t_mipi_csi2_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+/* V4L2 Async */
+
+static int
+sun8i_a83t_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *remote_subdev,
+ struct v4l2_async_subdev *async_subdev)
+{
+ struct v4l2_subdev *subdev = notifier->sd;
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev =
+ container_of(notifier, struct sun8i_a83t_mipi_csi2_device,
+ bridge.notifier);
+ struct media_entity *sink_entity = &subdev->entity;
+ struct media_entity *source_entity = &remote_subdev->entity;
+ struct device *dev = csi2_dev->dev;
+ int sink_pad_index = 0;
+ int source_pad_index;
+ int ret;
+
+ ret = media_entity_get_fwnode_pad(source_entity, remote_subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "missing source pad in external entity %s\n",
+ source_entity->name);
+ return -EINVAL;
+ }
+
+ source_pad_index = ret;
+
+ dev_dbg(dev, "creating %s:%u -> %s:%u link\n", source_entity->name,
+ source_pad_index, sink_entity->name, sink_pad_index);
+
+ ret = media_create_pad_link(source_entity, source_pad_index,
+ sink_entity, sink_pad_index,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(dev, "failed to create %s:%u -> %s:%u link\n",
+ source_entity->name, source_pad_index,
+ sink_entity->name, sink_pad_index);
+ return ret;
+ }
+
+ csi2_dev->bridge.source_subdev = remote_subdev;
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations
+sun8i_a83t_mipi_csi2_notifier_ops = {
+ .bound = sun8i_a83t_mipi_csi2_notifier_bound,
+};
+
+/* Bridge */
+
+static int
+sun8i_a83t_mipi_csi2_bridge_source_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
+{
+ struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier;
+ struct v4l2_fwnode_endpoint *endpoint = &csi2_dev->bridge.endpoint;
+ struct v4l2_async_subdev *subdev_async;
+ struct fwnode_handle *handle;
+ struct device *dev = csi2_dev->dev;
+ int ret;
+
+ handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!handle)
+ return -ENODEV;
+
+ endpoint->bus_type = V4L2_MBUS_CSI2_DPHY;
+
+ ret = v4l2_fwnode_endpoint_parse(handle, endpoint);
+ if (ret)
+ goto complete;
+
+ subdev_async =
+ v4l2_async_nf_add_fwnode_remote(notifier, handle,
+ struct v4l2_async_subdev);
+ if (IS_ERR(subdev_async))
+ ret = PTR_ERR(subdev_async);
+
+complete:
+ fwnode_handle_put(handle);
+
+ return ret;
+}
+
+static int
+sun8i_a83t_mipi_csi2_bridge_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
+{
+ struct sun8i_a83t_mipi_csi2_bridge *bridge = &csi2_dev->bridge;
+ struct v4l2_subdev *subdev = &bridge->subdev;
+ struct v4l2_async_notifier *notifier = &bridge->notifier;
+ struct media_pad *pads = bridge->pads;
+ struct device *dev = csi2_dev->dev;
+ int ret;
+
+ mutex_init(&bridge->lock);
+
+ /* V4L2 Subdev */
+
+ v4l2_subdev_init(subdev, &sun8i_a83t_mipi_csi2_subdev_ops);
+ strscpy(subdev->name, SUN8I_A83T_MIPI_CSI2_NAME, sizeof(subdev->name));
+ subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ subdev->owner = THIS_MODULE;
+ subdev->dev = dev;
+
+ v4l2_set_subdevdata(subdev, csi2_dev);
+
+ /* Media Entity */
+
+ subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ subdev->entity.ops = &sun8i_a83t_mipi_csi2_entity_ops;
+
+ /* Media Pads */
+
+ pads[SUN8I_A83T_MIPI_CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ pads[SUN8I_A83T_MIPI_CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&subdev->entity,
+ SUN8I_A83T_MIPI_CSI2_PAD_COUNT, pads);
+ if (ret)
+ return ret;
+
+ /* V4L2 Async */
+
+ v4l2_async_nf_init(notifier);
+ notifier->ops = &sun8i_a83t_mipi_csi2_notifier_ops;
+
+ ret = sun8i_a83t_mipi_csi2_bridge_source_setup(csi2_dev);
+ if (ret)
+ goto error_v4l2_notifier_cleanup;
+
+ ret = v4l2_async_subdev_nf_register(subdev, notifier);
+ if (ret < 0)
+ goto error_v4l2_notifier_cleanup;
+
+ /* V4L2 Subdev */
+
+ ret = v4l2_async_register_subdev(subdev);
+ if (ret < 0)
+ goto error_v4l2_notifier_unregister;
+
+ return 0;
+
+error_v4l2_notifier_unregister:
+ v4l2_async_nf_unregister(notifier);
+
+error_v4l2_notifier_cleanup:
+ v4l2_async_nf_cleanup(notifier);
+
+ media_entity_cleanup(&subdev->entity);
+
+ return ret;
+}
+
+static void
+sun8i_a83t_mipi_csi2_bridge_cleanup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
+{
+ struct v4l2_subdev *subdev = &csi2_dev->bridge.subdev;
+ struct v4l2_async_notifier *notifier = &csi2_dev->bridge.notifier;
+
+ v4l2_async_unregister_subdev(subdev);
+ v4l2_async_nf_unregister(notifier);
+ v4l2_async_nf_cleanup(notifier);
+ media_entity_cleanup(&subdev->entity);
+}
+
+/* Platform */
+
+static int sun8i_a83t_mipi_csi2_suspend(struct device *dev)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(csi2_dev->clock_misc);
+ clk_disable_unprepare(csi2_dev->clock_mipi);
+ clk_disable_unprepare(csi2_dev->clock_mod);
+ reset_control_assert(csi2_dev->reset);
+
+ return 0;
+}
+
+static int sun8i_a83t_mipi_csi2_resume(struct device *dev)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = reset_control_deassert(csi2_dev->reset);
+ if (ret) {
+ dev_err(dev, "failed to deassert reset\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(csi2_dev->clock_mod);
+ if (ret) {
+ dev_err(dev, "failed to enable module clock\n");
+ goto error_reset;
+ }
+
+ ret = clk_prepare_enable(csi2_dev->clock_mipi);
+ if (ret) {
+ dev_err(dev, "failed to enable MIPI clock\n");
+ goto error_clock_mod;
+ }
+
+ ret = clk_prepare_enable(csi2_dev->clock_misc);
+ if (ret) {
+ dev_err(dev, "failed to enable CSI misc clock\n");
+ goto error_clock_mipi;
+ }
+
+ sun8i_a83t_mipi_csi2_init(csi2_dev);
+
+ return 0;
+
+error_clock_mipi:
+ clk_disable_unprepare(csi2_dev->clock_mipi);
+
+error_clock_mod:
+ clk_disable_unprepare(csi2_dev->clock_mod);
+
+error_reset:
+ reset_control_assert(csi2_dev->reset);
+
+ return ret;
+}
+
+static const struct dev_pm_ops sun8i_a83t_mipi_csi2_pm_ops = {
+ .runtime_suspend = sun8i_a83t_mipi_csi2_suspend,
+ .runtime_resume = sun8i_a83t_mipi_csi2_resume,
+};
+
+static const struct regmap_config sun8i_a83t_mipi_csi2_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x120,
+};
+
+static int
+sun8i_a83t_mipi_csi2_resources_setup(struct sun8i_a83t_mipi_csi2_device *csi2_dev,
+ struct platform_device *platform_dev)
+{
+ struct device *dev = csi2_dev->dev;
+ void __iomem *io_base;
+ int ret;
+
+ /* Registers */
+
+ io_base = devm_platform_ioremap_resource(platform_dev, 0);
+ if (IS_ERR(io_base))
+ return PTR_ERR(io_base);
+
+ csi2_dev->regmap =
+ devm_regmap_init_mmio_clk(dev, "bus", io_base,
+ &sun8i_a83t_mipi_csi2_regmap_config);
+ if (IS_ERR(csi2_dev->regmap)) {
+ dev_err(dev, "failed to init register map\n");
+ return PTR_ERR(csi2_dev->regmap);
+ }
+
+ /* Clocks */
+
+ csi2_dev->clock_mod = devm_clk_get(dev, "mod");
+ if (IS_ERR(csi2_dev->clock_mod)) {
+ dev_err(dev, "failed to acquire mod clock\n");
+ return PTR_ERR(csi2_dev->clock_mod);
+ }
+
+ ret = clk_set_rate_exclusive(csi2_dev->clock_mod, 297000000);
+ if (ret) {
+ dev_err(dev, "failed to set mod clock rate\n");
+ return ret;
+ }
+
+ csi2_dev->clock_mipi = devm_clk_get(dev, "mipi");
+ if (IS_ERR(csi2_dev->clock_mipi)) {
+ dev_err(dev, "failed to acquire mipi clock\n");
+ return PTR_ERR(csi2_dev->clock_mipi);
+ }
+
+ csi2_dev->clock_misc = devm_clk_get(dev, "misc");
+ if (IS_ERR(csi2_dev->clock_misc)) {
+ dev_err(dev, "failed to acquire misc clock\n");
+ return PTR_ERR(csi2_dev->clock_misc);
+ }
+
+ /* Reset */
+
+ csi2_dev->reset = devm_reset_control_get_shared(dev, NULL);
+ if (IS_ERR(csi2_dev->reset)) {
+ dev_err(dev, "failed to get reset controller\n");
+ return PTR_ERR(csi2_dev->reset);
+ }
+
+ /* D-PHY */
+
+ ret = sun8i_a83t_dphy_register(csi2_dev);
+ if (ret) {
+ dev_err(dev, "failed to initialize MIPI D-PHY\n");
+ return ret;
+ }
+
+ /* Runtime PM */
+
+ pm_runtime_enable(dev);
+
+ return 0;
+}
+
+static void
+sun8i_a83t_mipi_csi2_resources_cleanup(struct sun8i_a83t_mipi_csi2_device *csi2_dev)
+{
+ pm_runtime_disable(csi2_dev->dev);
+ phy_exit(csi2_dev->dphy);
+ clk_rate_exclusive_put(csi2_dev->clock_mod);
+}
+
+static int sun8i_a83t_mipi_csi2_probe(struct platform_device *platform_dev)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev;
+ struct device *dev = &platform_dev->dev;
+ int ret;
+
+ csi2_dev = devm_kzalloc(dev, sizeof(*csi2_dev), GFP_KERNEL);
+ if (!csi2_dev)
+ return -ENOMEM;
+
+ csi2_dev->dev = dev;
+ platform_set_drvdata(platform_dev, csi2_dev);
+
+ ret = sun8i_a83t_mipi_csi2_resources_setup(csi2_dev, platform_dev);
+ if (ret)
+ return ret;
+
+ ret = sun8i_a83t_mipi_csi2_bridge_setup(csi2_dev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sun8i_a83t_mipi_csi2_remove(struct platform_device *platform_dev)
+{
+ struct sun8i_a83t_mipi_csi2_device *csi2_dev =
+ platform_get_drvdata(platform_dev);
+
+ sun8i_a83t_mipi_csi2_bridge_cleanup(csi2_dev);
+ sun8i_a83t_mipi_csi2_resources_cleanup(csi2_dev);
+
+ return 0;
+}
+
+static const struct of_device_id sun8i_a83t_mipi_csi2_of_match[] = {
+ { .compatible = "allwinner,sun8i-a83t-mipi-csi2" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sun8i_a83t_mipi_csi2_of_match);
+
+static struct platform_driver sun8i_a83t_mipi_csi2_platform_driver = {
+ .probe = sun8i_a83t_mipi_csi2_probe,
+ .remove = sun8i_a83t_mipi_csi2_remove,
+ .driver = {
+ .name = SUN8I_A83T_MIPI_CSI2_NAME,
+ .of_match_table = of_match_ptr(sun8i_a83t_mipi_csi2_of_match),
+ .pm = &sun8i_a83t_mipi_csi2_pm_ops,
+ },
+};
+module_platform_driver(sun8i_a83t_mipi_csi2_platform_driver);
+
+MODULE_DESCRIPTION("Allwinner A83T MIPI CSI-2 and D-PHY Controller Driver");
+MODULE_AUTHOR("Paul Kocialkowski <paul.kocialkowski@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h
new file mode 100644
index 000000000000..f1e64c53434c
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com>
+ * Copyright 2020-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN8I_A83T_MIPI_CSI2_H_
+#define _SUN8I_A83T_MIPI_CSI2_H_
+
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
+
+#define SUN8I_A83T_MIPI_CSI2_NAME "sun8i-a83t-mipi-csi2"
+
+enum sun8i_a83t_mipi_csi2_pad {
+ SUN8I_A83T_MIPI_CSI2_PAD_SINK = 0,
+ SUN8I_A83T_MIPI_CSI2_PAD_SOURCE = 1,
+ SUN8I_A83T_MIPI_CSI2_PAD_COUNT = 2,
+};
+
+struct sun8i_a83t_mipi_csi2_format {
+ u32 mbus_code;
+ u8 data_type;
+ u32 bpp;
+};
+
+struct sun8i_a83t_mipi_csi2_bridge {
+ struct v4l2_subdev subdev;
+ struct media_pad pads[SUN8I_A83T_MIPI_CSI2_PAD_COUNT];
+ struct v4l2_fwnode_endpoint endpoint;
+ struct v4l2_async_notifier notifier;
+ struct v4l2_mbus_framefmt mbus_format;
+ struct mutex lock; /* Mbus format lock. */
+
+ struct v4l2_subdev *source_subdev;
+};
+
+struct sun8i_a83t_mipi_csi2_device {
+ struct device *dev;
+
+ struct regmap *regmap;
+ struct clk *clock_mod;
+ struct clk *clock_mipi;
+ struct clk *clock_misc;
+ struct reset_control *reset;
+ struct phy *dphy;
+
+ struct sun8i_a83t_mipi_csi2_bridge bridge;
+};
+
+#endif
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h
new file mode 100644
index 000000000000..2cfc9eb490e6
--- /dev/null
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2020 Kévin L'hôpital <kevin.lhopital@bootlin.com>
+ * Copyright 2020-2022 Bootlin
+ * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+ */
+
+#ifndef _SUN8I_A83T_MIPI_CSI2_REG_H_
+#define _SUN8I_A83T_MIPI_CSI2_REG_H_
+
+#define SUN8I_A83T_MIPI_CSI2_VERSION_REG 0x0
+#define SUN8I_A83T_MIPI_CSI2_CTRL_REG 0x4
+#define SUN8I_A83T_MIPI_CSI2_CTRL_INIT_VALUE 0xb8c39bec
+#define SUN8I_A83T_MIPI_CSI2_CTRL_RESET_N BIT(31)
+#define SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG 0x8
+#define SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_INIT_VALUE 0xb8d257f8
+#define SUN8I_A83T_MIPI_CSI2_RSVD0_REG 0xc
+
+#define SUN8I_A83T_MIPI_CSI2_RSVD1_REG 0x18
+#define SUN8I_A83T_MIPI_CSI2_RSVD1_HW_LOCK_VALUE 0xb8c8a30c
+#define SUN8I_A83T_MIPI_CSI2_RSVD2_REG 0x1c
+#define SUN8I_A83T_MIPI_CSI2_RSVD2_HW_LOCK_VALUE 0xb8df8ad7
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_REG 0x20
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_ECC_ERR_DBL BIT(28)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC3 BIT(27)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC2 BIT(26)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC1 BIT(25)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC0 BIT(24)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT3 BIT(23)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT2 BIT(22)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT1 BIT(21)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT0 BIT(20)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT3 BIT(19)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT2 BIT(18)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT1 BIT(17)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT0 BIT(16)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC3 BIT(15)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC2 BIT(14)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC1 BIT(13)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC0 BIT(12)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC3 BIT(11)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC2 BIT(10)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC1 BIT(9)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC0 BIT(8)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC3 BIT(7)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC2 BIT(6)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC1 BIT(5)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC0 BIT(4)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_3 BIT(3)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_2 BIT(2)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_1 BIT(1)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_0 BIT(0)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_REG 0x24
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT7 BIT(23)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT6 BIT(22)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT5 BIT(21)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT4 BIT(20)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT7 BIT(19)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT6 BIT(18)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT5 BIT(17)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT4 BIT(16)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC3 BIT(15)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC2 BIT(14)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC1 BIT(13)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC0 BIT(12)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC3 BIT(11)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC2 BIT(10)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC1 BIT(9)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC0 BIT(8)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_3 BIT(7)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_2 BIT(6)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_1 BIT(5)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_0 BIT(4)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_3 BIT(3)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_2 BIT(2)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_1 BIT(1)
+#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_0 BIT(0)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_REG 0x28
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_ECC_ERR_DBL BIT(28)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC3 BIT(27)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC2 BIT(26)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC1 BIT(25)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC0 BIT(24)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT3 BIT(23)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT2 BIT(22)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT1 BIT(21)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT0 BIT(20)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT3 BIT(19)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT2 BIT(18)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT1 BIT(17)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT0 BIT(16)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC3 BIT(15)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC2 BIT(14)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC1 BIT(13)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC0 BIT(12)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC3 BIT(11)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC2 BIT(10)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC1 BIT(9)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC0 BIT(8)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC3 BIT(7)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC2 BIT(6)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC1 BIT(5)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC0 BIT(4)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_3 BIT(3)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_2 BIT(2)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_1 BIT(1)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_0 BIT(0)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_REG 0x2c
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC3 BIT(15)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC2 BIT(14)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC1 BIT(13)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC0 BIT(12)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC3 BIT(11)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC2 BIT(10)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC1 BIT(9)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC0 BIT(8)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_3 BIT(7)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_2 BIT(6)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_1 BIT(5)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_0 BIT(4)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_3 BIT(3)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_2 BIT(2)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_1 BIT(1)
+#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_0 BIT(0)
+
+#define SUN8I_A83T_MIPI_CSI2_CFG_REG 0x100
+#define SUN8I_A83T_MIPI_CSI2_CFG_INIT_VALUE 0xb8c64f24
+#define SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN BIT(31)
+#define SUN8I_A83T_MIPI_CSI2_CFG_BYPASS_ECC_EN BIT(29)
+#define SUN8I_A83T_MIPI_CSI2_CFG_UNPKT_EN BIT(28)
+#define SUN8I_A83T_MIPI_CSI2_CFG_NONE_UNPKT_RX_MODE BIT(27)
+#define SUN8I_A83T_MIPI_CSI2_CFG_YC_SWAB BIT(26)
+#define SUN8I_A83T_MIPI_CSI2_CFG_N_BYTE BIT(24)
+#define SUN8I_A83T_MIPI_CSI2_CFG_SYNC_DLY_CYCLE(v) (((v) << 18) & \
+ GENMASK(22, 18))
+#define SUN8I_A83T_MIPI_CSI2_CFG_N_CHANNEL(v) ((((v) - 1) << 16) & \
+ GENMASK(17, 16))
+#define SUN8I_A83T_MIPI_CSI2_CFG_N_LANE(v) ((((v) - 1) << 4) & \
+ GENMASK(5, 4))
+#define SUN8I_A83T_MIPI_CSI2_VCDT0_REG 0x104
+#define SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \
+ ((ch) * 8 + 6))
+#define SUN8I_A83T_MIPI_CSI2_VCDT0_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \
+ ((ch) * 8))
+#define SUN8I_A83T_MIPI_CSI2_VCDT1_REG 0x108
+#define SUN8I_A83T_MIPI_CSI2_VCDT1_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \
+ (((ch) - 4) * 8 + 6))
+#define SUN8I_A83T_MIPI_CSI2_VCDT1_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \
+ (((ch) - 4) * 8))
+
+#endif
diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c
index e69fed117fea..e136d70b4048 100644
--- a/drivers/media/platform/ti/cal/cal-camerarx.c
+++ b/drivers/media/platform/ti/cal/cal-camerarx.c
@@ -305,7 +305,7 @@ static int cal_camerarx_start(struct cal_camerarx *phy)
/*
* CSI-2 PHY Link Initialization Sequence, according to the DRA74xP /
* DRA75xP / DRA76xP / DRA77xP TRM. The DRA71x / DRA72x and the AM65x /
- * DRA80xM TRMs have a a slightly simplified sequence.
+ * DRA80xM TRMs have a slightly simplified sequence.
*/
/*
@@ -592,7 +592,7 @@ int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy,
if (!phy->source)
return -EPIPE;
- pad = media_entity_remote_pad(&phy->pads[CAL_CAMERARX_PAD_SINK]);
+ pad = media_pad_remote_pad_first(&phy->pads[CAL_CAMERARX_PAD_SINK]);
if (!pad)
return -EPIPE;
diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c
index 07ae1a34e6b0..776da0cfcdbe 100644
--- a/drivers/media/platform/ti/cal/cal-video.c
+++ b/drivers/media/platform/ti/cal/cal-video.c
@@ -685,7 +685,7 @@ static int cal_video_check_format(struct cal_ctx *ctx)
const struct v4l2_mbus_framefmt *format;
struct media_pad *remote_pad;
- remote_pad = media_entity_remote_pad(&ctx->pad);
+ remote_pad = media_pad_remote_pad_first(&ctx->pad);
if (!remote_pad)
return -ENODEV;
diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c
index 97ef770266af..da27da4c165a 100644
--- a/drivers/media/platform/ti/davinci/vpif.c
+++ b/drivers/media/platform/ti/davinci/vpif.c
@@ -469,6 +469,7 @@ static int vpif_probe(struct platform_device *pdev)
endpoint);
if (!endpoint)
return 0;
+ of_node_put(endpoint);
/*
* For DT platforms, manually create platform_devices for
diff --git a/drivers/media/platform/ti/davinci/vpif.h b/drivers/media/platform/ti/davinci/vpif.h
index c6d1d890478a..651943e3e375 100644
--- a/drivers/media/platform/ti/davinci/vpif.h
+++ b/drivers/media/platform/ti/davinci/vpif.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* VPIF header file
*
* Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * 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 VPIF_H
@@ -685,4 +677,3 @@ struct vpif_params {
};
#endif /* End of #ifndef VPIF_H */
-
diff --git a/drivers/media/platform/ti/davinci/vpif_display.h b/drivers/media/platform/ti/davinci/vpif_display.h
index f98062e79167..f27474e0fc36 100644
--- a/drivers/media/platform/ti/davinci/vpif_display.h
+++ b/drivers/media/platform/ti/davinci/vpif_display.h
@@ -1,16 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* VPIF display header file
*
* Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * 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 VPIF_DISPLAY_H
diff --git a/drivers/media/platform/ti/omap/omap_voutlib.c b/drivers/media/platform/ti/omap/omap_voutlib.c
index 480a7e95533d..fdea2309ee37 100644
--- a/drivers/media/platform/ti/omap/omap_voutlib.c
+++ b/drivers/media/platform/ti/omap/omap_voutlib.c
@@ -314,7 +314,7 @@ unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
if (virt_addr) {
while (size > 0) {
- SetPageReserved(virt_to_page(addr));
+ SetPageReserved(virt_to_page((void *)addr));
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
@@ -335,7 +335,7 @@ void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size)
order = get_order(size);
while (size > 0) {
- ClearPageReserved(virt_to_page(addr));
+ ClearPageReserved(virt_to_page((void *)addr));
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c
index 4c937f3f323e..d251736eb420 100644
--- a/drivers/media/platform/ti/omap3isp/isp.c
+++ b/drivers/media/platform/ti/omap3isp/isp.c
@@ -700,7 +700,7 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
@@ -797,7 +797,7 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
@@ -942,7 +942,7 @@ static int isp_pipeline_is_last(struct media_entity *me)
pipe = to_isp_pipeline(me);
if (pipe->stream_state == ISP_PIPELINE_STREAM_STOPPED)
return 0;
- pad = media_entity_remote_pad(&pipe->output->pad);
+ pad = media_pad_remote_pad_first(&pipe->output->pad);
return pad->entity == me;
}
diff --git a/drivers/media/platform/ti/omap3isp/ispccdc.c b/drivers/media/platform/ti/omap3isp/ispccdc.c
index 108b5e9f82cb..11afb8aec292 100644
--- a/drivers/media/platform/ti/omap3isp/ispccdc.c
+++ b/drivers/media/platform/ti/omap3isp/ispccdc.c
@@ -1133,7 +1133,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
ccdc->bt656 = false;
ccdc->fields = 0;
- pad = media_entity_remote_pad(&ccdc->pads[CCDC_PAD_SINK]);
+ pad = media_pad_remote_pad_first(&ccdc->pads[CCDC_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
if (ccdc->input == CCDC_INPUT_PARALLEL) {
struct v4l2_subdev *sd =
diff --git a/drivers/media/platform/ti/omap3isp/ispccp2.c b/drivers/media/platform/ti/omap3isp/ispccp2.c
index acb58b6ddba1..fc90ff88464f 100644
--- a/drivers/media/platform/ti/omap3isp/ispccp2.c
+++ b/drivers/media/platform/ti/omap3isp/ispccp2.c
@@ -357,7 +357,7 @@ static int ccp2_if_configure(struct isp_ccp2_device *ccp2)
ccp2_pwr_cfg(ccp2);
- pad = media_entity_remote_pad(&ccp2->pads[CCP2_PAD_SINK]);
+ pad = media_pad_remote_pad_first(&ccp2->pads[CCP2_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
buscfg = v4l2_subdev_to_bus_cfg(pipe->external);
diff --git a/drivers/media/platform/ti/omap3isp/ispcsi2.c b/drivers/media/platform/ti/omap3isp/ispcsi2.c
index 6302e0c94034..6870980a2fa9 100644
--- a/drivers/media/platform/ti/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/ti/omap3isp/ispcsi2.c
@@ -561,7 +561,7 @@ static int csi2_configure(struct isp_csi2_device *csi2)
if (csi2->contexts[0].enabled || csi2->ctrl.if_enable)
return -EBUSY;
- pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]);
+ pad = media_pad_remote_pad_first(&csi2->pads[CSI2_PAD_SINK]);
sensor = media_entity_to_v4l2_subdev(pad->entity);
buscfg = v4l2_subdev_to_bus_cfg(pipe->external);
diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c
index 8811d6dd4ee7..d7059180e80e 100644
--- a/drivers/media/platform/ti/omap3isp/ispvideo.c
+++ b/drivers/media/platform/ti/omap3isp/ispvideo.c
@@ -206,7 +206,7 @@ isp_video_remote_subdev(struct isp_video *video, u32 *pad)
{
struct media_pad *remote;
- remote = media_entity_remote_pad(&video->pad);
+ remote = media_pad_remote_pad_first(&video->pad);
if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
@@ -981,7 +981,7 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
continue;
/* ISP entities have always sink pad == 0. Find source. */
- source_pad = media_entity_remote_pad(&ents[i]->pads[0]);
+ source_pad = media_pad_remote_pad_first(&ents[i]->pads[0]);
if (source_pad == NULL)
continue;
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index b31e5913a4cd..71d97042a470 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -118,7 +118,7 @@ static int video_mux_s_stream(struct v4l2_subdev *sd, int enable)
return -EINVAL;
}
- pad = media_entity_remote_pad(&sd->entity.pads[vmux->active]);
+ pad = media_pad_remote_pad_first(&sd->entity.pads[vmux->active]);
if (!pad) {
dev_err(sd->dev, "Failed to find remote source pad\n");
return -ENOLINK;
diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
index 051c60cba1e0..cf8e892c47f0 100644
--- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c
+++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
@@ -474,7 +474,7 @@ static struct v4l2_subdev *xcsi2rxss_get_remote_subdev(struct media_pad *local)
{
struct media_pad *remote;
- remote = media_entity_remote_pad(local);
+ remote = media_pad_remote_pad_first(local);
if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index 338c3661d809..2d1ef7a25c33 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -44,7 +44,7 @@ xvip_dma_remote_subdev(struct media_pad *local, u32 *pad)
{
struct media_pad *remote;
- remote = media_entity_remote_pad(local);
+ remote = media_pad_remote_pad_first(local);
if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
return NULL;
@@ -107,7 +107,7 @@ static int xvip_pipeline_start_stop(struct xvip_pipeline *pipe, bool start)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
- pad = media_entity_remote_pad(pad);
+ pad = media_pad_remote_pad_first(pad);
if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
break;
diff --git a/drivers/media/platform/xilinx/xilinx-vip.h b/drivers/media/platform/xilinx/xilinx-vip.h
index d0b0e0600952..48fe229c5b33 100644
--- a/drivers/media/platform/xilinx/xilinx-vip.h
+++ b/drivers/media/platform/xilinx/xilinx-vip.h
@@ -28,8 +28,8 @@ struct clk;
#define XVIP_MAX_HEIGHT 7680
/*
- * Pad IDs. IP cores with with multiple inputs or outputs should define
- * their own values.
+ * Pad IDs. IP cores with multiple inputs or outputs should define their own
+ * values.
*/
#define XVIP_PAD_SINK 0
#define XVIP_PAD_SOURCE 1
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 3155e876616d..fff4dd48eaca 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -135,8 +135,6 @@ MODULE_PARM_DESC(mouse, "Enable mouse device, default = yes");
#define dbginfo(dev, format, arg...) \
do { if (debug) dev_info(dev , format , ## arg); } while (0)
-#undef err
-#define err(format, arg...) printk(KERN_ERR format , ## arg)
struct ati_receiver_type {
/* either default_keymap or get_default_keymap should be set */
@@ -816,11 +814,12 @@ static int ati_remote_probe(struct usb_interface *interface,
struct ati_receiver_type *type = (struct ati_receiver_type *)id->driver_info;
struct ati_remote *ati_remote;
struct input_dev *input_dev;
+ struct device *device = &interface->dev;
struct rc_dev *rc_dev;
int err = -ENOMEM;
if (iface_host->desc.bNumEndpoints != 2) {
- err("%s: Unexpected desc.bNumEndpoints\n", __func__);
+ dev_err(device, "%s: Unexpected desc.bNumEndpoints\n", __func__);
return -ENODEV;
}
@@ -828,15 +827,15 @@ static int ati_remote_probe(struct usb_interface *interface,
endpoint_out = &iface_host->endpoint[1].desc;
if (!usb_endpoint_is_int_in(endpoint_in)) {
- err("%s: Unexpected endpoint_in\n", __func__);
+ dev_err(device, "%s: Unexpected endpoint_in\n", __func__);
return -ENODEV;
}
if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
- err("%s: endpoint_in message size==0? \n", __func__);
+ dev_err(device, "%s: endpoint_in message size==0?\n", __func__);
return -ENODEV;
}
if (!usb_endpoint_is_int_out(endpoint_out)) {
- err("%s: Unexpected endpoint_out\n", __func__);
+ dev_err(device, "%s: Unexpected endpoint_out\n", __func__);
return -ENODEV;
}
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c
index b40dbf500186..1464ef9c55bc 100644
--- a/drivers/media/rc/igorplugusb.c
+++ b/drivers/media/rc/igorplugusb.c
@@ -38,7 +38,7 @@ struct igorplugusb {
struct timer_list timer;
- uint8_t buf_in[MAX_PACKET];
+ u8 *buf_in;
char phys[64];
};
@@ -110,7 +110,6 @@ static void igorplugusb_callback(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- usb_unlink_urb(urb);
return;
default:
dev_warn(ir->dev, "Error: urb status = %d\n", urb->status);
@@ -126,7 +125,7 @@ static void igorplugusb_cmd(struct igorplugusb *ir, int cmd)
ir->request.bRequest = cmd;
ir->urb->transfer_flags = 0;
ret = usb_submit_urb(ir->urb, GFP_ATOMIC);
- if (ret)
+ if (ret && ret != -EPERM)
dev_err(ir->dev, "submit urb failed: %d", ret);
}
@@ -171,15 +170,18 @@ static int igorplugusb_probe(struct usb_interface *intf,
ir->request.bRequest = GET_INFRACODE;
ir->request.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
- ir->request.wLength = cpu_to_le16(sizeof(ir->buf_in));
+ ir->request.wLength = cpu_to_le16(MAX_PACKET);
ir->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!ir->urb)
goto fail;
+ ir->buf_in = kmalloc(MAX_PACKET, GFP_KERNEL);
+ if (!ir->buf_in)
+ goto fail;
usb_fill_control_urb(ir->urb, udev,
usb_rcvctrlpipe(udev, 0), (uint8_t *)&ir->request,
- ir->buf_in, sizeof(ir->buf_in), igorplugusb_callback, ir);
+ ir->buf_in, MAX_PACKET, igorplugusb_callback, ir);
usb_make_path(udev, ir->phys, sizeof(ir->phys));
@@ -220,9 +222,12 @@ static int igorplugusb_probe(struct usb_interface *intf,
return 0;
fail:
- rc_free_device(ir->rc);
- usb_free_urb(ir->urb);
+ usb_poison_urb(ir->urb);
del_timer(&ir->timer);
+ usb_unpoison_urb(ir->urb);
+ usb_free_urb(ir->urb);
+ rc_free_device(ir->rc);
+ kfree(ir->buf_in);
return ret;
}
@@ -232,10 +237,12 @@ static void igorplugusb_disconnect(struct usb_interface *intf)
struct igorplugusb *ir = usb_get_intfdata(intf);
rc_unregister_device(ir->rc);
+ usb_poison_urb(ir->urb);
del_timer_sync(&ir->timer);
usb_set_intfdata(intf, NULL);
- usb_kill_urb(ir->urb);
+ usb_unpoison_urb(ir->urb);
usb_free_urb(ir->urb);
+ kfree(ir->buf_in);
}
static const struct usb_device_id igorplugusb_table[] = {
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index c9cb8277723f..276bf3c8a8cb 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -149,10 +149,8 @@ static void iguanair_rx(struct urb *urb)
return;
ir = urb->context;
- if (!ir) {
- usb_unlink_urb(urb);
+ if (!ir)
return;
- }
switch (urb->status) {
case 0:
@@ -161,7 +159,6 @@ static void iguanair_rx(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- usb_unlink_urb(urb);
return;
case -EPIPE:
default:
diff --git a/drivers/media/rc/imon_raw.c b/drivers/media/rc/imon_raw.c
index d41580f6e4c7..b02ded52f19e 100644
--- a/drivers/media/rc/imon_raw.c
+++ b/drivers/media/rc/imon_raw.c
@@ -14,7 +14,7 @@ struct imon {
struct device *dev;
struct urb *ir_urb;
struct rc_dev *rcdev;
- __be64 ir_buf;
+ __be64 *ir_buf;
char phys[64];
};
@@ -29,7 +29,7 @@ struct imon {
static void imon_ir_data(struct imon *imon)
{
struct ir_raw_event rawir = {};
- u64 data = be64_to_cpu(imon->ir_buf);
+ u64 data = be64_to_cpup(imon->ir_buf);
u8 packet_no = data & 0xff;
int offset = 40;
int bit;
@@ -37,7 +37,7 @@ static void imon_ir_data(struct imon *imon)
if (packet_no == 0xff)
return;
- dev_dbg(imon->dev, "data: %*ph", 8, &imon->ir_buf);
+ dev_dbg(imon->dev, "data: %*ph", 8, imon->ir_buf);
/*
* Only the first 5 bytes contain IR data. Right shift so we move
@@ -137,10 +137,16 @@ static int imon_probe(struct usb_interface *intf,
if (!imon->ir_urb)
return -ENOMEM;
+ imon->ir_buf = kmalloc(sizeof(__be64), GFP_KERNEL);
+ if (!imon->ir_buf) {
+ ret = -ENOMEM;
+ goto free_urb;
+ }
+
imon->dev = &intf->dev;
usb_fill_int_urb(imon->ir_urb, udev,
usb_rcvintpipe(udev, ir_ep->bEndpointAddress),
- &imon->ir_buf, sizeof(imon->ir_buf),
+ imon->ir_buf, sizeof(__be64),
imon_ir_rx, imon, ir_ep->bInterval);
rcdev = devm_rc_allocate_device(&intf->dev, RC_DRIVER_IR_RAW);
@@ -177,6 +183,7 @@ static int imon_probe(struct usb_interface *intf,
free_urb:
usb_free_urb(imon->ir_urb);
+ kfree(imon->ir_buf);
return ret;
}
@@ -186,6 +193,7 @@ static void imon_disconnect(struct usb_interface *intf)
usb_kill_urb(imon->ir_urb);
usb_free_urb(imon->ir_urb);
+ kfree(imon->ir_buf);
}
static const struct usb_device_id imon_table[] = {
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 765375bda0c6..25ab61dae126 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -715,7 +715,7 @@ int lirc_register(struct rc_dev *dev)
const char *rx_type, *tx_type;
int err, minor;
- minor = ida_simple_get(&lirc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
+ minor = ida_alloc_max(&lirc_ida, RC_DEV_MAX - 1, GFP_KERNEL);
if (minor < 0)
return minor;
@@ -760,7 +760,7 @@ int lirc_register(struct rc_dev *dev)
return 0;
out_ida:
- ida_simple_remove(&lirc_ida, minor);
+ ida_free(&lirc_ida, minor);
return err;
}
@@ -778,7 +778,7 @@ void lirc_unregister(struct rc_dev *dev)
spin_unlock_irqrestore(&dev->lirc_fh_lock, flags);
cdev_device_del(&dev->lirc_cdev, &dev->lirc_dev);
- ida_simple_remove(&lirc_ida, MINOR(dev->lirc_dev.devt));
+ ida_free(&lirc_ida, MINOR(dev->lirc_dev.devt));
}
int __init lirc_dev_init(void)
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index b90438a71c80..eba0cd30e314 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -786,7 +786,8 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
dev->last_toggle != toggle);
struct lirc_scancode sc = {
.scancode = scancode, .rc_proto = protocol,
- .flags = toggle ? LIRC_SCANCODE_FLAG_TOGGLE : 0,
+ .flags = (toggle ? LIRC_SCANCODE_FLAG_TOGGLE : 0) |
+ (!new_event ? LIRC_SCANCODE_FLAG_REPEAT : 0),
.keycode = keycode
};
@@ -1897,7 +1898,7 @@ int rc_register_device(struct rc_dev *dev)
if (!dev)
return -EINVAL;
- minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL);
+ minor = ida_alloc_max(&rc_ida, RC_DEV_MAX - 1, GFP_KERNEL);
if (minor < 0)
return minor;
@@ -1980,7 +1981,7 @@ out_rx_free:
out_raw:
ir_raw_event_free(dev);
out_minor:
- ida_simple_remove(&rc_ida, minor);
+ ida_free(&rc_ida, minor);
return rc;
}
EXPORT_SYMBOL_GPL(rc_register_device);
@@ -2040,7 +2041,7 @@ void rc_unregister_device(struct rc_dev *dev)
device_del(&dev->dev);
- ida_simple_remove(&rc_ida, dev->minor);
+ ida_free(&rc_ida, dev->minor);
if (!dev->managed_alloc)
rc_free_device(dev);
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index cb22316b3f00..9f2947af33aa 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -1155,9 +1155,9 @@ static int redrat3_dev_resume(struct usb_interface *intf)
{
struct redrat3_dev *rr3 = usb_get_intfdata(intf);
- if (usb_submit_urb(rr3->narrow_urb, GFP_ATOMIC))
+ if (usb_submit_urb(rr3->narrow_urb, GFP_NOIO))
return -EIO;
- if (usb_submit_urb(rr3->wide_urb, GFP_ATOMIC))
+ if (usb_submit_urb(rr3->wide_urb, GFP_NOIO))
return -EIO;
led_classdev_resume(&rr3->led);
return 0;
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index deb85330c940..9b209e687f25 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -406,7 +406,7 @@ static int streamzap_resume(struct usb_interface *intf)
{
struct streamzap_ir *sz = usb_get_intfdata(intf);
- if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
+ if (usb_submit_urb(sz->urb_in, GFP_NOIO)) {
dev_err(sz->dev, "Error submitting urb\n");
return -EIO;
}
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index 629787d53ee1..560a26f3965c 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -90,7 +90,6 @@ static void ttusbir_bulk_complete(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- usb_unlink_urb(urb);
return;
case -EPIPE:
default:
@@ -166,7 +165,6 @@ static void ttusbir_urb_complete(struct urb *urb)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- usb_unlink_urb(urb);
return;
case -EPIPE:
default:
@@ -402,7 +400,7 @@ static int ttusbir_resume(struct usb_interface *intf)
led_classdev_resume(&tt->led);
for (i = 0; i < NUM_URBS; i++) {
- rc = usb_submit_urb(tt->urb[i], GFP_KERNEL);
+ rc = usb_submit_urb(tt->urb[i], GFP_NOIO);
if (rc) {
dev_warn(tt->dev, "failed to submit urb: %d\n", rc);
break;
diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c
index 7424b2031152..a1572381d097 100644
--- a/drivers/media/rc/xbox_remote.c
+++ b/drivers/media/rc/xbox_remote.c
@@ -163,8 +163,8 @@ static void xbox_remote_rc_init(struct xbox_remote *xbox_remote)
rdev->dev.parent = &xbox_remote->interface->dev;
}
-static int xbox_remote_initialize(struct xbox_remote *xbox_remote,
- struct usb_endpoint_descriptor *endpoint_in)
+static void xbox_remote_initialize(struct xbox_remote *xbox_remote,
+ struct usb_endpoint_descriptor *endpoint_in)
{
struct usb_device *udev = xbox_remote->udev;
int pipe, maxp;
@@ -177,8 +177,6 @@ static int xbox_remote_initialize(struct xbox_remote *xbox_remote,
usb_fill_int_urb(xbox_remote->irq_urb, udev, pipe, xbox_remote->inbuf,
maxp, xbox_remote_irq_in, xbox_remote,
endpoint_in->bInterval);
-
- return 0;
}
/*
@@ -249,9 +247,7 @@ static int xbox_remote_probe(struct usb_interface *interface,
xbox_remote_rc_init(xbox_remote);
/* Device Hardware Initialization */
- err = xbox_remote_initialize(xbox_remote, endpoint_in);
- if (err)
- goto exit_kill_urbs;
+ xbox_remote_initialize(xbox_remote, endpoint_in);
/* Set up and register rc device */
err = rc_register_device(xbox_remote->rdev);
diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c
index be43f7d32df9..1d1bee111732 100644
--- a/drivers/media/test-drivers/vicodec/vicodec-core.c
+++ b/drivers/media/test-drivers/vicodec/vicodec-core.c
@@ -280,17 +280,13 @@ static int device_process(struct vicodec_ctx *ctx,
*/
if (!(ntohl(ctx->state.header.flags) & V4L2_FWHT_FL_I_FRAME)) {
struct vb2_buffer *ref_vb2_buf;
- int ref_buf_idx;
struct vb2_queue *vq_cap =
v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
V4L2_BUF_TYPE_VIDEO_CAPTURE);
- ref_buf_idx = vb2_find_timestamp(vq_cap,
- ctx->state.ref_frame_ts, 0);
- if (ref_buf_idx < 0)
+ ref_vb2_buf = vb2_find_buffer(vq_cap, ctx->state.ref_frame_ts);
+ if (!ref_vb2_buf)
return -EINVAL;
-
- ref_vb2_buf = vq_cap->bufs[ref_buf_idx];
if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR)
ret = -EINVAL;
ctx->state.ref_frame.buf =
diff --git a/drivers/media/test-drivers/vimc/Makefile b/drivers/media/test-drivers/vimc/Makefile
index a53b2b532e9f..9b9631562473 100644
--- a/drivers/media/test-drivers/vimc/Makefile
+++ b/drivers/media/test-drivers/vimc/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
vimc-y := vimc-core.o vimc-common.o vimc-streamer.o vimc-capture.o \
- vimc-debayer.o vimc-scaler.o vimc-sensor.o
+ vimc-debayer.o vimc-scaler.o vimc-sensor.o vimc-lens.o
obj-$(CONFIG_VIDEO_VIMC) += vimc.o
diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c
index d1e2d0739c00..6c437802f91f 100644
--- a/drivers/media/test-drivers/vimc/vimc-capture.c
+++ b/drivers/media/test-drivers/vimc/vimc-capture.c
@@ -13,7 +13,7 @@
#include "vimc-common.h"
#include "vimc-streamer.h"
-struct vimc_cap_device {
+struct vimc_capture_device {
struct vimc_ent_device ved;
struct video_device vdev;
struct v4l2_pix_format format;
@@ -41,7 +41,7 @@ static const struct v4l2_pix_format fmt_default = {
.colorspace = V4L2_COLORSPACE_SRGB,
};
-struct vimc_cap_buffer {
+struct vimc_capture_buffer {
/*
* struct vb2_v4l2_buffer must be the first element
* the videobuf2 framework will allocate this struct based on
@@ -52,7 +52,7 @@ struct vimc_cap_buffer {
struct list_head list;
};
-static int vimc_cap_querycap(struct file *file, void *priv,
+static int vimc_capture_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
strscpy(cap->driver, VIMC_PDEV_NAME, sizeof(cap->driver));
@@ -63,26 +63,26 @@ static int vimc_cap_querycap(struct file *file, void *priv,
return 0;
}
-static void vimc_cap_get_format(struct vimc_ent_device *ved,
+static void vimc_capture_get_format(struct vimc_ent_device *ved,
struct v4l2_pix_format *fmt)
{
- struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device,
+ struct vimc_capture_device *vcapture = container_of(ved, struct vimc_capture_device,
ved);
- *fmt = vcap->format;
+ *fmt = vcapture->format;
}
-static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv,
+static int vimc_capture_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct vimc_cap_device *vcap = video_drvdata(file);
+ struct vimc_capture_device *vcapture = video_drvdata(file);
- f->fmt.pix = vcap->format;
+ f->fmt.pix = vcapture->format;
return 0;
}
-static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv,
+static int vimc_capture_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct v4l2_pix_format *format = &f->fmt.pix;
@@ -114,40 +114,40 @@ static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv,
+static int vimc_capture_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct vimc_cap_device *vcap = video_drvdata(file);
+ struct vimc_capture_device *vcapture = video_drvdata(file);
int ret;
/* Do not change the format while stream is on */
- if (vb2_is_busy(&vcap->queue))
+ if (vb2_is_busy(&vcapture->queue))
return -EBUSY;
- ret = vimc_cap_try_fmt_vid_cap(file, priv, f);
+ ret = vimc_capture_try_fmt_vid_cap(file, priv, f);
if (ret)
return ret;
- dev_dbg(vcap->ved.dev, "%s: format update: "
+ dev_dbg(vcapture->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,
+ "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcapture->vdev.name,
/* old */
- vcap->format.width, vcap->format.height,
- vcap->format.pixelformat, vcap->format.colorspace,
- vcap->format.quantization, vcap->format.xfer_func,
- vcap->format.ycbcr_enc,
+ vcapture->format.width, vcapture->format.height,
+ vcapture->format.pixelformat, vcapture->format.colorspace,
+ vcapture->format.quantization, vcapture->format.xfer_func,
+ vcapture->format.ycbcr_enc,
/* new */
f->fmt.pix.width, f->fmt.pix.height,
f->fmt.pix.pixelformat, f->fmt.pix.colorspace,
f->fmt.pix.quantization, f->fmt.pix.xfer_func,
f->fmt.pix.ycbcr_enc);
- vcap->format = f->fmt.pix;
+ vcapture->format = f->fmt.pix;
return 0;
}
-static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv,
+static int vimc_capture_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
const struct vimc_pix_map *vpix;
@@ -169,7 +169,7 @@ static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int vimc_cap_enum_framesizes(struct file *file, void *fh,
+static int vimc_capture_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
const struct vimc_pix_map *vpix;
@@ -193,7 +193,7 @@ static int vimc_cap_enum_framesizes(struct file *file, void *fh,
return 0;
}
-static const struct v4l2_file_operations vimc_cap_fops = {
+static const struct v4l2_file_operations vimc_capture_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
.release = vb2_fop_release,
@@ -203,14 +203,14 @@ static const struct v4l2_file_operations vimc_cap_fops = {
.mmap = vb2_fop_mmap,
};
-static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = {
- .vidioc_querycap = vimc_cap_querycap,
+static const struct v4l2_ioctl_ops vimc_capture_ioctl_ops = {
+ .vidioc_querycap = vimc_capture_querycap,
- .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap,
- .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap,
- .vidioc_enum_framesizes = vimc_cap_enum_framesizes,
+ .vidioc_g_fmt_vid_cap = vimc_capture_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vimc_capture_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vimc_capture_try_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_cap = vimc_capture_enum_fmt_vid_cap,
+ .vidioc_enum_framesizes = vimc_capture_enum_framesizes,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
@@ -223,40 +223,40 @@ static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = {
.vidioc_streamoff = vb2_ioctl_streamoff,
};
-static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap,
+static void vimc_capture_return_all_buffers(struct vimc_capture_device *vcapture,
enum vb2_buffer_state state)
{
- struct vimc_cap_buffer *vbuf, *node;
+ struct vimc_capture_buffer *vbuf, *node;
- spin_lock(&vcap->qlock);
+ spin_lock(&vcapture->qlock);
- list_for_each_entry_safe(vbuf, node, &vcap->buf_list, list) {
+ list_for_each_entry_safe(vbuf, node, &vcapture->buf_list, list) {
list_del(&vbuf->list);
vb2_buffer_done(&vbuf->vb2.vb2_buf, state);
}
- spin_unlock(&vcap->qlock);
+ spin_unlock(&vcapture->qlock);
}
-static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
+static int vimc_capture_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);
- struct media_entity *entity = &vcap->vdev.entity;
+ struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq);
+ struct media_entity *entity = &vcapture->vdev.entity;
int ret;
- vcap->sequence = 0;
+ vcapture->sequence = 0;
/* Start the media pipeline */
- ret = media_pipeline_start(entity, &vcap->stream.pipe);
+ ret = media_pipeline_start(entity, &vcapture->stream.pipe);
if (ret) {
- vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
+ vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_QUEUED);
return ret;
}
- ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1);
+ ret = vimc_streamer_s_stream(&vcapture->stream, &vcapture->ved, 1);
if (ret) {
media_pipeline_stop(entity);
- vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED);
+ vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_QUEUED);
return ret;
}
@@ -267,65 +267,65 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count)
* Stop the stream engine. Any remaining buffers in the stream queue are
* dequeued and passed on to the vb2 framework marked as STATE_ERROR.
*/
-static void vimc_cap_stop_streaming(struct vb2_queue *vq)
+static void vimc_capture_stop_streaming(struct vb2_queue *vq)
{
- struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);
+ struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq);
- vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 0);
+ vimc_streamer_s_stream(&vcapture->stream, &vcapture->ved, 0);
/* Stop the media pipeline */
- media_pipeline_stop(&vcap->vdev.entity);
+ media_pipeline_stop(&vcapture->vdev.entity);
/* Release all active buffers */
- vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_ERROR);
+ vimc_capture_return_all_buffers(vcapture, VB2_BUF_STATE_ERROR);
}
-static void vimc_cap_buf_queue(struct vb2_buffer *vb2_buf)
+static void vimc_capture_buf_queue(struct vb2_buffer *vb2_buf)
{
- struct vimc_cap_device *vcap = vb2_get_drv_priv(vb2_buf->vb2_queue);
- struct vimc_cap_buffer *buf = container_of(vb2_buf,
- struct vimc_cap_buffer,
+ struct vimc_capture_device *vcapture = vb2_get_drv_priv(vb2_buf->vb2_queue);
+ struct vimc_capture_buffer *buf = container_of(vb2_buf,
+ struct vimc_capture_buffer,
vb2.vb2_buf);
- spin_lock(&vcap->qlock);
- list_add_tail(&buf->list, &vcap->buf_list);
- spin_unlock(&vcap->qlock);
+ spin_lock(&vcapture->qlock);
+ list_add_tail(&buf->list, &vcapture->buf_list);
+ spin_unlock(&vcapture->qlock);
}
-static int vimc_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+static int vimc_capture_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[],
struct device *alloc_devs[])
{
- struct vimc_cap_device *vcap = vb2_get_drv_priv(vq);
+ struct vimc_capture_device *vcapture = vb2_get_drv_priv(vq);
if (*nplanes)
- return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0;
+ return sizes[0] < vcapture->format.sizeimage ? -EINVAL : 0;
/* We don't support multiplanes for now */
*nplanes = 1;
- sizes[0] = vcap->format.sizeimage;
+ sizes[0] = vcapture->format.sizeimage;
return 0;
}
-static int vimc_cap_buffer_prepare(struct vb2_buffer *vb)
+static int vimc_capture_buffer_prepare(struct vb2_buffer *vb)
{
- struct vimc_cap_device *vcap = vb2_get_drv_priv(vb->vb2_queue);
- unsigned long size = vcap->format.sizeimage;
+ struct vimc_capture_device *vcapture = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long size = vcapture->format.sizeimage;
if (vb2_plane_size(vb, 0) < size) {
- dev_err(vcap->ved.dev, "%s: buffer too small (%lu < %lu)\n",
- vcap->vdev.name, vb2_plane_size(vb, 0), size);
+ dev_err(vcapture->ved.dev, "%s: buffer too small (%lu < %lu)\n",
+ vcapture->vdev.name, vb2_plane_size(vb, 0), size);
return -EINVAL;
}
return 0;
}
-static const struct vb2_ops vimc_cap_qops = {
- .start_streaming = vimc_cap_start_streaming,
- .stop_streaming = vimc_cap_stop_streaming,
- .buf_queue = vimc_cap_buf_queue,
- .queue_setup = vimc_cap_queue_setup,
- .buf_prepare = vimc_cap_buffer_prepare,
+static const struct vb2_ops vimc_capture_qops = {
+ .start_streaming = vimc_capture_start_streaming,
+ .stop_streaming = vimc_capture_stop_streaming,
+ .buf_queue = vimc_capture_buf_queue,
+ .queue_setup = vimc_capture_queue_setup,
+ .buf_prepare = vimc_capture_buffer_prepare,
/*
* Since q->lock is set we can use the standard
* vb2_ops_wait_prepare/finish helper functions.
@@ -334,107 +334,107 @@ static const struct vb2_ops vimc_cap_qops = {
.wait_finish = vb2_ops_wait_finish,
};
-static const struct media_entity_operations vimc_cap_mops = {
+static const struct media_entity_operations vimc_capture_mops = {
.link_validate = vimc_vdev_link_validate,
};
-static void vimc_cap_release(struct vimc_ent_device *ved)
+static void vimc_capture_release(struct vimc_ent_device *ved)
{
- struct vimc_cap_device *vcap =
- container_of(ved, struct vimc_cap_device, ved);
+ struct vimc_capture_device *vcapture =
+ container_of(ved, struct vimc_capture_device, ved);
- media_entity_cleanup(vcap->ved.ent);
- kfree(vcap);
+ media_entity_cleanup(vcapture->ved.ent);
+ kfree(vcapture);
}
-static void vimc_cap_unregister(struct vimc_ent_device *ved)
+static void vimc_capture_unregister(struct vimc_ent_device *ved)
{
- struct vimc_cap_device *vcap =
- container_of(ved, struct vimc_cap_device, ved);
+ struct vimc_capture_device *vcapture =
+ container_of(ved, struct vimc_capture_device, ved);
- vb2_video_unregister_device(&vcap->vdev);
+ vb2_video_unregister_device(&vcapture->vdev);
}
-static void *vimc_cap_process_frame(struct vimc_ent_device *ved,
+static void *vimc_capture_process_frame(struct vimc_ent_device *ved,
const void *frame)
{
- struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device,
+ struct vimc_capture_device *vcapture = container_of(ved, struct vimc_capture_device,
ved);
- struct vimc_cap_buffer *vimc_buf;
+ struct vimc_capture_buffer *vimc_buf;
void *vbuf;
- spin_lock(&vcap->qlock);
+ spin_lock(&vcapture->qlock);
/* Get the first entry of the list */
- vimc_buf = list_first_entry_or_null(&vcap->buf_list,
+ vimc_buf = list_first_entry_or_null(&vcapture->buf_list,
typeof(*vimc_buf), list);
if (!vimc_buf) {
- spin_unlock(&vcap->qlock);
+ spin_unlock(&vcapture->qlock);
return ERR_PTR(-EAGAIN);
}
/* Remove this entry from the list */
list_del(&vimc_buf->list);
- spin_unlock(&vcap->qlock);
+ spin_unlock(&vcapture->qlock);
/* Fill the buffer */
vimc_buf->vb2.vb2_buf.timestamp = ktime_get_ns();
- vimc_buf->vb2.sequence = vcap->sequence++;
- vimc_buf->vb2.field = vcap->format.field;
+ vimc_buf->vb2.sequence = vcapture->sequence++;
+ vimc_buf->vb2.field = vcapture->format.field;
vbuf = vb2_plane_vaddr(&vimc_buf->vb2.vb2_buf, 0);
- memcpy(vbuf, frame, vcap->format.sizeimage);
+ memcpy(vbuf, frame, vcapture->format.sizeimage);
/* Set it as ready */
vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0,
- vcap->format.sizeimage);
+ vcapture->format.sizeimage);
vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE);
return NULL;
}
-static struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
+static struct vimc_ent_device *vimc_capture_add(struct vimc_device *vimc,
const char *vcfg_name)
{
struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
const struct vimc_pix_map *vpix;
- struct vimc_cap_device *vcap;
+ struct vimc_capture_device *vcapture;
struct video_device *vdev;
struct vb2_queue *q;
int ret;
- /* Allocate the vimc_cap_device struct */
- vcap = kzalloc(sizeof(*vcap), GFP_KERNEL);
- if (!vcap)
+ /* Allocate the vimc_capture_device struct */
+ vcapture = kzalloc(sizeof(*vcapture), GFP_KERNEL);
+ if (!vcapture)
return ERR_PTR(-ENOMEM);
/* Initialize the media entity */
- 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->pad);
+ vcapture->vdev.entity.name = vcfg_name;
+ vcapture->vdev.entity.function = MEDIA_ENT_F_IO_V4L;
+ vcapture->pad.flags = MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(&vcapture->vdev.entity,
+ 1, &vcapture->pad);
if (ret)
- goto err_free_vcap;
+ goto err_free_vcapture;
/* Initialize the lock */
- mutex_init(&vcap->lock);
+ mutex_init(&vcapture->lock);
/* Initialize the vb2 queue */
- q = &vcap->queue;
+ q = &vcapture->queue;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_DMABUF;
if (vimc_allocator == VIMC_ALLOCATOR_VMALLOC)
q->io_modes |= VB2_USERPTR;
- q->drv_priv = vcap;
- q->buf_struct_size = sizeof(struct vimc_cap_buffer);
- q->ops = &vimc_cap_qops;
+ q->drv_priv = vcapture;
+ q->buf_struct_size = sizeof(struct vimc_capture_buffer);
+ q->ops = &vimc_capture_qops;
q->mem_ops = vimc_allocator == VIMC_ALLOCATOR_DMA_CONTIG
? &vb2_dma_contig_memops : &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->min_buffers_needed = 2;
- q->lock = &vcap->lock;
+ q->lock = &vcapture->lock;
q->dev = v4l2_dev->dev;
ret = vb2_queue_init(q);
@@ -445,57 +445,57 @@ static struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
}
/* Initialize buffer list and its lock */
- INIT_LIST_HEAD(&vcap->buf_list);
- spin_lock_init(&vcap->qlock);
+ INIT_LIST_HEAD(&vcapture->buf_list);
+ spin_lock_init(&vcapture->qlock);
/* Set default frame format */
- vcap->format = fmt_default;
- vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat);
- vcap->format.bytesperline = vcap->format.width * vpix->bpp;
- vcap->format.sizeimage = vcap->format.bytesperline *
- vcap->format.height;
+ vcapture->format = fmt_default;
+ vpix = vimc_pix_map_by_pixelformat(vcapture->format.pixelformat);
+ vcapture->format.bytesperline = vcapture->format.width * vpix->bpp;
+ vcapture->format.sizeimage = vcapture->format.bytesperline *
+ vcapture->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;
- vcap->ved.dev = vimc->mdev.dev;
+ vcapture->ved.ent = &vcapture->vdev.entity;
+ vcapture->ved.process_frame = vimc_capture_process_frame;
+ vcapture->ved.vdev_get_format = vimc_capture_get_format;
+ vcapture->ved.dev = vimc->mdev.dev;
/* Initialize the video_device struct */
- vdev = &vcap->vdev;
+ vdev = &vcapture->vdev;
vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
| V4L2_CAP_IO_MC;
- vdev->entity.ops = &vimc_cap_mops;
+ vdev->entity.ops = &vimc_capture_mops;
vdev->release = video_device_release_empty;
- vdev->fops = &vimc_cap_fops;
- vdev->ioctl_ops = &vimc_cap_ioctl_ops;
- vdev->lock = &vcap->lock;
+ vdev->fops = &vimc_capture_fops;
+ vdev->ioctl_ops = &vimc_capture_ioctl_ops;
+ vdev->lock = &vcapture->lock;
vdev->queue = q;
vdev->v4l2_dev = v4l2_dev;
vdev->vfl_dir = VFL_DIR_RX;
strscpy(vdev->name, vcfg_name, sizeof(vdev->name));
- video_set_drvdata(vdev, &vcap->ved);
+ video_set_drvdata(vdev, &vcapture->ved);
/* Register the video_device with the v4l2 and the media framework */
ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
if (ret) {
dev_err(vimc->mdev.dev, "%s: video register failed (err=%d)\n",
- vcap->vdev.name, ret);
+ vcapture->vdev.name, ret);
goto err_clean_m_ent;
}
- return &vcap->ved;
+ return &vcapture->ved;
err_clean_m_ent:
- media_entity_cleanup(&vcap->vdev.entity);
-err_free_vcap:
- kfree(vcap);
+ media_entity_cleanup(&vcapture->vdev.entity);
+err_free_vcapture:
+ kfree(vcapture);
return ERR_PTR(ret);
}
-struct vimc_ent_type vimc_cap_type = {
- .add = vimc_cap_add,
- .unregister = vimc_cap_unregister,
- .release = vimc_cap_release
+struct vimc_ent_type vimc_capture_type = {
+ .add = vimc_capture_add,
+ .unregister = vimc_capture_unregister,
+ .release = vimc_capture_release
};
diff --git a/drivers/media/test-drivers/vimc/vimc-common.h b/drivers/media/test-drivers/vimc/vimc-common.h
index ba1930772589..7641a101a728 100644
--- a/drivers/media/test-drivers/vimc/vimc-common.h
+++ b/drivers/media/test-drivers/vimc/vimc-common.h
@@ -167,10 +167,11 @@ struct vimc_ent_config {
*/
bool vimc_is_source(struct media_entity *ent);
-extern struct vimc_ent_type vimc_sen_type;
-extern struct vimc_ent_type vimc_deb_type;
-extern struct vimc_ent_type vimc_sca_type;
-extern struct vimc_ent_type vimc_cap_type;
+extern struct vimc_ent_type vimc_sensor_type;
+extern struct vimc_ent_type vimc_debayer_type;
+extern struct vimc_ent_type vimc_scaler_type;
+extern struct vimc_ent_type vimc_capture_type;
+extern struct vimc_ent_type vimc_lens_type;
/**
* vimc_pix_map_by_index - get vimc_pix_map struct by its index
diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c
index 06edf9d4d92c..2ae7a0f11ebf 100644
--- a/drivers/media/test-drivers/vimc/vimc-core.c
+++ b/drivers/media/test-drivers/vimc/vimc-core.c
@@ -24,7 +24,7 @@ MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n"
#define VIMC_MDEV_MODEL_NAME "VIMC MDEV"
-#define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \
+#define VIMC_DATA_LINK(src, srcpad, sink, sinkpad, link_flags) { \
.src_ent = src, \
.src_pad = srcpad, \
.sink_ent = sink, \
@@ -32,8 +32,13 @@ MODULE_PARM_DESC(allocator, " memory allocator selection, default is 0.\n"
.flags = link_flags, \
}
-/* Structure which describes links between entities */
-struct vimc_ent_link {
+#define VIMC_ANCILLARY_LINK(primary, ancillary) { \
+ .primary_ent = primary, \
+ .ancillary_ent = ancillary \
+}
+
+/* Structure which describes data links between entities */
+struct vimc_data_link {
unsigned int src_ent;
u16 src_pad;
unsigned int sink_ent;
@@ -41,12 +46,35 @@ struct vimc_ent_link {
u32 flags;
};
+/* Enum to improve clarity when defining vimc_data_links */
+enum vimc_data_link_ents {
+ SENSOR_A,
+ SENSOR_B,
+ DEBAYER_A,
+ DEBAYER_B,
+ RAW_CAPTURE_0,
+ RAW_CAPTURE_1,
+ RGB_YUV_INPUT,
+ SCALER,
+ RGB_YUV_CAPTURE,
+ LENS_A,
+ LENS_B,
+};
+
+/* Structure which describes ancillary links between entities */
+struct vimc_ancillary_link {
+ unsigned int primary_ent;
+ unsigned int ancillary_ent;
+};
+
/* Structure which describes the whole topology */
struct vimc_pipeline_config {
const struct vimc_ent_config *ents;
size_t num_ents;
- const struct vimc_ent_link *links;
- size_t num_links;
+ const struct vimc_data_link *data_links;
+ size_t num_data_links;
+ const struct vimc_ancillary_link *ancillary_links;
+ size_t num_ancillary_links;
};
/* --------------------------------------------------------------------------
@@ -54,69 +82,91 @@ struct vimc_pipeline_config {
*/
static struct vimc_ent_config ent_config[] = {
- {
+ [SENSOR_A] = {
.name = "Sensor A",
- .type = &vimc_sen_type
+ .type = &vimc_sensor_type
},
- {
+ [SENSOR_B] = {
.name = "Sensor B",
- .type = &vimc_sen_type
+ .type = &vimc_sensor_type
},
- {
+ [DEBAYER_A] = {
.name = "Debayer A",
- .type = &vimc_deb_type
+ .type = &vimc_debayer_type
},
- {
+ [DEBAYER_B] = {
.name = "Debayer B",
- .type = &vimc_deb_type
+ .type = &vimc_debayer_type
},
- {
+ [RAW_CAPTURE_0] = {
.name = "Raw Capture 0",
- .type = &vimc_cap_type
+ .type = &vimc_capture_type
},
- {
+ [RAW_CAPTURE_1] = {
.name = "Raw Capture 1",
- .type = &vimc_cap_type
+ .type = &vimc_capture_type
},
- {
+ [RGB_YUV_INPUT] = {
/* TODO: change this to vimc-input when it is implemented */
.name = "RGB/YUV Input",
- .type = &vimc_sen_type
+ .type = &vimc_sensor_type
},
- {
+ [SCALER] = {
.name = "Scaler",
- .type = &vimc_sca_type
+ .type = &vimc_scaler_type
},
- {
+ [RGB_YUV_CAPTURE] = {
.name = "RGB/YUV Capture",
- .type = &vimc_cap_type
+ .type = &vimc_capture_type
+ },
+ [LENS_A] = {
+ .name = "Lens A",
+ .type = &vimc_lens_type
+ },
+ [LENS_B] = {
+ .name = "Lens B",
+ .type = &vimc_lens_type
},
};
-static const struct vimc_ent_link ent_links[] = {
+static const struct vimc_data_link data_links[] = {
/* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */
- VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+ VIMC_DATA_LINK(SENSOR_A, 0, DEBAYER_A, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
/* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */
- VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+ VIMC_DATA_LINK(SENSOR_A, 0, RAW_CAPTURE_0, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
/* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */
- VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+ VIMC_DATA_LINK(SENSOR_B, 0, DEBAYER_B, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
/* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */
- VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+ VIMC_DATA_LINK(SENSOR_B, 0, RAW_CAPTURE_1, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
/* Link: Debayer A (Pad 1)->(Pad 0) Scaler */
- VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED),
+ VIMC_DATA_LINK(DEBAYER_A, 1, SCALER, 0, MEDIA_LNK_FL_ENABLED),
/* Link: Debayer B (Pad 1)->(Pad 0) Scaler */
- VIMC_ENT_LINK(3, 1, 7, 0, 0),
+ VIMC_DATA_LINK(DEBAYER_B, 1, SCALER, 0, 0),
/* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */
- VIMC_ENT_LINK(6, 0, 7, 0, 0),
+ VIMC_DATA_LINK(RGB_YUV_INPUT, 0, SCALER, 0, 0),
/* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */
- VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+ VIMC_DATA_LINK(SCALER, 1, RGB_YUV_CAPTURE, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE),
+};
+
+static const struct vimc_ancillary_link ancillary_links[] = {
+ /* Link: Sensor A -> Lens A */
+ VIMC_ANCILLARY_LINK(0, 9),
+ /* Link: Sensor B -> Lens B */
+ VIMC_ANCILLARY_LINK(1, 10),
};
static struct vimc_pipeline_config pipe_cfg = {
- .ents = ent_config,
- .num_ents = ARRAY_SIZE(ent_config),
- .links = ent_links,
- .num_links = ARRAY_SIZE(ent_links)
+ .ents = ent_config,
+ .num_ents = ARRAY_SIZE(ent_config),
+ .data_links = data_links,
+ .num_data_links = ARRAY_SIZE(data_links),
+ .ancillary_links = ancillary_links,
+ .num_ancillary_links = ARRAY_SIZE(ancillary_links),
};
/* -------------------------------------------------------------------------- */
@@ -135,8 +185,8 @@ static int vimc_create_links(struct vimc_device *vimc)
int ret;
/* 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];
+ for (i = 0; i < vimc->pipe_cfg->num_data_links; i++) {
+ const struct vimc_data_link *link = &vimc->pipe_cfg->data_links[i];
struct vimc_ent_device *ved_src =
vimc->ent_devs[link->src_ent];
@@ -150,6 +200,22 @@ static int vimc_create_links(struct vimc_device *vimc)
goto err_rm_links;
}
+ for (i = 0; i < vimc->pipe_cfg->num_ancillary_links; i++) {
+ const struct vimc_ancillary_link *link = &vimc->pipe_cfg->ancillary_links[i];
+
+ struct vimc_ent_device *ved_primary =
+ vimc->ent_devs[link->primary_ent];
+ struct vimc_ent_device *ved_ancillary =
+ vimc->ent_devs[link->ancillary_ent];
+ struct media_link *ret_link =
+ media_create_ancillary_link(ved_primary->ent, ved_ancillary->ent);
+
+ if (IS_ERR(ret_link)) {
+ ret = PTR_ERR(ret_link);
+ goto err_rm_links;
+ }
+ }
+
return 0;
err_rm_links:
diff --git a/drivers/media/test-drivers/vimc/vimc-debayer.c b/drivers/media/test-drivers/vimc/vimc-debayer.c
index 2d06cdbacc76..f671251fdf0e 100644
--- a/drivers/media/test-drivers/vimc/vimc-debayer.c
+++ b/drivers/media/test-drivers/vimc/vimc-debayer.c
@@ -15,28 +15,29 @@
#include "vimc-common.h"
-enum vimc_deb_rgb_colors {
- VIMC_DEB_RED = 0,
- VIMC_DEB_GREEN = 1,
- VIMC_DEB_BLUE = 2,
+enum vimc_debayer_rgb_colors {
+ VIMC_DEBAYER_RED = 0,
+ VIMC_DEBAYER_GREEN = 1,
+ VIMC_DEBAYER_BLUE = 2,
};
-struct vimc_deb_pix_map {
+struct vimc_debayer_pix_map {
u32 code;
- enum vimc_deb_rgb_colors order[2][2];
+ enum vimc_debayer_rgb_colors order[2][2];
};
-struct vimc_deb_device {
+struct vimc_debayer_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
/* The active format */
struct v4l2_mbus_framefmt sink_fmt;
u32 src_code;
- void (*set_rgb_src)(struct vimc_deb_device *vdeb, unsigned int lin,
- unsigned int col, unsigned int rgb[3]);
+ void (*set_rgb_src)(struct vimc_debayer_device *vdebayer,
+ unsigned int lin, unsigned int col,
+ unsigned int rgb[3]);
/* Values calculated when the stream starts */
u8 *src_frame;
- const struct vimc_deb_pix_map *sink_pix_map;
+ const struct vimc_debayer_pix_map *sink_pix_map;
unsigned int sink_bpp;
unsigned int mean_win_size;
struct v4l2_ctrl_handler hdl;
@@ -51,7 +52,7 @@ static const struct v4l2_mbus_framefmt sink_fmt_default = {
.colorspace = V4L2_COLORSPACE_SRGB,
};
-static const u32 vimc_deb_src_mbus_codes[] = {
+static const u32 vimc_debayer_src_mbus_codes[] = {
MEDIA_BUS_FMT_GBR888_1X24,
MEDIA_BUS_FMT_BGR888_1X24,
MEDIA_BUS_FMT_BGR888_3X8,
@@ -64,95 +65,95 @@ static const u32 vimc_deb_src_mbus_codes[] = {
MEDIA_BUS_FMT_RGB888_1X32_PADHI,
};
-static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = {
+static const struct vimc_debayer_pix_map vimc_debayer_pix_map_list[] = {
{
.code = MEDIA_BUS_FMT_SBGGR8_1X8,
- .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN },
- { VIMC_DEB_GREEN, VIMC_DEB_RED } }
+ .order = { { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN },
+ { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED } }
},
{
.code = MEDIA_BUS_FMT_SGBRG8_1X8,
- .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE },
- { VIMC_DEB_RED, VIMC_DEB_GREEN } }
+ .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE },
+ { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN } }
},
{
.code = MEDIA_BUS_FMT_SGRBG8_1X8,
- .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED },
- { VIMC_DEB_BLUE, VIMC_DEB_GREEN } }
+ .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED },
+ { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN } }
},
{
.code = MEDIA_BUS_FMT_SRGGB8_1X8,
- .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN },
- { VIMC_DEB_GREEN, VIMC_DEB_BLUE } }
+ .order = { { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN },
+ { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE } }
},
{
.code = MEDIA_BUS_FMT_SBGGR10_1X10,
- .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN },
- { VIMC_DEB_GREEN, VIMC_DEB_RED } }
+ .order = { { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN },
+ { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED } }
},
{
.code = MEDIA_BUS_FMT_SGBRG10_1X10,
- .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE },
- { VIMC_DEB_RED, VIMC_DEB_GREEN } }
+ .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE },
+ { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN } }
},
{
.code = MEDIA_BUS_FMT_SGRBG10_1X10,
- .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED },
- { VIMC_DEB_BLUE, VIMC_DEB_GREEN } }
+ .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED },
+ { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN } }
},
{
.code = MEDIA_BUS_FMT_SRGGB10_1X10,
- .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN },
- { VIMC_DEB_GREEN, VIMC_DEB_BLUE } }
+ .order = { { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN },
+ { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE } }
},
{
.code = MEDIA_BUS_FMT_SBGGR12_1X12,
- .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN },
- { VIMC_DEB_GREEN, VIMC_DEB_RED } }
+ .order = { { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN },
+ { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED } }
},
{
.code = MEDIA_BUS_FMT_SGBRG12_1X12,
- .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE },
- { VIMC_DEB_RED, VIMC_DEB_GREEN } }
+ .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE },
+ { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN } }
},
{
.code = MEDIA_BUS_FMT_SGRBG12_1X12,
- .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED },
- { VIMC_DEB_BLUE, VIMC_DEB_GREEN } }
+ .order = { { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_RED },
+ { VIMC_DEBAYER_BLUE, VIMC_DEBAYER_GREEN } }
},
{
.code = MEDIA_BUS_FMT_SRGGB12_1X12,
- .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN },
- { VIMC_DEB_GREEN, VIMC_DEB_BLUE } }
+ .order = { { VIMC_DEBAYER_RED, VIMC_DEBAYER_GREEN },
+ { VIMC_DEBAYER_GREEN, VIMC_DEBAYER_BLUE } }
},
};
-static const struct vimc_deb_pix_map *vimc_deb_pix_map_by_code(u32 code)
+static const struct vimc_debayer_pix_map *vimc_debayer_pix_map_by_code(u32 code)
{
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(vimc_deb_pix_map_list); i++)
- if (vimc_deb_pix_map_list[i].code == code)
- return &vimc_deb_pix_map_list[i];
+ for (i = 0; i < ARRAY_SIZE(vimc_debayer_pix_map_list); i++)
+ if (vimc_debayer_pix_map_list[i].code == code)
+ return &vimc_debayer_pix_map_list[i];
return NULL;
}
-static bool vimc_deb_src_code_is_valid(u32 code)
+static bool vimc_debayer_src_code_is_valid(u32 code)
{
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(vimc_deb_src_mbus_codes); i++)
- if (vimc_deb_src_mbus_codes[i] == code)
+ for (i = 0; i < ARRAY_SIZE(vimc_debayer_src_mbus_codes); i++)
+ if (vimc_debayer_src_mbus_codes[i] == code)
return true;
return false;
}
-static int vimc_deb_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int vimc_debayer_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
- struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
+ struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
unsigned int i;
@@ -162,45 +163,45 @@ static int vimc_deb_init_cfg(struct v4l2_subdev *sd,
for (i = 1; i < sd->entity.num_pads; i++) {
mf = v4l2_subdev_get_try_format(sd, sd_state, i);
*mf = sink_fmt_default;
- mf->code = vdeb->src_code;
+ mf->code = vdebayer->src_code;
}
return 0;
}
-static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
+static int vimc_debayer_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
{
if (VIMC_IS_SRC(code->pad)) {
- if (code->index >= ARRAY_SIZE(vimc_deb_src_mbus_codes))
+ if (code->index >= ARRAY_SIZE(vimc_debayer_src_mbus_codes))
return -EINVAL;
- code->code = vimc_deb_src_mbus_codes[code->index];
+ code->code = vimc_debayer_src_mbus_codes[code->index];
} else {
- if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list))
+ if (code->index >= ARRAY_SIZE(vimc_debayer_pix_map_list))
return -EINVAL;
- code->code = vimc_deb_pix_map_list[code->index].code;
+ code->code = vimc_debayer_pix_map_list[code->index].code;
}
return 0;
}
-static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_frame_size_enum *fse)
+static int vimc_debayer_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
{
if (fse->index)
return -EINVAL;
if (VIMC_IS_SINK(fse->pad)) {
- const struct vimc_deb_pix_map *vpix =
- vimc_deb_pix_map_by_code(fse->code);
+ const struct vimc_debayer_pix_map *vpix =
+ vimc_debayer_pix_map_by_code(fse->code);
if (!vpix)
return -EINVAL;
- } else if (!vimc_deb_src_code_is_valid(fse->code)) {
+ } else if (!vimc_debayer_src_code_is_valid(fse->code)) {
return -EINVAL;
}
@@ -212,30 +213,30 @@ static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int vimc_deb_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
+static int vimc_debayer_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
- struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
+ struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
/* Get the current sink format */
fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
*v4l2_subdev_get_try_format(sd, sd_state, 0) :
- vdeb->sink_fmt;
+ vdebayer->sink_fmt;
/* Set the right code for the source pad */
if (VIMC_IS_SRC(fmt->pad))
- fmt->format.code = vdeb->src_code;
+ fmt->format.code = vdebayer->src_code;
return 0;
}
-static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
+static void vimc_debayer_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
{
- const struct vimc_deb_pix_map *vpix;
+ const struct vimc_debayer_pix_map *vpix;
/* Don't accept a code that is not on the debayer table */
- vpix = vimc_deb_pix_map_by_code(fmt->code);
+ vpix = vimc_debayer_pix_map_by_code(fmt->code);
if (!vpix)
fmt->code = sink_fmt_default.code;
@@ -250,21 +251,21 @@ static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
vimc_colorimetry_clamp(fmt);
}
-static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
+static int vimc_debayer_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
- struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
+ struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *sink_fmt;
u32 *src_code;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Do not change the format while stream is on */
- if (vdeb->src_frame)
+ if (vdebayer->src_frame)
return -EBUSY;
- sink_fmt = &vdeb->sink_fmt;
- src_code = &vdeb->src_code;
+ sink_fmt = &vdebayer->sink_fmt;
+ src_code = &vdebayer->src_code;
} else {
sink_fmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
src_code = &v4l2_subdev_get_try_format(sd, sd_state, 1)->code;
@@ -279,17 +280,17 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
fmt->format = *sink_fmt;
- if (vimc_deb_src_code_is_valid(code))
+ if (vimc_debayer_src_code_is_valid(code))
*src_code = code;
fmt->format.code = *src_code;
} else {
/* Set the new format in the sink pad */
- vimc_deb_adjust_sink_fmt(&fmt->format);
+ vimc_debayer_adjust_sink_fmt(&fmt->format);
- dev_dbg(vdeb->ved.dev, "%s: sink format update: "
+ dev_dbg(vdebayer->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,
+ "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdebayer->sd.name,
/* old */
sink_fmt->width, sink_fmt->height, sink_fmt->code,
sink_fmt->colorspace, sink_fmt->quantization,
@@ -305,97 +306,97 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = {
- .init_cfg = vimc_deb_init_cfg,
- .enum_mbus_code = vimc_deb_enum_mbus_code,
- .enum_frame_size = vimc_deb_enum_frame_size,
- .get_fmt = vimc_deb_get_fmt,
- .set_fmt = vimc_deb_set_fmt,
+static const struct v4l2_subdev_pad_ops vimc_debayer_pad_ops = {
+ .init_cfg = vimc_debayer_init_cfg,
+ .enum_mbus_code = vimc_debayer_enum_mbus_code,
+ .enum_frame_size = vimc_debayer_enum_frame_size,
+ .get_fmt = vimc_debayer_get_fmt,
+ .set_fmt = vimc_debayer_set_fmt,
};
-static void vimc_deb_process_rgb_frame(struct vimc_deb_device *vdeb,
- unsigned int lin,
- unsigned int col,
- unsigned int rgb[3])
+static void vimc_debayer_process_rgb_frame(struct vimc_debayer_device *vdebayer,
+ unsigned int lin,
+ unsigned int col,
+ unsigned int rgb[3])
{
const struct vimc_pix_map *vpix;
unsigned int i, index;
- vpix = vimc_pix_map_by_code(vdeb->src_code);
- index = VIMC_FRAME_INDEX(lin, col, vdeb->sink_fmt.width, 3);
+ vpix = vimc_pix_map_by_code(vdebayer->src_code);
+ index = VIMC_FRAME_INDEX(lin, col, vdebayer->sink_fmt.width, 3);
for (i = 0; i < 3; i++) {
switch (vpix->pixelformat) {
case V4L2_PIX_FMT_RGB24:
- vdeb->src_frame[index + i] = rgb[i];
+ vdebayer->src_frame[index + i] = rgb[i];
break;
case V4L2_PIX_FMT_BGR24:
- vdeb->src_frame[index + i] = rgb[2 - i];
+ vdebayer->src_frame[index + i] = rgb[2 - i];
break;
}
}
}
-static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable)
+static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd);
+ struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
if (enable) {
const struct vimc_pix_map *vpix;
unsigned int frame_size;
- if (vdeb->src_frame)
+ if (vdebayer->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 = vimc_pix_map_by_code(vdebayer->src_code);
+ frame_size = vdebayer->sink_fmt.width * vdebayer->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;
+ vpix = vimc_pix_map_by_code(vdebayer->sink_fmt.code);
+ vdebayer->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);
+ vdebayer->sink_pix_map =
+ vimc_debayer_pix_map_by_code(vdebayer->sink_fmt.code);
/*
* Allocate the frame buffer. Use vmalloc to be able to
* allocate a large amount of memory
*/
- vdeb->src_frame = vmalloc(frame_size);
- if (!vdeb->src_frame)
+ vdebayer->src_frame = vmalloc(frame_size);
+ if (!vdebayer->src_frame)
return -ENOMEM;
} else {
- if (!vdeb->src_frame)
+ if (!vdebayer->src_frame)
return 0;
- vfree(vdeb->src_frame);
- vdeb->src_frame = NULL;
+ vfree(vdebayer->src_frame);
+ vdebayer->src_frame = NULL;
}
return 0;
}
-static const struct v4l2_subdev_core_ops vimc_deb_core_ops = {
+static const struct v4l2_subdev_core_ops vimc_debayer_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_video_ops vimc_debayer_video_ops = {
+ .s_stream = vimc_debayer_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,
+static const struct v4l2_subdev_ops vimc_debayer_ops = {
+ .core = &vimc_debayer_core_ops,
+ .pad = &vimc_debayer_pad_ops,
+ .video = &vimc_debayer_video_ops,
};
-static unsigned int vimc_deb_get_val(const u8 *bytes,
- const unsigned int n_bytes)
+static unsigned int vimc_debayer_get_val(const u8 *bytes,
+ const unsigned int n_bytes)
{
unsigned int i;
unsigned int acc = 0;
@@ -406,11 +407,11 @@ static unsigned int vimc_deb_get_val(const u8 *bytes,
return acc;
}
-static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb,
- const u8 *frame,
- const unsigned int lin,
- const unsigned int col,
- unsigned int rgb[3])
+static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
+ const u8 *frame,
+ const unsigned int lin,
+ const unsigned int col,
+ unsigned int rgb[3])
{
unsigned int i, seek, wlin, wcol;
unsigned int n_rgb[3] = {0, 0, 0};
@@ -423,13 +424,13 @@ 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 = vdeb->mean_win_size / 2;
+ seek = vdebayer->mean_win_size / 2;
/* Sum the values of the colors in the mean window */
- dev_dbg(vdeb->ved.dev,
+ dev_dbg(vdebayer->ved.dev,
"deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n",
- vdeb->sd.name, lin, col, vdeb->sink_fmt.height, seek);
+ vdebayer->sd.name, lin, col, vdebayer->sink_fmt.height, seek);
/*
* Iterate through all the lines in the mean window, start
@@ -438,7 +439,7 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb,
* frame
*/
for (wlin = seek > lin ? 0 : lin - seek;
- wlin < lin + seek + 1 && wlin < vdeb->sink_fmt.height;
+ wlin < lin + seek + 1 && wlin < vdebayer->sink_fmt.height;
wlin++) {
/*
@@ -448,78 +449,80 @@ static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb,
* frame
*/
for (wcol = seek > col ? 0 : col - seek;
- wcol < col + seek + 1 && wcol < vdeb->sink_fmt.width;
+ wcol < col + seek + 1 && wcol < vdebayer->sink_fmt.width;
wcol++) {
- enum vimc_deb_rgb_colors color;
+ enum vimc_debayer_rgb_colors color;
unsigned int index;
/* Check which color this pixel is */
- color = vdeb->sink_pix_map->order[wlin % 2][wcol % 2];
+ color = vdebayer->sink_pix_map->order[wlin % 2][wcol % 2];
index = VIMC_FRAME_INDEX(wlin, wcol,
- vdeb->sink_fmt.width,
- vdeb->sink_bpp);
+ vdebayer->sink_fmt.width,
+ vdebayer->sink_bpp);
- dev_dbg(vdeb->ved.dev,
+ dev_dbg(vdebayer->ved.dev,
"deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n",
- vdeb->sd.name, index, wlin, wcol, color);
+ vdebayer->sd.name, index, wlin, wcol, color);
/* Get its value */
rgb[color] = rgb[color] +
- vimc_deb_get_val(&frame[index], vdeb->sink_bpp);
+ vimc_debayer_get_val(&frame[index],
+ vdebayer->sink_bpp);
/* Save how many values we already added */
n_rgb[color]++;
- dev_dbg(vdeb->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n",
- vdeb->sd.name, rgb[color], n_rgb[color]);
+ dev_dbg(vdebayer->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n",
+ vdebayer->sd.name, rgb[color], n_rgb[color]);
}
}
/* Calculate the mean */
for (i = 0; i < 3; i++) {
- dev_dbg(vdeb->ved.dev,
+ dev_dbg(vdebayer->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]);
+ vdebayer->sd.name, lin, col, i, rgb[i], n_rgb[i]);
if (n_rgb[i])
rgb[i] = rgb[i] / n_rgb[i];
- dev_dbg(vdeb->ved.dev,
+ dev_dbg(vdebayer->ved.dev,
"deb: %s: FINAL CALC: %dx%d Color %d, val %d\n",
- vdeb->sd.name, lin, col, i, rgb[i]);
+ vdebayer->sd.name, lin, col, i, rgb[i]);
}
}
-static void *vimc_deb_process_frame(struct vimc_ent_device *ved,
- const void *sink_frame)
+static void *vimc_debayer_process_frame(struct vimc_ent_device *ved,
+ const void *sink_frame)
{
- struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device,
- ved);
+ struct vimc_debayer_device *vdebayer =
+ container_of(ved, struct vimc_debayer_device, ved);
+
unsigned int rgb[3];
unsigned int i, j;
/* If the stream in this node is not active, just return */
- if (!vdeb->src_frame)
+ if (!vdebayer->src_frame)
return ERR_PTR(-EINVAL);
- for (i = 0; i < vdeb->sink_fmt.height; i++)
- for (j = 0; j < vdeb->sink_fmt.width; j++) {
- vimc_deb_calc_rgb_sink(vdeb, sink_frame, i, j, rgb);
- vdeb->set_rgb_src(vdeb, i, j, rgb);
+ for (i = 0; i < vdebayer->sink_fmt.height; i++)
+ for (j = 0; j < vdebayer->sink_fmt.width; j++) {
+ vimc_debayer_calc_rgb_sink(vdebayer, sink_frame, i, j, rgb);
+ vdebayer->set_rgb_src(vdebayer, i, j, rgb);
}
- return vdeb->src_frame;
+ return vdebayer->src_frame;
}
-static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl)
+static int vimc_debayer_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct vimc_deb_device *vdeb =
- container_of(ctrl->handler, struct vimc_deb_device, hdl);
+ struct vimc_debayer_device *vdebayer =
+ container_of(ctrl->handler, struct vimc_debayer_device, hdl);
switch (ctrl->id) {
case VIMC_CID_MEAN_WIN_SIZE:
- vdeb->mean_win_size = ctrl->val;
+ vdebayer->mean_win_size = ctrl->val;
break;
default:
return -EINVAL;
@@ -527,29 +530,29 @@ static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = {
- .s_ctrl = vimc_deb_s_ctrl,
+static const struct v4l2_ctrl_ops vimc_debayer_ctrl_ops = {
+ .s_ctrl = vimc_debayer_s_ctrl,
};
-static void vimc_deb_release(struct vimc_ent_device *ved)
+static void vimc_debayer_release(struct vimc_ent_device *ved)
{
- struct vimc_deb_device *vdeb =
- container_of(ved, struct vimc_deb_device, ved);
+ struct vimc_debayer_device *vdebayer =
+ container_of(ved, struct vimc_debayer_device, ved);
- v4l2_ctrl_handler_free(&vdeb->hdl);
- media_entity_cleanup(vdeb->ved.ent);
- kfree(vdeb);
+ v4l2_ctrl_handler_free(&vdebayer->hdl);
+ media_entity_cleanup(vdebayer->ved.ent);
+ kfree(vdebayer);
}
-static const struct v4l2_ctrl_config vimc_deb_ctrl_class = {
+static const struct v4l2_ctrl_config vimc_debayer_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,
+static const struct v4l2_ctrl_config vimc_debayer_ctrl_mean_win_size = {
+ .ops = &vimc_debayer_ctrl_ops,
.id = VIMC_CID_MEAN_WIN_SIZE,
.name = "Debayer Mean Window Size",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -559,65 +562,65 @@ static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = {
.def = 3,
};
-static struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc,
- const char *vcfg_name)
+static struct vimc_ent_device *vimc_debayer_add(struct vimc_device *vimc,
+ const char *vcfg_name)
{
struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
- struct vimc_deb_device *vdeb;
+ struct vimc_debayer_device *vdebayer;
int ret;
- /* Allocate the vdeb struct */
- vdeb = kzalloc(sizeof(*vdeb), GFP_KERNEL);
- if (!vdeb)
+ /* Allocate the vdebayer struct */
+ vdebayer = kzalloc(sizeof(*vdebayer), GFP_KERNEL);
+ if (!vdebayer)
return ERR_PTR(-ENOMEM);
/* 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;
+ v4l2_ctrl_handler_init(&vdebayer->hdl, 2);
+ v4l2_ctrl_new_custom(&vdebayer->hdl, &vimc_debayer_ctrl_class, NULL);
+ v4l2_ctrl_new_custom(&vdebayer->hdl, &vimc_debayer_ctrl_mean_win_size, NULL);
+ vdebayer->sd.ctrl_handler = &vdebayer->hdl;
+ if (vdebayer->hdl.error) {
+ ret = vdebayer->hdl.error;
+ goto err_free_vdebayer;
}
/* Initialize ved and sd */
- vdeb->pads[0].flags = MEDIA_PAD_FL_SINK;
- vdeb->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ vdebayer->pads[0].flags = MEDIA_PAD_FL_SINK;
+ vdebayer->pads[1].flags = MEDIA_PAD_FL_SOURCE;
- ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev,
+ ret = vimc_ent_sd_register(&vdebayer->ved, &vdebayer->sd, v4l2_dev,
vcfg_name,
MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2,
- vdeb->pads, &vimc_deb_ops);
+ vdebayer->pads, &vimc_debayer_ops);
if (ret)
goto err_free_hdl;
- vdeb->ved.process_frame = vimc_deb_process_frame;
- vdeb->ved.dev = vimc->mdev.dev;
- vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def;
+ vdebayer->ved.process_frame = vimc_debayer_process_frame;
+ vdebayer->ved.dev = vimc->mdev.dev;
+ vdebayer->mean_win_size = vimc_debayer_ctrl_mean_win_size.def;
/* Initialize the frame format */
- vdeb->sink_fmt = sink_fmt_default;
+ vdebayer->sink_fmt = sink_fmt_default;
/*
* TODO: Add support for more output formats, we only support
* RGB888 for now
* NOTE: the src format is always the same as the sink, except
* for the code
*/
- vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24;
- vdeb->set_rgb_src = vimc_deb_process_rgb_frame;
+ vdebayer->src_code = MEDIA_BUS_FMT_RGB888_1X24;
+ vdebayer->set_rgb_src = vimc_debayer_process_rgb_frame;
- return &vdeb->ved;
+ return &vdebayer->ved;
err_free_hdl:
- v4l2_ctrl_handler_free(&vdeb->hdl);
-err_free_vdeb:
- kfree(vdeb);
+ v4l2_ctrl_handler_free(&vdebayer->hdl);
+err_free_vdebayer:
+ kfree(vdebayer);
return ERR_PTR(ret);
}
-struct vimc_ent_type vimc_deb_type = {
- .add = vimc_deb_add,
- .release = vimc_deb_release
+struct vimc_ent_type vimc_debayer_type = {
+ .add = vimc_debayer_add,
+ .release = vimc_debayer_release
};
diff --git a/drivers/media/test-drivers/vimc/vimc-lens.c b/drivers/media/test-drivers/vimc/vimc-lens.c
new file mode 100644
index 000000000000..3ce7f4b4d2cc
--- /dev/null
+++ b/drivers/media/test-drivers/vimc/vimc-lens.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * vimc-lens.c Virtual Media Controller Driver
+ * Copyright (C) 2022 Google, Inc
+ * Author: yunkec@google.com (Yunke Cao)
+ */
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+
+#include "vimc-common.h"
+
+#define VIMC_LENS_MAX_FOCUS_POS 1023
+#define VIMC_LENS_MAX_FOCUS_STEP 1
+
+struct vimc_lens_device {
+ struct vimc_ent_device ved;
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ u32 focus_absolute;
+};
+
+static const struct v4l2_subdev_core_ops vimc_lens_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_ops vimc_lens_ops = {
+ .core = &vimc_lens_core_ops
+};
+
+static int vimc_lens_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vimc_lens_device *vlens =
+ container_of(ctrl->handler, struct vimc_lens_device, hdl);
+ if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) {
+ vlens->focus_absolute = ctrl->val;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops vimc_lens_ctrl_ops = {
+ .s_ctrl = vimc_lens_s_ctrl,
+};
+
+static struct vimc_ent_device *vimc_lens_add(struct vimc_device *vimc,
+ const char *vcfg_name)
+{
+ struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
+ struct vimc_lens_device *vlens;
+ int ret;
+
+ /* Allocate the vlens struct */
+ vlens = kzalloc(sizeof(*vlens), GFP_KERNEL);
+ if (!vlens)
+ return ERR_PTR(-ENOMEM);
+
+ v4l2_ctrl_handler_init(&vlens->hdl, 1);
+
+ v4l2_ctrl_new_std(&vlens->hdl, &vimc_lens_ctrl_ops,
+ V4L2_CID_FOCUS_ABSOLUTE, 0,
+ VIMC_LENS_MAX_FOCUS_POS, VIMC_LENS_MAX_FOCUS_STEP, 0);
+ vlens->sd.ctrl_handler = &vlens->hdl;
+ if (vlens->hdl.error) {
+ ret = vlens->hdl.error;
+ goto err_free_vlens;
+ }
+ vlens->ved.dev = vimc->mdev.dev;
+
+ ret = vimc_ent_sd_register(&vlens->ved, &vlens->sd, v4l2_dev,
+ vcfg_name, MEDIA_ENT_F_LENS, 0,
+ NULL, &vimc_lens_ops);
+ if (ret)
+ goto err_free_hdl;
+
+ return &vlens->ved;
+
+err_free_hdl:
+ v4l2_ctrl_handler_free(&vlens->hdl);
+err_free_vlens:
+ kfree(vlens);
+
+ return ERR_PTR(ret);
+}
+
+static void vimc_lens_release(struct vimc_ent_device *ved)
+{
+ struct vimc_lens_device *vlens =
+ container_of(ved, struct vimc_lens_device, ved);
+
+ v4l2_ctrl_handler_free(&vlens->hdl);
+ media_entity_cleanup(vlens->ved.ent);
+ kfree(vlens);
+}
+
+struct vimc_ent_type vimc_lens_type = {
+ .add = vimc_lens_add,
+ .release = vimc_lens_release
+};
diff --git a/drivers/media/test-drivers/vimc/vimc-scaler.c b/drivers/media/test-drivers/vimc/vimc-scaler.c
index 820b8f5b502f..b671774e2784 100644
--- a/drivers/media/test-drivers/vimc/vimc-scaler.c
+++ b/drivers/media/test-drivers/vimc/vimc-scaler.c
@@ -16,14 +16,14 @@
/* Pad identifier */
enum vic_sca_pad {
- VIMC_SCA_SINK = 0,
- VIMC_SCA_SRC = 1,
+ VIMC_SCALER_SINK = 0,
+ VIMC_SCALER_SRC = 1,
};
-#define VIMC_SCA_FMT_WIDTH_DEFAULT 640
-#define VIMC_SCA_FMT_HEIGHT_DEFAULT 480
+#define VIMC_SCALER_FMT_WIDTH_DEFAULT 640
+#define VIMC_SCALER_FMT_HEIGHT_DEFAULT 480
-struct vimc_sca_device {
+struct vimc_scaler_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
struct v4l2_rect crop_rect;
@@ -36,16 +36,16 @@ struct vimc_sca_device {
};
static const struct v4l2_mbus_framefmt fmt_default = {
- .width = VIMC_SCA_FMT_WIDTH_DEFAULT,
- .height = VIMC_SCA_FMT_HEIGHT_DEFAULT,
+ .width = VIMC_SCALER_FMT_WIDTH_DEFAULT,
+ .height = VIMC_SCALER_FMT_HEIGHT_DEFAULT,
.code = MEDIA_BUS_FMT_RGB888_1X24,
.field = V4L2_FIELD_NONE,
.colorspace = V4L2_COLORSPACE_SRGB,
};
static const struct v4l2_rect crop_rect_default = {
- .width = VIMC_SCA_FMT_WIDTH_DEFAULT,
- .height = VIMC_SCA_FMT_HEIGHT_DEFAULT,
+ .width = VIMC_SCALER_FMT_WIDTH_DEFAULT,
+ .height = VIMC_SCALER_FMT_HEIGHT_DEFAULT,
.top = 0,
.left = 0,
};
@@ -58,7 +58,7 @@ static const struct v4l2_rect crop_rect_min = {
};
static struct v4l2_rect
-vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt)
+vimc_scaler_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt)
{
/* Get the crop bounds to clamp the crop rectangle correctly */
struct v4l2_rect r = {
@@ -70,7 +70,7 @@ vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt)
return r;
}
-static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
+static int vimc_scaler_init_cfg(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state)
{
struct v4l2_mbus_framefmt *mf;
@@ -82,13 +82,13 @@ static int vimc_sca_init_cfg(struct v4l2_subdev *sd,
*mf = fmt_default;
}
- r = v4l2_subdev_get_try_crop(sd, sd_state, VIMC_SCA_SINK);
+ r = v4l2_subdev_get_try_crop(sd, sd_state, VIMC_SCALER_SINK);
*r = crop_rect_default;
return 0;
}
-static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd,
+static int vimc_scaler_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
@@ -109,7 +109,7 @@ static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd,
+static int vimc_scaler_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
@@ -133,57 +133,57 @@ static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd,
}
static struct v4l2_mbus_framefmt *
-vimc_sca_pad_format(struct vimc_sca_device *vsca,
+vimc_scaler_pad_format(struct vimc_scaler_device *vscaler,
struct v4l2_subdev_state *sd_state, u32 pad,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_format(&vsca->sd, sd_state, pad);
+ return v4l2_subdev_get_try_format(&vscaler->sd, sd_state, pad);
else
- return &vsca->fmt[pad];
+ return &vscaler->fmt[pad];
}
static struct v4l2_rect *
-vimc_sca_pad_crop(struct vimc_sca_device *vsca,
+vimc_scaler_pad_crop(struct vimc_scaler_device *vscaler,
struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which)
{
if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_get_try_crop(&vsca->sd, sd_state,
- VIMC_SCA_SINK);
+ return v4l2_subdev_get_try_crop(&vscaler->sd, sd_state,
+ VIMC_SCALER_SINK);
else
- return &vsca->crop_rect;
+ return &vscaler->crop_rect;
}
-static int vimc_sca_get_fmt(struct v4l2_subdev *sd,
+static int vimc_scaler_get_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
- struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
+ struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd);
- format->format = *vimc_sca_pad_format(vsca, sd_state, format->pad,
+ format->format = *vimc_scaler_pad_format(vscaler, sd_state, format->pad,
format->which);
return 0;
}
-static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
+static int vimc_scaler_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
- struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
+ struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *fmt;
/* Do not change the active format while stream is on */
- if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsca->src_frame)
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && vscaler->src_frame)
return -EBUSY;
- fmt = vimc_sca_pad_format(vsca, sd_state, format->pad, format->which);
+ fmt = vimc_scaler_pad_format(vscaler, sd_state, format->pad, format->which);
/*
* The media bus code and colorspace can only be changed on the sink
* pad, the source pad only follows.
*/
- if (format->pad == VIMC_SCA_SINK) {
+ if (format->pad == VIMC_SCALER_SINK) {
const struct vimc_pix_map *vpix;
/* Only accept code in the pix map table in non bayer format. */
@@ -211,17 +211,17 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
* Propagate the sink pad format to the crop rectangle and the source
* pad.
*/
- if (format->pad == VIMC_SCA_SINK) {
+ if (format->pad == VIMC_SCALER_SINK) {
struct v4l2_mbus_framefmt *src_fmt;
struct v4l2_rect *crop;
- crop = vimc_sca_pad_crop(vsca, sd_state, format->which);
+ crop = vimc_scaler_pad_crop(vscaler, sd_state, format->which);
crop->width = fmt->width;
crop->height = fmt->height;
crop->top = 0;
crop->left = 0;
- src_fmt = vimc_sca_pad_format(vsca, sd_state, VIMC_SCA_SRC,
+ src_fmt = vimc_scaler_pad_format(vscaler, sd_state, VIMC_SCALER_SRC,
format->which);
*src_fmt = *fmt;
}
@@ -231,11 +231,11 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int vimc_sca_get_selection(struct v4l2_subdev *sd,
+static int vimc_scaler_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
+ struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *sink_fmt;
if (VIMC_IS_SRC(sel->pad))
@@ -243,12 +243,12 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- sel->r = *vimc_sca_pad_crop(vsca, sd_state, sel->which);
+ sel->r = *vimc_scaler_pad_crop(vscaler, sd_state, sel->which);
break;
case V4L2_SEL_TGT_CROP_BOUNDS:
- sink_fmt = vimc_sca_pad_format(vsca, sd_state, VIMC_SCA_SINK,
+ sink_fmt = vimc_scaler_pad_format(vscaler, sd_state, VIMC_SCALER_SINK,
sel->which);
- sel->r = vimc_sca_get_crop_bound_sink(sink_fmt);
+ sel->r = vimc_scaler_get_crop_bound_sink(sink_fmt);
break;
default:
return -EINVAL;
@@ -257,22 +257,22 @@ static int vimc_sca_get_selection(struct v4l2_subdev *sd,
return 0;
}
-static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r,
+static void vimc_scaler_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);
+ vimc_scaler_get_crop_bound_sink(sink_fmt);
/* 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_set_selection(struct v4l2_subdev *sd,
+static int vimc_scaler_set_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
+ struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *sink_fmt;
struct v4l2_rect *crop_rect;
@@ -280,165 +280,165 @@ static int vimc_sca_set_selection(struct v4l2_subdev *sd,
if (VIMC_IS_SRC(sel->pad) || sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsca->src_frame)
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && vscaler->src_frame)
return -EBUSY;
- crop_rect = vimc_sca_pad_crop(vsca, sd_state, sel->which);
- sink_fmt = vimc_sca_pad_format(vsca, sd_state, VIMC_SCA_SINK,
+ crop_rect = vimc_scaler_pad_crop(vscaler, sd_state, sel->which);
+ sink_fmt = vimc_scaler_pad_format(vscaler, sd_state, VIMC_SCALER_SINK,
sel->which);
- vimc_sca_adjust_sink_crop(&sel->r, sink_fmt);
+ vimc_scaler_adjust_sink_crop(&sel->r, sink_fmt);
*crop_rect = sel->r;
return 0;
}
-static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = {
- .init_cfg = vimc_sca_init_cfg,
- .enum_mbus_code = vimc_sca_enum_mbus_code,
- .enum_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 const struct v4l2_subdev_pad_ops vimc_scaler_pad_ops = {
+ .init_cfg = vimc_scaler_init_cfg,
+ .enum_mbus_code = vimc_scaler_enum_mbus_code,
+ .enum_frame_size = vimc_scaler_enum_frame_size,
+ .get_fmt = vimc_scaler_get_fmt,
+ .set_fmt = vimc_scaler_set_fmt,
+ .get_selection = vimc_scaler_get_selection,
+ .set_selection = vimc_scaler_set_selection,
};
-static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable)
+static int vimc_scaler_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd);
+ struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd);
if (enable) {
const struct vimc_pix_map *vpix;
unsigned int frame_size;
- if (vsca->src_frame)
+ if (vscaler->src_frame)
return 0;
/* Save the bytes per pixel of the sink */
- vpix = vimc_pix_map_by_code(vsca->fmt[VIMC_SCA_SINK].code);
- vsca->bpp = vpix->bpp;
+ vpix = vimc_pix_map_by_code(vscaler->fmt[VIMC_SCALER_SINK].code);
+ vscaler->bpp = vpix->bpp;
/* Calculate the frame size of the source pad */
- frame_size = vsca->fmt[VIMC_SCA_SRC].width
- * vsca->fmt[VIMC_SCA_SRC].height * vsca->bpp;
+ frame_size = vscaler->fmt[VIMC_SCALER_SRC].width
+ * vscaler->fmt[VIMC_SCALER_SRC].height * vscaler->bpp;
/* Allocate the frame buffer. Use vmalloc to be able to
* allocate a large amount of memory
*/
- vsca->src_frame = vmalloc(frame_size);
- if (!vsca->src_frame)
+ vscaler->src_frame = vmalloc(frame_size);
+ if (!vscaler->src_frame)
return -ENOMEM;
} else {
- if (!vsca->src_frame)
+ if (!vscaler->src_frame)
return 0;
- vfree(vsca->src_frame);
- vsca->src_frame = NULL;
+ vfree(vscaler->src_frame);
+ vscaler->src_frame = NULL;
}
return 0;
}
-static const struct v4l2_subdev_video_ops vimc_sca_video_ops = {
- .s_stream = vimc_sca_s_stream,
+static const struct v4l2_subdev_video_ops vimc_scaler_video_ops = {
+ .s_stream = vimc_scaler_s_stream,
};
-static const struct v4l2_subdev_ops vimc_sca_ops = {
- .pad = &vimc_sca_pad_ops,
- .video = &vimc_sca_video_ops,
+static const struct v4l2_subdev_ops vimc_scaler_ops = {
+ .pad = &vimc_scaler_pad_ops,
+ .video = &vimc_scaler_video_ops,
};
-static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca,
+static void vimc_scaler_fill_src_frame(const struct vimc_scaler_device *const vscaler,
const u8 *const sink_frame)
{
- const struct v4l2_mbus_framefmt *src_fmt = &vsca->fmt[VIMC_SCA_SRC];
- const struct v4l2_rect *r = &vsca->crop_rect;
- unsigned int snk_width = vsca->fmt[VIMC_SCA_SINK].width;
+ const struct v4l2_mbus_framefmt *src_fmt = &vscaler->fmt[VIMC_SCALER_SRC];
+ const struct v4l2_rect *r = &vscaler->crop_rect;
+ unsigned int snk_width = vscaler->fmt[VIMC_SCALER_SINK].width;
unsigned int src_x, src_y;
- u8 *walker = vsca->src_frame;
+ u8 *walker = vscaler->src_frame;
/* Set each pixel at the src_frame to its sink_frame equivalent */
for (src_y = 0; src_y < src_fmt->height; src_y++) {
unsigned int snk_y, y_offset;
snk_y = (src_y * r->height) / src_fmt->height + r->top;
- y_offset = snk_y * snk_width * vsca->bpp;
+ y_offset = snk_y * snk_width * vscaler->bpp;
for (src_x = 0; src_x < src_fmt->width; src_x++) {
unsigned int snk_x, x_offset, index;
snk_x = (src_x * r->width) / src_fmt->width + r->left;
- x_offset = snk_x * vsca->bpp;
+ x_offset = snk_x * vscaler->bpp;
index = y_offset + x_offset;
- memcpy(walker, &sink_frame[index], vsca->bpp);
- walker += vsca->bpp;
+ memcpy(walker, &sink_frame[index], vscaler->bpp);
+ walker += vscaler->bpp;
}
}
}
-static void *vimc_sca_process_frame(struct vimc_ent_device *ved,
+static void *vimc_scaler_process_frame(struct vimc_ent_device *ved,
const void *sink_frame)
{
- struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device,
+ struct vimc_scaler_device *vscaler = container_of(ved, struct vimc_scaler_device,
ved);
/* If the stream in this node is not active, just return */
- if (!vsca->src_frame)
+ if (!vscaler->src_frame)
return ERR_PTR(-EINVAL);
- vimc_sca_fill_src_frame(vsca, sink_frame);
+ vimc_scaler_fill_src_frame(vscaler, sink_frame);
- return vsca->src_frame;
+ return vscaler->src_frame;
};
-static void vimc_sca_release(struct vimc_ent_device *ved)
+static void vimc_scaler_release(struct vimc_ent_device *ved)
{
- struct vimc_sca_device *vsca =
- container_of(ved, struct vimc_sca_device, ved);
+ struct vimc_scaler_device *vscaler =
+ container_of(ved, struct vimc_scaler_device, ved);
- media_entity_cleanup(vsca->ved.ent);
- kfree(vsca);
+ media_entity_cleanup(vscaler->ved.ent);
+ kfree(vscaler);
}
-static struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc,
+static struct vimc_ent_device *vimc_scaler_add(struct vimc_device *vimc,
const char *vcfg_name)
{
struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
- struct vimc_sca_device *vsca;
+ struct vimc_scaler_device *vscaler;
int ret;
- /* Allocate the vsca struct */
- vsca = kzalloc(sizeof(*vsca), GFP_KERNEL);
- if (!vsca)
+ /* Allocate the vscaler struct */
+ vscaler = kzalloc(sizeof(*vscaler), GFP_KERNEL);
+ if (!vscaler)
return ERR_PTR(-ENOMEM);
/* Initialize ved and sd */
- vsca->pads[VIMC_SCA_SINK].flags = MEDIA_PAD_FL_SINK;
- vsca->pads[VIMC_SCA_SRC].flags = MEDIA_PAD_FL_SOURCE;
+ vscaler->pads[VIMC_SCALER_SINK].flags = MEDIA_PAD_FL_SINK;
+ vscaler->pads[VIMC_SCALER_SRC].flags = MEDIA_PAD_FL_SOURCE;
- ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev,
+ ret = vimc_ent_sd_register(&vscaler->ved, &vscaler->sd, v4l2_dev,
vcfg_name,
MEDIA_ENT_F_PROC_VIDEO_SCALER, 2,
- vsca->pads, &vimc_sca_ops);
+ vscaler->pads, &vimc_scaler_ops);
if (ret) {
- kfree(vsca);
+ kfree(vscaler);
return ERR_PTR(ret);
}
- vsca->ved.process_frame = vimc_sca_process_frame;
- vsca->ved.dev = vimc->mdev.dev;
+ vscaler->ved.process_frame = vimc_scaler_process_frame;
+ vscaler->ved.dev = vimc->mdev.dev;
/* Initialize the frame format */
- vsca->fmt[VIMC_SCA_SINK] = fmt_default;
- vsca->fmt[VIMC_SCA_SRC] = fmt_default;
+ vscaler->fmt[VIMC_SCALER_SINK] = fmt_default;
+ vscaler->fmt[VIMC_SCALER_SRC] = fmt_default;
/* Initialize the crop selection */
- vsca->crop_rect = crop_rect_default;
+ vscaler->crop_rect = crop_rect_default;
- return &vsca->ved;
+ return &vscaler->ved;
}
-struct vimc_ent_type vimc_sca_type = {
- .add = vimc_sca_add,
- .release = vimc_sca_release
+struct vimc_ent_type vimc_scaler_type = {
+ .add = vimc_scaler_add,
+ .release = vimc_scaler_release
};
diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c
index 74ab79cadb5d..41a3dce2d714 100644
--- a/drivers/media/test-drivers/vimc/vimc-sensor.c
+++ b/drivers/media/test-drivers/vimc/vimc-sensor.c
@@ -14,18 +14,18 @@
#include "vimc-common.h"
-enum vimc_sen_osd_mode {
- VIMC_SEN_OSD_SHOW_ALL = 0,
- VIMC_SEN_OSD_SHOW_COUNTERS = 1,
- VIMC_SEN_OSD_SHOW_NONE = 2
+enum vimc_sensor_osd_mode {
+ VIMC_SENSOR_OSD_SHOW_ALL = 0,
+ VIMC_SENSOR_OSD_SHOW_COUNTERS = 1,
+ VIMC_SENSOR_OSD_SHOW_NONE = 2
};
-struct vimc_sen_device {
+struct vimc_sensor_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
struct tpg_data tpg;
u8 *frame;
- enum vimc_sen_osd_mode osd_value;
+ enum vimc_sensor_osd_mode osd_value;
u64 start_stream_ts;
/* The active format */
struct v4l2_mbus_framefmt mbus_format;
@@ -41,8 +41,8 @@ static const struct v4l2_mbus_framefmt fmt_default = {
.colorspace = V4L2_COLORSPACE_SRGB,
};
-static int vimc_sen_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int vimc_sensor_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
unsigned int i;
@@ -56,9 +56,9 @@ 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_state *sd_state,
- struct v4l2_subdev_mbus_code_enum *code)
+static int vimc_sensor_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
{
u32 mbus_code = vimc_mbus_code_by_index(code->index);
@@ -70,9 +70,9 @@ static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_frame_size_enum *fse)
+static int vimc_sensor_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
{
const struct vimc_pix_map *vpix;
@@ -92,39 +92,39 @@ static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int vimc_sen_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
+static int vimc_sensor_get_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
- struct vimc_sen_device *vsen =
- container_of(sd, struct vimc_sen_device, sd);
+ struct vimc_sensor_device *vsensor =
+ container_of(sd, struct vimc_sensor_device, sd);
fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
*v4l2_subdev_get_try_format(sd, sd_state, fmt->pad) :
- vsen->mbus_format;
+ vsensor->mbus_format;
return 0;
}
-static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen)
+static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor)
{
const struct vimc_pix_map *vpix =
- vimc_pix_map_by_code(vsen->mbus_format.code);
+ vimc_pix_map_by_code(vsensor->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 * vpix->bpp);
- tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height);
- tpg_s_fourcc(&vsen->tpg, vpix->pixelformat);
+ tpg_reset_source(&vsensor->tpg, vsensor->mbus_format.width,
+ vsensor->mbus_format.height, vsensor->mbus_format.field);
+ tpg_s_bytesperline(&vsensor->tpg, 0, vsensor->mbus_format.width * vpix->bpp);
+ tpg_s_buf_height(&vsensor->tpg, vsensor->mbus_format.height);
+ tpg_s_fourcc(&vsensor->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);
- tpg_s_ycbcr_enc(&vsen->tpg, vsen->mbus_format.ycbcr_enc);
- tpg_s_quantization(&vsen->tpg, vsen->mbus_format.quantization);
- tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func);
+ tpg_s_field(&vsensor->tpg, vsensor->mbus_format.field, false);
+ tpg_s_colorspace(&vsensor->tpg, vsensor->mbus_format.colorspace);
+ tpg_s_ycbcr_enc(&vsensor->tpg, vsensor->mbus_format.ycbcr_enc);
+ tpg_s_quantization(&vsensor->tpg, vsensor->mbus_format.quantization);
+ tpg_s_xfer_func(&vsensor->tpg, vsensor->mbus_format.xfer_func);
}
-static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
+static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
{
const struct vimc_pix_map *vpix;
@@ -145,29 +145,29 @@ static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
vimc_colorimetry_clamp(fmt);
}
-static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
+static int vimc_sensor_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
{
- struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd);
+ struct vimc_sensor_device *vsensor = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
/* Do not change the format while stream is on */
- if (vsen->frame)
+ if (vsensor->frame)
return -EBUSY;
- mf = &vsen->mbus_format;
+ mf = &vsensor->mbus_format;
} else {
mf = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad);
}
/* Set the new format */
- vimc_sen_adjust_fmt(&fmt->format);
+ vimc_sensor_adjust_fmt(&fmt->format);
- dev_dbg(vsen->ved.dev, "%s: format update: "
+ dev_dbg(vsensor->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,
+ "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsensor->sd.name,
/* old */
mf->width, mf->height, mf->code,
mf->colorspace, mf->quantization,
@@ -182,146 +182,147 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd,
return 0;
}
-static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = {
- .init_cfg = vimc_sen_init_cfg,
- .enum_mbus_code = vimc_sen_enum_mbus_code,
- .enum_frame_size = vimc_sen_enum_frame_size,
- .get_fmt = vimc_sen_get_fmt,
- .set_fmt = vimc_sen_set_fmt,
+static const struct v4l2_subdev_pad_ops vimc_sensor_pad_ops = {
+ .init_cfg = vimc_sensor_init_cfg,
+ .enum_mbus_code = vimc_sensor_enum_mbus_code,
+ .enum_frame_size = vimc_sensor_enum_frame_size,
+ .get_fmt = vimc_sensor_get_fmt,
+ .set_fmt = vimc_sensor_set_fmt,
};
-static void *vimc_sen_process_frame(struct vimc_ent_device *ved,
- const void *sink_frame)
+static void *vimc_sensor_process_frame(struct vimc_ent_device *ved,
+ const void *sink_frame)
{
- struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device,
- ved);
+ struct vimc_sensor_device *vsensor =
+ container_of(ved, struct vimc_sensor_device, ved);
+
const unsigned int line_height = 16;
u8 *basep[TPG_MAX_PLANES][2];
unsigned int line = 1;
char str[100];
- tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame);
- tpg_calc_text_basep(&vsen->tpg, basep, 0, vsen->frame);
- switch (vsen->osd_value) {
- case VIMC_SEN_OSD_SHOW_ALL: {
- const char *order = tpg_g_color_order(&vsen->tpg);
+ tpg_fill_plane_buffer(&vsensor->tpg, 0, 0, vsensor->frame);
+ tpg_calc_text_basep(&vsensor->tpg, basep, 0, vsensor->frame);
+ switch (vsensor->osd_value) {
+ case VIMC_SENSOR_OSD_SHOW_ALL: {
+ const char *order = tpg_g_color_order(&vsensor->tpg);
- tpg_gen_text(&vsen->tpg, basep, line++ * line_height,
+ tpg_gen_text(&vsensor->tpg, basep, line++ * line_height,
16, order);
snprintf(str, sizeof(str),
"brightness %3d, contrast %3d, saturation %3d, hue %d ",
- vsen->tpg.brightness,
- vsen->tpg.contrast,
- vsen->tpg.saturation,
- vsen->tpg.hue);
- tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str);
+ vsensor->tpg.brightness,
+ vsensor->tpg.contrast,
+ vsensor->tpg.saturation,
+ vsensor->tpg.hue);
+ tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
snprintf(str, sizeof(str), "sensor size: %dx%d",
- vsen->mbus_format.width,
- vsen->mbus_format.height);
- tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str);
+ vsensor->mbus_format.width,
+ vsensor->mbus_format.height);
+ tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
fallthrough;
}
- case VIMC_SEN_OSD_SHOW_COUNTERS: {
+ case VIMC_SENSOR_OSD_SHOW_COUNTERS: {
unsigned int ms;
- ms = div_u64(ktime_get_ns() - vsen->start_stream_ts, 1000000);
+ ms = div_u64(ktime_get_ns() - vsensor->start_stream_ts, 1000000);
snprintf(str, sizeof(str), "%02d:%02d:%02d:%03d",
(ms / (60 * 60 * 1000)) % 24,
(ms / (60 * 1000)) % 60,
(ms / 1000) % 60,
ms % 1000);
- tpg_gen_text(&vsen->tpg, basep, line++ * line_height, 16, str);
+ tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
break;
}
- case VIMC_SEN_OSD_SHOW_NONE:
+ case VIMC_SENSOR_OSD_SHOW_NONE:
default:
break;
}
- return vsen->frame;
+ return vsensor->frame;
}
-static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable)
+static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct vimc_sen_device *vsen =
- container_of(sd, struct vimc_sen_device, sd);
+ struct vimc_sensor_device *vsensor =
+ container_of(sd, struct vimc_sensor_device, sd);
if (enable) {
const struct vimc_pix_map *vpix;
unsigned int frame_size;
- vsen->start_stream_ts = ktime_get_ns();
+ vsensor->start_stream_ts = ktime_get_ns();
/* Calculate the frame size */
- vpix = vimc_pix_map_by_code(vsen->mbus_format.code);
- frame_size = vsen->mbus_format.width * vpix->bpp *
- vsen->mbus_format.height;
+ vpix = vimc_pix_map_by_code(vsensor->mbus_format.code);
+ frame_size = vsensor->mbus_format.width * vpix->bpp *
+ vsensor->mbus_format.height;
/*
* Allocate the frame buffer. Use vmalloc to be able to
* allocate a large amount of memory
*/
- vsen->frame = vmalloc(frame_size);
- if (!vsen->frame)
+ vsensor->frame = vmalloc(frame_size);
+ if (!vsensor->frame)
return -ENOMEM;
/* configure the test pattern generator */
- vimc_sen_tpg_s_format(vsen);
+ vimc_sensor_tpg_s_format(vsensor);
} else {
- vfree(vsen->frame);
- vsen->frame = NULL;
+ vfree(vsensor->frame);
+ vsensor->frame = NULL;
}
return 0;
}
-static const struct v4l2_subdev_core_ops vimc_sen_core_ops = {
+static const struct v4l2_subdev_core_ops vimc_sensor_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
-static const struct v4l2_subdev_video_ops vimc_sen_video_ops = {
- .s_stream = vimc_sen_s_stream,
+static const struct v4l2_subdev_video_ops vimc_sensor_video_ops = {
+ .s_stream = vimc_sensor_s_stream,
};
-static const struct v4l2_subdev_ops vimc_sen_ops = {
- .core = &vimc_sen_core_ops,
- .pad = &vimc_sen_pad_ops,
- .video = &vimc_sen_video_ops,
+static const struct v4l2_subdev_ops vimc_sensor_ops = {
+ .core = &vimc_sensor_core_ops,
+ .pad = &vimc_sensor_pad_ops,
+ .video = &vimc_sensor_video_ops,
};
-static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl)
+static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct vimc_sen_device *vsen =
- container_of(ctrl->handler, struct vimc_sen_device, hdl);
+ struct vimc_sensor_device *vsensor =
+ container_of(ctrl->handler, struct vimc_sensor_device, hdl);
switch (ctrl->id) {
case VIMC_CID_TEST_PATTERN:
- tpg_s_pattern(&vsen->tpg, ctrl->val);
+ tpg_s_pattern(&vsensor->tpg, ctrl->val);
break;
case V4L2_CID_HFLIP:
- tpg_s_hflip(&vsen->tpg, ctrl->val);
+ tpg_s_hflip(&vsensor->tpg, ctrl->val);
break;
case V4L2_CID_VFLIP:
- tpg_s_vflip(&vsen->tpg, ctrl->val);
+ tpg_s_vflip(&vsensor->tpg, ctrl->val);
break;
case V4L2_CID_BRIGHTNESS:
- tpg_s_brightness(&vsen->tpg, ctrl->val);
+ tpg_s_brightness(&vsensor->tpg, ctrl->val);
break;
case V4L2_CID_CONTRAST:
- tpg_s_contrast(&vsen->tpg, ctrl->val);
+ tpg_s_contrast(&vsensor->tpg, ctrl->val);
break;
case V4L2_CID_HUE:
- tpg_s_hue(&vsen->tpg, ctrl->val);
+ tpg_s_hue(&vsensor->tpg, ctrl->val);
break;
case V4L2_CID_SATURATION:
- tpg_s_saturation(&vsen->tpg, ctrl->val);
+ tpg_s_saturation(&vsensor->tpg, ctrl->val);
break;
case VIMC_CID_OSD_TEXT_MODE:
- vsen->osd_value = ctrl->val;
+ vsensor->osd_value = ctrl->val;
break;
default:
return -EINVAL;
@@ -329,31 +330,31 @@ static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = {
- .s_ctrl = vimc_sen_s_ctrl,
+static const struct v4l2_ctrl_ops vimc_sensor_ctrl_ops = {
+ .s_ctrl = vimc_sensor_s_ctrl,
};
-static void vimc_sen_release(struct vimc_ent_device *ved)
+static void vimc_sensor_release(struct vimc_ent_device *ved)
{
- struct vimc_sen_device *vsen =
- container_of(ved, struct vimc_sen_device, ved);
+ struct vimc_sensor_device *vsensor =
+ container_of(ved, struct vimc_sensor_device, ved);
- v4l2_ctrl_handler_free(&vsen->hdl);
- tpg_free(&vsen->tpg);
- media_entity_cleanup(vsen->ved.ent);
- kfree(vsen);
+ v4l2_ctrl_handler_free(&vsensor->hdl);
+ tpg_free(&vsensor->tpg);
+ media_entity_cleanup(vsensor->ved.ent);
+ kfree(vsensor);
}
/* Image Processing Controls */
-static const struct v4l2_ctrl_config vimc_sen_ctrl_class = {
+static const struct v4l2_ctrl_config vimc_sensor_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_sen_ctrl_test_pattern = {
- .ops = &vimc_sen_ctrl_ops,
+static const struct v4l2_ctrl_config vimc_sensor_ctrl_test_pattern = {
+ .ops = &vimc_sensor_ctrl_ops,
.id = VIMC_CID_TEST_PATTERN,
.name = "Test Pattern",
.type = V4L2_CTRL_TYPE_MENU,
@@ -368,8 +369,8 @@ static const char * const vimc_ctrl_osd_mode_strings[] = {
NULL,
};
-static const struct v4l2_ctrl_config vimc_sen_ctrl_osd_mode = {
- .ops = &vimc_sen_ctrl_ops,
+static const struct v4l2_ctrl_config vimc_sensor_ctrl_osd_mode = {
+ .ops = &vimc_sensor_ctrl_ops,
.id = VIMC_CID_OSD_TEXT_MODE,
.name = "Show Information",
.type = V4L2_CTRL_TYPE_MENU,
@@ -377,76 +378,76 @@ static const struct v4l2_ctrl_config vimc_sen_ctrl_osd_mode = {
.qmenu = vimc_ctrl_osd_mode_strings,
};
-static struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc,
- const char *vcfg_name)
+static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc,
+ const char *vcfg_name)
{
struct v4l2_device *v4l2_dev = &vimc->v4l2_dev;
- struct vimc_sen_device *vsen;
+ struct vimc_sensor_device *vsensor;
int ret;
- /* Allocate the vsen struct */
- vsen = kzalloc(sizeof(*vsen), GFP_KERNEL);
- if (!vsen)
+ /* Allocate the vsensor struct */
+ vsensor = kzalloc(sizeof(*vsensor), GFP_KERNEL);
+ if (!vsensor)
return ERR_PTR(-ENOMEM);
- v4l2_ctrl_handler_init(&vsen->hdl, 4);
+ v4l2_ctrl_handler_init(&vsensor->hdl, 4);
- v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_class, NULL);
- v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_test_pattern, NULL);
- v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_osd_mode, NULL);
- v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ v4l2_ctrl_new_custom(&vsensor->hdl, &vimc_sensor_ctrl_class, NULL);
+ v4l2_ctrl_new_custom(&vsensor->hdl, &vimc_sensor_ctrl_test_pattern, NULL);
+ v4l2_ctrl_new_custom(&vsensor->hdl, &vimc_sensor_ctrl_osd_mode, NULL);
+ v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops,
V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
- v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops,
V4L2_CID_CONTRAST, 0, 255, 1, 128);
- v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops,
V4L2_CID_HUE, -128, 127, 1, 0);
- v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops,
+ v4l2_ctrl_new_std(&vsensor->hdl, &vimc_sensor_ctrl_ops,
V4L2_CID_SATURATION, 0, 255, 1, 128);
- vsen->sd.ctrl_handler = &vsen->hdl;
- if (vsen->hdl.error) {
- ret = vsen->hdl.error;
- goto err_free_vsen;
+ vsensor->sd.ctrl_handler = &vsensor->hdl;
+ if (vsensor->hdl.error) {
+ ret = vsensor->hdl.error;
+ goto err_free_vsensor;
}
/* 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);
+ tpg_init(&vsensor->tpg, vsensor->mbus_format.width,
+ vsensor->mbus_format.height);
+ ret = tpg_alloc(&vsensor->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,
+ vsensor->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = vimc_ent_sd_register(&vsensor->ved, &vsensor->sd, v4l2_dev,
vcfg_name,
- MEDIA_ENT_F_CAM_SENSOR, 1, &vsen->pad,
- &vimc_sen_ops);
+ MEDIA_ENT_F_CAM_SENSOR, 1, &vsensor->pad,
+ &vimc_sensor_ops);
if (ret)
goto err_free_tpg;
- vsen->ved.process_frame = vimc_sen_process_frame;
- vsen->ved.dev = vimc->mdev.dev;
+ vsensor->ved.process_frame = vimc_sensor_process_frame;
+ vsensor->ved.dev = vimc->mdev.dev;
/* Initialize the frame format */
- vsen->mbus_format = fmt_default;
+ vsensor->mbus_format = fmt_default;
- return &vsen->ved;
+ return &vsensor->ved;
err_free_tpg:
- tpg_free(&vsen->tpg);
+ tpg_free(&vsensor->tpg);
err_free_hdl:
- v4l2_ctrl_handler_free(&vsen->hdl);
-err_free_vsen:
- kfree(vsen);
+ v4l2_ctrl_handler_free(&vsensor->hdl);
+err_free_vsensor:
+ kfree(vsensor);
return ERR_PTR(ret);
}
-struct vimc_ent_type vimc_sen_type = {
- .add = vimc_sen_add,
- .release = vimc_sen_release
+struct vimc_ent_type vimc_sensor_type = {
+ .add = vimc_sensor_add,
+ .release = vimc_sensor_release
};
diff --git a/drivers/media/test-drivers/vimc/vimc-streamer.c b/drivers/media/test-drivers/vimc/vimc-streamer.c
index 65feb3c596db..807551a5143b 100644
--- a/drivers/media/test-drivers/vimc/vimc-streamer.c
+++ b/drivers/media/test-drivers/vimc/vimc-streamer.c
@@ -30,7 +30,7 @@ static struct media_entity *vimc_get_source_entity(struct media_entity *ent)
for (i = 0; i < ent->num_pads; i++) {
if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE)
continue;
- pad = media_entity_remote_pad(&ent->pads[i]);
+ pad = media_pad_remote_pad_first(&ent->pads[i]);
return pad ? pad->entity : NULL;
}
return NULL;
diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c
index e7516dc1227b..a78d676575bc 100644
--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c
+++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c
@@ -34,6 +34,7 @@
#define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10)
#define VIVID_CID_AREA (VIVID_CID_CUSTOM_BASE + 11)
#define VIVID_CID_RO_INTEGER (VIVID_CID_CUSTOM_BASE + 12)
+#define VIVID_CID_U32_DYN_ARRAY (VIVID_CID_CUSTOM_BASE + 13)
#define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000)
#define VIVID_CID_VIVID_CLASS (0x00f00000 | 1)
@@ -46,6 +47,7 @@
#define VIVID_CID_INSERT_SAV (VIVID_CID_VIVID_BASE + 6)
#define VIVID_CID_INSERT_EAV (VIVID_CID_VIVID_BASE + 7)
#define VIVID_CID_VBI_CAP_INTERLACED (VIVID_CID_VIVID_BASE + 8)
+#define VIVID_CID_INSERT_HDMI_VIDEO_GUARD_BAND (VIVID_CID_VIVID_BASE + 9)
#define VIVID_CID_HFLIP (VIVID_CID_VIVID_BASE + 20)
#define VIVID_CID_VFLIP (VIVID_CID_VIVID_BASE + 21)
@@ -189,6 +191,19 @@ static const struct v4l2_ctrl_config vivid_ctrl_u32_array = {
.dims = { 1 },
};
+static const struct v4l2_ctrl_config vivid_ctrl_u32_dyn_array = {
+ .ops = &vivid_user_gen_ctrl_ops,
+ .id = VIVID_CID_U32_DYN_ARRAY,
+ .name = "U32 Dynamic Array",
+ .type = V4L2_CTRL_TYPE_U32,
+ .flags = V4L2_CTRL_FLAG_DYNAMIC_ARRAY,
+ .def = 50,
+ .min = 10,
+ .max = 90,
+ .step = 1,
+ .dims = { 100 },
+};
+
static const struct v4l2_ctrl_config vivid_ctrl_u16_matrix = {
.ops = &vivid_user_gen_ctrl_ops,
.id = VIVID_CID_U16_MATRIX,
@@ -474,6 +489,9 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
case VIVID_CID_INSERT_EAV:
tpg_s_insert_eav(&dev->tpg, ctrl->val);
break;
+ case VIVID_CID_INSERT_HDMI_VIDEO_GUARD_BAND:
+ tpg_s_insert_hdmi_video_guard_band(&dev->tpg, ctrl->val);
+ break;
case VIVID_CID_HFLIP:
dev->sensor_hflip = ctrl->val;
tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
@@ -660,6 +678,15 @@ static const struct v4l2_ctrl_config vivid_ctrl_insert_eav = {
.step = 1,
};
+static const struct v4l2_ctrl_config vivid_ctrl_insert_hdmi_video_guard_band = {
+ .ops = &vivid_vid_cap_ctrl_ops,
+ .id = VIVID_CID_INSERT_HDMI_VIDEO_GUARD_BAND,
+ .name = "Insert Video Guard Band",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .max = 1,
+ .step = 1,
+};
+
static const struct v4l2_ctrl_config vivid_ctrl_hflip = {
.ops = &vivid_vid_cap_ctrl_ops,
.id = VIVID_CID_HFLIP,
@@ -1612,6 +1639,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
dev->ro_int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_ro_int32, 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_u32_dyn_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);
@@ -1638,6 +1666,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL);
+ v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_hdmi_video_guard_band, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_reduced_fps, NULL);
if (show_ccs_cap) {
dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-common.c b/drivers/media/test-drivers/vivid/vivid-vid-common.c
index 19701fe72030..38d788b5cf19 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-common.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-common.c
@@ -199,6 +199,21 @@ struct vivid_fmt vivid_formats[] = {
.buffers = 1,
},
{
+ .fourcc = V4L2_PIX_FMT_YUVA32,
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
+ .alpha_mask = 0xff000000,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUVX32,
+ .vdownsampling = { 1 },
+ .bit_depth = { 32 },
+ .planes = 1,
+ .buffers = 1,
+ },
+ {
.fourcc = V4L2_PIX_FMT_GREY,
.vdownsampling = { 1 },
.bit_depth = { 8 },
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig
index 8de08704f8e4..af88e0766388 100644
--- a/drivers/media/usb/Kconfig
+++ b/drivers/media/usb/Kconfig
@@ -17,7 +17,6 @@ source "drivers/media/usb/cpia2/Kconfig"
source "drivers/media/usb/gspca/Kconfig"
source "drivers/media/usb/pwc/Kconfig"
source "drivers/media/usb/s2255/Kconfig"
-source "drivers/media/usb/stkwebcam/Kconfig"
source "drivers/media/usb/usbtv/Kconfig"
source "drivers/media/usb/uvc/Kconfig"
source "drivers/media/usb/zr364xx/Kconfig"
diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile
index 044bd46c799c..25fa2015b179 100644
--- a/drivers/media/usb/Makefile
+++ b/drivers/media/usb/Makefile
@@ -10,7 +10,6 @@ obj-y += dvb-usb/
obj-y += dvb-usb-v2/
obj-y += s2255/
obj-y += siano/
-obj-y += stkwebcam/
obj-y += ttusb-budget/
obj-y += ttusb-dec/
obj-y += zr364xx/
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index d568452618d1..240a7cc56777 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -123,7 +123,7 @@ struct airspy {
/* USB control message buffer */
#define BUF_SIZE 128
- u8 buf[BUF_SIZE];
+ u8 *buf;
/* Current configuration */
unsigned int f_adc;
@@ -856,6 +856,7 @@ static void airspy_video_release(struct v4l2_device *v)
v4l2_ctrl_handler_free(&s->hdl);
v4l2_device_unregister(&s->v4l2_dev);
+ kfree(s->buf);
kfree(s);
}
@@ -963,7 +964,10 @@ static int airspy_probe(struct usb_interface *intf,
{
struct airspy *s;
int ret;
- u8 u8tmp, buf[BUF_SIZE];
+ u8 u8tmp, *buf;
+
+ buf = NULL;
+ ret = -ENOMEM;
s = kzalloc(sizeof(struct airspy), GFP_KERNEL);
if (s == NULL) {
@@ -971,6 +975,13 @@ static int airspy_probe(struct usb_interface *intf,
return -ENOMEM;
}
+ s->buf = kzalloc(BUF_SIZE, GFP_KERNEL);
+ if (!s->buf)
+ goto err_free_mem;
+ buf = kzalloc(BUF_SIZE, GFP_KERNEL);
+ if (!buf)
+ goto err_free_mem;
+
mutex_init(&s->v4l2_lock);
mutex_init(&s->vb_queue_lock);
spin_lock_init(&s->queued_bufs_lock);
@@ -1068,6 +1079,8 @@ err_free_controls:
v4l2_ctrl_handler_free(&s->hdl);
v4l2_device_unregister(&s->v4l2_dev);
err_free_mem:
+ kfree(buf);
+ kfree(s->buf);
kfree(s);
return ret;
}
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 4d5ab1433b44..ce1b0d9e0741 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -10,16 +10,6 @@
//
// This driver is based on my previous au600 usb pstn audio driver
// and inherits all the copyrights
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
#include "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index d1e66b503f4d..b5f58dc6dd0f 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -4,16 +4,6 @@
//
// Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@kernel.org>
// Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
#include "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index ae25d2cbfdfe..4d037c92af7c 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -8,16 +8,6 @@
// Mauro Carvalho Chehab <mchehab@kernel.org>
// Sascha Sommer <saschasommer@freenet.de>
// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
#include "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index c837cc528a33..61d7bf701d57 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -7,16 +7,6 @@
// Mauro Carvalho Chehab <mchehab@kernel.org>
// Sascha Sommer <saschasommer@freenet.de>
// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
#include "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 471bd74667e3..185e89c18d68 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -16,10 +16,6 @@
// Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
// (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
// (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation version 2 of the License.
#include "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index b9a8d3fbad1a..a7eb11f7fb34 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -7,16 +7,6 @@
// Mauro Carvalho Chehab <mchehab@kernel.org>
// Sascha Sommer <saschasommer@freenet.de>
// Copyright (C) 2013 Frank Schäfer <fschaefer.oss@googlemail.com>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
#include "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 0b6d77c3bec8..5f3b00869bdb 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -6,16 +6,6 @@
// Markus Rechberger <mrechberger@gmail.com>
// Mauro Carvalho Chehab <mchehab@kernel.org>
// Sascha Sommer <saschasommer@freenet.de>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
#include "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
index 6216cdd182f3..8455dcfdaf81 100644
--- a/drivers/media/usb/em28xx/em28xx-v4l.h
+++ b/drivers/media/usb/em28xx/em28xx-v4l.h
@@ -4,15 +4,6 @@
* video capture devices
*
* Copyright (C) 2013-2014 Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index 63c48361d3f2..b253c44c9724 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -5,16 +5,6 @@
// Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
//
// This work was sponsored by EyeMagnet Limited.
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
#include "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 6b84c3413e83..8181c0e6a25b 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -11,16 +11,6 @@
//
// Some parts based on SN9C10x PC Camera Controllers GPL driver made
// by Luca Risolia <luca.risolia@studio.unibo.it>
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; either version 2 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
#include "em28xx.h"
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 7fc0b68a4a22..db18dd814a67 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -8,16 +8,6 @@
* Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
*
* Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#ifndef _EM28XX_H
diff --git a/drivers/media/usb/gspca/spca501.c b/drivers/media/usb/gspca/spca501.c
index ecc97f807cfa..f7c75d7535c4 100644
--- a/drivers/media/usb/gspca/spca501.c
+++ b/drivers/media/usb/gspca/spca501.c
@@ -488,7 +488,7 @@ static const __u16 spca501_init_data[][3] = {
/* Data for video camera init before capture.
* Capture and decoding by Colin Peart.
- * This is is for the 3com HomeConnect Lite which is spca501a based.
+ * This is for the 3com HomeConnect Lite which is spca501a based.
*/
static const __u16 spca501_3com_open_data[][3] = {
/* bmRequest,value,index */
diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c
index cc87c24dd24c..acfb9a195106 100644
--- a/drivers/media/usb/gspca/xirlink_cit.c
+++ b/drivers/media/usb/gspca/xirlink_cit.c
@@ -817,7 +817,7 @@ static void cit_model2_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2)
* 00_d141_0124
* 00_0096_0127
* 00_fea8_0124
-*/
+ */
static void cit_model3_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2)
{
cit_write_reg(gspca_dev, 0x0078, 0x012d);
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index 60e57e0f1927..fd7d2a9d0449 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -409,7 +409,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count,
struct hdpvr_device *dev = video_drvdata(file);
struct hdpvr_buffer *buf = NULL;
struct urb *urb;
- unsigned int ret = 0;
+ int ret = 0;
int rem, cnt;
if (*pos)
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index a9666373af6b..62ff1fa1c753 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -2610,6 +2610,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
del_timer_sync(&hdw->encoder_run_timer);
del_timer_sync(&hdw->encoder_wait_timer);
flush_work(&hdw->workpoll);
+ v4l2_device_unregister(&hdw->v4l2_dev);
usb_free_urb(hdw->ctl_read_urb);
usb_free_urb(hdw->ctl_write_urb);
kfree(hdw->ctl_read_buffer);
@@ -5040,7 +5041,7 @@ void pvr2_hdw_status_poll(struct pvr2_hdw *hdw)
/* Note: There apparently is no replacement for VIDIOC_CROPCAP
using v4l2-subdev - therefore we can't support that AT ALL right
now. (Of course, no sub-drivers seem to implement it either.
- But now it's a a chicken and egg problem...) */
+ But now it's a chicken and egg problem...) */
v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner, vtp);
pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll type=%u strength=%u audio=0x%x cap=0x%x low=%u hi=%u",
vtp->type,
diff --git a/drivers/media/usb/stkwebcam/Kconfig b/drivers/media/usb/stkwebcam/Kconfig
deleted file mode 100644
index d94d023f1aa0..000000000000
--- a/drivers/media/usb/stkwebcam/Kconfig
+++ /dev/null
@@ -1,14 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config USB_STKWEBCAM
- tristate "USB Syntek DC1125 Camera support"
- depends on VIDEO_DEV
- help
- Say Y here if you want to use this type of camera.
- Supported devices are typically found in some Asus laptops,
- with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
- may be supported by the stk11xx driver, from which this is
- derived, see <http://sourceforge.net/projects/syntekdriver/>
-
- To compile this driver as a module, choose M here: the
- module will be called stkwebcam.
-
diff --git a/drivers/media/usb/stkwebcam/Makefile b/drivers/media/usb/stkwebcam/Makefile
deleted file mode 100644
index daa9ae6d48c2..000000000000
--- a/drivers/media/usb/stkwebcam/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-stkwebcam-objs := stk-webcam.o stk-sensor.o
-
-obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o
-
diff --git a/drivers/media/usb/stkwebcam/stk-sensor.c b/drivers/media/usb/stkwebcam/stk-sensor.c
deleted file mode 100644
index 94aa6a27f934..000000000000
--- a/drivers/media/usb/stkwebcam/stk-sensor.c
+++ /dev/null
@@ -1,587 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* stk-sensor.c: Driver for ov96xx sensor (used in some Syntek webcams)
- *
- * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
- *
- * Some parts derived from ov7670.c:
- * Copyright 2006 One Laptop Per Child Association, Inc. Written
- * by Jonathan Corbet with substantial inspiration from Mark
- * McClelland's ovcamchip code.
- *
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- *
- * This file may be distributed under the terms of the GNU General
- */
-
-/* Controlling the sensor via the STK1125 vendor specific control interface:
- * The camera uses an OmniVision sensor and the stk1125 provides an
- * SCCB(i2c)-USB bridge which let us program the sensor.
- * In my case the sensor id is 0x9652, it can be read from sensor's register
- * 0x0A and 0x0B as follows:
- * - read register #R:
- * output #R to index 0x0208
- * output 0x0070 to index 0x0200
- * input 1 byte from index 0x0201 (some kind of status register)
- * until its value is 0x01
- * input 1 byte from index 0x0209. This is the value of #R
- * - write value V to register #R
- * output #R to index 0x0204
- * output V to index 0x0205
- * output 0x0005 to index 0x0200
- * input 1 byte from index 0x0201 until its value becomes 0x04
- */
-
-/* It seems the i2c bus is controlled with these registers */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include "stk-webcam.h"
-
-#define STK_IIC_BASE (0x0200)
-# define STK_IIC_OP (STK_IIC_BASE)
-# define STK_IIC_OP_TX (0x05)
-# define STK_IIC_OP_RX (0x70)
-# define STK_IIC_STAT (STK_IIC_BASE+1)
-# define STK_IIC_STAT_TX_OK (0x04)
-# define STK_IIC_STAT_RX_OK (0x01)
-/* I don't know what does this register.
- * when it is 0x00 or 0x01, we cannot talk to the sensor,
- * other values work */
-# define STK_IIC_ENABLE (STK_IIC_BASE+2)
-# define STK_IIC_ENABLE_NO (0x00)
-/* This is what the driver writes in windows */
-# define STK_IIC_ENABLE_YES (0x1e)
-/*
- * Address of the slave. Seems like the binary driver look for the
- * sensor in multiple places, attempting a reset sequence.
- * We only know about the ov9650
- */
-# define STK_IIC_ADDR (STK_IIC_BASE+3)
-# define STK_IIC_TX_INDEX (STK_IIC_BASE+4)
-# define STK_IIC_TX_VALUE (STK_IIC_BASE+5)
-# define STK_IIC_RX_INDEX (STK_IIC_BASE+8)
-# define STK_IIC_RX_VALUE (STK_IIC_BASE+9)
-
-#define MAX_RETRIES (50)
-
-#define SENSOR_ADDRESS (0x60)
-
-/* From ov7670.c (These registers aren't fully accurate) */
-
-/* Registers */
-#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
-#define REG_BLUE 0x01 /* blue gain */
-#define REG_RED 0x02 /* red gain */
-#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
-#define REG_COM1 0x04 /* Control 1 */
-#define COM1_CCIR656 0x40 /* CCIR656 enable */
-#define COM1_QFMT 0x20 /* QVGA/QCIF format */
-#define COM1_SKIP_0 0x00 /* Do not skip any row */
-#define COM1_SKIP_2 0x04 /* Skip 2 rows of 4 */
-#define COM1_SKIP_3 0x08 /* Skip 3 rows of 4 */
-#define REG_BAVE 0x05 /* U/B Average level */
-#define REG_GbAVE 0x06 /* Y/Gb Average level */
-#define REG_AECHH 0x07 /* AEC MS 5 bits */
-#define REG_RAVE 0x08 /* V/R Average level */
-#define REG_COM2 0x09 /* Control 2 */
-#define COM2_SSLEEP 0x10 /* Soft sleep mode */
-#define REG_PID 0x0a /* Product ID MSB */
-#define REG_VER 0x0b /* Product ID LSB */
-#define REG_COM3 0x0c /* Control 3 */
-#define COM3_SWAP 0x40 /* Byte swap */
-#define COM3_SCALEEN 0x08 /* Enable scaling */
-#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */
-#define REG_COM4 0x0d /* Control 4 */
-#define REG_COM5 0x0e /* All "reserved" */
-#define REG_COM6 0x0f /* Control 6 */
-#define REG_AECH 0x10 /* More bits of AEC value */
-#define REG_CLKRC 0x11 /* Clock control */
-#define CLK_PLL 0x80 /* Enable internal PLL */
-#define CLK_EXT 0x40 /* Use external clock directly */
-#define CLK_SCALE 0x3f /* Mask for internal clock scale */
-#define REG_COM7 0x12 /* Control 7 */
-#define COM7_RESET 0x80 /* Register reset */
-#define COM7_FMT_MASK 0x38
-#define COM7_FMT_SXGA 0x00
-#define COM7_FMT_VGA 0x40
-#define COM7_FMT_CIF 0x20 /* CIF format */
-#define COM7_FMT_QVGA 0x10 /* QVGA format */
-#define COM7_FMT_QCIF 0x08 /* QCIF format */
-#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */
-#define COM7_YUV 0x00 /* YUV */
-#define COM7_BAYER 0x01 /* Bayer format */
-#define COM7_PBAYER 0x05 /* "Processed bayer" */
-#define REG_COM8 0x13 /* Control 8 */
-#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
-#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */
-#define COM8_BFILT 0x20 /* Band filter enable */
-#define COM8_AGC 0x04 /* Auto gain enable */
-#define COM8_AWB 0x02 /* White balance enable */
-#define COM8_AEC 0x01 /* Auto exposure enable */
-#define REG_COM9 0x14 /* Control 9 - gain ceiling */
-#define REG_COM10 0x15 /* Control 10 */
-#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */
-#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */
-#define COM10_HREF_REV 0x08 /* Reverse HREF */
-#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */
-#define COM10_VS_NEG 0x02 /* VSYNC negative */
-#define COM10_HS_NEG 0x01 /* HSYNC negative */
-#define REG_HSTART 0x17 /* Horiz start high bits */
-#define REG_HSTOP 0x18 /* Horiz stop high bits */
-#define REG_VSTART 0x19 /* Vert start high bits */
-#define REG_VSTOP 0x1a /* Vert stop high bits */
-#define REG_PSHFT 0x1b /* Pixel delay after HREF */
-#define REG_MIDH 0x1c /* Manuf. ID high */
-#define REG_MIDL 0x1d /* Manuf. ID low */
-#define REG_MVFP 0x1e /* Mirror / vflip */
-#define MVFP_MIRROR 0x20 /* Mirror image */
-#define MVFP_FLIP 0x10 /* Vertical flip */
-
-#define REG_AEW 0x24 /* AGC upper limit */
-#define REG_AEB 0x25 /* AGC lower limit */
-#define REG_VPT 0x26 /* AGC/AEC fast mode op region */
-#define REG_ADVFL 0x2d /* Insert dummy lines (LSB) */
-#define REG_ADVFH 0x2e /* Insert dummy lines (MSB) */
-#define REG_HSYST 0x30 /* HSYNC rising edge delay */
-#define REG_HSYEN 0x31 /* HSYNC falling edge delay */
-#define REG_HREF 0x32 /* HREF pieces */
-#define REG_TSLB 0x3a /* lots of stuff */
-#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */
-#define TSLB_BYTEORD 0x08 /* swap bytes in 16bit mode? */
-#define REG_COM11 0x3b /* Control 11 */
-#define COM11_NIGHT 0x80 /* NIght mode enable */
-#define COM11_NMFR 0x60 /* Two bit NM frame rate */
-#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
-#define COM11_50HZ 0x08 /* Manual 50Hz select */
-#define COM11_EXP 0x02
-#define REG_COM12 0x3c /* Control 12 */
-#define COM12_HREF 0x80 /* HREF always */
-#define REG_COM13 0x3d /* Control 13 */
-#define COM13_GAMMA 0x80 /* Gamma enable */
-#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */
-#define COM13_CMATRIX 0x10 /* Enable color matrix for RGB or YUV */
-#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */
-#define REG_COM14 0x3e /* Control 14 */
-#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */
-#define REG_EDGE 0x3f /* Edge enhancement factor */
-#define REG_COM15 0x40 /* Control 15 */
-#define COM15_R10F0 0x00 /* Data range 10 to F0 */
-#define COM15_R01FE 0x80 /* 01 to FE */
-#define COM15_R00FF 0xc0 /* 00 to FF */
-#define COM15_RGB565 0x10 /* RGB565 output */
-#define COM15_RGBFIXME 0x20 /* FIXME */
-#define COM15_RGB555 0x30 /* RGB555 output */
-#define REG_COM16 0x41 /* Control 16 */
-#define COM16_AWBGAIN 0x08 /* AWB gain enable */
-#define REG_COM17 0x42 /* Control 17 */
-#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */
-#define COM17_CBAR 0x08 /* DSP Color bar */
-
-/*
- * This matrix defines how the colors are generated, must be
- * tweaked to adjust hue and saturation.
- *
- * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
- *
- * They are nine-bit signed quantities, with the sign bit
- * stored in 0x58. Sign for v-red is bit 0, and up from there.
- */
-#define REG_CMATRIX_BASE 0x4f
-#define CMATRIX_LEN 6
-#define REG_CMATRIX_SIGN 0x58
-
-
-#define REG_BRIGHT 0x55 /* Brightness */
-#define REG_CONTRAS 0x56 /* Contrast control */
-
-#define REG_GFIX 0x69 /* Fix gain control */
-
-#define REG_RGB444 0x8c /* RGB 444 control */
-#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */
-#define R444_RGBX 0x01 /* Empty nibble at end */
-
-#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */
-#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
-
-#define REG_BD50MAX 0xa5 /* 50hz banding step limit */
-#define REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
-#define REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
-#define REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
-#define REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
-#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
-#define REG_BD60MAX 0xab /* 60hz banding step limit */
-
-
-
-
-/* Returns 0 if OK */
-static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val)
-{
- int i = 0;
- u8 tmpval = 0;
-
- if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg))
- return 1;
- if (stk_camera_write_reg(dev, STK_IIC_TX_VALUE, val))
- return 1;
- if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_TX))
- return 1;
- do {
- if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
- return 1;
- i++;
- } while (tmpval == 0 && i < MAX_RETRIES);
- if (tmpval != STK_IIC_STAT_TX_OK) {
- if (tmpval)
- pr_err("stk_sensor_outb failed, status=0x%02x\n",
- tmpval);
- return 1;
- } else
- return 0;
-}
-
-static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val)
-{
- int i = 0;
- u8 tmpval = 0;
-
- if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg))
- return 1;
- if (stk_camera_write_reg(dev, STK_IIC_OP, STK_IIC_OP_RX))
- return 1;
- do {
- if (stk_camera_read_reg(dev, STK_IIC_STAT, &tmpval))
- return 1;
- i++;
- } while (tmpval == 0 && i < MAX_RETRIES);
- if (tmpval != STK_IIC_STAT_RX_OK) {
- if (tmpval)
- pr_err("stk_sensor_inb failed, status=0x%02x\n",
- tmpval);
- return 1;
- }
-
- if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval))
- return 1;
-
- *val = tmpval;
- return 0;
-}
-
-static int stk_sensor_write_regvals(struct stk_camera *dev,
- struct regval *rv)
-{
- int ret;
- if (rv == NULL)
- return 0;
- while (rv->reg != 0xff || rv->val != 0xff) {
- ret = stk_sensor_outb(dev, rv->reg, rv->val);
- if (ret != 0)
- return ret;
- rv++;
- }
- return 0;
-}
-
-int stk_sensor_sleep(struct stk_camera *dev)
-{
- u8 tmp;
- return stk_sensor_inb(dev, REG_COM2, &tmp)
- || stk_sensor_outb(dev, REG_COM2, tmp|COM2_SSLEEP);
-}
-
-int stk_sensor_wakeup(struct stk_camera *dev)
-{
- u8 tmp;
- return stk_sensor_inb(dev, REG_COM2, &tmp)
- || stk_sensor_outb(dev, REG_COM2, tmp&~COM2_SSLEEP);
-}
-
-static struct regval ov_initvals[] = {
- {REG_CLKRC, CLK_PLL},
- {REG_COM11, 0x01},
- {0x6a, 0x7d},
- {REG_AECH, 0x40},
- {REG_GAIN, 0x00},
- {REG_BLUE, 0x80},
- {REG_RED, 0x80},
- /* Do not enable fast AEC for now */
- /*{REG_COM8, COM8_FASTAEC|COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},*/
- {REG_COM8, COM8_AECSTEP|COM8_BFILT|COM8_AGC|COM8_AEC},
- {0x39, 0x50}, {0x38, 0x93},
- {0x37, 0x00}, {0x35, 0x81},
- {REG_COM5, 0x20},
- {REG_COM1, 0x00},
- {REG_COM3, 0x00},
- {REG_COM4, 0x00},
- {REG_PSHFT, 0x00},
- {0x16, 0x07},
- {0x33, 0xe2}, {0x34, 0xbf},
- {REG_COM16, 0x00},
- {0x96, 0x04},
- /* Gamma curve values */
-/* { 0x7a, 0x20 }, { 0x7b, 0x10 },
- { 0x7c, 0x1e }, { 0x7d, 0x35 },
- { 0x7e, 0x5a }, { 0x7f, 0x69 },
- { 0x80, 0x76 }, { 0x81, 0x80 },
- { 0x82, 0x88 }, { 0x83, 0x8f },
- { 0x84, 0x96 }, { 0x85, 0xa3 },
- { 0x86, 0xaf }, { 0x87, 0xc4 },
- { 0x88, 0xd7 }, { 0x89, 0xe8 },
-*/
- {REG_GFIX, 0x40},
- {0x8e, 0x00},
- {REG_COM12, 0x73},
- {0x8f, 0xdf}, {0x8b, 0x06},
- {0x8c, 0x20},
- {0x94, 0x88}, {0x95, 0x88},
-/* {REG_COM15, 0xc1}, TODO */
- {0x29, 0x3f},
- {REG_COM6, 0x42},
- {REG_BD50MAX, 0x80},
- {REG_HAECC6, 0xb8}, {REG_HAECC7, 0x92},
- {REG_BD60MAX, 0x0a},
- {0x90, 0x00}, {0x91, 0x00},
- {REG_HAECC1, 0x00}, {REG_HAECC2, 0x00},
- {REG_AEW, 0x68}, {REG_AEB, 0x5c},
- {REG_VPT, 0xc3},
- {REG_COM9, 0x2e},
- {0x2a, 0x00}, {0x2b, 0x00},
-
- {0xff, 0xff}, /* END MARKER */
-};
-
-/* Probe the I2C bus and initialise the sensor chip */
-int stk_sensor_init(struct stk_camera *dev)
-{
- u8 idl = 0;
- u8 idh = 0;
-
- if (stk_camera_write_reg(dev, STK_IIC_ENABLE, STK_IIC_ENABLE_YES)
- || stk_camera_write_reg(dev, STK_IIC_ADDR, SENSOR_ADDRESS)
- || stk_sensor_outb(dev, REG_COM7, COM7_RESET)) {
- pr_err("Sensor resetting failed\n");
- return -ENODEV;
- }
- msleep(10);
- /* Read the manufacturer ID: ov = 0x7FA2 */
- if (stk_sensor_inb(dev, REG_MIDH, &idh)
- || stk_sensor_inb(dev, REG_MIDL, &idl)) {
- pr_err("Strange error reading sensor ID\n");
- return -ENODEV;
- }
- if (idh != 0x7f || idl != 0xa2) {
- pr_err("Huh? you don't have a sensor from ovt\n");
- return -ENODEV;
- }
- if (stk_sensor_inb(dev, REG_PID, &idh)
- || stk_sensor_inb(dev, REG_VER, &idl)) {
- pr_err("Could not read sensor model\n");
- return -ENODEV;
- }
- stk_sensor_write_regvals(dev, ov_initvals);
- msleep(10);
- pr_info("OmniVision sensor detected, id %02X%02X at address %x\n",
- idh, idl, SENSOR_ADDRESS);
- return 0;
-}
-
-/* V4L2_PIX_FMT_UYVY */
-static struct regval ov_fmt_uyvy[] = {
- {REG_TSLB, TSLB_YLAST|0x08 },
- { 0x4f, 0x80 }, /* "matrix coefficient 1" */
- { 0x50, 0x80 }, /* "matrix coefficient 2" */
- { 0x51, 0 }, /* vb */
- { 0x52, 0x22 }, /* "matrix coefficient 4" */
- { 0x53, 0x5e }, /* "matrix coefficient 5" */
- { 0x54, 0x80 }, /* "matrix coefficient 6" */
- {REG_COM13, COM13_UVSAT|COM13_CMATRIX},
- {REG_COM15, COM15_R00FF },
- {0xff, 0xff}, /* END MARKER */
-};
-/* V4L2_PIX_FMT_YUYV */
-static struct regval ov_fmt_yuyv[] = {
- {REG_TSLB, 0 },
- { 0x4f, 0x80 }, /* "matrix coefficient 1" */
- { 0x50, 0x80 }, /* "matrix coefficient 2" */
- { 0x51, 0 }, /* vb */
- { 0x52, 0x22 }, /* "matrix coefficient 4" */
- { 0x53, 0x5e }, /* "matrix coefficient 5" */
- { 0x54, 0x80 }, /* "matrix coefficient 6" */
- {REG_COM13, COM13_UVSAT|COM13_CMATRIX},
- {REG_COM15, COM15_R00FF },
- {0xff, 0xff}, /* END MARKER */
-};
-
-/* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */
-static struct regval ov_fmt_rgbr[] = {
- { REG_RGB444, 0 }, /* No RGB444 please */
- {REG_TSLB, 0x00},
- { REG_COM1, 0x0 },
- { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */
- { 0x4f, 0xb3 }, /* "matrix coefficient 1" */
- { 0x50, 0xb3 }, /* "matrix coefficient 2" */
- { 0x51, 0 }, /* vb */
- { 0x52, 0x3d }, /* "matrix coefficient 4" */
- { 0x53, 0xa7 }, /* "matrix coefficient 5" */
- { 0x54, 0xe4 }, /* "matrix coefficient 6" */
- { REG_COM13, COM13_GAMMA },
- { REG_COM15, COM15_RGB565|COM15_R00FF },
- { 0xff, 0xff },
-};
-
-/* V4L2_PIX_FMT_RGB565 gggbbbbb rrrrrggg */
-static struct regval ov_fmt_rgbp[] = {
- { REG_RGB444, 0 }, /* No RGB444 please */
- {REG_TSLB, TSLB_BYTEORD },
- { REG_COM1, 0x0 },
- { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */
- { 0x4f, 0xb3 }, /* "matrix coefficient 1" */
- { 0x50, 0xb3 }, /* "matrix coefficient 2" */
- { 0x51, 0 }, /* vb */
- { 0x52, 0x3d }, /* "matrix coefficient 4" */
- { 0x53, 0xa7 }, /* "matrix coefficient 5" */
- { 0x54, 0xe4 }, /* "matrix coefficient 6" */
- { REG_COM13, COM13_GAMMA },
- { REG_COM15, COM15_RGB565|COM15_R00FF },
- { 0xff, 0xff },
-};
-
-/* V4L2_PIX_FMT_SRGGB8 */
-static struct regval ov_fmt_bayer[] = {
- /* This changes color order */
- {REG_TSLB, 0x40}, /* BGGR */
- /* {REG_TSLB, 0x08}, */ /* BGGR with vertical image flipping */
- {REG_COM15, COM15_R00FF },
- {0xff, 0xff}, /* END MARKER */
-};
-/*
- * Store a set of start/stop values into the camera.
- */
-static int stk_sensor_set_hw(struct stk_camera *dev,
- int hstart, int hstop, int vstart, int vstop)
-{
- int ret;
- unsigned char v;
-/*
- * Horizontal: 11 bits, top 8 live in hstart and hstop. Bottom 3 of
- * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is
- * a mystery "edge offset" value in the top two bits of href.
- */
- ret = stk_sensor_outb(dev, REG_HSTART, (hstart >> 3) & 0xff);
- ret += stk_sensor_outb(dev, REG_HSTOP, (hstop >> 3) & 0xff);
- ret += stk_sensor_inb(dev, REG_HREF, &v);
- v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7);
- msleep(10);
- ret += stk_sensor_outb(dev, REG_HREF, v);
-/*
- * Vertical: similar arrangement (note: this is different from ov7670.c)
- */
- ret += stk_sensor_outb(dev, REG_VSTART, (vstart >> 3) & 0xff);
- ret += stk_sensor_outb(dev, REG_VSTOP, (vstop >> 3) & 0xff);
- ret += stk_sensor_inb(dev, REG_VREF, &v);
- v = (v & 0xc0) | ((vstop & 0x7) << 3) | (vstart & 0x7);
- msleep(10);
- ret += stk_sensor_outb(dev, REG_VREF, v);
- return ret;
-}
-
-
-int stk_sensor_configure(struct stk_camera *dev)
-{
- int com7;
- /*
- * We setup the sensor to output dummy lines in low-res modes,
- * so we don't get absurdly hight framerates.
- */
- unsigned dummylines;
- int flip;
- struct regval *rv;
-
- switch (dev->vsettings.mode) {
- case MODE_QCIF: com7 = COM7_FMT_QCIF;
- dummylines = 604;
- break;
- case MODE_QVGA: com7 = COM7_FMT_QVGA;
- dummylines = 267;
- break;
- case MODE_CIF: com7 = COM7_FMT_CIF;
- dummylines = 412;
- break;
- case MODE_VGA: com7 = COM7_FMT_VGA;
- dummylines = 11;
- break;
- case MODE_SXGA: com7 = COM7_FMT_SXGA;
- dummylines = 0;
- break;
- default:
- pr_err("Unsupported mode %d\n", dev->vsettings.mode);
- return -EFAULT;
- }
- switch (dev->vsettings.palette) {
- case V4L2_PIX_FMT_UYVY:
- com7 |= COM7_YUV;
- rv = ov_fmt_uyvy;
- break;
- case V4L2_PIX_FMT_YUYV:
- com7 |= COM7_YUV;
- rv = ov_fmt_yuyv;
- break;
- case V4L2_PIX_FMT_RGB565:
- com7 |= COM7_RGB;
- rv = ov_fmt_rgbp;
- break;
- case V4L2_PIX_FMT_RGB565X:
- com7 |= COM7_RGB;
- rv = ov_fmt_rgbr;
- break;
- case V4L2_PIX_FMT_SBGGR8:
- com7 |= COM7_PBAYER;
- rv = ov_fmt_bayer;
- break;
- default:
- pr_err("Unsupported colorspace\n");
- return -EFAULT;
- }
- /*FIXME sometimes the sensor go to a bad state
- stk_sensor_write_regvals(dev, ov_initvals); */
- stk_sensor_outb(dev, REG_COM7, com7);
- msleep(50);
- stk_sensor_write_regvals(dev, rv);
- flip = (dev->vsettings.vflip?MVFP_FLIP:0)
- | (dev->vsettings.hflip?MVFP_MIRROR:0);
- stk_sensor_outb(dev, REG_MVFP, flip);
- if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8
- && !dev->vsettings.vflip)
- stk_sensor_outb(dev, REG_TSLB, 0x08);
- stk_sensor_outb(dev, REG_ADVFH, dummylines >> 8);
- stk_sensor_outb(dev, REG_ADVFL, dummylines & 0xff);
- msleep(50);
- switch (dev->vsettings.mode) {
- case MODE_VGA:
- if (stk_sensor_set_hw(dev, 302, 1582, 6, 486))
- pr_err("stk_sensor_set_hw failed (VGA)\n");
- break;
- case MODE_SXGA:
- case MODE_CIF:
- case MODE_QVGA:
- case MODE_QCIF:
- /*FIXME These settings seem ignored by the sensor
- if (stk_sensor_set_hw(dev, 220, 1500, 10, 1034))
- pr_err("stk_sensor_set_hw failed (SXGA)\n");
- */
- break;
- }
- msleep(10);
- return 0;
-}
-
-int stk_sensor_set_brightness(struct stk_camera *dev, int br)
-{
- if (br < 0 || br > 0xff)
- return -EINVAL;
- stk_sensor_outb(dev, REG_AEB, max(0x00, br - 6));
- stk_sensor_outb(dev, REG_AEW, min(0xff, br + 6));
- return 0;
-}
-
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
deleted file mode 100644
index 787edb3d47c2..000000000000
--- a/drivers/media/usb/stkwebcam/stk-webcam.c
+++ /dev/null
@@ -1,1434 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * stk-webcam.c : Driver for Syntek 1125 USB webcam controller
- *
- * Copyright (C) 2006 Nicolas VIVIEN
- * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
- *
- * Some parts are inspired from cafe_ccic.c
- * Copyright 2006-2007 Jonathan Corbet
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-
-#include <linux/dmi.h>
-#include <linux/usb.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-event.h>
-
-#include "stk-webcam.h"
-
-
-static int hflip = -1;
-module_param(hflip, int, 0444);
-MODULE_PARM_DESC(hflip, "Horizontal image flip (mirror). Defaults to 0");
-
-static int vflip = -1;
-module_param(vflip, int, 0444);
-MODULE_PARM_DESC(vflip, "Vertical image flip. Defaults to 0");
-
-static int debug;
-module_param(debug, int, 0444);
-MODULE_PARM_DESC(debug, "Debug v4l ioctls. Defaults to 0");
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN");
-MODULE_DESCRIPTION("Syntek DC1125 webcam driver");
-
-/* Some cameras have audio interfaces, we aren't interested in those */
-static const struct usb_device_id stkwebcam_table[] = {
- { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(0x05e1, 0x0501, 0xff, 0xff, 0xff) },
- { }
-};
-MODULE_DEVICE_TABLE(usb, stkwebcam_table);
-
-/*
- * The stk webcam laptop module is mounted upside down in some laptops :(
- *
- * Some background information (thanks to Hans de Goede for providing this):
- *
- * 1) Once upon a time the stkwebcam driver was written
- *
- * 2) The webcam in question was used mostly in Asus laptop models, including
- * the laptop of the original author of the driver, and in these models, in
- * typical Asus fashion (see the long long list for uvc cams inside v4l-utils),
- * they mounted the webcam-module the wrong way up. So the hflip and vflip
- * module options were given a default value of 1 (the correct value for
- * upside down mounted models)
- *
- * 3) Years later I got a bug report from a user with a laptop with stkwebcam,
- * where the module was actually mounted the right way up, and thus showed
- * upside down under Linux. So now I was facing the choice of 2 options:
- *
- * a) Add a not-upside-down list to stkwebcam, which overrules the default.
- *
- * b) Do it like all the other drivers do, and make the default right for
- * cams mounted the proper way and add an upside-down model list, with
- * models where we need to flip-by-default.
- *
- * Despite knowing that going b) would cause a period of pain where we were
- * building the table I opted to go for option b), since a) is just too ugly,
- * and worse different from how every other driver does it leading to
- * confusion in the long run. This change was made in kernel 3.6.
- *
- * So for any user report about upside-down images since kernel 3.6 ask them
- * to provide the output of 'sudo dmidecode' so the laptop can be added in
- * the table below.
- */
-static const struct dmi_system_id stk_upside_down_dmi_table[] = {
- {
- .ident = "ASUS G1",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "G1")
- }
- }, {
- .ident = "ASUS F3JC",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "F3JC")
- }
- },
- {
- .ident = "T12Rg-H",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "HCL Infosystems Limited"),
- DMI_MATCH(DMI_PRODUCT_NAME, "T12Rg-H")
- }
- },
- {
- .ident = "ASUS A6VM",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6VM")
- }
- },
- {
- .ident = "ASUS A6JC",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "A6JC")
- }
- },
- {}
-};
-
-
-/*
- * Basic stuff
- */
-int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value)
-{
- struct usb_device *udev = dev->udev;
- int ret;
-
- ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- 0x01,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- index,
- NULL,
- 0,
- 500);
- if (ret < 0)
- return ret;
- else
- return 0;
-}
-
-int stk_camera_read_reg(struct stk_camera *dev, u16 index, u8 *value)
-{
- struct usb_device *udev = dev->udev;
- int ret;
-
- ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- 0x00,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x00,
- index,
- &dev->read_reg_scratch,
- sizeof(u8),
- 500);
- if (ret >= 0)
- *value = dev->read_reg_scratch;
-
- if (ret < 0)
- return ret;
- else
- return 0;
-}
-
-static int stk_start_stream(struct stk_camera *dev)
-{
- u8 value;
- int i, ret;
- u8 value_116, value_117;
-
-
- if (!is_present(dev))
- return -ENODEV;
- if (!is_memallocd(dev) || !is_initialised(dev)) {
- pr_err("FIXME: Buffers are not allocated\n");
- return -EFAULT;
- }
- ret = usb_set_interface(dev->udev, 0, 5);
-
- if (ret < 0)
- pr_err("usb_set_interface failed !\n");
- if (stk_sensor_wakeup(dev))
- pr_err("error awaking the sensor\n");
-
- stk_camera_read_reg(dev, 0x0116, &value_116);
- stk_camera_read_reg(dev, 0x0117, &value_117);
-
- stk_camera_write_reg(dev, 0x0116, 0x0000);
- stk_camera_write_reg(dev, 0x0117, 0x0000);
-
- stk_camera_read_reg(dev, 0x0100, &value);
- stk_camera_write_reg(dev, 0x0100, value | 0x80);
-
- stk_camera_write_reg(dev, 0x0116, value_116);
- stk_camera_write_reg(dev, 0x0117, value_117);
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- if (dev->isobufs[i].urb) {
- ret = usb_submit_urb(dev->isobufs[i].urb, GFP_KERNEL);
- atomic_inc(&dev->urbs_used);
- if (ret)
- return ret;
- }
- }
- set_streaming(dev);
- return 0;
-}
-
-static int stk_stop_stream(struct stk_camera *dev)
-{
- u8 value;
- int i;
- if (is_present(dev)) {
- stk_camera_read_reg(dev, 0x0100, &value);
- stk_camera_write_reg(dev, 0x0100, value & ~0x80);
- if (dev->isobufs != NULL) {
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- if (dev->isobufs[i].urb)
- usb_kill_urb(dev->isobufs[i].urb);
- }
- }
- unset_streaming(dev);
-
- if (usb_set_interface(dev->udev, 0, 0))
- pr_err("usb_set_interface failed !\n");
- if (stk_sensor_sleep(dev))
- pr_err("error suspending the sensor\n");
- }
- return 0;
-}
-
-/*
- * This seems to be the shortest init sequence we
- * must do in order to find the sensor
- * Bit 5 of reg. 0x0000 here is important, when reset to 0 the sensor
- * is also reset. Maybe powers down it?
- * Rest of values don't make a difference
- */
-
-static struct regval stk1125_initvals[] = {
- /*TODO: What means this sequence? */
- {0x0000, 0x24},
- {0x0100, 0x21},
- {0x0002, 0x68},
- {0x0003, 0x80},
- {0x0005, 0x00},
- {0x0007, 0x03},
- {0x000d, 0x00},
- {0x000f, 0x02},
- {0x0300, 0x12},
- {0x0350, 0x41},
- {0x0351, 0x00},
- {0x0352, 0x00},
- {0x0353, 0x00},
- {0x0018, 0x10},
- {0x0019, 0x00},
- {0x001b, 0x0e},
- {0x001c, 0x46},
- {0x0300, 0x80},
- {0x001a, 0x04},
- {0x0110, 0x00},
- {0x0111, 0x00},
- {0x0112, 0x00},
- {0x0113, 0x00},
-
- {0xffff, 0xff},
-};
-
-
-static int stk_initialise(struct stk_camera *dev)
-{
- struct regval *rv;
- int ret;
- if (!is_present(dev))
- return -ENODEV;
- if (is_initialised(dev))
- return 0;
- rv = stk1125_initvals;
- while (rv->reg != 0xffff) {
- ret = stk_camera_write_reg(dev, rv->reg, rv->val);
- if (ret)
- return ret;
- rv++;
- }
- if (stk_sensor_init(dev) == 0) {
- set_initialised(dev);
- return 0;
- } else
- return -1;
-}
-
-/* *********************************************** */
-/*
- * This function is called as an URB transfert is complete (Isochronous pipe).
- * So, the traitement is done in interrupt time, so it has be fast, not crash,
- * and not stall. Neat.
- */
-static void stk_isoc_handler(struct urb *urb)
-{
- int i;
- int ret;
- int framelen;
- unsigned long flags;
-
- unsigned char *fill = NULL;
- unsigned char *iso_buf = NULL;
-
- struct stk_camera *dev;
- struct stk_sio_buffer *fb;
-
- dev = (struct stk_camera *) urb->context;
-
- if (dev == NULL) {
- pr_err("isoc_handler called with NULL device !\n");
- return;
- }
-
- if (urb->status == -ENOENT || urb->status == -ECONNRESET
- || urb->status == -ESHUTDOWN) {
- atomic_dec(&dev->urbs_used);
- return;
- }
-
- spin_lock_irqsave(&dev->spinlock, flags);
-
- if (urb->status != -EINPROGRESS && urb->status != 0) {
- pr_err("isoc_handler: urb->status == %d\n", urb->status);
- goto resubmit;
- }
-
- if (list_empty(&dev->sio_avail)) {
- /*FIXME Stop streaming after a while */
- pr_err_ratelimited("isoc_handler without available buffer!\n");
- goto resubmit;
- }
- fb = list_first_entry(&dev->sio_avail,
- struct stk_sio_buffer, list);
- fill = fb->buffer + fb->v4lbuf.bytesused;
-
- for (i = 0; i < urb->number_of_packets; i++) {
- if (urb->iso_frame_desc[i].status != 0) {
- if (urb->iso_frame_desc[i].status != -EXDEV)
- pr_err("Frame %d has error %d\n",
- i, urb->iso_frame_desc[i].status);
- continue;
- }
- framelen = urb->iso_frame_desc[i].actual_length;
- iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- if (framelen <= 4)
- continue; /* no data */
-
- /*
- * we found something informational from there
- * the isoc frames have to type of headers
- * type1: 00 xx 00 00 or 20 xx 00 00
- * type2: 80 xx 00 00 00 00 00 00 or a0 xx 00 00 00 00 00 00
- * xx is a sequencer which has never been seen over 0x3f
- * imho data written down looks like bayer, i see similarities
- * after every 640 bytes
- */
- if (*iso_buf & 0x80) {
- framelen -= 8;
- iso_buf += 8;
- /* This marks a new frame */
- if (fb->v4lbuf.bytesused != 0
- && fb->v4lbuf.bytesused != dev->frame_size) {
- pr_err_ratelimited("frame %d, bytesused=%d, skipping\n",
- i, fb->v4lbuf.bytesused);
- fb->v4lbuf.bytesused = 0;
- fill = fb->buffer;
- } else if (fb->v4lbuf.bytesused == dev->frame_size) {
- if (list_is_singular(&dev->sio_avail)) {
- /* Always reuse the last buffer */
- fb->v4lbuf.bytesused = 0;
- fill = fb->buffer;
- } else {
- list_move_tail(dev->sio_avail.next,
- &dev->sio_full);
- wake_up(&dev->wait_frame);
- fb = list_first_entry(&dev->sio_avail,
- struct stk_sio_buffer, list);
- fb->v4lbuf.bytesused = 0;
- fill = fb->buffer;
- }
- }
- } else {
- framelen -= 4;
- iso_buf += 4;
- }
-
- /* Our buffer is full !!! */
- if (framelen + fb->v4lbuf.bytesused > dev->frame_size) {
- pr_err_ratelimited("Frame buffer overflow, lost sync\n");
- /*FIXME Do something here? */
- continue;
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
- memcpy(fill, iso_buf, framelen);
- spin_lock_irqsave(&dev->spinlock, flags);
- fill += framelen;
-
- /* New size of our buffer */
- fb->v4lbuf.bytesused += framelen;
- }
-
-resubmit:
- spin_unlock_irqrestore(&dev->spinlock, flags);
- urb->dev = dev->udev;
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret != 0) {
- pr_err("Error (%d) re-submitting urb in stk_isoc_handler\n",
- ret);
- }
-}
-
-/* -------------------------------------------- */
-
-static int stk_prepare_iso(struct stk_camera *dev)
-{
- void *kbuf;
- int i, j;
- struct urb *urb;
- struct usb_device *udev;
-
- if (dev == NULL)
- return -ENXIO;
- udev = dev->udev;
-
- if (dev->isobufs)
- pr_err("isobufs already allocated. Bad\n");
- else
- dev->isobufs = kcalloc(MAX_ISO_BUFS, sizeof(*dev->isobufs),
- GFP_KERNEL);
- if (dev->isobufs == NULL) {
- pr_err("Unable to allocate iso buffers\n");
- return -ENOMEM;
- }
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- if (dev->isobufs[i].data == NULL) {
- kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
- if (kbuf == NULL) {
- pr_err("Failed to allocate iso buffer %d\n", i);
- goto isobufs_out;
- }
- dev->isobufs[i].data = kbuf;
- } else
- pr_err("isobuf data already allocated\n");
- if (dev->isobufs[i].urb == NULL) {
- urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
- if (urb == NULL)
- goto isobufs_out;
- dev->isobufs[i].urb = urb;
- } else {
- pr_err("Killing URB\n");
- usb_kill_urb(dev->isobufs[i].urb);
- urb = dev->isobufs[i].urb;
- }
- urb->interval = 1;
- urb->dev = udev;
- urb->pipe = usb_rcvisocpipe(udev, dev->isoc_ep);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = dev->isobufs[i].data;
- urb->transfer_buffer_length = ISO_BUFFER_SIZE;
- urb->complete = stk_isoc_handler;
- urb->context = dev;
- urb->start_frame = 0;
- urb->number_of_packets = ISO_FRAMES_PER_DESC;
-
- for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
- urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
- urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
- }
- }
- set_memallocd(dev);
- return 0;
-
-isobufs_out:
- for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].data; i++)
- kfree(dev->isobufs[i].data);
- for (i = 0; i < MAX_ISO_BUFS && dev->isobufs[i].urb; i++)
- usb_free_urb(dev->isobufs[i].urb);
- kfree(dev->isobufs);
- dev->isobufs = NULL;
- return -ENOMEM;
-}
-
-static void stk_clean_iso(struct stk_camera *dev)
-{
- int i;
-
- if (dev == NULL || dev->isobufs == NULL)
- return;
-
- for (i = 0; i < MAX_ISO_BUFS; i++) {
- struct urb *urb;
-
- urb = dev->isobufs[i].urb;
- if (urb) {
- if (atomic_read(&dev->urbs_used) && is_present(dev))
- usb_kill_urb(urb);
- usb_free_urb(urb);
- }
- kfree(dev->isobufs[i].data);
- }
- kfree(dev->isobufs);
- dev->isobufs = NULL;
- unset_memallocd(dev);
-}
-
-static int stk_setup_siobuf(struct stk_camera *dev, int index)
-{
- struct stk_sio_buffer *buf = dev->sio_bufs + index;
- INIT_LIST_HEAD(&buf->list);
- buf->v4lbuf.length = PAGE_ALIGN(dev->frame_size);
- buf->buffer = vmalloc_user(buf->v4lbuf.length);
- if (buf->buffer == NULL)
- return -ENOMEM;
- buf->mapcount = 0;
- buf->dev = dev;
- buf->v4lbuf.index = index;
- buf->v4lbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf->v4lbuf.flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- buf->v4lbuf.field = V4L2_FIELD_NONE;
- buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
- buf->v4lbuf.m.offset = 2*index*buf->v4lbuf.length;
- return 0;
-}
-
-static int stk_free_sio_buffers(struct stk_camera *dev)
-{
- int i;
- int nbufs;
- unsigned long flags;
- if (dev->n_sbufs == 0 || dev->sio_bufs == NULL)
- return 0;
- /*
- * If any buffers are mapped, we cannot free them at all.
- */
- for (i = 0; i < dev->n_sbufs; i++) {
- if (dev->sio_bufs[i].mapcount > 0)
- return -EBUSY;
- }
- /*
- * OK, let's do it.
- */
- spin_lock_irqsave(&dev->spinlock, flags);
- INIT_LIST_HEAD(&dev->sio_avail);
- INIT_LIST_HEAD(&dev->sio_full);
- nbufs = dev->n_sbufs;
- dev->n_sbufs = 0;
- spin_unlock_irqrestore(&dev->spinlock, flags);
- for (i = 0; i < nbufs; i++)
- vfree(dev->sio_bufs[i].buffer);
- kfree(dev->sio_bufs);
- dev->sio_bufs = NULL;
- return 0;
-}
-
-static int stk_prepare_sio_buffers(struct stk_camera *dev, unsigned n_sbufs)
-{
- int i;
- if (dev->sio_bufs != NULL)
- pr_err("sio_bufs already allocated\n");
- else {
- dev->sio_bufs = kcalloc(n_sbufs,
- sizeof(struct stk_sio_buffer),
- GFP_KERNEL);
- if (dev->sio_bufs == NULL)
- return -ENOMEM;
- for (i = 0; i < n_sbufs; i++) {
- if (stk_setup_siobuf(dev, i))
- return (dev->n_sbufs > 1 ? 0 : -ENOMEM);
- dev->n_sbufs = i+1;
- }
- }
- return 0;
-}
-
-static int stk_allocate_buffers(struct stk_camera *dev, unsigned n_sbufs)
-{
- int err;
- err = stk_prepare_iso(dev);
- if (err) {
- stk_clean_iso(dev);
- return err;
- }
- err = stk_prepare_sio_buffers(dev, n_sbufs);
- if (err) {
- stk_free_sio_buffers(dev);
- return err;
- }
- return 0;
-}
-
-static void stk_free_buffers(struct stk_camera *dev)
-{
- stk_clean_iso(dev);
- stk_free_sio_buffers(dev);
-}
-/* -------------------------------------------- */
-
-/* v4l file operations */
-
-static int v4l_stk_open(struct file *fp)
-{
- struct stk_camera *dev = video_drvdata(fp);
- int err;
-
- if (dev == NULL || !is_present(dev))
- return -ENXIO;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- if (!dev->first_init)
- stk_camera_write_reg(dev, 0x0, 0x24);
- else
- dev->first_init = 0;
-
- err = v4l2_fh_open(fp);
- if (!err)
- usb_autopm_get_interface(dev->interface);
- mutex_unlock(&dev->lock);
- return err;
-}
-
-static int v4l_stk_release(struct file *fp)
-{
- struct stk_camera *dev = video_drvdata(fp);
-
- mutex_lock(&dev->lock);
- if (dev->owner == fp) {
- stk_stop_stream(dev);
- stk_free_buffers(dev);
- stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */
- unset_initialised(dev);
- dev->owner = NULL;
- }
-
- usb_autopm_put_interface(dev->interface);
- mutex_unlock(&dev->lock);
- return v4l2_fh_release(fp);
-}
-
-static ssize_t stk_read(struct file *fp, char __user *buf,
- size_t count, loff_t *f_pos)
-{
- int i;
- int ret;
- unsigned long flags;
- struct stk_sio_buffer *sbuf;
- struct stk_camera *dev = video_drvdata(fp);
-
- if (!is_present(dev))
- return -EIO;
- if (dev->owner && (!dev->reading || dev->owner != fp))
- return -EBUSY;
- dev->owner = fp;
- if (!is_streaming(dev)) {
- if (stk_initialise(dev)
- || stk_allocate_buffers(dev, 3)
- || stk_start_stream(dev))
- return -ENOMEM;
- dev->reading = 1;
- spin_lock_irqsave(&dev->spinlock, flags);
- for (i = 0; i < dev->n_sbufs; i++) {
- list_add_tail(&dev->sio_bufs[i].list, &dev->sio_avail);
- dev->sio_bufs[i].v4lbuf.flags = V4L2_BUF_FLAG_QUEUED;
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
- }
- if (*f_pos == 0) {
- if (fp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
- return -EWOULDBLOCK;
- ret = wait_event_interruptible(dev->wait_frame,
- !list_empty(&dev->sio_full) || !is_present(dev));
- if (ret)
- return ret;
- if (!is_present(dev))
- return -EIO;
- }
- if (count + *f_pos > dev->frame_size)
- count = dev->frame_size - *f_pos;
- spin_lock_irqsave(&dev->spinlock, flags);
- if (list_empty(&dev->sio_full)) {
- spin_unlock_irqrestore(&dev->spinlock, flags);
- pr_err("BUG: No siobufs ready\n");
- return 0;
- }
- sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
- spin_unlock_irqrestore(&dev->spinlock, flags);
-
- if (copy_to_user(buf, sbuf->buffer + *f_pos, count))
- return -EFAULT;
-
- *f_pos += count;
-
- if (*f_pos >= dev->frame_size) {
- *f_pos = 0;
- spin_lock_irqsave(&dev->spinlock, flags);
- list_move_tail(&sbuf->list, &dev->sio_avail);
- spin_unlock_irqrestore(&dev->spinlock, flags);
- }
- return count;
-}
-
-static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
- size_t count, loff_t *f_pos)
-{
- struct stk_camera *dev = video_drvdata(fp);
- int ret;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- ret = stk_read(fp, buf, count, f_pos);
- mutex_unlock(&dev->lock);
- return ret;
-}
-
-static __poll_t v4l_stk_poll(struct file *fp, poll_table *wait)
-{
- struct stk_camera *dev = video_drvdata(fp);
- __poll_t res = v4l2_ctrl_poll(fp, wait);
-
- poll_wait(fp, &dev->wait_frame, wait);
-
- if (!is_present(dev))
- return EPOLLERR;
-
- if (!list_empty(&dev->sio_full))
- return res | EPOLLIN | EPOLLRDNORM;
-
- return res;
-}
-
-
-static void stk_v4l_vm_open(struct vm_area_struct *vma)
-{
- struct stk_sio_buffer *sbuf = vma->vm_private_data;
- sbuf->mapcount++;
-}
-static void stk_v4l_vm_close(struct vm_area_struct *vma)
-{
- struct stk_sio_buffer *sbuf = vma->vm_private_data;
- sbuf->mapcount--;
- if (sbuf->mapcount == 0)
- sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_MAPPED;
-}
-static const struct vm_operations_struct stk_v4l_vm_ops = {
- .open = stk_v4l_vm_open,
- .close = stk_v4l_vm_close
-};
-
-static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
-{
- unsigned int i;
- int ret;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- struct stk_camera *dev = video_drvdata(fp);
- struct stk_sio_buffer *sbuf = NULL;
-
- if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
- return -EINVAL;
-
- for (i = 0; i < dev->n_sbufs; i++) {
- if (dev->sio_bufs[i].v4lbuf.m.offset == offset) {
- sbuf = dev->sio_bufs + i;
- break;
- }
- }
- if (sbuf == NULL)
- return -EINVAL;
- ret = remap_vmalloc_range(vma, sbuf->buffer, 0);
- if (ret)
- return ret;
- vma->vm_flags |= VM_DONTEXPAND;
- vma->vm_private_data = sbuf;
- vma->vm_ops = &stk_v4l_vm_ops;
- sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_MAPPED;
- stk_v4l_vm_open(vma);
- return 0;
-}
-
-/* v4l ioctl handlers */
-
-static int stk_vidioc_querycap(struct file *filp,
- void *priv, struct v4l2_capability *cap)
-{
- struct stk_camera *dev = video_drvdata(filp);
-
- strscpy(cap->driver, "stk", sizeof(cap->driver));
- strscpy(cap->card, "stk", sizeof(cap->card));
- usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
- return 0;
-}
-
-static int stk_vidioc_enum_input(struct file *filp,
- void *priv, struct v4l2_input *input)
-{
- if (input->index != 0)
- return -EINVAL;
-
- strscpy(input->name, "Syntek USB Camera", sizeof(input->name));
- input->type = V4L2_INPUT_TYPE_CAMERA;
- return 0;
-}
-
-
-static int stk_vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int stk_vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int stk_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct stk_camera *dev =
- container_of(ctrl->handler, struct stk_camera, hdl);
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- return stk_sensor_set_brightness(dev, ctrl->val);
- case V4L2_CID_HFLIP:
- if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.hflip = !ctrl->val;
- else
- dev->vsettings.hflip = ctrl->val;
- return 0;
- case V4L2_CID_VFLIP:
- if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.vflip = !ctrl->val;
- else
- dev->vsettings.vflip = ctrl->val;
- return 0;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-
-static int stk_vidioc_enum_fmt_vid_cap(struct file *filp,
- void *priv, struct v4l2_fmtdesc *fmtd)
-{
- switch (fmtd->index) {
- case 0:
- fmtd->pixelformat = V4L2_PIX_FMT_RGB565;
- break;
- case 1:
- fmtd->pixelformat = V4L2_PIX_FMT_RGB565X;
- break;
- case 2:
- fmtd->pixelformat = V4L2_PIX_FMT_UYVY;
- break;
- case 3:
- fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8;
- break;
- case 4:
- fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static struct stk_size {
- unsigned w;
- unsigned h;
- enum stk_mode m;
-} stk_sizes[] = {
- { .w = 1280, .h = 1024, .m = MODE_SXGA, },
- { .w = 640, .h = 480, .m = MODE_VGA, },
- { .w = 352, .h = 288, .m = MODE_CIF, },
- { .w = 320, .h = 240, .m = MODE_QVGA, },
- { .w = 176, .h = 144, .m = MODE_QCIF, },
-};
-
-static int stk_vidioc_g_fmt_vid_cap(struct file *filp,
- void *priv, struct v4l2_format *f)
-{
- struct v4l2_pix_format *pix_format = &f->fmt.pix;
- struct stk_camera *dev = video_drvdata(filp);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(stk_sizes) &&
- stk_sizes[i].m != dev->vsettings.mode; i++)
- ;
- if (i == ARRAY_SIZE(stk_sizes)) {
- pr_err("ERROR: mode invalid\n");
- return -EINVAL;
- }
- pix_format->width = stk_sizes[i].w;
- pix_format->height = stk_sizes[i].h;
- pix_format->field = V4L2_FIELD_NONE;
- pix_format->colorspace = V4L2_COLORSPACE_SRGB;
- pix_format->pixelformat = dev->vsettings.palette;
- if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
- pix_format->bytesperline = pix_format->width;
- else
- pix_format->bytesperline = 2 * pix_format->width;
- pix_format->sizeimage = pix_format->bytesperline
- * pix_format->height;
- return 0;
-}
-
-static int stk_try_fmt_vid_cap(struct file *filp,
- struct v4l2_format *fmtd, int *idx)
-{
- int i;
- switch (fmtd->fmt.pix.pixelformat) {
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_RGB565X:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_SBGGR8:
- break;
- default:
- return -EINVAL;
- }
- for (i = 1; i < ARRAY_SIZE(stk_sizes); i++) {
- if (fmtd->fmt.pix.width > stk_sizes[i].w)
- break;
- }
- if (i == ARRAY_SIZE(stk_sizes)
- || (abs(fmtd->fmt.pix.width - stk_sizes[i-1].w)
- < abs(fmtd->fmt.pix.width - stk_sizes[i].w))) {
- fmtd->fmt.pix.height = stk_sizes[i-1].h;
- fmtd->fmt.pix.width = stk_sizes[i-1].w;
- if (idx)
- *idx = i - 1;
- } else {
- fmtd->fmt.pix.height = stk_sizes[i].h;
- fmtd->fmt.pix.width = stk_sizes[i].w;
- if (idx)
- *idx = i;
- }
-
- fmtd->fmt.pix.field = V4L2_FIELD_NONE;
- fmtd->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
- if (fmtd->fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8)
- fmtd->fmt.pix.bytesperline = fmtd->fmt.pix.width;
- else
- fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width;
- fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline
- * fmtd->fmt.pix.height;
- return 0;
-}
-
-static int stk_vidioc_try_fmt_vid_cap(struct file *filp,
- void *priv, struct v4l2_format *fmtd)
-{
- return stk_try_fmt_vid_cap(filp, fmtd, NULL);
-}
-
-static int stk_setup_format(struct stk_camera *dev)
-{
- int i = 0;
- int depth;
- if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8)
- depth = 1;
- else
- depth = 2;
- while (i < ARRAY_SIZE(stk_sizes) &&
- stk_sizes[i].m != dev->vsettings.mode)
- i++;
- if (i == ARRAY_SIZE(stk_sizes)) {
- pr_err("Something is broken in %s\n", __func__);
- return -EFAULT;
- }
- /* This registers controls some timings, not sure of what. */
- stk_camera_write_reg(dev, 0x001b, 0x0e);
- if (dev->vsettings.mode == MODE_SXGA)
- stk_camera_write_reg(dev, 0x001c, 0x0e);
- else
- stk_camera_write_reg(dev, 0x001c, 0x46);
- /*
- * Registers 0x0115 0x0114 are the size of each line (bytes),
- * regs 0x0117 0x0116 are the height of the image.
- */
- stk_camera_write_reg(dev, 0x0115,
- ((stk_sizes[i].w * depth) >> 8) & 0xff);
- stk_camera_write_reg(dev, 0x0114,
- (stk_sizes[i].w * depth) & 0xff);
- stk_camera_write_reg(dev, 0x0117,
- (stk_sizes[i].h >> 8) & 0xff);
- stk_camera_write_reg(dev, 0x0116,
- stk_sizes[i].h & 0xff);
- return stk_sensor_configure(dev);
-}
-
-static int stk_vidioc_s_fmt_vid_cap(struct file *filp,
- void *priv, struct v4l2_format *fmtd)
-{
- int ret;
- int idx;
- struct stk_camera *dev = video_drvdata(filp);
-
- if (dev == NULL)
- return -ENODEV;
- if (!is_present(dev))
- return -ENODEV;
- if (is_streaming(dev))
- return -EBUSY;
- if (dev->owner)
- return -EBUSY;
- ret = stk_try_fmt_vid_cap(filp, fmtd, &idx);
- if (ret)
- return ret;
-
- dev->vsettings.palette = fmtd->fmt.pix.pixelformat;
- stk_free_buffers(dev);
- dev->frame_size = fmtd->fmt.pix.sizeimage;
- dev->vsettings.mode = stk_sizes[idx].m;
-
- stk_initialise(dev);
- return stk_setup_format(dev);
-}
-
-static int stk_vidioc_reqbufs(struct file *filp,
- void *priv, struct v4l2_requestbuffers *rb)
-{
- struct stk_camera *dev = video_drvdata(filp);
-
- if (dev == NULL)
- return -ENODEV;
- if (rb->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
- if (is_streaming(dev)
- || (dev->owner && dev->owner != filp))
- return -EBUSY;
- stk_free_buffers(dev);
- if (rb->count == 0) {
- stk_camera_write_reg(dev, 0x0, 0x49); /* turn off the LED */
- unset_initialised(dev);
- dev->owner = NULL;
- return 0;
- }
- dev->owner = filp;
-
- /*FIXME If they ask for zero, we must stop streaming and free */
- if (rb->count < 3)
- rb->count = 3;
- /* Arbitrary limit */
- else if (rb->count > 5)
- rb->count = 5;
-
- stk_allocate_buffers(dev, rb->count);
- rb->count = dev->n_sbufs;
- return 0;
-}
-
-static int stk_vidioc_querybuf(struct file *filp,
- void *priv, struct v4l2_buffer *buf)
-{
- struct stk_camera *dev = video_drvdata(filp);
- struct stk_sio_buffer *sbuf;
-
- if (buf->index >= dev->n_sbufs)
- return -EINVAL;
- sbuf = dev->sio_bufs + buf->index;
- *buf = sbuf->v4lbuf;
- return 0;
-}
-
-static int stk_vidioc_qbuf(struct file *filp,
- void *priv, struct v4l2_buffer *buf)
-{
- struct stk_camera *dev = video_drvdata(filp);
- struct stk_sio_buffer *sbuf;
- unsigned long flags;
-
- if (buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (buf->index >= dev->n_sbufs)
- return -EINVAL;
- sbuf = dev->sio_bufs + buf->index;
- if (sbuf->v4lbuf.flags & V4L2_BUF_FLAG_QUEUED)
- return 0;
- sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_QUEUED;
- sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_DONE;
- spin_lock_irqsave(&dev->spinlock, flags);
- list_add_tail(&sbuf->list, &dev->sio_avail);
- *buf = sbuf->v4lbuf;
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return 0;
-}
-
-static int stk_vidioc_dqbuf(struct file *filp,
- void *priv, struct v4l2_buffer *buf)
-{
- struct stk_camera *dev = video_drvdata(filp);
- struct stk_sio_buffer *sbuf;
- unsigned long flags;
- int ret;
-
- if (!is_streaming(dev))
- return -EINVAL;
-
- if (filp->f_flags & O_NONBLOCK && list_empty(&dev->sio_full))
- return -EWOULDBLOCK;
- ret = wait_event_interruptible(dev->wait_frame,
- !list_empty(&dev->sio_full) || !is_present(dev));
- if (ret)
- return ret;
- if (!is_present(dev))
- return -EIO;
-
- spin_lock_irqsave(&dev->spinlock, flags);
- sbuf = list_first_entry(&dev->sio_full, struct stk_sio_buffer, list);
- list_del_init(&sbuf->list);
- spin_unlock_irqrestore(&dev->spinlock, flags);
- sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
- sbuf->v4lbuf.flags |= V4L2_BUF_FLAG_DONE;
- sbuf->v4lbuf.sequence = ++dev->sequence;
- v4l2_buffer_set_timestamp(&sbuf->v4lbuf, ktime_get_ns());
-
- *buf = sbuf->v4lbuf;
- return 0;
-}
-
-static int stk_vidioc_streamon(struct file *filp,
- void *priv, enum v4l2_buf_type type)
-{
- struct stk_camera *dev = video_drvdata(filp);
- if (is_streaming(dev))
- return 0;
- if (dev->sio_bufs == NULL)
- return -EINVAL;
- dev->sequence = 0;
- return stk_start_stream(dev);
-}
-
-static int stk_vidioc_streamoff(struct file *filp,
- void *priv, enum v4l2_buf_type type)
-{
- struct stk_camera *dev = video_drvdata(filp);
- unsigned long flags;
- int i;
- stk_stop_stream(dev);
- spin_lock_irqsave(&dev->spinlock, flags);
- INIT_LIST_HEAD(&dev->sio_avail);
- INIT_LIST_HEAD(&dev->sio_full);
- for (i = 0; i < dev->n_sbufs; i++) {
- INIT_LIST_HEAD(&dev->sio_bufs[i].list);
- dev->sio_bufs[i].v4lbuf.flags = 0;
- }
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return 0;
-}
-
-
-static int stk_vidioc_g_parm(struct file *filp,
- void *priv, struct v4l2_streamparm *sp)
-{
- /*FIXME This is not correct */
- sp->parm.capture.timeperframe.numerator = 1;
- sp->parm.capture.timeperframe.denominator = 30;
- sp->parm.capture.readbuffers = 2;
- return 0;
-}
-
-static int stk_vidioc_enum_framesizes(struct file *filp,
- void *priv, struct v4l2_frmsizeenum *frms)
-{
- if (frms->index >= ARRAY_SIZE(stk_sizes))
- return -EINVAL;
- switch (frms->pixel_format) {
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_RGB565X:
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_SBGGR8:
- frms->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- frms->discrete.width = stk_sizes[frms->index].w;
- frms->discrete.height = stk_sizes[frms->index].h;
- return 0;
- default: return -EINVAL;
- }
-}
-
-static const struct v4l2_ctrl_ops stk_ctrl_ops = {
- .s_ctrl = stk_s_ctrl,
-};
-
-static const struct v4l2_file_operations v4l_stk_fops = {
- .owner = THIS_MODULE,
- .open = v4l_stk_open,
- .release = v4l_stk_release,
- .read = v4l_stk_read,
- .poll = v4l_stk_poll,
- .mmap = v4l_stk_mmap,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = {
- .vidioc_querycap = stk_vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = stk_vidioc_s_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = stk_vidioc_g_fmt_vid_cap,
- .vidioc_enum_input = stk_vidioc_enum_input,
- .vidioc_s_input = stk_vidioc_s_input,
- .vidioc_g_input = stk_vidioc_g_input,
- .vidioc_reqbufs = stk_vidioc_reqbufs,
- .vidioc_querybuf = stk_vidioc_querybuf,
- .vidioc_qbuf = stk_vidioc_qbuf,
- .vidioc_dqbuf = stk_vidioc_dqbuf,
- .vidioc_streamon = stk_vidioc_streamon,
- .vidioc_streamoff = stk_vidioc_streamoff,
- .vidioc_g_parm = stk_vidioc_g_parm,
- .vidioc_enum_framesizes = stk_vidioc_enum_framesizes,
- .vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static void stk_v4l_dev_release(struct video_device *vd)
-{
- struct stk_camera *dev = vdev_to_camera(vd);
-
- if (dev->sio_bufs != NULL || dev->isobufs != NULL)
- pr_err("We are leaking memory\n");
- usb_put_intf(dev->interface);
- usb_put_dev(dev->udev);
-
- v4l2_ctrl_handler_free(&dev->hdl);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
-}
-
-static const struct video_device stk_v4l_data = {
- .name = "stkwebcam",
- .fops = &v4l_stk_fops,
- .ioctl_ops = &v4l_stk_ioctl_ops,
- .release = stk_v4l_dev_release,
-};
-
-
-static int stk_register_video_device(struct stk_camera *dev)
-{
- int err;
-
- dev->vdev = stk_v4l_data;
- dev->vdev.lock = &dev->lock;
- dev->vdev.v4l2_dev = &dev->v4l2_dev;
- dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- video_set_drvdata(&dev->vdev, dev);
- err = video_register_device(&dev->vdev, VFL_TYPE_VIDEO, -1);
- if (err)
- pr_err("v4l registration failed\n");
- else
- pr_info("Syntek USB2.0 Camera is now controlling device %s\n",
- video_device_node_name(&dev->vdev));
- return err;
-}
-
-
-/* USB Stuff */
-
-static int stk_camera_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct v4l2_ctrl_handler *hdl;
- int err = 0;
- int i;
-
- struct stk_camera *dev = NULL;
- struct usb_device *udev = interface_to_usbdev(interface);
- struct usb_host_interface *iface_desc;
- struct usb_endpoint_descriptor *endpoint;
-
- dev = kzalloc(sizeof(struct stk_camera), GFP_KERNEL);
- if (dev == NULL) {
- pr_err("Out of memory !\n");
- return -ENOMEM;
- }
- err = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
- if (err < 0) {
- dev_err(&udev->dev, "couldn't register v4l2_device\n");
- kfree(dev);
- return err;
- }
- hdl = &dev->hdl;
- v4l2_ctrl_handler_init(hdl, 3);
- v4l2_ctrl_new_std(hdl, &stk_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 0xff, 0x1, 0x60);
- v4l2_ctrl_new_std(hdl, &stk_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 1);
- v4l2_ctrl_new_std(hdl, &stk_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 1);
- if (hdl->error) {
- err = hdl->error;
- dev_err(&udev->dev, "couldn't register control\n");
- goto error;
- }
- dev->v4l2_dev.ctrl_handler = hdl;
-
- spin_lock_init(&dev->spinlock);
- mutex_init(&dev->lock);
- init_waitqueue_head(&dev->wait_frame);
- dev->first_init = 1; /* webcam LED management */
-
- dev->udev = usb_get_dev(udev);
- dev->interface = interface;
- usb_get_intf(interface);
-
- if (hflip != -1)
- dev->vsettings.hflip = hflip;
- else if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.hflip = 1;
- else
- dev->vsettings.hflip = 0;
- if (vflip != -1)
- dev->vsettings.vflip = vflip;
- else if (dmi_check_system(stk_upside_down_dmi_table))
- dev->vsettings.vflip = 1;
- else
- dev->vsettings.vflip = 0;
- dev->n_sbufs = 0;
- set_present(dev);
-
- /* Set up the endpoint information
- * use only the first isoc-in endpoint
- * for the current alternate setting */
- iface_desc = interface->cur_altsetting;
-
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- endpoint = &iface_desc->endpoint[i].desc;
-
- if (!dev->isoc_ep
- && usb_endpoint_is_isoc_in(endpoint)) {
- /* we found an isoc in endpoint */
- dev->isoc_ep = usb_endpoint_num(endpoint);
- break;
- }
- }
- if (!dev->isoc_ep) {
- pr_err("Could not find isoc-in endpoint\n");
- err = -ENODEV;
- goto error_put;
- }
- dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
- dev->vsettings.mode = MODE_VGA;
- dev->frame_size = 640 * 480 * 2;
-
- INIT_LIST_HEAD(&dev->sio_avail);
- INIT_LIST_HEAD(&dev->sio_full);
-
- usb_set_intfdata(interface, dev);
-
- err = stk_register_video_device(dev);
- if (err)
- goto error_put;
-
- return 0;
-
-error_put:
- usb_put_intf(interface);
- usb_put_dev(dev->udev);
-error:
- v4l2_ctrl_handler_free(hdl);
- v4l2_device_unregister(&dev->v4l2_dev);
- kfree(dev);
- return err;
-}
-
-static void stk_camera_disconnect(struct usb_interface *interface)
-{
- struct stk_camera *dev = usb_get_intfdata(interface);
-
- usb_set_intfdata(interface, NULL);
- unset_present(dev);
-
- wake_up_interruptible(&dev->wait_frame);
-
- pr_info("Syntek USB2.0 Camera release resources device %s\n",
- video_device_node_name(&dev->vdev));
-
- video_unregister_device(&dev->vdev);
-}
-
-#ifdef CONFIG_PM
-static int stk_camera_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct stk_camera *dev = usb_get_intfdata(intf);
- if (is_streaming(dev)) {
- stk_stop_stream(dev);
- /* yes, this is ugly */
- set_streaming(dev);
- }
- return 0;
-}
-
-static int stk_camera_resume(struct usb_interface *intf)
-{
- struct stk_camera *dev = usb_get_intfdata(intf);
- if (!is_initialised(dev))
- return 0;
- unset_initialised(dev);
- stk_initialise(dev);
- stk_camera_write_reg(dev, 0x0, 0x49);
- stk_setup_format(dev);
- if (is_streaming(dev))
- stk_start_stream(dev);
- return 0;
-}
-#endif
-
-static struct usb_driver stk_camera_driver = {
- .name = "stkwebcam",
- .probe = stk_camera_probe,
- .disconnect = stk_camera_disconnect,
- .id_table = stkwebcam_table,
-#ifdef CONFIG_PM
- .suspend = stk_camera_suspend,
- .resume = stk_camera_resume,
-#endif
-};
-
-module_usb_driver(stk_camera_driver);
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h
deleted file mode 100644
index 136decffe9ce..000000000000
--- a/drivers/media/usb/stkwebcam/stk-webcam.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * stk-webcam.h : Driver for Syntek 1125 USB webcam controller
- *
- * Copyright (C) 2006 Nicolas VIVIEN
- * Copyright 2007-2008 Jaime Velasco Juan <jsagarribay@gmail.com>
- */
-
-#ifndef STKWEBCAM_H
-#define STKWEBCAM_H
-
-#include <linux/usb.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-common.h>
-
-#define DRIVER_VERSION "v0.0.1"
-#define DRIVER_VERSION_NUM 0x000001
-
-#define MAX_ISO_BUFS 3
-#define ISO_FRAMES_PER_DESC 16
-#define ISO_MAX_FRAME_SIZE 3 * 1024
-#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
-
-struct stk_iso_buf {
- void *data;
- int length;
- int read;
- struct urb *urb;
-};
-
-/* Streaming IO buffers */
-struct stk_sio_buffer {
- struct v4l2_buffer v4lbuf;
- char *buffer;
- int mapcount;
- struct stk_camera *dev;
- struct list_head list;
-};
-
-enum stk_mode {MODE_VGA, MODE_SXGA, MODE_CIF, MODE_QVGA, MODE_QCIF};
-
-struct stk_video {
- enum stk_mode mode;
- __u32 palette;
- int hflip;
- int vflip;
-};
-
-enum stk_status {
- S_PRESENT = 1,
- S_INITIALISED = 2,
- S_MEMALLOCD = 4,
- S_STREAMING = 8,
-};
-#define is_present(dev) ((dev)->status & S_PRESENT)
-#define is_initialised(dev) ((dev)->status & S_INITIALISED)
-#define is_streaming(dev) ((dev)->status & S_STREAMING)
-#define is_memallocd(dev) ((dev)->status & S_MEMALLOCD)
-#define set_present(dev) ((dev)->status = S_PRESENT)
-#define unset_present(dev) ((dev)->status &= \
- ~(S_PRESENT|S_INITIALISED|S_STREAMING))
-#define set_initialised(dev) ((dev)->status |= S_INITIALISED)
-#define unset_initialised(dev) ((dev)->status &= ~S_INITIALISED)
-#define set_memallocd(dev) ((dev)->status |= S_MEMALLOCD)
-#define unset_memallocd(dev) ((dev)->status &= ~S_MEMALLOCD)
-#define set_streaming(dev) ((dev)->status |= S_STREAMING)
-#define unset_streaming(dev) ((dev)->status &= ~S_STREAMING)
-
-struct regval {
- unsigned reg;
- unsigned val;
-};
-
-struct stk_camera {
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler hdl;
- struct video_device vdev;
- struct usb_device *udev;
- struct usb_interface *interface;
- int webcam_model;
- struct file *owner;
- struct mutex lock;
- int first_init;
-
- u8 isoc_ep;
-
- /* Not sure if this is right */
- atomic_t urbs_used;
-
- struct stk_video vsettings;
-
- enum stk_status status;
-
- spinlock_t spinlock;
- wait_queue_head_t wait_frame;
-
- struct stk_iso_buf *isobufs;
-
- int frame_size;
- /* Streaming buffers */
- int reading;
- unsigned int n_sbufs;
- struct stk_sio_buffer *sio_bufs;
- struct list_head sio_avail;
- struct list_head sio_full;
- unsigned sequence;
-
- u8 read_reg_scratch;
-};
-
-#define vdev_to_camera(d) container_of(d, struct stk_camera, vdev)
-
-int stk_camera_write_reg(struct stk_camera *, u16, u8);
-int stk_camera_read_reg(struct stk_camera *, u16, u8 *);
-
-int stk_sensor_init(struct stk_camera *);
-int stk_sensor_configure(struct stk_camera *);
-int stk_sensor_sleep(struct stk_camera *dev);
-int stk_sensor_wakeup(struct stk_camera *dev);
-int stk_sensor_set_brightness(struct stk_camera *dev, int br);
-
-#endif
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index a714ad77ca8e..1e30e05953dc 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -136,6 +136,8 @@ static uint16_t usbtv_norm_to_16f_reg(v4l2_std_id norm)
return 0x00a8;
if (norm & (V4L2_STD_PAL_M | V4L2_STD_PAL_60))
return 0x00bc;
+ if (norm & V4L2_STD_PAL_Nc)
+ return 0x00fe;
/* Fallback to automatic detection for other standards */
return 0x0000;
}
@@ -241,7 +243,8 @@ static int usbtv_select_norm(struct usbtv *usbtv, v4l2_std_id norm)
static const v4l2_std_id ntsc_mask =
V4L2_STD_NTSC | V4L2_STD_NTSC_443;
static const v4l2_std_id pal_mask =
- V4L2_STD_PAL | V4L2_STD_PAL_60 | V4L2_STD_PAL_M;
+ V4L2_STD_PAL | V4L2_STD_PAL_60 | V4L2_STD_PAL_M |
+ V4L2_STD_PAL_Nc;
if (norm & ntsc_mask)
ret = usbtv_set_regs(usbtv, ntsc, ARRAY_SIZE(ntsc));
diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h
index 77a368e90fd0..b9fa7c0088c9 100644
--- a/drivers/media/usb/usbtv/usbtv.h
+++ b/drivers/media/usb/usbtv/usbtv.h
@@ -68,7 +68,8 @@
#define USBTV_ODD(chunk) ((be32_to_cpu(chunk[0]) & 0x0000f000) >> 15)
#define USBTV_CHUNK_NO(chunk) (be32_to_cpu(chunk[0]) & 0x00000fff)
-#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL | V4L2_STD_SECAM)
+#define USBTV_TV_STD (V4L2_STD_525_60 | V4L2_STD_PAL | \
+ V4L2_STD_PAL_Nc | V4L2_STD_SECAM)
/* parameters for supported TV norms */
struct usbtv_norm_params {
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 0e78233fc8a0..8c208db9600b 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -366,6 +366,7 @@ static const struct uvc_menu_info power_line_frequency_controls[] = {
{ 0, "Disabled" },
{ 1, "50 Hz" },
{ 2, "60 Hz" },
+ { 3, "Auto" },
};
static const struct uvc_menu_info exposure_auto_controls[] = {
@@ -505,17 +506,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
.data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
},
{
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
- .size = 2,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_MENU,
- .data_type = UVC_CTRL_DATA_TYPE_ENUM,
- .menu_info = power_line_frequency_controls,
- .menu_count = ARRAY_SIZE(power_line_frequency_controls),
- },
- {
.id = V4L2_CID_HUE_AUTO,
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_HUE_AUTO_CONTROL,
@@ -730,6 +720,34 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
},
};
+static const struct uvc_control_mapping uvc_ctrl_mappings_uvc11[] = {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_info = power_line_frequency_controls,
+ .menu_count = ARRAY_SIZE(power_line_frequency_controls) - 1,
+ },
+};
+
+static const struct uvc_control_mapping uvc_ctrl_mappings_uvc15[] = {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_info = power_line_frequency_controls,
+ .menu_count = ARRAY_SIZE(power_line_frequency_controls),
+ },
+};
+
/* ------------------------------------------------------------------------
* Utility functions
*/
@@ -749,7 +767,8 @@ static inline void uvc_clear_bit(u8 *data, int bit)
data[bit >> 3] &= ~(1 << (bit & 7));
}
-/* Extract the bit string specified by mapping->offset and mapping->size
+/*
+ * Extract the bit string specified by mapping->offset and mapping->size
* from the little-endian data stored at 'data' and return the result as
* a signed 32bit integer. Sign extension will be performed if the mapping
* references a signed data type.
@@ -785,7 +804,8 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
return value;
}
-/* Set the bit string specified by mapping->offset and mapping->size
+/*
+ * Set the bit string specified by mapping->offset and mapping->size
* in the little-endian data stored at 'data' to the value 'value'.
*/
static void uvc_set_le_value(struct uvc_control_mapping *mapping,
@@ -795,7 +815,8 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
int offset = mapping->offset;
u8 mask;
- /* According to the v4l2 spec, writing any value to a button control
+ /*
+ * According to the v4l2 spec, writing any value to a button control
* should result in the action belonging to the button control being
* triggered. UVC devices however want to see a 1 written -> override
* value.
@@ -927,7 +948,8 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
UVC_VC_EXTENSION_UNIT)
return ret;
- /* GET_RES is mandatory for XU controls, but some
+ /*
+ * GET_RES is mandatory for XU controls, but some
* cameras still choke on it. Ignore errors and set the
* resolution value to zero.
*/
@@ -1522,8 +1544,10 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val,
changes);
- /* Mark the queue as active, allowing this initial
- event to be accepted. */
+ /*
+ * Mark the queue as active, allowing this initial event to be
+ * accepted.
+ */
sev->elems = elems;
v4l2_event_queue_fh(sev->fh, &ev);
}
@@ -1596,7 +1620,8 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
if (!ctrl->initialized)
continue;
- /* Reset the loaded flag for auto-update controls that were
+ /*
+ * Reset the loaded flag for auto-update controls that were
* marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
* uvc_ctrl_get from using the cached value, and for write-only
* controls to prevent uvc_ctrl_set from setting bits not
@@ -1755,7 +1780,8 @@ int uvc_ctrl_set(struct uvc_fh *handle,
return -ERANGE;
value = mapping->menu_info[xctrl->value].value;
- /* Valid menu indices are reported by the GET_RES request for
+ /*
+ * Valid menu indices are reported by the GET_RES request for
* UVC controls that support it.
*/
if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK &&
@@ -1779,7 +1805,8 @@ int uvc_ctrl_set(struct uvc_fh *handle,
break;
}
- /* If the mapping doesn't span the whole UVC control, the current value
+ /*
+ * If the mapping doesn't span the whole UVC control, the current value
* needs to be loaded from the device to perform the read-modify-write
* operation.
*/
@@ -2180,7 +2207,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
unsigned int size;
unsigned int i;
- /* Most mappings come from static kernel data and need to be duplicated.
+ /*
+ * Most mappings come from static kernel data and need to be duplicated.
* Mappings that come from userspace will be unnecessarily duplicated,
* this could be optimized.
*/
@@ -2385,11 +2413,11 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
{
const struct uvc_control_info *info = uvc_ctrls;
const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls);
- const struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
- const struct uvc_control_mapping *mend =
- mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+ const struct uvc_control_mapping *mapping;
+ const struct uvc_control_mapping *mend;
- /* XU controls initialization requires querying the device for control
+ /*
+ * XU controls initialization requires querying the device for control
* information. As some buggy UVC devices will crash when queried
* repeatedly in a tight loop, delay XU controls initialization until
* first use.
@@ -2415,6 +2443,48 @@ static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
if (!ctrl->initialized)
return;
+ /*
+ * First check if the device provides a custom mapping for this control,
+ * used to override standard mappings for non-conformant devices. Don't
+ * process standard mappings if a custom mapping is found. This
+ * mechanism doesn't support combining standard and custom mappings for
+ * a single control.
+ */
+ if (chain->dev->info->mappings) {
+ bool custom = false;
+ unsigned int i;
+
+ for (i = 0; (mapping = chain->dev->info->mappings[i]); ++i) {
+ if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
+ ctrl->info.selector == mapping->selector) {
+ __uvc_ctrl_add_mapping(chain, ctrl, mapping);
+ custom = true;
+ }
+ }
+
+ if (custom)
+ return;
+ }
+
+ /* Process common mappings next. */
+ mapping = uvc_ctrl_mappings;
+ mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+
+ for (; mapping < mend; ++mapping) {
+ if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
+ ctrl->info.selector == mapping->selector)
+ __uvc_ctrl_add_mapping(chain, ctrl, mapping);
+ }
+
+ /* Finally process version-specific mappings. */
+ if (chain->dev->uvc_version < 0x0150) {
+ mapping = uvc_ctrl_mappings_uvc11;
+ mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc11);
+ } else {
+ mapping = uvc_ctrl_mappings_uvc15;
+ mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings_uvc15);
+ }
+
for (; mapping < mend; ++mapping) {
if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
ctrl->info.selector == mapping->selector)
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 6c86faecbea2..9c05776f11d1 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -329,7 +329,8 @@ static enum v4l2_ycbcr_encoding uvc_ycbcr_enc(const u8 matrix_coefficients)
return V4L2_YCBCR_ENC_DEFAULT; /* Reserved */
}
-/* Simplify a fraction using a simple continued fraction decomposition. The
+/*
+ * Simplify a fraction using a simple continued fraction decomposition. The
* idea here is to convert fractions such as 333333/10000000 to 1/30 using
* 32 bit arithmetic only. The algorithm is not perfect and relies upon two
* arbitrary parameters to remove non-significative terms from the simple
@@ -347,8 +348,9 @@ void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
if (an == NULL)
return;
- /* Convert the fraction to a simple continued fraction. See
- * https://mathforum.org/dr.math/faq/faq.fractions.html
+ /*
+ * Convert the fraction to a simple continued fraction. See
+ * https://en.wikipedia.org/wiki/Continued_fraction
* Stop if the current term is bigger than or equal to the given
* threshold.
*/
@@ -383,7 +385,8 @@ void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
kfree(an);
}
-/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
+/*
+ * Convert a fraction to a frame interval in 100ns multiples. The idea here is
* to compute numerator / denominator * 10000000 using 32 bit fixed point
* arithmetic only.
*/
@@ -396,7 +399,8 @@ u32 uvc_fraction_to_interval(u32 numerator, u32 denominator)
numerator/denominator >= ((u32)-1)/10000000)
return (u32)-1;
- /* Divide both the denominator and the multiplier by two until
+ /*
+ * Divide both the denominator and the multiplier by two until
* numerator * multiplier doesn't overflow. If anyone knows a better
* algorithm please let me know.
*/
@@ -548,7 +552,8 @@ static int uvc_parse_format(struct uvc_device *dev,
format->bpp = buffer[21];
- /* Some devices report a format that doesn't match what they
+ /*
+ * Some devices report a format that doesn't match what they
* really send.
*/
if (dev->quirks & UVC_QUIRK_FORCE_Y8) {
@@ -663,7 +668,8 @@ static int uvc_parse_format(struct uvc_device *dev,
buflen -= buffer[0];
buffer += buffer[0];
- /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
+ /*
+ * Parse the frame descriptors. Only uncompressed, MJPEG and frame
* based formats have frame descriptors.
*/
while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
@@ -705,7 +711,8 @@ static int uvc_parse_format(struct uvc_device *dev,
}
frame->dwFrameInterval = *intervals;
- /* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
+ /*
+ * Several UVC chipsets screw up dwMaxVideoFrameBufferSize
* completely. Observed behaviours range from setting the
* value to 1.1x the actual frame size to hardwiring the
* 16 low bits to 0. This results in a higher than necessary
@@ -717,7 +724,8 @@ static int uvc_parse_format(struct uvc_device *dev,
frame->dwMaxVideoFrameBufferSize = format->bpp
* frame->wWidth * frame->wHeight / 8;
- /* Some bogus devices report dwMinFrameInterval equal to
+ /*
+ * Some bogus devices report dwMinFrameInterval equal to
* dwMaxFrameInterval and have dwFrameIntervalStep set to
* zero. Setting all null intervals to 1 fixes the problem and
* some other divisions by zero that could happen.
@@ -727,7 +735,8 @@ static int uvc_parse_format(struct uvc_device *dev,
*(*intervals)++ = interval ? interval : 1;
}
- /* Make sure that the default frame interval stays between
+ /*
+ * Make sure that the default frame interval stays between
* the boundaries.
*/
n -= frame->bFrameIntervalType ? 1 : 2;
@@ -819,7 +828,8 @@ static int uvc_parse_streaming(struct uvc_device *dev,
return -ENOMEM;
}
- /* The Pico iMage webcam has its class-specific interface descriptors
+ /*
+ * The Pico iMage webcam has its class-specific interface descriptors
* after the endpoint descriptors.
*/
if (buflen == 0) {
@@ -918,7 +928,8 @@ static int uvc_parse_streaming(struct uvc_device *dev,
break;
case UVC_VS_FORMAT_DV:
- /* DV format has no frame descriptor. We will create a
+ /*
+ * DV format has no frame descriptor. We will create a
* dummy frame descriptor with a dummy frame interval.
*/
nformats++;
@@ -1105,7 +1116,8 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
if (buffer[1] != 0x41 || buffer[2] != 0x01)
break;
- /* Logitech implements several vendor specific functions
+ /*
+ * Logitech implements several vendor specific functions
* through vendor specific extension units (LXU).
*
* The LXU descriptors are similar to XU descriptors
@@ -1303,7 +1315,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
return -EINVAL;
}
- /* Make sure the terminal type MSB is not null, otherwise it
+ /*
+ * Make sure the terminal type MSB is not null, otherwise it
* could be confused with a unit.
*/
type = get_unaligned_le16(&buffer[4]);
@@ -1437,7 +1450,8 @@ static int uvc_parse_control(struct uvc_device *dev)
int buflen = alts->extralen;
int ret;
- /* Parse the default alternate setting only, as the UVC specification
+ /*
+ * Parse the default alternate setting only, as the UVC specification
* defines a single alternate setting, the default alternate setting
* zero.
*/
@@ -1455,7 +1469,8 @@ next_descriptor:
buffer += buffer[0];
}
- /* Check if the optional status endpoint is present. Built-in iSight
+ /*
+ * Check if the optional status endpoint is present. Built-in iSight
* webcams have an interrupt endpoint but spit proprietary data that
* don't conform to the UVC status endpoint messages. Don't try to
* handle the interrupt endpoint for those cameras.
@@ -2057,7 +2072,8 @@ static int uvc_scan_device(struct uvc_device *dev)
if (!UVC_ENTITY_IS_OTERM(term))
continue;
- /* If the terminal is already included in a chain, skip it.
+ /*
+ * If the terminal is already included in a chain, skip it.
* This can happen for chains that have multiple output
* terminals, where all output terminals beside the first one
* will be inserted in the chain in forward scans.
@@ -2309,7 +2325,8 @@ static int uvc_register_terms(struct uvc_device *dev,
if (ret < 0)
return ret;
- /* Register a metadata node, but ignore a possible failure,
+ /*
+ * Register a metadata node, but ignore a possible failure,
* complete registration of video nodes anyway.
*/
uvc_meta_register(stream);
@@ -2507,7 +2524,8 @@ static void uvc_disconnect(struct usb_interface *intf)
{
struct uvc_device *dev = usb_get_intfdata(intf);
- /* Set the USB interface data to NULL. This can be done outside the
+ /*
+ * Set the USB interface data to NULL. This can be done outside the
* lock, as there's no other reader.
*/
usb_set_intfdata(intf, NULL);
@@ -2643,6 +2661,30 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
* Driver initialization and cleanup
*/
+static const struct uvc_menu_info power_line_frequency_controls_limited[] = {
+ { 1, "50 Hz" },
+ { 2, "60 Hz" },
+};
+
+static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited = {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .size = 2,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_MENU,
+ .data_type = UVC_CTRL_DATA_TYPE_ENUM,
+ .menu_info = power_line_frequency_controls_limited,
+ .menu_count = ARRAY_SIZE(power_line_frequency_controls_limited),
+};
+
+static const struct uvc_device_info uvc_ctrl_power_line_limited = {
+ .mappings = (const struct uvc_control_mapping *[]) {
+ &uvc_ctrl_power_line_mapping_limited,
+ NULL, /* Sentinel */
+ },
+};
+
static const struct uvc_device_info uvc_quirk_probe_minmax = {
.quirks = UVC_QUIRK_PROBE_MINMAX,
};
@@ -2673,6 +2715,33 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
* though they are compliant.
*/
static const struct usb_device_id uvc_ids[] = {
+ /* Quanta USB2.0 HD UVC Webcam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0408,
+ .idProduct = 0x3090,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ /* Quanta USB2.0 HD UVC Webcam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0408,
+ .idProduct = 0x4030,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ /* Quanta USB2.0 HD UVC Webcam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0408,
+ .idProduct = 0x4034,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
/* LogiLink Wireless Webcam */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2784,6 +2853,33 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTRICT_FRAME_RATE) },
+ /* Chicony EasyCamera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x04f2,
+ .idProduct = 0xb5eb,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ /* Chicony EasyCamera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x04f2,
+ .idProduct = 0xb6ba,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ /* Chicony EasyCamera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x04f2,
+ .idProduct = 0xb746,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
/* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -3168,6 +3264,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) },
+ /* Acer EasyCamera */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x5986,
+ .idProduct = 0x1172,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
/* Intel RealSense D4M */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/usb/uvc/uvc_isight.c b/drivers/media/usb/uvc/uvc_isight.c
index 2578d6ee4829..43cda5e760a3 100644
--- a/drivers/media/usb/uvc/uvc_isight.c
+++ b/drivers/media/usb/uvc/uvc_isight.c
@@ -14,7 +14,8 @@
#include "uvcvideo.h"
-/* Built-in iSight webcams implements most of UVC 1.0 except a
+/*
+ * Built-in iSight webcams implements most of UVC 1.0 except a
* different packet format. Instead of sending a header at the
* beginning of each isochronous transfer payload, the webcam sends a
* single header per image (on its own in a packet), followed by
@@ -65,7 +66,8 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
buf->state = UVC_BUF_STATE_ACTIVE;
}
- /* Mark the buffer as done if we're at the beginning of a new frame.
+ /*
+ * Mark the buffer as done if we're at the beginning of a new frame.
*
* Empty buffers (bytesused == 0) don't trigger end of frame detection
* as it doesn't make sense to return an empty buffer.
@@ -75,7 +77,8 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
return -EAGAIN;
}
- /* Copy the video data to the buffer. Skip header packets, as they
+ /*
+ * Copy the video data to the buffer. Skip header packets, as they
* contain no data.
*/
if (!is_header) {
@@ -109,7 +112,9 @@ void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf,
urb->iso_frame_desc[i].status);
}
- /* Decode the payload packet.
+ /*
+ * Decode the payload packet.
+ *
* uvc_video_decode is entered twice when a frame transition
* has been detected because the end of frame can only be
* reliably detected when the first packet of the new frame
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 21a907d32bb7..16fa17bbd15e 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -135,7 +135,8 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
kref_init(&buf->ref);
list_add_tail(&buf->queue, &queue->irqqueue);
} else {
- /* If the device is disconnected return the buffer to userspace
+ /*
+ * If the device is disconnected return the buffer to userspace
* directly. The next QBUF call will fail with -ENODEV.
*/
buf->state = UVC_BUF_STATE_ERROR;
@@ -412,7 +413,8 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
spin_lock_irqsave(&queue->irqlock, flags);
uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
- /* This must be protected by the irqlock spinlock to avoid race
+ /*
+ * This must be protected by the irqlock spinlock to avoid race
* conditions between uvc_buffer_queue and the disconnection event that
* could result in an interruptible wait in uvc_dequeue_buffer. Do not
* blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED
diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
index 753c8226db70..7518ffce22ed 100644
--- a/drivers/media/usb/uvc/uvc_status.c
+++ b/drivers/media/usb/uvc/uvc_status.c
@@ -202,8 +202,7 @@ static void uvc_status_complete(struct urb *urb)
case -ENOENT: /* usb_kill_urb() called. */
case -ECONNRESET: /* usb_unlink_urb() called. */
case -ESHUTDOWN: /* The endpoint is being disabled. */
- case -EPROTO: /* Device is disconnected (reported by some
- * host controller). */
+ case -EPROTO: /* Device is disconnected (reported by some host controllers). */
return;
default:
@@ -272,7 +271,8 @@ int uvc_status_init(struct uvc_device *dev)
pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
- /* For high-speed interrupt endpoints, the bInterval value is used as
+ /*
+ * For high-speed interrupt endpoints, the bInterval value is used as
* an exponent of two. Some developers forgot about it.
*/
interval = ep->desc.bInterval;
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 648dcd579e81..4cc3fa6b8c98 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -63,7 +63,8 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
break;
case V4L2_CTRL_TYPE_MENU:
- /* Prevent excessive memory consumption, as well as integer
+ /*
+ * Prevent excessive memory consumption, as well as integer
* overflows.
*/
if (xmap->menu_count == 0 ||
@@ -177,7 +178,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
fcc[0], fcc[1], fcc[2], fcc[3],
fmt->fmt.pix.width, fmt->fmt.pix.height);
- /* Check if the hardware supports the requested format, use the default
+ /*
+ * Check if the hardware supports the requested format, use the default
* format otherwise.
*/
for (i = 0; i < stream->nformats; ++i) {
@@ -191,7 +193,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
fmt->fmt.pix.pixelformat = format->fcc;
}
- /* Find the closest image size. The distance between image sizes is
+ /*
+ * Find the closest image size. The distance between image sizes is
* the size in pixels of the non-overlapping regions between the
* requested size and the frame-specified size.
*/
@@ -233,7 +236,8 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
probe->bFormatIndex = format->index;
probe->bFrameIndex = frame->bFrameIndex;
probe->dwFrameInterval = uvc_try_frame_interval(frame, interval);
- /* Some webcams stall the probe control set request when the
+ /*
+ * Some webcams stall the probe control set request when the
* dwMaxVideoFrameSize field is set to zero. The UVC specification
* clearly states that the field is read-only from the host, so this
* is a webcam bug. Set dwMaxVideoFrameSize to the value reported by
@@ -254,9 +258,10 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
ret = uvc_probe_video(stream, probe);
mutex_unlock(&stream->mutex);
if (ret < 0)
- goto done;
+ return ret;
- /* After the probe, update fmt with the values returned from
+ /*
+ * After the probe, update fmt with the values returned from
* negotiation with the device. Some devices return invalid bFormatIndex
* and bFrameIndex values, in which case we can only assume they have
* accepted the requested format as-is.
@@ -300,7 +305,6 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
if (uvc_frame != NULL)
*uvc_frame = frame;
-done:
return ret;
}
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 6d3dfa4e0bb2..170a008f4006 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -189,7 +189,8 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
ctrl->dwMaxVideoFrameSize =
frame->dwMaxVideoFrameBufferSize;
- /* The "TOSHIBA Web Camera - 5M" Chicony device (04f2:b50b) seems to
+ /*
+ * The "TOSHIBA Web Camera - 5M" Chicony device (04f2:b50b) seems to
* compute the bandwidth on 16 bits and erroneously sign-extend it to
* 32 bits, resulting in a huge bandwidth value. Detect and fix that
* condition by setting the 16 MSBs to 0 when they're all equal to 1.
@@ -207,7 +208,8 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
? ctrl->dwFrameInterval
: frame->dwFrameInterval[0];
- /* Compute a bandwidth estimation by multiplying the frame
+ /*
+ * Compute a bandwidth estimation by multiplying the frame
* size by the number of video frames per second, divide the
* result by the number of USB frames (or micro-frames for
* high-speed devices) per second and add the UVC header size
@@ -220,7 +222,8 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
bandwidth /= 8;
bandwidth += 12;
- /* The bandwidth estimate is too low for many cameras. Don't use
+ /*
+ * The bandwidth estimate is too low for many cameras. Don't use
* maximum packet sizes lower than 1024 bytes to try and work
* around the problem. According to measurements done on two
* different camera models, the value is high enough to get most
@@ -267,7 +270,8 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream,
size, uvc_timeout_param);
if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) {
- /* Some cameras, mostly based on Bison Electronics chipsets,
+ /*
+ * Some cameras, mostly based on Bison Electronics chipsets,
* answer a GET_MIN or GET_MAX request with the wCompQuality
* field only.
*/
@@ -279,7 +283,8 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream,
ret = 0;
goto out;
} else if (query == UVC_GET_DEF && probe == 1 && ret != size) {
- /* Many cameras don't support the GET_DEF request on their
+ /*
+ * Many cameras don't support the GET_DEF request on their
* video probe control. Warn once and return, the caller will
* fall back to GET_CUR.
*/
@@ -322,7 +327,8 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream,
ctrl->bMaxVersion = 0;
}
- /* Some broken devices return null or wrong dwMaxVideoFrameSize and
+ /*
+ * Some broken devices return null or wrong dwMaxVideoFrameSize and
* dwMaxPayloadTransferSize fields. Try to get the value from the
* format and frame descriptors.
*/
@@ -386,7 +392,8 @@ int uvc_probe_video(struct uvc_streaming *stream,
unsigned int i;
int ret;
- /* Perform probing. The device should adjust the requested values
+ /*
+ * Perform probing. The device should adjust the requested values
* according to its capabilities. However, some devices, namely the
* first generation UVC Logitech webcams, don't implement the Video
* Probe control properly, and just return the needed bandwidth. For
@@ -493,7 +500,8 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
if (len < header_size)
return;
- /* Extract the timestamps:
+ /*
+ * Extract the timestamps:
*
* - store the frame PTS in the buffer structure
* - if the SCR field is present, retrieve the host SOF counter and
@@ -506,7 +514,8 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
if (!has_scr)
return;
- /* To limit the amount of data, drop SCRs with an SOF identical to the
+ /*
+ * To limit the amount of data, drop SCRs with an SOF identical to the
* previous one.
*/
dev_sof = get_unaligned_le16(&data[header_size - 2]);
@@ -518,7 +527,8 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
host_sof = usb_get_current_frame_number(stream->dev->udev);
time = uvc_video_get_time();
- /* The UVC specification allows device implementations that can't obtain
+ /*
+ * The UVC specification allows device implementations that can't obtain
* the USB frame number to keep their own frame counters as long as they
* match the size and frequency of the frame number associated with USB
* SOF tokens. The SOF values sent by such devices differ from the USB
@@ -756,7 +766,8 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
y1 = NSEC_PER_SEC;
y2 = (u32)ktime_to_ns(ktime_sub(last->host_time, first->host_time)) + y1;
- /* Interpolated and host SOF timestamps can wrap around at slightly
+ /*
+ * Interpolated and host SOF timestamps can wrap around at slightly
* different times. Handle this by adding or removing 2048 to or from
* the computed SOF value to keep it close to the SOF samples mean
* value.
@@ -854,7 +865,8 @@ static void uvc_video_stats_decode(struct uvc_streaming *stream,
stream->stats.frame.pts = pts;
}
- /* Do all frames have a PTS in their first non-empty packet, or before
+ /*
+ * Do all frames have a PTS in their first non-empty packet, or before
* their first empty packet ?
*/
if (stream->stats.frame.size == 0) {
@@ -945,7 +957,8 @@ size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
unsigned int duration;
size_t count = 0;
- /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF
+ /*
+ * Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF
* frequency this will not overflow before more than 1h.
*/
duration = ktime_ms_delta(stream->stats.stream.stop_ts,
@@ -997,7 +1010,8 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream)
* Video codecs
*/
-/* Video payload decoding is handled by uvc_video_decode_start(),
+/*
+ * Video payload decoding is handled by uvc_video_decode_start(),
* uvc_video_decode_data() and uvc_video_decode_end().
*
* uvc_video_decode_start is called with URB data at the start of a bulk or
@@ -1037,7 +1051,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
{
u8 fid;
- /* Sanity checks:
+ /*
+ * Sanity checks:
* - packet must be at least 2 bytes long
* - bHeaderLength value must be at least 2 bytes (see above)
* - bHeaderLength value can't be larger than the packet size.
@@ -1049,7 +1064,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
fid = data[1] & UVC_STREAM_FID;
- /* Increase the sequence number regardless of any buffer states, so
+ /*
+ * Increase the sequence number regardless of any buffer states, so
* that discontinuous sequence numbers always indicate lost frames.
*/
if (stream->last_fid != fid) {
@@ -1061,7 +1077,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
uvc_video_clock_decode(stream, buf, data, len);
uvc_video_stats_decode(stream, data, len);
- /* Store the payload FID bit and return immediately when the buffer is
+ /*
+ * Store the payload FID bit and return immediately when the buffer is
* NULL.
*/
if (buf == NULL) {
@@ -1076,7 +1093,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
buf->error = 1;
}
- /* Synchronize to the input stream by waiting for the FID bit to be
+ /*
+ * Synchronize to the input stream by waiting for the FID bit to be
* toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
* stream->last_fid is initialized to -1, so the first isochronous
* frame will always be in sync.
@@ -1102,7 +1120,8 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
buf->state = UVC_BUF_STATE_ACTIVE;
}
- /* Mark the buffer as done if we're at the beginning of a new frame.
+ /*
+ * Mark the buffer as done if we're at the beginning of a new frame.
* End of frame detection is better implemented by checking the EOF
* bit (FID bit toggling is delayed by one frame compared to the EOF
* bit), but some devices don't set the bit at end of frame (and the
@@ -1226,7 +1245,8 @@ static void uvc_video_decode_end(struct uvc_streaming *stream,
}
}
-/* Video payload encoding is handled by uvc_video_encode_header() and
+/*
+ * Video payload encoding is handled by uvc_video_encode_header() and
* uvc_video_encode_data(). Only bulk transfers are currently supported.
*
* uvc_video_encode_header is called at the start of a payload. It adds header
@@ -1450,7 +1470,8 @@ static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb,
len = urb->actual_length;
stream->bulk.payload_size += len;
- /* If the URB is the first of its payload, decode and save the
+ /*
+ * If the URB is the first of its payload, decode and save the
* header.
*/
if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) {
@@ -1474,7 +1495,8 @@ static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb,
}
}
- /* The buffer queue might have been cancelled while a bulk transfer
+ /*
+ * The buffer queue might have been cancelled while a bulk transfer
* was in progress, so we can reach here with buf equal to NULL. Make
* sure buf is never dereferenced if NULL.
*/
@@ -1483,7 +1505,8 @@ static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb,
if (!stream->bulk.skip_payload && buf != NULL)
uvc_video_decode_data(uvc_urb, buf, mem, len);
- /* Detect the payload end by a URB smaller than the maximum size (or
+ /*
+ * Detect the payload end by a URB smaller than the maximum size (or
* a payload size equal to the maximum) and process the header again.
*/
if (urb->actual_length < urb->transfer_buffer_length ||
@@ -1686,7 +1709,8 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
if (stream->urb_size)
return stream->urb_size / psize;
- /* Compute the number of packets. Bulk endpoints might transfer UVC
+ /*
+ * Compute the number of packets. Bulk endpoints might transfer UVC
* payloads across multiple URBs.
*/
npackets = DIV_ROUND_UP(size, psize);
@@ -1975,7 +1999,8 @@ static int uvc_video_start_transfer(struct uvc_streaming *stream,
}
}
- /* The Logitech C920 temporarily forgets that it should not be adjusting
+ /*
+ * The Logitech C920 temporarily forgets that it should not be adjusting
* Exposure Absolute during init so restore controls to stored values.
*/
if (stream->dev->quirks & UVC_QUIRK_RESTORE_CTRLS_ON_INIT)
@@ -2018,7 +2043,8 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset)
{
int ret;
- /* If the bus has been reset on resume, set the alternate setting to 0.
+ /*
+ * If the bus has been reset on resume, set the alternate setting to 0.
* This should be the default value, but some devices crash or otherwise
* misbehave if they don't receive a SET_INTERFACE request before any
* other video control request.
@@ -2071,14 +2097,16 @@ int uvc_video_init(struct uvc_streaming *stream)
atomic_set(&stream->active, 0);
- /* Alternate setting 0 should be the default, yet the XBox Live Vision
+ /*
+ * Alternate setting 0 should be the default, yet the XBox Live Vision
* Cam (and possibly other devices) crash or otherwise misbehave if
* they don't receive a SET_INTERFACE request before any other video
* control request.
*/
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
- /* Set the streaming probe control with default streaming parameters
+ /*
+ * Set the streaming probe control with default streaming parameters
* retrieved from the device. Webcams that don't support GET_DEF
* requests on the probe control will just keep their current streaming
* parameters.
@@ -2086,7 +2114,8 @@ int uvc_video_init(struct uvc_streaming *stream)
if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0)
uvc_set_video_ctrl(stream, probe, 1);
- /* Initialize the streaming parameters with the probe control current
+ /*
+ * Initialize the streaming parameters with the probe control current
* value. This makes sure SET_CUR requests on the streaming commit
* control will always use values retrieved from a successful GET_CUR
* request on the probe control, as required by the UVC specification.
@@ -2095,7 +2124,8 @@ int uvc_video_init(struct uvc_streaming *stream)
if (ret < 0)
return ret;
- /* Check if the default format descriptor exists. Use the first
+ /*
+ * Check if the default format descriptor exists. Use the first
* available format otherwise.
*/
for (i = stream->nformats; i > 0; --i) {
@@ -2110,7 +2140,8 @@ int uvc_video_init(struct uvc_streaming *stream)
return -EINVAL;
}
- /* Zero bFrameIndex might be correct. Stream-based formats (including
+ /*
+ * Zero bFrameIndex might be correct. Stream-based formats (including
* MPEG-2 TS and DV) do not support frames but have a dummy frame
* descriptor with bFrameIndex set to zero. If the default frame
* descriptor is not found, use the first available frame.
@@ -2187,7 +2218,8 @@ void uvc_video_stop_streaming(struct uvc_streaming *stream)
if (stream->intf->num_altsetting > 1) {
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
} else {
- /* UVC doesn't specify how to inform a bulk-based device
+ /*
+ * UVC doesn't specify how to inform a bulk-based device
* when the video stream is stopped. Windows sends a
* CLEAR_FEATURE(HALT) request to the video streaming
* bulk endpoint, mimic the same behaviour.
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index c5b4febd2d94..24c911aeebce 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -225,7 +225,8 @@ struct gpio_desc;
struct sg_table;
struct uvc_device;
-/* TODO: Put the most frequently accessed fields at the beginning of
+/*
+ * TODO: Put the most frequently accessed fields at the beginning of
* structures to maximize cache efficiency.
*/
struct uvc_control_info {
@@ -270,8 +271,7 @@ struct uvc_control {
struct uvc_entity *entity;
struct uvc_control_info info;
- u8 index; /* Used to match the uvc_control entry with a
- uvc_control_info. */
+ u8 index; /* Used to match the uvc_control entry with a uvc_control_info. */
u8 dirty:1,
loaded:1,
modified:1,
@@ -289,7 +289,8 @@ struct uvc_format_desc {
u32 fcc;
};
-/* The term 'entity' refers to both UVC units and UVC terminals.
+/*
+ * The term 'entity' refers to both UVC units and UVC terminals.
*
* The type field is either the terminal type (wTerminalType in the terminal
* descriptor), or the unit type (bDescriptorSubtype in the unit descriptor).
@@ -308,8 +309,7 @@ struct uvc_format_desc {
struct uvc_entity {
struct list_head list; /* Entity as part of a UVC device. */
- struct list_head chain; /* Entity as part of a video device
- * chain. */
+ struct list_head chain; /* Entity as part of a video device chain. */
unsigned int flags;
/*
@@ -591,7 +591,8 @@ struct uvc_streaming {
struct uvc_format *cur_format;
struct uvc_frame *cur_frame;
- /* Protect access to ctrl, cur_format, cur_frame and hardware video
+ /*
+ * Protect access to ctrl, cur_format, cur_frame and hardware video
* probe control.
*/
struct mutex mutex;
@@ -667,6 +668,7 @@ struct uvc_device_info {
u32 quirks;
u32 meta_format;
u16 uvc_version;
+ const struct uvc_control_mapping **mappings;
};
struct uvc_device {
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index 1be9a2cc947a..348559bc2468 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -9,7 +9,7 @@ config VIDEO_V4L2_I2C
default y
config VIDEO_V4L2_SUBDEV_API
- bool "V4L2 sub-device userspace API"
+ bool
depends on VIDEO_DEV && MEDIA_CONTROLLER
help
Enables the V4L2 sub-device pad-level userspace API used to configure
@@ -56,9 +56,11 @@ config V4L2_MEM2MEM_DEV
# Used by LED subsystem flash drivers
config V4L2_FLASH_LED_CLASS
tristate "V4L2 flash API for LED flash class devices"
- depends on VIDEO_DEV && VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_DEV
depends on LEDS_CLASS_FLASH
+ select MEDIA_CONTROLLER
select V4L2_ASYNC
+ select VIDEO_V4L2_SUBDEV_API
help
Say Y here to enable V4L2 flash API support for LED flash
class drivers.
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index c6995718237a..2f1b718a9189 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -52,6 +52,15 @@ static int v4l2_async_nf_call_complete(struct v4l2_async_notifier *n)
return n->ops->complete(n);
}
+static void v4l2_async_nf_call_destroy(struct v4l2_async_notifier *n,
+ struct v4l2_async_subdev *asd)
+{
+ if (!n->ops || !n->ops->destroy)
+ return;
+
+ n->ops->destroy(asd);
+}
+
static bool match_i2c(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
{
@@ -66,8 +75,10 @@ static bool match_i2c(struct v4l2_async_notifier *notifier,
#endif
}
-static bool match_fwnode(struct v4l2_async_notifier *notifier,
- struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
+static bool
+match_fwnode_one(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd, struct fwnode_handle *sd_fwnode,
+ struct v4l2_async_subdev *asd)
{
struct fwnode_handle *other_fwnode;
struct fwnode_handle *dev_fwnode;
@@ -80,15 +91,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
* fwnode or a device fwnode. Start with the simple case of direct
* fwnode matching.
*/
- if (sd->fwnode == asd->match.fwnode)
- return true;
-
- /*
- * Check the same situation for any possible secondary assigned to the
- * subdev's fwnode
- */
- if (!IS_ERR_OR_NULL(sd->fwnode->secondary) &&
- sd->fwnode->secondary == asd->match.fwnode)
+ if (sd_fwnode == asd->match.fwnode)
return true;
/*
@@ -99,7 +102,7 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
* ACPI. This won't make a difference, as drivers should not try to
* match unconnected endpoints.
*/
- sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd->fwnode);
+ sd_fwnode_is_ep = fwnode_graph_is_endpoint(sd_fwnode);
asd_fwnode_is_ep = fwnode_graph_is_endpoint(asd->match.fwnode);
if (sd_fwnode_is_ep == asd_fwnode_is_ep)
@@ -110,11 +113,11 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
* parent of the endpoint fwnode, and compare it with the other fwnode.
*/
if (sd_fwnode_is_ep) {
- dev_fwnode = fwnode_graph_get_port_parent(sd->fwnode);
+ dev_fwnode = fwnode_graph_get_port_parent(sd_fwnode);
other_fwnode = asd->match.fwnode;
} else {
dev_fwnode = fwnode_graph_get_port_parent(asd->match.fwnode);
- other_fwnode = sd->fwnode;
+ other_fwnode = sd_fwnode;
}
fwnode_handle_put(dev_fwnode);
@@ -143,6 +146,19 @@ static bool match_fwnode(struct v4l2_async_notifier *notifier,
return true;
}
+static bool match_fwnode(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
+{
+ if (match_fwnode_one(notifier, sd, sd->fwnode, asd))
+ return true;
+
+ /* Also check the secondary fwnode. */
+ if (IS_ERR_OR_NULL(sd->fwnode->secondary))
+ return false;
+
+ return match_fwnode_one(notifier, sd, sd->fwnode->secondary, asd);
+}
+
static LIST_HEAD(subdev_list);
static LIST_HEAD(notifier_list);
static DEFINE_MUTEX(list_lock);
@@ -626,6 +642,7 @@ static void __v4l2_async_nf_cleanup(struct v4l2_async_notifier *notifier)
}
list_del(&asd->asd_list);
+ v4l2_async_nf_call_destroy(notifier, asd);
kfree(asd);
}
}
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index df34b2a283bc..e0fbe6ba4b6c 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -266,6 +266,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_NV61, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_YUV410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
{ .format = V4L2_PIX_FMT_YVU410, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 },
@@ -277,6 +278,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
/* Tiled YUV formats */
{ .format = V4L2_PIX_FMT_NV12_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 },
+ { .format = V4L2_PIX_FMT_P010_4L4, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .hdiv = 2, .vdiv = 2 },
/* YUV planar formats, non contiguous variant */
{ .format = V4L2_PIX_FMT_YUV420M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 },
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c
index db9baa0bd05f..50d012ba3c02 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-api.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c
@@ -97,29 +97,47 @@ static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
return ptr_to_user(c, ctrl, ctrl->p_new);
}
-/* Helper function: copy the caller-provider value to the given control value */
-static int user_to_ptr(struct v4l2_ext_control *c,
- struct v4l2_ctrl *ctrl,
- union v4l2_ctrl_ptr ptr)
+/* Helper function: copy the caller-provider value as the new control value */
+static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
{
int ret;
u32 size;
- ctrl->is_new = 1;
+ ctrl->is_new = 0;
+ if (ctrl->is_dyn_array &&
+ c->size > ctrl->p_dyn_alloc_elems * ctrl->elem_size) {
+ void *old = ctrl->p_dyn;
+ void *tmp = kvzalloc(2 * c->size, GFP_KERNEL);
+
+ if (!tmp)
+ return -ENOMEM;
+ memcpy(tmp, ctrl->p_new.p, ctrl->elems * ctrl->elem_size);
+ memcpy(tmp + c->size, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size);
+ ctrl->p_new.p = tmp;
+ ctrl->p_cur.p = tmp + c->size;
+ ctrl->p_dyn = tmp;
+ ctrl->p_dyn_alloc_elems = c->size / ctrl->elem_size;
+ kvfree(old);
+ }
+
if (ctrl->is_ptr && !ctrl->is_string) {
+ unsigned int elems = c->size / ctrl->elem_size;
unsigned int idx;
- ret = copy_from_user(ptr.p, c->ptr, c->size) ? -EFAULT : 0;
- if (ret || !ctrl->is_array)
- return ret;
- for (idx = c->size / ctrl->elem_size; idx < ctrl->elems; idx++)
- ctrl->type_ops->init(ctrl, idx, ptr);
+ if (copy_from_user(ctrl->p_new.p, c->ptr, c->size))
+ return -EFAULT;
+ ctrl->is_new = 1;
+ if (ctrl->is_dyn_array)
+ ctrl->new_elems = elems;
+ else if (ctrl->is_array)
+ for (idx = elems; idx < ctrl->elems; idx++)
+ ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
return 0;
}
switch (ctrl->type) {
case V4L2_CTRL_TYPE_INTEGER64:
- *ptr.p_s64 = c->value64;
+ *ctrl->p_new.p_s64 = c->value64;
break;
case V4L2_CTRL_TYPE_STRING:
size = c->size;
@@ -127,32 +145,27 @@ static int user_to_ptr(struct v4l2_ext_control *c,
return -ERANGE;
if (size > ctrl->maximum + 1)
size = ctrl->maximum + 1;
- ret = copy_from_user(ptr.p_char, c->string, size) ? -EFAULT : 0;
+ ret = copy_from_user(ctrl->p_new.p_char, c->string, size) ? -EFAULT : 0;
if (!ret) {
- char last = ptr.p_char[size - 1];
+ char last = ctrl->p_new.p_char[size - 1];
- ptr.p_char[size - 1] = 0;
+ ctrl->p_new.p_char[size - 1] = 0;
/*
* If the string was longer than ctrl->maximum,
* then return an error.
*/
- if (strlen(ptr.p_char) == ctrl->maximum && last)
+ if (strlen(ctrl->p_new.p_char) == ctrl->maximum && last)
return -ERANGE;
}
return ret;
default:
- *ptr.p_s32 = c->value;
+ *ctrl->p_new.p_s32 = c->value;
break;
}
+ ctrl->is_new = 1;
return 0;
}
-/* Helper function: copy the caller-provider value as the new control value */
-static int user_to_new(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
-{
- return user_to_ptr(c, ctrl, ctrl->p_new);
-}
-
/*
* VIDIOC_G/TRY/S_EXT_CTRLS implementation
*/
@@ -254,7 +267,31 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
have_clusters = true;
if (ctrl->cluster[0] != ctrl)
ref = find_ref_lock(hdl, ctrl->cluster[0]->id);
- if (ctrl->is_ptr && !ctrl->is_string) {
+ if (ctrl->is_dyn_array) {
+ unsigned int max_size = ctrl->dims[0] * ctrl->elem_size;
+ unsigned int tot_size = ctrl->elem_size;
+
+ if (cs->which == V4L2_CTRL_WHICH_REQUEST_VAL)
+ tot_size *= ref->p_req_elems;
+ else
+ tot_size *= ctrl->elems;
+
+ c->size = ctrl->elem_size * (c->size / ctrl->elem_size);
+ if (get) {
+ if (c->size < tot_size) {
+ c->size = tot_size;
+ return -ENOSPC;
+ }
+ c->size = tot_size;
+ } else {
+ if (c->size > max_size) {
+ c->size = max_size;
+ return -ENOSPC;
+ }
+ if (!c->size)
+ return -EFAULT;
+ }
+ } else if (ctrl->is_ptr && !ctrl->is_string) {
unsigned int tot_size = ctrl->elems * ctrl->elem_size;
if (c->size < tot_size) {
@@ -346,7 +383,7 @@ static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
*
* Note that v4l2_g_ext_ctrls_common() with 'which' set to
* V4L2_CTRL_WHICH_REQUEST_VAL is only called if the request was
- * completed, and in that case valid_p_req is true for all controls.
+ * completed, and in that case p_req_valid is true for all controls.
*/
int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
struct v4l2_ext_controls *cs,
@@ -430,7 +467,9 @@ int v4l2_g_ext_ctrls_common(struct v4l2_ctrl_handler *hdl,
if (is_default)
ret = def_to_user(cs->controls + idx, ref->ctrl);
- else if (is_request && ref->valid_p_req)
+ else if (is_request && ref->p_req_dyn_enomem)
+ ret = -ENOMEM;
+ else if (is_request && ref->p_req_valid)
ret = req_to_user(cs->controls + idx, ref);
else if (is_volatile)
ret = new_to_user(cs->controls + idx, ref->ctrl);
@@ -457,6 +496,17 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct video_device *vdev,
}
EXPORT_SYMBOL(v4l2_g_ext_ctrls);
+/* Validate a new control */
+static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
+{
+ unsigned int idx;
+ int err = 0;
+
+ for (idx = 0; !err && idx < ctrl->new_elems; idx++)
+ err = ctrl->type_ops->validate(ctrl, idx, p_new);
+ return err;
+}
+
/* Validate controls. */
static int validate_ctrls(struct v4l2_ext_controls *cs,
struct v4l2_ctrl_helper *helpers,
@@ -872,6 +922,9 @@ int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl,
/* It's a driver bug if this happens. */
if (WARN_ON(ctrl->type != type))
return -EINVAL;
+ /* Setting dynamic arrays is not (yet?) supported. */
+ if (WARN_ON(ctrl->is_dyn_array))
+ return -EINVAL;
memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size);
return set_ctrl(NULL, ctrl, 0);
}
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
index 949c1884d9c1..1f85828d6694 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
@@ -307,6 +307,21 @@ static void std_log(const struct v4l2_ctrl *ctrl)
case V4L2_CTRL_TYPE_VP9_FRAME:
pr_cont("VP9_FRAME");
break;
+ case V4L2_CTRL_TYPE_HEVC_SPS:
+ pr_cont("HEVC_SPS");
+ break;
+ case V4L2_CTRL_TYPE_HEVC_PPS:
+ pr_cont("HEVC_PPS");
+ break;
+ case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
+ pr_cont("HEVC_SLICE_PARAMS");
+ break;
+ case V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX:
+ pr_cont("HEVC_SCALING_MATRIX");
+ break;
+ case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
+ pr_cont("HEVC_DECODE_PARAMS");
+ break;
default:
pr_cont("unknown type %d", ctrl->type);
break;
@@ -521,7 +536,6 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
struct v4l2_ctrl_hevc_sps *p_hevc_sps;
struct v4l2_ctrl_hevc_pps *p_hevc_pps;
- struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params;
struct v4l2_area *area;
@@ -799,8 +813,6 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
p_hevc_pps->pps_beta_offset_div2 = 0;
p_hevc_pps->pps_tc_offset_div2 = 0;
}
-
- zero_padding(*p_hevc_pps);
break;
case V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS:
@@ -809,21 +821,9 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
if (p_hevc_decode_params->num_active_dpb_entries >
V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
return -EINVAL;
-
- for (i = 0; i < p_hevc_decode_params->num_active_dpb_entries;
- i++) {
- struct v4l2_hevc_dpb_entry *dpb_entry =
- &p_hevc_decode_params->dpb[i];
-
- zero_padding(*dpb_entry);
- }
break;
case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
- p_hevc_slice_params = p;
-
- zero_padding(p_hevc_slice_params->pred_weight_table);
- zero_padding(*p_hevc_slice_params);
break;
case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
@@ -991,11 +991,12 @@ EXPORT_SYMBOL(v4l2_ctrl_notify);
/* Copy the one value to another. */
static void ptr_to_ptr(struct v4l2_ctrl *ctrl,
- union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to)
+ union v4l2_ctrl_ptr from, union v4l2_ctrl_ptr to,
+ unsigned int elems)
{
if (ctrl == NULL)
return;
- memcpy(to.p, from.p_const, ctrl->elems * ctrl->elem_size);
+ memcpy(to.p, from.p_const, elems * ctrl->elem_size);
}
/* Copy the new value to the current value. */
@@ -1008,8 +1009,11 @@ void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
/* has_changed is set by cluster_changed */
changed = ctrl->has_changed;
- if (changed)
- ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur);
+ if (changed) {
+ if (ctrl->is_dyn_array)
+ ctrl->elems = ctrl->new_elems;
+ ptr_to_ptr(ctrl, ctrl->p_new, ctrl->p_cur, ctrl->elems);
+ }
if (ch_flags & V4L2_EVENT_CTRL_CH_FLAGS) {
/* Note: CH_FLAGS is only set for auto clusters. */
@@ -1039,36 +1043,122 @@ void cur_to_new(struct v4l2_ctrl *ctrl)
{
if (ctrl == NULL)
return;
- ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new);
+ if (ctrl->is_dyn_array)
+ ctrl->new_elems = ctrl->elems;
+ ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems);
+}
+
+static bool req_alloc_dyn_array(struct v4l2_ctrl_ref *ref, u32 elems)
+{
+ void *tmp;
+
+ if (elems < ref->p_req_dyn_alloc_elems)
+ return true;
+
+ tmp = kvmalloc(elems * ref->ctrl->elem_size, GFP_KERNEL);
+
+ if (!tmp) {
+ ref->p_req_dyn_enomem = true;
+ return false;
+ }
+ ref->p_req_dyn_enomem = false;
+ kvfree(ref->p_req.p);
+ ref->p_req.p = tmp;
+ ref->p_req_dyn_alloc_elems = elems;
+ return true;
}
/* Copy the new value to the request value */
void new_to_req(struct v4l2_ctrl_ref *ref)
{
+ struct v4l2_ctrl *ctrl;
+
if (!ref)
return;
- ptr_to_ptr(ref->ctrl, ref->ctrl->p_new, ref->p_req);
- ref->valid_p_req = true;
+
+ ctrl = ref->ctrl;
+ if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->new_elems))
+ return;
+
+ ref->p_req_elems = ctrl->new_elems;
+ ptr_to_ptr(ctrl, ctrl->p_new, ref->p_req, ref->p_req_elems);
+ ref->p_req_valid = true;
}
/* Copy the current value to the request value */
void cur_to_req(struct v4l2_ctrl_ref *ref)
{
+ struct v4l2_ctrl *ctrl;
+
if (!ref)
return;
- ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->p_req);
- ref->valid_p_req = true;
+
+ ctrl = ref->ctrl;
+ if (ctrl->is_dyn_array && !req_alloc_dyn_array(ref, ctrl->elems))
+ return;
+
+ ref->p_req_elems = ctrl->elems;
+ ptr_to_ptr(ctrl, ctrl->p_cur, ref->p_req, ctrl->elems);
+ ref->p_req_valid = true;
}
/* Copy the request value to the new value */
-void req_to_new(struct v4l2_ctrl_ref *ref)
+int req_to_new(struct v4l2_ctrl_ref *ref)
{
+ struct v4l2_ctrl *ctrl;
+
if (!ref)
- return;
- if (ref->valid_p_req)
- ptr_to_ptr(ref->ctrl, ref->p_req, ref->ctrl->p_new);
- else
- ptr_to_ptr(ref->ctrl, ref->ctrl->p_cur, ref->ctrl->p_new);
+ return 0;
+
+ ctrl = ref->ctrl;
+
+ /*
+ * This control was never set in the request, so just use the current
+ * value.
+ */
+ if (!ref->p_req_valid) {
+ if (ctrl->is_dyn_array)
+ ctrl->new_elems = ctrl->elems;
+ ptr_to_ptr(ctrl, ctrl->p_cur, ctrl->p_new, ctrl->new_elems);
+ return 0;
+ }
+
+ /* Not a dynamic array, so just copy the request value */
+ if (!ctrl->is_dyn_array) {
+ ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems);
+ return 0;
+ }
+
+ /* Sanity check, should never happen */
+ if (WARN_ON(!ref->p_req_dyn_alloc_elems))
+ return -ENOMEM;
+
+ /*
+ * Check if the number of elements in the request is more than the
+ * elements in ctrl->p_dyn. If so, attempt to realloc ctrl->p_dyn.
+ * Note that p_dyn is allocated with twice the number of elements
+ * in the dynamic array since it has to store both the current and
+ * new value of such a control.
+ */
+ if (ref->p_req_elems > ctrl->p_dyn_alloc_elems) {
+ unsigned int sz = ref->p_req_elems * ctrl->elem_size;
+ void *old = ctrl->p_dyn;
+ void *tmp = kvzalloc(2 * sz, GFP_KERNEL);
+
+ if (!tmp)
+ return -ENOMEM;
+ memcpy(tmp, ctrl->p_new.p, ctrl->elems * ctrl->elem_size);
+ memcpy(tmp + sz, ctrl->p_cur.p, ctrl->elems * ctrl->elem_size);
+ ctrl->p_new.p = tmp;
+ ctrl->p_cur.p = tmp + sz;
+ ctrl->p_dyn = tmp;
+ ctrl->p_dyn_alloc_elems = ref->p_req_elems;
+ kvfree(old);
+ }
+
+ ctrl->new_elems = ref->p_req_elems;
+ ptr_to_ptr(ctrl, ref->p_req, ctrl->p_new, ctrl->new_elems);
+ return 0;
}
/* Control range checking */
@@ -1110,17 +1200,6 @@ int check_range(enum v4l2_ctrl_type type,
}
}
-/* Validate a new control */
-int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
-{
- unsigned idx;
- int err = 0;
-
- for (idx = 0; !err && idx < ctrl->elems; idx++)
- err = ctrl->type_ops->validate(ctrl, idx, p_new);
- return err;
-}
-
/* Set the handler's error code if it wasn't set earlier already */
static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
{
@@ -1164,6 +1243,8 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
/* Free all nodes */
list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
list_del(&ref->node);
+ if (ref->p_req_dyn_alloc_elems)
+ kvfree(ref->p_req.p);
kfree(ref);
}
/* Free all controls owned by the handler */
@@ -1171,6 +1252,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
list_del(&ctrl->node);
list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
list_del(&sev->node);
+ kvfree(ctrl->p_dyn);
kvfree(ctrl);
}
kvfree(hdl->buckets);
@@ -1286,7 +1368,7 @@ int handler_new_ref(struct v4l2_ctrl_handler *hdl,
if (hdl->error)
return hdl->error;
- if (allocate_req)
+ if (allocate_req && !ctrl->is_dyn_array)
size_extra_req = ctrl->elems * ctrl->elem_size;
new_ref = kzalloc(sizeof(*new_ref) + size_extra_req, GFP_KERNEL);
if (!new_ref)
@@ -1460,7 +1542,6 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
elem_size = sizeof(s32);
break;
}
- tot_ctrl_size = elem_size * elems;
/* Sanity checks */
if (id == 0 || name == NULL || !elem_size ||
@@ -1481,17 +1562,33 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
handler_set_err(hdl, -EINVAL);
return NULL;
}
+ if (flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) {
+ /*
+ * For now only support this for one-dimensional arrays only.
+ *
+ * This can be relaxed in the future, but this will
+ * require more effort.
+ */
+ if (nr_of_dims != 1) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ /* Start with just 1 element */
+ elems = 1;
+ }
+ tot_ctrl_size = elem_size * elems;
sz_extra = 0;
if (type == V4L2_CTRL_TYPE_BUTTON)
flags |= V4L2_CTRL_FLAG_WRITE_ONLY |
V4L2_CTRL_FLAG_EXECUTE_ON_WRITE;
else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
flags |= V4L2_CTRL_FLAG_READ_ONLY;
- else if (type == V4L2_CTRL_TYPE_INTEGER64 ||
- type == V4L2_CTRL_TYPE_STRING ||
- type >= V4L2_CTRL_COMPOUND_TYPES ||
- is_array)
+ else if (!(flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY) &&
+ (type == V4L2_CTRL_TYPE_INTEGER64 ||
+ type == V4L2_CTRL_TYPE_STRING ||
+ type >= V4L2_CTRL_COMPOUND_TYPES ||
+ is_array))
sz_extra += 2 * tot_ctrl_size;
if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const)
@@ -1520,7 +1617,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->is_ptr = is_array || type >= V4L2_CTRL_COMPOUND_TYPES || ctrl->is_string;
ctrl->is_int = !ctrl->is_ptr && type != V4L2_CTRL_TYPE_INTEGER64;
ctrl->is_array = is_array;
+ ctrl->is_dyn_array = !!(flags & V4L2_CTRL_FLAG_DYNAMIC_ARRAY);
ctrl->elems = elems;
+ ctrl->new_elems = elems;
ctrl->nr_of_dims = nr_of_dims;
if (nr_of_dims)
memcpy(ctrl->dims, dims, nr_of_dims * sizeof(dims[0]));
@@ -1533,6 +1632,16 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
ctrl->cur.val = ctrl->val = def;
data = &ctrl[1];
+ if (ctrl->is_dyn_array) {
+ ctrl->p_dyn_alloc_elems = elems;
+ ctrl->p_dyn = kvzalloc(2 * elems * elem_size, GFP_KERNEL);
+ if (!ctrl->p_dyn) {
+ kvfree(ctrl);
+ return NULL;
+ }
+ data = ctrl->p_dyn;
+ }
+
if (!ctrl->is_int) {
ctrl->p_new.p = data;
ctrl->p_cur.p = data + tot_ctrl_size;
@@ -1542,7 +1651,10 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
}
if (type >= V4L2_CTRL_COMPOUND_TYPES && p_def.p_const) {
- ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
+ if (ctrl->is_dyn_array)
+ ctrl->p_def.p = &ctrl[1];
+ else
+ ctrl->p_def.p = ctrl->p_cur.p + tot_ctrl_size;
memcpy(ctrl->p_def.p, p_def.p_const, elem_size);
}
@@ -1552,6 +1664,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
}
if (handler_new_ref(hdl, ctrl, NULL, false, false)) {
+ kvfree(ctrl->p_dyn);
kvfree(ctrl);
return NULL;
}
@@ -1889,6 +2002,9 @@ static int cluster_changed(struct v4l2_ctrl *master)
continue;
}
+ if (ctrl->elems != ctrl->new_elems)
+ ctrl_changed = true;
+
for (idx = 0; !ctrl_changed && idx < ctrl->elems; idx++)
ctrl_changed = !ctrl->type_ops->equal(ctrl, idx,
ctrl->p_cur, ctrl->p_new);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
index 16f42d2fd359..e22921e7ea61 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -704,9 +704,9 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
return hevc_tier;
case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
return hevc_loop_filter_mode;
- case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
+ case V4L2_CID_STATELESS_HEVC_DECODE_MODE:
return hevc_decode_mode;
- case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
+ case V4L2_CID_STATELESS_HEVC_START_CODE:
return hevc_start_code;
case V4L2_CID_CAMERA_ORIENTATION:
return camera_orientation;
@@ -1003,13 +1003,6 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: return "HEVC Size of Length Field";
case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: return "Reference Frames for a P-Frame";
case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: return "Prepend SPS and PPS to IDR";
- case V4L2_CID_MPEG_VIDEO_HEVC_SPS: return "HEVC Sequence Parameter Set";
- case V4L2_CID_MPEG_VIDEO_HEVC_PPS: return "HEVC Picture Parameter Set";
- case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters";
- case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX: return "HEVC Scaling Matrix";
- case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS: return "HEVC Decode Parameters";
- case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: return "HEVC Decode Mode";
- case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return "HEVC Start Code";
/* CAMERA controls */
/* Keep the order of the 'case's the same as in v4l2-controls.h! */
@@ -1188,6 +1181,14 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_STATELESS_MPEG2_QUANTISATION: return "MPEG-2 Quantisation Matrices";
case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR: return "VP9 Probabilities Updates";
case V4L2_CID_STATELESS_VP9_FRAME: return "VP9 Frame Decode Parameters";
+ case V4L2_CID_STATELESS_HEVC_SPS: return "HEVC Sequence Parameter Set";
+ case V4L2_CID_STATELESS_HEVC_PPS: return "HEVC Picture Parameter Set";
+ case V4L2_CID_STATELESS_HEVC_SLICE_PARAMS: return "HEVC Slice Parameters";
+ case V4L2_CID_STATELESS_HEVC_SCALING_MATRIX: return "HEVC Scaling Matrix";
+ case V4L2_CID_STATELESS_HEVC_DECODE_PARAMS: return "HEVC Decode Parameters";
+ case V4L2_CID_STATELESS_HEVC_DECODE_MODE: return "HEVC Decode Mode";
+ case V4L2_CID_STATELESS_HEVC_START_CODE: return "HEVC Start Code";
+ case V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS: return "HEVC Entry Point Offsets";
/* Colorimetry controls */
/* Keep the order of the 'case's the same as in v4l2-controls.h! */
@@ -1363,8 +1364,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
- case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE:
- case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE:
+ case V4L2_CID_STATELESS_HEVC_DECODE_MODE:
+ case V4L2_CID_STATELESS_HEVC_START_CODE:
case V4L2_CID_STATELESS_H264_DECODE_MODE:
case V4L2_CID_STATELESS_H264_START_CODE:
case V4L2_CID_CAMERA_ORIENTATION:
@@ -1502,21 +1503,26 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_STATELESS_VP8_FRAME:
*type = V4L2_CTRL_TYPE_VP8_FRAME;
break;
- case V4L2_CID_MPEG_VIDEO_HEVC_SPS:
+ case V4L2_CID_STATELESS_HEVC_SPS:
*type = V4L2_CTRL_TYPE_HEVC_SPS;
break;
- case V4L2_CID_MPEG_VIDEO_HEVC_PPS:
+ case V4L2_CID_STATELESS_HEVC_PPS:
*type = V4L2_CTRL_TYPE_HEVC_PPS;
break;
- case V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS:
+ case V4L2_CID_STATELESS_HEVC_SLICE_PARAMS:
*type = V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS;
+ *flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
break;
- case V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX:
+ case V4L2_CID_STATELESS_HEVC_SCALING_MATRIX:
*type = V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX;
break;
- case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS:
+ case V4L2_CID_STATELESS_HEVC_DECODE_PARAMS:
*type = V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS;
break;
+ case V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS:
+ *type = V4L2_CTRL_TYPE_U32;
+ *flags |= V4L2_CTRL_FLAG_DYNAMIC_ARRAY;
+ break;
case V4L2_CID_STATELESS_VP9_COMPRESSED_HDR:
*type = V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR;
break;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-priv.h b/drivers/media/v4l2-core/v4l2-ctrls-priv.h
index d4bf2c716f97..aba6176fab6c 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-priv.h
+++ b/drivers/media/v4l2-core/v4l2-ctrls-priv.h
@@ -57,10 +57,9 @@ void cur_to_new(struct v4l2_ctrl *ctrl);
void cur_to_req(struct v4l2_ctrl_ref *ref);
void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags);
void new_to_req(struct v4l2_ctrl_ref *ref);
-void req_to_new(struct v4l2_ctrl_ref *ref);
+int req_to_new(struct v4l2_ctrl_ref *ref);
void send_initial_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl);
void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes);
-int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new);
int handler_new_ref(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl *ctrl,
struct v4l2_ctrl_ref **ctrl_ref,
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-request.c b/drivers/media/v4l2-core/v4l2-ctrls-request.c
index 7d098f287fd9..c637049d7a2b 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-request.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-request.c
@@ -143,7 +143,7 @@ v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
{
struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
- return (ref && ref->valid_p_req) ? ref->ctrl : NULL;
+ return (ref && ref->p_req_valid) ? ref->ctrl : NULL;
}
EXPORT_SYMBOL_GPL(v4l2_ctrl_request_hdl_ctrl_find);
@@ -373,7 +373,7 @@ void v4l2_ctrl_request_complete(struct media_request *req,
v4l2_ctrl_unlock(master);
continue;
}
- if (ref->valid_p_req)
+ if (ref->p_req_valid)
continue;
/* Copy the current control value into the request */
@@ -442,7 +442,7 @@ int v4l2_ctrl_request_setup(struct media_request *req,
struct v4l2_ctrl_ref *r =
find_ref(hdl, master->cluster[i]->id);
- if (r->valid_p_req) {
+ if (r->p_req_valid) {
have_new_data = true;
break;
}
@@ -458,7 +458,11 @@ int v4l2_ctrl_request_setup(struct media_request *req,
struct v4l2_ctrl_ref *r =
find_ref(hdl, master->cluster[i]->id);
- req_to_new(r);
+ ret = req_to_new(r);
+ if (ret) {
+ v4l2_ctrl_unlock(master);
+ goto error;
+ }
master->cluster[i]->is_new = 1;
r->req_done = true;
}
@@ -490,6 +494,7 @@ int v4l2_ctrl_request_setup(struct media_request *req,
break;
}
+error:
media_request_object_put(obj);
return ret;
}
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 21470de62d72..c314025d977e 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1007,6 +1007,31 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
return -EINVAL;
}
+static void v4l_sanitize_colorspace(u32 pixelformat, u32 *colorspace,
+ u32 *encoding, u32 *quantization,
+ u32 *xfer_func)
+{
+ bool is_hsv = pixelformat == V4L2_PIX_FMT_HSV24 ||
+ pixelformat == V4L2_PIX_FMT_HSV32;
+
+ if (!v4l2_is_colorspace_valid(*colorspace)) {
+ *colorspace = V4L2_COLORSPACE_DEFAULT;
+ *encoding = V4L2_YCBCR_ENC_DEFAULT;
+ *quantization = V4L2_QUANTIZATION_DEFAULT;
+ *xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ }
+
+ if ((!is_hsv && !v4l2_is_ycbcr_enc_valid(*encoding)) ||
+ (is_hsv && !v4l2_is_hsv_enc_valid(*encoding)))
+ *encoding = V4L2_YCBCR_ENC_DEFAULT;
+
+ if (!v4l2_is_quant_valid(*quantization))
+ *quantization = V4L2_QUANTIZATION_DEFAULT;
+
+ if (!v4l2_is_xfer_func_valid(*xfer_func))
+ *xfer_func = V4L2_XFER_FUNC_DEFAULT;
+}
+
static void v4l_sanitize_format(struct v4l2_format *fmt)
{
unsigned int offset;
@@ -1026,20 +1051,40 @@ static void v4l_sanitize_format(struct v4l2_format *fmt)
* field to the magic value when the extended pixel format structure
* isn't used by applications.
*/
+ if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (fmt->fmt.pix.priv != V4L2_PIX_FMT_PRIV_MAGIC) {
+ fmt->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+
+ offset = offsetof(struct v4l2_pix_format, priv)
+ + sizeof(fmt->fmt.pix.priv);
+ memset(((void *)&fmt->fmt.pix) + offset, 0,
+ sizeof(fmt->fmt.pix) - offset);
+ }
+ }
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
- return;
-
- if (fmt->fmt.pix.priv == V4L2_PIX_FMT_PRIV_MAGIC)
- return;
+ /* Replace invalid colorspace values with defaults. */
+ if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ v4l_sanitize_colorspace(fmt->fmt.pix.pixelformat,
+ &fmt->fmt.pix.colorspace,
+ &fmt->fmt.pix.ycbcr_enc,
+ &fmt->fmt.pix.quantization,
+ &fmt->fmt.pix.xfer_func);
+ } else if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ||
+ fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ u32 ycbcr_enc = fmt->fmt.pix_mp.ycbcr_enc;
+ u32 quantization = fmt->fmt.pix_mp.quantization;
+ u32 xfer_func = fmt->fmt.pix_mp.xfer_func;
- fmt->fmt.pix.priv = V4L2_PIX_FMT_PRIV_MAGIC;
+ v4l_sanitize_colorspace(fmt->fmt.pix_mp.pixelformat,
+ &fmt->fmt.pix_mp.colorspace, &ycbcr_enc,
+ &quantization, &xfer_func);
- offset = offsetof(struct v4l2_pix_format, priv)
- + sizeof(fmt->fmt.pix.priv);
- memset(((void *)&fmt->fmt.pix) + offset, 0,
- sizeof(fmt->fmt.pix) - offset);
+ fmt->fmt.pix_mp.ycbcr_enc = ycbcr_enc;
+ fmt->fmt.pix_mp.quantization = quantization;
+ fmt->fmt.pix_mp.xfer_func = xfer_func;
+ }
}
static int v4l_querycap(const struct v4l2_ioctl_ops *ops,
@@ -1296,6 +1341,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_XYUV32: descr = "32-bit XYUV 8-8-8-8"; break;
case V4L2_PIX_FMT_VUYA32: descr = "32-bit VUYA 8-8-8-8"; break;
case V4L2_PIX_FMT_VUYX32: descr = "32-bit VUYX 8-8-8-8"; break;
+ case V4L2_PIX_FMT_YUVA32: descr = "32-bit YUVA 8-8-8-8"; break;
+ case V4L2_PIX_FMT_YUVX32: descr = "32-bit YUVX 8-8-8-8"; break;
case V4L2_PIX_FMT_YUV410: descr = "Planar YUV 4:1:0"; break;
case V4L2_PIX_FMT_YUV420: descr = "Planar YUV 4:2:0"; break;
case V4L2_PIX_FMT_HI240: descr = "8-bit Dithered RGB (BTTV)"; break;
@@ -1306,9 +1353,11 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_NV61: descr = "Y/CrCb 4:2:2"; break;
case V4L2_PIX_FMT_NV24: descr = "Y/CbCr 4:4:4"; break;
case V4L2_PIX_FMT_NV42: descr = "Y/CrCb 4:4:4"; break;
+ case V4L2_PIX_FMT_P010: descr = "10-bit Y/CbCr 4:2:0"; break;
case V4L2_PIX_FMT_NV12_4L4: descr = "Y/CbCr 4:2:0 (4x4 Linear)"; break;
case V4L2_PIX_FMT_NV12_16L16: descr = "Y/CbCr 4:2:0 (16x16 Linear)"; break;
case V4L2_PIX_FMT_NV12_32L32: descr = "Y/CbCr 4:2:0 (32x32 Linear)"; break;
+ case V4L2_PIX_FMT_P010_4L4: descr = "10-bit Y/CbCr 4:2:0 (4x4 Linear)"; break;
case V4L2_PIX_FMT_NV12M: descr = "Y/CbCr 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_NV21M: descr = "Y/CrCb 4:2:0 (N-C)"; break;
case V4L2_PIX_FMT_NV16M: descr = "Y/CbCr 4:2:2 (N-C)"; break;
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index 6469f9a25a4e..837e1855f94b 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -925,7 +925,7 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file,
if ((!src_q->streaming || src_q->error ||
list_empty(&src_q->queued_list)) &&
(!dst_q->streaming || dst_q->error ||
- list_empty(&dst_q->queued_list)))
+ (list_empty(&dst_q->queued_list) && !dst_q->last_buffer_dequeued)))
return EPOLLERR;
spin_lock_irqsave(&src_q->done_lock, flags);